Skip to content

Commit 4b74ac9

Browse files
authored
Support autoFocus in Combobox-based components (#1628)
1 parent faf8088 commit 4b74ac9

File tree

23 files changed

+77
-24
lines changed

23 files changed

+77
-24
lines changed

packages/components/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Added
1111

12+
- The `autoFocus` prop will now work for inputs in `Popover` and `Dialog`
13+
- `Select`, `SelectMulti`, `InputTimeSelect`, and `InputSearch` now support `autoFocus`
1214
- `Dialog` & `Drawer` now support semantic sizes (`xxsmall - xlarge`)
1315
- `Dialog` now supports `placement` - `center` (default), `top` & `cover`
1416
- `Drawer` now supports `placement` - `left` & `right` (default)

packages/components/src/Form/Fields/FieldCheckboxGroup/FieldCheckboxGroup.story.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ const defaultValueCheckbox = ['swiss', 'cheddar']
9494
const Template: Story<FieldCheckboxGroupProps> = (args) => (
9595
<FieldCheckboxGroup
9696
{...args}
97+
autoFocus
9798
defaultValue={defaultValueCheckbox}
9899
label="Cheeses"
99100
description="Pick all your cheeses"

packages/components/src/Form/Fields/FieldSelect/FieldSelect.story.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ export const SelectContent = () => {
234234
aria-label="Fruits"
235235
placeholder="Select Brand"
236236
defaultValue="Boulder Creek"
237+
autoFocus
237238
/>
238239
<Label>
239240
Use alignSelf="flex-start" to avoid filling height as a flex child
@@ -376,6 +377,7 @@ export const SelectDemo = () => {
376377
aria-label="Fruits"
377378
defaultValue="1"
378379
isClearable
380+
autoFocus
379381
/>
380382
</Form>
381383
</CardContent>

packages/components/src/Form/Fields/FieldSelectMulti/FieldSelectMulti.story.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,12 @@
2727
import { Story } from '@storybook/react/types-6-0'
2828
import React, { useMemo, useState, useEffect } from 'react'
2929
import { Button } from '../../../Button'
30-
import { Dialog, DialogContent } from '../../../Dialog'
30+
import {
31+
Dialog,
32+
DialogContent,
33+
DialogFooter,
34+
DialogHeader,
35+
} from '../../../Dialog'
3136
import { Icon } from '../../../Icon'
3237
import { Space, SpaceVertical } from '../../../Layout'
3338
import { List, ListItem } from '../../../List'
@@ -280,6 +285,7 @@ export const SelectMultiDemo = () => {
280285
return (
281286
<SpaceVertical p="large" width={400}>
282287
<Dialog isOpen={isOpen} onClose={handleClose}>
288+
<DialogHeader>SelectMulti in a Dialog</DialogHeader>
283289
<DialogContent>
284290
<FieldSelectMulti
285291
options={newOptions1k}
@@ -290,8 +296,10 @@ export const SelectMultiDemo = () => {
290296
showCreate
291297
defaultValues={['Boulder Creek']}
292298
freeInput
299+
autoFocus
293300
/>
294301
</DialogContent>
302+
<DialogFooter />
295303
</Dialog>
296304
<Button onClick={handleClick}>Open</Button>
297305
<Heading>FieldSelectMulti</Heading>
@@ -308,6 +316,7 @@ export const SelectMultiDemo = () => {
308316
description="this is the description"
309317
values={['cheddar']}
310318
options={cheeseOptions}
319+
autoFocus
311320
/>
312321
</SpaceVertical>
313322
<Heading>SelectMulti</Heading>

packages/components/src/Form/Fields/FieldTimeSelect/FieldTimeSelect.story.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ export const Controlled = () => {
9393
label="Standard Time"
9494
value={controlledTime}
9595
onChange={setControlledTime}
96+
autoFocus
9697
/>
9798
<FieldTimeSelect
9899
label="Military Time"

packages/components/src/Form/Inputs/Checkbox/Checkbox.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,11 @@
2525
*/
2626

2727
import noop from 'lodash/noop'
28-
import pick from 'lodash/pick'
2928
import React, { forwardRef, Ref, useState, FormEvent, useEffect } from 'react'
3029
import styled from 'styled-components'
3130
import { reset, space, SpaceProps } from '@looker/design-tokens'
3231
import isUndefined from 'lodash/isUndefined'
33-
import { InputProps, inputPropKeys } from '../InputProps'
32+
import { InputProps, pickInputProps } from '../InputProps'
3433
import { ValidationType } from '../../ValidationMessage'
3534
import { inputTextValidation } from '../InputText'
3635

@@ -82,7 +81,7 @@ const CheckboxLayout = forwardRef(
8281
<div className={className}>
8382
<input
8483
type="checkbox"
85-
{...pick(restProps, inputPropKeys)}
84+
{...pickInputProps(restProps)}
8685
checked={!!isChecked}
8786
aria-checked={checked}
8887
aria-invalid={validationType === 'error' ? 'true' : undefined}

packages/components/src/Form/Inputs/InlineInputText/InlineInputText.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
2525
*/
2626

27-
import pick from 'lodash/pick'
2827
import React, { ChangeEvent, forwardRef, Ref, useState } from 'react'
2928
import isFunction from 'lodash/isFunction'
3029
import styled from 'styled-components'
@@ -33,7 +32,7 @@ import {
3332
typography,
3433
TypographyProps,
3534
} from '@looker/design-tokens'
36-
import { inputPropKeys, InputProps, InputTextTypeProps } from '../InputProps'
35+
import { pickInputProps, InputProps, InputTextTypeProps } from '../InputProps'
3736
import { innerInputStyle } from '../innerInputStyle'
3837

3938
export interface InlineInputTextProps
@@ -75,7 +74,7 @@ const InlineInputTextLayout = forwardRef(
7574
placeholder={placeholder}
7675
type={type}
7776
ref={ref}
78-
{...omitStyledProps(pick(props, inputPropKeys))}
77+
{...omitStyledProps(pickInputProps(props))}
7978
/>
8079
<StyledText>{displayValue || placeholder || ' '}</StyledText>
8180
</span>

packages/components/src/Form/Inputs/InlineTextArea/InlineTextArea.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
2525
*/
2626

27-
import pick from 'lodash/pick'
2827
import React, { ChangeEvent, forwardRef, Ref, useState } from 'react'
2928
import isFunction from 'lodash/isFunction'
3029
import styled from 'styled-components'
@@ -35,7 +34,7 @@ import {
3534
CompatibleHTMLProps,
3635
LayoutProps,
3736
} from '@looker/design-tokens'
38-
import { inputPropKeys } from '../InputProps'
37+
import { pickInputProps } from '../InputProps'
3938

4039
export interface InlineTextAreaProps
4140
extends Omit<LayoutProps, 'size'>,
@@ -75,7 +74,7 @@ export const InlineTextAreaLayout = forwardRef(
7574
ref={ref}
7675
underlineOnlyOnHover={underlineOnlyOnHover}
7776
value={displayValue}
78-
{...pick(props, inputPropKeys)}
77+
{...pickInputProps(props)}
7978
/>
8079
<VisibleText displayValue={displayValue}>
8180
{displayValue || placeholder}

packages/components/src/Form/Inputs/InputProps.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,14 @@
2424
2525
*/
2626

27+
import pick from 'lodash/pick'
2728
import { CompatibleHTMLProps } from '@looker/design-tokens'
2829
import { ValidationType } from '../ValidationMessage'
2930

3031
export interface InputProps extends CompatibleHTMLProps<HTMLInputElement> {
3132
validationType?: ValidationType
33+
'data-autofocus'?: string
34+
'data-testid'?: string
3235
}
3336

3437
export interface InputTextTypeProps {
@@ -92,3 +95,19 @@ export const inputPropKeys = [
9295
'aria-describedby',
9396
'aria-labelledby',
9497
]
98+
/**
99+
* Adds data-autofocus attribute for use with focus-trap (Popover & Dialog)
100+
* Can't use the autofocus dom attribute b/c React does not pass it down
101+
* https://github.com/facebook/react/issues/11851
102+
*/
103+
export const getAutoFocusProps = (autoFocus?: boolean) => {
104+
return autoFocus ? { autoFocus, 'data-autofocus': 'true' } : {}
105+
}
106+
107+
export const pickInputProps = <T extends { autoFocus?: boolean }>({
108+
autoFocus,
109+
...props
110+
}: T) => {
111+
const inputProps = pick(props, inputPropKeys)
112+
return { ...getAutoFocusProps(autoFocus), ...inputProps }
113+
}

packages/components/src/Form/Inputs/InputSearch/InputSearch.story.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ export const Advanced = () => {
9292
options={options}
9393
noOptionsLabel="Nothing matched your search"
9494
isClearable={false}
95+
autoFocus
9596
/>
9697
)
9798
}

0 commit comments

Comments
 (0)