bestax-mcp 1.2.2 → 1.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +1 -1
  2. package/data/catalog.json +22 -22
  3. package/data/components/Button.json +15 -1
  4. package/data/components/Buttons.json +35 -2
  5. package/data/components/Control.json +4 -4
  6. package/data/components/DateInput.json +2 -2
  7. package/data/components/DateTimeInput.json +2 -2
  8. package/data/components/Dialog.json +14 -1
  9. package/data/components/Dropdown.json +25 -2
  10. package/data/components/Field.json +4 -4
  11. package/data/components/Icon.json +40 -27
  12. package/data/components/IconText.json +38 -29
  13. package/data/components/Input.json +2 -2
  14. package/data/components/LinkButton.json +15 -1
  15. package/data/components/Message.json +10 -1
  16. package/data/components/Modal.json +47 -2
  17. package/data/components/Navbar.json +58 -5
  18. package/data/components/Panel.json +23 -14
  19. package/data/components/Select.json +1 -1
  20. package/data/components/Sidebar.json +1 -1
  21. package/data/components/Tags.json +21 -7
  22. package/data/components/TimeInput.json +2 -2
  23. package/data/components/Valid value constants.json +1 -1
  24. package/data/components/useBulmaClasses.json +13 -1
  25. package/data/skills/bestax-custom-component/references/component-catalog.md +1 -1
  26. package/data/skills/bestax-icons/SKILL.md +28 -0
  27. package/data/skills/bestax-migrate/SKILL.md +78 -32
  28. package/data/skills/bestax-migrate/references/bloomer/component-map.md +159 -0
  29. package/data/skills/bestax-migrate/references/bloomer/prop-map.md +135 -0
  30. package/data/skills/bestax-migrate/references/bloomer/unmappables.md +240 -0
  31. package/data/skills/bestax-migrate/references/css-migration.md +18 -10
  32. package/data/skills/bestax-migrate/references/rbx/component-map.md +171 -0
  33. package/data/skills/bestax-migrate/references/rbx/prop-map.md +153 -0
  34. package/data/skills/bestax-migrate/references/rbx/unmappables.md +171 -0
  35. package/data/skills/bestax-migrate/references/{component-map.md → react-bulma-components/component-map.md} +1 -1
  36. package/data/skills/bestax-migrate/references/{prop-map.md → react-bulma-components/prop-map.md} +1 -1
  37. package/data/skills/bestax-migrate/references/{unmappables.md → react-bulma-components/unmappables.md} +36 -6
  38. package/data/skills.json +44 -10
  39. package/package.json +5 -4
package/README.md CHANGED
@@ -96,4 +96,4 @@ One per skill, so a task can start from the library's own guidance:
96
96
  - [Documentation](https://bestax.io)
97
97
  - [GitHub](https://github.com/allxsmith/bestax)
98
98
 
99
- MIT © Alex Smith
99
+ Source code licensed MIT
package/data/catalog.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "schemaVersion": 1,
3
3
  "generatedFrom": {
4
4
  "package": "@allxsmith/bestax-bulma",
5
- "version": "5.11.5"
5
+ "version": "5.15.0"
6
6
  },
7
7
  "docsBase": "https://bestax.io/docs",
8
8
  "categories": [
@@ -206,7 +206,7 @@
206
206
  "import": "import { Button } from '@allxsmith/bestax-bulma';",
207
207
  "compound": false,
208
208
  "propCount": 23,
209
- "exampleCount": 24
209
+ "exampleCount": 25
210
210
  },
211
211
  {
212
212
  "name": "Buttons",
@@ -216,8 +216,8 @@
216
216
  "slug": "elements/buttons",
217
217
  "import": "import { Buttons } from '@allxsmith/bestax-bulma';",
218
218
  "compound": true,
219
- "propCount": 52,
220
- "exampleCount": 7
219
+ "propCount": 53,
220
+ "exampleCount": 8
221
221
  },
222
222
  {
223
223
  "name": "Card",
@@ -403,8 +403,8 @@
403
403
  "slug": "components/dialog",
404
404
  "import": "import { Dialog, DialogContainer, dialog } from '@allxsmith/bestax-bulma';",
405
405
  "compound": false,
406
- "propCount": 12,
407
- "exampleCount": 5
406
+ "propCount": 13,
407
+ "exampleCount": 6
408
408
  },
409
409
  {
410
410
  "name": "Divider",
@@ -425,8 +425,8 @@
425
425
  "slug": "components/dropdown",
426
426
  "import": "import { Dropdown } from '@allxsmith/bestax-bulma';",
427
427
  "compound": true,
428
- "propCount": 16,
429
- "exampleCount": 7
428
+ "propCount": 17,
429
+ "exampleCount": 8
430
430
  },
431
431
  {
432
432
  "name": "Emphasis",
@@ -513,8 +513,8 @@
513
513
  "slug": "elements/icon",
514
514
  "import": "import { Icon } from '@allxsmith/bestax-bulma';",
515
515
  "compound": false,
516
- "propCount": 14,
517
- "exampleCount": 11
516
+ "propCount": 15,
517
+ "exampleCount": 12
518
518
  },
519
519
  {
520
520
  "name": "IconText",
@@ -524,7 +524,7 @@
524
524
  "slug": "elements/icontext",
525
525
  "import": "import { IconText } from '@allxsmith/bestax-bulma';",
526
526
  "compound": true,
527
- "propCount": 21,
527
+ "propCount": 22,
528
528
  "exampleCount": 11
529
529
  },
530
530
  {
@@ -580,7 +580,7 @@
580
580
  "import": "import { LinkButton } from '@allxsmith/bestax-bulma';",
581
581
  "compound": false,
582
582
  "propCount": 21,
583
- "exampleCount": 9
583
+ "exampleCount": 10
584
584
  },
585
585
  {
586
586
  "name": "ListItem",
@@ -634,7 +634,7 @@
634
634
  "slug": "components/message",
635
635
  "import": "import { Message } from '@allxsmith/bestax-bulma';",
636
636
  "compound": true,
637
- "propCount": 11,
637
+ "propCount": 12,
638
638
  "exampleCount": 8
639
639
  },
640
640
  {
@@ -645,8 +645,8 @@
645
645
  "slug": "components/modal",
646
646
  "import": "import { Modal } from '@allxsmith/bestax-bulma';",
647
647
  "compound": true,
648
- "propCount": 20,
649
- "exampleCount": 8
648
+ "propCount": 23,
649
+ "exampleCount": 10
650
650
  },
651
651
  {
652
652
  "name": "Navbar",
@@ -656,8 +656,8 @@
656
656
  "slug": "components/navbar",
657
657
  "import": "import { Navbar } from '@allxsmith/bestax-bulma';",
658
658
  "compound": true,
659
- "propCount": 54,
660
- "exampleCount": 16
659
+ "propCount": 55,
660
+ "exampleCount": 17
661
661
  },
662
662
  {
663
663
  "name": "Notification",
@@ -711,7 +711,7 @@
711
711
  "slug": "components/panel",
712
712
  "import": "import { Panel } from '@allxsmith/bestax-bulma';",
713
713
  "compound": true,
714
- "propCount": 34,
714
+ "propCount": 35,
715
715
  "exampleCount": 3
716
716
  },
717
717
  {
@@ -949,12 +949,12 @@
949
949
  "name": "Tags",
950
950
  "kind": "component",
951
951
  "category": "elements",
952
- "purpose": "The `Tags` component groups multiple `Tag` components together in a horizontal (or multiline) Bulma-styled container.",
952
+ "purpose": "The `Tags` component groups multiple `Tag` components together in a Bulma-styled container that wraps onto multiple lines by default.",
953
953
  "slug": "elements/tags",
954
954
  "import": "import { Tags } from '@allxsmith/bestax-bulma';",
955
955
  "compound": true,
956
- "propCount": 13,
957
- "exampleCount": 7
956
+ "propCount": 14,
957
+ "exampleCount": 8
958
958
  },
959
959
  {
960
960
  "name": "TextArea",
@@ -1064,7 +1064,7 @@
1064
1064
  "import": "import { useBulmaClasses } from '@allxsmith/bestax-bulma';",
1065
1065
  "compound": false,
1066
1066
  "propCount": 0,
1067
- "exampleCount": 40
1067
+ "exampleCount": 43
1068
1068
  },
1069
1069
  {
1070
1070
  "name": "usePrefixedClassNames",
@@ -91,6 +91,10 @@
91
91
  {
92
92
  "title": "Polymorphic `as` (Router Links)",
93
93
  "code": "import { Link as RouterLink } from 'react-router-dom';\nimport { Button } from '@allxsmith/bestax-bulma';\n\n<Button as={RouterLink} to=\"/visit\" color=\"primary\">\n Book a visit\n</Button>;"
94
+ },
95
+ {
96
+ "title": "Forwarded ref",
97
+ "code": "function example() {\n const buttonRef = React.useRef(null);\n const [tag, setTag] = React.useState(null);\n\n return (\n <>\n <Button color=\"primary\" ref={buttonRef}>\n Target\n </Button>\n <Button ml=\"2\" onClick={() => setTag(buttonRef.current?.tagName)}>\n Read the tag from its ref\n </Button>\n <p>Rendered element: {tag ?? '—'}</p>\n </>\n );\n}"
94
98
  }
95
99
  ],
96
100
  "accessibility": "- **Labeling:** Always provide descriptive content for buttons for screen readers.\n- **States:** The `isDisabled` and `disabled` props ensure correct `aria-disabled` and `disabled` attributes.\n- **Keyboard:** When rendered as `<a>`, disabled buttons are not focusable.\n- **Focus:** Use `isFocused` and `isActive` for visual feedback, but rely on browser focus for actual accessibility.\n\n:::note\nIf your button has only an icon, use `aria-label` to provide accessible text.\n:::",
@@ -317,7 +321,17 @@
317
321
  "deprecated": false
318
322
  }
319
323
  ],
320
- "extraProps": [],
324
+ "extraProps": [
325
+ {
326
+ "name": "ref",
327
+ "type": "React.Ref<HTMLButtonElement | HTMLAnchorElement>",
328
+ "default": null,
329
+ "description": "Ref forwarded to the rendered button or anchor element.",
330
+ "required": false,
331
+ "inherited": false,
332
+ "deprecated": false
333
+ }
334
+ ],
321
335
  "catchAll": "All standard <button> attributes and Bulma helper props",
322
336
  "types": []
323
337
  }
@@ -17,6 +17,10 @@
17
17
  "title": "All Sizes Group",
18
18
  "code": "<Buttons>\n {['small', 'normal', 'medium', 'large'].map(size => (\n <Button key={size} size={size}>\n {size.charAt(0).toUpperCase() + size.slice(1)}\n </Button>\n ))}\n</Buttons>"
19
19
  },
20
+ {
21
+ "title": "Group Size",
22
+ "code": "<>\n <Buttons size=\"small\">\n <Button color=\"primary\">Small</Button>\n <Button color=\"info\">Small</Button>\n </Buttons>\n <Buttons size=\"medium\">\n <Button color=\"primary\">Medium</Button>\n <Button color=\"info\">Medium</Button>\n </Buttons>\n <Buttons size=\"large\">\n <Button color=\"primary\">Large</Button>\n <Button color=\"info\">Large</Button>\n </Buttons>\n</>"
23
+ },
20
24
  {
21
25
  "title": "Add-ons (No Spacing Between Buttons)",
22
26
  "code": "<Buttons hasAddons>\n <Button color=\"primary\">Left</Button>\n <Button color=\"primary\">Center</Button>\n <Button color=\"primary\">Right</Button>\n</Buttons>"
@@ -112,6 +116,15 @@
112
116
  "inherited": false,
113
117
  "deprecated": false
114
118
  },
119
+ {
120
+ "name": "size",
121
+ "type": "'small' | 'medium' | 'large'",
122
+ "default": null,
123
+ "description": "Size of the button group.",
124
+ "required": false,
125
+ "inherited": false,
126
+ "deprecated": false
127
+ },
115
128
  {
116
129
  "name": "children",
117
130
  "type": "React.ReactNode",
@@ -342,7 +355,17 @@
342
355
  "deprecated": false
343
356
  }
344
357
  ],
345
- "extraProps": [],
358
+ "extraProps": [
359
+ {
360
+ "name": "ref",
361
+ "type": "React.Ref<HTMLButtonElement | HTMLAnchorElement>",
362
+ "default": null,
363
+ "description": "Ref forwarded to the rendered button or anchor element.",
364
+ "required": false,
365
+ "inherited": false,
366
+ "deprecated": false
367
+ }
368
+ ],
346
369
  "catchAll": "All standard <button> attributes and Bulma helper props",
347
370
  "types": []
348
371
  },
@@ -544,7 +567,17 @@
544
567
  "deprecated": false
545
568
  }
546
569
  ],
547
- "extraProps": [],
570
+ "extraProps": [
571
+ {
572
+ "name": "ref",
573
+ "type": "React.Ref<HTMLButtonElement | HTMLAnchorElement>",
574
+ "default": null,
575
+ "description": "Ref forwarded to the rendered button or anchor element.",
576
+ "required": false,
577
+ "inherited": false,
578
+ "deprecated": false
579
+ }
580
+ ],
548
581
  "catchAll": "All standard <button> attributes and Bulma helper props",
549
582
  "types": []
550
583
  }
@@ -169,18 +169,18 @@
169
169
  },
170
170
  {
171
171
  "name": "iconLeft",
172
- "type": "IconProps",
172
+ "type": "IconProps | React.ReactNode",
173
173
  "default": null,
174
- "description": "Icon props for left icon.",
174
+ "description": "Icon props for left icon, or a custom node (an inline SVG, a `react-icons` component, …) rendered in place of a class-based glyph.",
175
175
  "required": false,
176
176
  "inherited": true,
177
177
  "deprecated": false
178
178
  },
179
179
  {
180
180
  "name": "iconRight",
181
- "type": "IconProps",
181
+ "type": "IconProps | React.ReactNode",
182
182
  "default": null,
183
- "description": "Icon props for right icon.",
183
+ "description": "Icon props for right icon, or a custom node (an inline SVG, a `react-icons` component, …) rendered in place of a class-based glyph.",
184
184
  "required": false,
185
185
  "inherited": true,
186
186
  "deprecated": false
@@ -205,7 +205,7 @@
205
205
  },
206
206
  {
207
207
  "name": "iconLeft",
208
- "type": "IconProps",
208
+ "type": "IconProps | React.ReactNode",
209
209
  "default": null,
210
210
  "description": "Icon props for the left icon.",
211
211
  "required": false,
@@ -214,7 +214,7 @@
214
214
  },
215
215
  {
216
216
  "name": "iconRight",
217
- "type": "IconProps",
217
+ "type": "IconProps | React.ReactNode",
218
218
  "default": null,
219
219
  "description": "Icon props for the right icon.",
220
220
  "required": false,
@@ -213,7 +213,7 @@
213
213
  },
214
214
  {
215
215
  "name": "iconLeft",
216
- "type": "IconProps",
216
+ "type": "IconProps | React.ReactNode",
217
217
  "default": null,
218
218
  "description": "Icon props for the left icon.",
219
219
  "required": false,
@@ -222,7 +222,7 @@
222
222
  },
223
223
  {
224
224
  "name": "iconRight",
225
- "type": "IconProps",
225
+ "type": "IconProps | React.ReactNode",
226
226
  "default": null,
227
227
  "description": "Icon props for the right icon.",
228
228
  "required": false,
@@ -24,9 +24,13 @@
24
24
  {
25
25
  "title": "Non-cancelable Dialog",
26
26
  "code": "function example() {\n const [showDialog, setShowDialog] = useState(false);\n return (\n <Block>\n <Button color=\"warning\" onClick={() => setShowDialog(true)}>\n Show Required Action\n </Button>\n <Dialog\n isOpen={showDialog}\n title=\"Required Action\"\n message=\"You must complete this action to continue.\"\n type=\"warning\"\n canCancel={false}\n showCancel={false}\n confirmText=\"I Understand\"\n onConfirm={() => setShowDialog(false)}\n />\n </Block>\n );\n}"
27
+ },
28
+ {
29
+ "title": "Portal",
30
+ "code": "function example() {\n const [showDialog, setShowDialog] = useState(false);\n return (\n <Block>\n <Button onClick={() => setShowDialog(true)}>Show Portaled Dialog</Button>\n <Dialog\n isOpen={showDialog}\n title=\"Rendered in document.body\"\n message=\"This dialog is portaled, so it escapes any ancestor with overflow: hidden.\"\n onConfirm={() => setShowDialog(false)}\n showCancel={false}\n portal\n />\n </Block>\n );\n}"
27
31
  }
28
32
  ],
29
- "accessibility": "- Uses `role=\"alertdialog\"` for proper screen reader announcement\n- Has `aria-modal=\"true\"` to indicate modal behavior\n- Focus is trapped within the dialog when open\n- Escape key closes the dialog (when `canCancel` is true)\n- Body scroll is prevented when dialog is open\n- Confirm/cancel buttons are keyboard accessible",
33
+ "accessibility": "- Uses `role=\"alertdialog\"` for proper screen reader announcement\n- Has `aria-modal=\"true\"` to indicate modal behavior — note this does not make background content inert; no `inert` attribute is applied, so background content stays reachable by pointer\n- `title` is wired up as `aria-labelledby` and `message` as `aria-describedby`\n- Focus moves to the confirm (or cancel, with `focusCancel`) button when opened\n- Escape key closes the dialog (when `canCancel` is true) — handled by the underlying [`Modal`](./modal.md), which routes it to the topmost open modal only\n- Tab and Shift+Tab cycle within the dialog while it is open — also from the underlying [`Modal`](./modal.md)\n- Body scroll is prevented when dialog is open, through the ref-counted lock shared with `Modal`, `Sidebar` and `Loading`\n- Confirm/cancel buttons are keyboard accessible",
30
34
  "related": ["Modal", "Toast"],
31
35
  "storybook": "https://bestax.io/storybook/?path=/story/components-dialog",
32
36
  "summary": "The `Dialog` component provides ready-made confirm and alert dialogs, so a destructive action stays one `await dialog.confirm()` call away.",
@@ -146,6 +150,15 @@
146
150
  "required": false,
147
151
  "inherited": false,
148
152
  "deprecated": false
153
+ },
154
+ {
155
+ "name": "portal",
156
+ "type": "boolean | string | HTMLElement",
157
+ "default": "false",
158
+ "description": "Renders the dialog into a portal target instead of inline. Forwarded to the underlying `Modal`; see its `portal` prop for the accepted values.",
159
+ "required": false,
160
+ "inherited": false,
161
+ "deprecated": false
149
162
  }
150
163
  ],
151
164
  "extraProps": [
@@ -29,12 +29,16 @@
29
29
  "title": "Controlled Dropdown Example",
30
30
  "code": "function example() {\n const [open, setOpen] = useState(false);\n\n return (\n <Dropdown\n label=\"Controlled Dropdown\"\n active={open}\n onActiveChange={setOpen}\n >\n <Dropdown.Item>Item A</Dropdown.Item>\n <Dropdown.Item>Item B</Dropdown.Item>\n </Dropdown>\n );\n}"
31
31
  },
32
+ {
33
+ "title": "Forwarded ref",
34
+ "code": "function example() {\n const dropdownRef = React.useRef(null);\n const [tag, setTag] = React.useState(null);\n\n return (\n <>\n <Dropdown label=\"Pick one\" ref={dropdownRef}>\n <Dropdown.Item>First</Dropdown.Item>\n <Dropdown.Item>Second</Dropdown.Item>\n </Dropdown>\n <Button mt=\"3\" onClick={() => setTag(dropdownRef.current?.className)}>\n Read the root from its ref\n </Button>\n <p>Root class: {tag ?? '—'}</p>\n </>\n );\n}"
35
+ },
32
36
  {
33
37
  "title": "Compound (dot-notation) usage",
34
38
  "code": "<Dropdown label=\"Dropdown Menu\" active>\n <Dropdown.Item>First Item</Dropdown.Item>\n <Dropdown.Item>Second Item</Dropdown.Item>\n <Dropdown.Divider />\n <Dropdown.Item>Third Item</Dropdown.Item>\n</Dropdown>"
35
39
  }
36
40
  ],
37
- "accessibility": "- The dropdown root is a `<div class=\"dropdown\">` with ARIA roles/attributes for menu and trigger.\n- The trigger button uses `aria-haspopup`, `aria-controls`, and `aria-expanded`.\n- Menu items are focusable and use `role=\"menuitem\"`.\n- Clicking outside closes the dropdown in most cases.\n\n:::note\nFor custom keyboard navigation or focus management, add handlers as needed.\n:::",
41
+ "accessibility": "- The dropdown root is a `<div class=\"dropdown\">` with ARIA roles/attributes for menu and trigger.\n- The trigger button uses `aria-haspopup`, `aria-controls`, and `aria-expanded`.\n- Menu items are focusable and use `role=\"menuitem\"`.\n- Clicking outside closes the dropdown in most cases.\n\n`Dropdown` implements the [WAI-ARIA Menu Button pattern](https://www.w3.org/WAI/ARIA/apg/patterns/menu-button/)\nout of the box:\n\n- On the trigger: <kbd>ArrowDown</kbd> or <kbd>Enter</kbd>/<kbd>Space</kbd> open the menu and\n focus the first item; <kbd>ArrowUp</kbd> opens the menu and focuses the last item;\n <kbd>Escape</kbd> closes an open menu.\n- Inside the menu: <kbd>ArrowDown</kbd>/<kbd>ArrowUp</kbd> move between items and wrap around;\n <kbd>Home</kbd>/<kbd>End</kbd> jump to the first/last item; <kbd>Escape</kbd> closes the menu\n and returns focus to the trigger; <kbd>Tab</kbd> closes the menu and lets focus continue\n naturally.\n- Disabled items (a `Dropdown.Item` rendered with a native `disabled` attribute or\n `aria-disabled=\"true\"`) and dividers are skipped during arrow-key navigation.\n\n:::note\nThere is no typeahead and no built-in outside-click handling inside the menu beyond the\nexisting click-outside-to-close behavior — add those yourself if your use case needs them.\n:::",
38
42
  "related": ["Button", "useBulmaClasses"],
39
43
  "storybook": "https://bestax.io/storybook/?path=/story/components-dropdown--default",
40
44
  "summary": "The `Dropdown` component provides Bulma's versatile dropdown menu for your Bulma React UI.",
@@ -156,7 +160,17 @@
156
160
  "deprecated": false
157
161
  }
158
162
  ],
159
- "extraProps": [],
163
+ "extraProps": [
164
+ {
165
+ "name": "ref",
166
+ "type": "React.Ref<HTMLDivElement>",
167
+ "default": null,
168
+ "description": "Ref forwarded to the root dropdown element.",
169
+ "required": false,
170
+ "inherited": false,
171
+ "deprecated": false
172
+ }
173
+ ],
160
174
  "catchAll": "All standard <div> attributes and Bulma helper props",
161
175
  "types": []
162
176
  },
@@ -192,6 +206,15 @@
192
206
  "inherited": false,
193
207
  "deprecated": false
194
208
  },
209
+ {
210
+ "name": "disabled",
211
+ "type": "boolean",
212
+ "default": "false",
213
+ "description": "Marks the item as disabled; disabled items are skipped during keyboard navigation. Use with `as=\"button\"` for a native disabled control, or pair with `aria-disabled` on a link.",
214
+ "required": false,
215
+ "inherited": false,
216
+ "deprecated": false
217
+ },
195
218
  {
196
219
  "name": "children",
197
220
  "type": "React.ReactNode",
@@ -446,18 +446,18 @@
446
446
  },
447
447
  {
448
448
  "name": "iconLeft",
449
- "type": "IconProps",
449
+ "type": "IconProps | React.ReactNode",
450
450
  "default": null,
451
- "description": "Icon props for left icon.",
451
+ "description": "Icon props for left icon, or a custom node (an inline SVG, a `react-icons` component, …) rendered in place of a class-based glyph.",
452
452
  "required": false,
453
453
  "inherited": true,
454
454
  "deprecated": false
455
455
  },
456
456
  {
457
457
  "name": "iconRight",
458
- "type": "IconProps",
458
+ "type": "IconProps | React.ReactNode",
459
459
  "default": null,
460
- "description": "Icon props for right icon.",
460
+ "description": "Icon props for right icon, or a custom node (an inline SVG, a `react-icons` component, …) rendered in place of a class-based glyph.",
461
461
  "required": false,
462
462
  "inherited": true,
463
463
  "deprecated": false
@@ -48,9 +48,13 @@
48
48
  {
49
49
  "title": "Ionicons",
50
50
  "code": "<Icon library=\"ion\" name=\"settings\" ariaLabel=\"Ionicons settings icon\" />"
51
+ },
52
+ {
53
+ "title": "Custom node",
54
+ "code": "<Icon ariaLabel=\"Custom SVG icon\" textColor=\"primary\">\n <svg viewBox=\"0 0 16 16\" width=\"1em\" height=\"1em\" fill=\"currentColor\">\n <circle cx=\"8\" cy=\"8\" r=\"6\" />\n </svg>\n</Icon>"
51
55
  }
52
56
  ],
53
- "accessibility": "- **ARIA label:** Always set a meaningful `ariaLabel` for screen readers (default `'icon'`).\n- **Keyboard:** Icon is decorative by default. If interactive, use with `Button` or `a` and add ARIA as needed.\n- **Color and size:** Use `textColor`, `bgColor`, and `size` for accessible, themeable icons.\n\n:::note\nFor purely decorative icons, you can use `aria-hidden=\"true\"` via the `...rest` props.\n:::",
57
+ "accessibility": "- **ARIA label:** `ariaLabel` defaults to `'icon'` and is applied to the container span **unconditionally** — an `Icon` that never sets it still renders `aria-label=\"icon\"`. For an icon-only control, put the real `aria-label` on the control (e.g. `Button`) and set `aria-hidden` on the `Icon`; for a decorative icon beside visible text, set `aria-hidden` on the `Icon` so it doesn't add `\"icon\"` to the accessible name.\n- **Keyboard:** If interactive, use with `Button` or `a` and put the ARIA (`aria-label`, roles) on that control.\n- **Color and size:** Use `textColor`, `bgColor`, and `size` for accessible, themeable icons.\n\n:::note\nFor purely decorative icons, you can use `aria-hidden=\"true\"` via the `...rest` props.\n:::",
54
58
  "related": ["Button", "Card", "IconText", "useBulmaClasses"],
55
59
  "storybook": "https://bestax.io/storybook/?path=/story/elements-icon--default",
56
60
  "summary": "The `Icon` component is a Bulma-styled wrapper for displaying icons from various libraries (Font Awesome, Material Design Icons, Ionicons, Google Material Icons, Material Symbols, etc.).",
@@ -63,13 +67,31 @@
63
67
  "summary": "The `Icon` component is a Bulma-styled wrapper for displaying icons from various libraries (Font Awesome, Material Design Icons, Ionicons, Google Material Icons, Material Symbols, etc.).",
64
68
  "component": null,
65
69
  "props": [
70
+ {
71
+ "name": "name",
72
+ "type": "string | undefined",
73
+ "default": null,
74
+ "description": "The icon name, with or without its library prefix (e.g. `'star'` or `'fa-star'`). Mutually exclusive with `children`.",
75
+ "required": false,
76
+ "inherited": true,
77
+ "deprecated": false
78
+ },
79
+ {
80
+ "name": "children",
81
+ "type": "Exclude<React.ReactNode, undefined>",
82
+ "default": null,
83
+ "description": "A custom node (an inline SVG, a `react-icons` component, …) rendered inside the icon container in place of a class-based glyph. Mutually exclusive with `name`.",
84
+ "required": false,
85
+ "inherited": true,
86
+ "deprecated": false
87
+ },
66
88
  {
67
89
  "name": "className",
68
90
  "type": "string",
69
91
  "default": null,
70
92
  "description": "Additional CSS classes to apply.",
71
93
  "required": false,
72
- "inherited": false,
94
+ "inherited": true,
73
95
  "deprecated": false
74
96
  },
75
97
  {
@@ -78,7 +100,7 @@
78
100
  "default": null,
79
101
  "description": "Text color helper.",
80
102
  "required": false,
81
- "inherited": false,
103
+ "inherited": true,
82
104
  "deprecated": false,
83
105
  "valuesRef": "helpers/valid-values"
84
106
  },
@@ -88,7 +110,7 @@
88
110
  "default": null,
89
111
  "description": "Bulma color modifier for the icon.",
90
112
  "required": false,
91
- "inherited": false,
113
+ "inherited": true,
92
114
  "deprecated": false
93
115
  },
94
116
  {
@@ -97,53 +119,44 @@
97
119
  "default": null,
98
120
  "description": "Background color helper.",
99
121
  "required": false,
100
- "inherited": false,
122
+ "inherited": true,
101
123
  "deprecated": false,
102
124
  "valuesRef": "helpers/valid-values"
103
125
  },
104
- {
105
- "name": "name",
106
- "type": "string",
107
- "default": null,
108
- "description": "The icon name, with or without its library prefix (e.g. `'star'` or `'fa-star'`).",
109
- "required": false,
110
- "inherited": false,
111
- "deprecated": false
112
- },
113
126
  {
114
127
  "name": "icon",
115
128
  "type": "string",
116
129
  "default": null,
117
130
  "description": "DEPRECATED: Legacy prop, use `name` instead.",
118
131
  "required": false,
119
- "inherited": false,
132
+ "inherited": true,
120
133
  "deprecated": false
121
134
  },
122
135
  {
123
136
  "name": "library",
124
137
  "type": "'fa' | 'mdi' | 'ion' | 'material-icons' | 'material-symbols'",
125
138
  "default": "'fa'",
126
- "description": "The icon library to use ('fa' = Font Awesome, 'mdi' = Material Design Icons, 'ion' = Ionicons Web Components, 'material-icons' = Google Material Icons, 'material-symbols' = Google Material Symbols). Defaults to the value set in ConfigProvider or 'fa' if not configured.",
139
+ "description": "The icon library to use ('fa' = Font Awesome, 'mdi' = Material Design Icons, 'ion' = Ionicons Web Components, 'material-icons' = Google Material Icons, 'material-symbols' = Google Material Symbols). Defaults to the value set in ConfigProvider or 'fa' if not configured. Ignored when `children` supplies the glyph instead of `name`.",
127
140
  "required": false,
128
- "inherited": false,
141
+ "inherited": true,
129
142
  "deprecated": false
130
143
  },
131
144
  {
132
145
  "name": "variant",
133
146
  "type": "string",
134
147
  "default": null,
135
- "description": "Icon style variant (e.g. `'solid'`, `'outlined'`, `'rounded'`).",
148
+ "description": "Icon style variant (e.g. `'solid'`, `'outlined'`, `'rounded'`). Ignored when `children` supplies the glyph instead of `name`.",
136
149
  "required": false,
137
- "inherited": false,
150
+ "inherited": true,
138
151
  "deprecated": false
139
152
  },
140
153
  {
141
154
  "name": "features",
142
155
  "type": "string | string[]",
143
156
  "default": null,
144
- "description": "Additional modifiers (e.g. `'fa-lg'`, `'fa-spin'`, `'is-size-1'`).",
157
+ "description": "Additional modifiers (e.g. `'fa-lg'`, `'fa-spin'`, `'is-size-1'`). Ignored when `children` supplies the glyph instead of `name`.",
145
158
  "required": false,
146
- "inherited": false,
159
+ "inherited": true,
147
160
  "deprecated": false
148
161
  },
149
162
  {
@@ -152,7 +165,7 @@
152
165
  "default": null,
153
166
  "description": "**DEPRECATED:** Use `variant` and `features` instead.",
154
167
  "required": false,
155
- "inherited": false,
168
+ "inherited": true,
156
169
  "deprecated": false
157
170
  },
158
171
  {
@@ -161,16 +174,16 @@
161
174
  "default": null,
162
175
  "description": "Size modifier for the icon container.",
163
176
  "required": false,
164
- "inherited": false,
177
+ "inherited": true,
165
178
  "deprecated": false
166
179
  },
167
180
  {
168
181
  "name": "ariaLabel",
169
182
  "type": "string",
170
183
  "default": "'icon'",
171
- "description": "ARIA label for accessibility (default: 'icon').",
184
+ "description": "ARIA label for accessibility. Applied unconditionally to the container span, so an icon that never sets it still renders `aria-label=\"icon\"`. For an icon-only control, put the real `aria-label` on the control (e.g. `Button`) and set `aria-hidden` here instead — otherwise the control's accessible name is announced as just \"icon\". For a decorative icon beside visible text, set `aria-hidden` here rather than leaving the default, so it doesn't add \"icon\" to the text's accessible name.",
172
185
  "required": false,
173
- "inherited": false,
186
+ "inherited": true,
174
187
  "deprecated": false
175
188
  },
176
189
  {
@@ -179,7 +192,7 @@
179
192
  "default": null,
180
193
  "description": "Inline style object.",
181
194
  "required": false,
182
- "inherited": false,
195
+ "inherited": true,
183
196
  "deprecated": false
184
197
  },
185
198
  {
@@ -188,7 +201,7 @@
188
201
  "default": null,
189
202
  "description": "Override the default `'icon'` container class (e.g., `'panel-icon'`).",
190
203
  "required": false,
191
- "inherited": false,
204
+ "inherited": true,
192
205
  "deprecated": false
193
206
  }
194
207
  ],