ionbase-ui 0.86.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.
- package/dist/components/MultiSelect.d.ts +90 -0
- package/dist/components/MultiSelect.d.ts.map +1 -0
- package/dist/components/MultiSelect.js +189 -0
- package/dist/components/MultiSelect.js.map +1 -0
- package/dist/components/Toolbar.d.ts +35 -0
- package/dist/components/Toolbar.d.ts.map +1 -0
- package/dist/components/Toolbar.js +81 -0
- package/dist/components/Toolbar.js.map +1 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +2 -0
- package/dist/components/index.js.map +1 -1
- package/dist/figma-descriptions.json +89 -79
- package/dist/figma-map.json +97 -2
- package/dist/meta/CheckboxGroup.json +2 -2
- package/dist/meta/Combobox.json +8 -0
- package/dist/meta/MultiSelect.json +269 -0
- package/dist/meta/Select.json +2 -1
- package/dist/meta/Toolbar.json +130 -0
- package/dist/meta/components.json +412 -4
- package/dist/meta/contrast.json +28 -0
- package/dist/meta/index.json +26 -1
- package/dist/meta/patterns/DataTable.json +21 -2
- package/dist/meta/patterns/index.json +3 -1
- package/dist/styles/index.css +2 -0
- package/dist/styles/multi-select.css +104 -0
- package/dist/styles/toolbar.css +36 -0
- package/llms.txt +2 -2
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"package": "ionbase-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.88.0",
|
|
4
4
|
"generated": "by scripts/build-meta.mjs — do not edit; intent lives in meta/*.json",
|
|
5
5
|
"hooks": [
|
|
6
6
|
"useAgentRun",
|
|
@@ -3303,8 +3303,8 @@
|
|
|
3303
3303
|
},
|
|
3304
3304
|
{
|
|
3305
3305
|
"when": "the options are many, or space is tight",
|
|
3306
|
-
"use": "
|
|
3307
|
-
"why": "past about seven options a list of boxes is longer than the form around it"
|
|
3306
|
+
"use": "MultiSelect",
|
|
3307
|
+
"why": "past about seven options a list of boxes is longer than the form around it; MultiSelect filters them and shows the chosen ones as tags"
|
|
3308
3308
|
},
|
|
3309
3309
|
{
|
|
3310
3310
|
"when": "there is one on/off choice",
|
|
@@ -3854,6 +3854,11 @@
|
|
|
3854
3854
|
"use": "Select",
|
|
3855
3855
|
"why": "the native control brings keyboard handling and the mobile platform picker for free; this rebuilds all of it"
|
|
3856
3856
|
},
|
|
3857
|
+
{
|
|
3858
|
+
"when": "more than one value may be picked",
|
|
3859
|
+
"use": "MultiSelect",
|
|
3860
|
+
"why": "its input holds only the filter text, the list stays open between picks, and the chosen values show as tags"
|
|
3861
|
+
},
|
|
3857
3862
|
{
|
|
3858
3863
|
"when": "there are two or three mutually exclusive choices worth showing at once",
|
|
3859
3864
|
"use": "RadioGroup"
|
|
@@ -3895,6 +3900,9 @@
|
|
|
3895
3900
|
"requires": [
|
|
3896
3901
|
"`label`, or an `aria-label` when no visible label is rendered",
|
|
3897
3902
|
"`emptyLabel` wording that says why nothing is listed, if the default is too terse"
|
|
3903
|
+
],
|
|
3904
|
+
"notes": [
|
|
3905
|
+
"While the list is open, React Aria hides everything outside the field and the list from assistive technology. That is the platform pattern for a combobox; a whole-page accessibility scan taken with the list open reports the hidden page, not this control."
|
|
3898
3906
|
]
|
|
3899
3907
|
},
|
|
3900
3908
|
"antiPatterns": [
|
|
@@ -8506,6 +8514,275 @@
|
|
|
8506
8514
|
"other": 0
|
|
8507
8515
|
}
|
|
8508
8516
|
},
|
|
8517
|
+
"MultiSelect": {
|
|
8518
|
+
"name": "MultiSelect",
|
|
8519
|
+
"source": "src/components/MultiSelect.tsx",
|
|
8520
|
+
"propsType": "MultiSelectProps",
|
|
8521
|
+
"description": "MultiSelect — a text field that filters a list, with any number of selected\nvalues shown as removable tags beneath it.\n\nWHY IT IS ITS OWN COMPONENT, NOT `Combobox selectionMode=\"multiple\"`\n\nThe two differ in what the field holds. Combobox's input shows the chosen\nlabel — typing edits the value. Here the input only ever holds the filter\ntext, the value lives in the tags, and choosing an option leaves the list\nopen for the next one. One prop switching the meaning of the text in the\nbox is the kind of contract agents get wrong in generated code.\n\nWHAT REACT ARIA GIVES IT\n\n`useComboBoxState` and `useComboBox` in `selectionMode: 'multiple'`: the\nlistbox is `aria-multiselectable`, Enter and click toggle an option without\nclosing the list, the filter text clears after each pick, and native\n`required` is set only while nothing is chosen — \"at least one\", the same\nrule CheckboxGroup enforces.\n\nWHAT IT ADDS\n\n - The tags. A TagGroup under the field, named by the field's label, one\n tab stop, Delete or the × to remove. The selection must be visible with\n the list closed, and \"3 selected\" hides which three.\n - The value is announced with the field. React Aria points the input's\n `aria-describedby` at a value element; this fills it with the chosen\n labels joined by `Intl.ListFormat`, so \"Billing, Legal and Ops\" is read\n in the user's language with no string shipped for it.\n - Backspace in an empty field removes the last value, which is what\n every tag input on the web has taught people to expect.\n - Focus lands back in the field when the last tag is removed, instead of\n falling to <body> with the TagGroup that held it.",
|
|
8522
|
+
"import": "import { MultiSelect } from 'ionbase-ui';",
|
|
8523
|
+
"status": "stable",
|
|
8524
|
+
"summary": "A text field that filters a list, with any number of values chosen. The choices show as removable tags beneath the field and are read with it.",
|
|
8525
|
+
"useWhen": [
|
|
8526
|
+
"the user picks several values from a list too long to show as checkboxes — teams, regions, labels, assignees",
|
|
8527
|
+
"a table filter can match more than one value — \"Status is Failing or Paused\""
|
|
8528
|
+
],
|
|
8529
|
+
"useInstead": [
|
|
8530
|
+
{
|
|
8531
|
+
"when": "exactly one value is picked",
|
|
8532
|
+
"use": "Combobox",
|
|
8533
|
+
"why": "Combobox's input shows the chosen label; here the input only ever holds the filter text, and the list stays open for the next pick"
|
|
8534
|
+
},
|
|
8535
|
+
{
|
|
8536
|
+
"when": "there are about seven options or fewer",
|
|
8537
|
+
"use": "CheckboxGroup",
|
|
8538
|
+
"why": "every option visible at once beats typing to find one, and nothing is hidden behind a popover"
|
|
8539
|
+
},
|
|
8540
|
+
{
|
|
8541
|
+
"when": "the values are free text the user invents, not options from a list",
|
|
8542
|
+
"use": "TagGroup",
|
|
8543
|
+
"why": "MultiSelect only chooses from `options`; a free-text tag input is a TagGroup beside an Input"
|
|
8544
|
+
}
|
|
8545
|
+
],
|
|
8546
|
+
"composition": {
|
|
8547
|
+
"order": [
|
|
8548
|
+
"MultiSelect"
|
|
8549
|
+
],
|
|
8550
|
+
"note": "Pass the full `options` list; filtering, the tags and the announcement are the component's. In a table's filter bar, give it `aria-label` and `hideTags`, and list its values in the table's active-filters TagGroup — one removable tag per value, not the same tags twice.",
|
|
8551
|
+
"example": "<MultiSelect label=\"Notify teams\" options={teams} value={teamIds} onChange={setTeamIds} placeholder=\"Search teams\" />"
|
|
8552
|
+
},
|
|
8553
|
+
"variants": {
|
|
8554
|
+
"size": {
|
|
8555
|
+
"sm": {
|
|
8556
|
+
"use": "dense forms, table filters"
|
|
8557
|
+
},
|
|
8558
|
+
"md": {
|
|
8559
|
+
"use": "the default"
|
|
8560
|
+
},
|
|
8561
|
+
"lg": {
|
|
8562
|
+
"use": "prominent single-field forms"
|
|
8563
|
+
}
|
|
8564
|
+
}
|
|
8565
|
+
},
|
|
8566
|
+
"slots": {
|
|
8567
|
+
"label": {
|
|
8568
|
+
"accepts": "text",
|
|
8569
|
+
"note": "names the field and the tags beneath it"
|
|
8570
|
+
},
|
|
8571
|
+
"description": {
|
|
8572
|
+
"accepts": "text",
|
|
8573
|
+
"note": "replaced by `errorMessage` while `isInvalid` is set"
|
|
8574
|
+
},
|
|
8575
|
+
"errorMessage": {
|
|
8576
|
+
"accepts": "text",
|
|
8577
|
+
"note": "shown only while `isInvalid` is set"
|
|
8578
|
+
},
|
|
8579
|
+
"emptyLabel": {
|
|
8580
|
+
"accepts": "text",
|
|
8581
|
+
"note": "shown in the list when the filter matches nothing"
|
|
8582
|
+
}
|
|
8583
|
+
},
|
|
8584
|
+
"a11y": {
|
|
8585
|
+
"role": "combobox, controlling a listbox that is aria-multiselectable",
|
|
8586
|
+
"guarantees": [
|
|
8587
|
+
"React Aria's multi-select combobox: arrow keys move through the list while focus stays in the input, Enter or click toggles an option, and the list stays open for the next pick",
|
|
8588
|
+
"the chosen labels are on the input's `aria-describedby`, joined by `Intl.ListFormat` — read with the field in the user's language, with no string shipped for it",
|
|
8589
|
+
"the chosen values are a TagGroup named by the field's label: one tab stop, arrow keys between tags, Delete or the × to remove",
|
|
8590
|
+
"Backspace in an empty field removes the last value; with text in the field it only edits the text",
|
|
8591
|
+
"removing the last tag returns focus to the field instead of dropping it on <body>",
|
|
8592
|
+
"`isRequired` marks the field required only while nothing is chosen — at least one"
|
|
8593
|
+
],
|
|
8594
|
+
"requires": [
|
|
8595
|
+
"`label`, or `aria-label` when there is no visible label — it names the tags as well as the field"
|
|
8596
|
+
],
|
|
8597
|
+
"notes": [
|
|
8598
|
+
"While the list is open, React Aria hides everything outside the field and the list from assistive technology, the tags included. That is the platform pattern for a combobox, not a defect: the chosen options are marked selected in the list itself."
|
|
8599
|
+
]
|
|
8600
|
+
},
|
|
8601
|
+
"antiPatterns": [
|
|
8602
|
+
{
|
|
8603
|
+
"dont": "a Combobox that appends each pick to a TagGroup by hand",
|
|
8604
|
+
"why": "the list closes after every pick, the input shows the last label, and nothing announces what is chosen"
|
|
8605
|
+
},
|
|
8606
|
+
{
|
|
8607
|
+
"dont": "a native <select multiple>",
|
|
8608
|
+
"why": "it needs Ctrl or Cmd to pick a second option, which most people never discover, and it cannot filter"
|
|
8609
|
+
},
|
|
8610
|
+
{
|
|
8611
|
+
"dont": "a count in place of the values — \"3 selected\"",
|
|
8612
|
+
"why": "it hides which three; the tags show them and the field reads them"
|
|
8613
|
+
},
|
|
8614
|
+
{
|
|
8615
|
+
"dont": "`hideTags` with nowhere else showing the values",
|
|
8616
|
+
"why": "the field shows only the filter text, so the choice is invisible until the list is opened"
|
|
8617
|
+
}
|
|
8618
|
+
],
|
|
8619
|
+
"stylesheet": "src/styles/multi-select.css",
|
|
8620
|
+
"tokens": [
|
|
8621
|
+
"--border-disabled",
|
|
8622
|
+
"--border-primary-strong",
|
|
8623
|
+
"--border-stronger",
|
|
8624
|
+
"--border-width-default",
|
|
8625
|
+
"--border-width-thick",
|
|
8626
|
+
"--font-weight-regular",
|
|
8627
|
+
"--icon-on-color",
|
|
8628
|
+
"--ion-shadow-raised-flush-xs",
|
|
8629
|
+
"--radius-xs",
|
|
8630
|
+
"--spacing-16",
|
|
8631
|
+
"--spacing-2",
|
|
8632
|
+
"--spacing-4",
|
|
8633
|
+
"--spacing-8",
|
|
8634
|
+
"--surface-default",
|
|
8635
|
+
"--surface-disabled",
|
|
8636
|
+
"--surface-hover",
|
|
8637
|
+
"--surface-primary",
|
|
8638
|
+
"--type-body-line-height"
|
|
8639
|
+
],
|
|
8640
|
+
"props": {
|
|
8641
|
+
"options": {
|
|
8642
|
+
"type": "readonly ComboboxOption[]",
|
|
8643
|
+
"required": true,
|
|
8644
|
+
"origin": "own",
|
|
8645
|
+
"description": "The full option list. Filtering happens here, against what is typed."
|
|
8646
|
+
},
|
|
8647
|
+
"label": {
|
|
8648
|
+
"type": "React.ReactNode",
|
|
8649
|
+
"required": false,
|
|
8650
|
+
"origin": "own",
|
|
8651
|
+
"description": "Field label. Required for a usable control — see `a11y.requires`."
|
|
8652
|
+
},
|
|
8653
|
+
"aria-label": {
|
|
8654
|
+
"type": "string | undefined",
|
|
8655
|
+
"required": false,
|
|
8656
|
+
"origin": "own",
|
|
8657
|
+
"description": "Names the field, and its tags, when there is no visible `label`."
|
|
8658
|
+
},
|
|
8659
|
+
"description": {
|
|
8660
|
+
"type": "React.ReactNode",
|
|
8661
|
+
"required": false,
|
|
8662
|
+
"origin": "own",
|
|
8663
|
+
"description": "Helper text below the field."
|
|
8664
|
+
},
|
|
8665
|
+
"errorMessage": {
|
|
8666
|
+
"type": "React.ReactNode",
|
|
8667
|
+
"required": false,
|
|
8668
|
+
"origin": "own",
|
|
8669
|
+
"description": "Replaces the helper text when `isInvalid` is set."
|
|
8670
|
+
},
|
|
8671
|
+
"isInvalid": {
|
|
8672
|
+
"type": "boolean | undefined",
|
|
8673
|
+
"required": false,
|
|
8674
|
+
"origin": "own"
|
|
8675
|
+
},
|
|
8676
|
+
"isDisabled": {
|
|
8677
|
+
"type": "boolean | undefined",
|
|
8678
|
+
"required": false,
|
|
8679
|
+
"origin": "own"
|
|
8680
|
+
},
|
|
8681
|
+
"isReadOnly": {
|
|
8682
|
+
"type": "boolean | undefined",
|
|
8683
|
+
"required": false,
|
|
8684
|
+
"origin": "own"
|
|
8685
|
+
},
|
|
8686
|
+
"isRequired": {
|
|
8687
|
+
"type": "boolean | undefined",
|
|
8688
|
+
"required": false,
|
|
8689
|
+
"origin": "own",
|
|
8690
|
+
"description": "At least one value must be chosen."
|
|
8691
|
+
},
|
|
8692
|
+
"size": {
|
|
8693
|
+
"type": "MultiSelectSize | undefined",
|
|
8694
|
+
"required": false,
|
|
8695
|
+
"origin": "own",
|
|
8696
|
+
"description": "Matches Input's `Size` variant: Small, Medium, Large.",
|
|
8697
|
+
"values": [
|
|
8698
|
+
"sm",
|
|
8699
|
+
"md",
|
|
8700
|
+
"lg"
|
|
8701
|
+
]
|
|
8702
|
+
},
|
|
8703
|
+
"placeholder": {
|
|
8704
|
+
"type": "string | undefined",
|
|
8705
|
+
"required": false,
|
|
8706
|
+
"origin": "own"
|
|
8707
|
+
},
|
|
8708
|
+
"value": {
|
|
8709
|
+
"type": "readonly string[] | undefined",
|
|
8710
|
+
"required": false,
|
|
8711
|
+
"origin": "own",
|
|
8712
|
+
"description": "The selected values (controlled), in the order they were chosen."
|
|
8713
|
+
},
|
|
8714
|
+
"defaultValue": {
|
|
8715
|
+
"type": "readonly string[] | undefined",
|
|
8716
|
+
"required": false,
|
|
8717
|
+
"origin": "own",
|
|
8718
|
+
"description": "The initially selected values (uncontrolled)."
|
|
8719
|
+
},
|
|
8720
|
+
"onChange": {
|
|
8721
|
+
"type": "((value: string[]) => void) | undefined",
|
|
8722
|
+
"required": false,
|
|
8723
|
+
"origin": "own",
|
|
8724
|
+
"description": "Receives the whole new selection."
|
|
8725
|
+
},
|
|
8726
|
+
"inputValue": {
|
|
8727
|
+
"type": "string | undefined",
|
|
8728
|
+
"required": false,
|
|
8729
|
+
"origin": "own",
|
|
8730
|
+
"description": "Controlled filter text. Usually only needed for remote filtering."
|
|
8731
|
+
},
|
|
8732
|
+
"onInputChange": {
|
|
8733
|
+
"type": "((value: string) => void) | undefined",
|
|
8734
|
+
"required": false,
|
|
8735
|
+
"origin": "own"
|
|
8736
|
+
},
|
|
8737
|
+
"hideTags": {
|
|
8738
|
+
"type": "boolean | undefined",
|
|
8739
|
+
"required": false,
|
|
8740
|
+
"origin": "own",
|
|
8741
|
+
"description": "Leave the tags out, when the chosen values are already on screen as\nremovable tags — a table's active-filters row. The values are still read\nwith the field, and still marked in the list."
|
|
8742
|
+
},
|
|
8743
|
+
"emptyLabel": {
|
|
8744
|
+
"type": "React.ReactNode",
|
|
8745
|
+
"required": false,
|
|
8746
|
+
"origin": "own",
|
|
8747
|
+
"description": "Shown in place of the list when nothing matches."
|
|
8748
|
+
},
|
|
8749
|
+
"buttonLabel": {
|
|
8750
|
+
"type": "string | undefined",
|
|
8751
|
+
"required": false,
|
|
8752
|
+
"origin": "own",
|
|
8753
|
+
"description": "Accessible label for the disclosure button."
|
|
8754
|
+
},
|
|
8755
|
+
"name": {
|
|
8756
|
+
"type": "string | undefined",
|
|
8757
|
+
"required": false,
|
|
8758
|
+
"origin": "own",
|
|
8759
|
+
"description": "Posts every selected value under this name, for an uncontrolled form."
|
|
8760
|
+
},
|
|
8761
|
+
"className": {
|
|
8762
|
+
"type": "string | undefined",
|
|
8763
|
+
"required": false,
|
|
8764
|
+
"origin": "own",
|
|
8765
|
+
"description": "Class names for the field box (`.ion-input`)."
|
|
8766
|
+
},
|
|
8767
|
+
"wrapperClassName": {
|
|
8768
|
+
"type": "string | undefined",
|
|
8769
|
+
"required": false,
|
|
8770
|
+
"origin": "own",
|
|
8771
|
+
"description": "Class names for the `.ion-field` wrapper."
|
|
8772
|
+
},
|
|
8773
|
+
"id": {
|
|
8774
|
+
"type": "string | undefined",
|
|
8775
|
+
"required": false,
|
|
8776
|
+
"origin": "own"
|
|
8777
|
+
}
|
|
8778
|
+
},
|
|
8779
|
+
"propCounts": {
|
|
8780
|
+
"own": 23,
|
|
8781
|
+
"aria": 0,
|
|
8782
|
+
"dom": 0,
|
|
8783
|
+
"other": 0
|
|
8784
|
+
}
|
|
8785
|
+
},
|
|
8509
8786
|
"NavItem": {
|
|
8510
8787
|
"name": "NavItem",
|
|
8511
8788
|
"source": "src/components/NavItem.tsx",
|
|
@@ -11987,7 +12264,8 @@
|
|
|
11987
12264
|
},
|
|
11988
12265
|
{
|
|
11989
12266
|
"when": "the user may pick more than one",
|
|
11990
|
-
"use": "
|
|
12267
|
+
"use": "MultiSelect",
|
|
12268
|
+
"why": "a native <select multiple> needs Ctrl or Cmd for a second pick and cannot filter; for a handful of options use CheckboxGroup"
|
|
11991
12269
|
}
|
|
11992
12270
|
],
|
|
11993
12271
|
"variants": {
|
|
@@ -16077,6 +16355,136 @@
|
|
|
16077
16355
|
"other": 0
|
|
16078
16356
|
}
|
|
16079
16357
|
},
|
|
16358
|
+
"Toolbar": {
|
|
16359
|
+
"name": "Toolbar",
|
|
16360
|
+
"source": "src/components/Toolbar.tsx",
|
|
16361
|
+
"propsType": "ToolbarProps",
|
|
16362
|
+
"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.",
|
|
16363
|
+
"import": "import { Toolbar } from 'ionbase-ui';",
|
|
16364
|
+
"status": "stable",
|
|
16365
|
+
"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.",
|
|
16366
|
+
"useWhen": [
|
|
16367
|
+
"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",
|
|
16368
|
+
"the row has enough controls that tabbing through each one costs a keyboard user more than it gives"
|
|
16369
|
+
],
|
|
16370
|
+
"useInstead": [
|
|
16371
|
+
{
|
|
16372
|
+
"when": "the row holds a search field or filters",
|
|
16373
|
+
"use": "a plain flex row",
|
|
16374
|
+
"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"
|
|
16375
|
+
},
|
|
16376
|
+
{
|
|
16377
|
+
"when": "two or three actions at the top of a page",
|
|
16378
|
+
"use": "PageHeader",
|
|
16379
|
+
"why": "its `actions` slot is a row of ordinary tab stops, which for a few buttons is what a keyboard user expects"
|
|
16380
|
+
},
|
|
16381
|
+
{
|
|
16382
|
+
"when": "the controls are one choice among options",
|
|
16383
|
+
"use": "SegmentedControl",
|
|
16384
|
+
"why": "that is a radio group with a selected value; a toolbar holds independent actions"
|
|
16385
|
+
}
|
|
16386
|
+
],
|
|
16387
|
+
"composition": {
|
|
16388
|
+
"order": [
|
|
16389
|
+
"Toolbar",
|
|
16390
|
+
"Button",
|
|
16391
|
+
"Divider",
|
|
16392
|
+
"MenuTrigger"
|
|
16393
|
+
],
|
|
16394
|
+
"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\".",
|
|
16395
|
+
"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>"
|
|
16396
|
+
},
|
|
16397
|
+
"variants": {
|
|
16398
|
+
"orientation": {
|
|
16399
|
+
"horizontal": {
|
|
16400
|
+
"use": "the default — ← → move between controls; wraps rather than overflowing"
|
|
16401
|
+
},
|
|
16402
|
+
"vertical": {
|
|
16403
|
+
"use": "a side rail of tools — ↑ ↓ move between controls"
|
|
16404
|
+
}
|
|
16405
|
+
}
|
|
16406
|
+
},
|
|
16407
|
+
"slots": {
|
|
16408
|
+
"children": {
|
|
16409
|
+
"accepts": "Button, MenuTrigger, SegmentedControl, Divider, Toolbar",
|
|
16410
|
+
"note": "a nested Toolbar becomes a named `group`, and the outer toolbar keeps the arrow keys"
|
|
16411
|
+
}
|
|
16412
|
+
},
|
|
16413
|
+
"a11y": {
|
|
16414
|
+
"role": "toolbar, with aria-orientation",
|
|
16415
|
+
"guarantees": [
|
|
16416
|
+
"React Aria's `useToolbar`: arrow keys move between controls, skipping disabled ones and separators, and are mirrored in right-to-left",
|
|
16417
|
+
"Tab leaves the whole toolbar in one press, and Shift+Tab or Tab back in returns to the control used last",
|
|
16418
|
+
"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",
|
|
16419
|
+
"↓ still reaches a MenuTrigger in a horizontal toolbar, so an overflow menu opens as it does anywhere else"
|
|
16420
|
+
],
|
|
16421
|
+
"requires": [
|
|
16422
|
+
"`aria-label` or `aria-labelledby` naming what the toolbar acts on"
|
|
16423
|
+
]
|
|
16424
|
+
},
|
|
16425
|
+
"antiPatterns": [
|
|
16426
|
+
{
|
|
16427
|
+
"dont": "a table's search field and filters inside a Toolbar",
|
|
16428
|
+
"why": "Tab from the search field leaves the toolbar, so the filters after it can only be reached by Shift+Tab and arrows"
|
|
16429
|
+
},
|
|
16430
|
+
{
|
|
16431
|
+
"dont": "a Toolbar with one button",
|
|
16432
|
+
"why": "a single stop gains nothing from arrow keys, and screen readers announce a toolbar the user has to learn"
|
|
16433
|
+
},
|
|
16434
|
+
{
|
|
16435
|
+
"dont": "an unnamed Toolbar",
|
|
16436
|
+
"why": "\"toolbar\" alone does not say what the buttons act on, and pages with two cannot be told apart"
|
|
16437
|
+
}
|
|
16438
|
+
],
|
|
16439
|
+
"stylesheet": "src/styles/toolbar.css",
|
|
16440
|
+
"tokens": [
|
|
16441
|
+
"--spacing-4",
|
|
16442
|
+
"--spacing-8"
|
|
16443
|
+
],
|
|
16444
|
+
"props": {
|
|
16445
|
+
"aria-label": {
|
|
16446
|
+
"type": "string | undefined",
|
|
16447
|
+
"required": false,
|
|
16448
|
+
"origin": "own",
|
|
16449
|
+
"description": "Names the toolbar — \"Bulk actions\", \"Formatting\". Required, or `aria-labelledby`.",
|
|
16450
|
+
"tags": {
|
|
16451
|
+
"see": "aria-labelledby."
|
|
16452
|
+
}
|
|
16453
|
+
},
|
|
16454
|
+
"aria-labelledby": {
|
|
16455
|
+
"type": "string | undefined",
|
|
16456
|
+
"required": false,
|
|
16457
|
+
"origin": "own",
|
|
16458
|
+
"description": "Identifies the element (or elements) that labels the current element.",
|
|
16459
|
+
"tags": {
|
|
16460
|
+
"see": "aria-describedby."
|
|
16461
|
+
}
|
|
16462
|
+
},
|
|
16463
|
+
"orientation": {
|
|
16464
|
+
"type": "ToolbarOrientation | undefined",
|
|
16465
|
+
"required": false,
|
|
16466
|
+
"origin": "own",
|
|
16467
|
+
"description": "Which arrow keys move between controls. Horizontal: ← →; vertical: ↑ ↓.",
|
|
16468
|
+
"values": [
|
|
16469
|
+
"vertical",
|
|
16470
|
+
"horizontal"
|
|
16471
|
+
],
|
|
16472
|
+
"default": "horizontal"
|
|
16473
|
+
},
|
|
16474
|
+
"children": {
|
|
16475
|
+
"type": "React.ReactNode",
|
|
16476
|
+
"required": false,
|
|
16477
|
+
"origin": "own",
|
|
16478
|
+
"description": "Buttons, MenuTriggers, a SegmentedControl, and a vertical Divider between groups."
|
|
16479
|
+
}
|
|
16480
|
+
},
|
|
16481
|
+
"propCounts": {
|
|
16482
|
+
"own": 4,
|
|
16483
|
+
"aria": 0,
|
|
16484
|
+
"dom": 274,
|
|
16485
|
+
"other": 0
|
|
16486
|
+
}
|
|
16487
|
+
},
|
|
16080
16488
|
"ToolCall": {
|
|
16081
16489
|
"name": "ToolCall",
|
|
16082
16490
|
"source": "src/components/ToolCall.tsx",
|
package/dist/meta/contrast.json
CHANGED
|
@@ -4002,6 +4002,34 @@
|
|
|
4002
4002
|
"ratio": 5.38,
|
|
4003
4003
|
"min": 4.5
|
|
4004
4004
|
},
|
|
4005
|
+
{
|
|
4006
|
+
"component": "multi-select",
|
|
4007
|
+
"context": "ion-multi-select-menu ion-multi-select-menu__option",
|
|
4008
|
+
"state": "selected",
|
|
4009
|
+
"fg": "--icon-on-color",
|
|
4010
|
+
"bg": "--surface-primary",
|
|
4011
|
+
"backdrop": null,
|
|
4012
|
+
"kind": "non-text",
|
|
4013
|
+
"mode": "Light",
|
|
4014
|
+
"fgHex": "#ffffff",
|
|
4015
|
+
"bgHex": "#1c62e3",
|
|
4016
|
+
"ratio": 5.38,
|
|
4017
|
+
"min": 3
|
|
4018
|
+
},
|
|
4019
|
+
{
|
|
4020
|
+
"component": "multi-select",
|
|
4021
|
+
"context": "ion-multi-select-menu ion-multi-select-menu__option",
|
|
4022
|
+
"state": "selected",
|
|
4023
|
+
"fg": "--icon-on-color",
|
|
4024
|
+
"bg": "--surface-primary",
|
|
4025
|
+
"backdrop": null,
|
|
4026
|
+
"kind": "non-text",
|
|
4027
|
+
"mode": "Dark",
|
|
4028
|
+
"fgHex": "#ffffff",
|
|
4029
|
+
"bgHex": "#1c62e3",
|
|
4030
|
+
"ratio": 5.38,
|
|
4031
|
+
"min": 3
|
|
4032
|
+
},
|
|
4005
4033
|
{
|
|
4006
4034
|
"component": "nav-item",
|
|
4007
4035
|
"context": "ion-nav-item--current ion-nav-item__icon",
|
package/dist/meta/index.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"package": "ionbase-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.88.0",
|
|
4
4
|
"usage": "Pick a component here, then read dist/meta/<Name>.json for its full contract.",
|
|
5
5
|
"hooks": [
|
|
6
6
|
"useAgentRun",
|
|
@@ -636,6 +636,19 @@
|
|
|
636
636
|
"detail": "dist/meta/Modal.json",
|
|
637
637
|
"hasIntent": true
|
|
638
638
|
},
|
|
639
|
+
"MultiSelect": {
|
|
640
|
+
"summary": "A text field that filters a list, with any number of values chosen. The choices show as removable tags beneath the field and are read with it.",
|
|
641
|
+
"status": "stable",
|
|
642
|
+
"variants": {
|
|
643
|
+
"size": [
|
|
644
|
+
"sm",
|
|
645
|
+
"md",
|
|
646
|
+
"lg"
|
|
647
|
+
]
|
|
648
|
+
},
|
|
649
|
+
"detail": "dist/meta/MultiSelect.json",
|
|
650
|
+
"hasIntent": true
|
|
651
|
+
},
|
|
639
652
|
"NavItem": {
|
|
640
653
|
"summary": "A primary navigation destination. Renders an <a> when given `href`, a <button> otherwise.",
|
|
641
654
|
"status": "stable",
|
|
@@ -1154,6 +1167,18 @@
|
|
|
1154
1167
|
"detail": "dist/meta/Toggle.json",
|
|
1155
1168
|
"hasIntent": true
|
|
1156
1169
|
},
|
|
1170
|
+
"Toolbar": {
|
|
1171
|
+
"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.",
|
|
1172
|
+
"status": "stable",
|
|
1173
|
+
"variants": {
|
|
1174
|
+
"orientation": [
|
|
1175
|
+
"vertical",
|
|
1176
|
+
"horizontal"
|
|
1177
|
+
]
|
|
1178
|
+
},
|
|
1179
|
+
"detail": "dist/meta/Toolbar.json",
|
|
1180
|
+
"hasIntent": true
|
|
1181
|
+
},
|
|
1157
1182
|
"ToolCall": {
|
|
1158
1183
|
"summary": "The evidence behind one step of an agent run: which tool, with what input, and what came back — collapsed by default, with any failure shown without a click.",
|
|
1159
1184
|
"status": "stable",
|
|
@@ -12,15 +12,17 @@
|
|
|
12
12
|
"TableRow",
|
|
13
13
|
"TableCell",
|
|
14
14
|
"Checkbox",
|
|
15
|
+
"Toolbar",
|
|
15
16
|
"Button",
|
|
16
17
|
"Badge",
|
|
17
18
|
"Alert",
|
|
18
19
|
"SearchField",
|
|
20
|
+
"MultiSelect",
|
|
19
21
|
"TagGroup"
|
|
20
22
|
],
|
|
21
23
|
"structure": [
|
|
22
|
-
"A toolbar above the table: a SearchField (size sm, with an aria-label naming what it searches), filter controls
|
|
23
|
-
"Under the toolbar, once any filter is applied: a TagGroup of the active filters, each removable on its own
|
|
24
|
+
"A toolbar above the table: a SearchField (size sm, with an aria-label naming what it searches), filter controls — a MultiSelect with `hideTags` for any filter that can match more than one value — and, once something is selected, the bulk actions in a Toolbar named for what they act on. The search and filters stay ordinary tab stops outside it — see Toolbar's contract.",
|
|
25
|
+
"Under the toolbar, once any filter is applied: a TagGroup of the active filters, each removable on its own — one tag per value of a multi-value filter — beside a Clear all Button. When the last one goes the row goes with it, so move focus to the SearchField.",
|
|
24
26
|
"Table with a TableHead whose first cell carries the select-all Checkbox, and a TableBody whose rows each carry their own.",
|
|
25
27
|
"Sortable columns: every header that sorts gets `sortDirection` — the current direction on the sorted column, `none` on the others — so each shows it can be sorted before anyone tries.",
|
|
26
28
|
"One region below the table for pagination or a load-more Button.",
|
|
@@ -71,6 +73,9 @@
|
|
|
71
73
|
"isIndeterminate",
|
|
72
74
|
"isDisabled"
|
|
73
75
|
],
|
|
76
|
+
"Toolbar": [
|
|
77
|
+
"aria-label"
|
|
78
|
+
],
|
|
74
79
|
"Button": [
|
|
75
80
|
"variant",
|
|
76
81
|
"size"
|
|
@@ -91,6 +96,15 @@
|
|
|
91
96
|
"onChange",
|
|
92
97
|
"placeholder",
|
|
93
98
|
"aria-label"
|
|
99
|
+
],
|
|
100
|
+
"MultiSelect": [
|
|
101
|
+
"size",
|
|
102
|
+
"aria-label",
|
|
103
|
+
"options",
|
|
104
|
+
"value",
|
|
105
|
+
"onChange",
|
|
106
|
+
"hideTags",
|
|
107
|
+
"placeholder"
|
|
94
108
|
]
|
|
95
109
|
},
|
|
96
110
|
"variantsUsed": {
|
|
@@ -160,6 +174,11 @@
|
|
|
160
174
|
{
|
|
161
175
|
"dont": "an Input with type=\"search\" and a magnifier icon as the table's search",
|
|
162
176
|
"why": "it has no searchbox role, no Escape to clear and no labelled clear button — SearchField is the same box with that behaviour"
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
"dont": "a multi-value filter as a MultiSelect showing its own tags above the active-filters row",
|
|
180
|
+
"do": "`hideTags` on the MultiSelect, and one active-filter tag per value",
|
|
181
|
+
"why": "the same values drawn twice, each removable, in two places that can disagree about focus"
|
|
163
182
|
}
|
|
164
183
|
]
|
|
165
184
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"package": "ionbase-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.88.0",
|
|
4
4
|
"usage": "A pattern is a documented composition of components, not a component. Read one here, then read the contracts of what it composes.",
|
|
5
5
|
"patterns": {
|
|
6
6
|
"AgentRun": {
|
|
@@ -52,10 +52,12 @@
|
|
|
52
52
|
"TableRow",
|
|
53
53
|
"TableCell",
|
|
54
54
|
"Checkbox",
|
|
55
|
+
"Toolbar",
|
|
55
56
|
"Button",
|
|
56
57
|
"Badge",
|
|
57
58
|
"Alert",
|
|
58
59
|
"SearchField",
|
|
60
|
+
"MultiSelect",
|
|
59
61
|
"TagGroup"
|
|
60
62
|
],
|
|
61
63
|
"drivenBy": "useTableSort",
|
package/dist/styles/index.css
CHANGED
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
@import url('./table.css');
|
|
48
48
|
@import url('./pagination.css');
|
|
49
49
|
@import url('./divider.css');
|
|
50
|
+
@import url('./toolbar.css');
|
|
50
51
|
@import url('./link.css');
|
|
51
52
|
@import url('./modal.css');
|
|
52
53
|
@import url('./popover.css');
|
|
@@ -83,6 +84,7 @@
|
|
|
83
84
|
@import url('./sidebar.css');
|
|
84
85
|
@import url('./file-upload.css');
|
|
85
86
|
@import url('./combobox.css');
|
|
87
|
+
@import url('./multi-select.css');
|
|
86
88
|
|
|
87
89
|
/*
|
|
88
90
|
* date-range-picker AFTER date-picker, and the order is load-bearing rather
|