ionbase-ui 0.81.1 → 0.86.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/Checkbox.d.ts +39 -0
- package/dist/components/Checkbox.d.ts.map +1 -1
- package/dist/components/Checkbox.js +77 -4
- package/dist/components/Checkbox.js.map +1 -1
- package/dist/components/Fieldset.d.ts +62 -0
- package/dist/components/Fieldset.d.ts.map +1 -0
- package/dist/components/Fieldset.js +58 -0
- package/dist/components/Fieldset.js.map +1 -0
- package/dist/components/Menu.d.ts +87 -24
- package/dist/components/Menu.d.ts.map +1 -1
- package/dist/components/Menu.js +245 -28
- package/dist/components/Menu.js.map +1 -1
- package/dist/components/PageHeader.d.ts +59 -0
- package/dist/components/PageHeader.d.ts.map +1 -0
- package/dist/components/PageHeader.js +29 -0
- package/dist/components/PageHeader.js.map +1 -0
- package/dist/components/Radio.d.ts +14 -0
- package/dist/components/Radio.d.ts.map +1 -1
- package/dist/components/Radio.js +15 -4
- package/dist/components/Radio.js.map +1 -1
- package/dist/components/SearchField.d.ts +36 -0
- package/dist/components/SearchField.d.ts.map +1 -0
- package/dist/components/SearchField.js +76 -0
- package/dist/components/SearchField.js.map +1 -0
- package/dist/components/index.d.ts +10 -4
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +5 -2
- package/dist/components/index.js.map +1 -1
- package/dist/figma-descriptions.json +96 -76
- package/dist/figma-map.json +272 -39
- package/dist/meta/Checkbox.json +8 -6
- package/dist/meta/CheckboxGroup.json +268 -0
- package/dist/meta/Divider.json +2 -2
- package/dist/meta/Fieldset.json +162 -0
- package/dist/meta/Menu.json +201 -27
- package/dist/meta/MenuItem.json +137 -17
- package/dist/meta/MenuSection.json +90 -0
- package/dist/meta/MenuTrigger.json +177 -0
- package/dist/meta/PageHeader.json +169 -0
- package/dist/meta/Radio.json +0 -1
- package/dist/meta/RadioGroup.json +59 -7
- package/dist/meta/SearchField.json +487 -0
- package/dist/meta/Stepper.json +2 -2
- package/dist/meta/Tabs.json +3 -3
- package/dist/meta/components.json +1917 -217
- package/dist/meta/contrast.json +594 -90
- package/dist/meta/index.json +89 -10
- package/dist/meta/patterns/DataTable.json +14 -6
- package/dist/meta/patterns/Form.json +27 -2
- package/dist/meta/patterns/PageShell.json +18 -5
- package/dist/meta/patterns/index.json +5 -2
- package/dist/styles/fieldset.css +65 -0
- package/dist/styles/index.css +3 -0
- package/dist/styles/menu.css +153 -32
- package/dist/styles/page-header.css +94 -0
- package/dist/styles/radio.css +0 -20
- package/dist/styles/search-field.css +70 -0
- package/llms.txt +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "MenuTrigger",
|
|
3
|
+
"source": "src/components/Menu.tsx",
|
|
4
|
+
"propsType": "MenuTriggerProps",
|
|
5
|
+
"description": "MenuTrigger — a Button that opens a Menu.\n\nThe \"⋯\" overflow menu is this with an icon-only Button; there is no separate\ncomponent for it, because the only difference is the Button's content and\nits required aria-label.\n\n`useMenuTrigger` does what a Popover wrapped round a Menu could not: the\ntrigger announces `aria-haspopup=\"menu\"` and `aria-expanded`, the menu is\nnamed by the trigger, ArrowDown and ArrowUp open it with focus on the first\nor last row, and choosing an action closes it and returns focus to the\ntrigger.",
|
|
6
|
+
"import": "import { MenuTrigger } from 'ionbase-ui';",
|
|
7
|
+
"status": "stable",
|
|
8
|
+
"summary": "A Button that opens a Menu. The \"⋯\" overflow menu is this with an icon-only Button. Owns open state, positioning, focus, and the ARIA link between the two.",
|
|
9
|
+
"useWhen": [
|
|
10
|
+
"a button opens a list of actions — row actions, an overflow \"⋯\", a \"New\" button with several kinds of new",
|
|
11
|
+
"a button opens a list of choices applied immediately, such as a sort order",
|
|
12
|
+
"the actions nest one level or more — submenus open only inside a MenuTrigger"
|
|
13
|
+
],
|
|
14
|
+
"useInstead": [
|
|
15
|
+
{
|
|
16
|
+
"when": "the button opens a form, a filter panel or anything that is not a list of rows",
|
|
17
|
+
"use": "Popover",
|
|
18
|
+
"why": "a menu promises arrow keys between rows and nothing else; a field inside it cannot be reached"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"when": "the choice is a form field's value",
|
|
22
|
+
"use": "Select",
|
|
23
|
+
"why": "a form value is a listbox the form can read, not a menu of actions"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"when": "there are only two or three actions and room to show them",
|
|
27
|
+
"use": "Button",
|
|
28
|
+
"why": "hiding actions behind a menu costs a click and makes them undiscoverable; show them when they fit"
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
"composition": {
|
|
32
|
+
"order": [
|
|
33
|
+
"MenuTrigger",
|
|
34
|
+
"Button",
|
|
35
|
+
"Menu"
|
|
36
|
+
],
|
|
37
|
+
"note": "Exactly two children, in this order: the Button, then the Menu. The Menu is named by the Button unless it has its own aria-label. A MenuItem with a `title` and MenuItem children opens a submenu; `onAction` on the root Menu receives actions from every level.",
|
|
38
|
+
"example": "<MenuTrigger><Button variant=\"tertiary\" aria-label=\"Actions for Payroll\" startIcon={<Icon as={Ellipsis} />} /><Menu onAction={(key) => run(key)}><MenuItem key=\"rename\">Rename</MenuItem><MenuItem key=\"move\" title=\"Move to\"><MenuItem key=\"archive\">Archive</MenuItem><MenuItem key=\"trash\">Trash</MenuItem></MenuItem></Menu></MenuTrigger>"
|
|
39
|
+
},
|
|
40
|
+
"variants": {
|
|
41
|
+
"placement": {
|
|
42
|
+
"bottom start": {
|
|
43
|
+
"use": "the default — below, aligned to the trigger's start edge"
|
|
44
|
+
},
|
|
45
|
+
"bottom end": {
|
|
46
|
+
"use": "a trigger at the end of a row or toolbar, so the menu does not run off the edge"
|
|
47
|
+
},
|
|
48
|
+
"top start": {
|
|
49
|
+
"use": "a trigger near the bottom of the viewport, such as a footer"
|
|
50
|
+
},
|
|
51
|
+
"top end": {
|
|
52
|
+
"use": "as top start, for a trigger at the end of its row"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"slots": {
|
|
57
|
+
"children": {
|
|
58
|
+
"accepts": [
|
|
59
|
+
"Button",
|
|
60
|
+
"Menu"
|
|
61
|
+
],
|
|
62
|
+
"note": "the Button first, the Menu second"
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"a11y": {
|
|
66
|
+
"role": "none — the Button gets aria-haspopup=\"menu\" and aria-expanded; the Menu is the menu",
|
|
67
|
+
"namesChild": true,
|
|
68
|
+
"guarantees": [
|
|
69
|
+
"Enter, Space and ArrowDown open the menu with focus on its first row; ArrowUp opens it on the last",
|
|
70
|
+
"choosing an action closes every open level and returns focus to the trigger; so do Escape and an outside click",
|
|
71
|
+
"the menu is named by the trigger unless it has its own aria-label",
|
|
72
|
+
"a submenu opens with the right arrow, Enter or Space and closes with the left arrow or Escape, which puts focus back on the row that opened it",
|
|
73
|
+
"submenus are non-modal: the parent menu stays on screen and hoverable, so the pointer can move between levels"
|
|
74
|
+
],
|
|
75
|
+
"requires": [
|
|
76
|
+
"an icon-only trigger Button needs its own aria-label — it names the menu too"
|
|
77
|
+
]
|
|
78
|
+
},
|
|
79
|
+
"antiPatterns": [
|
|
80
|
+
{
|
|
81
|
+
"dont": "wrapping a Menu in a Popover to make a dropdown",
|
|
82
|
+
"why": "the trigger then announces a dialog, not a menu, the arrow keys cannot open it, and choosing an action does not close it. That is exactly what MenuTrigger exists to replace"
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"dont": "a plain <button> as the trigger",
|
|
86
|
+
"why": "the trigger must accept react-aria press props and a ref; IonBase's Button does, a DOM button silently never opens"
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"dont": "more than two levels of submenu",
|
|
90
|
+
"why": "each level is a hover target narrower than the last; past two, the pointer falls off the path and the menu closes. Flatten with sections instead"
|
|
91
|
+
}
|
|
92
|
+
],
|
|
93
|
+
"stylesheet": "src/styles/menu.css",
|
|
94
|
+
"tokens": [
|
|
95
|
+
"--border-focus",
|
|
96
|
+
"--border-strong",
|
|
97
|
+
"--border-subtle",
|
|
98
|
+
"--border-width-default",
|
|
99
|
+
"--border-width-thick",
|
|
100
|
+
"--font-family-sans",
|
|
101
|
+
"--font-weight-regular",
|
|
102
|
+
"--icon-default",
|
|
103
|
+
"--icon-disabled",
|
|
104
|
+
"--icon-primary",
|
|
105
|
+
"--icon-size-sm",
|
|
106
|
+
"--ion-duration-base",
|
|
107
|
+
"--ion-ease-out",
|
|
108
|
+
"--ion-menu-min-width",
|
|
109
|
+
"--ion-shadow-shadow-lg",
|
|
110
|
+
"--radius-sm",
|
|
111
|
+
"--radius-xl",
|
|
112
|
+
"--spacing-12",
|
|
113
|
+
"--spacing-2",
|
|
114
|
+
"--spacing-4",
|
|
115
|
+
"--spacing-40",
|
|
116
|
+
"--spacing-6",
|
|
117
|
+
"--spacing-8",
|
|
118
|
+
"--surface-default",
|
|
119
|
+
"--surface-hover",
|
|
120
|
+
"--surface-primary-subtle",
|
|
121
|
+
"--text-disabled",
|
|
122
|
+
"--text-primary",
|
|
123
|
+
"--text-secondary",
|
|
124
|
+
"--text-tertiary",
|
|
125
|
+
"--type-body",
|
|
126
|
+
"--type-body-line-height",
|
|
127
|
+
"--type-caption",
|
|
128
|
+
"--type-caption-line-height"
|
|
129
|
+
],
|
|
130
|
+
"props": {
|
|
131
|
+
"children": {
|
|
132
|
+
"type": "[React.ReactElement<unknown, string | React.JSXElementConstructor<any>>, React.ReactElement<unknown, string | React.JSXElementConstructor<any>>]",
|
|
133
|
+
"required": true,
|
|
134
|
+
"origin": "own",
|
|
135
|
+
"description": "Exactly two children: the Button that opens the menu, then the Menu. The\nButton must accept a ref and react-aria press props — IonBase's Button\ndoes; a plain `<button>` does not."
|
|
136
|
+
},
|
|
137
|
+
"placement": {
|
|
138
|
+
"type": "MenuTriggerPlacement | undefined",
|
|
139
|
+
"required": false,
|
|
140
|
+
"origin": "own",
|
|
141
|
+
"description": "Where the menu opens, relative to the trigger. A preference, not a\nguarantee: it flips when there is no room.",
|
|
142
|
+
"values": [
|
|
143
|
+
"bottom start",
|
|
144
|
+
"bottom end",
|
|
145
|
+
"top start",
|
|
146
|
+
"top end"
|
|
147
|
+
]
|
|
148
|
+
},
|
|
149
|
+
"isDisabled": {
|
|
150
|
+
"type": "boolean | undefined",
|
|
151
|
+
"required": false,
|
|
152
|
+
"origin": "own",
|
|
153
|
+
"description": "Whether the trigger is disabled."
|
|
154
|
+
},
|
|
155
|
+
"isOpen": {
|
|
156
|
+
"type": "boolean | undefined",
|
|
157
|
+
"required": false,
|
|
158
|
+
"origin": "own"
|
|
159
|
+
},
|
|
160
|
+
"defaultOpen": {
|
|
161
|
+
"type": "boolean | undefined",
|
|
162
|
+
"required": false,
|
|
163
|
+
"origin": "own"
|
|
164
|
+
},
|
|
165
|
+
"onOpenChange": {
|
|
166
|
+
"type": "((isOpen: boolean) => void) | undefined",
|
|
167
|
+
"required": false,
|
|
168
|
+
"origin": "own"
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
"propCounts": {
|
|
172
|
+
"own": 6,
|
|
173
|
+
"aria": 0,
|
|
174
|
+
"dom": 0,
|
|
175
|
+
"other": 0
|
|
176
|
+
}
|
|
177
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "PageHeader",
|
|
3
|
+
"source": "src/components/PageHeader.tsx",
|
|
4
|
+
"propsType": "PageHeaderProps",
|
|
5
|
+
"description": "PageHeader — the top of a page: where you are, what it is, and what you can\ndo to it.\n\nPromoted from the demo app, where five screens hand-wrote it in three\ndifferent shapes (`.demo-page__header`, `.demo-run-header`, and a bare\n`<div>`), each with its own gap and its own idea of where the actions\naligned. Every enterprise system ships one — Carbon's PageHeader,\nLightning's page headers — because every page has one.\n\nNOT A LANDMARK\n\nIt renders a `<div>`, not a `<header>`. A `<header>` that is a child of\n`<body>` is the page's banner, and the app shell's Header already is that.\nThe page's landmark is `<main>`, named by this title: pass `titleId` and\npoint `<main aria-labelledby>` at it.\n\nNo `'use client'`: `useId` resolves on the server, and nothing here is\ninteractive. Interactive parts arrive through the slots.",
|
|
6
|
+
"import": "import { PageHeader } from 'ionbase-ui';",
|
|
7
|
+
"status": "stable",
|
|
8
|
+
"summary": "The top of a page: breadcrumb, the page's h1, a description, the record's status, and the page's actions. Not a landmark — main is, named by this title.",
|
|
9
|
+
"useWhen": [
|
|
10
|
+
"the top of every page inside the app shell — list pages, record pages, settings, wizards",
|
|
11
|
+
"the page has a title and actions that act on the whole page, such as New agent or Pause"
|
|
12
|
+
],
|
|
13
|
+
"useInstead": [
|
|
14
|
+
{
|
|
15
|
+
"when": "it is the bar across the top of the whole app, with the logo and the account menu",
|
|
16
|
+
"use": "Header",
|
|
17
|
+
"why": "Header is the banner landmark, rendered once by the shell. PageHeader is inside main and changes with each page"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"when": "it titles one section of a page rather than the page",
|
|
21
|
+
"use": "Card",
|
|
22
|
+
"why": "a Card's title is an h2 for a named region; a page has one PageHeader and one h1"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"when": "the page is empty or failed to load",
|
|
26
|
+
"use": "EmptyState",
|
|
27
|
+
"why": "keep the PageHeader so the user still knows where they are, and put the EmptyState beneath it with headingLevel 2"
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"composition": {
|
|
31
|
+
"order": [
|
|
32
|
+
"PageHeader",
|
|
33
|
+
"Breadcrumb",
|
|
34
|
+
"Badge",
|
|
35
|
+
"Button",
|
|
36
|
+
"MenuTrigger",
|
|
37
|
+
"Tabs"
|
|
38
|
+
],
|
|
39
|
+
"note": "Slots, not children: `breadcrumb` above, `status` beside the title, `actions` at the end of the title row, and `children` as a row beneath for the page's Tabs or filters. Pass `titleId` and point `<main aria-labelledby>` at it.",
|
|
40
|
+
"example": "<main aria-labelledby=\"page-title\"><PageHeader titleId=\"page-title\" title=\"Payroll reconciler\" description=\"Matches payroll exports against the ledger every night.\" breadcrumb={<Breadcrumb><BreadcrumbItem href=\"/agents\">Agents</BreadcrumbItem><BreadcrumbItem isCurrent>Payroll reconciler</BreadcrumbItem></Breadcrumb>} status={<Badge intent=\"warning\">Paused</Badge>} actions={<><MenuTrigger><Button variant=\"tertiary\" aria-label=\"More actions\" startIcon={<Icon as={Ellipsis} />} /><Menu onAction={run}><MenuItem key=\"delete\">Delete…</MenuItem></Menu></MenuTrigger><Button variant=\"primary-brand\">Resume</Button></>} /></main>"
|
|
41
|
+
},
|
|
42
|
+
"slots": {
|
|
43
|
+
"breadcrumb": {
|
|
44
|
+
"accepts": "Breadcrumb"
|
|
45
|
+
},
|
|
46
|
+
"status": {
|
|
47
|
+
"accepts": [
|
|
48
|
+
"Badge",
|
|
49
|
+
"Tag"
|
|
50
|
+
],
|
|
51
|
+
"note": "the record's state. Never an action, and never colour alone — a Badge carries its label"
|
|
52
|
+
},
|
|
53
|
+
"actions": {
|
|
54
|
+
"accepts": [
|
|
55
|
+
"Button",
|
|
56
|
+
"MenuTrigger",
|
|
57
|
+
"Link"
|
|
58
|
+
],
|
|
59
|
+
"note": "most important last, so the primary action sits at the end of the row. One primary Button at most; beyond two or three actions, put the rest in a MenuTrigger"
|
|
60
|
+
},
|
|
61
|
+
"children": {
|
|
62
|
+
"accepts": [
|
|
63
|
+
"Tabs",
|
|
64
|
+
"SegmentedControl"
|
|
65
|
+
],
|
|
66
|
+
"note": "a row that belongs to the header: the page's own tabs, or the filters its table answers to"
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
"a11y": {
|
|
70
|
+
"role": "none — a <div>. The page's landmark is <main>, named by this title",
|
|
71
|
+
"guarantees": [
|
|
72
|
+
"the title is a real heading, h1 by default, with a stable id for aria-labelledby",
|
|
73
|
+
"actions keep their DOM order when they wrap beneath the title on a narrow screen, so reading order matches visual order"
|
|
74
|
+
],
|
|
75
|
+
"notes": [
|
|
76
|
+
"`headingLevel` is 1 by default. Use 2 only for a header on a pane that is not the page — the detail half of a list-detail layout, under the list's h1.",
|
|
77
|
+
"It is deliberately not a <header>: a <header> directly inside <body> is the banner, and the app shell's Header already is that."
|
|
78
|
+
]
|
|
79
|
+
},
|
|
80
|
+
"antiPatterns": [
|
|
81
|
+
{
|
|
82
|
+
"dont": "two PageHeaders on one page",
|
|
83
|
+
"why": "two h1s, and two answers to where am I. Sections below the header are Cards with h2 titles"
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"dont": "dropping the PageHeader while the page loads or fails",
|
|
87
|
+
"why": "the user loses where they are exactly when something went wrong. Keep the title; put Skeleton or EmptyState beneath it"
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"dont": "putting filters or a search field in `actions`",
|
|
91
|
+
"why": "actions act on the page; filters narrow what it shows. Filters go in `children`, the row beneath"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"dont": "several primary Buttons in `actions`",
|
|
95
|
+
"why": "a page has one next step. The one-primary-action lint rule counts them"
|
|
96
|
+
}
|
|
97
|
+
],
|
|
98
|
+
"stylesheet": "src/styles/page-header.css",
|
|
99
|
+
"tokens": [
|
|
100
|
+
"--font-family-sans",
|
|
101
|
+
"--font-weight-semibold",
|
|
102
|
+
"--ion-page-header-heading-basis",
|
|
103
|
+
"--spacing-16",
|
|
104
|
+
"--spacing-4",
|
|
105
|
+
"--spacing-8",
|
|
106
|
+
"--text-default",
|
|
107
|
+
"--text-secondary",
|
|
108
|
+
"--type-body",
|
|
109
|
+
"--type-body-line-height",
|
|
110
|
+
"--type-h4",
|
|
111
|
+
"--type-h4-line-height"
|
|
112
|
+
],
|
|
113
|
+
"props": {
|
|
114
|
+
"title": {
|
|
115
|
+
"type": "React.ReactNode",
|
|
116
|
+
"required": true,
|
|
117
|
+
"origin": "own",
|
|
118
|
+
"description": "The page's title. Rendered as the `h1`."
|
|
119
|
+
},
|
|
120
|
+
"titleId": {
|
|
121
|
+
"type": "string | undefined",
|
|
122
|
+
"required": false,
|
|
123
|
+
"origin": "own",
|
|
124
|
+
"description": "The title's id. Pass it when something else points at the heading —\n`<main aria-labelledby>` is the usual one. Generated when omitted."
|
|
125
|
+
},
|
|
126
|
+
"headingLevel": {
|
|
127
|
+
"type": "PageHeaderHeadingLevel | undefined",
|
|
128
|
+
"required": false,
|
|
129
|
+
"origin": "own",
|
|
130
|
+
"description": "Heading element for the title. Defaults to `1`."
|
|
131
|
+
},
|
|
132
|
+
"description": {
|
|
133
|
+
"type": "React.ReactNode",
|
|
134
|
+
"required": false,
|
|
135
|
+
"origin": "own",
|
|
136
|
+
"description": "One or two sentences under the title: what this page is for."
|
|
137
|
+
},
|
|
138
|
+
"breadcrumb": {
|
|
139
|
+
"type": "React.ReactNode",
|
|
140
|
+
"required": false,
|
|
141
|
+
"origin": "own",
|
|
142
|
+
"description": "A Breadcrumb, above the title."
|
|
143
|
+
},
|
|
144
|
+
"status": {
|
|
145
|
+
"type": "React.ReactNode",
|
|
146
|
+
"required": false,
|
|
147
|
+
"origin": "own",
|
|
148
|
+
"description": "Beside the title: a Badge or two for the record's state — \"Paused\",\n\"Draft\". State, not actions."
|
|
149
|
+
},
|
|
150
|
+
"actions": {
|
|
151
|
+
"type": "React.ReactNode",
|
|
152
|
+
"required": false,
|
|
153
|
+
"origin": "own",
|
|
154
|
+
"description": "At the end of the title row: the page's actions, most important last.\nOne primary Button at most; several more go in a MenuTrigger."
|
|
155
|
+
},
|
|
156
|
+
"children": {
|
|
157
|
+
"type": "React.ReactNode",
|
|
158
|
+
"required": false,
|
|
159
|
+
"origin": "own",
|
|
160
|
+
"description": "A row beneath, that belongs to the header rather than the page's\ncontent: the page's Tabs, or the filters its table answers to."
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
"propCounts": {
|
|
164
|
+
"own": 8,
|
|
165
|
+
"aria": 0,
|
|
166
|
+
"dom": 276,
|
|
167
|
+
"other": 0
|
|
168
|
+
}
|
|
169
|
+
}
|
package/dist/meta/Radio.json
CHANGED
|
@@ -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": "
|
|
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":
|
|
257
|
+
"own": 15,
|
|
206
258
|
"aria": 0,
|
|
207
259
|
"dom": 276,
|
|
208
260
|
"other": 0
|