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,162 @@
1
+ {
2
+ "name": "Fieldset",
3
+ "source": "src/components/Fieldset.tsx",
4
+ "propsType": "FieldsetProps",
5
+ "description": "Groups related fields under one label, with one description and one error —\nan address, a date range typed as two fields, a set of limits.\n\nFor checkboxes use CheckboxGroup and for radios RadioGroup: both render this\nsame shell, and add the selection state it deliberately does not own.\n\nThere is no `isDisabled`. A native `disabled` fieldset does disable every\ncontrol inside, but Input, Select and the rest draw their disabled state from\ntheir own prop, so the fields would stop working while still looking live.\nDisable the fields themselves; the choice groups can cascade because their\ncheckboxes and radios style off `:disabled`.",
6
+ "import": "import { Fieldset } from 'ionbase-ui';",
7
+ "status": "stable",
8
+ "summary": "A <fieldset>/<legend> that groups related fields under one label, one description and one error — an address, a pair of limits, a date typed as two fields.",
9
+ "useWhen": [
10
+ "several fields answer one question and a reader must hear the question with each of them — street, city and postcode under \"Billing address\"",
11
+ "one error belongs to the group rather than to a field — \"the minimum must be below the maximum\""
12
+ ],
13
+ "useInstead": [
14
+ {
15
+ "when": "the fields are checkboxes",
16
+ "use": "CheckboxGroup",
17
+ "why": "it renders this same shell and adds the selected values and \"select at least one\""
18
+ },
19
+ {
20
+ "when": "the fields are radios",
21
+ "use": "RadioGroup",
22
+ "why": "it renders this same shell and adds the shared name and the selected value"
23
+ },
24
+ {
25
+ "when": "a single field needs a label and help text",
26
+ "use": "Input",
27
+ "why": "every field already renders its own label, description and error; a fieldset around one field announces the label twice"
28
+ },
29
+ {
30
+ "when": "the grouping is visual — a titled section of a settings page",
31
+ "use": "Card",
32
+ "why": "a fieldset is a form grouping that assistive technology announces on entry; a section of unrelated settings is not one question"
33
+ }
34
+ ],
35
+ "composition": {
36
+ "order": [
37
+ "Fieldset",
38
+ "Input"
39
+ ],
40
+ "note": "Each field keeps its own label — the legend names the group, not the fields. Put a group-level error in `errorMessage` with `isInvalid`, and keep field-level errors on the fields.",
41
+ "example": "<Fieldset label=\"Run limits\" description=\"Runs stop at whichever comes first.\" orientation=\"horizontal\"><NumberInput label=\"Max steps\" /><NumberInput label=\"Max minutes\" /></Fieldset>"
42
+ },
43
+ "variants": {
44
+ "orientation": {
45
+ "vertical": {
46
+ "use": "the default — fields stacked, as a form reads"
47
+ },
48
+ "horizontal": {
49
+ "use": "two or three short fields that read as one value — a range, a size, a city and postcode. Wraps rather than overflows"
50
+ }
51
+ }
52
+ },
53
+ "slots": {
54
+ "label": {
55
+ "accepts": "text",
56
+ "note": "renders as the <legend> — the question the fields answer"
57
+ },
58
+ "description": {
59
+ "accepts": "text",
60
+ "note": "help beneath the fields; replaced by `errorMessage` while `isInvalid` is set, as Input's is"
61
+ },
62
+ "errorMessage": {
63
+ "accepts": "text",
64
+ "note": "the group's error, shown only while `isInvalid` is set"
65
+ },
66
+ "children": {
67
+ "accepts": "Input, Select, NumberInput, DatePicker and other fields"
68
+ }
69
+ },
70
+ "a11y": {
71
+ "role": "group, from <fieldset> and <legend>",
72
+ "guarantees": [
73
+ "the legend is announced as the group's name when focus enters any field inside",
74
+ "`aria-describedby` on the fieldset points at whichever of the description or the error is showing"
75
+ ],
76
+ "requires": [
77
+ "`label`, or `aria-label` when the question is already visible as a heading"
78
+ ],
79
+ "notes": [
80
+ "There is no `isDisabled`. A native disabled fieldset disables every control inside, but Input, Select and the rest draw their disabled look from their own prop — the fields would stop working while still looking live. Disable the fields themselves."
81
+ ]
82
+ },
83
+ "antiPatterns": [
84
+ {
85
+ "dont": "a Fieldset around one field",
86
+ "why": "the field's label and the legend both announce, saying the same thing twice"
87
+ },
88
+ {
89
+ "dont": "a Fieldset of Checkboxes",
90
+ "do": "<CheckboxGroup label=\"Notify me when\">…</CheckboxGroup>",
91
+ "why": "it looks the same, but nothing owns the selected values or \"select at least one\""
92
+ },
93
+ {
94
+ "dont": "<fieldset disabled> around Inputs",
95
+ "why": "the fields stop accepting input while still drawn as enabled"
96
+ }
97
+ ],
98
+ "stylesheet": "src/styles/fieldset.css",
99
+ "tokens": [
100
+ "--font-family-sans",
101
+ "--font-weight-medium",
102
+ "--font-weight-regular",
103
+ "--ion-fieldset-gap",
104
+ "--ion-fieldset-inline-gap",
105
+ "--spacing-16",
106
+ "--spacing-6",
107
+ "--spacing-8",
108
+ "--text-error",
109
+ "--text-secondary",
110
+ "--text-tertiary",
111
+ "--type-body-sm",
112
+ "--type-body-sm-line-height"
113
+ ],
114
+ "props": {
115
+ "label": {
116
+ "type": "React.ReactNode",
117
+ "required": false,
118
+ "origin": "own",
119
+ "description": "The question the fields answer. Renders as the `<legend>`."
120
+ },
121
+ "description": {
122
+ "type": "React.ReactNode",
123
+ "required": false,
124
+ "origin": "own",
125
+ "description": "Help text beneath the fields. Replaced by `errorMessage` while invalid."
126
+ },
127
+ "errorMessage": {
128
+ "type": "React.ReactNode",
129
+ "required": false,
130
+ "origin": "own",
131
+ "description": "Shown in the description's place while `isInvalid` is set."
132
+ },
133
+ "isInvalid": {
134
+ "type": "boolean | undefined",
135
+ "required": false,
136
+ "origin": "own",
137
+ "description": "Whether the group as a whole fails validation."
138
+ },
139
+ "orientation": {
140
+ "type": "FieldsetOrientation | undefined",
141
+ "required": false,
142
+ "origin": "own",
143
+ "description": "How the fields flow. Horizontal wraps rather than overflowing.",
144
+ "values": [
145
+ "vertical",
146
+ "horizontal"
147
+ ],
148
+ "default": "vertical"
149
+ },
150
+ "children": {
151
+ "type": "React.ReactNode",
152
+ "required": false,
153
+ "origin": "own"
154
+ }
155
+ },
156
+ "propCounts": {
157
+ "own": 6,
158
+ "aria": 0,
159
+ "dom": 279,
160
+ "other": 0
161
+ }
162
+ }
@@ -0,0 +1,269 @@
1
+ {
2
+ "name": "MultiSelect",
3
+ "source": "src/components/MultiSelect.tsx",
4
+ "propsType": "MultiSelectProps",
5
+ "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.",
6
+ "import": "import { MultiSelect } from 'ionbase-ui';",
7
+ "status": "stable",
8
+ "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.",
9
+ "useWhen": [
10
+ "the user picks several values from a list too long to show as checkboxes — teams, regions, labels, assignees",
11
+ "a table filter can match more than one value — \"Status is Failing or Paused\""
12
+ ],
13
+ "useInstead": [
14
+ {
15
+ "when": "exactly one value is picked",
16
+ "use": "Combobox",
17
+ "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"
18
+ },
19
+ {
20
+ "when": "there are about seven options or fewer",
21
+ "use": "CheckboxGroup",
22
+ "why": "every option visible at once beats typing to find one, and nothing is hidden behind a popover"
23
+ },
24
+ {
25
+ "when": "the values are free text the user invents, not options from a list",
26
+ "use": "TagGroup",
27
+ "why": "MultiSelect only chooses from `options`; a free-text tag input is a TagGroup beside an Input"
28
+ }
29
+ ],
30
+ "composition": {
31
+ "order": [
32
+ "MultiSelect"
33
+ ],
34
+ "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.",
35
+ "example": "<MultiSelect label=\"Notify teams\" options={teams} value={teamIds} onChange={setTeamIds} placeholder=\"Search teams\" />"
36
+ },
37
+ "variants": {
38
+ "size": {
39
+ "sm": {
40
+ "use": "dense forms, table filters"
41
+ },
42
+ "md": {
43
+ "use": "the default"
44
+ },
45
+ "lg": {
46
+ "use": "prominent single-field forms"
47
+ }
48
+ }
49
+ },
50
+ "slots": {
51
+ "label": {
52
+ "accepts": "text",
53
+ "note": "names the field and the tags beneath it"
54
+ },
55
+ "description": {
56
+ "accepts": "text",
57
+ "note": "replaced by `errorMessage` while `isInvalid` is set"
58
+ },
59
+ "errorMessage": {
60
+ "accepts": "text",
61
+ "note": "shown only while `isInvalid` is set"
62
+ },
63
+ "emptyLabel": {
64
+ "accepts": "text",
65
+ "note": "shown in the list when the filter matches nothing"
66
+ }
67
+ },
68
+ "a11y": {
69
+ "role": "combobox, controlling a listbox that is aria-multiselectable",
70
+ "guarantees": [
71
+ "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",
72
+ "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",
73
+ "the chosen values are a TagGroup named by the field's label: one tab stop, arrow keys between tags, Delete or the × to remove",
74
+ "Backspace in an empty field removes the last value; with text in the field it only edits the text",
75
+ "removing the last tag returns focus to the field instead of dropping it on <body>",
76
+ "`isRequired` marks the field required only while nothing is chosen — at least one"
77
+ ],
78
+ "requires": [
79
+ "`label`, or `aria-label` when there is no visible label — it names the tags as well as the field"
80
+ ],
81
+ "notes": [
82
+ "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."
83
+ ]
84
+ },
85
+ "antiPatterns": [
86
+ {
87
+ "dont": "a Combobox that appends each pick to a TagGroup by hand",
88
+ "why": "the list closes after every pick, the input shows the last label, and nothing announces what is chosen"
89
+ },
90
+ {
91
+ "dont": "a native <select multiple>",
92
+ "why": "it needs Ctrl or Cmd to pick a second option, which most people never discover, and it cannot filter"
93
+ },
94
+ {
95
+ "dont": "a count in place of the values — \"3 selected\"",
96
+ "why": "it hides which three; the tags show them and the field reads them"
97
+ },
98
+ {
99
+ "dont": "`hideTags` with nowhere else showing the values",
100
+ "why": "the field shows only the filter text, so the choice is invisible until the list is opened"
101
+ }
102
+ ],
103
+ "stylesheet": "src/styles/multi-select.css",
104
+ "tokens": [
105
+ "--border-disabled",
106
+ "--border-primary-strong",
107
+ "--border-stronger",
108
+ "--border-width-default",
109
+ "--border-width-thick",
110
+ "--font-weight-regular",
111
+ "--icon-on-color",
112
+ "--ion-shadow-raised-flush-xs",
113
+ "--radius-xs",
114
+ "--spacing-16",
115
+ "--spacing-2",
116
+ "--spacing-4",
117
+ "--spacing-8",
118
+ "--surface-default",
119
+ "--surface-disabled",
120
+ "--surface-hover",
121
+ "--surface-primary",
122
+ "--type-body-line-height"
123
+ ],
124
+ "props": {
125
+ "options": {
126
+ "type": "readonly ComboboxOption[]",
127
+ "required": true,
128
+ "origin": "own",
129
+ "description": "The full option list. Filtering happens here, against what is typed."
130
+ },
131
+ "label": {
132
+ "type": "React.ReactNode",
133
+ "required": false,
134
+ "origin": "own",
135
+ "description": "Field label. Required for a usable control — see `a11y.requires`."
136
+ },
137
+ "aria-label": {
138
+ "type": "string | undefined",
139
+ "required": false,
140
+ "origin": "own",
141
+ "description": "Names the field, and its tags, when there is no visible `label`."
142
+ },
143
+ "description": {
144
+ "type": "React.ReactNode",
145
+ "required": false,
146
+ "origin": "own",
147
+ "description": "Helper text below the field."
148
+ },
149
+ "errorMessage": {
150
+ "type": "React.ReactNode",
151
+ "required": false,
152
+ "origin": "own",
153
+ "description": "Replaces the helper text when `isInvalid` is set."
154
+ },
155
+ "isInvalid": {
156
+ "type": "boolean | undefined",
157
+ "required": false,
158
+ "origin": "own"
159
+ },
160
+ "isDisabled": {
161
+ "type": "boolean | undefined",
162
+ "required": false,
163
+ "origin": "own"
164
+ },
165
+ "isReadOnly": {
166
+ "type": "boolean | undefined",
167
+ "required": false,
168
+ "origin": "own"
169
+ },
170
+ "isRequired": {
171
+ "type": "boolean | undefined",
172
+ "required": false,
173
+ "origin": "own",
174
+ "description": "At least one value must be chosen."
175
+ },
176
+ "size": {
177
+ "type": "MultiSelectSize | undefined",
178
+ "required": false,
179
+ "origin": "own",
180
+ "description": "Matches Input's `Size` variant: Small, Medium, Large.",
181
+ "values": [
182
+ "sm",
183
+ "md",
184
+ "lg"
185
+ ]
186
+ },
187
+ "placeholder": {
188
+ "type": "string | undefined",
189
+ "required": false,
190
+ "origin": "own"
191
+ },
192
+ "value": {
193
+ "type": "readonly string[] | undefined",
194
+ "required": false,
195
+ "origin": "own",
196
+ "description": "The selected values (controlled), in the order they were chosen."
197
+ },
198
+ "defaultValue": {
199
+ "type": "readonly string[] | undefined",
200
+ "required": false,
201
+ "origin": "own",
202
+ "description": "The initially selected values (uncontrolled)."
203
+ },
204
+ "onChange": {
205
+ "type": "((value: string[]) => void) | undefined",
206
+ "required": false,
207
+ "origin": "own",
208
+ "description": "Receives the whole new selection."
209
+ },
210
+ "inputValue": {
211
+ "type": "string | undefined",
212
+ "required": false,
213
+ "origin": "own",
214
+ "description": "Controlled filter text. Usually only needed for remote filtering."
215
+ },
216
+ "onInputChange": {
217
+ "type": "((value: string) => void) | undefined",
218
+ "required": false,
219
+ "origin": "own"
220
+ },
221
+ "hideTags": {
222
+ "type": "boolean | undefined",
223
+ "required": false,
224
+ "origin": "own",
225
+ "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."
226
+ },
227
+ "emptyLabel": {
228
+ "type": "React.ReactNode",
229
+ "required": false,
230
+ "origin": "own",
231
+ "description": "Shown in place of the list when nothing matches."
232
+ },
233
+ "buttonLabel": {
234
+ "type": "string | undefined",
235
+ "required": false,
236
+ "origin": "own",
237
+ "description": "Accessible label for the disclosure button."
238
+ },
239
+ "name": {
240
+ "type": "string | undefined",
241
+ "required": false,
242
+ "origin": "own",
243
+ "description": "Posts every selected value under this name, for an uncontrolled form."
244
+ },
245
+ "className": {
246
+ "type": "string | undefined",
247
+ "required": false,
248
+ "origin": "own",
249
+ "description": "Class names for the field box (`.ion-input`)."
250
+ },
251
+ "wrapperClassName": {
252
+ "type": "string | undefined",
253
+ "required": false,
254
+ "origin": "own",
255
+ "description": "Class names for the `.ion-field` wrapper."
256
+ },
257
+ "id": {
258
+ "type": "string | undefined",
259
+ "required": false,
260
+ "origin": "own"
261
+ }
262
+ },
263
+ "propCounts": {
264
+ "own": 23,
265
+ "aria": 0,
266
+ "dom": 0,
267
+ "other": 0
268
+ }
269
+ }
@@ -91,7 +91,6 @@
91
91
  "--border-width-default",
92
92
  "--border-width-thick",
93
93
  "--font-family-sans",
94
- "--font-weight-medium",
95
94
  "--icon-disabled",
96
95
  "--icon-on-color",
97
96
  "--ion-duration-base",
@@ -2,10 +2,10 @@
2
2
  "name": "RadioGroup",
3
3
  "source": "src/components/Radio.tsx",
4
4
  "propsType": "RadioGroupProps",
5
- "description": "Renders a `<fieldset>` with a `<legend>` rather than a div with\n`role=\"radiogroup\"`. Both are announced correctly, but a fieldset also groups\nthe inputs for form submission and native validation, which the ARIA version\ndoes not.",
5
+ "description": "Renders a `<fieldset>` with a `<legend>` rather than a div with\n`role=\"radiogroup\"`. Both are announced correctly, but a fieldset also groups\nthe inputs for form submission and native validation, which the ARIA version\ndoes not.\n\nThe fieldset itself is Fieldset's shell, shared with CheckboxGroup, so the\ntwo choice groups take the same label, help, error and orientation props.",
6
6
  "import": "import { RadioGroup } from 'ionbase-ui';",
7
7
  "status": "stable",
8
- "summary": "A <fieldset>/<legend> group of mutually exclusive options. Owns the shared name and the selected value.",
8
+ "summary": "A <fieldset>/<legend> group of mutually exclusive options. Owns the shared name and the selected value, and the group's label, help and error.",
9
9
  "useWhen": [
10
10
  "exactly one choice from a small set, all worth showing at once",
11
11
  "the options need explaining — each one can carry its own label text"
@@ -17,7 +17,7 @@
17
17
  },
18
18
  {
19
19
  "when": "more than one may be picked",
20
- "use": "Checkbox"
20
+ "use": "CheckboxGroup"
21
21
  },
22
22
  {
23
23
  "when": "there are exactly two states and the change is immediate",
@@ -46,6 +46,14 @@
46
46
  "danger": {
47
47
  "use": "a set where the options are destructive"
48
48
  }
49
+ },
50
+ "orientation": {
51
+ "vertical": {
52
+ "use": "the default, and always when a label runs past a few words"
53
+ },
54
+ "horizontal": {
55
+ "use": "two to four one-word options. Wraps rather than overflows"
56
+ }
49
57
  }
50
58
  },
51
59
  "slots": {
@@ -53,6 +61,14 @@
53
61
  "accepts": "text",
54
62
  "note": "renders as the <legend> — the question the options answer"
55
63
  },
64
+ "description": {
65
+ "accepts": "text",
66
+ "note": "help beneath the options; replaced by `errorMessage` while `isInvalid` is set"
67
+ },
68
+ "errorMessage": {
69
+ "accepts": "text",
70
+ "note": "shown only while `isInvalid` is set"
71
+ },
56
72
  "children": {
57
73
  "accepts": "Radio"
58
74
  }
@@ -62,7 +78,10 @@
62
78
  "guarantees": [
63
79
  "a real fieldset rather than `role=\"radiogroup\"`: both announce correctly, but the fieldset also groups the inputs for form submission and native validation",
64
80
  "`name` is generated when omitted, so two groups on one page never collide",
65
- "`isDisabled` cascades to every Radio that has not set its own"
81
+ "`isDisabled` cascades to every Radio that has not set its own",
82
+ "the fieldset is Fieldset's shell, shared with CheckboxGroup — the same label, help, error and orientation props",
83
+ "the description or error is on every radio's `aria-describedby` as well as the fieldset's, so it is read on the radio that takes focus",
84
+ "`isRequired` is native `required` on the radios, which the platform already reads as \"one of this name\""
66
85
  ],
67
86
  "requires": [
68
87
  "`label`, or `aria-label` when the question is already visible elsewhere"
@@ -99,7 +118,6 @@
99
118
  "--border-width-default",
100
119
  "--border-width-thick",
101
120
  "--font-family-sans",
102
- "--font-weight-medium",
103
121
  "--icon-disabled",
104
122
  "--icon-on-color",
105
123
  "--ion-duration-base",
@@ -159,7 +177,41 @@
159
177
  "label": {
160
178
  "type": "React.ReactNode",
161
179
  "required": false,
162
- "origin": "own"
180
+ "origin": "own",
181
+ "description": "The question the options answer. Renders as the `<legend>`."
182
+ },
183
+ "description": {
184
+ "type": "React.ReactNode",
185
+ "required": false,
186
+ "origin": "own",
187
+ "description": "Help text beneath the options. Replaced by `errorMessage` while invalid."
188
+ },
189
+ "errorMessage": {
190
+ "type": "React.ReactNode",
191
+ "required": false,
192
+ "origin": "own",
193
+ "description": "Shown in the description's place while `isInvalid` is set."
194
+ },
195
+ "isInvalid": {
196
+ "type": "boolean | undefined",
197
+ "required": false,
198
+ "origin": "own",
199
+ "description": "Shows `errorMessage` in the description's place."
200
+ },
201
+ "isRequired": {
202
+ "type": "boolean | undefined",
203
+ "required": false,
204
+ "origin": "own",
205
+ "description": "One option must be chosen before the form submits."
206
+ },
207
+ "orientation": {
208
+ "type": "FieldsetOrientation | undefined",
209
+ "required": false,
210
+ "origin": "own",
211
+ "values": [
212
+ "vertical",
213
+ "horizontal"
214
+ ]
163
215
  },
164
216
  "size": {
165
217
  "type": "RadioSize | undefined",
@@ -202,7 +254,7 @@
202
254
  }
203
255
  },
204
256
  "propCounts": {
205
- "own": 10,
257
+ "own": 15,
206
258
  "aria": 0,
207
259
  "dom": 276,
208
260
  "other": 0