ionbase-ui 0.84.0 → 0.88.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.
Files changed (57) hide show
  1. package/dist/components/Checkbox.d.ts +39 -0
  2. package/dist/components/Checkbox.d.ts.map +1 -1
  3. package/dist/components/Checkbox.js +77 -4
  4. package/dist/components/Checkbox.js.map +1 -1
  5. package/dist/components/Fieldset.d.ts +62 -0
  6. package/dist/components/Fieldset.d.ts.map +1 -0
  7. package/dist/components/Fieldset.js +58 -0
  8. package/dist/components/Fieldset.js.map +1 -0
  9. package/dist/components/MultiSelect.d.ts +90 -0
  10. package/dist/components/MultiSelect.d.ts.map +1 -0
  11. package/dist/components/MultiSelect.js +189 -0
  12. package/dist/components/MultiSelect.js.map +1 -0
  13. package/dist/components/Radio.d.ts +14 -0
  14. package/dist/components/Radio.d.ts.map +1 -1
  15. package/dist/components/Radio.js +15 -4
  16. package/dist/components/Radio.js.map +1 -1
  17. package/dist/components/SearchField.d.ts +36 -0
  18. package/dist/components/SearchField.d.ts.map +1 -0
  19. package/dist/components/SearchField.js +76 -0
  20. package/dist/components/SearchField.js.map +1 -0
  21. package/dist/components/Toolbar.d.ts +35 -0
  22. package/dist/components/Toolbar.d.ts.map +1 -0
  23. package/dist/components/Toolbar.js +81 -0
  24. package/dist/components/Toolbar.js.map +1 -0
  25. package/dist/components/index.d.ts +10 -2
  26. package/dist/components/index.d.ts.map +1 -1
  27. package/dist/components/index.js +5 -1
  28. package/dist/components/index.js.map +1 -1
  29. package/dist/figma-descriptions.json +97 -77
  30. package/dist/figma-map.json +228 -4
  31. package/dist/meta/Checkbox.json +8 -6
  32. package/dist/meta/CheckboxGroup.json +268 -0
  33. package/dist/meta/Combobox.json +8 -0
  34. package/dist/meta/Divider.json +2 -2
  35. package/dist/meta/Fieldset.json +162 -0
  36. package/dist/meta/MultiSelect.json +269 -0
  37. package/dist/meta/Radio.json +0 -1
  38. package/dist/meta/RadioGroup.json +59 -7
  39. package/dist/meta/SearchField.json +487 -0
  40. package/dist/meta/Select.json +2 -1
  41. package/dist/meta/Stepper.json +2 -2
  42. package/dist/meta/Tabs.json +3 -3
  43. package/dist/meta/Toolbar.json +130 -0
  44. package/dist/meta/components.json +1616 -238
  45. package/dist/meta/contrast.json +398 -74
  46. package/dist/meta/index.json +84 -8
  47. package/dist/meta/patterns/DataTable.json +33 -6
  48. package/dist/meta/patterns/Form.json +27 -2
  49. package/dist/meta/patterns/index.json +6 -2
  50. package/dist/styles/fieldset.css +65 -0
  51. package/dist/styles/index.css +4 -0
  52. package/dist/styles/multi-select.css +104 -0
  53. package/dist/styles/radio.css +0 -20
  54. package/dist/styles/search-field.css +70 -0
  55. package/dist/styles/toolbar.css +36 -0
  56. package/llms.txt +2 -2
  57. package/package.json +1 -1
@@ -0,0 +1,487 @@
1
+ {
2
+ "name": "SearchField",
3
+ "source": "src/components/SearchField.tsx",
4
+ "propsType": "SearchFieldProps",
5
+ "description": "SearchField — a text field for a search query.\n\nNOT `<Input type=\"search\">`. That gets the right input type and nothing\nelse. `useSearchField` adds what a search box owes its user:\n\n `role=\"searchbox\"`, so a screen reader announces a search field, not a\n text field. Enter calls `onSubmit` with the query. Escape clears it — a\n second Escape then reaches whatever the field sits in, so a search inside\n a dialog clears first and closes second. A clear button appears once there\n is something to clear, named in the user's language by React Aria.\n\nThe clear button is out of the tab order on purpose, as React Aria sets it:\nEscape is the keyboard's way to clear, and an extra tab stop in every search\nbox costs every keyboard user a keystroke. Pressing it puts focus back in the\nfield.\n\nThe box IS Input's — the component renders `.ion-input` and its size and\nstate classes, so a search field beside an Input in a toolbar matches it\nexactly and cannot drift. Same arrangement as NumberInput.",
6
+ "import": "import { SearchField } from 'ionbase-ui';",
7
+ "status": "stable",
8
+ "summary": "A text field for a search query: role=\"searchbox\", Enter submits, Escape clears, and a clear button once there is something to clear. Input's box and sizes.",
9
+ "useWhen": [
10
+ "the user types to search or filter a list, a table or a page — the search above a DataTable, the filter at the top of a Sidebar",
11
+ "the query is free text that narrows what is shown, not a value chosen from a list"
12
+ ],
13
+ "useInstead": [
14
+ {
15
+ "when": "the typed text picks one value from a known list — an assignee, a country",
16
+ "use": "Combobox",
17
+ "why": "a combobox commits a choice and offers the options; a search field commits a query and offers nothing"
18
+ },
19
+ {
20
+ "when": "the user is looking for a page or an action anywhere in the product",
21
+ "use": "CommandPalette",
22
+ "why": "that is global and keyboard-first; a SearchField searches the content in front of it"
23
+ },
24
+ {
25
+ "when": "it is ordinary text entry — a name, an email — that happens to be used for lookup later",
26
+ "use": "Input",
27
+ "why": "announcing a searchbox promises search behaviour: Escape clears, Enter searches"
28
+ }
29
+ ],
30
+ "composition": {
31
+ "order": [
32
+ "SearchField"
33
+ ],
34
+ "note": "Filter as the user types with `onChange`, or search on Enter with `onSubmit` — pick one per field and say which in the placeholder or label. In a table toolbar, give it `aria-label` naming what it searches.",
35
+ "example": "<SearchField aria-label=\"Search agents\" placeholder=\"Search by name or purpose\" value={query} onChange={setQuery} />"
36
+ },
37
+ "variants": {
38
+ "size": {
39
+ "sm": {
40
+ "use": "toolbars, table headers and Sidebar filters, beside small Buttons"
41
+ },
42
+ "md": {
43
+ "use": "the default"
44
+ },
45
+ "lg": {
46
+ "use": "a page whose main task is searching"
47
+ }
48
+ }
49
+ },
50
+ "a11y": {
51
+ "role": "searchbox",
52
+ "guarantees": [
53
+ "the input is role=\"searchbox\" and type=\"search\", so it is announced as a search field",
54
+ "Escape clears the query; a second Escape is left for whatever contains the field, so a search in a dialog clears before it closes",
55
+ "Enter calls onSubmit with the query",
56
+ "the clear button is named by React Aria in the user's language, appears only when there is something to clear, and returns focus to the field",
57
+ "the clear button is out of the tab order on purpose: Escape is the keyboard's way to clear, and an extra tab stop in every search box costs every keyboard user a keystroke",
58
+ "the browser's own cancel button is hidden, so there are never two"
59
+ ],
60
+ "requires": [
61
+ "`label`, or an `aria-label` naming what is searched when no visible label is rendered — \"Search\" alone does not say what"
62
+ ],
63
+ "notes": [
64
+ "When filtering as the user types, announce the result count with a polite live region near the results. The field cannot know how many results its query produced; the list does."
65
+ ]
66
+ },
67
+ "antiPatterns": [
68
+ {
69
+ "dont": "<Input type=\"search\"> with a magnifier as leadingIcon",
70
+ "why": "it looks the same and has none of the behaviour: no searchbox role, no Escape to clear, no labelled clear button"
71
+ },
72
+ {
73
+ "dont": "placeholder as the only name",
74
+ "why": "a placeholder disappears once the user types, and is not a reliable accessible name. Pass `aria-label` or `label`"
75
+ },
76
+ {
77
+ "dont": "a separate Search button beside a field that already filters as you type",
78
+ "why": "it teaches the user that nothing happens until they press it, and it does nothing when they do"
79
+ }
80
+ ],
81
+ "stylesheet": "src/styles/search-field.css",
82
+ "tokens": [
83
+ "--border-focus",
84
+ "--border-width-thick",
85
+ "--icon-default",
86
+ "--icon-secondary",
87
+ "--ion-input-height",
88
+ "--ion-input-icon-size",
89
+ "--radius-sm",
90
+ "--spacing-4",
91
+ "--spacing-8",
92
+ "--surface-default",
93
+ "--surface-hover",
94
+ "--surface-pressed"
95
+ ],
96
+ "props": {
97
+ "size": {
98
+ "type": "SearchFieldSize | undefined",
99
+ "required": false,
100
+ "origin": "own",
101
+ "description": "Input's sizes: Small, Medium, Large.",
102
+ "values": [
103
+ "sm",
104
+ "md",
105
+ "lg"
106
+ ],
107
+ "default": "md"
108
+ },
109
+ "className": {
110
+ "type": "string | undefined",
111
+ "required": false,
112
+ "origin": "own",
113
+ "description": "Class names for the control box (`.ion-input`)."
114
+ },
115
+ "wrapperClassName": {
116
+ "type": "string | undefined",
117
+ "required": false,
118
+ "origin": "own",
119
+ "description": "Class names for the `.ion-field` wrapper when a label or helper is shown."
120
+ },
121
+ "enterKeyHint": {
122
+ "type": "\"done\" | \"enter\" | \"go\" | \"next\" | \"previous\" | \"search\" | \"send\" | undefined",
123
+ "required": false,
124
+ "origin": "aria",
125
+ "description": "An enumerated attribute that defines what action label or icon to preset for the enter key on\nvirtual keyboards. See\n[MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/enterkeyhint).",
126
+ "values": [
127
+ "done",
128
+ "enter",
129
+ "go",
130
+ "next",
131
+ "previous",
132
+ "search",
133
+ "send"
134
+ ]
135
+ },
136
+ "type": {
137
+ "type": "(string & {}) | \"search\" | \"text\" | \"url\" | \"tel\" | \"email\" | \"password\" | undefined",
138
+ "required": false,
139
+ "origin": "aria",
140
+ "description": "The type of input to render. See\n[MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdeftype).",
141
+ "tags": {
142
+ "default": "'search'"
143
+ }
144
+ },
145
+ "onSubmit": {
146
+ "type": "((value: string) => void) | undefined",
147
+ "required": false,
148
+ "origin": "other",
149
+ "description": "Handler that is called when the SearchField is submitted."
150
+ },
151
+ "onClear": {
152
+ "type": "(() => void) | undefined",
153
+ "required": false,
154
+ "origin": "other",
155
+ "description": "Handler that is called when the clear button is pressed."
156
+ },
157
+ "isDisabled": {
158
+ "type": "boolean | undefined",
159
+ "required": false,
160
+ "origin": "aria",
161
+ "description": "Whether the input is disabled."
162
+ },
163
+ "isReadOnly": {
164
+ "type": "boolean | undefined",
165
+ "required": false,
166
+ "origin": "aria",
167
+ "description": "Whether the input can be selected but not changed by the user."
168
+ },
169
+ "isRequired": {
170
+ "type": "boolean | undefined",
171
+ "required": false,
172
+ "origin": "aria",
173
+ "description": "Whether user input is required on the input before form submission."
174
+ },
175
+ "isInvalid": {
176
+ "type": "boolean | undefined",
177
+ "required": false,
178
+ "origin": "aria",
179
+ "description": "Whether the input value is invalid."
180
+ },
181
+ "validationState": {
182
+ "type": "ValidationState | undefined",
183
+ "required": false,
184
+ "origin": "aria",
185
+ "values": [
186
+ "valid",
187
+ "invalid"
188
+ ],
189
+ "tags": {
190
+ "deprecated": "Use `isInvalid` instead."
191
+ }
192
+ },
193
+ "validationBehavior": {
194
+ "type": "\"aria\" | \"native\" | undefined",
195
+ "required": false,
196
+ "origin": "aria",
197
+ "description": "Whether to use native HTML form validation to prevent form submission\nwhen the value is missing or invalid, or mark the field as required\nor invalid via ARIA.",
198
+ "values": [
199
+ "aria",
200
+ "native"
201
+ ],
202
+ "tags": {
203
+ "default": "'aria'"
204
+ }
205
+ },
206
+ "validate": {
207
+ "type": "((value: string) => ValidationError | true | null | undefined) | undefined",
208
+ "required": false,
209
+ "origin": "aria",
210
+ "description": "A function that returns an error message if a given value is invalid.\nValidation errors are displayed to the user when the form is submitted\nif `validationBehavior=\"native\"`. For realtime validation, use the `isInvalid`\nprop instead."
211
+ },
212
+ "description": {
213
+ "type": "ReactNode",
214
+ "required": false,
215
+ "origin": "aria",
216
+ "description": "A description for the field. Provides a hint such as specific requirements for what to choose."
217
+ },
218
+ "errorMessage": {
219
+ "type": "ReactNode | ((v: ValidationResult) => ReactNode)",
220
+ "required": false,
221
+ "origin": "aria",
222
+ "description": "An error message for the field."
223
+ },
224
+ "autoFocus": {
225
+ "type": "boolean | undefined",
226
+ "required": false,
227
+ "origin": "aria",
228
+ "description": "Whether the element should receive focus on render."
229
+ },
230
+ "onFocus": {
231
+ "type": "((e: FocusEvent<HTMLInputElement, Element>) => void) | undefined",
232
+ "required": false,
233
+ "origin": "aria",
234
+ "description": "Handler that is called when the element receives focus."
235
+ },
236
+ "onBlur": {
237
+ "type": "((e: FocusEvent<HTMLInputElement, Element>) => void) | undefined",
238
+ "required": false,
239
+ "origin": "aria",
240
+ "description": "Handler that is called when the element loses focus."
241
+ },
242
+ "onFocusChange": {
243
+ "type": "((isFocused: boolean) => void) | undefined",
244
+ "required": false,
245
+ "origin": "aria",
246
+ "description": "Handler that is called when the element's focus status changes."
247
+ },
248
+ "onKeyDown": {
249
+ "type": "((e: KeyboardEvent) => void) | undefined",
250
+ "required": false,
251
+ "origin": "aria",
252
+ "description": "Handler that is called when a key is pressed."
253
+ },
254
+ "onKeyUp": {
255
+ "type": "((e: KeyboardEvent) => void) | undefined",
256
+ "required": false,
257
+ "origin": "aria",
258
+ "description": "Handler that is called when a key is released."
259
+ },
260
+ "placeholder": {
261
+ "type": "string | undefined",
262
+ "required": false,
263
+ "origin": "aria",
264
+ "description": "Temporary text that occupies the text input when it is empty."
265
+ },
266
+ "value": {
267
+ "type": "string | undefined",
268
+ "required": false,
269
+ "origin": "aria",
270
+ "description": "The current value (controlled)."
271
+ },
272
+ "defaultValue": {
273
+ "type": "string | undefined",
274
+ "required": false,
275
+ "origin": "aria",
276
+ "description": "The default value (uncontrolled)."
277
+ },
278
+ "onChange": {
279
+ "type": "((value: string) => void) | undefined",
280
+ "required": false,
281
+ "origin": "aria",
282
+ "description": "Handler that is called when the value changes."
283
+ },
284
+ "label": {
285
+ "type": "ReactNode",
286
+ "required": false,
287
+ "origin": "aria",
288
+ "description": "The content to display as the label."
289
+ },
290
+ "id": {
291
+ "type": "string | undefined",
292
+ "required": false,
293
+ "origin": "aria",
294
+ "description": "The element's unique identifier. See\n[MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id)."
295
+ },
296
+ "spellCheck": {
297
+ "type": "string | undefined",
298
+ "required": false,
299
+ "origin": "aria",
300
+ "description": "An enumerated attribute that defines whether the element may be checked for spelling errors.\nSee [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/spellcheck)."
301
+ },
302
+ "autoCorrect": {
303
+ "type": "string | undefined",
304
+ "required": false,
305
+ "origin": "aria",
306
+ "description": "An attribute that takes as its value a space-separated string that describes what, if any, type\nof autocomplete functionality the input should provide. See\n[MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#autocomplete)."
307
+ },
308
+ "inputMode": {
309
+ "type": "\"none\" | \"search\" | \"text\" | \"url\" | \"tel\" | \"email\" | \"numeric\" | \"decimal\" | undefined",
310
+ "required": false,
311
+ "origin": "aria",
312
+ "description": "Hints at the type of data that might be entered by the user while editing the element or its\ncontents. See\n[MDN](https://html.spec.whatwg.org/multipage/interaction.html#input-modalities:-the-inputmode-attribute).",
313
+ "values": [
314
+ "none",
315
+ "search",
316
+ "text",
317
+ "url",
318
+ "tel",
319
+ "email",
320
+ "numeric",
321
+ "decimal"
322
+ ]
323
+ },
324
+ "aria-activedescendant": {
325
+ "type": "string | undefined",
326
+ "required": false,
327
+ "origin": "aria",
328
+ "description": "Identifies the currently active element when DOM focus is on a composite widget, textbox,\ngroup, or application."
329
+ },
330
+ "aria-autocomplete": {
331
+ "type": "\"inline\" | \"list\" | \"none\" | \"both\" | undefined",
332
+ "required": false,
333
+ "origin": "aria",
334
+ "description": "Indicates whether inputting text could trigger display of one or more predictions of the user's\nintended value for an input and specifies how predictions would be presented if they are made.",
335
+ "values": [
336
+ "inline",
337
+ "list",
338
+ "none",
339
+ "both"
340
+ ]
341
+ },
342
+ "aria-controls": {
343
+ "type": "string | undefined",
344
+ "required": false,
345
+ "origin": "aria",
346
+ "description": "Identifies the element (or elements) whose contents or presence are controlled by the current\nelement."
347
+ },
348
+ "aria-describedby": {
349
+ "type": "string | undefined",
350
+ "required": false,
351
+ "origin": "aria",
352
+ "description": "Identifies the element (or elements) that describes the object."
353
+ },
354
+ "aria-details": {
355
+ "type": "string | undefined",
356
+ "required": false,
357
+ "origin": "aria",
358
+ "description": "Identifies the element (or elements) that provide a detailed, extended description for the\nobject."
359
+ },
360
+ "aria-errormessage": {
361
+ "type": "string | undefined",
362
+ "required": false,
363
+ "origin": "aria",
364
+ "description": "Identifies the element that provides an error message for the object."
365
+ },
366
+ "aria-haspopup": {
367
+ "type": "boolean | \"true\" | \"false\" | \"menu\" | \"listbox\" | \"tree\" | \"grid\" | \"dialog\" | undefined",
368
+ "required": false,
369
+ "origin": "aria",
370
+ "description": "Indicates the availability and type of interactive popup element, such as menu or dialog, that\ncan be triggered by an element."
371
+ },
372
+ "aria-label": {
373
+ "type": "string | undefined",
374
+ "required": false,
375
+ "origin": "aria",
376
+ "description": "Defines a string value that labels the current element."
377
+ },
378
+ "aria-labelledby": {
379
+ "type": "string | undefined",
380
+ "required": false,
381
+ "origin": "aria",
382
+ "description": "Identifies the element (or elements) that labels the current element."
383
+ },
384
+ "onCopy": {
385
+ "type": "ClipboardEventHandler<HTMLInputElement> | undefined",
386
+ "required": false,
387
+ "origin": "aria",
388
+ "description": "Handler that is called when the user copies text. See\n[MDN](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/oncopy)."
389
+ },
390
+ "onCut": {
391
+ "type": "ClipboardEventHandler<HTMLInputElement> | undefined",
392
+ "required": false,
393
+ "origin": "aria",
394
+ "description": "Handler that is called when the user cuts text. See\n[MDN](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/oncut)."
395
+ },
396
+ "onPaste": {
397
+ "type": "ClipboardEventHandler<HTMLInputElement> | undefined",
398
+ "required": false,
399
+ "origin": "aria",
400
+ "description": "Handler that is called when the user pastes text. See\n[MDN](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/onpaste)."
401
+ },
402
+ "onCompositionEnd": {
403
+ "type": "CompositionEventHandler<HTMLInputElement> | undefined",
404
+ "required": false,
405
+ "origin": "aria",
406
+ "description": "Handler that is called when a text composition system completes or cancels the current text\ncomposition session. See\n[MDN](https://developer.mozilla.org/en-US/docs/Web/API/Element/compositionend_event)."
407
+ },
408
+ "onCompositionStart": {
409
+ "type": "CompositionEventHandler<HTMLInputElement> | undefined",
410
+ "required": false,
411
+ "origin": "aria",
412
+ "description": "Handler that is called when a text composition system starts a new text composition session.\nSee [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Element/compositionstart_event)."
413
+ },
414
+ "onCompositionUpdate": {
415
+ "type": "CompositionEventHandler<HTMLInputElement> | undefined",
416
+ "required": false,
417
+ "origin": "aria",
418
+ "description": "Handler that is called when a new character is received in the current text composition\nsession. See\n[MDN](https://developer.mozilla.org/en-US/docs/Web/API/Element/compositionupdate_event)."
419
+ },
420
+ "onBeforeInput": {
421
+ "type": "FormEventHandler<HTMLInputElement> | undefined",
422
+ "required": false,
423
+ "origin": "aria",
424
+ "description": "Handler that is called when the input value is about to be modified. See\n[MDN](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/beforeinput_event)."
425
+ },
426
+ "onInput": {
427
+ "type": "FormEventHandler<HTMLInputElement> | undefined",
428
+ "required": false,
429
+ "origin": "aria",
430
+ "description": "Handler that is called when the input value is modified. See\n[MDN](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/input_event)."
431
+ },
432
+ "onSelect": {
433
+ "type": "ReactEventHandler<HTMLInputElement> | undefined",
434
+ "required": false,
435
+ "origin": "aria",
436
+ "description": "Handler that is called when text in the input is selected. See\n[MDN](https://developer.mozilla.org/en-US/docs/Web/API/Element/select_event)."
437
+ },
438
+ "form": {
439
+ "type": "string | undefined",
440
+ "required": false,
441
+ "origin": "aria",
442
+ "description": "The `<form>` element to associate the input with.\nThe value of this attribute must be the id of a `<form>` in the same document.\nSee [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input#form)."
443
+ },
444
+ "name": {
445
+ "type": "string | undefined",
446
+ "required": false,
447
+ "origin": "aria",
448
+ "description": "The name of the input element, used when submitting an HTML form. See\n[MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefname)."
449
+ },
450
+ "autoComplete": {
451
+ "type": "string | undefined",
452
+ "required": false,
453
+ "origin": "aria",
454
+ "description": "Describes the type of autocomplete functionality the input should provide if any. See\n[MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefautocomplete)."
455
+ },
456
+ "maxLength": {
457
+ "type": "number | undefined",
458
+ "required": false,
459
+ "origin": "aria",
460
+ "description": "The maximum number of characters supported by the input. See\n[MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefmaxlength)."
461
+ },
462
+ "minLength": {
463
+ "type": "number | undefined",
464
+ "required": false,
465
+ "origin": "aria",
466
+ "description": "The minimum number of characters required by the input. See\n[MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefminlength)."
467
+ },
468
+ "pattern": {
469
+ "type": "string | undefined",
470
+ "required": false,
471
+ "origin": "aria",
472
+ "description": "Regex pattern that the value of the input must match to be valid. See\n[MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefpattern)."
473
+ },
474
+ "excludeFromTabOrder": {
475
+ "type": "boolean | undefined",
476
+ "required": false,
477
+ "origin": "aria",
478
+ "description": "Whether to exclude the element from the sequential tab order. If true,\nthe element will not be focusable via the keyboard by tabbing. This should\nbe avoided except in rare scenarios where an alternative means of accessing\nthe element or its functionality via the keyboard is available."
479
+ }
480
+ },
481
+ "propCounts": {
482
+ "own": 3,
483
+ "aria": 51,
484
+ "dom": 264,
485
+ "other": 2
486
+ }
487
+ }
@@ -27,7 +27,8 @@
27
27
  },
28
28
  {
29
29
  "when": "the user may pick more than one",
30
- "use": "Checkbox"
30
+ "use": "MultiSelect",
31
+ "why": "a native <select multiple> needs Ctrl or Cmd for a second pick and cannot filter; for a handful of options use CheckboxGroup"
31
32
  }
32
33
  ],
33
34
  "variants": {
@@ -115,8 +115,8 @@
115
115
  "origin": "own",
116
116
  "description": "`horizontal` for a page-width header above the form, `vertical` for a side\nrail. Below 40rem a horizontal stepper hides every label but the current\none, so it does not need a second variant for mobile.",
117
117
  "values": [
118
- "horizontal",
119
- "vertical"
118
+ "vertical",
119
+ "horizontal"
120
120
  ]
121
121
  },
122
122
  "children": {
@@ -163,13 +163,13 @@
163
163
  "default": "md"
164
164
  },
165
165
  "orientation": {
166
- "type": "\"horizontal\" | \"vertical\" | undefined",
166
+ "type": "\"vertical\" | \"horizontal\" | undefined",
167
167
  "required": false,
168
168
  "origin": "own",
169
169
  "description": "Drives both the arrow-key axis and the track layout.\n\n`vertical` is keyboard- and ARIA-complete — up/down move between tabs, and\nthe track stacks — but its *decoration* is not: the underline rule and the\npill track's padding are still written for the horizontal axis only. Those\nare Figma's to specify, not this file's to invent. See tabs.css.",
170
170
  "values": [
171
- "horizontal",
172
- "vertical"
171
+ "vertical",
172
+ "horizontal"
173
173
  ],
174
174
  "tags": {
175
175
  "default": "'horizontal'"
@@ -0,0 +1,130 @@
1
+ {
2
+ "name": "Toolbar",
3
+ "source": "src/components/Toolbar.tsx",
4
+ "propsType": "ToolbarProps",
5
+ "description": "Toolbar — a row of controls that act on one thing, reached as one stop.\n\nReact Aria's `useToolbar` gives it `role=\"toolbar\"` and `aria-orientation`,\narrow keys between its controls (mirrored in right-to-left), Tab that leaves\nthe whole toolbar rather than walking every button, and focus returned to the\ncontrol used last when Tab brings the user back. A toolbar inside a toolbar\nbecomes a `group`, so nesting one for grouping is safe.\n\nEvery control keeps its own tab stop in the DOM — React Aria moves focus to\nthe first or last control on Tab and lets the browser take it from there —\nso nothing here rewrites a child's `tabIndex`, and a control that mounts\nlater (the bulk actions appearing on selection) needs no registration.\n\nWHAT IT IS NOT FOR\n\nA filter bar. Tab leaves a toolbar in one press, so a search field inside one\nstrands the filters after it: Tab skips them and ← → belong to the caret.\nThat is WAI-ARIA's own caution about text fields in toolbars. A table's\nsearch and filters stay ordinary tab stops; the toolbar is the row of\nactions — the batch bar, a record's actions, an editor's formatting.",
6
+ "import": "import { Toolbar } from 'ionbase-ui';",
7
+ "status": "stable",
8
+ "summary": "A row of controls that act on one thing, reached as one tab stop: arrow keys between the controls, Tab out in one press, and back to the control used last.",
9
+ "useWhen": [
10
+ "a set of actions on one selection or one record — the batch bar over a table, a run's Resume/Pause/Stop, an editor's formatting",
11
+ "the row has enough controls that tabbing through each one costs a keyboard user more than it gives"
12
+ ],
13
+ "useInstead": [
14
+ {
15
+ "when": "the row holds a search field or filters",
16
+ "use": "a plain flex row",
17
+ "why": "Tab leaves a toolbar in one press and ← → belong to the caret, so a text field inside strands every filter after it — WAI-ARIA's own caution"
18
+ },
19
+ {
20
+ "when": "two or three actions at the top of a page",
21
+ "use": "PageHeader",
22
+ "why": "its `actions` slot is a row of ordinary tab stops, which for a few buttons is what a keyboard user expects"
23
+ },
24
+ {
25
+ "when": "the controls are one choice among options",
26
+ "use": "SegmentedControl",
27
+ "why": "that is a radio group with a selected value; a toolbar holds independent actions"
28
+ }
29
+ ],
30
+ "composition": {
31
+ "order": [
32
+ "Toolbar",
33
+ "Button",
34
+ "Divider",
35
+ "MenuTrigger"
36
+ ],
37
+ "note": "Buttons in the order they are read, a vertical Divider between groups, and a MenuTrigger with an icon-only Button last for the overflow. Name it with `aria-label` for what it acts on — \"Bulk actions\", not \"Toolbar\".",
38
+ "example": "<Toolbar aria-label=\"Bulk actions\"><Button size=\"sm\" variant=\"secondary\">Pause</Button><Divider orientation=\"vertical\" /><Button size=\"sm\" variant=\"destructive\">Delete 3</Button></Toolbar>"
39
+ },
40
+ "variants": {
41
+ "orientation": {
42
+ "horizontal": {
43
+ "use": "the default — ← → move between controls; wraps rather than overflowing"
44
+ },
45
+ "vertical": {
46
+ "use": "a side rail of tools — ↑ ↓ move between controls"
47
+ }
48
+ }
49
+ },
50
+ "slots": {
51
+ "children": {
52
+ "accepts": "Button, MenuTrigger, SegmentedControl, Divider, Toolbar",
53
+ "note": "a nested Toolbar becomes a named `group`, and the outer toolbar keeps the arrow keys"
54
+ }
55
+ },
56
+ "a11y": {
57
+ "role": "toolbar, with aria-orientation",
58
+ "guarantees": [
59
+ "React Aria's `useToolbar`: arrow keys move between controls, skipping disabled ones and separators, and are mirrored in right-to-left",
60
+ "Tab leaves the whole toolbar in one press, and Shift+Tab or Tab back in returns to the control used last",
61
+ "a text field, native select, combobox, slider or radio inside keeps its own arrow keys — the caret moves and the value changes instead of focus jumping",
62
+ "↓ still reaches a MenuTrigger in a horizontal toolbar, so an overflow menu opens as it does anywhere else"
63
+ ],
64
+ "requires": [
65
+ "`aria-label` or `aria-labelledby` naming what the toolbar acts on"
66
+ ]
67
+ },
68
+ "antiPatterns": [
69
+ {
70
+ "dont": "a table's search field and filters inside a Toolbar",
71
+ "why": "Tab from the search field leaves the toolbar, so the filters after it can only be reached by Shift+Tab and arrows"
72
+ },
73
+ {
74
+ "dont": "a Toolbar with one button",
75
+ "why": "a single stop gains nothing from arrow keys, and screen readers announce a toolbar the user has to learn"
76
+ },
77
+ {
78
+ "dont": "an unnamed Toolbar",
79
+ "why": "\"toolbar\" alone does not say what the buttons act on, and pages with two cannot be told apart"
80
+ }
81
+ ],
82
+ "stylesheet": "src/styles/toolbar.css",
83
+ "tokens": [
84
+ "--spacing-4",
85
+ "--spacing-8"
86
+ ],
87
+ "props": {
88
+ "aria-label": {
89
+ "type": "string | undefined",
90
+ "required": false,
91
+ "origin": "own",
92
+ "description": "Names the toolbar — \"Bulk actions\", \"Formatting\". Required, or `aria-labelledby`.",
93
+ "tags": {
94
+ "see": "aria-labelledby."
95
+ }
96
+ },
97
+ "aria-labelledby": {
98
+ "type": "string | undefined",
99
+ "required": false,
100
+ "origin": "own",
101
+ "description": "Identifies the element (or elements) that labels the current element.",
102
+ "tags": {
103
+ "see": "aria-describedby."
104
+ }
105
+ },
106
+ "orientation": {
107
+ "type": "ToolbarOrientation | undefined",
108
+ "required": false,
109
+ "origin": "own",
110
+ "description": "Which arrow keys move between controls. Horizontal: ← →; vertical: ↑ ↓.",
111
+ "values": [
112
+ "vertical",
113
+ "horizontal"
114
+ ],
115
+ "default": "horizontal"
116
+ },
117
+ "children": {
118
+ "type": "React.ReactNode",
119
+ "required": false,
120
+ "origin": "own",
121
+ "description": "Buttons, MenuTriggers, a SegmentedControl, and a vertical Divider between groups."
122
+ }
123
+ },
124
+ "propCounts": {
125
+ "own": 4,
126
+ "aria": 0,
127
+ "dom": 274,
128
+ "other": 0
129
+ }
130
+ }