@workday/canvas-kit-docs 16.2.0-0612-next.0 → 16.2.0-0618-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/es6/lib/docs.js +4 -4
- package/dist/es6/lib/specs.js +20 -0
- package/dist/es6/lib/stackblitzFiles/packageJSONFile.js +5 -5
- package/dist/es6/lib/stackblitzFiles/packageJSONFile.ts +5 -5
- package/dist/mdx/accessibility/AccessibilityOverview.mdx +3 -1
- package/dist/mdx/preview-react/_examples/mdx/FormLibraryExample.mdx +33 -1
- package/dist/mdx/preview-react/_examples/mdx/examples/TextInputWithReactHookForm.tsx +94 -65
- package/dist/mdx/react/_examples/mdx/Density.mdx +19 -3
- package/dist/mdx/react/_examples/mdx/examples/Density.tsx +139 -212
- package/dist/mdx/react/select/Select.mdx +239 -77
- package/dist/mdx/react/select/examples/GroupedItems.tsx +24 -30
- package/dist/mdx/react/select/examples/WithIcons.tsx +1 -1
- package/package.json +6 -6
- package/dist/mdx/react/_examples/mdx/FormsWithFormik.mdx +0 -9
- package/dist/mdx/react/_examples/mdx/examples/SelectWithFormik.tsx +0 -84
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ExampleCodeBlock,
|
|
3
|
-
Specifications,
|
|
4
|
-
SymbolDoc,
|
|
5
|
-
} from '@workday/canvas-kit-docs';
|
|
6
|
-
import {Table} from '@workday/canvas-kit-react/table';
|
|
1
|
+
import {ExampleCodeBlock, Specifications, SymbolDoc} from '@workday/canvas-kit-docs';
|
|
7
2
|
import Basic from './examples/Basic';
|
|
8
3
|
import Caution from './examples/Caution';
|
|
9
4
|
import Complex from './examples/Complex';
|
|
@@ -40,30 +35,16 @@ yarn add @workday/canvas-kit-react
|
|
|
40
35
|
|
|
41
36
|
### Basic Example
|
|
42
37
|
|
|
43
|
-
`Select` supports a
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
items may be provided as an
|
|
38
|
+
`Select` supports a [dynamic API](/get-started/for-developers/guides/collection-api/#dynamic-items)
|
|
39
|
+
where you pass an array of items via the `items` prop and provide a render function to display the
|
|
40
|
+
items. The items may be provided as an
|
|
47
41
|
[array of strings](/get-started/for-developers/guides/collection-api/#array-of-strings) or an
|
|
48
42
|
[array of objects](/get-started/for-developers/guides/collection-api/#array-of-objects).
|
|
49
43
|
|
|
50
|
-
`Select` should be used in tandem with [Form Field](/components/inputs/form-field/)
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
```tsx
|
|
56
|
-
<Select items={options}>
|
|
57
|
-
<FormField label="Your Label">
|
|
58
|
-
<Select.Input onChange={e => handleChange(e)} id="contact-select" />
|
|
59
|
-
<Select.Popper>
|
|
60
|
-
<Select.Card>
|
|
61
|
-
<Select.List>{item => <Select.Item>{item.id}</Select.Item>}</Select.List>
|
|
62
|
-
</Select.Card>
|
|
63
|
-
</Select.Popper>
|
|
64
|
-
</FormField>
|
|
65
|
-
</Select>
|
|
66
|
-
```
|
|
44
|
+
`Select` should be used in tandem with [Form Field](/components/inputs/form-field/) to ensure proper
|
|
45
|
+
label association and screen reader support. Wrap **`Select`** with **`FormField`**, and compose
|
|
46
|
+
**`FormField.Input as={Select.Input}`** so the combobox receives the field label. Include
|
|
47
|
+
**`Select.Popper`**, **`Select.Card`**, **`Select.List`**, and **`Select.Item`**.
|
|
67
48
|
|
|
68
49
|
<ExampleCodeBlock code={Basic} />
|
|
69
50
|
|
|
@@ -96,14 +77,15 @@ input component. By default, the orientation will be set to `vertical`.
|
|
|
96
77
|
|
|
97
78
|
### Required
|
|
98
79
|
|
|
99
|
-
Set the `
|
|
80
|
+
Set the `isRequired` prop of the wrapping `FormField` to `true` to indicate that the field is
|
|
100
81
|
required. Labels for required fields are suffixed by a red asterisk.
|
|
101
82
|
|
|
102
83
|
<ExampleCodeBlock code={Required} />
|
|
103
84
|
|
|
104
85
|
### Disabled
|
|
105
86
|
|
|
106
|
-
Set the `disabled` prop
|
|
87
|
+
Set the `disabled` prop on **`FormField.Input as={Select.Input}`** to prevent users from interacting
|
|
88
|
+
with the combobox.
|
|
107
89
|
|
|
108
90
|
<ExampleCodeBlock code={Disabled} />
|
|
109
91
|
|
|
@@ -129,20 +111,21 @@ sets `aria-disabled` for the disabled items.
|
|
|
129
111
|
Use `Select.Item.Icon` to render an icon for a `Select.Item`. The `icon` prop for `Select.Item.Icon`
|
|
130
112
|
accepts [system icons](/assets/system-icons/) from `@workday/canvas-system-icons-web`.
|
|
131
113
|
|
|
132
|
-
In order to render the icon for the selected item
|
|
114
|
+
In order to render the icon for the selected item on **`FormField.Input as={Select.Input}`**:
|
|
133
115
|
|
|
134
116
|
1. Obtain a reference to the `model` by registering your `items` with `useSelectModel`.
|
|
135
117
|
2. Get the selected item:
|
|
136
118
|
`const selectedItem = model.navigation.getItem(model.state.selectedIds[0], model)`
|
|
137
119
|
3. Pass the icon for the selected item to the input:
|
|
138
|
-
`<Select.Input inputStartIcon={selectedItem
|
|
120
|
+
`<FormField.Input as={Select.Input} inputStartIcon={selectedItem?.value.icon} />`
|
|
139
121
|
|
|
140
|
-
> **Note
|
|
141
|
-
>
|
|
122
|
+
> **Note:** Dynamic `{item => <Select.Item>}` registration already uses the collection `id`. Set
|
|
123
|
+
> **`data-id`** only on static **`Select.Item`** children (see [Grouped Items](#grouped-items)), and
|
|
124
|
+
> keep it equal to that id (`id` or **`getId`**).
|
|
142
125
|
|
|
143
126
|
<ExampleCodeBlock code={WithIcons} />
|
|
144
127
|
|
|
145
|
-
**Note: that `Select.Input` will only render an icon if an item is selected.**
|
|
128
|
+
**Note: that `FormField.Input as={Select.Input}` will only render an icon if an item is selected.**
|
|
146
129
|
|
|
147
130
|
### Grow
|
|
148
131
|
|
|
@@ -167,23 +150,10 @@ forward `ref` to its underlying `<input type="text" role="combobox">` element.
|
|
|
167
150
|
|
|
168
151
|
### Error States
|
|
169
152
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
attributes ensure that the caution message is associated to the `Select` and read out by voiceover.
|
|
175
|
-
|
|
176
|
-
**Note: The Select container component, `Select`, must wrap `FormField` to ensure `Select.Input` is
|
|
177
|
-
styled correctly.**
|
|
178
|
-
|
|
179
|
-
```tsx
|
|
180
|
-
<Select items={options}>
|
|
181
|
-
<FormField label="Contact" inputId="contact-id-formfield">
|
|
182
|
-
<Select.Input id="contact-id-formfield" />
|
|
183
|
-
...
|
|
184
|
-
</FormField>
|
|
185
|
-
</Select>
|
|
186
|
-
```
|
|
153
|
+
Form Field provides error and caution states for Select. Set the `error` prop on Form Field to
|
|
154
|
+
`"error"` or `"caution"` and use `FormField.Hint` to provide messages. See
|
|
155
|
+
[Form Field's Error documentation](/components/inputs/form-field/#error-states) for examples and
|
|
156
|
+
accessibility guidance.
|
|
187
157
|
|
|
188
158
|
#### Caution
|
|
189
159
|
|
|
@@ -205,8 +175,9 @@ You can set `initialSelectedIds` to the value that you want initially selected.
|
|
|
205
175
|
|
|
206
176
|
### Placeholder
|
|
207
177
|
|
|
208
|
-
You can change the placeholder text by passing
|
|
209
|
-
|
|
178
|
+
You can change the placeholder text by passing a string to the `placeholder` prop on
|
|
179
|
+
**`FormField.Input as={Select.Input}`**. Placeholder text is not a substitute for
|
|
180
|
+
**`FormField.Label`**.
|
|
210
181
|
|
|
211
182
|
<ExampleCodeBlock code={Placeholder} />
|
|
212
183
|
|
|
@@ -232,8 +203,9 @@ to `id` and `text` hence the usage of `getId` and `getTextValue`. If your object
|
|
|
232
203
|
<ExampleCodeBlock code={Complex} />
|
|
233
204
|
|
|
234
205
|
**Note: By default, the identifier and text value are `id` and `text` properties respectively. If
|
|
235
|
-
your data object for each item is different, provide
|
|
236
|
-
|
|
206
|
+
your data object for each item is different, provide `getId` and/or `getTextValue`. If a custom
|
|
207
|
+
`getId` does not return the display text, also pass `getTextValue` — otherwise the model uses
|
|
208
|
+
`getId` for type-ahead and the selected value. For example:**
|
|
237
209
|
|
|
238
210
|
```jsx
|
|
239
211
|
const items = [
|
|
@@ -265,20 +237,24 @@ prop as well as the `value` DOM property and will update the model accordingly.
|
|
|
265
237
|
`items`, do not override this function. Instead provide static items via JSX. the list will create
|
|
266
238
|
an internal array of items where `id` is the only property and the default `getId` will return the
|
|
267
239
|
desired result. **Note: If your array of objects has a different property for `id`, like
|
|
268
|
-
`serverId`, use this function to set the id
|
|
240
|
+
`serverId`, use this function to set the id. If that function does not return the display text,
|
|
241
|
+
also pass `getTextValue`.**
|
|
269
242
|
|
|
270
243
|
```tsx
|
|
271
244
|
const options = [{text: 'Pizza', serverId: 'pizza-1'}, {text: 'Cheeseburger', serverId: 'cheeseburger'}]
|
|
272
|
-
<
|
|
273
|
-
<FormField
|
|
274
|
-
|
|
275
|
-
<Select.
|
|
276
|
-
<Select.
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
245
|
+
<FormField>
|
|
246
|
+
<FormField.Label>Your Label</FormField.Label>
|
|
247
|
+
<FormField.Field>
|
|
248
|
+
<Select items={options} getId={(item) => item.serverId} getTextValue={(item) => item.text}>
|
|
249
|
+
<FormField.Input as={Select.Input} onChange={e => handleChange(e)} />
|
|
250
|
+
<Select.Popper>
|
|
251
|
+
<Select.Card>
|
|
252
|
+
<Select.List>{item => <Select.Item>{item.text}</Select.Item>}</Select.List>
|
|
253
|
+
</Select.Card>
|
|
254
|
+
</Select.Popper>
|
|
255
|
+
</Select>
|
|
256
|
+
</FormField.Field>
|
|
257
|
+
</FormField>
|
|
282
258
|
```
|
|
283
259
|
|
|
284
260
|
- `getTextValue`: Optional function to return the text representation of an item. If not provided,
|
|
@@ -289,21 +265,25 @@ prop as well as the `value` DOM property and will update the model accordingly.
|
|
|
289
265
|
|
|
290
266
|
```tsx
|
|
291
267
|
const options = [{label: 'Pizza', id: 'pizza-1'}, {label: 'Cheeseburger', id: 'cheeseburger'}]
|
|
292
|
-
<
|
|
293
|
-
<FormField
|
|
294
|
-
|
|
295
|
-
<Select.
|
|
296
|
-
<Select.
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
268
|
+
<FormField>
|
|
269
|
+
<FormField.Label>Your Label</FormField.Label>
|
|
270
|
+
<FormField.Field>
|
|
271
|
+
<Select items={options} getTextValue={(item) => item.label}>
|
|
272
|
+
<FormField.Input as={Select.Input} onChange={e => handleChange(e)} />
|
|
273
|
+
<Select.Popper>
|
|
274
|
+
<Select.Card>
|
|
275
|
+
<Select.List>{item => <Select.Item>{item.label}</Select.Item>}</Select.List>
|
|
276
|
+
</Select.Card>
|
|
277
|
+
</Select.Popper>
|
|
278
|
+
</Select>
|
|
279
|
+
</FormField.Field>
|
|
280
|
+
</FormField>
|
|
302
281
|
```
|
|
303
282
|
|
|
304
283
|
### Grouped Items
|
|
305
284
|
|
|
306
|
-
In order to group items,
|
|
285
|
+
In order to group items, use the static item API with **`Menu.Group`** inside **`Select.List`**, and
|
|
286
|
+
still pass **`items`** whose ids match each **`Select.Item`** **`data-id`**.
|
|
307
287
|
|
|
308
288
|
<ExampleCodeBlock code={GroupedItems} />
|
|
309
289
|
|
|
@@ -313,6 +293,188 @@ Select and its subcomponents support custom styling via the `cs` prop. For more
|
|
|
313
293
|
our
|
|
314
294
|
["How To Customize Styles"](https://workday.github.io/canvas-kit/?path=/docs/styling-guides-customizing-styles--docs).
|
|
315
295
|
|
|
296
|
+
## Accessibility
|
|
297
|
+
|
|
298
|
+
The primary accessibility goal for `Select` is a visible, persistent label and a single choice from
|
|
299
|
+
a known list that assistive technology identifies as a combobox. Use **`Select`** when the user must
|
|
300
|
+
pick one option. For multiple selections, use [**MultiSelect**](/docs/preview-multiselect--docs).
|
|
301
|
+
For a value outside a fixed list, use [**Combobox**](/features/combobox/). See
|
|
302
|
+
[FormField's accessibility documentation](/components/inputs/form-field/#accessibility) for label,
|
|
303
|
+
hint, error, and required wiring. This follows the WAI-ARIA
|
|
304
|
+
[Select-Only Combobox](https://www.w3.org/WAI/ARIA/apg/patterns/combobox/examples/combobox-select-only/)
|
|
305
|
+
pattern.
|
|
306
|
+
|
|
307
|
+
### Minimum Accessible Structure
|
|
308
|
+
|
|
309
|
+
Build on the [Basic Example](#basic-example): label first, then **`Select`** inside
|
|
310
|
+
**`FormField.Field`**, with the combobox, popup, list, and items in this order.
|
|
311
|
+
|
|
312
|
+
```tsx
|
|
313
|
+
import {FormField} from '@workday/canvas-kit-react/form-field';
|
|
314
|
+
import {Select} from '@workday/canvas-kit-react/select';
|
|
315
|
+
|
|
316
|
+
const options = ['E-mail', 'Phone', 'Fax'];
|
|
317
|
+
|
|
318
|
+
<FormField>
|
|
319
|
+
<FormField.Label>Contact</FormField.Label>
|
|
320
|
+
<FormField.Field>
|
|
321
|
+
<Select items={options}>
|
|
322
|
+
<FormField.Input as={Select.Input} />
|
|
323
|
+
<Select.Popper>
|
|
324
|
+
<Select.Card>
|
|
325
|
+
<Select.List>{item => <Select.Item>{item}</Select.Item>}</Select.List>
|
|
326
|
+
</Select.Card>
|
|
327
|
+
</Select.Popper>
|
|
328
|
+
</Select>
|
|
329
|
+
</FormField.Field>
|
|
330
|
+
</FormField>;
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
Every `Select` requires **`FormField`**, a visible **`FormField.Label`**, and
|
|
334
|
+
**`FormField.Input as={Select.Input}`** so the combobox has a programmatically determinable name,
|
|
335
|
+
relationships, and instructions. See
|
|
336
|
+
[FormField's accessibility documentation](/components/inputs/form-field/#accessibility) for hint,
|
|
337
|
+
error, and required wiring.
|
|
338
|
+
|
|
339
|
+
### Built-in Behaviors
|
|
340
|
+
|
|
341
|
+
Canvas Kit applies these automatically when you compose `Select` with `FormField` subcomponents.
|
|
342
|
+
**Do not duplicate them** in consuming code.
|
|
343
|
+
|
|
344
|
+
**ARIA and DOM** (_applied by subcomponents_):
|
|
345
|
+
|
|
346
|
+
- **`Select.Input`**: Visual `<input>` with `role="combobox"`, `aria-haspopup="listbox"`,
|
|
347
|
+
`aria-expanded` from menu visibility, `aria-autocomplete="list"` (do not change to `"none"`),
|
|
348
|
+
`aria-controls` pointing at the listbox id (`{modelId}-list`), and `aria-activedescendant` while
|
|
349
|
+
the list is open (removed when the list is closed). `autoComplete` is `"off"`. Keyboard characters
|
|
350
|
+
are not inserted into the input; type-ahead is handled by the model. **`FormField.Label`** (via
|
|
351
|
+
**`FormField.Input`**) is the accessible name of the combobox — do not add a second name on the
|
|
352
|
+
listbox.
|
|
353
|
+
- **Hidden form input**: A second input holds the selected id(s) for form submission. It is
|
|
354
|
+
`aria-hidden`, has `tabIndex={-1}`, and is not in the tab order. `onChange` and `name` apply to
|
|
355
|
+
this input. Focus and blur on a `ref` are forwarded to the visual combobox.
|
|
356
|
+
- **`Select.List`**: `role="listbox"` with an id that matches the combobox `aria-controls`. Options
|
|
357
|
+
are not in the tab order; keyboard focus stays on the combobox. Listbox labelling is library-owned
|
|
358
|
+
— do not set `aria-labelledby` (or `aria-label`) on **`Select.List`**.
|
|
359
|
+
- **`Select.Item`**: `role="option"` and `aria-selected` from selection state. Disabled options need
|
|
360
|
+
**`aria-disabled`** from application code (see **Accessibility Requirements**).
|
|
361
|
+
- **`Menu.Group`** (when used inside **`Select.List`**): `role="group"` with `aria-labelledby`
|
|
362
|
+
referencing the group heading (`title` or **`Menu.Group.Heading`**).
|
|
363
|
+
- **`Select.Item.Icon`** and the caret / start icons on **`Select.Input`**: Canvas Kit icons use
|
|
364
|
+
`role="presentation"` and `focusable="false"`. Decorative icons need no extra attributes.
|
|
365
|
+
- **`disabled` on `Select.Input`**: Maps to the native `disabled` attribute on both inputs; the
|
|
366
|
+
combobox is removed from the tab order.
|
|
367
|
+
- **`ref`**: Forwards to the visual combobox (`<input type="text" role="combobox">`).
|
|
368
|
+
|
|
369
|
+
**Keyboard** (_select-only combobox; focus remains on **`Select.Input`**_):
|
|
370
|
+
|
|
371
|
+
- <kbd>Tab</kbd> / <kbd>Shift</kbd>+<kbd>Tab</kbd> move to and from the combobox (native tab order).
|
|
372
|
+
Other keys are prevented from editing the input.
|
|
373
|
+
- Clicking **`FormField.Label`** moves focus to the combobox. Clicking the combobox opens or closes
|
|
374
|
+
the list.
|
|
375
|
+
- <kbd>ArrowDown</kbd> / <kbd>ArrowUp</kbd> open the list. While the list is open, those keys move
|
|
376
|
+
the active option (skipping ids in **`nonInteractiveIds`**). <kbd>Home</kbd> / <kbd>End</kbd> move
|
|
377
|
+
to the first or last option while the list is open.
|
|
378
|
+
- <kbd>Space</kbd> opens the list when it is closed and no type-ahead string is in progress. While
|
|
379
|
+
the list is open and type-ahead is empty, <kbd>Space</kbd> selects the active option and closes
|
|
380
|
+
the list.
|
|
381
|
+
- Printable characters type-ahead: with the list closed, matching options are selected; with the
|
|
382
|
+
list open, assistive focus moves to the matching option. Consecutive keys within 500ms form a
|
|
383
|
+
search string.
|
|
384
|
+
- <kbd>Enter</kbd> while the list is open selects the active option (unless **`aria-disabled`**) and
|
|
385
|
+
closes the list in single-select mode. It does not submit the form while the list is open.
|
|
386
|
+
- <kbd>Escape</kbd> closes the list. Blur also hides the list. After close, `aria-activedescendant`
|
|
387
|
+
is removed; the active option returns to the selected item when one is selected.
|
|
388
|
+
- Activating an option with the pointer keeps focus on the combobox and closes the list.
|
|
389
|
+
|
|
390
|
+
**Screen reader expectations** (_when built-in behaviors are used as intended_):
|
|
391
|
+
|
|
392
|
+
- On focus, assistive technology announces the field label and, when applicable: required state,
|
|
393
|
+
invalid state (`error="error"`), hint or error text via `aria-describedby`, and the current
|
|
394
|
+
selected text (or the placeholder when nothing is selected).
|
|
395
|
+
- The control is announced as a combobox. Collapsed vs expanded follows `aria-expanded`. While the
|
|
396
|
+
list is open, the active option is exposed through `aria-activedescendant`.
|
|
397
|
+
- Options are announced with selected or not-selected state (`aria-selected`). Disabled options are
|
|
398
|
+
announced as disabled when **`aria-disabled`** is set.
|
|
399
|
+
- The Caution state is visual only — `aria-invalid` is **not** set for `error="caution"`.
|
|
400
|
+
- Disabled comboboxes may be announced as unavailable and are skipped in the tab order.
|
|
401
|
+
- The hidden form input and decorative icons are not announced.
|
|
402
|
+
|
|
403
|
+
For rendered label, input, and hint association markup, see the DOM examples in
|
|
404
|
+
[FormField's Built-in Behaviors](/components/inputs/form-field/#built-in-behaviors).
|
|
405
|
+
|
|
406
|
+
### Accessibility Requirements
|
|
407
|
+
|
|
408
|
+
Required in application code for an accessible `Select`. Rows marked _(conditional)_ apply only when
|
|
409
|
+
the situation matches—otherwise omit.
|
|
410
|
+
|
|
411
|
+
**If no design spec is provided:** use a visible `FormField.Label`, wrap **`Select`** with
|
|
412
|
+
**`FormField`**, use **`FormField.Input as={Select.Input}`**, include **`Select.Popper`**,
|
|
413
|
+
**`Select.Card`**, **`Select.List`**, and **`Select.Item`**, and pass **`items`**. Omit `isHidden`,
|
|
414
|
+
omit a custom `id` unless testing or composition requires it, omit a `ref` unless programmatic focus
|
|
415
|
+
is required, omit **`disabled`**, **`nonInteractiveIds`**, icons, grouped list items, and a custom
|
|
416
|
+
**`placeholder`** unless the spec includes them.
|
|
417
|
+
|
|
418
|
+
**Programmatic focus** _(conditional — omit by default)_:
|
|
419
|
+
|
|
420
|
+
Use a ref when the product needs to move focus to the combobox after an action. Do not attach a
|
|
421
|
+
`ref` or call `focus()` unless the design or developer asks for it. See
|
|
422
|
+
[Ref Forwarding](#ref-forwarding) under Usage for a complete Storybook example (imports, `ref` on
|
|
423
|
+
**`FormField.Input as={Select.Input}`**, and a button that calls `focus()`).
|
|
424
|
+
|
|
425
|
+
**Disabled options** _(conditional)_:
|
|
426
|
+
|
|
427
|
+
When an option is unavailable, set **`nonInteractiveIds`** on **`Select`** and **`aria-disabled`**
|
|
428
|
+
on those **`Select.Item`**s. See [Disabled Items](#disabled-items) under Usage for a complete
|
|
429
|
+
Storybook example. Do not use styling alone.
|
|
430
|
+
|
|
431
|
+
| Requirement | How to satisfy |
|
|
432
|
+
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
433
|
+
| Input wiring | **`FormField.Input as={Select.Input}`** for the combobox, with **`Select.Popper`**, **`Select.Card`**, **`Select.List`**, and **`Select.Item`**. See [FormField accessibility](/components/inputs/form-field/#accessibility) for label, hint, error, and required wiring |
|
|
434
|
+
| Disabled combobox _(conditional)_ | `disabled` on **`FormField.Input as={Select.Input}`**. See [Disabled](#disabled) |
|
|
435
|
+
| Disabled options _(conditional)_ | **`nonInteractiveIds`** on **`Select`** (ids skipped by keyboard and type-ahead) **and** **`aria-disabled`** on those **`Select.Item`**s. See [Disabled Items](#disabled-items) |
|
|
436
|
+
| Grouped list items _(conditional)_ | Keep **`items`**. Inside **`Select.List`**, render static **`Menu.Group`** (`title` or **`Menu.Group.Heading`**) and **`Select.Item`**s with matching **`data-id`** — not `{item => …}`. See [Grouped Items](#grouped-items) |
|
|
437
|
+
| Option icons _(conditional)_ | **`Select.Item.Icon`** on each item; **`inputStartIcon`** on **`FormField.Input as={Select.Input}`** for the selected item. Decorative icons need no extra attributes; meaning beyond the label must be text |
|
|
438
|
+
| Custom placeholder _(conditional)_ | `placeholder` on **`FormField.Input as={Select.Input}`** only as short prompt text—never as the only name. Default is `"Choose an option"` |
|
|
439
|
+
| Programmatic focus _(conditional)_ | `ref` on **`FormField.Input as={Select.Input}`** and call `focus()` when moving focus to the field after an action—omit by default (see **Programmatic focus** above) |
|
|
440
|
+
|
|
441
|
+
**Summary for code generation:**
|
|
442
|
+
|
|
443
|
+
- **REQUIRED:** visible label, **`FormField.Input as={Select.Input}`**, popup list composition
|
|
444
|
+
(**`Select.Popper`**, **`Select.Card`**, **`Select.List`**, **`Select.Item`**), **`items`**.
|
|
445
|
+
Default list rendering is `{item => <Select.Item>{item}</Select.Item>}` (or `item.text` /
|
|
446
|
+
**`getTextValue`**).
|
|
447
|
+
- **CONDITIONAL:** disabled combobox, disabled options (`nonInteractiveIds` + `aria-disabled`),
|
|
448
|
+
grouped list items (**`items`** plus static **`Menu.Group`** / **`data-id`** children — do not
|
|
449
|
+
omit **`items`**), option icons, custom placeholder, programmatic focus via `ref`, **`getId`** and
|
|
450
|
+
**`getTextValue`** when item shape is not `{id, text}` (always pass **`getTextValue`** if custom
|
|
451
|
+
**`getId`** is not the display text), **`data-id`** on static JSX **`Select.Item`**s. See
|
|
452
|
+
[FormField accessibility](/components/inputs/form-field/#accessibility) for shared FormField
|
|
453
|
+
conditionals (hint/error, required, stable `id`).
|
|
454
|
+
|
|
455
|
+
### Anti-Patterns
|
|
456
|
+
|
|
457
|
+
Do **not** generate code that does the following (see **Accessibility Requirements** above for what
|
|
458
|
+
to supply instead):
|
|
459
|
+
|
|
460
|
+
- **Missing `FormField` wiring**: Do not use `Select` without **`FormField`** and
|
|
461
|
+
**`FormField.Label`**, and do not render a bare **`Select.Input`** when a **`FormField`** is
|
|
462
|
+
present. Use **`FormField.Input as={Select.Input}`** (see **Minimum accessible structure**). For
|
|
463
|
+
shared FormField anti-patterns (manual ARIA, placeholder-only labels, color-only errors, broken ID
|
|
464
|
+
references), see [FormField Anti-Patterns](/components/inputs/form-field/#anti-patterns).
|
|
465
|
+
- **Duplicating combobox or listbox ARIA**: Do not set `role`, `aria-haspopup`, `aria-expanded`,
|
|
466
|
+
`aria-autocomplete` (including `"none"`), `aria-controls`, `aria-activedescendant`,
|
|
467
|
+
`autoComplete`, or listbox `role` / `id` / `aria-labelledby` / `aria-label`. Do not make
|
|
468
|
+
**`Select.Item`** focusable — the active option is **`aria-activedescendant`** on the combobox.
|
|
469
|
+
- **Wrong component**: Do not use a native `<select>`, **`Menu`**, **`Combobox`**, **`TextInput`**,
|
|
470
|
+
or **`FormFieldGroup`** for a single submitted list value. Use
|
|
471
|
+
[**MultiSelect**](/docs/preview-multiselect--docs) when more than one option can be selected.
|
|
472
|
+
- **Item identity / grouping**: Do not set **`data-id`** on `{item => <Select.Item>}`. Do not omit
|
|
473
|
+
**`items`** when grouping, and do not group with a render callback alone — use **`Menu.Group`**
|
|
474
|
+
and **`data-id`** (see **Static item ids** and **Grouped list items**).
|
|
475
|
+
- **Free-text keyboard on the combobox**: Do not add `onKeyDown` that types into the input or calls
|
|
476
|
+
`preventDefault` on <kbd>Tab</kbd> — Select is select-only.
|
|
477
|
+
|
|
316
478
|
## Component API
|
|
317
479
|
|
|
318
480
|
<SymbolDoc name="Select" fileName="/react/" />
|
|
@@ -24,36 +24,30 @@ const items = [
|
|
|
24
24
|
];
|
|
25
25
|
|
|
26
26
|
export default () => {
|
|
27
|
-
const [selected, setSelected] = React.useState('');
|
|
28
|
-
|
|
29
27
|
return (
|
|
30
|
-
|
|
31
|
-
<FormField>
|
|
32
|
-
|
|
33
|
-
<
|
|
34
|
-
<
|
|
35
|
-
|
|
36
|
-
<Select.
|
|
37
|
-
<Select.
|
|
38
|
-
<
|
|
39
|
-
<
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
<
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
</Select>
|
|
55
|
-
</FormField.Field>
|
|
56
|
-
</FormField>
|
|
57
|
-
</>
|
|
28
|
+
<FormField>
|
|
29
|
+
<FormField.Label>Contact</FormField.Label>
|
|
30
|
+
<FormField.Field>
|
|
31
|
+
<Select items={items} getId={item => item.id} getTextValue={item => item.text}>
|
|
32
|
+
<FormField.Input as={Select.Input} />
|
|
33
|
+
<Select.Popper>
|
|
34
|
+
<Select.Card>
|
|
35
|
+
<Select.List>
|
|
36
|
+
<Menu.Group title="First Group">
|
|
37
|
+
<Select.Item data-id="first">First Item</Select.Item>
|
|
38
|
+
<Select.Item data-id="second">Second Item</Select.Item>
|
|
39
|
+
</Menu.Group>
|
|
40
|
+
<Menu.Group title="Second Group">
|
|
41
|
+
<Select.Item data-id="third">
|
|
42
|
+
Third Item (with a really, really, really long label)
|
|
43
|
+
</Select.Item>
|
|
44
|
+
<Select.Item data-id="fourth">Fourth Item</Select.Item>
|
|
45
|
+
</Menu.Group>
|
|
46
|
+
</Select.List>
|
|
47
|
+
</Select.Card>
|
|
48
|
+
</Select.Popper>
|
|
49
|
+
</Select>
|
|
50
|
+
</FormField.Field>
|
|
51
|
+
</FormField>
|
|
58
52
|
);
|
|
59
53
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@workday/canvas-kit-docs",
|
|
3
|
-
"version": "16.2.0-
|
|
3
|
+
"version": "16.2.0-0618-next.0",
|
|
4
4
|
"description": "Documentation components of Canvas Kit components",
|
|
5
5
|
"author": "Workday, Inc. (https://www.workday.com)",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -47,10 +47,10 @@
|
|
|
47
47
|
"@stackblitz/sdk": "^1.11.0",
|
|
48
48
|
"@storybook/csf": "0.0.1",
|
|
49
49
|
"@workday/canvas-expressive-icons-web": "1.0.2",
|
|
50
|
-
"@workday/canvas-kit-labs-react": "^16.2.0-
|
|
51
|
-
"@workday/canvas-kit-preview-react": "^16.2.0-
|
|
52
|
-
"@workday/canvas-kit-react": "^16.2.0-
|
|
53
|
-
"@workday/canvas-kit-styling": "^16.2.0-
|
|
50
|
+
"@workday/canvas-kit-labs-react": "^16.2.0-0618-next.0",
|
|
51
|
+
"@workday/canvas-kit-preview-react": "^16.2.0-0618-next.0",
|
|
52
|
+
"@workday/canvas-kit-react": "^16.2.0-0618-next.0",
|
|
53
|
+
"@workday/canvas-kit-styling": "^16.2.0-0618-next.0",
|
|
54
54
|
"@workday/canvas-system-icons-web": "^5.0.3",
|
|
55
55
|
"@workday/canvas-tokens-web": "^4.4.0",
|
|
56
56
|
"markdown-to-jsx": "^7.2.0",
|
|
@@ -63,5 +63,5 @@
|
|
|
63
63
|
"mkdirp": "^1.0.3",
|
|
64
64
|
"typescript": "5.0"
|
|
65
65
|
},
|
|
66
|
-
"gitHead": "
|
|
66
|
+
"gitHead": "ba328694a792ddcde9af773b023266cc890f0afd"
|
|
67
67
|
}
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import {useFormik} from 'formik';
|
|
2
|
-
|
|
3
|
-
import {PrimaryButton} from '@workday/canvas-kit-react/button';
|
|
4
|
-
import {FormField} from '@workday/canvas-kit-react/form-field';
|
|
5
|
-
import {Flex} from '@workday/canvas-kit-react/layout';
|
|
6
|
-
import {Select, useSelectModel} from '@workday/canvas-kit-react/select';
|
|
7
|
-
import {px2rem} from '@workday/canvas-kit-styling';
|
|
8
|
-
import {cloudArrowUpIcon, cloudIcon, commentIcon, userIcon} from '@workday/canvas-system-icons-web';
|
|
9
|
-
import {system} from '@workday/canvas-tokens-web';
|
|
10
|
-
|
|
11
|
-
export default [
|
|
12
|
-
{
|
|
13
|
-
label: 'Dessert Person by Claire Saffitz',
|
|
14
|
-
serverId: 1,
|
|
15
|
-
icon: commentIcon,
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
label: 'Elements of Pizza by Ken Forkish',
|
|
19
|
-
serverId: 2,
|
|
20
|
-
icon: cloudIcon,
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
label: 'Flour Water Salt Yeast by Ken Forkish',
|
|
24
|
-
serverId: 3,
|
|
25
|
-
icon: cloudArrowUpIcon,
|
|
26
|
-
},
|
|
27
|
-
{label: 'Mastering Pasta by Marc Verti', serverId: 4, icon: userIcon},
|
|
28
|
-
];
|
|
29
|
-
|
|
30
|
-
export default () => {
|
|
31
|
-
const formik = useFormik({
|
|
32
|
-
initialValues: {
|
|
33
|
-
selectedBook: '',
|
|
34
|
-
},
|
|
35
|
-
onSubmit: values => {
|
|
36
|
-
// Send data to server
|
|
37
|
-
setTimeout(() => {
|
|
38
|
-
alert(JSON.stringify(values, null, 2));
|
|
39
|
-
}, 0);
|
|
40
|
-
},
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
const selectModel = useSelectModel({
|
|
44
|
-
items: customOptionsMain,
|
|
45
|
-
getId: item => {
|
|
46
|
-
return item.serverId;
|
|
47
|
-
},
|
|
48
|
-
getTextValue: item => item.label,
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
return (
|
|
52
|
-
<form onSubmit={formik.handleSubmit} action=".">
|
|
53
|
-
<Flex cs={{gap: system.gap.sm, flexDirection: 'column', alignItems: 'flex-start'}}>
|
|
54
|
-
<FormField orientation="vertical" cs={{alignSelf: 'stretch', alignItems: 'normal'}}>
|
|
55
|
-
<Select model={selectModel}>
|
|
56
|
-
<FormField.Label>Choose a book</FormField.Label>
|
|
57
|
-
<FormField.Input
|
|
58
|
-
as={Select.Input}
|
|
59
|
-
name="selectedBook"
|
|
60
|
-
onChange={event => formik.setFieldValue('selectedBook', event.currentTarget.value)}
|
|
61
|
-
value={formik.values.selectedBook}
|
|
62
|
-
grow
|
|
63
|
-
/>
|
|
64
|
-
<Select.Popper>
|
|
65
|
-
<Select.Card>
|
|
66
|
-
<Select.List cs={{maxHeight: px2rem(200)}}>
|
|
67
|
-
{item => {
|
|
68
|
-
return (
|
|
69
|
-
<Select.Item data-id={item.serverId} data-text={item.label}>
|
|
70
|
-
<Select.Item.Icon icon={item.icon} />
|
|
71
|
-
{item.label}
|
|
72
|
-
</Select.Item>
|
|
73
|
-
);
|
|
74
|
-
}}
|
|
75
|
-
</Select.List>
|
|
76
|
-
</Select.Card>
|
|
77
|
-
</Select.Popper>
|
|
78
|
-
</Select>
|
|
79
|
-
</FormField>
|
|
80
|
-
<PrimaryButton type="submit">Submit</PrimaryButton>
|
|
81
|
-
</Flex>
|
|
82
|
-
</form>
|
|
83
|
-
);
|
|
84
|
-
};
|