ionbase-ui 0.18.1 → 0.19.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/meta/Avatar.json +66 -0
- package/dist/meta/AvatarGroup.json +57 -0
- package/dist/meta/Badge.json +65 -0
- package/dist/meta/Checkbox.json +82 -0
- package/dist/meta/Divider.json +39 -0
- package/dist/meta/FullCard.json +77 -0
- package/dist/meta/Header.json +59 -0
- package/dist/meta/Icon.json +54 -0
- package/dist/meta/Link.json +67 -0
- package/dist/meta/Logo.json +49 -0
- package/dist/meta/LogoMark.json +38 -0
- package/dist/meta/Menu.json +54 -0
- package/dist/meta/MenuItem.json +51 -0
- package/dist/meta/NavItem.json +53 -0
- package/dist/meta/PhoneInput.json +60 -0
- package/dist/meta/Popover.json +92 -0
- package/dist/meta/Radio.json +77 -0
- package/dist/meta/RadioGroup.json +84 -0
- package/dist/meta/ScrollProgress.json +41 -0
- package/dist/meta/TabItem.json +42 -0
- package/dist/meta/TableBody.json +36 -0
- package/dist/meta/TableCell.json +83 -0
- package/dist/meta/TableHead.json +39 -0
- package/dist/meta/TableRow.json +45 -0
- package/dist/meta/Tabs.json +85 -0
- package/dist/meta/Toast.json +81 -0
- package/dist/meta/ToastProvider.json +57 -0
- package/dist/meta/Toggle.json +76 -0
- package/dist/meta/Tooltip.json +74 -0
- package/dist/meta/components.json +1859 -76
- package/dist/meta/index.json +88 -59
- package/package.json +1 -1
package/dist/meta/TabItem.json
CHANGED
|
@@ -3,6 +3,48 @@
|
|
|
3
3
|
"source": "../../node_modules/.pnpm/react-stately@3.48.0_react@19.2.8/node_modules/react-stately/dist/types/src/collections/Item.d.ts",
|
|
4
4
|
"propsType": null,
|
|
5
5
|
"import": "import { TabItem } from 'ionbase-ui';",
|
|
6
|
+
"status": "stable",
|
|
7
|
+
"summary": "One tab and its panel. Re-exported from react-stately's collection Item — `title` is the tab label, children are the panel.",
|
|
8
|
+
"useWhen": [
|
|
9
|
+
"a child of Tabs — it is not usable anywhere else"
|
|
10
|
+
],
|
|
11
|
+
"useInstead": [
|
|
12
|
+
{
|
|
13
|
+
"when": "it is a row in a dropdown list",
|
|
14
|
+
"use": "MenuItem"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"when": "it is a navigation destination",
|
|
18
|
+
"use": "NavItem"
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"composition": {
|
|
22
|
+
"order": [
|
|
23
|
+
"Tabs",
|
|
24
|
+
"TabItem"
|
|
25
|
+
],
|
|
26
|
+
"note": "A collection item, not a rendered component: Tabs reads it to build the collection, so it never appears in the DOM itself. That is why it exposes no props of its own here — `key` and `title` are the collection's API.",
|
|
27
|
+
"example": "<TabItem key=\"billing\" title=\"Billing\">Billing panel content</TabItem>"
|
|
28
|
+
},
|
|
29
|
+
"a11y": {
|
|
30
|
+
"guarantees": [
|
|
31
|
+
"the tab/panel roles, ids and aria-controls pairing are supplied by Tabs, not by this element"
|
|
32
|
+
],
|
|
33
|
+
"requires": [
|
|
34
|
+
"a stable `key` — it identifies the tab across renders and is what selection is expressed in",
|
|
35
|
+
"a `title` that reads as a label on its own"
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
"antiPatterns": [
|
|
39
|
+
{
|
|
40
|
+
"dont": "wrapping TabItem in a <div> or a fragment inside Tabs",
|
|
41
|
+
"why": "Tabs reads the collection from its direct children; a wrapper makes the item invisible to it"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"dont": "conditionally rendering TabItems with array indexes as keys",
|
|
45
|
+
"why": "selection is tracked by key, so the selected tab silently becomes a different tab"
|
|
46
|
+
}
|
|
47
|
+
],
|
|
6
48
|
"stylesheet": null,
|
|
7
49
|
"tokens": [],
|
|
8
50
|
"props": {},
|
package/dist/meta/TableBody.json
CHANGED
|
@@ -3,6 +3,42 @@
|
|
|
3
3
|
"source": "src/components/Table.tsx",
|
|
4
4
|
"propsType": null,
|
|
5
5
|
"import": "import { TableBody } from 'ionbase-ui';",
|
|
6
|
+
"status": "stable",
|
|
7
|
+
"summary": "The <tbody> section. Takes no props — it places the data rows and gives their cells body context.",
|
|
8
|
+
"useWhen": [
|
|
9
|
+
"every Table — the data rows go here"
|
|
10
|
+
],
|
|
11
|
+
"useInstead": [
|
|
12
|
+
{
|
|
13
|
+
"when": "the row names the columns",
|
|
14
|
+
"use": "TableHead"
|
|
15
|
+
}
|
|
16
|
+
],
|
|
17
|
+
"composition": {
|
|
18
|
+
"order": [
|
|
19
|
+
"Table",
|
|
20
|
+
"TableBody",
|
|
21
|
+
"TableRow",
|
|
22
|
+
"TableCell"
|
|
23
|
+
],
|
|
24
|
+
"note": "Zebra striping is read from each row's position inside this section rather than a prop repeated on every TableRow.",
|
|
25
|
+
"example": "<TableBody><TableRow><TableCell>Ada</TableCell></TableRow></TableBody>"
|
|
26
|
+
},
|
|
27
|
+
"a11y": {
|
|
28
|
+
"guarantees": [
|
|
29
|
+
"cells inside it default to <td>, and `scope` is inferred as `row` when a cell is marked `header`"
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
"antiPatterns": [
|
|
33
|
+
{
|
|
34
|
+
"dont": "rendering rows directly under Table with no TableBody",
|
|
35
|
+
"why": "the browser inserts a tbody anyway, but the head-or-body context does not exist, so cells cannot infer their scope"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"dont": "an empty TableBody with no empty state",
|
|
39
|
+
"why": "an empty table looks like a broken one — Table has no empty state of its own, so it is the caller's"
|
|
40
|
+
}
|
|
41
|
+
],
|
|
6
42
|
"stylesheet": "src/styles/table.css",
|
|
7
43
|
"tokens": [
|
|
8
44
|
"--border-default",
|
package/dist/meta/TableCell.json
CHANGED
|
@@ -4,6 +4,89 @@
|
|
|
4
4
|
"propsType": "TableCellProps",
|
|
5
5
|
"description": "One component covers Figma's `Table Cell` + `Cell Text`: the two are never\nused apart in the design (`Table Cell` always wraps exactly one `Cell\nText`), so splitting them into two exported components would only add API\nsurface for a composition nothing ever varies independently.\n\n`header` decides `<th>` vs `<td>` directly rather than a `type` prop that\ncould disagree with where the cell actually sits — a `<th>` rendered inside\n`<tbody>` is still a header cell to the browser and to CSS either way.",
|
|
6
6
|
"import": "import { TableCell } from 'ionbase-ui';",
|
|
7
|
+
"status": "stable",
|
|
8
|
+
"summary": "One cell, covering Figma's Table Cell and Cell Text together. `header` decides <th> versus <td>.",
|
|
9
|
+
"useWhen": [
|
|
10
|
+
"every cell in a Table, header or data"
|
|
11
|
+
],
|
|
12
|
+
"useInstead": [
|
|
13
|
+
{
|
|
14
|
+
"when": "the content is a status label",
|
|
15
|
+
"use": "Badge",
|
|
16
|
+
"why": "put it inside the cell — the cell is the container, not the label"
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"variants": {
|
|
20
|
+
"scope": {
|
|
21
|
+
"col": {
|
|
22
|
+
"use": "a column header — inferred inside TableHead"
|
|
23
|
+
},
|
|
24
|
+
"row": {
|
|
25
|
+
"use": "a row header, e.g. the name column — inferred for a `header` cell in TableBody"
|
|
26
|
+
},
|
|
27
|
+
"colgroup": {
|
|
28
|
+
"use": "a header spanning several columns, with colspan"
|
|
29
|
+
},
|
|
30
|
+
"rowgroup": {
|
|
31
|
+
"use": "a header spanning several rows, with rowspan"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"align": {
|
|
35
|
+
"leading": {
|
|
36
|
+
"use": "the default — text, names, identifiers"
|
|
37
|
+
},
|
|
38
|
+
"trailing": {
|
|
39
|
+
"use": "numbers, currency and dates, so digits line up column-wise"
|
|
40
|
+
},
|
|
41
|
+
"center": {
|
|
42
|
+
"use": "icons, short status marks, checkboxes"
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"variant": {
|
|
46
|
+
"default": {
|
|
47
|
+
"use": "the default — body text and icon colours"
|
|
48
|
+
},
|
|
49
|
+
"link": {
|
|
50
|
+
"use": "recolours the content to `text/link` / `icon/primary` for a cell whose content navigates"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"slots": {
|
|
55
|
+
"icon": {
|
|
56
|
+
"accepts": "Icon",
|
|
57
|
+
"note": "leading icon; omit its `label`"
|
|
58
|
+
},
|
|
59
|
+
"trailingIcon": {
|
|
60
|
+
"accepts": "Icon",
|
|
61
|
+
"note": "trailing icon; same rule"
|
|
62
|
+
},
|
|
63
|
+
"children": {
|
|
64
|
+
"accepts": "any"
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"a11y": {
|
|
68
|
+
"guarantees": [
|
|
69
|
+
"`scope` is inferred when omitted — `col` in TableHead, `row` in TableBody — and can be set explicitly when the inference is wrong",
|
|
70
|
+
"`header` decides the element directly rather than a `type` prop that could disagree with where the cell sits"
|
|
71
|
+
],
|
|
72
|
+
"requires": [
|
|
73
|
+
"`scope=\"col\"` on header cells — inferred inside TableHead, but explicit for a header rendered outside it"
|
|
74
|
+
]
|
|
75
|
+
},
|
|
76
|
+
"antiPatterns": [
|
|
77
|
+
{
|
|
78
|
+
"dont": "`variant=\"link\"` on a cell with no link in it",
|
|
79
|
+
"why": "link-coloured text that does nothing is the clearest possible false affordance"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"dont": "leading-aligning a numeric column",
|
|
83
|
+
"why": "digits stop lining up, so the column can no longer be scanned for magnitude"
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"dont": "`showDivider` on every cell",
|
|
87
|
+
"why": "it is a column rule, not a row rule — on every cell it becomes a grid"
|
|
88
|
+
}
|
|
89
|
+
],
|
|
7
90
|
"stylesheet": "src/styles/table.css",
|
|
8
91
|
"tokens": [
|
|
9
92
|
"--border-default",
|
package/dist/meta/TableHead.json
CHANGED
|
@@ -3,6 +3,45 @@
|
|
|
3
3
|
"source": "src/components/Table.tsx",
|
|
4
4
|
"propsType": null,
|
|
5
5
|
"import": "import { TableHead } from 'ionbase-ui';",
|
|
6
|
+
"status": "stable",
|
|
7
|
+
"summary": "The <thead> section. Takes no props — it places the header row and gives its cells their head-or-body context.",
|
|
8
|
+
"useWhen": [
|
|
9
|
+
"every Table with column headers, which is every data table"
|
|
10
|
+
],
|
|
11
|
+
"useInstead": [
|
|
12
|
+
{
|
|
13
|
+
"when": "the rows are data",
|
|
14
|
+
"use": "TableBody"
|
|
15
|
+
}
|
|
16
|
+
],
|
|
17
|
+
"composition": {
|
|
18
|
+
"order": [
|
|
19
|
+
"Table",
|
|
20
|
+
"TableHead",
|
|
21
|
+
"TableRow",
|
|
22
|
+
"TableCell"
|
|
23
|
+
],
|
|
24
|
+
"note": "Exists so TableRow and TableCell can tell head from body through context, rather than the caller repeating a prop that has to stay in sync with where the row actually sits.",
|
|
25
|
+
"example": "<TableHead><TableRow><TableCell scope=\"col\">Name</TableCell></TableRow></TableHead>"
|
|
26
|
+
},
|
|
27
|
+
"a11y": {
|
|
28
|
+
"guarantees": [
|
|
29
|
+
"cells inside it default to <th scope=\"col\">, and a row-selection cell becomes the select-all header"
|
|
30
|
+
],
|
|
31
|
+
"requires": [
|
|
32
|
+
"a header row for every data table — without one, no data cell has a column to be associated with"
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
"antiPatterns": [
|
|
36
|
+
{
|
|
37
|
+
"dont": "a data table with no TableHead",
|
|
38
|
+
"why": "a screen-reader user hears values with no field names"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"dont": "styling a first TableBody row to look like a header",
|
|
42
|
+
"why": "it looks like a header and announces as data"
|
|
43
|
+
}
|
|
44
|
+
],
|
|
6
45
|
"stylesheet": "src/styles/table.css",
|
|
7
46
|
"tokens": [
|
|
8
47
|
"--border-default",
|
package/dist/meta/TableRow.json
CHANGED
|
@@ -4,6 +4,51 @@
|
|
|
4
4
|
"propsType": "TableRowProps",
|
|
5
5
|
"description": "A plain `<tr>`. Hover is CSS-only (`:hover` plus a `data-hovered` escape\nhatch, matching the rest of the system) rather than React Aria's\n`useHover`: a row is not itself an interactive element — nothing about it\ntakes focus or fires a click — so there is no keyboard-vs-pointer\ndistinction to track. A clickable row is a link or button inside a cell,\nthe same accessible pattern Menu and Table Cell's own link variant use;\nnesting an interactive role on `<tr>` itself is not valid HTML.",
|
|
6
6
|
"import": "import { TableRow } from 'ionbase-ui';",
|
|
7
|
+
"status": "stable",
|
|
8
|
+
"summary": "A plain <tr>. Hover is CSS-only; a row is not itself interactive.",
|
|
9
|
+
"useWhen": [
|
|
10
|
+
"every row, in either TableHead or TableBody"
|
|
11
|
+
],
|
|
12
|
+
"useInstead": [
|
|
13
|
+
{
|
|
14
|
+
"when": "the whole row should be clickable",
|
|
15
|
+
"use": "Link",
|
|
16
|
+
"why": "put the link or Button in a cell — nesting an interactive role on <tr> is not valid HTML"
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"slots": {
|
|
20
|
+
"selection": {
|
|
21
|
+
"accepts": "Checkbox props",
|
|
22
|
+
"note": "renders a leading Checkbox cell — a <th scope=\"col\"> select-all inside TableHead, a <td> inside TableBody. Takes the checkbox's own props rather than a boolean, since a selectable row needs `checked`/`onChange` wiring"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"a11y": {
|
|
26
|
+
"guarantees": [
|
|
27
|
+
"hover comes from CSS `:hover` plus a `data-hovered` escape hatch, not React Aria — a row takes no focus and fires no click, so there is no keyboard-versus-pointer distinction to track",
|
|
28
|
+
"the selection cell's element follows the section it sits in"
|
|
29
|
+
],
|
|
30
|
+
"requires": [
|
|
31
|
+
"every row-selection Checkbox to be labelled — those boxes have no visible label by design, so see Checkbox's own contract",
|
|
32
|
+
"`isSelected` alongside a checked selection checkbox, so the row's state is not carried by colour alone"
|
|
33
|
+
],
|
|
34
|
+
"notes": [
|
|
35
|
+
"TableRow itself is never named — a <tr> is not an interactive element and takes no accessible name. The naming requirement above belongs to the Checkbox inside it."
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
"antiPatterns": [
|
|
39
|
+
{
|
|
40
|
+
"dont": "`onClick` on TableRow",
|
|
41
|
+
"why": "it takes no focus, so a keyboard user can never fire it"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"dont": "`selection={{ checked }}` with no `onChange`",
|
|
45
|
+
"why": "a checkbox that cannot be changed reads as broken rather than as disabled"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"dont": "`isSelected` without a selection checkbox",
|
|
49
|
+
"why": "the row is tinted with nothing announcing why"
|
|
50
|
+
}
|
|
51
|
+
],
|
|
7
52
|
"stylesheet": "src/styles/table.css",
|
|
8
53
|
"tokens": [
|
|
9
54
|
"--border-default",
|
package/dist/meta/Tabs.json
CHANGED
|
@@ -3,6 +3,91 @@
|
|
|
3
3
|
"source": "src/components/Tabs.tsx",
|
|
4
4
|
"propsType": "TabsProps",
|
|
5
5
|
"import": "import { Tabs } from 'ionbase-ui';",
|
|
6
|
+
"status": "stable",
|
|
7
|
+
"summary": "A tab list and its panels, built on react-aria's tab collection. Children are TabItem.",
|
|
8
|
+
"useWhen": [
|
|
9
|
+
"one region of the page shows one of several peer views, and only one at a time",
|
|
10
|
+
"the views are peers — no ordering, no progression between them"
|
|
11
|
+
],
|
|
12
|
+
"useInstead": [
|
|
13
|
+
{
|
|
14
|
+
"when": "the steps must be completed in order",
|
|
15
|
+
"use": "Button",
|
|
16
|
+
"why": "tabs imply peers you may visit in any order; a wizard is a sequence"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"when": "the sections should all be readable at once, or printable",
|
|
20
|
+
"use": "Divider",
|
|
21
|
+
"why": "tabs hide everything but the active panel, including from Ctrl-F"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"when": "it is navigation between pages rather than panels within one",
|
|
25
|
+
"use": "NavItem"
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"composition": {
|
|
29
|
+
"order": [
|
|
30
|
+
"Tabs",
|
|
31
|
+
"TabItem"
|
|
32
|
+
],
|
|
33
|
+
"note": "TabItem comes from react-stately's collection Item — it takes no props of its own beyond `title` (the tab label) and `key`; its children are the panel.",
|
|
34
|
+
"example": "<Tabs aria-label=\"Account\"><TabItem key=\"profile\" title=\"Profile\">…</TabItem><TabItem key=\"billing\" title=\"Billing\">…</TabItem></Tabs>"
|
|
35
|
+
},
|
|
36
|
+
"variants": {
|
|
37
|
+
"type": {
|
|
38
|
+
"pill": {
|
|
39
|
+
"use": "the default — a filled track, for switching views inside a panel or card"
|
|
40
|
+
},
|
|
41
|
+
"underline": {
|
|
42
|
+
"use": "a rule under the active tab, for page-level sections"
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"size": {
|
|
46
|
+
"sm": {
|
|
47
|
+
"use": "dense panels and toolbars"
|
|
48
|
+
},
|
|
49
|
+
"md": {
|
|
50
|
+
"use": "the default"
|
|
51
|
+
},
|
|
52
|
+
"lg": {
|
|
53
|
+
"use": "page-level section switching"
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"orientation": {
|
|
57
|
+
"horizontal": {
|
|
58
|
+
"use": "the default"
|
|
59
|
+
},
|
|
60
|
+
"vertical": {
|
|
61
|
+
"use": "a stacked track with up/down arrow keys",
|
|
62
|
+
"caveat": "keyboard and ARIA are complete, but the decoration is not — the underline rule and the pill track's padding are still written for the horizontal axis. Figma has not specified the vertical drawing"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"a11y": {
|
|
67
|
+
"role": "tablist / tab / tabpanel",
|
|
68
|
+
"guarantees": [
|
|
69
|
+
"roving tabindex, arrow-key navigation and the aria-controls/aria-labelledby pairing between each tab and its panel come from react-aria",
|
|
70
|
+
"the focus ring shows for keyboard focus only, and hover does not latch on touch"
|
|
71
|
+
],
|
|
72
|
+
"requires": [
|
|
73
|
+
"`aria-label` or `aria-labelledby` on Tabs — the tab list is a named region",
|
|
74
|
+
"a stable `key` on every TabItem"
|
|
75
|
+
]
|
|
76
|
+
},
|
|
77
|
+
"antiPatterns": [
|
|
78
|
+
{
|
|
79
|
+
"dont": "tabs whose panels the user must read in order",
|
|
80
|
+
"why": "the role announces peers, and nothing stops a user landing on the last one first"
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"dont": "hiding required form fields behind a tab",
|
|
84
|
+
"why": "a validation error in an inactive panel is invisible; the user is told the form is invalid with nothing on screen to fix"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"dont": "one tab",
|
|
88
|
+
"why": "a tablist with a single tab is chrome with no choice in it"
|
|
89
|
+
}
|
|
90
|
+
],
|
|
6
91
|
"stylesheet": "src/styles/tabs.css",
|
|
7
92
|
"tokens": [
|
|
8
93
|
"--border-default",
|
package/dist/meta/Toast.json
CHANGED
|
@@ -4,6 +4,87 @@
|
|
|
4
4
|
"propsType": "ToastProps",
|
|
5
5
|
"description": "Toast — Figma `Toast` (820:1655).\n\nNeutral chrome on `surface/raised`; the intent is carried by the icon alone.\nA tinted panel floating over unknown content competes with whatever is\nbehind it, and makes Toast and Alert indistinguishable at a glance.\n\nAUTO-DISMISS PAUSES ON HOVER AND FOCUS. A toast that keeps counting down\nwhile being read or while its action has keyboard focus takes the action\naway mid-reach — WCAG 2.2.1 asks for exactly this. The timer restarts rather\nthan resumes, which is the forgiving direction.",
|
|
6
6
|
"import": "import { Toast } from 'ionbase-ui';",
|
|
7
|
+
"status": "stable",
|
|
8
|
+
"summary": "A transient notification on neutral chrome. Intent is carried by the icon, not by a tinted panel.",
|
|
9
|
+
"useWhen": [
|
|
10
|
+
"confirming that something the user just did succeeded or failed",
|
|
11
|
+
"the message is short, transient, and not required to complete a task"
|
|
12
|
+
],
|
|
13
|
+
"useInstead": [
|
|
14
|
+
{
|
|
15
|
+
"when": "the message must stay until the condition is resolved",
|
|
16
|
+
"use": "Alert",
|
|
17
|
+
"why": "a toast disappears, and anything the user must act on should not"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"when": "the message belongs to one field",
|
|
21
|
+
"use": "Input",
|
|
22
|
+
"why": "Input's error text sits with the field it is about"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"when": "you need a decision from the user",
|
|
26
|
+
"use": "Modal",
|
|
27
|
+
"why": "a toast offers one action and takes it away on a timer"
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"variants": {
|
|
31
|
+
"intent": {
|
|
32
|
+
"neutral": {
|
|
33
|
+
"use": "a plain fact with no status attached"
|
|
34
|
+
},
|
|
35
|
+
"primary": {
|
|
36
|
+
"use": "brand-flavoured confirmations"
|
|
37
|
+
},
|
|
38
|
+
"success": {
|
|
39
|
+
"use": "the action completed"
|
|
40
|
+
},
|
|
41
|
+
"warning": {
|
|
42
|
+
"use": "it completed with a caveat worth knowing"
|
|
43
|
+
},
|
|
44
|
+
"error": {
|
|
45
|
+
"use": "it failed — pair with a way to retry"
|
|
46
|
+
},
|
|
47
|
+
"information": {
|
|
48
|
+
"use": "the default — a neutral update"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"slots": {
|
|
53
|
+
"title": {
|
|
54
|
+
"accepts": "text"
|
|
55
|
+
},
|
|
56
|
+
"message": {
|
|
57
|
+
"accepts": "text"
|
|
58
|
+
},
|
|
59
|
+
"action": {
|
|
60
|
+
"accepts": "{ label, onPress }",
|
|
61
|
+
"note": "exactly one action. A second choice belongs in a Modal, which will still be there"
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"a11y": {
|
|
65
|
+
"guarantees": [
|
|
66
|
+
"auto-dismiss pauses on hover and on focus, and restarts rather than resumes — WCAG 2.2.1, and the forgiving direction",
|
|
67
|
+
"announcement comes from ToastProvider's live region, which is always present rather than appearing with its content"
|
|
68
|
+
],
|
|
69
|
+
"requires": [
|
|
70
|
+
"rendering inside a ToastProvider — a Toast on its own is not in a live region",
|
|
71
|
+
"`duration={null}` when the message carries an action the user genuinely needs"
|
|
72
|
+
]
|
|
73
|
+
},
|
|
74
|
+
"antiPatterns": [
|
|
75
|
+
{
|
|
76
|
+
"dont": "a toast for an error the user must fix",
|
|
77
|
+
"why": "it vanishes; the fix does not"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"dont": "two actions in one toast",
|
|
81
|
+
"why": "a timed choice is not a choice"
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"dont": "stacking several toasts for one operation",
|
|
85
|
+
"why": "the stack covers the page and the last one is the only one read"
|
|
86
|
+
}
|
|
87
|
+
],
|
|
7
88
|
"stylesheet": "src/styles/toast.css",
|
|
8
89
|
"tokens": [
|
|
9
90
|
"--border-subtle",
|
|
@@ -4,6 +4,63 @@
|
|
|
4
4
|
"propsType": "ToastProviderProps",
|
|
5
5
|
"description": "Renders the queue and supplies `useToast`.\n\nThe live region is the CONTAINER, declared once and always present. A region\nthat appears at the same moment as its content is not reliably announced —\nassistive tech has to be watching the node before the text lands in it.",
|
|
6
6
|
"import": "import { ToastProvider } from 'ionbase-ui';",
|
|
7
|
+
"status": "stable",
|
|
8
|
+
"summary": "Renders the toast queue and supplies the `useToast` hook. Mount once, near the app root.",
|
|
9
|
+
"useWhen": [
|
|
10
|
+
"the app shows toasts anywhere — this is the only way to get `useToast`"
|
|
11
|
+
],
|
|
12
|
+
"useInstead": [
|
|
13
|
+
{
|
|
14
|
+
"when": "you only need one persistent in-page message",
|
|
15
|
+
"use": "Alert",
|
|
16
|
+
"why": "no provider, no queue, and it stays put"
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"variants": {
|
|
20
|
+
"placement": {
|
|
21
|
+
"top-left": {
|
|
22
|
+
"use": "rare — for RTL layouts or where the top-right is occupied"
|
|
23
|
+
},
|
|
24
|
+
"top-right": {
|
|
25
|
+
"use": "the common desktop choice, out of the way of primary content"
|
|
26
|
+
},
|
|
27
|
+
"bottom-left": {
|
|
28
|
+
"use": "keeps toasts clear of a right-hand panel"
|
|
29
|
+
},
|
|
30
|
+
"bottom-right": {
|
|
31
|
+
"use": "close to where a save or submit action usually sits"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"slots": {
|
|
36
|
+
"children": {
|
|
37
|
+
"accepts": "any",
|
|
38
|
+
"note": "your app — the provider wraps it"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"a11y": {
|
|
42
|
+
"guarantees": [
|
|
43
|
+
"the live region is the container, declared once and always present — a region that appears at the same moment as its content is not reliably announced",
|
|
44
|
+
"`limit` drops the oldest toasts, so the stack can never cover the page"
|
|
45
|
+
],
|
|
46
|
+
"requires": [
|
|
47
|
+
"mounting exactly one ToastProvider — a second live region competes with the first"
|
|
48
|
+
]
|
|
49
|
+
},
|
|
50
|
+
"antiPatterns": [
|
|
51
|
+
{
|
|
52
|
+
"dont": "mounting a ToastProvider per route or per page",
|
|
53
|
+
"why": "toasts queued before the switch are unmounted mid-announcement, and two live regions announce over each other"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"dont": "placing it inside a Modal",
|
|
57
|
+
"why": "the toasts are removed from the tree when the modal closes, and hidden from assistive tech while it is open"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"dont": "raising `limit` to keep everything",
|
|
61
|
+
"why": "an unbounded stack covers the content the toasts are about"
|
|
62
|
+
}
|
|
63
|
+
],
|
|
7
64
|
"stylesheet": "src/styles/toast.css",
|
|
8
65
|
"tokens": [
|
|
9
66
|
"--border-subtle",
|
package/dist/meta/Toggle.json
CHANGED
|
@@ -4,6 +4,82 @@
|
|
|
4
4
|
"propsType": "ToggleProps",
|
|
5
5
|
"description": "Toggle is a checkbox with `role=\"switch\"`.\n\nNot a button with aria-pressed: a switch is a form value, and the checkbox\ngives form association and `:checked` for free. `role=\"switch\"` changes only\nhow it is announced — \"on/off\" rather than \"checked/unchecked\" — which is\nwhat Figma's On/Off states describe.\n\nThe visual difference from Checkbox is entirely in CSS; this component and\nCheckbox are near-identical by design rather than by accident, and are kept\napart because Figma models them as separate components with separate size\nramps.",
|
|
6
6
|
"import": "import { Toggle } from 'ionbase-ui';",
|
|
7
|
+
"status": "stable",
|
|
8
|
+
"summary": "A switch — a checkbox with role=\"switch\", announced as on/off.",
|
|
9
|
+
"useWhen": [
|
|
10
|
+
"the change takes effect immediately: a setting, a feature flag, a preference"
|
|
11
|
+
],
|
|
12
|
+
"useInstead": [
|
|
13
|
+
{
|
|
14
|
+
"when": "the value is collected and submitted with a form",
|
|
15
|
+
"use": "Checkbox",
|
|
16
|
+
"why": "a switch reads as taking effect now; a checkbox reads as a value being gathered"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"when": "there are more than two states",
|
|
20
|
+
"use": "RadioGroup"
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
"variants": {
|
|
24
|
+
"size": {
|
|
25
|
+
"sm": {
|
|
26
|
+
"use": "dense settings rows and table filters"
|
|
27
|
+
},
|
|
28
|
+
"md": {
|
|
29
|
+
"use": "the default"
|
|
30
|
+
},
|
|
31
|
+
"lg": {
|
|
32
|
+
"use": "touch targets and prominent single settings"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"intent": {
|
|
36
|
+
"brand": {
|
|
37
|
+
"use": "the default"
|
|
38
|
+
},
|
|
39
|
+
"neutral": {
|
|
40
|
+
"use": "a setting with no positive or negative reading — display and layout preferences"
|
|
41
|
+
},
|
|
42
|
+
"danger": {
|
|
43
|
+
"use": "turning on something destructive or hard to undo"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"slots": {
|
|
48
|
+
"children": {
|
|
49
|
+
"accepts": "text",
|
|
50
|
+
"note": "the visible label; omit for a bare switch and supply `aria-label`"
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"a11y": {
|
|
54
|
+
"role": "switch",
|
|
55
|
+
"guarantees": [
|
|
56
|
+
"a real <input type=\"checkbox\"> underneath, so form association, label clicking and `:checked` come from the platform",
|
|
57
|
+
"`role=\"switch\"` changes only the announcement — \"on/off\" rather than \"checked/unchecked\""
|
|
58
|
+
],
|
|
59
|
+
"requires": [
|
|
60
|
+
"`children`, or `aria-label` when there is no visible label"
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
"antiPatterns": [
|
|
64
|
+
{
|
|
65
|
+
"dont": "a Toggle with a Save button beside it",
|
|
66
|
+
"why": "a switch says the change is already applied; if it needs saving it is a Checkbox"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"dont": "labelling a Toggle \"Enable dark mode?\" as a question",
|
|
70
|
+
"why": "a switch label names the thing being switched, not a question about it"
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"dont": "a button with `aria-pressed` for a setting",
|
|
74
|
+
"why": "a switch is a form value; the checkbox gives form association and `:checked` for free"
|
|
75
|
+
}
|
|
76
|
+
],
|
|
77
|
+
"deprecated": [
|
|
78
|
+
{
|
|
79
|
+
"prop": "disabled",
|
|
80
|
+
"replacement": "isDisabled"
|
|
81
|
+
}
|
|
82
|
+
],
|
|
7
83
|
"stylesheet": "src/styles/toggle.css",
|
|
8
84
|
"tokens": [
|
|
9
85
|
"--border-disabled",
|