bestax-mcp 1.14.3 → 1.14.5
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/data/catalog.json +26 -2
- package/data/components/Autocomplete.json +5 -5
- package/data/components/DateInput.json +1 -1
- package/data/components/DateRangeInput.json +1 -1
- package/data/components/DateTimeInput.json +1 -1
- package/data/components/Delete.json +4 -4
- package/data/components/Field.json +5 -5
- package/data/components/File.json +1 -1
- package/data/components/HoverCard.json +229 -0
- package/data/components/Input.json +7 -7
- package/data/components/Notification.json +7 -1
- package/data/components/Numberinput.json +1 -1
- package/data/components/Popover.json +1 -0
- package/data/components/Select.json +5 -5
- package/data/components/Slider.json +12 -4
- package/data/components/Taginput.json +1 -1
- package/data/components/TextArea.json +4 -4
- package/data/components/Theme.json +2 -2
- package/data/components/TimeInput.json +1 -1
- package/data/components/Tooltip.json +1 -1
- package/data/skills/bestax-custom-component/SKILL.md +7 -0
- package/data/skills/bestax-custom-component/references/api.md +6 -4
- package/data/skills/bestax-custom-component/references/component-catalog.md +2 -1
- package/data/skills/bestax-form/SKILL.md +42 -26
- package/data/skills/bestax-form/references/api.md +12 -10
- package/data/skills/bestax-form/references/patterns.md +26 -6
- package/data/skills/bestax-icons/SKILL.md +8 -1
- package/data/skills/bestax-icons/references/icon-libraries.md +42 -4
- package/data/skills/bestax-layout-scaffold/SKILL.md +6 -0
- package/data/skills/bestax-optimize/SKILL.md +2 -0
- package/data/skills/bestax-optimize/references/modular-build.md +19 -10
- package/data/skills/bestax-theming/SKILL.md +4 -1
- package/data/skills/bestax-theming/references/css-variables.md +46 -2
- package/data/skills.json +7 -7
- package/package.json +4 -4
package/data/catalog.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"generatedFrom": {
|
|
4
4
|
"package": "@allxsmith/bestax-bulma",
|
|
5
|
-
"version": "5.
|
|
5
|
+
"version": "5.28.0"
|
|
6
6
|
},
|
|
7
7
|
"docsBase": "https://bestax.io/docs",
|
|
8
8
|
"categories": [
|
|
@@ -57,6 +57,7 @@
|
|
|
57
57
|
"Collapses",
|
|
58
58
|
"Dialog",
|
|
59
59
|
"Dropdown",
|
|
60
|
+
"HoverCard",
|
|
60
61
|
"Loading",
|
|
61
62
|
"Menu",
|
|
62
63
|
"Message",
|
|
@@ -545,6 +546,17 @@
|
|
|
545
546
|
"propCount": 21,
|
|
546
547
|
"exampleCount": 6
|
|
547
548
|
},
|
|
549
|
+
{
|
|
550
|
+
"name": "HoverCard",
|
|
551
|
+
"kind": "component",
|
|
552
|
+
"category": "components",
|
|
553
|
+
"purpose": "The `HoverCard` component shows a card previewing what's behind a link or a button while the pointer rests on it or keyboard focus is on it.",
|
|
554
|
+
"slug": "components/hovercard",
|
|
555
|
+
"import": "import { HoverCard } from '@allxsmith/bestax-bulma';",
|
|
556
|
+
"compound": false,
|
|
557
|
+
"propCount": 11,
|
|
558
|
+
"exampleCount": 6
|
|
559
|
+
},
|
|
548
560
|
{
|
|
549
561
|
"name": "Icon",
|
|
550
562
|
"kind": "component",
|
|
@@ -917,7 +929,7 @@
|
|
|
917
929
|
"import": "import { Slider } from '@allxsmith/bestax-bulma';",
|
|
918
930
|
"compound": false,
|
|
919
931
|
"propCount": 30,
|
|
920
|
-
"exampleCount":
|
|
932
|
+
"exampleCount": 13
|
|
921
933
|
},
|
|
922
934
|
{
|
|
923
935
|
"name": "Span",
|
|
@@ -1545,6 +1557,17 @@
|
|
|
1545
1557
|
"--bulma-hero-gradient-h-offset": ["Hero"],
|
|
1546
1558
|
"--bulma-hero-gradient-l-offset": ["Hero"],
|
|
1547
1559
|
"--bulma-hero-gradient-s-offset": ["Hero"],
|
|
1560
|
+
"--bulma-hover-card-animation-duration": ["HoverCard"],
|
|
1561
|
+
"--bulma-hover-card-background": ["HoverCard"],
|
|
1562
|
+
"--bulma-hover-card-border-color": ["HoverCard"],
|
|
1563
|
+
"--bulma-hover-card-color": ["HoverCard"],
|
|
1564
|
+
"--bulma-hover-card-max-width": ["HoverCard"],
|
|
1565
|
+
"--bulma-hover-card-min-width": ["HoverCard"],
|
|
1566
|
+
"--bulma-hover-card-offset": ["HoverCard"],
|
|
1567
|
+
"--bulma-hover-card-padding": ["HoverCard"],
|
|
1568
|
+
"--bulma-hover-card-radius": ["HoverCard"],
|
|
1569
|
+
"--bulma-hover-card-shadow": ["HoverCard"],
|
|
1570
|
+
"--bulma-hover-card-z-index": ["HoverCard"],
|
|
1548
1571
|
"--bulma-icon-dimensions": ["Icon", "IconText"],
|
|
1549
1572
|
"--bulma-icon-dimensions-large": ["Icon", "IconText"],
|
|
1550
1573
|
"--bulma-icon-dimensions-medium": ["Icon", "IconText"],
|
|
@@ -2007,6 +2030,7 @@
|
|
|
2007
2030
|
"--bulma-notification-background-l": ["Notification"],
|
|
2008
2031
|
"--bulma-notification-code-background-color": ["Notification"],
|
|
2009
2032
|
"--bulma-notification-color-l": ["Notification"],
|
|
2033
|
+
"--bulma-notification-delete-padding-inline-end": ["Notification"],
|
|
2010
2034
|
"--bulma-notification-h": ["Notification"],
|
|
2011
2035
|
"--bulma-notification-padding": ["Notification"],
|
|
2012
2036
|
"--bulma-notification-radius": ["Notification"],
|
|
@@ -47,14 +47,14 @@
|
|
|
47
47
|
},
|
|
48
48
|
{
|
|
49
49
|
"title": "Context-Aware Rendering",
|
|
50
|
-
"code": "function example() {\n return (\n <Field
|
|
50
|
+
"code": "function example() {\n return (\n <Field\n horizontal\n label=\"Fruit\"\n labelProps={{ htmlFor: 'fruit-field', id: 'fruit-field-label' }}\n >\n <Field.Body>\n <Field>\n <Autocomplete\n id=\"fruit-field\"\n data={['Apple', 'Banana', 'Cherry']}\n placeholder=\"Search fruit...\"\n />\n </Field>\n </Field.Body>\n </Field>\n );\n}"
|
|
51
51
|
},
|
|
52
52
|
{
|
|
53
53
|
"title": "Context-Aware Rendering",
|
|
54
|
-
"code": "function example() {\n return (\n <Field\n horizontal\n label=\"Fruit\"\n labelProps={{
|
|
54
|
+
"code": "function example() {\n return (\n <Field\n horizontal\n label=\"Fruit\"\n labelProps={{\n htmlFor: 'fruit-field-control',\n id: 'fruit-field-control-label',\n }}\n >\n <Field.Body>\n <Field>\n <Control iconLeftName=\"search\">\n <Autocomplete\n id=\"fruit-field-control\"\n data={['Apple', 'Banana', 'Cherry']}\n placeholder=\"Search fruit...\"\n />\n </Control>\n </Field>\n </Field.Body>\n </Field>\n );\n}"
|
|
55
55
|
}
|
|
56
56
|
],
|
|
57
|
-
"accessibility": "- The `label` prop is automatically associated with the inner text input (`htmlFor` plus a generated `id`, or your own `id` if you pass one), so clicking the label focuses the input and assistive technology announces it. Inside a labeled `Field`, that `Field`'s label names the input the
|
|
57
|
+
"accessibility": "- The `label` prop is automatically associated with the inner text input (`htmlFor` plus a generated `id`, or your own `id` if you pass one), so clicking the label focuses the input and assistive technology announces it. Inside a labeled `Field`, that `Field`'s label names the input instead when it points at it: a `Field` that is not `grouped` or `hasAddons` points it there on its own when the Autocomplete has no `id` and no inner `Field` sits between them, and a label you wire by hand with `labelProps.htmlFor` points at the input with that `id`.\n- A user-supplied `id` is applied to the inner input (the labellable control), not the wrapper div.\n- Uses `role=\"combobox\"` with `aria-expanded`, which is true only while the list is on screen\n- Has `aria-haspopup=\"listbox\"` and `aria-autocomplete=\"list\"`, and, while the list is on screen, `aria-controls` pointing at it\n- Focus stays in the input, which points `aria-activedescendant` at the highlighted option as the arrow keys move it\n- The list is a `role=\"listbox\"` named through `aria-labelledby` by the label that names the input, when that label has an id: the `label` prop's label always has one, and so does a `Field`'s label that the `Field` wires itself. A `Field` label you wire by hand with `labelProps.htmlFor`, which is how a horizontal form names an Autocomplete in an inner `Field`, needs an `id` in its `labelProps` as well. Otherwise the list falls back to `aria-label=\"Suggestions\"`\n- Dropdown items use `role=\"option\"` with `aria-selected`\n- Disabled items have `aria-disabled`\n- The `clearable` clear button is a native button named \"Clear\": `Tab` from the input reaches it, and `Enter` or `Space` clears the input and puts focus back in it\n- Full keyboard navigation support",
|
|
58
58
|
"related": ["Input", "Select", "Taginput"],
|
|
59
59
|
"storybook": "https://bestax.io/storybook/?path=/story/form-autocomplete",
|
|
60
60
|
"summary": "The `Autocomplete` component provides an input field with dropdown suggestions that filter based on user input.",
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"name": "label",
|
|
72
72
|
"type": "React.ReactNode",
|
|
73
73
|
"default": null,
|
|
74
|
-
"description": "Field label
|
|
74
|
+
"description": "Field label, associated with the text input via `htmlFor`: through your `id` when provided, otherwise a generated one. Dropped inside an outer `Field`, whose label names the input instead when it points at it. The `Field` points its label there itself when the Autocomplete has no `id` and no inner `Field` sits between them (and the `Field` is not `grouped` or `hasAddons`); a label you wire by hand with `labelProps.htmlFor` points at the input with that `id`. The label naming the input also names the open suggestion list, through `aria-labelledby`, when it has an id: this label always does, and an outer `Field`'s does unless you wired it by hand without an `id` in its `labelProps`. Otherwise the list is named \"Suggestions\".",
|
|
75
75
|
"required": false,
|
|
76
76
|
"inherited": false,
|
|
77
77
|
"deprecated": false
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"name": "labelProps",
|
|
81
81
|
"type": "React.LabelHTMLAttributes<HTMLLabelElement> & { [key: string]: unknown; }",
|
|
82
82
|
"default": null,
|
|
83
|
-
"description": "Props for the label element. An explicit `htmlFor` here overrides the automatic association (no id
|
|
83
|
+
"description": "Props for the label element. An explicit `htmlFor` here overrides the automatic association (the input then gets no generated id). While the label names the input, the suggestion list's `aria-labelledby` points at it, through an `id` here when you give one and a generated one otherwise.",
|
|
84
84
|
"required": false,
|
|
85
85
|
"inherited": false,
|
|
86
86
|
"deprecated": false
|
|
@@ -191,7 +191,7 @@
|
|
|
191
191
|
"name": "label",
|
|
192
192
|
"type": "React.ReactNode",
|
|
193
193
|
"default": null,
|
|
194
|
-
"description": "Field label (component auto-wraps in a `Field` if not already inside). Automatically associated with the input via `htmlFor` — uses your `id` when provided, otherwise a generated one. Not wired in `inline` mode (no visible input to label). Dropped inside an outer `Field`, whose own label associates instead when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`).",
|
|
194
|
+
"description": "Field label (component auto-wraps in a `Field` if not already inside). Automatically associated with the input via `htmlFor` — uses your `id` when provided, otherwise a generated one. Not wired in `inline` mode (no visible input to label). Dropped inside an outer `Field`, whose own label associates instead when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`) and you set no `id` here.",
|
|
195
195
|
"required": false,
|
|
196
196
|
"inherited": false,
|
|
197
197
|
"deprecated": false
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"code": "<Field label=\"Leave\">\n <Control iconLeftName=\"calendar-alt\">\n <DateRangeInput />\n </Control>\n</Field>"
|
|
47
47
|
}
|
|
48
48
|
],
|
|
49
|
-
"accessibility": "- The root is a `role=\"group\"` named by `label` through `aria-labelledby`, since the label names two inputs rather than one. Inside a labeled `Field`, that `Field`'s label names the group the same way. An `aria-label` or `aria-labelledby` you give the group wins over either label.\n- Each input is a `role=\"combobox\"` with `aria-haspopup=\"dialog\"`, `aria-expanded` and `aria-controls`, and its own name: \"Start date\" or \"End date\", from the `labels` keys `rangeStart` and `rangeEnd`. The separator between them is hidden from assistive technology.\n- The popover is a `role=\"dialog\"` named \"Choose date range\" (`labels.chooseDateRange`). Opening it puts focus on the calendar's focused day, and closing it returns focus to the input you were last in, or to the start input.\n- The day grid is `aria-multiselectable`, and its days sit in a `role=\"row\"` per week. Every day of the range is `aria-selected`, both ends included. While the end is still being picked, only the start is: the preview is not a selection.\n- The start and end days are described as \"Start date\" and \"End date\", so moving onto either says which it is. While the end is still being picked, the day the range would end on is described as \"Choose as end date\" (`labels.rangePreviewEnd`).\n- A polite live region in the calendar states the range in words, such as \"Start date: June 10, 2024, End date: June 13, 2024\", and announces each pick. The grid points at it too, so moving into the grid reads the current range.\n- Everything else is the calendar `DateInput` uses: a roving `tabindex`, `aria-disabled` on disabled days and `aria-current=\"date\"` on today.",
|
|
49
|
+
"accessibility": "- The root is a `role=\"group\"` named by `label` through `aria-labelledby`, since the label names two inputs rather than one. Inside a labeled `Field`, that `Field`'s label names the group the same way, whether the `Field` holds `DateRangeInput` or a `DateRangeInputBase` you composed in a `Control` yourself, `inline` or not. An `aria-label` or `aria-labelledby` you give the group wins over either label.\n- Each input is a `role=\"combobox\"` with `aria-haspopup=\"dialog\"`, `aria-expanded` and `aria-controls`, and its own name: \"Start date\" or \"End date\", from the `labels` keys `rangeStart` and `rangeEnd`. The separator between them is hidden from assistive technology.\n- The popover is a `role=\"dialog\"` named \"Choose date range\" (`labels.chooseDateRange`). Opening it puts focus on the calendar's focused day, and closing it returns focus to the input you were last in, or to the start input.\n- The day grid is `aria-multiselectable`, and its days sit in a `role=\"row\"` per week. Every day of the range is `aria-selected`, both ends included. While the end is still being picked, only the start is: the preview is not a selection.\n- The start and end days are described as \"Start date\" and \"End date\", so moving onto either says which it is. While the end is still being picked, the day the range would end on is described as \"Choose as end date\" (`labels.rangePreviewEnd`).\n- A polite live region in the calendar states the range in words, such as \"Start date: June 10, 2024, End date: June 13, 2024\", and announces each pick. The grid points at it too, so moving into the grid reads the current range.\n- Everything else is the calendar `DateInput` uses: a roving `tabindex`, `aria-disabled` on disabled days and `aria-current=\"date\"` on today.",
|
|
50
50
|
"related": ["DateInput", "DateTimeInput", "Field"],
|
|
51
51
|
"storybook": "https://bestax.io/storybook/?path=/story/form-daterangeinput",
|
|
52
52
|
"summary": "The `DateRangeInput` component is a form input for a start and end date, picked from one popover calendar or typed into two segmented inputs.",
|
|
@@ -187,7 +187,7 @@
|
|
|
187
187
|
"name": "label",
|
|
188
188
|
"type": "React.ReactNode",
|
|
189
189
|
"default": null,
|
|
190
|
-
"description": "Field label. Automatically associated with the input via `htmlFor` — uses your `id` when provided, otherwise a generated one. Not wired in `inline` mode (no visible input to label). Dropped inside an outer `Field`, whose own label associates instead when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`).",
|
|
190
|
+
"description": "Field label. Automatically associated with the input via `htmlFor` — uses your `id` when provided, otherwise a generated one. Not wired in `inline` mode (no visible input to label). Dropped inside an outer `Field`, whose own label associates instead when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`) and you set no `id` here.",
|
|
191
191
|
"required": false,
|
|
192
192
|
"inherited": false,
|
|
193
193
|
"deprecated": false
|
|
@@ -129,25 +129,25 @@
|
|
|
129
129
|
"css": "--bulma-delete-dimensions",
|
|
130
130
|
"sass": null,
|
|
131
131
|
"default": "1.25rem",
|
|
132
|
-
"scope": "
|
|
132
|
+
"scope": "compound"
|
|
133
133
|
},
|
|
134
134
|
{
|
|
135
135
|
"css": "--bulma-delete-background-l",
|
|
136
136
|
"sass": null,
|
|
137
137
|
"default": "0%",
|
|
138
|
-
"scope": "
|
|
138
|
+
"scope": "root"
|
|
139
139
|
},
|
|
140
140
|
{
|
|
141
141
|
"css": "--bulma-delete-background-alpha",
|
|
142
142
|
"sass": null,
|
|
143
143
|
"default": "0.5",
|
|
144
|
-
"scope": "
|
|
144
|
+
"scope": "root"
|
|
145
145
|
},
|
|
146
146
|
{
|
|
147
147
|
"css": "--bulma-delete-color",
|
|
148
148
|
"sass": null,
|
|
149
149
|
"default": "var(--bulma-white)",
|
|
150
|
-
"scope": "
|
|
150
|
+
"scope": "root"
|
|
151
151
|
}
|
|
152
152
|
]
|
|
153
153
|
}
|
|
@@ -83,10 +83,10 @@
|
|
|
83
83
|
},
|
|
84
84
|
{
|
|
85
85
|
"title": "Compound (dot-notation) usage",
|
|
86
|
-
"code": "<Field horizontal>\n <Field.Label
|
|
86
|
+
"code": "<Field horizontal>\n <Field.Label size=\"normal\">\n <label className=\"label\" htmlFor=\"compound-name\">\n Name\n </label>\n </Field.Label>\n <Field.Body>\n <Field.Control>\n <Input id=\"compound-name\" placeholder=\"Jane Doe\" />\n </Field.Control>\n </Field.Body>\n</Field>"
|
|
87
87
|
}
|
|
88
88
|
],
|
|
89
|
-
"accessibility": "- The `label` prop names the one control the Field holds. A composed `InputBase`, `SelectBase`, or `
|
|
89
|
+
"accessibility": "- For a single control, prefer the control's own `label` prop, with `horizontal` for a side-by-side row. It renders this `Field` and its label and wires the `for` itself, to your `id` when you pass one: `<Input label=\"Email\" id=\"email\" horizontal />`.\n- The `label` prop names the one control the Field holds. A composed `InputBase`, `SelectBase`, `TextAreaBase`, `DateInputBase`, `TimeInputBase`, or `DateTimeInputBase`, or a bestax input that renders a single input of its own (`Input`, `Select`, `TextArea`, `Numberinput`, `Slider`, `DateInput`, `TimeInput`, `DateTimeInput`, `Autocomplete`, `Taginput`, `File`), adopts a generated id the label's `for` points at, so clicking the label focuses the control and assistive technology announces it. An `inline` picker renders no input, so it takes nothing.\n- A control with an `id` of its own keeps it and never takes the generated one, so `<Field label=\"Email\"><Input id=\"email\" /></Field>` renders a label that names nothing. Leave the `id` off, or pass the same value as `labelProps={{ htmlFor: 'email' }}`. Pass `labelProps={{ htmlFor: undefined }}` to opt out of the association entirely.\n- A range `Slider` takes that id on its low thumb, and its thumbs also point `aria-labelledby` at the label (at `labelProps.id` when you set one), so under a label of \"Price range\" they announce as \"Price range Minimum value\" and \"Price range Maximum value\". An `ariaLabel` entry names its thumb instead, and an `aria-label` or `aria-labelledby` on the Slider takes the label's place in both names. A label you wire by hand with `labelProps={{ htmlFor }}` gets no generated id, so it reaches the thumbs' names only when you give it an `id` there too, as in `labelProps={{ htmlFor: 'price', id: 'price-label' }}`.\n- An `Autocomplete` points its open suggestion list's `aria-labelledby` at the label the same way, so under a label of \"Country\" the list announces as \"Country\" rather than its fallback name, \"Suggestions\". A label you wire by hand needs an `id` in `labelProps` for this too, as in `labelProps={{ htmlFor: 'country', id: 'country-label' }}`.\n- A group (`Radios`, `Checkboxes`, `Rate`, `DateRangeInput`, or a composed `DateRangeInputBase`, `inline` or not) can't take a `for`, so the label gets an id (yours from `labelProps.id`, otherwise a generated one) and the group points `aria-labelledby` at it. An `aria-label` or `aria-labelledby` you set on the group wins over the Field's label, as it does over a group's own `label`.\n- Association is skipped for `grouped`/`hasAddons` fields (they hold several controls), and a `Field` nested inside a labeled one starts its own scope. A horizontal Field wraps its children in a `Field.Body` of its own and keeps the association, but the pattern with an inner `Field` in that body needs it wired by hand. A label you wire by hand names the control its `for` points at in a `grouped` or `hasAddons` field too, and with an `id` in `labelProps` it names a range `Slider`'s thumbs and an `Autocomplete`'s list there as well. No group points at it on its own.\n- Two controls in one plain labeled Field would both adopt its id. Give each an `id` of its own and label it individually.\n- Once a labeled Field's content has mounted, its label keeps the generated `for` only while one of the inputs above holds the id, and drops it over anything else: a group, a `Checkbox`, `Radio` or `Switch`, an `inline` picker, an inner `Field`, an input with an `id` of its own, markup of your own, or nothing at all. A server render, and the first render while hydrating, still write the `for`, so hydration matches, and an input that mounts later puts it back. A `for` you set with `labelProps={{ htmlFor }}` always stays. `Checkbox`, `Radio` and `Switch` take nothing from the label on their own: each is named by its own children, so put the text there, and the label names one only when you wire it as you would any control with an `id` of its own, `labelProps={{ htmlFor }}` plus that control's `id`. Where you point content at the label by hand, as with a group in an inner `Field`, `labelProps={{ id }}` is enough in the browser, and `labelProps={{ id, htmlFor: undefined }}` keeps the `for` out of server-rendered HTML too.\n- Grouped/horizontal layouts use Bulma’s grid for layout.",
|
|
90
90
|
"related": [
|
|
91
91
|
"Checkbox",
|
|
92
92
|
"Checkboxes",
|
|
@@ -149,7 +149,7 @@
|
|
|
149
149
|
"name": "label",
|
|
150
150
|
"type": "React.ReactNode",
|
|
151
151
|
"default": null,
|
|
152
|
-
"description": "Field label, rendered above the widget. Automatically names the one control the Field holds: a composed `InputBase`, `SelectBase` or `
|
|
152
|
+
"description": "Field label, rendered above the widget. Automatically names the one control the Field holds: a composed `InputBase`, `SelectBase`, `TextAreaBase`, `DateInputBase`, `TimeInputBase` or `DateTimeInputBase` (an `inline` picker has no input, so it takes nothing), or a bestax input that renders a single input of its own (`Input`, `Select`, `TextArea`, `Numberinput`, `Slider`, `DateInput`, `TimeInput`, `DateTimeInput`, `Autocomplete`, `Taginput`, `File`), adopts a generated id that the label's `htmlFor` points at, and a group (`Radios`, `Checkboxes`, `Rate`, `DateRangeInput`, or a composed `DateRangeInputBase`, `inline` or not) points `aria-labelledby` at the label's own id unless you gave the group an `aria-label` or `aria-labelledby`. A range `Slider` takes the id on its low thumb and also starts each thumb's name with the label through `aria-labelledby`, unless its `ariaLabel` names that thumb or its own `aria-label` or `aria-labelledby` takes the label's place. An `Autocomplete` also names its open suggestion list after the label through `aria-labelledby`. Nothing else takes the label: `Checkbox`, `Radio` and `Switch` are named by their own children, and the label names one only when you wire it as you would any control with an `id` of its own, `labelProps={{ htmlFor }}` plus that control's `id`. Only the single inputs take the `htmlFor`, so once the Field's content has mounted the label keeps it only while one of them holds the id, and drops it over anything else: a group, a `Checkbox`, `Radio` or `Switch`, an `inline` picker, an inner `Field`, an input with an `id` of its own, markup of your own, or nothing at all. A server render, and the first render while hydrating, still write the `htmlFor`, which keeps hydration matching, and an input that mounts later puts it back. The label names an input with an `id` of your own only through `labelProps={{ htmlFor }}` set to that `id`, a `for` it always keeps; `labelProps={{ htmlFor: undefined }}` opts out. Skipped for `grouped`/`hasAddons` fields (multiple controls), and a nested `Field` starts its own scope, so a horizontal Field whose body holds an inner `Field` names the control there only when you wire it. Two controls in one plain labeled Field would both adopt the id, so give each an `id` of its own.",
|
|
153
153
|
"required": false,
|
|
154
154
|
"inherited": false,
|
|
155
155
|
"deprecated": false
|
|
@@ -167,7 +167,7 @@
|
|
|
167
167
|
"name": "labelProps",
|
|
168
168
|
"type": "React.LabelHTMLAttributes<HTMLLabelElement> & { [key: string]: unknown; }",
|
|
169
169
|
"default": null,
|
|
170
|
-
"description": "Props for the label element. An explicit `htmlFor` key — even set to `undefined` — takes over the association.
|
|
170
|
+
"description": "Props for the label element. An explicit `htmlFor` key — even set to `undefined` — takes over the association. While the association is on, the label renders with the `id` given here, or a generated one, and a group control, a range `Slider`'s thumbs and an `Autocomplete`'s suggestion list point `aria-labelledby` at it. A label you take over gets no generated id, and no group points at it on its own. With an `id` here, though, a range `Slider` or an `Autocomplete` whose `id` your `htmlFor` names still points its thumbs or its suggestion list at it, in a `grouped` or `hasAddons` Field too. To point a group in an inner `Field` at this label by hand, pass that `id`. Nothing in the inner `Field` takes the generated `htmlFor`, so the label drops it after mounting, and adding `htmlFor: undefined` keeps it out of server-rendered markup too.",
|
|
171
171
|
"required": false,
|
|
172
172
|
"inherited": false,
|
|
173
173
|
"deprecated": false
|
|
@@ -226,7 +226,7 @@
|
|
|
226
226
|
},
|
|
227
227
|
{
|
|
228
228
|
"path": "Field.Label",
|
|
229
|
-
"summary": "FieldLabel component for rendering a Bulma field label.",
|
|
229
|
+
"summary": "FieldLabel component for rendering a Bulma field label. It renders the label column of a horizontal `Field` (a `div` with the `field-label` class), not a `<label>`, so text placed straight in it names nothing. Put a `<label>` with the `label` class inside it and point its `htmlFor` at the control's `id`, or give the horizontal `Field` a `label` prop, which renders this column and its `<label>` for you. A `<label>` you put here names the control through its `htmlFor` alone: a range `Slider`'s thumbs and an `Autocomplete`'s suggestion list point `aria-labelledby` at a `Field`'s label only when its `label` prop renders it and it names the control. Where it would not name the control on its own, as in an inner `Field`, pass `labelProps={{ htmlFor, id }}` with a matching `id` on the control.",
|
|
230
230
|
"component": null,
|
|
231
231
|
"props": [
|
|
232
232
|
{
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
"name": "label",
|
|
92
92
|
"type": "React.ReactNode",
|
|
93
93
|
"default": null,
|
|
94
|
-
"description": "Field label. Automatically associated with the file input via `htmlFor` — uses your `id` when provided, otherwise a generated one. The input then has two labels (this one plus the wrapping `file-label`); assistive tech reads both. Dropped inside an outer `Field`, whose own label associates instead when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`).",
|
|
94
|
+
"description": "Field label. Automatically associated with the file input via `htmlFor` — uses your `id` when provided, otherwise a generated one. The input then has two labels (this one plus the wrapping `file-label`); assistive tech reads both. Dropped inside an outer `Field`, whose own label associates instead when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`) and you set no `id` here.",
|
|
95
95
|
"required": false,
|
|
96
96
|
"inherited": false,
|
|
97
97
|
"deprecated": false
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "HoverCard",
|
|
3
|
+
"kind": "component",
|
|
4
|
+
"category": "components",
|
|
5
|
+
"slug": "components/hovercard",
|
|
6
|
+
"docsUrl": "https://bestax.io/docs/api/components/hovercard",
|
|
7
|
+
"examples": [
|
|
8
|
+
{
|
|
9
|
+
"title": "Basic HoverCard",
|
|
10
|
+
"code": "<HoverCard trigger={<Link href=\"#ada\">Ada Lovelace</Link>}>\n <Media>\n <Media.Left>\n <Avatar name=\"Ada Lovelace\" size=\"48x48\" />\n </Media.Left>\n <Media.Content>\n <Title as=\"p\" size=\"6\">\n Ada Lovelace\n </Title>\n <SubTitle as=\"p\" size=\"6\">\n Analytical Engine team\n </SubTitle>\n <Link href=\"#profile\">View profile</Link>\n </Media.Content>\n </Media>\n</HoverCard>"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"title": "In Running Text",
|
|
14
|
+
"code": "<Paragraph>\n Reviewed by{' '}\n <HoverCard appendToBody trigger={<Link href=\"#ada\">Ada Lovelace</Link>}>\n <Title as=\"p\" size=\"6\">\n Ada Lovelace\n </Title>\n <SubTitle as=\"p\" size=\"6\">\n Analytical Engine team\n </SubTitle>\n <Link href=\"#profile\">View profile</Link>\n </HoverCard>{' '}\n and merged the same day.\n</Paragraph>"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"title": "Placement",
|
|
18
|
+
"code": "<Buttons>\n <HoverCard\n openOnTap\n position=\"bottom-left\"\n trigger={<Button>bottom-left</Button>}\n >\n <Paragraph>Opens below, on the left edge.</Paragraph>\n </HoverCard>\n <HoverCard\n openOnTap\n position=\"bottom-right\"\n trigger={<Button>bottom-right</Button>}\n >\n <Paragraph>Opens below, on the right edge.</Paragraph>\n </HoverCard>\n <HoverCard\n openOnTap\n position=\"auto\"\n trigger={<Button color=\"info\">auto</Button>}\n >\n <Paragraph>Opens wherever it fits.</Paragraph>\n </HoverCard>\n</Buttons>"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"title": "Delays",
|
|
22
|
+
"code": "<Buttons>\n <HoverCard openOnTap openDelay={0} trigger={<Button>Opens at once</Button>}>\n <Paragraph>No wait before this one.</Paragraph>\n </HoverCard>\n <HoverCard\n openOnTap\n openDelay={1000}\n closeDelay={600}\n trigger={<Button>Takes its time</Button>}\n >\n <Paragraph>A slower card, with longer to reach it.</Paragraph>\n </HoverCard>\n</Buttons>"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"title": "On Touch Screens",
|
|
26
|
+
"code": "<HoverCard openOnTap trigger={<Button>Engine team</Button>}>\n <Title as=\"p\" size=\"6\">\n Analytical Engine team\n </Title>\n <Paragraph mb=\"2\">Ada Lovelace and Charles Babbage</Paragraph>\n <Link href=\"#team\">View the team</Link>\n</HoverCard>"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"title": "Controlled",
|
|
30
|
+
"code": "function example() {\n const [open, setOpen] = useState(false);\n const [following, setFollowing] = useState(false);\n\n return (\n <>\n <Paragraph mb=\"3\">\n The card is {open ? 'open' : 'closed'}\n {following ? ', and you follow Ada' : ''}.\n </Paragraph>\n <HoverCard\n open={open}\n onOpenChange={setOpen}\n trigger={<Link href=\"#ada\">Ada Lovelace</Link>}\n >\n <Paragraph mb=\"3\">Analytical Engine team</Paragraph>\n <Button\n size=\"small\"\n color=\"primary\"\n onClick={() => {\n setFollowing(true);\n setOpen(false);\n }}\n >\n Follow\n </Button>\n </HoverCard>\n </>\n );\n}"
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
"accessibility": "`HoverCard` is built to\n[WCAG's Content on Hover or Focus](https://www.w3.org/WAI/WCAG22/Understanding/content-on-hover-or-focus.html)\ncriterion, condition by condition:\n\n- **Dismissible:** <kbd>Escape</kbd> closes the card wherever focus is, without moving the pointer\n or focus. The keypress belongs to whatever has focus. When that's the card, its trigger or\n nothing, the card takes it, so a `Popover` or `Modal` around it stays open. When it's something\n else, such as a field elsewhere on the page or a `Modal` opened from the card, the card still\n closes and the key goes on to it. With one card inside another, the inner one closes first.\n Focus that was in the card goes back to the trigger, and the card stays closed until the pointer\n or focus leaves and comes back.\n- **Hoverable:** the pointer can move from the trigger onto the card. `closeDelay` covers the gap\n between them, and the card takes pointer events, unlike a tooltip.\n- **Persistent:** no timer closes a card that's hovered or focused. Focus inside the card holds it\n however it got there. Whether a click focuses what it lands on is up to the browser, though:\n Safari and Firefox on macOS don't focus a button on click, so there a clicked button doesn't keep\n the card open once the pointer moves away.\n\nAnd around it:\n\n- Keyboard focus on the trigger opens the card, as hover does. Focus that a press brings doesn't,\n and neither does a touch pointer, so tapping the trigger on a phone just does what the trigger\n does. Clicking the trigger never toggles the card.\n- By default, then, a phone or tablet never opens the card, so whatever it shows has to be\n reachable from the trigger as well. `openOnTap` opens it with a tap, for a trigger with no tap\n action of its own. While a tap holds it open, a tap outside the trigger and the card closes it.\n- The trigger gets `aria-expanded` and `aria-controls`, which say it's expanded and name the card\n only while the card is on the page. It gets no role, no tab stop and no `aria-haspopup`, so the trigger element itself has to\n take focus, such as a link or a button. A link inside a `<span>` doesn't do, since focus comes\n back to the trigger and its ARIA is on it. A development build warns when the trigger can't take\n focus.\n- The card is a plain element with an `id` and no role. It isn't a dialog, since focus doesn't move\n into it, and it isn't a tooltip, since it can hold links. In place, a screen reader meets it\n right after the trigger, Tab goes from the trigger into its links and buttons, and tabbing past\n them closes it.\n- With `appendToBody` the card renders at the end of `<body>`, so it sits last in the Tab order.\n Tab reaches it only after the rest of the page, and focus leaving the trigger on the way closes\n it. Keyboard users can open it, read it and close it, so whatever it links to should be\n reachable from the page as well.\n- Opening the card moves no focus, and nothing traps it. Links and buttons belong in a card; a form\n belongs in a `Popover`, which opens on purpose and holds focus.\n- The fade-in is turned off under `prefers-reduced-motion: reduce`.",
|
|
34
|
+
"related": ["Media", "Popover", "Portal", "Tooltip", "useBulmaClasses"],
|
|
35
|
+
"storybook": "https://bestax.io/storybook/?path=/story/components-hovercard--default",
|
|
36
|
+
"summary": "The `HoverCard` component shows a card previewing what's behind a link or a button while the pointer rests on it or keyboard focus is on it. Nothing moves focus when the card opens, and nothing traps it. In place, the card comes right after the trigger, so Tab goes from the trigger into its links and tabbing past them closes it. The pointer can move onto the card, Escape closes it from anywhere, and by default touch doesn't open it, so tapping the trigger just does what the trigger does. `openOnTap` opens it with a tap, for a trigger with no tap action of its own. For hints with nothing to click use `Tooltip`, and for content opened on purpose, such as a form, use `Popover`.",
|
|
37
|
+
"import": "import { HoverCard } from '@allxsmith/bestax-bulma';",
|
|
38
|
+
"sourceFile": "bulma-ui/src/components/HoverCard.tsx",
|
|
39
|
+
"rootClass": "hover-card",
|
|
40
|
+
"parts": [
|
|
41
|
+
{
|
|
42
|
+
"path": "HoverCard",
|
|
43
|
+
"summary": "The `HoverCard` component shows a card previewing what's behind a link or a button while the pointer rests on it or keyboard focus is on it. Nothing moves focus when the card opens, and nothing traps it. In place, the card comes right after the trigger, so Tab goes from the trigger into its links and tabbing past them closes it. The pointer can move onto the card, Escape closes it from anywhere, and by default touch doesn't open it, so tapping the trigger just does what the trigger does. `openOnTap` opens it with a tap, for a trigger with no tap action of its own. For hints with nothing to click use `Tooltip`, and for content opened on purpose, such as a form, use `Popover`.",
|
|
44
|
+
"component": null,
|
|
45
|
+
"props": [
|
|
46
|
+
{
|
|
47
|
+
"name": "trigger",
|
|
48
|
+
"type": "React.ReactElement",
|
|
49
|
+
"default": null,
|
|
50
|
+
"description": "The element the card previews, such as a link or a `Button`. The element itself has to take focus, so keyboard users can open the card too: a link inside a `<span>` doesn't do, since focus comes back to the trigger and its ARIA is on it. HoverCard gives it no role and no tab stop, since it can't know what the element is, and a development build warns when it can't take focus: use a link or a button, or give the element `tabIndex={0}`. A disabled button can't take focus either. HoverCard adds `aria-expanded` and `aria-controls`, both naming the card only while it is on the page, so it has to be a single element that passes those to its DOM node. Its own click and keys stay its own, and the card doesn't toggle on them, except Escape while the card is open, which closes the card before the trigger sees it.",
|
|
51
|
+
"required": false,
|
|
52
|
+
"inherited": false,
|
|
53
|
+
"deprecated": false
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"name": "children",
|
|
57
|
+
"type": "React.ReactNode",
|
|
58
|
+
"default": null,
|
|
59
|
+
"description": "The card's content: a preview whose links and buttons are fine, but not a form, which belongs in a `Popover`. The card pads itself, so content goes straight in.",
|
|
60
|
+
"required": false,
|
|
61
|
+
"inherited": false,
|
|
62
|
+
"deprecated": false
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"name": "open",
|
|
66
|
+
"type": "boolean",
|
|
67
|
+
"default": null,
|
|
68
|
+
"description": "Controlled open state. When set, hover, focus and Escape only report through `onOpenChange`, so an action inside the card can close it. While the card is open, Escape is reported, and when focus is in the card, on its trigger or nowhere, the key stops there even if you keep the card open, so a `Modal` around it doesn't close from the keyboard until the card does.",
|
|
69
|
+
"required": false,
|
|
70
|
+
"inherited": false,
|
|
71
|
+
"deprecated": false
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"name": "defaultOpen",
|
|
75
|
+
"type": "boolean",
|
|
76
|
+
"default": "false",
|
|
77
|
+
"description": "Initial open state when uncontrolled. A card that starts open stays open until the pointer or focus has been and gone, or Escape closes it.",
|
|
78
|
+
"required": false,
|
|
79
|
+
"inherited": false,
|
|
80
|
+
"deprecated": false
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"name": "onOpenChange",
|
|
84
|
+
"type": "(open: boolean) => void",
|
|
85
|
+
"default": null,
|
|
86
|
+
"description": "Called with the state asked for: when `openDelay` or `closeDelay` runs out, and right away on Escape. Fires in both controlled and uncontrolled use. An Escape it reports stops at the card when focus is in the card, on its trigger or nowhere, so nothing around it sees that key. With focus anywhere else, the card still closes and the key goes on to whatever has focus.",
|
|
87
|
+
"required": false,
|
|
88
|
+
"inherited": false,
|
|
89
|
+
"deprecated": false
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"name": "openDelay",
|
|
93
|
+
"type": "number",
|
|
94
|
+
"default": "600",
|
|
95
|
+
"description": "How long the pointer or keyboard focus waits on the trigger before the card opens, in milliseconds.",
|
|
96
|
+
"required": false,
|
|
97
|
+
"inherited": false,
|
|
98
|
+
"deprecated": false
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"name": "closeDelay",
|
|
102
|
+
"type": "number",
|
|
103
|
+
"default": "300",
|
|
104
|
+
"description": "How long the card stays after the pointer and focus have left the trigger and the card, in milliseconds. It is the time the pointer has to cross the gap between the trigger and the card: with `0` the card closes as the pointer leaves the trigger, before the pointer can reach it.",
|
|
105
|
+
"required": false,
|
|
106
|
+
"inherited": false,
|
|
107
|
+
"deprecated": false
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"name": "position",
|
|
111
|
+
"type": "'bottom-left' | 'bottom-right' | 'top-left' | 'top-right' | 'auto'",
|
|
112
|
+
"default": "'bottom-left'",
|
|
113
|
+
"description": "Where the card opens against the trigger.",
|
|
114
|
+
"required": false,
|
|
115
|
+
"inherited": false,
|
|
116
|
+
"deprecated": false
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"name": "appendToBody",
|
|
120
|
+
"type": "boolean",
|
|
121
|
+
"default": "false",
|
|
122
|
+
"description": "Render the card at the end of `document.body` through `Portal`, fixed to the viewport, so an ancestor's `overflow`, `transform` or stacking context can't clip it. A trigger in running text needs it too, since the card's block content can't sit inside a `<p>`. The card then shows from the commit after hydration, never in server markup, and it sits last in the Tab order, at the end of `<body>`. Tab reaches it only after the rest of the page, and focus leaving the trigger on the way closes it, so keyboard users can open it, read it and close it with Escape, and whatever it links to has to be reachable from the page as well. It is measured against the trigger when it opens and on resize and scroll, so it doesn't follow content that changes size while it is open. Theming variables set on an ancestor of the trigger don't reach it there.",
|
|
123
|
+
"required": false,
|
|
124
|
+
"inherited": false,
|
|
125
|
+
"deprecated": false
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"name": "openOnTap",
|
|
129
|
+
"type": "boolean",
|
|
130
|
+
"default": "false",
|
|
131
|
+
"description": "Open the card with a tap on a touch screen. Touch has no hover, so without this a phone or tablet never opens the card. With it, a tap on the trigger opens the card at once, and it stays until a second tap on the trigger, a tap outside the trigger and the card, or Escape. The tap still does whatever the trigger does, so turn this on only for a trigger with no tap action of its own, such as a `Button` with no `onClick`: on a link, the first tap would follow the link rather than show the card. Mouse and pen work the same either way.",
|
|
132
|
+
"required": false,
|
|
133
|
+
"inherited": false,
|
|
134
|
+
"deprecated": false
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
"name": "contentClassName",
|
|
138
|
+
"type": "string",
|
|
139
|
+
"default": null,
|
|
140
|
+
"description": "Additional classes for the card (`.hover-card-content`).",
|
|
141
|
+
"required": false,
|
|
142
|
+
"inherited": false,
|
|
143
|
+
"deprecated": false
|
|
144
|
+
}
|
|
145
|
+
],
|
|
146
|
+
"extraProps": [
|
|
147
|
+
{
|
|
148
|
+
"name": "className",
|
|
149
|
+
"type": "string",
|
|
150
|
+
"default": null,
|
|
151
|
+
"description": "Additional classes for the `span` around the trigger. The card takes `contentClassName`.",
|
|
152
|
+
"required": false,
|
|
153
|
+
"inherited": false,
|
|
154
|
+
"deprecated": false
|
|
155
|
+
}
|
|
156
|
+
],
|
|
157
|
+
"catchAll": "All standard <span> attributes and Bulma helper props",
|
|
158
|
+
"types": []
|
|
159
|
+
}
|
|
160
|
+
],
|
|
161
|
+
"cssVars": [
|
|
162
|
+
{
|
|
163
|
+
"css": "--bulma-hover-card-z-index",
|
|
164
|
+
"sass": "$hover-card-z-index",
|
|
165
|
+
"default": "$extras-z-index-tooltip",
|
|
166
|
+
"scope": "element"
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
"css": "--bulma-hover-card-background",
|
|
170
|
+
"sass": "$hover-card-background",
|
|
171
|
+
"default": "var(--bulma-scheme-main)",
|
|
172
|
+
"scope": "element"
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
"css": "--bulma-hover-card-color",
|
|
176
|
+
"sass": "$hover-card-color",
|
|
177
|
+
"default": "var(--bulma-text)",
|
|
178
|
+
"scope": "element"
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
"css": "--bulma-hover-card-border-color",
|
|
182
|
+
"sass": "$hover-card-border-color",
|
|
183
|
+
"default": "var(--bulma-border-weak)",
|
|
184
|
+
"scope": "element"
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
"css": "--bulma-hover-card-radius",
|
|
188
|
+
"sass": "$hover-card-radius",
|
|
189
|
+
"default": "var(--bulma-radius-large)",
|
|
190
|
+
"scope": "element"
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
"css": "--bulma-hover-card-shadow",
|
|
194
|
+
"sass": "$hover-card-shadow",
|
|
195
|
+
"default": "var(--bulma-shadow)",
|
|
196
|
+
"scope": "element"
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
"css": "--bulma-hover-card-padding",
|
|
200
|
+
"sass": "$hover-card-padding",
|
|
201
|
+
"default": "1rem",
|
|
202
|
+
"scope": "element"
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
"css": "--bulma-hover-card-min-width",
|
|
206
|
+
"sass": "$hover-card-min-width",
|
|
207
|
+
"default": "12rem",
|
|
208
|
+
"scope": "element"
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
"css": "--bulma-hover-card-max-width",
|
|
212
|
+
"sass": "$hover-card-max-width",
|
|
213
|
+
"default": "min(20rem, calc(100vw - 2rem))",
|
|
214
|
+
"scope": "element"
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
"css": "--bulma-hover-card-offset",
|
|
218
|
+
"sass": "$hover-card-offset",
|
|
219
|
+
"default": "0.25rem",
|
|
220
|
+
"scope": "element"
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
"css": "--bulma-hover-card-animation-duration",
|
|
224
|
+
"sass": "$hover-card-animation-duration",
|
|
225
|
+
"default": "0.15s",
|
|
226
|
+
"scope": "element"
|
|
227
|
+
}
|
|
228
|
+
]
|
|
229
|
+
}
|
|
@@ -99,15 +99,15 @@
|
|
|
99
99
|
},
|
|
100
100
|
{
|
|
101
101
|
"title": "Horizontal — Validation Error",
|
|
102
|
-
"code": "<Field horizontal label=\"Email\">\n <Field.Body>\n <Field>\n <Control iconLeftName=\"envelope\" iconRightName=\"exclamation-triangle\">\n <Input
|
|
102
|
+
"code": "<Field horizontal label=\"Email\" labelProps={{ htmlFor: 'invalid-email' }}>\n <Field.Body>\n <Field>\n <Control iconLeftName=\"envelope\" iconRightName=\"exclamation-triangle\">\n <Input\n id=\"invalid-email\"\n type=\"email\"\n color=\"danger\"\n value=\"hello@\"\n onChange={() => {}}\n />\n </Control>\n <p className=\"help is-danger\">This email is invalid</p>\n </Field>\n </Field.Body>\n</Field>"
|
|
103
103
|
},
|
|
104
104
|
{
|
|
105
105
|
"title": "Horizontal — Addons (Phone with Country Code)",
|
|
106
|
-
"code": "<Field horizontal label=\"Phone\">\n <Field.Body>\n <Field hasAddons>\n <Control>\n <Button isStatic>+44</Button>\n </Control>\n <Control isExpanded>\n <Input type=\"tel\" placeholder=\"Your phone number\" />\n </Control>\n </Field>\n </Field.Body>\n</Field>"
|
|
106
|
+
"code": "<Field horizontal label=\"Phone\" labelProps={{ htmlFor: 'phone-number' }}>\n <Field.Body>\n <Field hasAddons>\n <Control>\n <Button isStatic>+44</Button>\n </Control>\n <Control isExpanded>\n <Input id=\"phone-number\" type=\"tel\" placeholder=\"Your phone number\" />\n </Control>\n </Field>\n </Field.Body>\n</Field>"
|
|
107
107
|
},
|
|
108
108
|
{
|
|
109
109
|
"title": "Horizontal — Submit Row",
|
|
110
|
-
"code": "<>\n <Field horizontal label=\"Name\">\n <Field.Body>\n <Field>\n <Control>\n <Input placeholder=\"Your name\" />\n </Control>\n </Field>\n </Field.Body>\n </Field>\n <Field horizontal>\n <Field.Label />\n <Field.Body>\n <Field>\n <Control>\n <Button color=\"primary\">Submit</Button>\n </Control>\n </Field>\n </Field.Body>\n </Field>\n</>"
|
|
110
|
+
"code": "<>\n <Field horizontal label=\"Name\" labelProps={{ htmlFor: 'submit-row-name' }}>\n <Field.Body>\n <Field>\n <Control>\n <Input id=\"submit-row-name\" placeholder=\"Your name\" />\n </Control>\n </Field>\n </Field.Body>\n </Field>\n <Field horizontal>\n <Field.Label />\n <Field.Body>\n <Field>\n <Control>\n <Button color=\"primary\">Submit</Button>\n </Control>\n </Field>\n </Field.Body>\n </Field>\n</>"
|
|
111
111
|
},
|
|
112
112
|
{
|
|
113
113
|
"title": "Disabled Fieldset",
|
|
@@ -119,14 +119,14 @@
|
|
|
119
119
|
},
|
|
120
120
|
{
|
|
121
121
|
"title": "Context-Aware Rendering",
|
|
122
|
-
"code": "function example() {\n return (\n <Field
|
|
122
|
+
"code": "function example() {\n return (\n <Field\n horizontal\n label=\"Username\"\n labelProps={{ htmlFor: 'username-field' }}\n >\n <Field.Body>\n <Field>\n <Input id=\"username-field\" placeholder=\"Enter username\" />\n </Field>\n </Field.Body>\n </Field>\n );\n}"
|
|
123
123
|
},
|
|
124
124
|
{
|
|
125
125
|
"title": "Context-Aware Rendering",
|
|
126
|
-
"code": "function example() {\n return (\n <Field
|
|
126
|
+
"code": "function example() {\n return (\n <Field\n horizontal\n label=\"Username\"\n labelProps={{ htmlFor: 'username-field-control' }}\n >\n <Field.Body>\n <Field>\n <Control iconLeftName=\"user\">\n <Input id=\"username-field-control\" placeholder=\"Enter username\" />\n </Control>\n </Field>\n </Field.Body>\n </Field>\n );\n}"
|
|
127
127
|
}
|
|
128
128
|
],
|
|
129
|
-
"accessibility": "- Always provide a label. The `label` prop is automatically associated with the input (`htmlFor` plus a generated `id`, or your own `id` if you pass one), so clicking the label focuses the input and assistive technology announces it.\n- When composing with `Field` instead, the `Field`'s own `label` associates with the input automatically when the input sits directly in that labeled `Field`
|
|
129
|
+
"accessibility": "- Always provide a label. The `label` prop is automatically associated with the input (`htmlFor` plus a generated `id`, or your own `id` if you pass one), so clicking the label focuses the input and assistive technology announces it.\n- When composing with `Field` instead, the `Field`'s own `label` associates with the input automatically when the input sits directly in that labeled `Field` and has no `id` of its own. A nested unlabeled `Field` (as in horizontal multi-field layouts) starts its own scope. With an `id` of your own, or across a nested `Field`, the label names the input only when you pass that `id` as `labelProps={{ htmlFor }}`.\n- Use the correct input `type` for semantics (`text`, `email`, etc.).",
|
|
130
130
|
"related": ["Control", "Field"],
|
|
131
131
|
"storybook": "https://bestax.io/storybook/?path=/story/form-input--default",
|
|
132
132
|
"summary": "The `Input` component provides a Bulma-styled text input, supporting colors, sizes, rounded corners, static state, hover/focus/loading states, and all Bulma helper props.",
|
|
@@ -143,7 +143,7 @@
|
|
|
143
143
|
"name": "label",
|
|
144
144
|
"type": "React.ReactNode",
|
|
145
145
|
"default": null,
|
|
146
|
-
"description": "Field label. Automatically associated with the input via `htmlFor` — uses your `id` when provided, otherwise a generated one. Dropped inside an outer `Field`, whose own label associates instead when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`).",
|
|
146
|
+
"description": "Field label. Automatically associated with the input via `htmlFor` — uses your `id` when provided, otherwise a generated one. Dropped inside an outer `Field`, whose own label associates instead when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`) and you set no `id` here.",
|
|
147
147
|
"required": false,
|
|
148
148
|
"inherited": false,
|
|
149
149
|
"deprecated": false
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"name": "hasDelete",
|
|
90
90
|
"type": "boolean",
|
|
91
91
|
"default": "false",
|
|
92
|
-
"description": "Shows a close (delete) button in the notification. It renders `type=\"button\"`, so it does not submit a form around it.",
|
|
92
|
+
"description": "Shows a close (delete) button in the notification. It renders `type=\"button\"`, so it does not submit a form around it. The notification also takes `has-delete`, which pads its end by `--bulma-notification-delete-padding-inline-end` so the text clears the button. That rule ships in bestax's stylesheets, not Bulma's, so an app styled by Bulma's CSS alone keeps Bulma's padding.",
|
|
93
93
|
"required": false,
|
|
94
94
|
"inherited": false,
|
|
95
95
|
"deprecated": false
|
|
@@ -119,6 +119,12 @@
|
|
|
119
119
|
}
|
|
120
120
|
],
|
|
121
121
|
"cssVars": [
|
|
122
|
+
{
|
|
123
|
+
"css": "--bulma-notification-delete-padding-inline-end",
|
|
124
|
+
"sass": "$notification-delete-padding-inline-end",
|
|
125
|
+
"default": "calc(1rem + 1.25rem + 0.75rem)",
|
|
126
|
+
"scope": "root"
|
|
127
|
+
},
|
|
122
128
|
{
|
|
123
129
|
"css": "--bulma-notification-h",
|
|
124
130
|
"sass": null,
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"name": "label",
|
|
72
72
|
"type": "React.ReactNode",
|
|
73
73
|
"default": null,
|
|
74
|
-
"description": "Field label. Automatically associated with the number input via `htmlFor` — uses your `id` when provided, otherwise a generated one. Dropped inside an outer `Field`, whose own label associates instead when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`). Not rendered either by a plusminus `bare` Numberinput outside a `Field`.",
|
|
74
|
+
"description": "Field label. Automatically associated with the number input via `htmlFor` — uses your `id` when provided, otherwise a generated one. Dropped inside an outer `Field`, whose own label associates instead when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`) and you set no `id` here. Not rendered either by a plusminus `bare` Numberinput outside a `Field`.",
|
|
75
75
|
"required": false,
|
|
76
76
|
"inherited": false,
|
|
77
77
|
"deprecated": false
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
"accessibility": "`Popover` follows the [WAI-ARIA dialog pattern](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/)\nfor a non-modal dialog:\n\n- The panel is a `role=\"dialog\"` without `aria-modal`. It is named by its `Popover.Header` through\n `aria-labelledby`, or by `ariaLabel`, which takes precedence. A development build warns when an\n open panel has neither.\n- The trigger gets `aria-haspopup=\"dialog\"`, `aria-expanded`, and `aria-controls` pointing at the\n panel while it is open.\n- Opening moves focus to the first control in the panel, or to the panel itself when it has none.\n Closing hands focus back to the trigger, as long as focus is still in the panel then, so a click\n that put it somewhere else keeps it there.\n- Tab and Shift+Tab wrap inside the open panel, which the pattern asks of non-modal dialogs too.\n Pointer focus, the screen reader's reading cursor and the rest of the page stay free: nothing\n outside is hidden or made inert, and the page still scrolls. `trapFocus={false}` lets Tab leave.\n- <kbd>Escape</kbd> closes the popover while focus is in the panel or on the trigger. A dialog\n nested inside the panel, such as a date picker's calendar or another popover, takes its own\n Escape first.\n- <kbd>Enter</kbd> and <kbd>Space</kbd> toggle a trigger the browser doesn't click on its own.\n- The open animation is turned off under `prefers-reduced-motion: reduce`.",
|
|
42
42
|
"related": [
|
|
43
43
|
"Dropdown",
|
|
44
|
+
"HoverCard",
|
|
44
45
|
"Modal",
|
|
45
46
|
"Portal",
|
|
46
47
|
"Tooltip",
|