bestax-mcp 1.15.3 → 1.15.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.
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.34.0"
5
+ "version": "5.34.1"
6
6
  },
7
7
  "docsBase": "https://bestax.io/docs",
8
8
  "categories": [
@@ -86,7 +86,7 @@
86
86
  "code": "<Field horizontal>\n <Field.Label size=\"normal\">\n <label className=\"label\" htmlFor=\"compound-name\">\n Name\n </label>\n </Field.Label>\n <Field.Body>\n <Field.Control>\n <Input id=\"compound-name\" placeholder=\"Jane Doe\" />\n </Field.Control>\n </Field.Body>\n</Field>"
87
87
  }
88
88
  ],
89
- "accessibility": "- For a single control, prefer the control's own `label` prop, with `horizontal` for a side-by-side row. It renders this `Field` and its label and wires the `for` itself, to your `id` when you pass one: `<Input label=\"Email\" id=\"email\" horizontal />`.\n- The `label` prop names the one control the Field holds. A composed `InputBase`, `SelectBase`, `TextAreaBase`, `DateInputBase`, `TimeInputBase`, or `DateTimeInputBase`, or a bestax input that renders a single input of its own (`Input`, `Select`, `TextArea`, `Numberinput`, `Slider`, `DateInput`, `TimeInput`, `DateTimeInput`, `Autocomplete`, `Taginput`, `File`), adopts a generated id the label's `for` points at, so clicking the label focuses the control and assistive technology announces it. An `inline` picker renders no input, so it takes nothing.\n- A control with an `id` of its own keeps it and never takes the generated one, so `<Field label=\"Email\"><Input id=\"email\" /></Field>` renders a label that names nothing. Leave the `id` off, or pass the same value as `labelProps={{ htmlFor: 'email' }}`. Pass `labelProps={{ htmlFor: undefined }}` to opt out of the association entirely.\n- A range `Slider` takes that id on its low thumb, and its thumbs also point `aria-labelledby` at the label (at `labelProps.id` when you set one), so under a label of \"Price range\" they announce as \"Price range Minimum value\" and \"Price range Maximum value\". An `ariaLabel` entry names its thumb instead, and an `aria-label` or `aria-labelledby` on the Slider takes the label's place in both names. A label you wire by hand with `labelProps={{ htmlFor }}` gets no generated id, so it reaches the thumbs' names only when you give it an `id` there too, as in `labelProps={{ htmlFor: 'price', id: 'price-label' }}`.\n- An `Autocomplete` points its open suggestion list's `aria-labelledby` at the label the same way, so under a label of \"Country\" the list announces as \"Country\" rather than its fallback name, \"Suggestions\". A label you wire by hand needs an `id` in `labelProps` for this too, as in `labelProps={{ htmlFor: 'country', id: 'country-label' }}`.\n- A group (`Radios`, `Checkboxes`, `Rate`, `DateRangeInput`, or a composed `DateRangeInputBase`, `inline` or not) can't take a `for`, so the label gets an id (yours from `labelProps.id`, otherwise a generated one) and the group points `aria-labelledby` at it. An `aria-label` or `aria-labelledby` you set on the group wins over the Field's label, as it does over a group's own `label`.\n- Association is skipped for `grouped`/`hasAddons` fields (they hold several controls), and a `Field` nested inside a labeled one starts its own scope. A horizontal Field wraps its children in a `Field.Body` of its own and keeps the association, but the pattern with an inner `Field` in that body needs it wired by hand. A label you wire by hand names the control its `for` points at in a `grouped` or `hasAddons` field too, and with an `id` in `labelProps` it names a range `Slider`'s thumbs and an `Autocomplete`'s list there as well. No group points at it on its own.\n- Two controls in one plain labeled Field would both adopt its id. Give each an `id` of its own and label it individually.\n- Once a labeled Field's content has mounted, its label keeps the generated `for` only while one of the inputs above holds the id, and drops it over anything else: a group, a `Checkbox`, `Radio` or `Switch`, an `inline` picker, an inner `Field`, an input with an `id` of its own, markup of your own, or nothing at all. A server render, and the first render while hydrating, still write the `for`, so hydration matches, and an input that mounts later puts it back. A `for` you set with `labelProps={{ htmlFor }}` always stays. `Checkbox`, `Radio` and `Switch` take nothing from the label on their own: each is named by its own children, so put the text there, and the label names one only when you wire it as you would any control with an `id` of its own, `labelProps={{ htmlFor }}` plus that control's `id`. Where you point content at the label by hand, as with a group in an inner `Field`, `labelProps={{ id }}` is enough in the browser, and `labelProps={{ id, htmlFor: undefined }}` keeps the `for` out of server-rendered HTML too.\n- Grouped/horizontal layouts use Bulma’s grid for layout.",
89
+ "accessibility": "- For a single control, prefer the control's own `label` prop, with `horizontal` for a side-by-side row. It renders this `Field` and its label and wires the `for` itself, to your `id` when you pass one: `<Input label=\"Email\" id=\"email\" horizontal />`.\n- The `label` prop names the one control the Field holds. A composed `InputBase`, `SelectBase`, `TextAreaBase`, `DateInputBase`, `TimeInputBase`, or `DateTimeInputBase`, or a bestax input that renders a single input of its own (`Input`, `Select`, `TextArea`, `Numberinput`, `Slider`, `DateInput`, `TimeInput`, `DateTimeInput`, `Autocomplete`, `Taginput`, `File`), adopts a generated id the label's `for` points at, so clicking the label focuses the control and assistive technology announces it. An `inline` picker renders no input, so it takes nothing.\n- A control with an `id` of its own keeps it and never takes the generated one, so `<Field label=\"Email\"><Input id=\"email\" /></Field>` renders a label that names nothing. Leave the `id` off, or pass the same value as `labelProps={{ htmlFor: 'email' }}`. Pass `labelProps={{ htmlFor: undefined }}` to opt out of the association entirely.\n- A range `Slider` takes that id on its low thumb, and its thumbs also point `aria-labelledby` at the label (at `labelProps.id` when you set one), so under a label of \"Price range\" they announce as \"Price range Minimum value\" and \"Price range Maximum value\". An `ariaLabel` entry names its thumb instead, and an `aria-label` or `aria-labelledby` on the Slider takes the label's place in both names. A label you wire by hand with `labelProps={{ htmlFor }}` gets no generated id, so it reaches the thumbs' names only when you give it an `id` there too, as in `labelProps={{ htmlFor: 'price', id: 'price-label' }}`.\n- An `Autocomplete` or a `Taginput` points its open suggestion list's `aria-labelledby` at the label the same way, so under a label of \"Country\" the list announces as \"Country\" rather than its fallback name, \"Suggestions\". A label you wire by hand needs an `id` in `labelProps` for this too, as in `labelProps={{ htmlFor: 'country', id: 'country-label' }}`.\n- A group (`Radios`, `Checkboxes`, `Rate`, `DateRangeInput`, or a composed `DateRangeInputBase`, `inline` or not) can't take a `for`, so the label gets an id (yours from `labelProps.id`, otherwise a generated one) and the group points `aria-labelledby` at it. An `aria-label` or `aria-labelledby` you set on the group wins over the Field's label, as it does over a group's own `label`.\n- Association is skipped for `grouped`/`hasAddons` fields (they hold several controls), and a `Field` nested inside a labeled one starts its own scope. A horizontal Field wraps its children in a `Field.Body` of its own and keeps the association, but the pattern with an inner `Field` in that body needs it wired by hand. A label you wire by hand names the control its `for` points at in a `grouped` or `hasAddons` field too, and with an `id` in `labelProps` it names a range `Slider`'s thumbs and an `Autocomplete`'s or `Taginput`'s list there as well. No group points at it on its own.\n- Two controls in one plain labeled Field would both adopt its id. Give each an `id` of its own and label it individually.\n- Once a labeled Field's content has mounted, its label keeps the generated `for` only while one of the inputs above holds the id, and drops it over anything else: a group, a `Checkbox`, `Radio` or `Switch`, an `inline` picker, an inner `Field`, an input with an `id` of its own, markup of your own, or nothing at all. A server render, and the first render while hydrating, still write the `for`, so hydration matches, and an input that mounts later puts it back. A `for` you set with `labelProps={{ htmlFor }}` always stays. `Checkbox`, `Radio` and `Switch` take nothing from the label on their own: each is named by its own children, so put the text there, and the label names one only when you wire it as you would any control with an `id` of its own, `labelProps={{ htmlFor }}` plus that control's `id`. Where you point content at the label by hand, as with a group in an inner `Field`, `labelProps={{ id }}` is enough in the browser, and `labelProps={{ id, htmlFor: undefined }}` keeps the `for` out of server-rendered HTML too.\n- Grouped/horizontal layouts use Bulma’s grid for layout.",
90
90
  "related": [
91
91
  "Checkbox",
92
92
  "Checkboxes",
@@ -149,7 +149,7 @@
149
149
  "name": "label",
150
150
  "type": "React.ReactNode",
151
151
  "default": null,
152
- "description": "Field label, rendered above the widget. Automatically names the one control the Field holds: a composed `InputBase`, `SelectBase`, `TextAreaBase`, `DateInputBase`, `TimeInputBase` or `DateTimeInputBase` (an `inline` picker has no input, so it takes nothing), or a bestax input that renders a single input of its own (`Input`, `Select`, `TextArea`, `Numberinput`, `Slider`, `DateInput`, `TimeInput`, `DateTimeInput`, `Autocomplete`, `Taginput`, `File`), adopts a generated id that the label's `htmlFor` points at, and a group (`Radios`, `Checkboxes`, `Rate`, `DateRangeInput`, or a composed `DateRangeInputBase`, `inline` or not) points `aria-labelledby` at the label's own id unless you gave the group an `aria-label` or `aria-labelledby`. A range `Slider` takes the id on its low thumb and also starts each thumb's name with the label through `aria-labelledby`, unless its `ariaLabel` names that thumb or its own `aria-label` or `aria-labelledby` takes the label's place. An `Autocomplete` also names its open suggestion list after the label through `aria-labelledby`. Nothing else takes the label: `Checkbox`, `Radio` and `Switch` are named by their own children, and the label names one only when you wire it as you would any control with an `id` of its own, `labelProps={{ htmlFor }}` plus that control's `id`. Only the single inputs take the `htmlFor`, so once the Field's content has mounted the label keeps it only while one of them holds the id, and drops it over anything else: a group, a `Checkbox`, `Radio` or `Switch`, an `inline` picker, an inner `Field`, an input with an `id` of its own, markup of your own, or nothing at all. A server render, and the first render while hydrating, still write the `htmlFor`, which keeps hydration matching, and an input that mounts later puts it back. The label names an input with an `id` of your own only through `labelProps={{ htmlFor }}` set to that `id`, a `for` it always keeps; `labelProps={{ htmlFor: undefined }}` opts out. Skipped for `grouped`/`hasAddons` fields (multiple controls), and a nested `Field` starts its own scope, so a horizontal Field whose body holds an inner `Field` names the control there only when you wire it. Two controls in one plain labeled Field would both adopt the id, so give each an `id` of its own.",
152
+ "description": "Field label, rendered above the widget. Automatically names the one control the Field holds: a composed `InputBase`, `SelectBase`, `TextAreaBase`, `DateInputBase`, `TimeInputBase` or `DateTimeInputBase` (an `inline` picker has no input, so it takes nothing), or a bestax input that renders a single input of its own (`Input`, `Select`, `TextArea`, `Numberinput`, `Slider`, `DateInput`, `TimeInput`, `DateTimeInput`, `Autocomplete`, `Taginput`, `File`), adopts a generated id that the label's `htmlFor` points at, and a group (`Radios`, `Checkboxes`, `Rate`, `DateRangeInput`, or a composed `DateRangeInputBase`, `inline` or not) points `aria-labelledby` at the label's own id unless you gave the group an `aria-label` or `aria-labelledby`. A range `Slider` takes the id on its low thumb and also starts each thumb's name with the label through `aria-labelledby`, unless its `ariaLabel` names that thumb or its own `aria-label` or `aria-labelledby` takes the label's place. An `Autocomplete` or a `Taginput` also names its open suggestion list after the label through `aria-labelledby`. Nothing else takes the label: `Checkbox`, `Radio` and `Switch` are named by their own children, and the label names one only when you wire it as you would any control with an `id` of its own, `labelProps={{ htmlFor }}` plus that control's `id`. Only the single inputs take the `htmlFor`, so once the Field's content has mounted the label keeps it only while one of them holds the id, and drops it over anything else: a group, a `Checkbox`, `Radio` or `Switch`, an `inline` picker, an inner `Field`, an input with an `id` of its own, markup of your own, or nothing at all. A server render, and the first render while hydrating, still write the `htmlFor`, which keeps hydration matching, and an input that mounts later puts it back. The label names an input with an `id` of your own only through `labelProps={{ htmlFor }}` set to that `id`, a `for` it always keeps; `labelProps={{ htmlFor: undefined }}` opts out. Skipped for `grouped`/`hasAddons` fields (multiple controls), and a nested `Field` starts its own scope, so a horizontal Field whose body holds an inner `Field` names the control there only when you wire it. Two controls in one plain labeled Field would both adopt the id, so give each an `id` of its own.",
153
153
  "required": false,
154
154
  "inherited": false,
155
155
  "deprecated": false
@@ -167,7 +167,7 @@
167
167
  "name": "labelProps",
168
168
  "type": "React.LabelHTMLAttributes<HTMLLabelElement> & { [key: string]: unknown; }",
169
169
  "default": null,
170
- "description": "Props for the label element. An explicit `htmlFor` key — even set to `undefined` — takes over the association. While the association is on, the label renders with the `id` given here, or a generated one, and a group control, a range `Slider`'s thumbs and an `Autocomplete`'s suggestion list point `aria-labelledby` at it. A label you take over gets no generated id, and no group points at it on its own. With an `id` here, though, a range `Slider` or an `Autocomplete` whose `id` your `htmlFor` names still points its thumbs or its suggestion list at it, in a `grouped` or `hasAddons` Field too. To point a group in an inner `Field` at this label by hand, pass that `id`. Nothing in the inner `Field` takes the generated `htmlFor`, so the label drops it after mounting, and adding `htmlFor: undefined` keeps it out of server-rendered markup too.",
170
+ "description": "Props for the label element. An explicit `htmlFor` key — even set to `undefined` — takes over the association. While the association is on, the label renders with the `id` given here, or a generated one, and a group control, a range `Slider`'s thumbs and an `Autocomplete`'s or `Taginput`'s suggestion list point `aria-labelledby` at it. A label you take over gets no generated id, and no group points at it on its own. With an `id` here, though, a range `Slider`, an `Autocomplete` or a `Taginput` whose `id` your `htmlFor` names still points its thumbs or its suggestion list at it, in a `grouped` or `hasAddons` Field too. To point a group in an inner `Field` at this label by hand, pass that `id`. Nothing in the inner `Field` takes the generated `htmlFor`, so the label drops it after mounting, and adding `htmlFor: undefined` keeps it out of server-rendered markup too.",
171
171
  "required": false,
172
172
  "inherited": false,
173
173
  "deprecated": false
@@ -226,7 +226,7 @@
226
226
  },
227
227
  {
228
228
  "path": "Field.Label",
229
- "summary": "FieldLabel component for rendering a Bulma field label. It renders the label column of a horizontal `Field` (a `div` with the `field-label` class), not a `<label>`, so text placed straight in it names nothing. Put a `<label>` with the `label` class inside it and point its `htmlFor` at the control's `id`, or give the horizontal `Field` a `label` prop, which renders this column and its `<label>` for you. A `<label>` you put here names the control through its `htmlFor` alone: a range `Slider`'s thumbs and an `Autocomplete`'s suggestion list point `aria-labelledby` at a `Field`'s label only when its `label` prop renders it and it names the control. Where it would not name the control on its own, as in an inner `Field`, pass `labelProps={{ htmlFor, id }}` with a matching `id` on the control.",
229
+ "summary": "FieldLabel component for rendering a Bulma field label. It renders the label column of a horizontal `Field` (a `div` with the `field-label` class), not a `<label>`, so text placed straight in it names nothing. Put a `<label>` with the `label` class inside it and point its `htmlFor` at the control's `id`, or give the horizontal `Field` a `label` prop, which renders this column and its `<label>` for you. A `<label>` you put here names the control through its `htmlFor` alone: a range `Slider`'s thumbs and an `Autocomplete`'s or `Taginput`'s suggestion list point `aria-labelledby` at a `Field`'s label only when its `label` prop renders it and it names the control. Where it would not name the control on its own, as in an inner `Field`, pass `labelProps={{ htmlFor, id }}` with a matching `id` on the control.",
230
230
  "component": null,
231
231
  "props": [
232
232
  {
@@ -58,7 +58,7 @@
58
58
  "code": "function example() {\n return (\n <Field\n horizontal\n label=\"Tags\"\n labelProps={{ htmlFor: 'tags-field-control' }}\n >\n <Field.Body>\n <Field>\n <Control>\n <Taginput\n id=\"tags-field-control\"\n icon=\"tags\"\n defaultValue={['React', 'TypeScript']}\n placeholder=\"Add a tag...\"\n tagColor=\"primary\"\n />\n </Control>\n </Field>\n </Field.Body>\n </Field>\n );\n}"
59
59
  }
60
60
  ],
61
- "accessibility": "- The `label` prop is automatically associated with the inner text input (`htmlFor` plus a generated `id`, or your own `id` if you pass one). While the label is wired it also names the input; without one, the input falls back to `aria-label=\"Add tag\"`. Inside a labeled `Field`, that `Field`'s label names the input the same way and replaces the fallback.\n- A user-supplied `id` is applied to the inner input (the labellable control), not the wrapper div.\n- When `maxTags` is reached the text input is not rendered, so the label renders without a `for` attribute.\n- Tags are keyboard navigable\n- Delete buttons have proper `aria-label`\n- Autocomplete dropdown follows ARIA listbox pattern",
61
+ "accessibility": "- The `label` prop is automatically associated with the inner text input (`htmlFor` plus a generated `id`, or your own `id` if you pass one). While the label is wired it also names the input; without one, the input falls back to `aria-label=\"Add tag\"`. Inside a labeled `Field`, that `Field`'s label names the input the same way and replaces the fallback.\n- A user-supplied `id` is applied to the inner input (the labellable control), not the wrapper div.\n- When `maxTags` is reached the text input is not rendered, so the label renders without a `for` attribute.\n- Tags are keyboard navigable\n- Delete buttons have proper `aria-label`\n- With `data`, the input is a `role=\"combobox\"` with `aria-autocomplete=\"list\"` and `aria-haspopup=\"listbox\"`. Its `aria-expanded` is true only while the suggestion list is on screen, and while it is, `aria-controls` points at the list. While no suggestion matches there's no list, so it stays false. Without `data` there's never a list, so the input stays a plain text field\n- Focus stays in the input, which points `aria-activedescendant` at the highlighted suggestion as the arrow keys or the mouse move it\n- The list is a `role=\"listbox\"` named through `aria-labelledby` by the label that names the input, when that label has an id: the `label` prop's label always has one, and so does a `Field`'s label that the `Field` wires itself. A `Field` label you wire by hand with `labelProps.htmlFor`, which is how the horizontal examples above name the Taginput, needs an `id` in its `labelProps` as well. Otherwise the list falls back to `aria-label=\"Suggestions\"`\n- The list holds only the suggestions, each a `role=\"option\"` with an id of its own, and the highlighted one has `aria-selected=\"true\"`",
62
62
  "related": ["Autocomplete", "Input", "Tag"],
63
63
  "storybook": "https://bestax.io/storybook/?path=/story/form-taginput",
64
64
  "summary": "The `Taginput` component provides a tag/chip input field for managing multiple tags.",
@@ -75,7 +75,7 @@
75
75
  "name": "label",
76
76
  "type": "React.ReactNode",
77
77
  "default": null,
78
- "description": "Field label. Automatically associated with the text input via `htmlFor` — uses your `id` when provided, otherwise a generated one. Not wired when the tag limit is reached (the input is not rendered). Dropped inside an outer `Field`, whose own label associates instead when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`) and you set no `id` here; it then replaces the `aria-label=\"Add tag\"` fallback too.",
78
+ "description": "Field label. Automatically associated with the text input via `htmlFor` — uses your `id` when provided, otherwise a generated one. Not wired when the tag limit is reached (the input is not rendered). Dropped inside an outer `Field`, whose own label associates instead when that `Field` generates a target id (not `grouped`/`hasAddons`, no explicit `labelProps.htmlFor`) and you set no `id` here; it then replaces the `aria-label=\"Add tag\"` fallback too. With `data`, the label naming the input also names the open suggestion list, through `aria-labelledby`, when it has an id: this label always does, and an outer `Field`'s does unless you wired it by hand without an `id` in its `labelProps`. Otherwise the list is named \"Suggestions\".",
79
79
  "required": false,
80
80
  "inherited": false,
81
81
  "deprecated": false
@@ -84,7 +84,7 @@
84
84
  "name": "labelProps",
85
85
  "type": "React.LabelHTMLAttributes<HTMLLabelElement> & { [key: string]: unknown; }",
86
86
  "default": null,
87
- "description": "Props for the label element. An explicit `htmlFor` here overrides the automatic association (no id is generated then).",
87
+ "description": "Props for the label element. An explicit `htmlFor` here overrides the automatic association (no id is generated then). With `data`, while the label names the input, the suggestion list's `aria-labelledby` points at it, through an `id` here when you give one and a generated one otherwise.",
88
88
  "required": false,
89
89
  "inherited": false,
90
90
  "deprecated": false
@@ -119,8 +119,8 @@
119
119
  {
120
120
  "name": "data",
121
121
  "type": "string[]",
122
- "default": "[]",
123
- "description": "Autocomplete suggestions.",
122
+ "default": null,
123
+ "description": "Autocomplete suggestions. With `data` set, even to an empty array, the text input is a `role=\"combobox\"` that controls the suggestion list and points `aria-activedescendant` at the highlighted suggestion. Without it there's no list, so the input stays a plain text field.",
124
124
  "required": false,
125
125
  "inherited": false,
126
126
  "deprecated": false
@@ -174,7 +174,7 @@ the children with `gap`. Before writing `style={{ … }}` anywhere, translate ea
174
174
  | `textAlign: 'center'` | `textAlign="centered"` (also `left`, `right`, `justified`) |
175
175
  | `color: '#…'` | `textColor` with the nearest Bulma color: `primary`, `link`, `info`, `success`, `warning`, `danger`, `white`, `black`, `grey` (+ `grey-light`, `grey-dark`, …) |
176
176
  | `backgroundColor: '#…'` | `bgColor` (same palette) |
177
- | `fontSize: …` | `textSize="1"`…`"7"` (`1` largest) — for headings use `Title`/`SubTitle` `size` |
177
+ | `fontSize: …` | `textSize="1"`…`"7"` (`1` largest). On `Title`/`SubTitle`, `as` sets the level and `size` picks it too, so an `<h3>` at size 4 is `as="h3" textSize="4"` |
178
178
  | `fontWeight: …` | `textWeight`: `light`, `normal`, `medium`, `semibold`, `bold` |
179
179
  | `textTransform`, italics | `textTransform`: `uppercase`, `lowercase`, `capitalized`, `italic` |
180
180
  | `display: 'flex'` + flex properties | same-named props: `display="flex"`, `flexDirection`, `justifyContent`, `alignItems`, `flexWrap` |
@@ -148,18 +148,18 @@ unmatched `for` out of server-rendered HTML.
148
148
 
149
149
  A `range` `Slider` points the `for` at its low thumb and starts both thumbs' names with the label
150
150
  ("Price range Minimum value"); its `ariaLabel={[low, high]}` replaces those names outright, so
151
- leave it off when a label already names the Slider. Those thumbs and an `Autocomplete`'s
152
- suggestion list point `aria-labelledby` at the label's `id`, which a label wired by hand has only
153
- when you pass one, `labelProps={{ htmlFor, id }}`; without it they keep their fallback names
154
- ("Minimum value"/"Maximum value", "Suggestions"). A `<label htmlFor>` you put in `Field.Label`
155
- yourself (`references/patterns.md`) names its control through the `for` alone, so label a row
156
- holding either with the `Field`'s `label` prop. An `aria-label` or `aria-labelledby` you give a
157
- group wins over any label, and a `Checkbox`, `Radio` or `Switch` takes nothing from a `Field` on
158
- its own: its children name it, and a `Field`'s label names one only when you wire it as you would
159
- any control with an `id` of its own, `labelProps={{ htmlFor }}` plus that control's `id`. A
160
- labeled `Field` whose `for` nothing takes (a group, a `Checkbox`, `Radio` or `Switch`, an input
161
- with an `id` of its own, your own markup) drops it once mounted, though server-rendered HTML keeps
162
- it. `labelProps={{ htmlFor: undefined }}` opts out of the association entirely.
151
+ leave it off when a label already names the Slider. Those thumbs and an `Autocomplete`'s or
152
+ `Taginput`'s suggestion list point `aria-labelledby` at the label's `id`, which a label wired by
153
+ hand has only when you pass one, `labelProps={{ htmlFor, id }}`; without it they keep their
154
+ fallback names ("Minimum value"/"Maximum value", "Suggestions"). A `<label htmlFor>` you put in
155
+ `Field.Label` yourself (`references/patterns.md`) names its control through the `for` alone, so
156
+ label a row holding either with the `Field`'s `label` prop. An `aria-label` or `aria-labelledby`
157
+ you give a group wins over any label, and a `Checkbox`, `Radio` or `Switch` takes nothing from a
158
+ `Field` on its own: its children name it, and a `Field`'s label names one only when you wire it as
159
+ you would any control with an `id` of its own, `labelProps={{ htmlFor }}` plus that control's
160
+ `id`. A labeled `Field` whose `for` nothing takes (a group, a `Checkbox`, `Radio` or `Switch`, an
161
+ input with an `id` of its own, your own markup) drops it once mounted, though server-rendered HTML
162
+ keeps it. `labelProps={{ htmlFor: undefined }}` opts out of the association entirely.
163
163
 
164
164
  ## Convenience vs composed
165
165
 
@@ -19,7 +19,7 @@ Container and layout. Compound parts: `Field.Label`, `Field.Body`.
19
19
  | `labelProps` | label attributes | Props for the `<label>`. An explicit `htmlFor` (even `undefined`) takes over the association; otherwise it is set automatically. For its `id`, see below. |
20
20
  | `textColor` / `bgColor` | Bulma color | Helper colors for the field. |
21
21
 
22
- An `id` in `labelProps` is what a group's, a range `Slider`'s and an `Autocomplete` suggestion list's `aria-labelledby` points at. A label wired by hand with `htmlFor` gets no generated id, so give it one, `labelProps={{ htmlFor, id }}`, for a range `Slider` or an `Autocomplete`. No group points at a label wired by hand.
22
+ An `id` in `labelProps` is what a group's, a range `Slider`'s and an `Autocomplete` or `Taginput` suggestion list's `aria-labelledby` points at. A label wired by hand with `htmlFor` gets no generated id, so give it one, `labelProps={{ htmlFor, id }}`, for a range `Slider`, an `Autocomplete` or a `Taginput`. No group points at a label wired by hand.
23
23
 
24
24
  ## Control — `form/Control.tsx`
25
25
 
@@ -165,9 +165,9 @@ Recipes built on addons, each written out in full in the docs:
165
165
  `Button` and a `Dropdown` in `Field hasAddons`, one `Control` each. `Buttons hasAddons` does
166
166
  not join the Dropdown's trigger. Keep the default color, since the trigger takes no `color`.
167
167
  - To label an addon row, put the label on an outer `Field` with `labelProps={{ htmlFor, id }}`
168
- and a matching `id` on the input. The label's `id` names an `Autocomplete`'s suggestion list
169
- or a range `Slider`'s thumbs, which point `aria-labelledby` at it. A label inside the
170
- `hasAddons` field sits in the row beside the controls.
168
+ and a matching `id` on the input. The label's `id` names an `Autocomplete`'s or `Taginput`'s
169
+ suggestion list or a range `Slider`'s thumbs, which point `aria-labelledby` at it. A label
170
+ inside the `hasAddons` field sits in the row beside the controls.
171
171
 
172
172
  ## Horizontal field with explicit label/body
173
173
 
@@ -191,7 +191,7 @@ background comes from the semantic `color` prop, not `bgColor`.
191
191
  | `textAlign: 'center'` | `textAlign="centered"` (also `left`, `right`, `justified`) |
192
192
  | `color: '#…'` | `textColor` with the nearest Bulma color: `primary`, `link`, `info`, `success`, `warning`, `danger`, `white`, `black`, `grey` (+ `grey-light`, `grey-dark`, …) |
193
193
  | `backgroundColor: '#…'` | `bgColor` (same palette) |
194
- | `fontSize: …` | `textSize="1"`…`"7"` (`1` largest) — for headings use `Title`/`SubTitle` `size` |
194
+ | `fontSize: …` | `textSize="1"`…`"7"` (`1` largest). On `Title`/`SubTitle`, `as` sets the level and `size` picks it too, so an `<h3>` at size 4 is `as="h3" textSize="4"` |
195
195
  | `fontWeight: …` | `textWeight`: `light`, `normal`, `medium`, `semibold`, `bold` |
196
196
  | `textTransform`, italics | `textTransform`: `uppercase`, `lowercase`, `capitalized`, `italic` |
197
197
  | `display: 'flex'` + flex properties | same-named props: `display="flex"`, `flexDirection`, `justifyContent`, `alignItems`, `flexWrap` |
@@ -54,8 +54,8 @@ leftover would be a type error rather than a no-op.
54
54
  | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
55
55
  | `isColor="primary"` | `color="primary"` (every component that had it) |
56
56
  | `isSize="large"` | `size="large"` — Button, Content, Delete, Icon, Input, Progress, Section, Select, Tag, TextArea, Breadcrumb, Pagination, Tabs, Field.Label, Modal.Close |
57
- | `Title isSize={3}` | `size={3}` — bestax accepts the numbers 1–6 |
58
- | `Subtitle isSize={4}` | `SubTitle size={4} as="h2"` — bloomer's default was an `<h2>`, bestax's is an `<h1>`, so the level is kept |
57
+ | `Title isSize={3}` | `textSize="3"`, so the `<h1>` stays an `<h1>` (see [Title and Subtitle sizes](#title-and-subtitle-sizes)) |
58
+ | `Subtitle isSize={4}` | `SubTitle textSize="4" as="h2"`: bloomer's default was an `<h2>`, bestax's is an `<h1>`, so the level is written out |
59
59
  | `Image isSize="128x128"` | `size="128x128"` |
60
60
  | `Image isRatio="16:9"` | `size="16by9"` (`square`→`square`, `1:1`→`1by1`, `4:3`→`4by3`, `3:2`→`3by2`, `2:1`→`2by1`) |
61
61
  | `Breadcrumb isAlign` | `alignment` |
@@ -77,6 +77,31 @@ leftover would be a type error rather than a no-op.
77
77
  | `isActive` on Dropdown, DropdownItem, MenuLink, Modal, NavbarBurger, NavbarMenu, NavbarItem, PanelBlock, Tab | `active` |
78
78
  | `Input`, `Select`, `TextArea` | `InputBase`, `SelectBase`, `TextAreaBase` — bloomer's were bare elements; bestax's `Input`/`Select`/`TextArea` wrap themselves in `Field` and `Control`, so the bare `*Base` exports are the faithful targets and your existing `Field`/`Control` markup stays as written |
79
79
 
80
+ ## Title and Subtitle sizes
81
+
82
+ bloomer's `Title` rendered an `<h1>` and its `Subtitle` an `<h2>` whatever `isSize` said, or
83
+ the element `tag` named. bestax's `Title` and `SubTitle` render the heading their `size` names
84
+ unless `as="p"`, so `<SubTitle size={4} as="h2">` is an `<h4>`. The codemod keeps the element
85
+ bloomer rendered:
86
+
87
+ | bloomer | bestax-bulma | renders |
88
+ | ----------------------------- | --------------------------------- | ------- |
89
+ | `<Title isSize={4}>` | `<Title textSize="4">` | `<h1>` |
90
+ | `<Title isSize={1}>` | `<Title size={1}>` | `<h1>` |
91
+ | `<Title isSize={4} tag="h2">` | `<Title textSize="4" as="h2">` | `<h2>` |
92
+ | `<Title isSize={6} tag="p">` | `<Title size={6} as="p">` | `<p>` |
93
+ | `<Subtitle>` | `<SubTitle as="h2">` | `<h2>` |
94
+ | `<Subtitle isSize={2}>` | `<SubTitle size={2}>` | `<h2>` |
95
+ | `<Subtitle isSize={4}>` | `<SubTitle textSize="4" as="h2">` | `<h2>` |
96
+
97
+ `size` stays only where it renders the same element: a `<p>`, or the heading the size names.
98
+ Everywhere else the size moves to the `textSize` helper, and so does a 7, which bestax's `size`
99
+ does not take. The helper sets the same font size through Bulma's `is-size-4` class rather than the
100
+ title's own `is-4`, so a rule of your own that targets `.title.is-4` needs the new class too.
101
+ `is-size-4` is also `!important`, so a font size your own CSS gives the title, such as
102
+ `.hero .title`, now loses to it where it used to beat `is-4`. A literal outside 1 to 7 keeps `size`
103
+ and gets a `prop:isSize` TODO.
104
+
80
105
  ## Column sizes
81
106
 
82
107
  | bloomer | bestax-bulma |
@@ -274,6 +274,24 @@ prop conditionally:
274
274
  counterpart in bestax (only `isNarrowTouch`) — Bulma keeps the `is-*-touch` classes, so use
275
275
  `className`.
276
276
 
277
+ ## `prop:isSize` on `Title` and `Subtitle`: a size the codemod cannot carry
278
+
279
+ bloomer's `Title` and `Subtitle` kept their element at every size. bestax's render the heading
280
+ their `size` names, so a literal `isSize` moves to `textSize` to keep the level (see "Title and
281
+ Subtitle sizes" in the prop map). A dynamic one cannot move, because `textSize` takes a string,
282
+ so it becomes `size`. Pass it to `textSize` yourself:
283
+
284
+ ```jsx
285
+ <Subtitle isSize={compact ? 5 : 4}>Report</Subtitle>
286
+ <SubTitle textSize={compact ? '5' : '4'} as="h2">Report</SubTitle>
287
+ ```
288
+
289
+ A literal outside 1 to 7 has no Bulma class, and bestax renders none for it either: drop it, or set
290
+ a `textSize` from `'1'` to `'7'`.
291
+
292
+ A dynamic size beside `tag="p"` is not flagged, since bestax never turns a `<p>` into a
293
+ heading.
294
+
277
295
  ## `value-reference` — a component used as a value
278
296
 
279
297
  `const Wrapped = Box` and `{ Subtitle }` are rewritten to the bestax binding (`Hero.Foot`,
@@ -118,6 +118,29 @@ wrong:
118
118
  Note that this one does change the rendered element: rbx's `forwardRefAs` rendered the tag you
119
119
  gave it, so that really was a `<span>`, and the TODO exists to tell you the element moved.
120
120
 
121
+ ## Title sizes
122
+
123
+ rbx's `Title` rendered an `<h1>` at every size, subtitle or not, or the element `as` named.
124
+ bestax's `Title` and `SubTitle` render the heading their `size` names unless `as="p"`, so the
125
+ codemod keeps the element rbx rendered:
126
+
127
+ | rbx | bestax-bulma | renders |
128
+ | ---------------------------------- | ------------------------------ | ------- |
129
+ | `<Title size={4}>` | `<Title textSize="4">` | `<h1>` |
130
+ | `<Title size={1}>` | `<Title size={1}>` | `<h1>` |
131
+ | `<Title subtitle size={6}>` | `<SubTitle textSize="6">` | `<h1>` |
132
+ | `<Title as="h2" size={5}>` | `<Title as="h2" textSize="5">` | `<h2>` |
133
+ | `<Title as="p" subtitle size={5}>` | `<SubTitle as="p" size={5}>` | `<p>` |
134
+
135
+ `size` stays only where it renders the same element: a `<p>`, or the heading the size names.
136
+ Everywhere else the size moves to the `textSize` helper, and so does a 7, which bestax's `size`
137
+ does not take. The helper sets the same font size through Bulma's `is-size-4` class rather than the
138
+ title's own `is-4`, so a rule of your own that targets `.title.is-4` needs the new class too.
139
+ `is-size-4` is also `!important`, so a font size your own CSS gives the title, such as
140
+ `.hero .title`, now loses to it where it used to beat `is-4`. Beside a spread, which may carry
141
+ `as`, a size moves even where it names the default `<h1>`. A literal outside 1 to 7 keeps `size`
142
+ and gets a `prop:size` TODO.
143
+
121
144
  ## `href` follows `as`
122
145
 
123
146
  bestax gives an element the attributes of the tag `as` names, so `href` exists only where that
@@ -181,6 +181,24 @@ prop.
181
181
  A dynamic `Image.Container` size gets the same rule, since the codemod can't turn it into
182
182
  bestax's `NxN` form. Set `size` on the migrated `<Image>` by hand.
183
183
 
184
+ ## `prop:size` on `Title`: a size the codemod cannot carry
185
+
186
+ rbx's `Title` rendered an `<h1>` at every size, subtitle or not. bestax's `Title` and `SubTitle`
187
+ render the heading their `size` names unless `as="p"`, so a literal size moves to `textSize` to
188
+ keep the level (see "Title sizes" in the prop map). A dynamic one cannot move, because
189
+ `textSize` takes a string, so it stays `size`. Pass it to `textSize` yourself:
190
+
191
+ ```jsx
192
+ <Title size={compact ? 5 : 4}>Report</Title>
193
+ <Title textSize={compact ? '5' : '4'}>Report</Title>
194
+ ```
195
+
196
+ A literal outside 1 to 7 has no Bulma class, and bestax renders none for it either: drop it, or set
197
+ a `textSize` from `'1'` to `'7'`.
198
+
199
+ The same TODO marks a `Title` that sets `size` and `textSize` both: drop `size` and let
200
+ `textSize` set the font size.
201
+
184
202
  ## Props with no counterpart
185
203
 
186
204
  | TODO | What to do |
@@ -20,7 +20,7 @@ codemod converts it; **Flagged** = it leaves a `TODO(bestax-migrate)` comment (s
20
20
  | `Element` | — | Flagged: no generic element; use a semantic component + helper props |
21
21
  | `Footer` | `Footer` | Auto |
22
22
  | `Form.*` | flat imports | See Form table below |
23
- | `Heading` | `Title` / `SubTitle` / `<p class="heading">` | Auto for literal `subtitle`/`heading` (by value, not presence — `subtitle={false}` is `Title`); dynamic value flagged |
23
+ | `Heading` | `Title` / `SubTitle` / `<p class="heading">` | Auto for literal `subtitle`/`heading` (by value, not presence — `subtitle={false}` is `Title`); dynamic value flagged; `size` may become `textSize` |
24
24
  | `Hero` | `Hero` | Auto; `hasNavbar`→`fullheightWithNavbar`; `halfheight`/`gradient` flagged |
25
25
  | `Icon` | `Icon` | `<i class="fas fa-x">` children → `name`/`library`/`variant` props; else flagged |
26
26
  | `Image` | `Image` | Auto; numeric `size={128}` → `size="128x128"`, `rounded`→`isRounded` |
@@ -46,6 +46,28 @@ href="/x">`) keeps the element and drops the `href`, with a `prop:href` TODO. RB
46
46
  `<Button href="/x">` with no `renderAs` goes the same way: bestax's `Button` renders a
47
47
  `<button>`. Set `as="a"` to make it a link.
48
48
 
49
+ ## `Heading` sizes
50
+
51
+ RBC's `Heading` rendered an `<h1>` at every size, subtitle or not, or the element `renderAs`
52
+ named. bestax's `Title` and `SubTitle` render the heading their `size` names unless `as="p"`, so
53
+ the codemod keeps the element RBC rendered:
54
+
55
+ | RBC | bestax-bulma | renders |
56
+ | ------------------------------------------ | ------------------------------ | ------- |
57
+ | `<Heading size={4}>` | `<Title textSize="4">` | `<h1>` |
58
+ | `<Heading size={1}>` | `<Title size="1">` | `<h1>` |
59
+ | `<Heading subtitle size={6}>` | `<SubTitle textSize="6">` | `<h1>` |
60
+ | `<Heading renderAs="h2" size={5}>` | `<Title as="h2" textSize="5">` | `<h2>` |
61
+ | `<Heading renderAs="p" subtitle size={5}>` | `<SubTitle as="p" size="5">` | `<p>` |
62
+
63
+ `size` stays only where it renders the same element: a `<p>`, or the heading the size names.
64
+ Everywhere else the size moves to the `textSize` helper, and so does a 7, which bestax's `size`
65
+ does not take. The helper sets the same font size through Bulma's `is-size-4` class rather than the
66
+ title's own `is-4`, so a rule of your own that targets `.title.is-4` needs the new class too.
67
+ `is-size-4` is also `!important`, so a font size your own CSS gives the title, such as
68
+ `.hero .title`, now loses to it where it used to beat `is-4`. A literal outside 1 to 7 keeps `size`
69
+ and gets a `prop:size` TODO.
70
+
49
71
  ## Boolean modifier convention
50
72
 
51
73
  RBC uses bare booleans (`loading`, `outlined`, `rounded`, `fullwidth`); bestax prefixes
@@ -142,6 +142,24 @@ bestax `Button` colors are the semantic set + `text`/`ghost`. For shades use
142
142
  takes the value. Any other value, or one the codemod can't read, stays as written with a TODO
143
143
  that lists the sizes that component takes: use one of them, or drop the prop.
144
144
 
145
+ ## `prop:size` on `Heading`: a size the codemod cannot carry
146
+
147
+ RBC's `Heading` rendered an `<h1>` at every size, subtitle or not. bestax's `Title` and
148
+ `SubTitle` render the heading their `size` names unless `as="p"`, so a literal size moves to
149
+ `textSize` to keep the level (see "`Heading` sizes" in the prop map). A dynamic one cannot move,
150
+ because `textSize` takes a string, so it stays `size`. Pass it to `textSize` yourself:
151
+
152
+ ```jsx
153
+ <Heading size={compact ? 5 : 4}>Report</Heading>
154
+ <Title textSize={compact ? '5' : '4'}>Report</Title>
155
+ ```
156
+
157
+ A literal outside 1 to 7 has no Bulma class, and bestax renders none for it either: drop it, or set
158
+ a `textSize` from `'1'` to `'7'`.
159
+
160
+ The same TODO marks a `Heading` that sets `size` and `textSize` both: drop `size` and let
161
+ `textSize` set the font size.
162
+
145
163
  ## `domRef`
146
164
 
147
165
  bestax components don't take `domRef`, but many forward a plain `ref` — the form controls, plus
package/data/skills.json CHANGED
@@ -29,8 +29,8 @@
29
29
  "promptName": "form",
30
30
  "dir": "bestax-form",
31
31
  "references": [
32
- { "id": "api", "file": "references/api.md", "bytes": 13008 },
33
- { "id": "patterns", "file": "references/patterns.md", "bytes": 7509 }
32
+ { "id": "api", "file": "references/api.md", "bytes": 13036 },
33
+ { "id": "patterns", "file": "references/patterns.md", "bytes": 7525 }
34
34
  ],
35
35
  "examples": []
36
36
  },
@@ -93,12 +93,12 @@
93
93
  {
94
94
  "id": "bloomer-prop-map",
95
95
  "file": "references/bloomer/prop-map.md",
96
- "bytes": 24639
96
+ "bytes": 26286
97
97
  },
98
98
  {
99
99
  "id": "bloomer-unmappables",
100
100
  "file": "references/bloomer/unmappables.md",
101
- "bytes": 16955
101
+ "bytes": 17739
102
102
  },
103
103
  {
104
104
  "id": "bulma-classes-component-map",
@@ -128,12 +128,12 @@
128
128
  {
129
129
  "id": "rbx-prop-map",
130
130
  "file": "references/rbx/prop-map.md",
131
- "bytes": 12404
131
+ "bytes": 13914
132
132
  },
133
133
  {
134
134
  "id": "rbx-unmappables",
135
135
  "file": "references/rbx/unmappables.md",
136
- "bytes": 14336
136
+ "bytes": 15120
137
137
  },
138
138
  {
139
139
  "id": "react-bulma-components-component-map",
@@ -143,12 +143,12 @@
143
143
  {
144
144
  "id": "react-bulma-components-prop-map",
145
145
  "file": "references/react-bulma-components/prop-map.md",
146
- "bytes": 7334
146
+ "bytes": 8820
147
147
  },
148
148
  {
149
149
  "id": "react-bulma-components-unmappables",
150
150
  "file": "references/react-bulma-components/unmappables.md",
151
- "bytes": 12266
151
+ "bytes": 13064
152
152
  }
153
153
  ],
154
154
  "examples": []
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bestax-mcp",
3
- "version": "1.15.3",
3
+ "version": "1.15.4",
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.31.0",
44
44
  "zod": "^4.4.3",
45
- "@allxsmith/bestax-bulma": "^5.34.0"
45
+ "@allxsmith/bestax-bulma": "^5.34.1"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@jest/globals": "^30.0.0",