ionbase-ui 0.81.0 → 0.84.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/DatePicker.d.ts +1 -1
- package/dist/components/DatePicker.d.ts.map +1 -1
- package/dist/components/DatePicker.js +14 -6
- package/dist/components/DatePicker.js.map +1 -1
- package/dist/components/DateRangePicker.d.ts +1 -1
- package/dist/components/DateRangePicker.d.ts.map +1 -1
- package/dist/components/DateRangePicker.js +14 -6
- package/dist/components/DateRangePicker.js.map +1 -1
- 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/TimeField.d.ts +1 -1
- package/dist/components/TimeField.d.ts.map +1 -1
- package/dist/components/index.d.ts +4 -2
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +2 -1
- package/dist/components/index.js.map +1 -1
- package/dist/figma-descriptions.json +86 -76
- package/dist/figma-map.json +142 -38
- package/dist/meta/DatePicker.json +3 -2
- package/dist/meta/DateRangePicker.json +3 -2
- 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/TimeField.json +1 -1
- package/dist/meta/components.json +841 -109
- package/dist/meta/contrast.json +240 -32
- package/dist/meta/index.json +31 -3
- package/dist/meta/patterns/PageShell.json +18 -5
- package/dist/meta/patterns/index.json +2 -1
- package/dist/styles/index.css +1 -0
- package/dist/styles/menu.css +153 -32
- package/dist/styles/page-header.css +94 -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.84.0",
|
|
4
4
|
"generated": "by scripts/build-meta.mjs — do not edit; intent lives in meta/*.json",
|
|
5
5
|
"hooks": [
|
|
6
6
|
"useAgentRun",
|
|
@@ -4181,7 +4181,8 @@
|
|
|
4181
4181
|
"every day cell carries the full date as its accessible name in the reader's own language, so the narrow weekday headers are never load-bearing",
|
|
4182
4182
|
"unavailable and disabled days are distinguished visually and in the accessible name, not by colour alone",
|
|
4183
4183
|
"today is marked with a dot rather than a ring, so it cannot be mistaken for a second selected day",
|
|
4184
|
-
"the selected fill and the segment focus box are redeclared under forced-colors, where background-color is discarded"
|
|
4184
|
+
"the selected fill and the segment focus box are redeclared under forced-colors, where background-color is discarded",
|
|
4185
|
+
"a typed date outside `minValue`/`maxValue` turns the field invalid and names the bound in the reader's own format, without `isInvalid` — the value is kept, not silently clamped"
|
|
4185
4186
|
],
|
|
4186
4187
|
"requires": [
|
|
4187
4188
|
"`label`, or an `aria-label` when no visible label is rendered",
|
|
@@ -4289,7 +4290,7 @@
|
|
|
4289
4290
|
"type": "React.ReactNode",
|
|
4290
4291
|
"required": false,
|
|
4291
4292
|
"origin": "own",
|
|
4292
|
-
"description": "Replaces the helper text
|
|
4293
|
+
"description": "Replaces the helper text while the field is invalid — `isInvalid`, or its own bounds check."
|
|
4293
4294
|
},
|
|
4294
4295
|
"isInvalid": {
|
|
4295
4296
|
"type": "boolean | undefined",
|
|
@@ -4444,7 +4445,8 @@
|
|
|
4444
4445
|
"preset rows are buttons in a labelled group carrying aria-pressed, so 'which shortcut is active' is answerable without seeing the tint",
|
|
4445
4446
|
"the selected preset is marked by weight as well as by background, so it does not rely on colour alone",
|
|
4446
4447
|
"range endpoints and the band between them keep their fill under forced-colors, where background-color is otherwise discarded",
|
|
4447
|
-
"the rail stacks above the grids below 32rem rather than being hidden, because shortcuts matter most on the device where dragging across two months is worst"
|
|
4448
|
+
"the rail stacks above the grids below 32rem rather than being hidden, because shortcuts matter most on the device where dragging across two months is worst",
|
|
4449
|
+
"a typed date outside `minValue`/`maxValue`, or an end before the start, turns the field invalid with React Aria's localized message, without `isInvalid` — the value is kept, not silently clamped"
|
|
4448
4450
|
],
|
|
4449
4451
|
"requires": [
|
|
4450
4452
|
"`label`, or an `aria-label` when no visible label is rendered",
|
|
@@ -4545,7 +4547,7 @@
|
|
|
4545
4547
|
"type": "React.ReactNode",
|
|
4546
4548
|
"required": false,
|
|
4547
4549
|
"origin": "own",
|
|
4548
|
-
"description": "Replaces the helper text
|
|
4550
|
+
"description": "Replaces the helper text while the field is invalid — `isInvalid`, or its own bounds check."
|
|
4549
4551
|
},
|
|
4550
4552
|
"isInvalid": {
|
|
4551
4553
|
"type": "boolean | undefined",
|
|
@@ -7022,87 +7024,597 @@
|
|
|
7022
7024
|
"required": false,
|
|
7023
7025
|
"origin": "own",
|
|
7024
7026
|
"values": [
|
|
7025
|
-
"sm",
|
|
7026
|
-
"lg"
|
|
7027
|
+
"sm",
|
|
7028
|
+
"lg"
|
|
7029
|
+
]
|
|
7030
|
+
},
|
|
7031
|
+
"label": {
|
|
7032
|
+
"type": "string | undefined",
|
|
7033
|
+
"required": false,
|
|
7034
|
+
"origin": "own",
|
|
7035
|
+
"description": "Accessible name for the mark used standalone. Omit when it sits beside\na visible wordmark, which already carries the name."
|
|
7036
|
+
}
|
|
7037
|
+
},
|
|
7038
|
+
"propCounts": {
|
|
7039
|
+
"own": 2,
|
|
7040
|
+
"aria": 0,
|
|
7041
|
+
"dom": 487,
|
|
7042
|
+
"other": 0
|
|
7043
|
+
}
|
|
7044
|
+
},
|
|
7045
|
+
"Menu": {
|
|
7046
|
+
"name": "Menu",
|
|
7047
|
+
"source": "src/components/Menu.tsx",
|
|
7048
|
+
"propsType": "MenuProps",
|
|
7049
|
+
"description": "Menu — Figma `Menu` (82:306), `Menu Item` and `Menu Section Title`.\n\nA real ARIA menu: `role=\"menu\"`, one tab stop, arrow keys, Home and End,\ntypeahead, and disabled rows listed but skipped. Figma's `Type` is\n`selectionMode` — Single draws one check, Multi draws several — and with\na selection mode the rows become `menuitemradio` / `menuitemcheckbox` and\nannounce their checked state.\n\nOn its own it is the surface only, rendered in flow. Inside a MenuTrigger it\nfloats, opens and closes, is named by its trigger, and can open submenus.",
|
|
7050
|
+
"import": "import { Menu } from 'ionbase-ui';",
|
|
7051
|
+
"status": "stable",
|
|
7052
|
+
"summary": "An ARIA menu: one tab stop, arrow keys, typeahead, and optional single or multiple selection. Children are MenuItem and MenuSection. Inside a MenuTrigger it floats, opens and closes, and can open submenus; on its own it renders in flow.",
|
|
7053
|
+
"useWhen": [
|
|
7054
|
+
"a list of actions or choices for the thing the user is on — row actions, a workspace switcher, a sort order",
|
|
7055
|
+
"the rows need icons, a selected check, or grouping under headings — more than a native <select> can hold"
|
|
7056
|
+
],
|
|
7057
|
+
"useInstead": [
|
|
7058
|
+
{
|
|
7059
|
+
"when": "a button opens it",
|
|
7060
|
+
"use": "MenuTrigger",
|
|
7061
|
+
"why": "it gives the trigger aria-haspopup and aria-expanded, opens on ArrowDown, and closes on an action and returns focus — a Popover round a Menu does none of that"
|
|
7062
|
+
},
|
|
7063
|
+
{
|
|
7064
|
+
"when": "one value is picked for a form field from a modest list of plain text options",
|
|
7065
|
+
"use": "Select",
|
|
7066
|
+
"why": "a form value is a listbox, not a menu; the native picker brings type-ahead and the mobile platform picker for free"
|
|
7067
|
+
},
|
|
7068
|
+
{
|
|
7069
|
+
"when": "the user types to narrow a long list down to one value",
|
|
7070
|
+
"use": "Combobox"
|
|
7071
|
+
},
|
|
7072
|
+
{
|
|
7073
|
+
"when": "it is primary navigation rather than a list of actions",
|
|
7074
|
+
"use": "NavItem",
|
|
7075
|
+
"why": "a menu's rows are actions; links to pages belong in the document's navigation, where a screen reader's landmarks find them"
|
|
7076
|
+
},
|
|
7077
|
+
{
|
|
7078
|
+
"when": "any action or page should be reachable by searching",
|
|
7079
|
+
"use": "CommandPalette"
|
|
7080
|
+
}
|
|
7081
|
+
],
|
|
7082
|
+
"composition": {
|
|
7083
|
+
"order": [
|
|
7084
|
+
"Menu",
|
|
7085
|
+
"MenuSection",
|
|
7086
|
+
"MenuItem"
|
|
7087
|
+
],
|
|
7088
|
+
"note": "MenuItem and MenuSection are collection elements: Menu reads them from its DIRECT children to build the collection, and neither renders anything itself. Every MenuItem needs a `key`, and `onAction`, `selectedKeys` and `disabledKeys` all speak in those keys. To open it from a button, put the Button and the Menu inside a MenuTrigger.",
|
|
7089
|
+
"example": "<Menu aria-label=\"Row actions\" onAction={(key) => run(key)}><MenuSection title=\"Edit\"><MenuItem key=\"rename\" icon={<Icon as={Pencil} />}>Rename</MenuItem><MenuItem key=\"duplicate\">Duplicate</MenuItem></MenuSection><MenuSection aria-label=\"Danger\"><MenuItem key=\"archive\" isDisabled>Archive</MenuItem></MenuSection></Menu>"
|
|
7090
|
+
},
|
|
7091
|
+
"variants": {
|
|
7092
|
+
"selectionMode": {
|
|
7093
|
+
"none": {
|
|
7094
|
+
"use": "the default — a list of actions. Rows are `menuitem`, and there is no check slot"
|
|
7095
|
+
},
|
|
7096
|
+
"single": {
|
|
7097
|
+
"use": "Figma's Type=Single — one current choice, such as a sort order or the active workspace. Rows are `menuitemradio`"
|
|
7098
|
+
},
|
|
7099
|
+
"multiple": {
|
|
7100
|
+
"use": "Figma's Type=Multi — independent toggles, such as visible columns. Rows are `menuitemcheckbox`"
|
|
7101
|
+
}
|
|
7102
|
+
}
|
|
7103
|
+
},
|
|
7104
|
+
"slots": {
|
|
7105
|
+
"children": {
|
|
7106
|
+
"accepts": [
|
|
7107
|
+
"MenuItem",
|
|
7108
|
+
"MenuSection"
|
|
7109
|
+
]
|
|
7110
|
+
}
|
|
7111
|
+
},
|
|
7112
|
+
"a11y": {
|
|
7113
|
+
"role": "menu",
|
|
7114
|
+
"guarantees": [
|
|
7115
|
+
"one tab stop; arrow keys move between rows, Home and End jump, and typing a letter moves to the next row starting with it",
|
|
7116
|
+
"disabled rows are listed and announced as unavailable, and the arrow keys skip them",
|
|
7117
|
+
"with a selection mode, rows are `menuitemradio` or `menuitemcheckbox` and announce `aria-checked` — the check glyph is never the only signal",
|
|
7118
|
+
"the pointer and the keyboard share one highlighted row: hovering a row focuses it"
|
|
7119
|
+
],
|
|
7120
|
+
"requires": [
|
|
7121
|
+
"an accessible name — `aria-label` or `aria-labelledby` naming what the actions are for"
|
|
7122
|
+
],
|
|
7123
|
+
"notes": [
|
|
7124
|
+
"A menu is not a form control. It has no `name` and submits nothing; `selectedKeys` is state you hold.",
|
|
7125
|
+
"Titled sections are named groups. An untitled section needs `aria-label`, and is set off by a rule.",
|
|
7126
|
+
"Submenus need a MenuTrigger. In a standalone Menu a row with MenuItem children renders as a plain row: there is no root to open a submenu from."
|
|
7127
|
+
]
|
|
7128
|
+
},
|
|
7129
|
+
"antiPatterns": [
|
|
7130
|
+
{
|
|
7131
|
+
"dont": "wrapping MenuItems in a <div>, a fragment or your own component inside Menu",
|
|
7132
|
+
"why": "Menu reads its collection from its direct children; a wrapped row is invisible to it and renders nothing"
|
|
7133
|
+
},
|
|
7134
|
+
{
|
|
7135
|
+
"dont": "an `onClick` on MenuItem",
|
|
7136
|
+
"why": "MenuItem renders nothing, so there is no element to click. Pass `onAction` to Menu; it receives the item's key, from the pointer, Enter and Space alike"
|
|
7137
|
+
},
|
|
7138
|
+
{
|
|
7139
|
+
"dont": "using Menu for a form field's value",
|
|
7140
|
+
"why": "a screen reader announces a menu as actions, and a form cannot read it. Use Select or Combobox"
|
|
7141
|
+
},
|
|
7142
|
+
{
|
|
7143
|
+
"dont": "putting links to other pages in a Menu",
|
|
7144
|
+
"why": "they vanish from the page's link list and landmarks. Navigation belongs in NavItem or Sidebar"
|
|
7145
|
+
}
|
|
7146
|
+
],
|
|
7147
|
+
"stylesheet": "src/styles/menu.css",
|
|
7148
|
+
"tokens": [
|
|
7149
|
+
"--border-focus",
|
|
7150
|
+
"--border-strong",
|
|
7151
|
+
"--border-subtle",
|
|
7152
|
+
"--border-width-default",
|
|
7153
|
+
"--border-width-thick",
|
|
7154
|
+
"--font-family-sans",
|
|
7155
|
+
"--font-weight-regular",
|
|
7156
|
+
"--icon-default",
|
|
7157
|
+
"--icon-disabled",
|
|
7158
|
+
"--icon-primary",
|
|
7159
|
+
"--icon-size-sm",
|
|
7160
|
+
"--ion-duration-base",
|
|
7161
|
+
"--ion-ease-out",
|
|
7162
|
+
"--ion-menu-min-width",
|
|
7163
|
+
"--ion-shadow-shadow-lg",
|
|
7164
|
+
"--radius-sm",
|
|
7165
|
+
"--radius-xl",
|
|
7166
|
+
"--spacing-12",
|
|
7167
|
+
"--spacing-2",
|
|
7168
|
+
"--spacing-4",
|
|
7169
|
+
"--spacing-40",
|
|
7170
|
+
"--spacing-6",
|
|
7171
|
+
"--spacing-8",
|
|
7172
|
+
"--surface-default",
|
|
7173
|
+
"--surface-hover",
|
|
7174
|
+
"--surface-primary-subtle",
|
|
7175
|
+
"--text-disabled",
|
|
7176
|
+
"--text-primary",
|
|
7177
|
+
"--text-secondary",
|
|
7178
|
+
"--text-tertiary",
|
|
7179
|
+
"--type-body",
|
|
7180
|
+
"--type-body-line-height",
|
|
7181
|
+
"--type-caption",
|
|
7182
|
+
"--type-caption-line-height"
|
|
7183
|
+
],
|
|
7184
|
+
"props": {
|
|
7185
|
+
"className": {
|
|
7186
|
+
"type": "string | undefined",
|
|
7187
|
+
"required": false,
|
|
7188
|
+
"origin": "own"
|
|
7189
|
+
},
|
|
7190
|
+
"style": {
|
|
7191
|
+
"type": "React.CSSProperties | undefined",
|
|
7192
|
+
"required": false,
|
|
7193
|
+
"origin": "own"
|
|
7194
|
+
},
|
|
7195
|
+
"escapeKeyBehavior": {
|
|
7196
|
+
"type": "\"none\" | \"clearSelection\" | undefined",
|
|
7197
|
+
"required": false,
|
|
7198
|
+
"origin": "aria",
|
|
7199
|
+
"description": "Whether pressing the escape key should clear selection in the menu or not.\n\nMost experiences should not modify this option as it eliminates a keyboard user's ability to\neasily clear selection. Only use if the escape key is being handled externally or should not\ntrigger selection clearing contextually.",
|
|
7200
|
+
"values": [
|
|
7201
|
+
"none",
|
|
7202
|
+
"clearSelection"
|
|
7203
|
+
],
|
|
7204
|
+
"tags": {
|
|
7205
|
+
"default": "'clearSelection'"
|
|
7206
|
+
}
|
|
7207
|
+
},
|
|
7208
|
+
"autoFocus": {
|
|
7209
|
+
"type": "boolean | FocusStrategy | undefined",
|
|
7210
|
+
"required": false,
|
|
7211
|
+
"origin": "aria",
|
|
7212
|
+
"description": "Where the focus should be set."
|
|
7213
|
+
},
|
|
7214
|
+
"shouldFocusWrap": {
|
|
7215
|
+
"type": "boolean | undefined",
|
|
7216
|
+
"required": false,
|
|
7217
|
+
"origin": "aria",
|
|
7218
|
+
"description": "Whether keyboard navigation is circular."
|
|
7219
|
+
},
|
|
7220
|
+
"onAction": {
|
|
7221
|
+
"type": "((key: Key, value: T) => void) | undefined",
|
|
7222
|
+
"required": false,
|
|
7223
|
+
"origin": "aria",
|
|
7224
|
+
"description": "Handler that is called when an item is selected."
|
|
7225
|
+
},
|
|
7226
|
+
"onClose": {
|
|
7227
|
+
"type": "(() => void) | undefined",
|
|
7228
|
+
"required": false,
|
|
7229
|
+
"origin": "aria",
|
|
7230
|
+
"description": "Handler that is called when the menu should close after selecting an item."
|
|
7231
|
+
},
|
|
7232
|
+
"children": {
|
|
7233
|
+
"type": "CollectionChildren<T>",
|
|
7234
|
+
"required": true,
|
|
7235
|
+
"origin": "aria",
|
|
7236
|
+
"description": "The contents of the collection."
|
|
7237
|
+
},
|
|
7238
|
+
"items": {
|
|
7239
|
+
"type": "Iterable<T> | undefined",
|
|
7240
|
+
"required": false,
|
|
7241
|
+
"origin": "aria",
|
|
7242
|
+
"description": "Item objects in the collection."
|
|
7243
|
+
},
|
|
7244
|
+
"disabledKeys": {
|
|
7245
|
+
"type": "Iterable<Key> | undefined",
|
|
7246
|
+
"required": false,
|
|
7247
|
+
"origin": "aria",
|
|
7248
|
+
"description": "The item keys that are disabled. These items cannot be selected, focused, or otherwise\ninteracted with."
|
|
7249
|
+
},
|
|
7250
|
+
"selectionMode": {
|
|
7251
|
+
"type": "SelectionMode | undefined",
|
|
7252
|
+
"required": false,
|
|
7253
|
+
"origin": "aria",
|
|
7254
|
+
"description": "The type of selection that is allowed in the collection.",
|
|
7255
|
+
"values": [
|
|
7256
|
+
"multiple",
|
|
7257
|
+
"none",
|
|
7258
|
+
"single"
|
|
7259
|
+
]
|
|
7260
|
+
},
|
|
7261
|
+
"disallowEmptySelection": {
|
|
7262
|
+
"type": "boolean | undefined",
|
|
7263
|
+
"required": false,
|
|
7264
|
+
"origin": "aria",
|
|
7265
|
+
"description": "Whether the collection allows empty selection."
|
|
7266
|
+
},
|
|
7267
|
+
"selectedKeys": {
|
|
7268
|
+
"type": "Iterable<Key> | \"all\" | undefined",
|
|
7269
|
+
"required": false,
|
|
7270
|
+
"origin": "aria",
|
|
7271
|
+
"description": "The currently selected keys in the collection (controlled)."
|
|
7272
|
+
},
|
|
7273
|
+
"defaultSelectedKeys": {
|
|
7274
|
+
"type": "Iterable<Key> | \"all\" | undefined",
|
|
7275
|
+
"required": false,
|
|
7276
|
+
"origin": "aria",
|
|
7277
|
+
"description": "The initial selected keys in the collection (uncontrolled)."
|
|
7278
|
+
},
|
|
7279
|
+
"onSelectionChange": {
|
|
7280
|
+
"type": "((keys: Selection) => void) | undefined",
|
|
7281
|
+
"required": false,
|
|
7282
|
+
"origin": "aria",
|
|
7283
|
+
"description": "Handler that is called when the selection changes."
|
|
7284
|
+
},
|
|
7285
|
+
"id": {
|
|
7286
|
+
"type": "string | undefined",
|
|
7287
|
+
"required": false,
|
|
7288
|
+
"origin": "aria",
|
|
7289
|
+
"description": "The element's unique identifier. See\n[MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id)."
|
|
7290
|
+
},
|
|
7291
|
+
"aria-label": {
|
|
7292
|
+
"type": "string | undefined",
|
|
7293
|
+
"required": false,
|
|
7294
|
+
"origin": "aria",
|
|
7295
|
+
"description": "Defines a string value that labels the current element."
|
|
7296
|
+
},
|
|
7297
|
+
"aria-labelledby": {
|
|
7298
|
+
"type": "string | undefined",
|
|
7299
|
+
"required": false,
|
|
7300
|
+
"origin": "aria",
|
|
7301
|
+
"description": "Identifies the element (or elements) that labels the current element."
|
|
7302
|
+
},
|
|
7303
|
+
"aria-describedby": {
|
|
7304
|
+
"type": "string | undefined",
|
|
7305
|
+
"required": false,
|
|
7306
|
+
"origin": "aria",
|
|
7307
|
+
"description": "Identifies the element (or elements) that describes the object."
|
|
7308
|
+
},
|
|
7309
|
+
"aria-details": {
|
|
7310
|
+
"type": "string | undefined",
|
|
7311
|
+
"required": false,
|
|
7312
|
+
"origin": "aria",
|
|
7313
|
+
"description": "Identifies the element (or elements) that provide a detailed, extended description for the\nobject."
|
|
7314
|
+
}
|
|
7315
|
+
},
|
|
7316
|
+
"propCounts": {
|
|
7317
|
+
"own": 2,
|
|
7318
|
+
"aria": 18,
|
|
7319
|
+
"dom": 0,
|
|
7320
|
+
"other": 0
|
|
7321
|
+
}
|
|
7322
|
+
},
|
|
7323
|
+
"MenuItem": {
|
|
7324
|
+
"name": "MenuItem",
|
|
7325
|
+
"source": "src/components/Menu.tsx",
|
|
7326
|
+
"propsType": "MenuItemProps",
|
|
7327
|
+
"description": "One row of a Menu. A collection element, like TabItem: it renders nothing\nitself — Menu reads its props and draws the row — so it only means anything\nas a direct child of Menu or MenuSection. Give it a `key`; that key is what\n`onAction` and `selectedKeys` speak in.",
|
|
7328
|
+
"import": "import { MenuItem } from 'ionbase-ui';",
|
|
7329
|
+
"status": "stable",
|
|
7330
|
+
"summary": "One row of a Menu. A collection element: Menu reads its props and draws the row as `menuitem`, `menuitemradio` or `menuitemcheckbox`.",
|
|
7331
|
+
"useWhen": [
|
|
7332
|
+
"a row in a Menu or a MenuSection — it is not usable anywhere else"
|
|
7333
|
+
],
|
|
7334
|
+
"useInstead": [
|
|
7335
|
+
{
|
|
7336
|
+
"when": "it is a top-level navigation destination",
|
|
7337
|
+
"use": "NavItem"
|
|
7338
|
+
},
|
|
7339
|
+
{
|
|
7340
|
+
"when": "it is a standalone action outside a list",
|
|
7341
|
+
"use": "Button"
|
|
7342
|
+
}
|
|
7343
|
+
],
|
|
7344
|
+
"composition": {
|
|
7345
|
+
"order": [
|
|
7346
|
+
"Menu",
|
|
7347
|
+
"MenuItem"
|
|
7348
|
+
],
|
|
7349
|
+
"note": "A collection element, like TabItem: it renders nothing itself and never appears in the DOM. `key` identifies it to Menu's `onAction`, `selectedKeys` and `disabledKeys`.",
|
|
7350
|
+
"example": "<MenuItem key=\"duplicate\" icon={<Icon as={Copy} />}>Duplicate</MenuItem>\n<MenuItem key=\"move\" title=\"Move to\"><MenuItem key=\"archive\">Archive</MenuItem></MenuItem>"
|
|
7351
|
+
},
|
|
7352
|
+
"slots": {
|
|
7353
|
+
"icon": {
|
|
7354
|
+
"accepts": "Icon",
|
|
7355
|
+
"note": "leading icon; omit its `label` — the row's text names it"
|
|
7356
|
+
},
|
|
7357
|
+
"children": {
|
|
7358
|
+
"accepts": "text",
|
|
7359
|
+
"note": "the row label"
|
|
7360
|
+
},
|
|
7361
|
+
"title": {
|
|
7362
|
+
"accepts": "text",
|
|
7363
|
+
"note": "only on a row that opens a submenu: the row's label, while its children are the submenu's MenuItems. Submenus open only inside a MenuTrigger"
|
|
7364
|
+
}
|
|
7365
|
+
},
|
|
7366
|
+
"a11y": {
|
|
7367
|
+
"guarantees": [
|
|
7368
|
+
"the role, `aria-checked` and `aria-disabled` are supplied by Menu from its selection mode and keys, not by this element",
|
|
7369
|
+
"the check glyph occupies its slot whenever the menu has a selection mode, so rows never reflow as the selection moves"
|
|
7370
|
+
],
|
|
7371
|
+
"requires": [
|
|
7372
|
+
"a stable `key`",
|
|
7373
|
+
"text in `children`, or `textValue` when the children are not plain text — typeahead matches against it"
|
|
7374
|
+
]
|
|
7375
|
+
},
|
|
7376
|
+
"antiPatterns": [
|
|
7377
|
+
{
|
|
7378
|
+
"dont": "using MenuItem outside a Menu",
|
|
7379
|
+
"why": "it renders nothing on its own"
|
|
7380
|
+
},
|
|
7381
|
+
{
|
|
7382
|
+
"dont": "an icon-only MenuItem with no children",
|
|
7383
|
+
"why": "the row announces nothing and typeahead cannot reach it"
|
|
7384
|
+
},
|
|
7385
|
+
{
|
|
7386
|
+
"dont": "array indexes as keys in a list that can change",
|
|
7387
|
+
"why": "selection and actions are expressed in keys, so the selected row silently becomes a different row"
|
|
7388
|
+
}
|
|
7389
|
+
],
|
|
7390
|
+
"deprecated": [
|
|
7391
|
+
{
|
|
7392
|
+
"prop": "disabled",
|
|
7393
|
+
"replacement": "isDisabled"
|
|
7394
|
+
},
|
|
7395
|
+
{
|
|
7396
|
+
"prop": "isSelected",
|
|
7397
|
+
"note": "Put the item's key in Menu's `selectedKeys` and set its `selectionMode`."
|
|
7398
|
+
}
|
|
7399
|
+
],
|
|
7400
|
+
"stylesheet": "src/styles/menu.css",
|
|
7401
|
+
"tokens": [
|
|
7402
|
+
"--border-focus",
|
|
7403
|
+
"--border-strong",
|
|
7404
|
+
"--border-subtle",
|
|
7405
|
+
"--border-width-default",
|
|
7406
|
+
"--border-width-thick",
|
|
7407
|
+
"--font-family-sans",
|
|
7408
|
+
"--font-weight-regular",
|
|
7409
|
+
"--icon-default",
|
|
7410
|
+
"--icon-disabled",
|
|
7411
|
+
"--icon-primary",
|
|
7412
|
+
"--icon-size-sm",
|
|
7413
|
+
"--ion-duration-base",
|
|
7414
|
+
"--ion-ease-out",
|
|
7415
|
+
"--ion-menu-min-width",
|
|
7416
|
+
"--ion-shadow-shadow-lg",
|
|
7417
|
+
"--radius-sm",
|
|
7418
|
+
"--radius-xl",
|
|
7419
|
+
"--spacing-12",
|
|
7420
|
+
"--spacing-2",
|
|
7421
|
+
"--spacing-4",
|
|
7422
|
+
"--spacing-40",
|
|
7423
|
+
"--spacing-6",
|
|
7424
|
+
"--spacing-8",
|
|
7425
|
+
"--surface-default",
|
|
7426
|
+
"--surface-hover",
|
|
7427
|
+
"--surface-primary-subtle",
|
|
7428
|
+
"--text-disabled",
|
|
7429
|
+
"--text-primary",
|
|
7430
|
+
"--text-secondary",
|
|
7431
|
+
"--text-tertiary",
|
|
7432
|
+
"--type-body",
|
|
7433
|
+
"--type-body-line-height",
|
|
7434
|
+
"--type-caption",
|
|
7435
|
+
"--type-caption-line-height"
|
|
7436
|
+
],
|
|
7437
|
+
"props": {
|
|
7438
|
+
"title": {
|
|
7439
|
+
"type": "React.ReactNode",
|
|
7440
|
+
"required": false,
|
|
7441
|
+
"origin": "own",
|
|
7442
|
+
"description": "Only on a row that opens a submenu: the row's label. Its children are then\nthe submenu's MenuItems rather than its label. Submenus open only inside a\nMenuTrigger — a standalone Menu has nothing to open them from."
|
|
7443
|
+
},
|
|
7444
|
+
"icon": {
|
|
7445
|
+
"type": "React.ReactNode",
|
|
7446
|
+
"required": false,
|
|
7447
|
+
"origin": "own",
|
|
7448
|
+
"description": "Figma's `Show Leading Icon` + `Leading Icon` swap."
|
|
7449
|
+
},
|
|
7450
|
+
"isDisabled": {
|
|
7451
|
+
"type": "boolean | undefined",
|
|
7452
|
+
"required": false,
|
|
7453
|
+
"origin": "own",
|
|
7454
|
+
"description": "Whether the item is disabled. Listed, skipped by the arrow keys."
|
|
7455
|
+
},
|
|
7456
|
+
"disabled": {
|
|
7457
|
+
"type": "boolean | undefined",
|
|
7458
|
+
"required": false,
|
|
7459
|
+
"origin": "own",
|
|
7460
|
+
"tags": {
|
|
7461
|
+
"deprecated": "Use `isDisabled`. Accepted as an alias for one minor version."
|
|
7462
|
+
}
|
|
7463
|
+
},
|
|
7464
|
+
"isSelected": {
|
|
7465
|
+
"type": "boolean | undefined",
|
|
7466
|
+
"required": false,
|
|
7467
|
+
"origin": "own",
|
|
7468
|
+
"tags": {
|
|
7469
|
+
"deprecated": "Put the item's key in Menu's `selectedKeys`. Accepted for one\nminor version: when no item's key is in `selectedKeys` and Menu is given\nneither `selectedKeys` nor `defaultSelectedKeys`, the items passing this\nbecome the selection."
|
|
7470
|
+
}
|
|
7471
|
+
},
|
|
7472
|
+
"children": {
|
|
7473
|
+
"type": "ReactNode",
|
|
7474
|
+
"required": true,
|
|
7475
|
+
"origin": "aria",
|
|
7476
|
+
"description": "Rendered contents of the item or child items."
|
|
7477
|
+
},
|
|
7478
|
+
"textValue": {
|
|
7479
|
+
"type": "string | undefined",
|
|
7480
|
+
"required": false,
|
|
7481
|
+
"origin": "aria",
|
|
7482
|
+
"description": "A string representation of the item's contents, used for features like typeahead."
|
|
7483
|
+
},
|
|
7484
|
+
"aria-label": {
|
|
7485
|
+
"type": "string | undefined",
|
|
7486
|
+
"required": false,
|
|
7487
|
+
"origin": "aria",
|
|
7488
|
+
"description": "An accessibility label for this item."
|
|
7489
|
+
},
|
|
7490
|
+
"childItems": {
|
|
7491
|
+
"type": "Iterable<T> | undefined",
|
|
7492
|
+
"required": false,
|
|
7493
|
+
"origin": "aria",
|
|
7494
|
+
"description": "A list of child item objects. Used for dynamic collections."
|
|
7495
|
+
},
|
|
7496
|
+
"hasChildItems": {
|
|
7497
|
+
"type": "boolean | undefined",
|
|
7498
|
+
"required": false,
|
|
7499
|
+
"origin": "aria",
|
|
7500
|
+
"description": "Whether this item has children, even if not loaded yet."
|
|
7501
|
+
},
|
|
7502
|
+
"href": {
|
|
7503
|
+
"type": "string | undefined",
|
|
7504
|
+
"required": false,
|
|
7505
|
+
"origin": "aria",
|
|
7506
|
+
"description": "A URL to link to. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#href)."
|
|
7507
|
+
},
|
|
7508
|
+
"hrefLang": {
|
|
7509
|
+
"type": "string | undefined",
|
|
7510
|
+
"required": false,
|
|
7511
|
+
"origin": "aria",
|
|
7512
|
+
"description": "Hints at the human language of the linked URL.\nSee[MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#hreflang)."
|
|
7513
|
+
},
|
|
7514
|
+
"target": {
|
|
7515
|
+
"type": "HTMLAttributeAnchorTarget | undefined",
|
|
7516
|
+
"required": false,
|
|
7517
|
+
"origin": "aria",
|
|
7518
|
+
"description": "The target window for the link. See\n[MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#target)."
|
|
7519
|
+
},
|
|
7520
|
+
"rel": {
|
|
7521
|
+
"type": "string | undefined",
|
|
7522
|
+
"required": false,
|
|
7523
|
+
"origin": "aria",
|
|
7524
|
+
"description": "The relationship between the linked resource and the current page. See\n[MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel)."
|
|
7525
|
+
},
|
|
7526
|
+
"download": {
|
|
7527
|
+
"type": "string | boolean | undefined",
|
|
7528
|
+
"required": false,
|
|
7529
|
+
"origin": "aria",
|
|
7530
|
+
"description": "Causes the browser to download the linked URL. A string may be provided to suggest a file name.\nSee [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#download)."
|
|
7531
|
+
},
|
|
7532
|
+
"ping": {
|
|
7533
|
+
"type": "string | undefined",
|
|
7534
|
+
"required": false,
|
|
7535
|
+
"origin": "aria",
|
|
7536
|
+
"description": "A space-separated list of URLs to ping when the link is followed. See\n[MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#ping)."
|
|
7537
|
+
},
|
|
7538
|
+
"referrerPolicy": {
|
|
7539
|
+
"type": "HTMLAttributeReferrerPolicy | undefined",
|
|
7540
|
+
"required": false,
|
|
7541
|
+
"origin": "aria",
|
|
7542
|
+
"description": "How much of the referrer to send when following the link. See\n[MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#referrerpolicy).",
|
|
7543
|
+
"values": [
|
|
7544
|
+
"",
|
|
7545
|
+
"origin",
|
|
7546
|
+
"no-referrer",
|
|
7547
|
+
"no-referrer-when-downgrade",
|
|
7548
|
+
"origin-when-cross-origin",
|
|
7549
|
+
"same-origin",
|
|
7550
|
+
"strict-origin",
|
|
7551
|
+
"strict-origin-when-cross-origin",
|
|
7552
|
+
"unsafe-url"
|
|
7027
7553
|
]
|
|
7028
7554
|
},
|
|
7029
|
-
"
|
|
7030
|
-
"type": "
|
|
7555
|
+
"routerOptions": {
|
|
7556
|
+
"type": "undefined",
|
|
7031
7557
|
"required": false,
|
|
7032
|
-
"origin": "
|
|
7033
|
-
"description": "
|
|
7558
|
+
"origin": "aria",
|
|
7559
|
+
"description": "Options for the configured client side router."
|
|
7034
7560
|
}
|
|
7035
7561
|
},
|
|
7036
7562
|
"propCounts": {
|
|
7037
|
-
"own":
|
|
7038
|
-
"aria":
|
|
7039
|
-
"dom":
|
|
7563
|
+
"own": 5,
|
|
7564
|
+
"aria": 13,
|
|
7565
|
+
"dom": 0,
|
|
7040
7566
|
"other": 0
|
|
7041
7567
|
}
|
|
7042
7568
|
},
|
|
7043
|
-
"
|
|
7044
|
-
"name": "
|
|
7045
|
-
"source": "src/
|
|
7046
|
-
"propsType":
|
|
7047
|
-
"
|
|
7048
|
-
"import": "import { Menu } from 'ionbase-ui';",
|
|
7569
|
+
"MenuSection": {
|
|
7570
|
+
"name": "MenuSection",
|
|
7571
|
+
"source": "../../node_modules/.pnpm/react-stately@3.48.0_react@19.2.8/node_modules/react-stately/dist/types/src/collections/Section.d.ts",
|
|
7572
|
+
"propsType": null,
|
|
7573
|
+
"import": "import { MenuSection } from 'ionbase-ui';",
|
|
7049
7574
|
"status": "stable",
|
|
7050
|
-
"summary": "
|
|
7575
|
+
"summary": "A named group of MenuItems. Re-exported from react-stately's collection Section — `title` is Figma's Menu Section Title.",
|
|
7051
7576
|
"useWhen": [
|
|
7052
|
-
"
|
|
7053
|
-
"the rows
|
|
7577
|
+
"a Menu has more than one kind of action, such as editing actions and destructive ones",
|
|
7578
|
+
"the rows fall into groups the user scans by name"
|
|
7054
7579
|
],
|
|
7055
7580
|
"useInstead": [
|
|
7056
7581
|
{
|
|
7057
|
-
"when": "
|
|
7058
|
-
"use": "
|
|
7059
|
-
"why": "
|
|
7060
|
-
},
|
|
7061
|
-
{
|
|
7062
|
-
"when": "one value is picked from a modest list of plain text options",
|
|
7063
|
-
"use": "Select",
|
|
7064
|
-
"why": "the native picker brings keyboard handling, type-ahead and the mobile platform picker for free"
|
|
7065
|
-
},
|
|
7066
|
-
{
|
|
7067
|
-
"when": "it is primary navigation rather than a dropdown",
|
|
7068
|
-
"use": "NavItem"
|
|
7582
|
+
"when": "the menu has one group",
|
|
7583
|
+
"use": "MenuItem",
|
|
7584
|
+
"why": "a single section adds a heading the user must hear before every menu, and says nothing the menu's own label does not"
|
|
7069
7585
|
}
|
|
7070
7586
|
],
|
|
7071
7587
|
"composition": {
|
|
7072
7588
|
"order": [
|
|
7073
7589
|
"Menu",
|
|
7590
|
+
"MenuSection",
|
|
7074
7591
|
"MenuItem"
|
|
7075
7592
|
],
|
|
7076
|
-
"
|
|
7077
|
-
|
|
7078
|
-
"slots": {
|
|
7079
|
-
"children": {
|
|
7080
|
-
"accepts": "MenuItem"
|
|
7081
|
-
}
|
|
7593
|
+
"note": "A collection element: Menu reads it from its direct children. With `title`, the heading is drawn with a rule after it; without one, `aria-label` names the group and a rule is drawn above it instead.",
|
|
7594
|
+
"example": "<MenuSection title=\"Sort by\"><MenuItem key=\"name\">Name</MenuItem><MenuItem key=\"updated\">Last updated</MenuItem></MenuSection>"
|
|
7082
7595
|
},
|
|
7083
7596
|
"a11y": {
|
|
7084
|
-
"role": "
|
|
7597
|
+
"role": "group",
|
|
7085
7598
|
"guarantees": [
|
|
7086
|
-
"
|
|
7599
|
+
"the group is named by its title, so a screen reader announces it on entering the first row"
|
|
7600
|
+
],
|
|
7601
|
+
"requires": [
|
|
7602
|
+
"a `title`; an untitled section still needs a label for the group, or it is announced as an unnamed group"
|
|
7087
7603
|
],
|
|
7088
7604
|
"notes": [
|
|
7089
|
-
"
|
|
7090
|
-
"The role arrives when the popover that owns it does."
|
|
7605
|
+
"The accessible-name lint rule is deliberately not driven from here: a titled section is named by its title and needs nothing more, so demanding a label on every MenuSection would be wrong for the common case."
|
|
7091
7606
|
]
|
|
7092
7607
|
},
|
|
7093
7608
|
"antiPatterns": [
|
|
7094
7609
|
{
|
|
7095
|
-
"dont": "
|
|
7096
|
-
"why": "
|
|
7097
|
-
},
|
|
7098
|
-
{
|
|
7099
|
-
"dont": "using Menu as a dropdown without positioning it",
|
|
7100
|
-
"why": "it renders in flow — it has no anchor logic of its own"
|
|
7610
|
+
"dont": "nesting a MenuSection inside another",
|
|
7611
|
+
"why": "a menu has one level of grouping; a section inside a section renders nothing"
|
|
7101
7612
|
}
|
|
7102
7613
|
],
|
|
7103
7614
|
"stylesheet": "src/styles/menu.css",
|
|
7104
7615
|
"tokens": [
|
|
7105
7616
|
"--border-focus",
|
|
7617
|
+
"--border-strong",
|
|
7106
7618
|
"--border-subtle",
|
|
7107
7619
|
"--border-width-default",
|
|
7108
7620
|
"--border-width-thick",
|
|
@@ -7114,10 +7626,13 @@
|
|
|
7114
7626
|
"--icon-size-sm",
|
|
7115
7627
|
"--ion-duration-base",
|
|
7116
7628
|
"--ion-ease-out",
|
|
7629
|
+
"--ion-menu-min-width",
|
|
7630
|
+
"--ion-shadow-shadow-lg",
|
|
7117
7631
|
"--radius-sm",
|
|
7118
7632
|
"--radius-xl",
|
|
7119
7633
|
"--spacing-12",
|
|
7120
7634
|
"--spacing-2",
|
|
7635
|
+
"--spacing-4",
|
|
7121
7636
|
"--spacing-40",
|
|
7122
7637
|
"--spacing-6",
|
|
7123
7638
|
"--spacing-8",
|
|
@@ -7127,82 +7642,116 @@
|
|
|
7127
7642
|
"--text-disabled",
|
|
7128
7643
|
"--text-primary",
|
|
7129
7644
|
"--text-secondary",
|
|
7645
|
+
"--text-tertiary",
|
|
7130
7646
|
"--type-body",
|
|
7131
|
-
"--type-body-line-height"
|
|
7647
|
+
"--type-body-line-height",
|
|
7648
|
+
"--type-caption",
|
|
7649
|
+
"--type-caption-line-height"
|
|
7132
7650
|
],
|
|
7133
|
-
"props": {
|
|
7134
|
-
"children": {
|
|
7135
|
-
"type": "React.ReactNode",
|
|
7136
|
-
"required": false,
|
|
7137
|
-
"origin": "own"
|
|
7138
|
-
}
|
|
7139
|
-
},
|
|
7651
|
+
"props": {},
|
|
7140
7652
|
"propCounts": {
|
|
7141
|
-
"own":
|
|
7653
|
+
"own": 0,
|
|
7142
7654
|
"aria": 0,
|
|
7143
|
-
"dom":
|
|
7655
|
+
"dom": 0,
|
|
7144
7656
|
"other": 0
|
|
7145
7657
|
}
|
|
7146
7658
|
},
|
|
7147
|
-
"
|
|
7148
|
-
"name": "
|
|
7659
|
+
"MenuTrigger": {
|
|
7660
|
+
"name": "MenuTrigger",
|
|
7149
7661
|
"source": "src/components/Menu.tsx",
|
|
7150
|
-
"propsType": "
|
|
7151
|
-
"
|
|
7662
|
+
"propsType": "MenuTriggerProps",
|
|
7663
|
+
"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.",
|
|
7664
|
+
"import": "import { MenuTrigger } from 'ionbase-ui';",
|
|
7152
7665
|
"status": "stable",
|
|
7153
|
-
"summary": "
|
|
7666
|
+
"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.",
|
|
7154
7667
|
"useWhen": [
|
|
7155
|
-
"a row
|
|
7668
|
+
"a button opens a list of actions — row actions, an overflow \"⋯\", a \"New\" button with several kinds of new",
|
|
7669
|
+
"a button opens a list of choices applied immediately, such as a sort order",
|
|
7670
|
+
"the actions nest one level or more — submenus open only inside a MenuTrigger"
|
|
7156
7671
|
],
|
|
7157
7672
|
"useInstead": [
|
|
7158
7673
|
{
|
|
7159
|
-
"when": "
|
|
7160
|
-
"use": "
|
|
7674
|
+
"when": "the button opens a form, a filter panel or anything that is not a list of rows",
|
|
7675
|
+
"use": "Popover",
|
|
7676
|
+
"why": "a menu promises arrow keys between rows and nothing else; a field inside it cannot be reached"
|
|
7161
7677
|
},
|
|
7162
7678
|
{
|
|
7163
|
-
"when": "
|
|
7164
|
-
"use": "
|
|
7679
|
+
"when": "the choice is a form field's value",
|
|
7680
|
+
"use": "Select",
|
|
7681
|
+
"why": "a form value is a listbox the form can read, not a menu of actions"
|
|
7682
|
+
},
|
|
7683
|
+
{
|
|
7684
|
+
"when": "there are only two or three actions and room to show them",
|
|
7685
|
+
"use": "Button",
|
|
7686
|
+
"why": "hiding actions behind a menu costs a click and makes them undiscoverable; show them when they fit"
|
|
7165
7687
|
}
|
|
7166
7688
|
],
|
|
7689
|
+
"composition": {
|
|
7690
|
+
"order": [
|
|
7691
|
+
"MenuTrigger",
|
|
7692
|
+
"Button",
|
|
7693
|
+
"Menu"
|
|
7694
|
+
],
|
|
7695
|
+
"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.",
|
|
7696
|
+
"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>"
|
|
7697
|
+
},
|
|
7698
|
+
"variants": {
|
|
7699
|
+
"placement": {
|
|
7700
|
+
"bottom start": {
|
|
7701
|
+
"use": "the default — below, aligned to the trigger's start edge"
|
|
7702
|
+
},
|
|
7703
|
+
"bottom end": {
|
|
7704
|
+
"use": "a trigger at the end of a row or toolbar, so the menu does not run off the edge"
|
|
7705
|
+
},
|
|
7706
|
+
"top start": {
|
|
7707
|
+
"use": "a trigger near the bottom of the viewport, such as a footer"
|
|
7708
|
+
},
|
|
7709
|
+
"top end": {
|
|
7710
|
+
"use": "as top start, for a trigger at the end of its row"
|
|
7711
|
+
}
|
|
7712
|
+
}
|
|
7713
|
+
},
|
|
7167
7714
|
"slots": {
|
|
7168
|
-
"icon": {
|
|
7169
|
-
"accepts": "Icon",
|
|
7170
|
-
"note": "leading icon; omit its `label` — the row's text names it"
|
|
7171
|
-
},
|
|
7172
7715
|
"children": {
|
|
7173
|
-
"accepts":
|
|
7174
|
-
|
|
7716
|
+
"accepts": [
|
|
7717
|
+
"Button",
|
|
7718
|
+
"Menu"
|
|
7719
|
+
],
|
|
7720
|
+
"note": "the Button first, the Menu second"
|
|
7175
7721
|
}
|
|
7176
7722
|
},
|
|
7177
7723
|
"a11y": {
|
|
7178
|
-
"role": "
|
|
7724
|
+
"role": "none — the Button gets aria-haspopup=\"menu\" and aria-expanded; the Menu is the menu",
|
|
7725
|
+
"namesChild": true,
|
|
7179
7726
|
"guarantees": [
|
|
7180
|
-
"
|
|
7181
|
-
"
|
|
7727
|
+
"Enter, Space and ArrowDown open the menu with focus on its first row; ArrowUp opens it on the last",
|
|
7728
|
+
"choosing an action closes every open level and returns focus to the trigger; so do Escape and an outside click",
|
|
7729
|
+
"the menu is named by the trigger unless it has its own aria-label",
|
|
7730
|
+
"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",
|
|
7731
|
+
"submenus are non-modal: the parent menu stays on screen and hoverable, so the pointer can move between levels"
|
|
7182
7732
|
],
|
|
7183
7733
|
"requires": [
|
|
7184
|
-
"
|
|
7734
|
+
"an icon-only trigger Button needs its own aria-label — it names the menu too"
|
|
7185
7735
|
]
|
|
7186
7736
|
},
|
|
7187
7737
|
"antiPatterns": [
|
|
7188
7738
|
{
|
|
7189
|
-
"dont": "
|
|
7190
|
-
"why": "it
|
|
7739
|
+
"dont": "wrapping a Menu in a Popover to make a dropdown",
|
|
7740
|
+
"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"
|
|
7191
7741
|
},
|
|
7192
7742
|
{
|
|
7193
|
-
"dont": "
|
|
7194
|
-
"why": "the
|
|
7195
|
-
}
|
|
7196
|
-
],
|
|
7197
|
-
"deprecated": [
|
|
7743
|
+
"dont": "a plain <button> as the trigger",
|
|
7744
|
+
"why": "the trigger must accept react-aria press props and a ref; IonBase's Button does, a DOM button silently never opens"
|
|
7745
|
+
},
|
|
7198
7746
|
{
|
|
7199
|
-
"
|
|
7200
|
-
"
|
|
7747
|
+
"dont": "more than two levels of submenu",
|
|
7748
|
+
"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"
|
|
7201
7749
|
}
|
|
7202
7750
|
],
|
|
7203
7751
|
"stylesheet": "src/styles/menu.css",
|
|
7204
7752
|
"tokens": [
|
|
7205
7753
|
"--border-focus",
|
|
7754
|
+
"--border-strong",
|
|
7206
7755
|
"--border-subtle",
|
|
7207
7756
|
"--border-width-default",
|
|
7208
7757
|
"--border-width-thick",
|
|
@@ -7214,10 +7763,13 @@
|
|
|
7214
7763
|
"--icon-size-sm",
|
|
7215
7764
|
"--ion-duration-base",
|
|
7216
7765
|
"--ion-ease-out",
|
|
7766
|
+
"--ion-menu-min-width",
|
|
7767
|
+
"--ion-shadow-shadow-lg",
|
|
7217
7768
|
"--radius-sm",
|
|
7218
7769
|
"--radius-xl",
|
|
7219
7770
|
"--spacing-12",
|
|
7220
7771
|
"--spacing-2",
|
|
7772
|
+
"--spacing-4",
|
|
7221
7773
|
"--spacing-40",
|
|
7222
7774
|
"--spacing-6",
|
|
7223
7775
|
"--spacing-8",
|
|
@@ -7227,46 +7779,57 @@
|
|
|
7227
7779
|
"--text-disabled",
|
|
7228
7780
|
"--text-primary",
|
|
7229
7781
|
"--text-secondary",
|
|
7782
|
+
"--text-tertiary",
|
|
7230
7783
|
"--type-body",
|
|
7231
|
-
"--type-body-line-height"
|
|
7784
|
+
"--type-body-line-height",
|
|
7785
|
+
"--type-caption",
|
|
7786
|
+
"--type-caption-line-height"
|
|
7232
7787
|
],
|
|
7233
7788
|
"props": {
|
|
7234
|
-
"
|
|
7235
|
-
"type": "
|
|
7236
|
-
"required":
|
|
7789
|
+
"children": {
|
|
7790
|
+
"type": "[React.ReactElement<unknown, string | React.JSXElementConstructor<any>>, React.ReactElement<unknown, string | React.JSXElementConstructor<any>>]",
|
|
7791
|
+
"required": true,
|
|
7237
7792
|
"origin": "own",
|
|
7238
|
-
"description": "
|
|
7793
|
+
"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."
|
|
7239
7794
|
},
|
|
7240
|
-
"
|
|
7241
|
-
"type": "
|
|
7795
|
+
"placement": {
|
|
7796
|
+
"type": "MenuTriggerPlacement | undefined",
|
|
7242
7797
|
"required": false,
|
|
7243
7798
|
"origin": "own",
|
|
7244
|
-
"description": "
|
|
7799
|
+
"description": "Where the menu opens, relative to the trigger. A preference, not a\nguarantee: it flips when there is no room.",
|
|
7800
|
+
"values": [
|
|
7801
|
+
"bottom start",
|
|
7802
|
+
"bottom end",
|
|
7803
|
+
"top start",
|
|
7804
|
+
"top end"
|
|
7805
|
+
]
|
|
7245
7806
|
},
|
|
7246
7807
|
"isDisabled": {
|
|
7247
7808
|
"type": "boolean | undefined",
|
|
7248
7809
|
"required": false,
|
|
7249
7810
|
"origin": "own",
|
|
7250
|
-
"description": "Whether the
|
|
7811
|
+
"description": "Whether the trigger is disabled."
|
|
7251
7812
|
},
|
|
7252
|
-
"
|
|
7813
|
+
"isOpen": {
|
|
7253
7814
|
"type": "boolean | undefined",
|
|
7254
7815
|
"required": false,
|
|
7255
|
-
"origin": "own"
|
|
7256
|
-
"tags": {
|
|
7257
|
-
"deprecated": "Use `isDisabled`. Accepted as an alias for one minor version."
|
|
7258
|
-
}
|
|
7816
|
+
"origin": "own"
|
|
7259
7817
|
},
|
|
7260
|
-
"
|
|
7261
|
-
"type": "
|
|
7818
|
+
"defaultOpen": {
|
|
7819
|
+
"type": "boolean | undefined",
|
|
7820
|
+
"required": false,
|
|
7821
|
+
"origin": "own"
|
|
7822
|
+
},
|
|
7823
|
+
"onOpenChange": {
|
|
7824
|
+
"type": "((isOpen: boolean) => void) | undefined",
|
|
7262
7825
|
"required": false,
|
|
7263
7826
|
"origin": "own"
|
|
7264
7827
|
}
|
|
7265
7828
|
},
|
|
7266
7829
|
"propCounts": {
|
|
7267
|
-
"own":
|
|
7830
|
+
"own": 6,
|
|
7268
7831
|
"aria": 0,
|
|
7269
|
-
"dom":
|
|
7832
|
+
"dom": 0,
|
|
7270
7833
|
"other": 0
|
|
7271
7834
|
}
|
|
7272
7835
|
},
|
|
@@ -8061,6 +8624,175 @@
|
|
|
8061
8624
|
"other": 2
|
|
8062
8625
|
}
|
|
8063
8626
|
},
|
|
8627
|
+
"PageHeader": {
|
|
8628
|
+
"name": "PageHeader",
|
|
8629
|
+
"source": "src/components/PageHeader.tsx",
|
|
8630
|
+
"propsType": "PageHeaderProps",
|
|
8631
|
+
"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.",
|
|
8632
|
+
"import": "import { PageHeader } from 'ionbase-ui';",
|
|
8633
|
+
"status": "stable",
|
|
8634
|
+
"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.",
|
|
8635
|
+
"useWhen": [
|
|
8636
|
+
"the top of every page inside the app shell — list pages, record pages, settings, wizards",
|
|
8637
|
+
"the page has a title and actions that act on the whole page, such as New agent or Pause"
|
|
8638
|
+
],
|
|
8639
|
+
"useInstead": [
|
|
8640
|
+
{
|
|
8641
|
+
"when": "it is the bar across the top of the whole app, with the logo and the account menu",
|
|
8642
|
+
"use": "Header",
|
|
8643
|
+
"why": "Header is the banner landmark, rendered once by the shell. PageHeader is inside main and changes with each page"
|
|
8644
|
+
},
|
|
8645
|
+
{
|
|
8646
|
+
"when": "it titles one section of a page rather than the page",
|
|
8647
|
+
"use": "Card",
|
|
8648
|
+
"why": "a Card's title is an h2 for a named region; a page has one PageHeader and one h1"
|
|
8649
|
+
},
|
|
8650
|
+
{
|
|
8651
|
+
"when": "the page is empty or failed to load",
|
|
8652
|
+
"use": "EmptyState",
|
|
8653
|
+
"why": "keep the PageHeader so the user still knows where they are, and put the EmptyState beneath it with headingLevel 2"
|
|
8654
|
+
}
|
|
8655
|
+
],
|
|
8656
|
+
"composition": {
|
|
8657
|
+
"order": [
|
|
8658
|
+
"PageHeader",
|
|
8659
|
+
"Breadcrumb",
|
|
8660
|
+
"Badge",
|
|
8661
|
+
"Button",
|
|
8662
|
+
"MenuTrigger",
|
|
8663
|
+
"Tabs"
|
|
8664
|
+
],
|
|
8665
|
+
"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.",
|
|
8666
|
+
"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>"
|
|
8667
|
+
},
|
|
8668
|
+
"slots": {
|
|
8669
|
+
"breadcrumb": {
|
|
8670
|
+
"accepts": "Breadcrumb"
|
|
8671
|
+
},
|
|
8672
|
+
"status": {
|
|
8673
|
+
"accepts": [
|
|
8674
|
+
"Badge",
|
|
8675
|
+
"Tag"
|
|
8676
|
+
],
|
|
8677
|
+
"note": "the record's state. Never an action, and never colour alone — a Badge carries its label"
|
|
8678
|
+
},
|
|
8679
|
+
"actions": {
|
|
8680
|
+
"accepts": [
|
|
8681
|
+
"Button",
|
|
8682
|
+
"MenuTrigger",
|
|
8683
|
+
"Link"
|
|
8684
|
+
],
|
|
8685
|
+
"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"
|
|
8686
|
+
},
|
|
8687
|
+
"children": {
|
|
8688
|
+
"accepts": [
|
|
8689
|
+
"Tabs",
|
|
8690
|
+
"SegmentedControl"
|
|
8691
|
+
],
|
|
8692
|
+
"note": "a row that belongs to the header: the page's own tabs, or the filters its table answers to"
|
|
8693
|
+
}
|
|
8694
|
+
},
|
|
8695
|
+
"a11y": {
|
|
8696
|
+
"role": "none — a <div>. The page's landmark is <main>, named by this title",
|
|
8697
|
+
"guarantees": [
|
|
8698
|
+
"the title is a real heading, h1 by default, with a stable id for aria-labelledby",
|
|
8699
|
+
"actions keep their DOM order when they wrap beneath the title on a narrow screen, so reading order matches visual order"
|
|
8700
|
+
],
|
|
8701
|
+
"notes": [
|
|
8702
|
+
"`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.",
|
|
8703
|
+
"It is deliberately not a <header>: a <header> directly inside <body> is the banner, and the app shell's Header already is that."
|
|
8704
|
+
]
|
|
8705
|
+
},
|
|
8706
|
+
"antiPatterns": [
|
|
8707
|
+
{
|
|
8708
|
+
"dont": "two PageHeaders on one page",
|
|
8709
|
+
"why": "two h1s, and two answers to where am I. Sections below the header are Cards with h2 titles"
|
|
8710
|
+
},
|
|
8711
|
+
{
|
|
8712
|
+
"dont": "dropping the PageHeader while the page loads or fails",
|
|
8713
|
+
"why": "the user loses where they are exactly when something went wrong. Keep the title; put Skeleton or EmptyState beneath it"
|
|
8714
|
+
},
|
|
8715
|
+
{
|
|
8716
|
+
"dont": "putting filters or a search field in `actions`",
|
|
8717
|
+
"why": "actions act on the page; filters narrow what it shows. Filters go in `children`, the row beneath"
|
|
8718
|
+
},
|
|
8719
|
+
{
|
|
8720
|
+
"dont": "several primary Buttons in `actions`",
|
|
8721
|
+
"why": "a page has one next step. The one-primary-action lint rule counts them"
|
|
8722
|
+
}
|
|
8723
|
+
],
|
|
8724
|
+
"stylesheet": "src/styles/page-header.css",
|
|
8725
|
+
"tokens": [
|
|
8726
|
+
"--font-family-sans",
|
|
8727
|
+
"--font-weight-semibold",
|
|
8728
|
+
"--ion-page-header-heading-basis",
|
|
8729
|
+
"--spacing-16",
|
|
8730
|
+
"--spacing-4",
|
|
8731
|
+
"--spacing-8",
|
|
8732
|
+
"--text-default",
|
|
8733
|
+
"--text-secondary",
|
|
8734
|
+
"--type-body",
|
|
8735
|
+
"--type-body-line-height",
|
|
8736
|
+
"--type-h4",
|
|
8737
|
+
"--type-h4-line-height"
|
|
8738
|
+
],
|
|
8739
|
+
"props": {
|
|
8740
|
+
"title": {
|
|
8741
|
+
"type": "React.ReactNode",
|
|
8742
|
+
"required": true,
|
|
8743
|
+
"origin": "own",
|
|
8744
|
+
"description": "The page's title. Rendered as the `h1`."
|
|
8745
|
+
},
|
|
8746
|
+
"titleId": {
|
|
8747
|
+
"type": "string | undefined",
|
|
8748
|
+
"required": false,
|
|
8749
|
+
"origin": "own",
|
|
8750
|
+
"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."
|
|
8751
|
+
},
|
|
8752
|
+
"headingLevel": {
|
|
8753
|
+
"type": "PageHeaderHeadingLevel | undefined",
|
|
8754
|
+
"required": false,
|
|
8755
|
+
"origin": "own",
|
|
8756
|
+
"description": "Heading element for the title. Defaults to `1`."
|
|
8757
|
+
},
|
|
8758
|
+
"description": {
|
|
8759
|
+
"type": "React.ReactNode",
|
|
8760
|
+
"required": false,
|
|
8761
|
+
"origin": "own",
|
|
8762
|
+
"description": "One or two sentences under the title: what this page is for."
|
|
8763
|
+
},
|
|
8764
|
+
"breadcrumb": {
|
|
8765
|
+
"type": "React.ReactNode",
|
|
8766
|
+
"required": false,
|
|
8767
|
+
"origin": "own",
|
|
8768
|
+
"description": "A Breadcrumb, above the title."
|
|
8769
|
+
},
|
|
8770
|
+
"status": {
|
|
8771
|
+
"type": "React.ReactNode",
|
|
8772
|
+
"required": false,
|
|
8773
|
+
"origin": "own",
|
|
8774
|
+
"description": "Beside the title: a Badge or two for the record's state — \"Paused\",\n\"Draft\". State, not actions."
|
|
8775
|
+
},
|
|
8776
|
+
"actions": {
|
|
8777
|
+
"type": "React.ReactNode",
|
|
8778
|
+
"required": false,
|
|
8779
|
+
"origin": "own",
|
|
8780
|
+
"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."
|
|
8781
|
+
},
|
|
8782
|
+
"children": {
|
|
8783
|
+
"type": "React.ReactNode",
|
|
8784
|
+
"required": false,
|
|
8785
|
+
"origin": "own",
|
|
8786
|
+
"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."
|
|
8787
|
+
}
|
|
8788
|
+
},
|
|
8789
|
+
"propCounts": {
|
|
8790
|
+
"own": 8,
|
|
8791
|
+
"aria": 0,
|
|
8792
|
+
"dom": 276,
|
|
8793
|
+
"other": 0
|
|
8794
|
+
}
|
|
8795
|
+
},
|
|
8064
8796
|
"Pagination": {
|
|
8065
8797
|
"name": "Pagination",
|
|
8066
8798
|
"source": "src/components/Pagination.tsx",
|
|
@@ -13746,7 +14478,7 @@
|
|
|
13746
14478
|
"type": "React.ReactNode",
|
|
13747
14479
|
"required": false,
|
|
13748
14480
|
"origin": "own",
|
|
13749
|
-
"description": "Replaces the helper text
|
|
14481
|
+
"description": "Replaces the helper text while the field is invalid — `isInvalid`, or its own bounds check."
|
|
13750
14482
|
},
|
|
13751
14483
|
"isInvalid": {
|
|
13752
14484
|
"type": "boolean | undefined",
|