bestax-mcp 1.18.35 → 1.18.37

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 (31) hide show
  1. package/data/bulma-classes.json +1 -1
  2. package/data/catalog.json +2 -2
  3. package/data/components/AppFrame.json +1 -1
  4. package/data/components/DateInput.json +3 -3
  5. package/data/components/DateRangeInput.json +2 -2
  6. package/data/components/DateTimeInput.json +3 -3
  7. package/data/components/Dialog.json +1 -1
  8. package/data/components/HoverCard.json +1 -1
  9. package/data/components/Icon.json +1 -1
  10. package/data/components/IconText.json +1 -1
  11. package/data/components/Level.json +12 -3
  12. package/data/components/Modal.json +2 -2
  13. package/data/components/Navbar.json +1 -1
  14. package/data/components/Panel.json +1 -1
  15. package/data/components/Popover.json +1 -1
  16. package/data/components/Radio.json +1 -1
  17. package/data/components/Sidebar.json +3 -3
  18. package/data/components/Slider.json +8 -8
  19. package/data/components/Toast.json +1 -1
  20. package/data/skills/bestax-custom-component/references/patterns.md +2 -1
  21. package/data/skills/bestax-form/references/api.md +3 -1
  22. package/data/skills/bestax-layout-scaffold/references/layout-components.md +10 -5
  23. package/data/skills/bestax-migrate/references/bloomer/prop-map.md +1 -1
  24. package/data/skills/bestax-migrate/references/bulma-classes/component-map.md +1 -1
  25. package/data/skills/bestax-migrate/references/rbx/prop-map.md +1 -0
  26. package/data/skills/bestax-migrate/references/react-bulma-components/prop-map.md +1 -1
  27. package/data/skills/bestax-optimize/SKILL.md +1 -1
  28. package/data/skills/bestax-optimize/references/modular-build.md +24 -11
  29. package/data/skills/bestax-theming/references/css-variables.md +2 -1
  30. package/data/skills.json +8 -8
  31. package/package.json +2 -2
@@ -2248,7 +2248,7 @@
2248
2248
  "status": "mapped",
2249
2249
  "target": "Level",
2250
2250
  "tag": "nav",
2251
- "as": null,
2251
+ "as": ["nav", "div", "header", "footer"],
2252
2252
  "sizeDrivesTag": false,
2253
2253
  "textColor": "textColor",
2254
2254
  "bgColor": "bgColor",
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.66.1"
5
+ "version": "5.67.0"
6
6
  },
7
7
  "docsBase": "https://bestax.io/docs",
8
8
  "categories": [
@@ -875,7 +875,7 @@
875
875
  "slug": "layout/level",
876
876
  "import": "import { Level } from '@allxsmith/bestax-bulma';",
877
877
  "compound": true,
878
- "propCount": 23,
878
+ "propCount": 24,
879
879
  "exampleCount": 5
880
880
  },
881
881
  {
@@ -38,7 +38,7 @@
38
38
  "code": "<AppFrame>\n <AppFrameHeader>\n <Navbar aria-label=\"Site\">\n <Navbar.Brand>\n <Navbar.Item href=\"#\">\n <strong>Acme</strong>\n </Navbar.Item>\n <AppFrameBurger />\n </Navbar.Brand>\n </Navbar>\n </AppFrameHeader>\n <AppFrameNav>\n <Menu>\n <Menu.List>\n <Menu.Item href=\"#\" active>\n Dashboard\n </Menu.Item>\n </Menu.List>\n </Menu>\n </AppFrameNav>\n <AppFrame.Main>\n <Section>\n <Paragraph>\n AppFrameNav and AppFrame.Nav are the same component.\n </Paragraph>\n </Section>\n </AppFrame.Main>\n</AppFrame>"
39
39
  }
40
40
  ],
41
- "accessibility": "- **Landmarks:** the header, the nav, the page and the footer are the page's banner, navigation,\n main and contentinfo landmarks, and the aside a complementary one, as long as the frame sits at\n the top of the page. A development build warns when it sits inside a `main` or a sectioning\n element, where the header and footer stop being landmarks.\n- **Names:** the nav is named \"Sections\" (`labels.nav`), since the `Navbar` in the header names\n its own navigation. The name leaves out the word \"navigation\", which the role says. A `Menu`\n in the nav keeps its `<aside>`, which inside a `<nav>` is a plain element unless it's named.\n- **Skip link:** the first thing on the page, hidden until it has focus, moves focus to the page's\n `<main>` (WCAG 2.4.1).\n- **Sticky header:** `scroll-padding-top` on the document keeps an in-page link's target and a\n focused element below the header (WCAG 2.4.11, technique C43).\n- **The burger** is a button named \"menu\" (`labels.burger`), with `aria-expanded` saying whether\n the drawer is open, or from the breakpoint up whether the column is shown, and `aria-controls`\n naming the nav. The server can't know the width, so until the page hydrates the burger has no\n `aria-expanded` and shows its bars, and the first paint after hydration has both right.\n- **The drawer** is modal by default: focus moves to its close button, Tab and Shift+Tab stay\n inside, the page doesn't scroll, the rest of the frame is inert, and Escape closes it while it's\n the topmost overlay, so a `Modal` opened from it closes first. Escape, the close button and a\n click on the backdrop hand focus back to the burger, and so does a press outside the drawer\n without `overlay`, before the press moves it to what was pressed. The close button is there for\n a touch screen reader user, who has no Escape key. It stays a navigation landmark rather than a\n dialog: the inert frame is what keeps assistive technology inside it, so keep the page's content\n inside the frame's parts.\n- **A closed drawer and a collapsed column** are `visibility: hidden`, so their links are out of\n the Tab order and the accessibility tree before any script runs.\n- **Reflow:** at 320 pixels wide the nav is a drawer, so nothing scrolls sideways (WCAG 1.4.10).\n- **Motion:** the drawer's slide, the backdrop's fade and the column's collapse don't play under\n `prefers-reduced-motion: reduce`.\n- **Forced colors:** the column keeps its divider, and the drawer gets a border on its open edge in\n place of its shadow.\n- **Right to left:** the column sits on the right, and the drawer slides in from the right.",
41
+ "accessibility": "- **Landmarks:** the header, the nav, the page and the footer are the page's banner, navigation,\n main and contentinfo landmarks, and the aside a complementary one, as long as the frame sits at\n the top of the page. A development build warns when it sits inside a `main` or a sectioning\n element, where the header and footer stop being landmarks.\n- **Names:** the nav is named \"Sections\" (`labels.nav`), since the `Navbar` in the header names\n its own navigation. The name leaves out the word \"navigation\", which the role says. A `Menu`\n in the nav keeps its `<aside>`, which inside a `<nav>` is a plain element unless it's named.\n- **Skip link:** the first thing on the page, hidden until it has focus, moves focus to the page's\n `<main>` (WCAG 2.4.1).\n- **Sticky header:** `scroll-padding-top` on the document keeps an in-page link's target and a\n focused element below the header (WCAG 2.4.11, technique C43).\n- **The burger** is a button named \"menu\" (`labels.burger`), with `aria-expanded` saying whether\n the drawer is open, or from the breakpoint up whether the column is shown, and `aria-controls`\n naming the nav. The server can't know the width, so until the page hydrates the burger has no\n `aria-expanded` and shows its bars, and the first paint after hydration has both right.\n- **The drawer** is modal by default: focus moves to its close button, Tab and Shift+Tab stay\n inside, the page doesn't scroll, the rest of the frame is inert, and Escape closes it while it's\n the topmost overlay, so a `Modal` opened from it closes first. Escape, the close button and a\n click on the backdrop hand focus back to the burger, and so does a press outside the drawer\n without `overlay`, before the press moves it to what was pressed. The close button is there for\n a touch screen reader user, who has no Escape key. It stays a navigation landmark rather than a\n dialog: the inert frame is what keeps assistive technology inside it, so keep the page's content\n inside the frame's parts.\n- **A closed drawer and a collapsed column** are `visibility: hidden`, so their links are out of\n the Tab order and the accessibility tree before any script runs.\n- **Reflow:** at 320 pixels wide the nav is a drawer, so nothing scrolls sideways (WCAG 1.4.10).\n- **Motion:** the drawer's slide, the backdrop's fade and the column's collapse don't play under\n `prefers-reduced-motion: reduce`.\n- **Forced colors:** the column keeps its divider, the drawer gets a border on its open edge in\n place of its shadow, and the burger keeps its bars, as a [`Navbar`](https://bestax.io/docs/api/components/navbar)'s\n does.\n- **Right to left:** the column sits on the right, and the drawer slides in from the right.",
42
42
  "related": [
43
43
  "Footer",
44
44
  "Menu",
@@ -178,7 +178,7 @@
178
178
  "code": "function example() {\n return (\n <Field\n horizontal\n label=\"Date\"\n labelProps={{ htmlFor: 'date-field-control' }}\n >\n <Field.Body>\n <Field>\n <Control iconLeftName=\"calendar-alt\">\n <DateInput id=\"date-field-control\" placeholder=\"YYYY-MM-DD\" />\n </Control>\n </Field>\n </Field.Body>\n </Field>\n );\n}"
179
179
  }
180
180
  ],
181
- "accessibility": "- Trigger uses `role=\"combobox\"` with `aria-haspopup=\"dialog\"`, `aria-expanded`, and `aria-controls`.\n- Popover panel has `role=\"dialog\"` with an accessible name. Opening it puts focus on the focused date, month or year.\n- Closing the popover with `Escape` or a pick returns focus to the input, whether the input or the launcher opened it. Under `openOnFocus` that returning focus leaves the popover closed; focusing or clicking the input again opens it. Dismissing without a pick commits nothing: an empty field stays empty, and leaving afterwards commits only what you typed.\n- Calendar uses `role=\"grid\"` with cells as `role=\"gridcell\"`.\n- Cells expose `aria-selected`, `aria-disabled`, and `aria-current=\"date\"` for today.\n- Roving `tabindex` keeps a single grid cell focusable at a time, and focus moves with it, inline as in the popover. When the focused date is disabled, that cell is the nearest enabled day of the month.\n- The month grid is a `role=\"grid\"` of `role=\"row\"`s, labelled by the year in its header. Each month cell carries the full month name as its accessible name, `aria-current=\"date\"` for this month and `aria-disabled` for a month with no selectable day.\n- The year list is a `role=\"listbox\"` named by the `chooseYear` label. As the selection surface its options take `aria-selected` from the value's year rather than from focus, which roves through the list. When the focused year is disabled, the nearest enabled year takes the tab stop, so `Tab` still reaches the list.\n- The launcher and popover are named \"Choose month\" or \"Choose year\" to match the granularity; override them, and the month grid's \"Previous year\" / \"Next year\" buttons, through `labels` (`chooseMonth`, `chooseYear`, `prevYear`, `nextYear`).\n- Honors `prefers-reduced-motion` (skip popover fade-in).\n- On a right-to-left page the launcher sits at the end of the line and the calendar icon at the start, and the previous-month chevron points right. The month names follow the page.",
181
+ "accessibility": "- Trigger uses `role=\"combobox\"` with `aria-haspopup=\"dialog\"`, `aria-expanded`, and `aria-controls`.\n- Popover panel has `role=\"dialog\"` with an accessible name. Opening it puts focus on the focused date, month or year.\n- Closing the popover with `Escape` or a pick returns focus to the input, whether the input or the launcher opened it. Under `openOnFocus` that returning focus leaves the popover closed; focusing or clicking the input again opens it. Dismissing without a pick commits nothing: an empty field stays empty, and leaving afterwards commits only what you typed.\n- Calendar uses `role=\"grid\"` with cells as `role=\"gridcell\"`.\n- Cells expose `aria-selected`, `aria-disabled`, and `aria-current=\"date\"` for today. On a server-rendered page, today's day, month and year get it once the page hydrates, so the reader's clock decides which.\n- Roving `tabindex` keeps a single grid cell focusable at a time, and focus moves with it, inline as in the popover. When the focused date is disabled, that cell is the nearest enabled day of the month.\n- The month grid is a `role=\"grid\"` of `role=\"row\"`s, labelled by the year in its header. Each month cell carries the full month name as its accessible name, `aria-current=\"date\"` for this month and `aria-disabled` for a month with no selectable day.\n- The year list is a `role=\"listbox\"` named by the `chooseYear` label. As the selection surface its options take `aria-selected` from the value's year rather than from focus, which roves through the list. When the focused year is disabled, the nearest enabled year takes the tab stop, so `Tab` still reaches the list.\n- The launcher and popover are named \"Choose month\" or \"Choose year\" to match the granularity; override them, and the month grid's \"Previous year\" / \"Next year\" buttons, through `labels` (`chooseMonth`, `chooseYear`, `prevYear`, `nextYear`).\n- Honors `prefers-reduced-motion` (skip popover fade-in).\n- On a right-to-left page the launcher sits at the end of the line and the calendar icon at the start, and the previous-month chevron points right. The month names follow the page.",
182
182
  "related": ["DateTimeInput", "Input", "TimeInput"],
183
183
  "storybook": "https://bestax.io/storybook/?path=/story/form-dateinput",
184
184
  "summary": "The `DateInput` component is a form input that opens a popover calendar for date selection.",
@@ -492,7 +492,7 @@
492
492
  "name": "inline",
493
493
  "type": "boolean",
494
494
  "default": "false",
495
- "description": "Render the calendar inline (no popover).",
495
+ "description": "Render the calendar inline (no popover). On a server-rendered page it marks today once the page hydrates, by the browser's clock rather than the server's. With no `value` or `defaultValue` it opens on the month the clock reads, and around the end of a month the server's clock and the browser's can read different months, so give it a date both render the same.",
496
496
  "required": false,
497
497
  "inherited": true,
498
498
  "deprecated": false
@@ -854,7 +854,7 @@
854
854
  "name": "inline",
855
855
  "type": "boolean",
856
856
  "default": "false",
857
- "description": "Render the calendar inline (no popover).",
857
+ "description": "Render the calendar inline (no popover). On a server-rendered page it marks today once the page hydrates, by the browser's clock rather than the server's. With no `value` or `defaultValue` it opens on the month the clock reads, and around the end of a month the server's clock and the browser's can read different months, so give it a date both render the same.",
858
858
  "required": false,
859
859
  "inherited": false,
860
860
  "deprecated": false
@@ -351,7 +351,7 @@
351
351
  "name": "inline",
352
352
  "type": "boolean",
353
353
  "default": "false",
354
- "description": "Render the calendar inline, with no inputs and no popover. The hidden form inputs still carry the range.",
354
+ "description": "Render the calendar inline, with no inputs and no popover. The hidden form inputs still carry the range. On a server-rendered page it marks today once the page hydrates, by the browser's clock rather than the server's. With no `value` or `defaultValue` it opens on the month the clock reads, and around the end of a month the server's clock and the browser's can read different months, so give it a date both render the same.",
355
355
  "required": false,
356
356
  "inherited": true,
357
357
  "deprecated": false
@@ -740,7 +740,7 @@
740
740
  "name": "inline",
741
741
  "type": "boolean",
742
742
  "default": "false",
743
- "description": "Render the calendar inline, with no inputs and no popover. The hidden form inputs still carry the range.",
743
+ "description": "Render the calendar inline, with no inputs and no popover. The hidden form inputs still carry the range. On a server-rendered page it marks today once the page hydrates, by the browser's clock rather than the server's. With no `value` or `defaultValue` it opens on the month the clock reads, and around the end of a month the server's clock and the browser's can read different months, so give it a date both render the same.",
744
744
  "required": false,
745
745
  "inherited": false,
746
746
  "deprecated": false
@@ -170,7 +170,7 @@
170
170
  "code": "<DateTimeInput label=\"Input only\" popover={false} defaultValue={new Date()} />"
171
171
  }
172
172
  ],
173
- "accessibility": "- Trigger uses `role=\"combobox\"` with `aria-haspopup=\"dialog\"`, `aria-expanded`, and `aria-controls`.\n- Popover panel has `role=\"dialog\"` with an accessible name. Opening it puts focus on the focused date.\n- Closing the popover with `Escape`, the ✓ button or `Enter` on a time wheel returns focus to the input, whether the input or the launcher opened it. Under `openOnFocus` that returning focus leaves the popover closed; focusing or clicking the input again opens it. Closing it commits nothing by itself: an empty field stays empty, and leaving afterwards commits only what you typed, so seconds the display leaves out are kept.\n- Calendar uses `role=\"grid\"`; cells expose `aria-selected`, `aria-disabled`, and `aria-current=\"date\"`.\n- Roving `tabindex` keeps a single day focusable at a time, and focus moves with it, inline as in the popover. When the focused date is disabled, that cell is the nearest enabled day of the month.\n- Each time wheel uses `role=\"spinbutton\"` with `aria-valuemin`, `aria-valuemax`, `aria-valuenow`, and `aria-valuetext`. The values drawn above and below are click targets hidden from assistive technology, which reads the value from the spinbutton.\n- In a 12-hour picker, AM/PM is one of those wheels, reading `AM` or `PM`. Its accessible name is `AM/PM` unless `labels.ampm` sets another.\n- The footer's confirm button exposes an accessible label (`Done`); the Reset button reverts your edits to the value the popover opened with.\n- Tab order walks from the calendar to the footer (Reset / ✓), and from the time wheels to the footer while they are open.\n- On a right-to-left page the launcher sits at the end of the line and the calendar icon at the start. The time wheels keep `dir=\"ltr\"`.",
173
+ "accessibility": "- Trigger uses `role=\"combobox\"` with `aria-haspopup=\"dialog\"`, `aria-expanded`, and `aria-controls`.\n- Popover panel has `role=\"dialog\"` with an accessible name. Opening it puts focus on the focused date.\n- Closing the popover with `Escape`, the ✓ button or `Enter` on a time wheel returns focus to the input, whether the input or the launcher opened it. Under `openOnFocus` that returning focus leaves the popover closed; focusing or clicking the input again opens it. Closing it commits nothing by itself: an empty field stays empty, and leaving afterwards commits only what you typed, so seconds the display leaves out are kept.\n- Calendar uses `role=\"grid\"`; cells expose `aria-selected`, `aria-disabled`, and `aria-current=\"date\"` for today. On a server-rendered page, today gets it once the page hydrates, so the reader's clock decides which day.\n- Roving `tabindex` keeps a single day focusable at a time, and focus moves with it, inline as in the popover. When the focused date is disabled, that cell is the nearest enabled day of the month.\n- Each time wheel uses `role=\"spinbutton\"` with `aria-valuemin`, `aria-valuemax`, `aria-valuenow`, and `aria-valuetext`. The values drawn above and below are click targets hidden from assistive technology, which reads the value from the spinbutton.\n- In a 12-hour picker, AM/PM is one of those wheels, reading `AM` or `PM`. Its accessible name is `AM/PM` unless `labels.ampm` sets another.\n- The footer's confirm button exposes an accessible label (`Done`); the Reset button reverts your edits to the value the popover opened with.\n- Tab order walks from the calendar to the footer (Reset / ✓), and from the time wheels to the footer while they are open.\n- On a right-to-left page the launcher sits at the end of the line and the calendar icon at the start. The time wheels keep `dir=\"ltr\"`.",
174
174
  "related": ["DateInput", "Input", "TimeInput"],
175
175
  "storybook": "https://bestax.io/storybook/?path=/story/form-datetimeinput",
176
176
  "summary": "The `DateTimeInput` combines a calendar and a time **wheel spinner** in a single popover — an iOS-style layout.",
@@ -475,7 +475,7 @@
475
475
  "name": "inline",
476
476
  "type": "boolean",
477
477
  "default": "false",
478
- "description": "Render the panel inline (no popover).",
478
+ "description": "Render the panel inline (no popover). On a server-rendered page it marks today once the page hydrates, by the browser's clock rather than the server's. With no `value` or `defaultValue` it opens on the month the clock reads, and around the end of a month the server's clock and the browser's can read different months, so give it a date both render the same.",
479
479
  "required": false,
480
480
  "inherited": true,
481
481
  "deprecated": false
@@ -900,7 +900,7 @@
900
900
  "name": "inline",
901
901
  "type": "boolean",
902
902
  "default": "false",
903
- "description": "Render the panel inline (no popover).",
903
+ "description": "Render the panel inline (no popover). On a server-rendered page it marks today once the page hydrates, by the browser's clock rather than the server's. With no `value` or `defaultValue` it opens on the month the clock reads, and around the end of a month the server's clock and the browser's can read different months, so give it a date both render the same.",
904
904
  "required": false,
905
905
  "inherited": false,
906
906
  "deprecated": false
@@ -30,7 +30,7 @@
30
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=\"Portaled Dialog\"\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}"
31
31
  }
32
32
  ],
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). The underlying [`Modal`](https://bestax.io/docs/api/components/modal#accessibility) handles it, so one Escape closes the topmost overlay only: a dialog opened over a Modal or a [Sidebar](https://bestax.io/docs/api/components/sidebar) closes first, and the one under it on the next Escape\n- Tab and Shift+Tab cycle within the dialog while it is the topmost modal overlay, also from the underlying [`Modal`](https://bestax.io/docs/api/components/modal)\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",
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). The underlying [`Modal`](https://bestax.io/docs/api/components/modal#accessibility) handles it, so one Escape closes the topmost overlay only: a dialog opened over a Modal or a [Sidebar](https://bestax.io/docs/api/components/sidebar) closes first, and the one under it on the next Escape\n- Tab and Shift+Tab cycle within the dialog while it is the topmost modal overlay, also from the underlying [`Modal`](https://bestax.io/docs/api/components/modal)\n- The page doesn't scroll while the dialog is open, through the [`Modal`](https://bestax.io/docs/api/components/modal#accessibility)'s ref-counted lock, shared with `Sidebar` and `Loading`\n- Confirm/cancel buttons are keyboard accessible",
34
34
  "related": ["Modal", "Toast"],
35
35
  "storybook": "https://bestax.io/storybook/?path=/story/components-dialog",
36
36
  "summary": "The `Dialog` component provides ready-made confirm and alert dialogs, so a destructive action stays one `await dialog.confirm()` call away.",
@@ -119,7 +119,7 @@
119
119
  "name": "appendToBody",
120
120
  "type": "boolean",
121
121
  "default": "false",
122
- "description": "Render the card through `Portal`, into the `portalContainer` a `ConfigProvider` sets, `document.body` by default, 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 in the Tab order where its container is. At the end of `<body>`, the default, 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 reach it only when its container is inside that ancestor.",
122
+ "description": "Render the card through `Portal`, into the `portalContainer` a `ConfigProvider` sets, `document.body` by default, 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 in the Tab order where its container is. At the end of `<body>`, the default, 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. Theming variables set on an ancestor of the trigger reach it only when its container is inside that ancestor.",
123
123
  "required": false,
124
124
  "inherited": false,
125
125
  "deprecated": false
@@ -77,7 +77,7 @@
77
77
  "props": [
78
78
  {
79
79
  "name": "name",
80
- "type": "string | undefined",
80
+ "type": "string",
81
81
  "default": null,
82
82
  "description": "The icon name, with or without its library prefix (e.g. `'star'` or `'fa-star'`). Mutually exclusive with `children`.",
83
83
  "required": false,
@@ -140,7 +140,7 @@
140
140
  "props": [
141
141
  {
142
142
  "name": "name",
143
- "type": "string | undefined",
143
+ "type": "string",
144
144
  "default": null,
145
145
  "description": "The icon name, with or without its library prefix (e.g. `'star'` or `'fa-star'`). Mutually exclusive with `children`.",
146
146
  "required": false,
@@ -11,7 +11,7 @@
11
11
  },
12
12
  {
13
13
  "title": "Centered Level (Statistics)",
14
- "code": "<Level>\n <Level.Item hasTextCentered>\n <Block>\n <Paragraph\n textSize=\"7\"\n textTransform=\"uppercase\"\n textWeight=\"semibold\"\n mb=\"1\"\n >\n Posts\n </Paragraph>\n <Title as=\"p\">1,234</Title>\n </Block>\n </Level.Item>\n <Level.Item hasTextCentered>\n <Block>\n <Paragraph\n textSize=\"7\"\n textTransform=\"uppercase\"\n textWeight=\"semibold\"\n mb=\"1\"\n >\n Following\n </Paragraph>\n <Title as=\"p\">6789</Title>\n </Block>\n </Level.Item>\n <Level.Item hasTextCentered>\n <Block>\n <Paragraph\n textSize=\"7\"\n textTransform=\"uppercase\"\n textWeight=\"semibold\"\n mb=\"1\"\n >\n Followers\n </Paragraph>\n <Title as=\"p\">123K</Title>\n </Block>\n </Level.Item>\n <Level.Item hasTextCentered>\n <Block>\n <Paragraph\n textSize=\"7\"\n textTransform=\"uppercase\"\n textWeight=\"semibold\"\n mb=\"1\"\n >\n Likes\n </Paragraph>\n <Title as=\"p\">9876</Title>\n </Block>\n </Level.Item>\n</Level>"
14
+ "code": "<Level as=\"div\">\n <Level.Item hasTextCentered>\n <Block>\n <Paragraph\n textSize=\"7\"\n textTransform=\"uppercase\"\n textWeight=\"semibold\"\n mb=\"1\"\n >\n Posts\n </Paragraph>\n <Title as=\"p\">1,234</Title>\n </Block>\n </Level.Item>\n <Level.Item hasTextCentered>\n <Block>\n <Paragraph\n textSize=\"7\"\n textTransform=\"uppercase\"\n textWeight=\"semibold\"\n mb=\"1\"\n >\n Following\n </Paragraph>\n <Title as=\"p\">6,789</Title>\n </Block>\n </Level.Item>\n <Level.Item hasTextCentered>\n <Block>\n <Paragraph\n textSize=\"7\"\n textTransform=\"uppercase\"\n textWeight=\"semibold\"\n mb=\"1\"\n >\n Followers\n </Paragraph>\n <Title as=\"p\">123K</Title>\n </Block>\n </Level.Item>\n <Level.Item hasTextCentered>\n <Block>\n <Paragraph\n textSize=\"7\"\n textTransform=\"uppercase\"\n textWeight=\"semibold\"\n mb=\"1\"\n >\n Likes\n </Paragraph>\n <Title as=\"p\">9,876</Title>\n </Block>\n </Level.Item>\n</Level>"
15
15
  },
16
16
  {
17
17
  "title": "Centered Level Menu",
@@ -19,14 +19,14 @@
19
19
  },
20
20
  {
21
21
  "title": "Mobile Level",
22
- "code": "<Level isMobile>\n <Level.Item hasTextCentered>\n <Block>\n <Paragraph\n textSize=\"7\"\n textTransform=\"uppercase\"\n textWeight=\"semibold\"\n mb=\"1\"\n >\n Posts\n </Paragraph>\n <Title as=\"p\">1,234</Title>\n </Block>\n </Level.Item>\n <Level.Item hasTextCentered>\n <Block>\n <Paragraph\n textSize=\"7\"\n textTransform=\"uppercase\"\n textWeight=\"semibold\"\n mb=\"1\"\n >\n Following\n </Paragraph>\n <Title as=\"p\">4567</Title>\n </Block>\n </Level.Item>\n <Level.Item hasTextCentered>\n <Block>\n <Paragraph\n textSize=\"7\"\n textTransform=\"uppercase\"\n textWeight=\"semibold\"\n mb=\"1\"\n >\n Followers\n </Paragraph>\n <Title as=\"p\">123K</Title>\n </Block>\n </Level.Item>\n <Level.Item hasTextCentered>\n <Block>\n <Paragraph\n textSize=\"7\"\n textTransform=\"uppercase\"\n textWeight=\"semibold\"\n mb=\"1\"\n >\n Likes\n </Paragraph>\n <Title as=\"p\">9876</Title>\n </Block>\n </Level.Item>\n</Level>"
22
+ "code": "<Level as=\"div\" isMobile>\n <Level.Item hasTextCentered>\n <Block>\n <Paragraph\n textSize=\"7\"\n textTransform=\"uppercase\"\n textWeight=\"semibold\"\n mb=\"1\"\n >\n Posts\n </Paragraph>\n <Title as=\"p\">1,234</Title>\n </Block>\n </Level.Item>\n <Level.Item hasTextCentered>\n <Block>\n <Paragraph\n textSize=\"7\"\n textTransform=\"uppercase\"\n textWeight=\"semibold\"\n mb=\"1\"\n >\n Following\n </Paragraph>\n <Title as=\"p\">4,567</Title>\n </Block>\n </Level.Item>\n <Level.Item hasTextCentered>\n <Block>\n <Paragraph\n textSize=\"7\"\n textTransform=\"uppercase\"\n textWeight=\"semibold\"\n mb=\"1\"\n >\n Followers\n </Paragraph>\n <Title as=\"p\">123K</Title>\n </Block>\n </Level.Item>\n <Level.Item hasTextCentered>\n <Block>\n <Paragraph\n textSize=\"7\"\n textTransform=\"uppercase\"\n textWeight=\"semibold\"\n mb=\"1\"\n >\n Likes\n </Paragraph>\n <Title as=\"p\">9,876</Title>\n </Block>\n </Level.Item>\n</Level>"
23
23
  },
24
24
  {
25
25
  "title": "Compound (dot-notation) usage",
26
26
  "code": "<Level>\n <Level.Left>\n <Level.Item>\n <Title as=\"p\" size=\"5\">\n <strong>All Posts</strong>\n </Title>\n </Level.Item>\n </Level.Left>\n <Level.Right>\n <Level.Item as=\"p\">\n <a>Published</a>\n </Level.Item>\n <Level.Item as=\"p\">\n <Button color=\"success\" as=\"a\">\n New\n </Button>\n </Level.Item>\n </Level.Right>\n</Level>"
27
27
  }
28
28
  ],
29
- "accessibility": "- The root `Level` renders as a semantic `<nav>` for grouping and navigation.\n- Items can be rendered as `<div>`, `<p>`, or `<a>`. Use `as=\"a\"` for links, and provide clear text or accessible labels.\n- Use Bulma helper props for spacing and color to improve contrast and readability.\n\n:::note\nFor best accessibility, use semantic elements for headings/content within items, and ensure interactive elements (like `Button` or links) are focusable and labeled.\n:::",
29
+ "accessibility": "- `Level` renders a `<nav>` by default, as Bulma's markup does. A `nav` is a navigation landmark, which a screen reader user can list and jump to, so keep it for a row of links. A row that isn't navigation, such as the statistics above, takes `as=\"div\"`, which adds no landmark. `as=\"header\"` suits a level that opens a section and `as=\"footer\"` one that closes it.\n- Items can be rendered as `<div>`, `<p>`, or `<a>`. Use `as=\"a\"` for links, and provide clear text or accessible labels.\n- Use Bulma helper props for spacing and color to improve contrast and readability.\n\n:::note\nFor best accessibility, use semantic elements for headings/content within items, and ensure interactive elements (like `Button` or links) are focusable and labeled.\n:::",
30
30
  "related": ["Button", "Field", "Input", "Title", "useBulmaClasses"],
31
31
  "storybook": "https://bestax.io/storybook/?path=/story/layout-level--default",
32
32
  "summary": "The `Level` component provides a flexible horizontal layout for your Bulma React UI, perfect for aligning items on the left and right, distributing items evenly, or centering statistics and controls.",
@@ -39,6 +39,15 @@
39
39
  "summary": "The `Level` component provides a flexible horizontal layout for your Bulma React UI, perfect for aligning items on the left and right, distributing items evenly, or centering statistics and controls.",
40
40
  "component": null,
41
41
  "props": [
42
+ {
43
+ "name": "as",
44
+ "type": "'nav' | 'div' | 'header' | 'footer'",
45
+ "default": "'nav'",
46
+ "description": "HTML element to render (default: `nav`, as in Bulma's markup). A `nav` is a `navigation` landmark, so keep it for a row of links. A row that is not navigation, such as figures or a toolbar, takes `div`, which is no landmark. `header` suits a level that opens a section and `footer` one that closes it. A `header` is a `banner` landmark, and a `footer` a `contentinfo` one, only when no `section`, `article`, `aside`, `nav` or `main` is around it.",
47
+ "required": false,
48
+ "inherited": false,
49
+ "deprecated": false
50
+ },
42
51
  {
43
52
  "name": "isMobile",
44
53
  "type": "boolean",
@@ -46,7 +46,7 @@
46
46
  "code": "function example() {\n const [open, setOpen] = useState(false);\n const closeModal = () => setOpen(false);\n\n return (\n <>\n <Button color=\"success\" onClick={() => setOpen(true)}>\n Show Modal\n </Button>\n <Modal\n isActive={open}\n onClose={closeModal}\n aria-labelledby=\"custom-content-title\"\n >\n <Modal.Background onClick={closeModal} />\n <Modal.Content>\n <Box>\n <Title size=\"4\" id=\"custom-content-title\">\n Custom Content\n </Title>\n <Paragraph>Using compound components for full control!</Paragraph>\n </Box>\n </Modal.Content>\n <Modal.Close variant=\"floating\" />\n </Modal>\n </>\n );\n}"
47
47
  }
48
48
  ],
49
- "accessibility": "- The modal root gets `role=\"dialog\"` and `aria-modal=\"true\"` while active — pass an explicit `role` to override (e.g. `Dialog` passes `role=\"presentation\"` on the `Modal` it wraps so its own `role=\"alertdialog\"` is the only one announced).\n- **Give the dialog an accessible name.** With the legacy API, `modalCardTitle` is wired up as `aria-labelledby` for you. With the compound API, pass your own `aria-label` or `aria-labelledby` on `<Modal>` — a `role=\"dialog\"` with no name is announced as just \"dialog\". An explicit `aria-labelledby` always wins over the generated one.\n- Escape closes the modal (calls `onClose`) by default; opt out with `closeOnEscape={false}`. One Escape closes the topmost overlay only, whichever open Modal, [Dialog](https://bestax.io/docs/api/components/dialog), [Sidebar](https://bestax.io/docs/api/components/sidebar) or full-page [Loading](https://bestax.io/docs/api/components/loading) opened last, and the next Escape closes the one under it. A modal on top with `closeOnEscape={false}` still keeps Escape from the layers under it. A [Toast](https://bestax.io/docs/api/components/toast) waits until no overlay is open.\n- The modal calls `preventDefault()` on the Escape it closes on, so a listener of your own that runs after it can tell the key was used.\n- A popup inside the modal takes its own Escape first. With an Autocomplete list, a Dropdown menu, a Popover or a date picker's calendar open, the first Escape closes that and the next one closes the modal.\n- A popup of your own inside a modal should call `preventDefault()` on the Escape it closes on. The modal leaves an Escape that was prevented alone, whether your popup hears it in a React `onKeyDown` or in a listener on `document`. Call it only when the popup is open and the key was pressed in it, so an Escape with nothing to close still closes the modal, and so does one pressed in a modal opened over your popup.\n- Body scroll is locked while the modal is active; opt out with `lockScroll={false}`. The lock is ref-counted and shared with `Dialog`, `Sidebar` and `Loading`, so whichever overlay closes first doesn't unlock the page underneath one that is still open.\n- Focus moves to the first tab stop (or the modal itself) on open, and is restored to the previously focused element on close — unless another modal is still open on top, in which case that one keeps focus.\n- Tab and Shift+Tab cycle within the modal while it is the topmost modal overlay, so the keyboard order agrees with what `aria-modal=\"true\"` tells assistive technology. They wrap at the same tab stops [`useFocusTrap`](https://bestax.io/docs/api/helpers/usefocustrap) does, so disabled, hidden and `tabIndex={-1}` elements are skipped, and so is inert content, such as a closed [Sidebar](https://bestax.io/docs/api/components/sidebar) inside the modal, and the content of a closed `<details>`. A radio group counts once. A Tab from outside the modal brings focus back in, and so does a Tab the browser takes out anyway, as Safari does past links when its settings say to. With another Modal or Dialog, a [Sidebar](https://bestax.io/docs/api/components/sidebar) with an overlay or a full-page Loading opened over it, the modal leaves Tab alone until that one closes. A Sidebar without an overlay isn't modal: opened over the modal, it takes Escape first, but the modal keeps holding Tab and keeps focus, so the sidebar doesn't take focus when it opens, and a Tab from its controls comes back into the modal. A focus trap of your own inside it, such as a portaled panel's, keeps a Tab it calls `preventDefault()` on, and the modal leaves focus where your trap put it. Note that `aria-modal` does not by itself make background content inert, and no `inert` attribute is applied, so background content remains reachable by pointer and by browser UI such as find-in-page.\n- In the props form, the background closes the modal on click, and a close button is provided for both modal-card and modal-content variants (both call `onClose`, so pass it).\n- In the compound form, `Modal.Close` calls the modal's `onClose` unless you give it an `onClick` of your own, and `Modal.Background` closes the modal only when you pass it `onClick={onClose}`.\n\n:::note\nAlways provide an `onClose` handler for accessibility and to allow users to dismiss the modal.\n:::",
49
+ "accessibility": "- The modal root gets `role=\"dialog\"` and `aria-modal=\"true\"` while active — pass an explicit `role` to override (e.g. `Dialog` passes `role=\"presentation\"` on the `Modal` it wraps so its own `role=\"alertdialog\"` is the only one announced).\n- **Give the dialog an accessible name.** With the legacy API, `modalCardTitle` is wired up as `aria-labelledby` for you. With the compound API, pass your own `aria-label` or `aria-labelledby` on `<Modal>` — a `role=\"dialog\"` with no name is announced as just \"dialog\". An explicit `aria-labelledby` always wins over the generated one.\n- Escape closes the modal (calls `onClose`) by default; opt out with `closeOnEscape={false}`. One Escape closes the topmost overlay only, whichever open Modal, [Dialog](https://bestax.io/docs/api/components/dialog), [Sidebar](https://bestax.io/docs/api/components/sidebar) or full-page [Loading](https://bestax.io/docs/api/components/loading) opened last, and the next Escape closes the one under it. A modal on top with `closeOnEscape={false}` still keeps Escape from the layers under it. A [Toast](https://bestax.io/docs/api/components/toast) waits until no overlay is open.\n- The modal calls `preventDefault()` on the Escape it closes on, so a listener of your own that runs after it can tell the key was used.\n- A popup inside the modal takes its own Escape first. With an Autocomplete list, a Dropdown menu, a Popover or a date picker's calendar open, the first Escape closes that and the next one closes the modal.\n- A popup of your own inside a modal should call `preventDefault()` on the Escape it closes on. The modal leaves an Escape that was prevented alone, whether your popup hears it in a React `onKeyDown` or in a listener on `document`. Call it only when the popup is open and the key was pressed in it, so an Escape with nothing to close still closes the modal, and so does one pressed in a modal opened over your popup.\n- The page doesn't scroll under the modal while it's active; opt out with `lockScroll={false}`. The lock is ref-counted and shared with `Dialog`, `Sidebar` and `Loading`, so whichever overlay closes first doesn't unlock the page underneath one that is still open.\n- Focus moves to the first tab stop (or the modal itself) on open, and is restored to the previously focused element on close — unless another modal is still open on top, in which case that one keeps focus.\n- Tab and Shift+Tab cycle within the modal while it is the topmost modal overlay, so the keyboard order agrees with what `aria-modal=\"true\"` tells assistive technology. They wrap at the same tab stops [`useFocusTrap`](https://bestax.io/docs/api/helpers/usefocustrap) does, so disabled, hidden and `tabIndex={-1}` elements are skipped, and so is inert content, such as a closed [Sidebar](https://bestax.io/docs/api/components/sidebar) inside the modal, and the content of a closed `<details>`. A radio group counts once. A Tab from outside the modal brings focus back in, and so does a Tab the browser takes out anyway, as Safari does past links when its settings say to. With another Modal or Dialog, a [Sidebar](https://bestax.io/docs/api/components/sidebar) with an overlay or a full-page Loading opened over it, the modal leaves Tab alone until that one closes. A Sidebar without an overlay isn't modal: opened over the modal, it takes Escape first, but the modal keeps holding Tab and keeps focus, so the sidebar doesn't take focus when it opens, and a Tab from its controls comes back into the modal. A focus trap of your own inside it, such as a portaled panel's, keeps a Tab it calls `preventDefault()` on, and the modal leaves focus where your trap put it. Note that `aria-modal` does not by itself make background content inert, and no `inert` attribute is applied, so background content remains reachable by pointer and by browser UI such as find-in-page.\n- In the props form, the background closes the modal on click, and a close button is provided for both modal-card and modal-content variants (both call `onClose`, so pass it).\n- In the compound form, `Modal.Close` calls the modal's `onClose` unless you give it an `onClick` of your own, and `Modal.Background` closes the modal only when you pass it `onClick={onClose}`.\n\n:::note\nAlways provide an `onClose` handler for accessibility and to allow users to dismiss the modal.\n:::",
50
50
  "related": [
51
51
  "Button",
52
52
  "Dialog",
@@ -171,7 +171,7 @@
171
171
  "name": "lockScroll",
172
172
  "type": "boolean",
173
173
  "default": "true",
174
- "description": "Lock body scroll while the modal is active. Ref-counted and shared with `Dialog`, `Sidebar` and `Loading`, so whichever overlay closes first does not unlock the page underneath one that is still open.",
174
+ "description": "Lock page scroll while the modal is active, padding the page by the room its scrollbar took so the content stays put. An element fixed to the window's right edge, such as a `fixed` Navbar, isn't padded, and moves by the scrollbar's width while the page is locked. Ref-counted and shared with `Dialog`, `Sidebar` and `Loading`, so whichever overlay closes first does not unlock the page underneath one that is still open.",
175
175
  "required": false,
176
176
  "inherited": false,
177
177
  "deprecated": false
@@ -82,7 +82,7 @@
82
82
  "code": "<Navbar>\n <Navbar.Brand>\n <Navbar.Item href=\"#\">\n <img src=\"/img/logo.svg\" alt=\"Logo\" width=\"28\" height=\"28\" />\n </Navbar.Item>\n <Navbar.Burger aria-label=\"menu\" />\n </Navbar.Brand>\n <Navbar.Menu active>\n <Navbar.Start>\n <Navbar.Item href=\"#\">Home</Navbar.Item>\n <Navbar.Item href=\"#\">Docs</Navbar.Item>\n </Navbar.Start>\n <Navbar.End>\n <Navbar.Item href=\"#\">Log in</Navbar.Item>\n </Navbar.End>\n </Navbar.Menu>\n</Navbar>"
83
83
  }
84
84
  ],
85
- "accessibility": "- The root `Navbar` renders as `<nav role=\"navigation\" aria-label=\"main navigation\">`.\n The default accessible name is `main navigation`. A screen reader announces it with\n the role, and since the name holds the role word, \"navigation\" is heard twice.\n Pass a name without the role word (`aria-label=\"Site\"`), and a different name\n on each Navbar when a page has more than one. A passed `aria-label` replaces\n the default.\n- `Navbar.Item active` sets `aria-current=\"page\"` on the element `as` renders, the link by\n default, so the current item isn't only a color. An `aria-current` you pass wins: a navbar of\n sections on one page can say `\"location\"`, and `aria-current={false}` turns it off.\n- Use semantic links (`<a>`) and buttons, and provide clear `aria-label` and `aria-expanded` for the burger toggle.\n- `Navbar.Link` inside a `Navbar.Dropdown` automatically gets `aria-haspopup=\"true\"` and\n `aria-expanded` synced to the dropdown's open state — no manual wiring required.\n <kbd>Enter</kbd>/<kbd>Space</kbd> toggle the dropdown open/closed, and <kbd>Escape</kbd>\n closes it and keeps focus on the link. When the trigger isn't interactive on its own — no\n `href`, not `as=\"button\"`, and not a custom component — it also gets `role=\"button\"` and\n `tabIndex={0}` so it's reachable and operable by keyboard, and a mouse/touch click on it\n toggles the dropdown too (a caller-supplied `onClick` still runs, and can\n `preventDefault()` to opt out).\n- A custom component passed to `as` keeps its own semantics, because a router link takes `to`\n rather than `href` and so can't be recognised from the props it's given. If yours renders\n something non-interactive instead, pass `role=\"button\"` and it takes the fallback above —\n `tabIndex` and click included. The keyboard path is wired either way.\n- `hoverable` dropdowns keep working with a mouse (hover-to-open); the keyboard path above\n opens and closes them independently of hover.\n\n:::note\nThere's no arrow-key roving between navbar items and no outside-click handling for\n`Navbar.Dropdown` — Bulma navbar dropdowns are hover/click surfaces, so this is intentionally\nkept simple.\n:::",
85
+ "accessibility": "- The root `Navbar` renders as `<nav role=\"navigation\" aria-label=\"main navigation\">`.\n The default accessible name is `main navigation`. A screen reader announces it with\n the role, and since the name holds the role word, \"navigation\" is heard twice.\n Pass a name without the role word (`aria-label=\"Site\"`), and a different name\n on each Navbar when a page has more than one. A passed `aria-label` replaces\n the default.\n- `Navbar.Item active` sets `aria-current=\"page\"` on the element `as` renders, the link by\n default, so the current item isn't only a color. An `aria-current` you pass wins: a navbar of\n sections on one page can say `\"location\"`, and `aria-current={false}` turns it off.\n- Use semantic links (`<a>`) and buttons, and provide clear `aria-label` and `aria-expanded` for the burger toggle.\n- `Navbar.Link` inside a `Navbar.Dropdown` automatically gets `aria-haspopup=\"true\"` and\n `aria-expanded` synced to the dropdown's open state — no manual wiring required.\n <kbd>Enter</kbd>/<kbd>Space</kbd> toggle the dropdown open/closed, and <kbd>Escape</kbd>\n closes it and keeps focus on the link. When the trigger isn't interactive on its own — no\n `href`, not `as=\"button\"`, and not a custom component — it also gets `role=\"button\"` and\n `tabIndex={0}` so it's reachable and operable by keyboard, and a mouse/touch click on it\n toggles the dropdown too (a caller-supplied `onClick` still runs, and can\n `preventDefault()` to opt out).\n- A custom component passed to `as` keeps its own semantics, because a router link takes `to`\n rather than `href` and so can't be recognised from the props it's given. If yours renders\n something non-interactive instead, pass `role=\"button\"` and it takes the fallback above —\n `tabIndex` and click included. The keyboard path is wired either way.\n- `hoverable` dropdowns keep working with a mouse (hover-to-open); the keyboard path above\n opens and closes them independently of hover.\n- **Forced colors:** Bulma draws the burger's bars as a background color, which forced colors\n (Windows' contrast themes) replaces, so the burger would vanish there while it still works and\n takes focus. bestax's styles keep its bars visible in the system's button text color. That rule\n ships in `bestax.css` and `extras.css`, not in Bulma's own stylesheet, and an\n [`AppFrame`](https://bestax.io/docs/api/layout/appframe)'s burger gets it too.\n\n:::note\nThere's no arrow-key roving between navbar items and no outside-click handling for\n`Navbar.Dropdown` — Bulma navbar dropdowns are hover/click surfaces, so this is intentionally\nkept simple.\n:::",
86
86
  "related": ["Button", "Icon", "useBulmaClasses"],
87
87
  "storybook": "https://bestax.io/storybook/?path=/story/components-navbar--default",
88
88
  "summary": "The `Navbar` component implements Bulma's powerful, responsive navigation bar for your Bulma React UI.",
@@ -185,7 +185,7 @@
185
185
  "props": [
186
186
  {
187
187
  "name": "name",
188
- "type": "string | undefined",
188
+ "type": "string",
189
189
  "default": null,
190
190
  "description": "The icon name, with or without its library prefix (e.g. `'star'` or `'fa-star'`). Mutually exclusive with `children`.",
191
191
  "required": false,
@@ -118,7 +118,7 @@
118
118
  "name": "appendToBody",
119
119
  "type": "boolean",
120
120
  "default": "false",
121
- "description": "Render the panel through `Portal`, into the `portalContainer` a `ConfigProvider` sets, `document.body` by default, fixed to the viewport, so an ancestor's `overflow`, `transform` or stacking context can't clip it. The panel then shows from the commit after hydration, never in server markup. 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 reach it only when its container is inside that ancestor.",
121
+ "description": "Render the panel through `Portal`, into the `portalContainer` a `ConfigProvider` sets, `document.body` by default, fixed to the viewport, so an ancestor's `overflow`, `transform` or stacking context can't clip it. The panel then shows from the commit after hydration, never in server markup. Theming variables set on an ancestor of the trigger reach it only when its container is inside that ancestor.",
122
122
  "required": false,
123
123
  "inherited": false,
124
124
  "deprecated": false
@@ -142,7 +142,7 @@
142
142
  {
143
143
  "css": "--bulma-radio-dot-color",
144
144
  "sass": "$radio-dot-color",
145
- "default": "var(--bulma-scheme-main)",
145
+ "default": "var(--bulma-radio-active-color)",
146
146
  "scope": "root"
147
147
  },
148
148
  {
@@ -38,7 +38,7 @@
38
38
  "code": "function example() {\n const [isOpen, setIsOpen] = useState(false);\n return (\n <>\n <Button color=\"primary\" onClick={() => setIsOpen(true)}>\n Open Sidebar\n </Button>\n <Sidebar inline isOpen={isOpen} onClose={() => setIsOpen(false)}>\n <Sidebar.Header>\n <Sidebar.Title>Dot Notation</Sidebar.Title>\n <Sidebar.Close onClick={() => setIsOpen(false)} />\n </Sidebar.Header>\n <Sidebar.Body>\n <Paragraph>\n Header, Title, Close, Body, and Footer are all available from the\n single Sidebar import.\n </Paragraph>\n </Sidebar.Body>\n <Sidebar.Footer>\n <Button color=\"primary\" onClick={() => setIsOpen(false)}>\n Done\n </Button>\n </Sidebar.Footer>\n </Sidebar>\n </>\n );\n}"
39
39
  }
40
40
  ],
41
- "accessibility": "- Uses `role=\"dialog\"` for proper screen reader announcement\n- Has `aria-modal=\"true\"` when overlay is shown\n- Focus moves into the sidebar when it opens, to its first tab stop or the sidebar itself, unless it has no overlay and a modal overlay is open under it (see below). That's decided as it opens, so changing `overlay` while it's open leaves focus where it is. When it closes, focus goes back to whatever had it when the sidebar opened, unless focus has already left the sidebar, say for an overlay that's still open on top\n- With an overlay, Tab and Shift+Tab stay inside the sidebar while it's the topmost modal overlay, so the keyboard order agrees with what `aria-modal=\"true\"` tells assistive technology. They wrap at the same tab stops [`useFocusTrap`](https://bestax.io/docs/api/helpers/usefocustrap) does, so hidden, disabled and `tabIndex={-1}` elements are skipped and a radio group counts once. A Tab from outside the sidebar brings focus back in, and so does a Tab the browser takes out anyway, as Safari does past links when its settings say to\n- A [Modal](https://bestax.io/docs/api/components/modal) or [Dialog](https://bestax.io/docs/api/components/dialog) opened over the sidebar, including one rendered inside it, holds Tab until it closes, and then the sidebar holds it again. A sidebar with an overlay opened over a Modal holds Tab until it closes, and then the Modal does\n- A focus trap of your own inside the sidebar, such as a portaled panel's, keeps a Tab it calls `preventDefault()` on, and the sidebar leaves focus where your trap put it\n- Without an overlay the sidebar isn't modal and holds no Tab. On the page, Tab moves in and out of it freely. Opened over a Modal, or over a sidebar with an overlay, it takes Escape first, but the one under it keeps holding Tab and keeps focus: the sidebar doesn't take focus when it opens, and a Tab from its controls, once a click puts focus there, goes back into that one\n- A closed sidebar stays in the page so it can slide out, and it's `inert` and `aria-hidden` while closed: Tab passes over its content and assistive technology doesn't read it\n- Escape key closes the sidebar by default. One Escape closes the topmost overlay only: a [Modal](https://bestax.io/docs/api/components/modal) or [Dialog](https://bestax.io/docs/api/components/dialog) opened over the sidebar closes first, and the sidebar on the next Escape. A sidebar opened over a Modal closes before it\n- A sidebar on top that can't close on Escape, with `escapeClose` or `canCancel` off, still keeps the key from the overlays under it. A [Toast](https://bestax.io/docs/api/components/toast) waits until no overlay is open\n- A popup open inside it, such as a Dropdown menu or a date picker's calendar, takes the first Escape, and the next one closes the sidebar. A popup of your own does the same by calling `preventDefault()` on the Escape it closes on, as the [Modal](https://bestax.io/docs/api/components/modal#accessibility) page explains.\n- Body scroll is prevented when the sidebar is open with an overlay, through the ref-counted lock shared with `Modal`, `Dialog` and `Loading` — so closing one overlay never unlocks the page underneath another that is still open",
41
+ "accessibility": "- Uses `role=\"dialog\"` for proper screen reader announcement\n- Has `aria-modal=\"true\"` when overlay is shown\n- Focus moves into the sidebar when it opens, to its first tab stop or the sidebar itself, unless it has no overlay and a modal overlay is open under it (see below). That's decided as it opens, so changing `overlay` while it's open leaves focus where it is. When it closes, focus goes back to whatever had it when the sidebar opened, unless focus has already left the sidebar, say for an overlay that's still open on top\n- With an overlay, Tab and Shift+Tab stay inside the sidebar while it's the topmost modal overlay, so the keyboard order agrees with what `aria-modal=\"true\"` tells assistive technology. They wrap at the same tab stops [`useFocusTrap`](https://bestax.io/docs/api/helpers/usefocustrap) does, so hidden, disabled and `tabIndex={-1}` elements are skipped and a radio group counts once. A Tab from outside the sidebar brings focus back in, and so does a Tab the browser takes out anyway, as Safari does past links when its settings say to\n- A [Modal](https://bestax.io/docs/api/components/modal) or [Dialog](https://bestax.io/docs/api/components/dialog) opened over the sidebar, including one rendered inside it, holds Tab until it closes, and then the sidebar holds it again. A sidebar with an overlay opened over a Modal holds Tab until it closes, and then the Modal does\n- A focus trap of your own inside the sidebar, such as a portaled panel's, keeps a Tab it calls `preventDefault()` on, and the sidebar leaves focus where your trap put it\n- Without an overlay the sidebar isn't modal and holds no Tab. On the page, Tab moves in and out of it freely. Opened over a Modal, or over a sidebar with an overlay, it takes Escape first, but the one under it keeps holding Tab and keeps focus: the sidebar doesn't take focus when it opens, and a Tab from its controls, once a click puts focus there, goes back into that one\n- A closed sidebar stays in the page so it can slide out, and it's `inert` and `aria-hidden` while closed: Tab passes over its content and assistive technology doesn't read it\n- Escape key closes the sidebar by default. One Escape closes the topmost overlay only: a [Modal](https://bestax.io/docs/api/components/modal) or [Dialog](https://bestax.io/docs/api/components/dialog) opened over the sidebar closes first, and the sidebar on the next Escape. A sidebar opened over a Modal closes before it\n- A sidebar on top that can't close on Escape, with `escapeClose` or `canCancel` off, still keeps the key from the overlays under it. A [Toast](https://bestax.io/docs/api/components/toast) waits until no overlay is open\n- A popup open inside it, such as a Dropdown menu or a date picker's calendar, takes the first Escape, and the next one closes the sidebar. A popup of your own does the same by calling `preventDefault()` on the Escape it closes on, as the [Modal](https://bestax.io/docs/api/components/modal#accessibility) page explains.\n- The page doesn't scroll while the sidebar is open with an overlay, through the ref-counted lock shared with [`Modal`](https://bestax.io/docs/api/components/modal#accessibility), `Dialog` and `Loading`, so closing one overlay never unlocks the page underneath another that is still open",
42
42
  "related": ["Menu", "Modal"],
43
43
  "storybook": "https://bestax.io/storybook/?path=/story/components-sidebar",
44
44
  "summary": "The `Sidebar` component provides a slide-out navigation panel that appears from the left or right side of the screen.",
@@ -110,7 +110,7 @@
110
110
  "name": "overlay",
111
111
  "type": "boolean",
112
112
  "default": "true",
113
- "description": "Show an overlay behind the sidebar, which makes it modal: it gets `aria-modal=\"true\"`, locks body scroll, and keeps Tab and Shift+Tab inside it while it is the topmost modal overlay. A Modal or Dialog opened over it, even one rendered inside it, holds Tab until it closes. Without an overlay the sidebar isn't modal and holds no Tab: on the page, Tab moves in and out of it freely, and opened over a Modal, it leaves the Modal holding Tab, and focus, while still taking Escape first. Whether the sidebar takes focus is decided as it opens: changing this while it's open moves the Tab trap, not focus. Default: true.",
113
+ "description": "Show an overlay behind the sidebar, which makes it modal: it gets `aria-modal=\"true\"`, locks page scroll, and keeps Tab and Shift+Tab inside it while it is the topmost modal overlay. A Modal or Dialog opened over it, even one rendered inside it, holds Tab until it closes. Without an overlay the sidebar isn't modal and holds no Tab: on the page, Tab moves in and out of it freely, and opened over a Modal, it leaves the Modal holding Tab, and focus, while still taking Escape first. Whether the sidebar takes focus is decided as it opens: changing this while it's open moves the Tab trap, not focus. Default: true.",
114
114
  "required": false,
115
115
  "inherited": false,
116
116
  "deprecated": false
@@ -155,7 +155,7 @@
155
155
  "name": "inline",
156
156
  "type": "boolean",
157
157
  "default": "false",
158
- "description": "Renders inline instead of using a portal.",
158
+ "description": "Renders inline instead of using a portal. Without it, the sidebar renders inline on the server and while hydrating, moving into the portal once the client takes over, so hydration matches.",
159
159
  "required": false,
160
160
  "inherited": false,
161
161
  "deprecated": false
@@ -108,19 +108,19 @@
108
108
  "deprecated": false
109
109
  },
110
110
  {
111
- "name": "minDistance",
112
- "type": "number",
113
- "default": "0",
114
- "description": "Minimum distance between thumbs in range mode.",
111
+ "name": "ariaLabel",
112
+ "type": "string | [string, string]",
113
+ "default": null,
114
+ "description": "ARIA label(s) for the slider thumb(s), which win over a label, the Slider's own or a surrounding `Field`'s. In range mode each entry is that thumb's whole name, and a thumb without one is named \"Minimum value\" or \"Maximum value\", after whatever names the Slider: a label, or in its place an `aria-label` or `aria-labelledby` given to the Slider, as in \"Budget Minimum value\" and \"Budget Maximum value\". An `aria-labelledby` set to `undefined` keeps every label out of both names.",
115
115
  "required": false,
116
116
  "inherited": true,
117
117
  "deprecated": false
118
118
  },
119
119
  {
120
- "name": "ariaLabel",
121
- "type": "string | [string, string]",
122
- "default": null,
123
- "description": "ARIA label(s) for the slider thumb(s), which win over a label, the Slider's own or a surrounding `Field`'s. In range mode each entry is that thumb's whole name, and a thumb without one is named \"Minimum value\" or \"Maximum value\", after whatever names the Slider: a label, or in its place an `aria-label` or `aria-labelledby` given to the Slider, as in \"Budget Minimum value\" and \"Budget Maximum value\". An `aria-labelledby` set to `undefined` keeps every label out of both names.",
120
+ "name": "minDistance",
121
+ "type": "number",
122
+ "default": "0",
123
+ "description": "Minimum distance between thumbs in range mode.",
124
124
  "required": false,
125
125
  "inherited": true,
126
126
  "deprecated": false
@@ -195,7 +195,7 @@
195
195
  "name": "inline",
196
196
  "type": "boolean",
197
197
  "default": "false",
198
- "description": "Renders inline instead of using a portal. Through `toast.show()`, a toast already renders inline in `ToastContainer`'s stack for its position, and `inline` keeps one with a `container` in that stack too.",
198
+ "description": "Renders inline instead of using a portal. Without it, a toast renders inline on the server and while hydrating, moving into the portal once the client takes over, so hydration matches. Through `toast.show()`, a toast already renders inline in `ToastContainer`'s stack for its position, and `inline` keeps one with a `container` in that stack too.",
199
199
  "required": false,
200
200
  "inherited": false,
201
201
  "deprecated": false
@@ -122,7 +122,8 @@ Dialog also shows optional patterns you can borrow when relevant:
122
122
  - An **imperative API** (`dialog.alert`, `dialog.confirm`, `dialog.close`) plus a
123
123
  `DialogContainer` for programmatic mounting, exported from the same module.
124
124
  - **Accessibility**: `role="alertdialog"`, Escape-to-cancel, and focus management on open.
125
- - **Body scroll lock** via a module-level ref count so chained/overlapping dialogs behave.
125
+ - **Page scroll lock** through the `Modal` it renders, whose lock is ref-counted so
126
+ chained/overlapping dialogs behave.
126
127
 
127
128
  These are not required for every component — start from the simple template in
128
129
  `library-contributor.md` and add only what your component needs.
@@ -212,7 +212,9 @@ does a picker given its own `dayNames`, which it shows exactly as given: pass `f
212
212
  them and list them from that day. With
213
213
  server rendering, set a locale: without one, an `inline` calendar names its days in the server's
214
214
  language on the server and the reader's in the browser, and hydration fails to match whenever
215
- the two languages differ.
215
+ the two languages differ. Give an `inline` picker a `value` or `defaultValue` there too: without
216
+ one it opens on the month the clock reads, and the server's clock and the reader's can read
217
+ different months.
216
218
 
217
219
  ```tsx
218
220
  <LocaleProvider locale="de">
@@ -128,11 +128,16 @@ back to. A header taller than Bulma's navbar sets
128
128
  `<Level>` is a horizontal toolbar (left/right groups). Subcomponents: `Level.Left`, `Level.Right`,
129
129
  `Level.Item`.
130
130
 
131
- | Prop | Type |
132
- | ---------------------------- | ------------------------------------- |
133
- | `Level.isMobile` | `boolean` (keep horizontal on mobile) |
134
- | `Level.Item.as` | `'div' \| 'p' \| 'a'` |
135
- | `Level.Item.hasTextCentered` | `boolean` |
131
+ | Prop | Type |
132
+ | ---------------------------- | -------------------------------------------------------- |
133
+ | `Level.as` | `'nav'` (default) \| `'div'` \| `'header'` \| `'footer'` |
134
+ | `Level.isMobile` | `boolean` (keep horizontal on mobile) |
135
+ | `Level.Item.as` | `'div' \| 'p' \| 'a'` |
136
+ | `Level.Item.hasTextCentered` | `boolean` |
137
+
138
+ A `nav` is a navigation landmark, so keep the default for a row of links. A row that isn't
139
+ navigation takes `as="div"`, or `as="header"` when it opens a section and `as="footer"` when it
140
+ closes one. A dashboard's row of key figures is `Stats`, not a `Level`.
136
141
 
137
142
  ## Stack / Group / Center / Flex
138
143
 
@@ -118,7 +118,7 @@ bloomer put `tag` on nearly every component; bestax declares `as` on a subset, s
118
118
  narrowed to a literal union, so a value outside the union is a type error you can see rather
119
119
  than a silent rewrite. The components whose `tag` becomes `as`:
120
120
 
121
- `Button`, `Image`, `Title`, `Subtitle`, `Footer`, `Media`, `MediaLeft`, `LevelItem`, `Control`,
121
+ `Button`, `Image`, `Title`, `Subtitle`, `Footer`, `Media`, `MediaLeft`, `Level`, `LevelItem`, `Control`,
122
122
  `DropdownItem`, `MenuLink`, `NavbarItem`, `NavbarLink`, `Container`, `Hero`, `HeroHeader`,
123
123
  `HeroFooter`, `Panel`.
124
124
 
@@ -60,7 +60,7 @@ a `tag:<Target>` TODO instead of a conversion. A component's own `as` can take m
60
60
  | `.hero-head` | `Hero.Head` | `<div>`, `<header>`, `<nav>` via `as` |
61
61
  | `.hero-body` | `Hero.Body` | `<div>` only |
62
62
  | `.hero-foot` | `Hero.Foot` | `<div>`, `<footer>`, `<nav>` via `as` |
63
- | `.level` | `Level` | `<nav>` only |
63
+ | `.level` | `Level` | `<nav>`, `<div>`, `<header>`, `<footer>` via `as` |
64
64
  | `.level-left` | `Level.Left` | `<div>` only |
65
65
  | `.level-right` | `Level.Right` | `<div>` only |
66
66
  | `.level-item` | `Level.Item` | `<div>`, `<p>`, `<a>` via `as` |
@@ -96,6 +96,7 @@ everywhere else:
96
96
  | `Footer` | `'footer' \| 'div'` |
97
97
  | `Media` | `'article' \| 'div'` |
98
98
  | `Media.Left` | `'figure' \| 'div'` |
99
+ | `Level` | `'nav' \| 'div' \| 'header' \| 'footer'` |
99
100
  | `Level.Item` | `'div' \| 'p' \| 'a'` |
100
101
  | `Control` | `'div' \| 'p'` |
101
102
  | `Menu.Item` | any element type |
@@ -32,7 +32,7 @@ this automatically for literal values; dynamic values get TODOs.
32
32
  ## `renderAs` → `as`, and the props that follow it
33
33
 
34
34
  `renderAs` becomes `as` on the components bestax declares one on: `Button`, `Title` and
35
- `SubTitle` (from `Heading`), `Image`, `Form.Control`, `Footer`, `Level.Item`, `Media` and its
35
+ `SubTitle` (from `Heading`), `Image`, `Form.Control`, `Footer`, `Level`, `Level.Item`, `Media` and its
36
36
  `Item`s, `Menu.Item`, `Navbar.Item`, `Navbar.Link`, `Dropdown.Item`, `Container`, `Hero`,
37
37
  `Hero.Header`, `Hero.Footer`, `Panel` and `Panel.Block`. Everywhere else it is flagged.
38
38
 
@@ -104,7 +104,7 @@ Create `src/styles.scss` — base + themes always come first:
104
104
 
105
105
  // One line per stock Bulma component the app imports…
106
106
  @use 'bulma/sass/elements/button';
107
- @use 'bulma/sass/components/navbar';
107
+ @use 'bulma/sass/components/card';
108
108
  // …and per bestax extras component:
109
109
  @use '@allxsmith/bestax-bulma/scss/components/dialog';
110
110
  // …and bestax's partial for a stock component that has one:
@@ -46,7 +46,7 @@ publishes its SCSS sources (`src/scss` ships in the npm package, exposed via the
46
46
 
47
47
  **Rule:** stock Bulma components map to `bulma/sass/<category>/<lowercased-name>`; bestax
48
48
  extras map to `@allxsmith/bestax-bulma/scss/<category>/<lowercased-name>`. Components that
49
- are pure stock Bulma (Box, Card, Navbar, Modal, Hero, …) have **no** extras partial —
49
+ are pure stock Bulma (Box, Card, Modal, Hero, …) have **no** extras partial —
50
50
  Bulma's own module is all they need.
51
51
 
52
52
  Bulma groups its form controls, so their modules don't follow the name: `Input` and `TextArea`
@@ -82,7 +82,7 @@ is **more complete** than the docs page's Option C example, which omits several)
82
82
  `loading`, `collapse`, `tooltip`, `popover`, `hovercard`, `contextmenu`, `steps`, `sidebar`,
83
83
  `toast`, `dialog`, `carousel`, `lightbox`, `tabs`, `menu`, `tableofcontents`, `reveal`, `avatar`, `avatars`,
84
84
  `badge`, `emptystate`, `timeline`, `treeview`, `scrollarea`, `command`, `datatable`,
85
- `pagination`, `affix`
85
+ `pagination`, `affix`, `navbar`
86
86
 
87
87
  **Layout** (`@allxsmith/bestax-bulma/scss/layout/<name>`): `appframe`, `splitter`, `stack`
88
88
 
@@ -135,6 +135,16 @@ Notes:
135
135
  @use '@allxsmith/bestax-bulma/scss/components/pagination' as bestax-pagination;
136
136
  ```
137
137
 
138
+ - The `navbar` partial **extends** stock Bulma navbar (it keeps the burger's bars in
139
+ ButtonText in forced colors, where Chromium paints them in the page's Canvas color), so an
140
+ app using `Navbar` needs both, in either order. `AppFrame.Burger` renders `Navbar.Burger`,
141
+ so a build with one wants this partial too:
142
+
143
+ ```scss
144
+ @use 'bulma/sass/components/navbar';
145
+ @use '@allxsmith/bestax-bulma/scss/components/navbar' as bestax-navbar;
146
+ ```
147
+
138
148
  - The `file` partial **extends** stock Bulma file (File's keyboard focus ring, and the rounded
139
149
  corners of a boxed `hasName` File with no name to show), so an app using `File` needs both, in
140
150
  either order:
@@ -213,12 +223,15 @@ Notes:
213
223
  so its text clears the button, so include it (`as bestax-notification`) next to the Bulma
214
224
  module in any build that shows a dismissible notification. It doesn't depend on the order of
215
225
  the two `@use` lines either.
216
- - `Delete` is stock Bulma too (`bulma/sass/elements/delete`), and it's the close button of
217
- `Notification`, `Message`, `Toast`, a `Modal` card, `AppFrame`'s drawer and the tags of
218
- `Taginput`, `Combobox` and `Dropzone`. Bulma draws its circle and cross as background colors, which forced colors
219
- (Windows' contrast themes) replaces, so they vanish there. The `delete` extras partial keeps
220
- them drawn in the system's button colors, and the `Modal`'s floating close
221
- (`bulma/sass/components/modal`) and `Tag isDelete` (`bulma/sass/elements/tag`) with them, so
226
+ - `Delete` is stock Bulma too, and it's the close button of `Notification`, `Message`, `Toast`, a
227
+ `Modal` card, `AppFrame`'s drawer and the tags of `Taginput`, `Combobox`, `Dropzone` and
228
+ `TreeSelect`. Bulma draws it in `bulma/sass/elements/delete`, and the modules of the components
229
+ it sits in don't, so a build that shows one needs that module next to theirs. Without it the
230
+ button doesn't show, though it still takes keyboard focus. The `Modal`'s floating close is the
231
+ exception, since `bulma/sass/components/modal` draws that one itself. Bulma draws the circle and
232
+ cross as background colors, which forced colors (Windows' contrast themes) replaces, so they
233
+ vanish there. The `delete` extras partial keeps them drawn in the system's button colors, and
234
+ the `Modal`'s floating close and `Tag isDelete` (`bulma/sass/elements/tag`) with them, so
222
235
  include it (`as bestax-delete`) in any build that shows a close button. Its rules win over
223
236
  Bulma's either way, so the order of the `@use` lines does not matter.
224
237
  - `Button` is stock Bulma too (`bulma/sass/elements/button`). Bulma shows a focused button with
@@ -245,9 +258,9 @@ Notes:
245
258
 
246
259
  - Stock-Bulma form controls still need their Bulma module (`bulma/sass/form/…`); the extras
247
260
  form partials above style only the bestax-specific behavior.
248
- - Bulma component modules pull their own internal sub-elements — e.g.
249
- `elements/notification` styles its `delete` close button itself (verified). No extra
250
- `@use` lines are needed for pieces rendered _inside_ a component you've already included.
261
+ - Bulma's module for a component doesn't always style what bestax renders inside it. A close
262
+ button is the common case: it needs `bulma/sass/elements/delete` and the `delete` partial, as
263
+ the `Delete` note above says.
251
264
 
252
265
  ## Bulma helper categories
253
266
 
@@ -820,7 +820,8 @@ As with Checkbox, set these on a class you pass through `className`, with both c
820
820
  selector (`.styled-radio.my-radio`): `style` goes to the hidden `<input>`. A `color` prop
821
821
  declares `--bulma-radio-active-color` again on `.styled-radio.is-<color>`, which ties that
822
822
  selector, so leave `color` unset when a class sets it. The unchecked ring, `--bulma-radio-border-color`, defaults to `text-weak` for the same 3:1 boundary
823
- contrast.
823
+ contrast. The checked dot, `--bulma-radio-dot-color`, defaults to `--bulma-radio-active-color`,
824
+ so it follows the ring and a `color` prop until a class gives it a color of its own.
824
825
 
825
826
  `--bulma-radio-size` (default `1.25em`) can't take the circle below 24px: the stylesheet gives the
826
827
  `.check` circle a `min-width` and `min-height` of 24px, WCAG 2.2's minimum target size, so with
package/data/skills.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "file": "references/library-contributor.md",
18
18
  "bytes": 23311
19
19
  },
20
- { "id": "patterns", "file": "references/patterns.md", "bytes": 4601 }
20
+ { "id": "patterns", "file": "references/patterns.md", "bytes": 4632 }
21
21
  ],
22
22
  "examples": [
23
23
  { "id": "stat-card", "file": "examples/stat-card.tsx", "bytes": 3734 }
@@ -29,7 +29,7 @@
29
29
  "promptName": "form",
30
30
  "dir": "bestax-form",
31
31
  "references": [
32
- { "id": "api", "file": "references/api.md", "bytes": 32997 },
32
+ { "id": "api", "file": "references/api.md", "bytes": 33178 },
33
33
  { "id": "patterns", "file": "references/patterns.md", "bytes": 10001 }
34
34
  ],
35
35
  "examples": []
@@ -64,7 +64,7 @@
64
64
  {
65
65
  "id": "layout-components",
66
66
  "file": "references/layout-components.md",
67
- "bytes": 25314
67
+ "bytes": 25761
68
68
  }
69
69
  ],
70
70
  "examples": [
@@ -93,7 +93,7 @@
93
93
  {
94
94
  "id": "bloomer-prop-map",
95
95
  "file": "references/bloomer/prop-map.md",
96
- "bytes": 27249
96
+ "bytes": 27258
97
97
  },
98
98
  {
99
99
  "id": "bloomer-unmappables",
@@ -128,7 +128,7 @@
128
128
  {
129
129
  "id": "rbx-prop-map",
130
130
  "file": "references/rbx/prop-map.md",
131
- "bytes": 16090
131
+ "bytes": 16213
132
132
  },
133
133
  {
134
134
  "id": "rbx-unmappables",
@@ -143,7 +143,7 @@
143
143
  {
144
144
  "id": "react-bulma-components-prop-map",
145
145
  "file": "references/react-bulma-components/prop-map.md",
146
- "bytes": 8367
146
+ "bytes": 8376
147
147
  },
148
148
  {
149
149
  "id": "react-bulma-components-unmappables",
@@ -162,7 +162,7 @@
162
162
  {
163
163
  "id": "modular-build",
164
164
  "file": "references/modular-build.md",
165
- "bytes": 18954
165
+ "bytes": 19671
166
166
  }
167
167
  ],
168
168
  "examples": []
@@ -176,7 +176,7 @@
176
176
  {
177
177
  "id": "css-variables",
178
178
  "file": "references/css-variables.md",
179
- "bytes": 71903
179
+ "bytes": 72074
180
180
  },
181
181
  {
182
182
  "id": "themeable-components",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bestax-mcp",
3
- "version": "1.18.35",
3
+ "version": "1.18.37",
4
4
  "mcpName": "io.github.allxsmith/bestax-mcp",
5
5
  "description": "MCP server for @allxsmith/bestax-bulma — component props, examples, CSS variables and agent skills, served offline from a version-pinned index",
6
6
  "type": "module",
@@ -42,7 +42,7 @@
42
42
  "dependencies": {
43
43
  "@modelcontextprotocol/sdk": "^1.32.2",
44
44
  "zod": "^4.6.7",
45
- "@allxsmith/bestax-bulma": "^5.66.1"
45
+ "@allxsmith/bestax-bulma": "^5.67.0"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@types/node": "^26.6.6",