bestax-mcp 1.13.0 → 1.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/data/bulma-classes.json +18 -2
- package/data/catalog.json +101 -12
- package/data/components/Autocomplete.json +1 -1
- package/data/components/Avatar.json +1 -1
- package/data/components/Avatars.json +1 -1
- package/data/components/Button.json +2 -2
- package/data/components/Buttons.json +2 -2
- package/data/components/Card.json +20 -1
- package/data/components/Carousel.json +2 -2
- package/data/components/ClientOnly.json +29 -0
- package/data/components/Collapse.json +17 -12
- package/data/components/Collapses.json +261 -0
- package/data/components/Column.json +1 -1
- package/data/components/Control.json +1 -1
- package/data/components/DateInput.json +37 -6
- package/data/components/DateTimeInput.json +13 -3
- package/data/components/Delete.json +4 -4
- package/data/components/Dropdown.json +8 -4
- package/data/components/Field.json +1 -1
- package/data/components/Input.json +10 -2
- package/data/components/Link.json +1 -1
- package/data/components/LinkButton.json +1 -1
- package/data/components/Loader.json +74 -0
- package/data/components/Menu.json +2 -2
- package/data/components/Modal.json +28 -2
- package/data/components/Navbar.json +15 -6
- package/data/components/Notification.json +2 -2
- package/data/components/Numberinput.json +1 -1
- package/data/components/Popover.json +534 -0
- package/data/components/Portal.json +29 -0
- package/data/components/Select.json +1 -1
- package/data/components/Sidebar.json +20 -1
- package/data/components/Steps.json +1 -1
- package/data/components/Table.json +3 -3
- package/data/components/Tag.json +1 -1
- package/data/components/Taginput.json +1 -1
- package/data/components/Tags.json +1 -1
- package/data/components/TextArea.json +1 -1
- package/data/components/Theme.json +2 -2
- package/data/components/TimeInput.json +3 -3
- package/data/components/Toast.json +1 -1
- package/data/components/Valid value constants.json +2 -2
- package/data/components/useBulmaClasses.json +12 -4
- package/data/components/useFocusTrap.json +25 -0
- package/data/skills/bestax-custom-component/SKILL.md +18 -0
- package/data/skills/bestax-custom-component/references/api.md +100 -10
- package/data/skills/bestax-custom-component/references/component-catalog.md +8 -2
- package/data/skills/bestax-custom-component/references/library-contributor.md +17 -0
- package/data/skills/bestax-form/SKILL.md +1 -1
- package/data/skills/bestax-form/references/api.md +17 -0
- package/data/skills/bestax-form/references/patterns.md +19 -0
- package/data/skills/bestax-layout-scaffold/SKILL.md +11 -1
- package/data/skills/bestax-migrate/references/bloomer/prop-map.md +5 -5
- package/data/skills/bestax-migrate/references/bloomer/unmappables.md +17 -0
- package/data/skills/bestax-migrate/references/bulma-classes/component-map.md +7 -4
- package/data/skills/bestax-migrate/references/bulma-classes/prop-map.md +4 -3
- package/data/skills/bestax-migrate/references/bulma-classes/unmappables.md +2 -1
- package/data/skills/bestax-migrate/references/rbx/component-map.md +15 -15
- package/data/skills/bestax-migrate/references/rbx/prop-map.md +1 -1
- package/data/skills/bestax-migrate/references/rbx/unmappables.md +17 -0
- package/data/skills/bestax-migrate/references/react-bulma-components/component-map.md +1 -1
- package/data/skills/bestax-migrate/references/react-bulma-components/unmappables.md +18 -1
- package/data/skills/bestax-optimize/SKILL.md +1 -1
- package/data/skills/bestax-optimize/references/modular-build.md +16 -4
- package/data/skills/bestax-theming/references/css-variables.md +28 -6
- package/data/skills/bestax-theming/references/themeable-components.md +10 -9
- package/data/skills.json +17 -17
- package/dist/helper-props.d.ts.map +1 -1
- package/dist/helper-props.js +17 -2
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -26,6 +26,10 @@ you when they disagree, rather than confidently describing props you do not have
|
|
|
26
26
|
|
|
27
27
|
## Setup
|
|
28
28
|
|
|
29
|
+
Each release is published to the official
|
|
30
|
+
[MCP Registry](https://registry.modelcontextprotocol.io) as
|
|
31
|
+
`io.github.allxsmith/bestax-mcp`, for clients that install from it.
|
|
32
|
+
|
|
29
33
|
### Claude Code
|
|
30
34
|
|
|
31
35
|
```bash
|
package/data/bulma-classes.json
CHANGED
|
@@ -6449,11 +6449,27 @@
|
|
|
6449
6449
|
},
|
|
6450
6450
|
{
|
|
6451
6451
|
"why": "an `.image` modifier, which converts only on its own `.image`, and only where bestax has a prop for it",
|
|
6452
|
-
"match": "^(?:is-\\d+by\\d+|is-\\d+x\\d+|is-square|
|
|
6452
|
+
"match": "^(?:is-\\d+by\\d+|is-\\d+x\\d+|is-square|has-ratio)$"
|
|
6453
|
+
},
|
|
6454
|
+
{
|
|
6455
|
+
"why": "a Bulma helper the codemod does not convert; the `pos` prop renders it",
|
|
6456
|
+
"match": "^is-position-.+$"
|
|
6457
|
+
},
|
|
6458
|
+
{
|
|
6459
|
+
"why": "a Bulma helper the codemod does not convert; the `overflow`, `overflowX` and `overflowY` props render it",
|
|
6460
|
+
"match": "^is-overflow-.+$"
|
|
6461
|
+
},
|
|
6462
|
+
{
|
|
6463
|
+
"why": "a Bulma helper the codemod does not convert; the `radius` prop renders it",
|
|
6464
|
+
"match": "^has-radius-.+$"
|
|
6465
|
+
},
|
|
6466
|
+
{
|
|
6467
|
+
"why": "a Bulma helper the codemod does not convert; the `aspectRatio` prop renders it",
|
|
6468
|
+
"match": "^is-aspect-ratio-.+$"
|
|
6453
6469
|
},
|
|
6454
6470
|
{
|
|
6455
6471
|
"why": "a Bulma helper with no bestax prop",
|
|
6456
|
-
"match": "^(?:is-display-.+|is-visibility-.+|is-
|
|
6472
|
+
"match": "^(?:is-display-.+|is-visibility-.+|is-float-.+|is-clear-.+|has-text-weight-extrabold|is-align-content-(?:baseline|start|end)|is-align-items-self-(?:start|end)|is-offset-0(?:-[a-z]+)?)$"
|
|
6457
6473
|
},
|
|
6458
6474
|
{
|
|
6459
6475
|
"why": "a `.breadcrumb` separator, which converts only on its own `.breadcrumb`",
|
package/data/catalog.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"generatedFrom": {
|
|
4
4
|
"package": "@allxsmith/bestax-bulma",
|
|
5
|
-
"version": "5.
|
|
5
|
+
"version": "5.23.0"
|
|
6
6
|
},
|
|
7
7
|
"docsBase": "https://bestax.io/docs",
|
|
8
8
|
"categories": [
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"Link",
|
|
27
27
|
"LinkButton",
|
|
28
28
|
"ListItem",
|
|
29
|
+
"Loader",
|
|
29
30
|
"Notification",
|
|
30
31
|
"OrderedList",
|
|
31
32
|
"Paragraph",
|
|
@@ -53,6 +54,7 @@
|
|
|
53
54
|
"Card",
|
|
54
55
|
"Carousel",
|
|
55
56
|
"Collapse",
|
|
57
|
+
"Collapses",
|
|
56
58
|
"Dialog",
|
|
57
59
|
"Dropdown",
|
|
58
60
|
"Loading",
|
|
@@ -62,6 +64,7 @@
|
|
|
62
64
|
"Navbar",
|
|
63
65
|
"Pagination",
|
|
64
66
|
"Panel",
|
|
67
|
+
"Popover",
|
|
65
68
|
"Reveal",
|
|
66
69
|
"Sidebar",
|
|
67
70
|
"Steps",
|
|
@@ -110,11 +113,14 @@
|
|
|
110
113
|
"id": "helpers",
|
|
111
114
|
"label": "Helpers",
|
|
112
115
|
"components": [
|
|
116
|
+
"ClientOnly",
|
|
113
117
|
"ConfigProvider",
|
|
118
|
+
"Portal",
|
|
114
119
|
"Theme",
|
|
115
120
|
"Valid value constants",
|
|
116
121
|
"classNames",
|
|
117
122
|
"useBulmaClasses",
|
|
123
|
+
"useFocusTrap",
|
|
118
124
|
"usePrefixedClassNames"
|
|
119
125
|
]
|
|
120
126
|
}
|
|
@@ -274,6 +280,17 @@
|
|
|
274
280
|
"propCount": 20,
|
|
275
281
|
"exampleCount": 5
|
|
276
282
|
},
|
|
283
|
+
{
|
|
284
|
+
"name": "ClientOnly",
|
|
285
|
+
"kind": "helper",
|
|
286
|
+
"category": "helpers",
|
|
287
|
+
"purpose": "`ClientOnly` renders its children only in the browser, after hydration, and a `fallback` until then, so content that depends on browser-only state doesn't…",
|
|
288
|
+
"slug": "helpers/clientonly",
|
|
289
|
+
"import": "import { ClientOnly } from '@allxsmith/bestax-bulma';",
|
|
290
|
+
"compound": false,
|
|
291
|
+
"propCount": 0,
|
|
292
|
+
"exampleCount": 3
|
|
293
|
+
},
|
|
277
294
|
{
|
|
278
295
|
"name": "Code",
|
|
279
296
|
"kind": "component",
|
|
@@ -293,8 +310,19 @@
|
|
|
293
310
|
"slug": "components/collapse",
|
|
294
311
|
"import": "import { Collapse } from '@allxsmith/bestax-bulma';",
|
|
295
312
|
"compound": false,
|
|
296
|
-
"propCount":
|
|
297
|
-
"exampleCount":
|
|
313
|
+
"propCount": 12,
|
|
314
|
+
"exampleCount": 6
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
"name": "Collapses",
|
|
318
|
+
"kind": "component",
|
|
319
|
+
"category": "components",
|
|
320
|
+
"purpose": "The `Collapses` component groups `Collapse` items into an accordion that keeps one item open at a time, or any number with `multiple`.",
|
|
321
|
+
"slug": "components/collapses",
|
|
322
|
+
"import": "import { Collapses, Collapse } from '@allxsmith/bestax-bulma';",
|
|
323
|
+
"compound": true,
|
|
324
|
+
"propCount": 19,
|
|
325
|
+
"exampleCount": 8
|
|
298
326
|
},
|
|
299
327
|
{
|
|
300
328
|
"name": "Column",
|
|
@@ -370,8 +398,8 @@
|
|
|
370
398
|
"slug": "form/datetime/dateinput",
|
|
371
399
|
"import": "import { DateInput } from '@allxsmith/bestax-bulma';",
|
|
372
400
|
"compound": false,
|
|
373
|
-
"propCount":
|
|
374
|
-
"exampleCount":
|
|
401
|
+
"propCount": 53,
|
|
402
|
+
"exampleCount": 41
|
|
375
403
|
},
|
|
376
404
|
{
|
|
377
405
|
"name": "DateTimeInput",
|
|
@@ -382,7 +410,7 @@
|
|
|
382
410
|
"import": "import { DateTimeInput } from '@allxsmith/bestax-bulma';",
|
|
383
411
|
"compound": false,
|
|
384
412
|
"propCount": 62,
|
|
385
|
-
"exampleCount":
|
|
413
|
+
"exampleCount": 40
|
|
386
414
|
},
|
|
387
415
|
{
|
|
388
416
|
"name": "Delete",
|
|
@@ -423,10 +451,10 @@
|
|
|
423
451
|
"category": "components",
|
|
424
452
|
"purpose": "The `Dropdown` component provides Bulma's versatile dropdown menu for your Bulma React UI.",
|
|
425
453
|
"slug": "components/dropdown",
|
|
426
|
-
"import": "import { Dropdown } from '@allxsmith/bestax-bulma';",
|
|
454
|
+
"import": "import { Dropdown, Button, Field, Control, Span } from '@allxsmith/bestax-bulma';",
|
|
427
455
|
"compound": true,
|
|
428
456
|
"propCount": 17,
|
|
429
|
-
"exampleCount":
|
|
457
|
+
"exampleCount": 9
|
|
430
458
|
},
|
|
431
459
|
{
|
|
432
460
|
"name": "Emphasis",
|
|
@@ -544,10 +572,10 @@
|
|
|
544
572
|
"category": "form",
|
|
545
573
|
"purpose": "The `Input` component provides a Bulma-styled text input, supporting colors, sizes, rounded corners, static/read-only state, hover/focus/loading states, and…",
|
|
546
574
|
"slug": "form/input",
|
|
547
|
-
"import": "import { Input, Field, Control } from '@allxsmith/bestax-bulma';",
|
|
575
|
+
"import": "import { Input, Field, Control, Button, Select, Icon } from '@allxsmith/bestax-bulma';",
|
|
548
576
|
"compound": false,
|
|
549
577
|
"propCount": 29,
|
|
550
|
-
"exampleCount":
|
|
578
|
+
"exampleCount": 30
|
|
551
579
|
},
|
|
552
580
|
{
|
|
553
581
|
"name": "Level",
|
|
@@ -593,6 +621,17 @@
|
|
|
593
621
|
"propCount": 4,
|
|
594
622
|
"exampleCount": 6
|
|
595
623
|
},
|
|
624
|
+
{
|
|
625
|
+
"name": "Loader",
|
|
626
|
+
"kind": "component",
|
|
627
|
+
"category": "elements",
|
|
628
|
+
"purpose": "The `Loader` component renders Bulma's `.loader`, a small spinning ring for inline loading states.",
|
|
629
|
+
"slug": "elements/loader",
|
|
630
|
+
"import": "import { Loader } from '@allxsmith/bestax-bulma';",
|
|
631
|
+
"compound": false,
|
|
632
|
+
"propCount": 2,
|
|
633
|
+
"exampleCount": 5
|
|
634
|
+
},
|
|
596
635
|
{
|
|
597
636
|
"name": "Loading",
|
|
598
637
|
"kind": "component",
|
|
@@ -725,6 +764,28 @@
|
|
|
725
764
|
"propCount": 4,
|
|
726
765
|
"exampleCount": 10
|
|
727
766
|
},
|
|
767
|
+
{
|
|
768
|
+
"name": "Popover",
|
|
769
|
+
"kind": "component",
|
|
770
|
+
"category": "components",
|
|
771
|
+
"purpose": "The `Popover` component opens a panel of interactive content, such as a filter form or a set of share options, anchored to the element that toggles it.",
|
|
772
|
+
"slug": "components/popover",
|
|
773
|
+
"import": "import { Popover } from '@allxsmith/bestax-bulma';",
|
|
774
|
+
"compound": true,
|
|
775
|
+
"propCount": 33,
|
|
776
|
+
"exampleCount": 8
|
|
777
|
+
},
|
|
778
|
+
{
|
|
779
|
+
"name": "Portal",
|
|
780
|
+
"kind": "helper",
|
|
781
|
+
"category": "helpers",
|
|
782
|
+
"purpose": "`Portal` renders its children into another part of the page, `document.body` unless `container` says otherwise, so floating content escapes an ancestor's…",
|
|
783
|
+
"slug": "helpers/portal",
|
|
784
|
+
"import": "import { Portal } from '@allxsmith/bestax-bulma';",
|
|
785
|
+
"compound": false,
|
|
786
|
+
"propCount": 0,
|
|
787
|
+
"exampleCount": 3
|
|
788
|
+
},
|
|
728
789
|
{
|
|
729
790
|
"name": "Pre",
|
|
730
791
|
"kind": "component",
|
|
@@ -1037,7 +1098,7 @@
|
|
|
1037
1098
|
"name": "Valid value constants",
|
|
1038
1099
|
"kind": "helper",
|
|
1039
1100
|
"category": "helpers",
|
|
1040
|
-
"purpose": "The
|
|
1101
|
+
"purpose": "The helper tuples enumerate the core accepted values for the shared Bulma helper props — public API for building prop types and validation.",
|
|
1041
1102
|
"slug": "helpers/valid-values",
|
|
1042
1103
|
"import": "import { Valid value constants } from '@allxsmith/bestax-bulma';",
|
|
1043
1104
|
"compound": false,
|
|
@@ -1064,7 +1125,18 @@
|
|
|
1064
1125
|
"import": "import { useBulmaClasses } from '@allxsmith/bestax-bulma';",
|
|
1065
1126
|
"compound": false,
|
|
1066
1127
|
"propCount": 0,
|
|
1067
|
-
"exampleCount":
|
|
1128
|
+
"exampleCount": 45
|
|
1129
|
+
},
|
|
1130
|
+
{
|
|
1131
|
+
"name": "useFocusTrap",
|
|
1132
|
+
"kind": "helper",
|
|
1133
|
+
"category": "helpers",
|
|
1134
|
+
"purpose": "`useFocusTrap` keeps keyboard focus inside a container while it is active: focus moves in when the trap turns on, Tab and Shift+Tab wrap between the first and…",
|
|
1135
|
+
"slug": "helpers/usefocustrap",
|
|
1136
|
+
"import": "import { useFocusTrap } from '@allxsmith/bestax-bulma';",
|
|
1137
|
+
"compound": false,
|
|
1138
|
+
"propCount": 0,
|
|
1139
|
+
"exampleCount": 2
|
|
1068
1140
|
},
|
|
1069
1141
|
{
|
|
1070
1142
|
"name": "usePrefixedClassNames",
|
|
@@ -1297,6 +1369,7 @@
|
|
|
1297
1369
|
"--bulma-dateinput-cell-today-color": "DateTimeInput",
|
|
1298
1370
|
"--bulma-dateinput-day-name-color": "DateTimeInput",
|
|
1299
1371
|
"--bulma-dateinput-day-name-size": "DateTimeInput",
|
|
1372
|
+
"--bulma-dateinput-focus-ring-color": "DateTimeInput",
|
|
1300
1373
|
"--bulma-dateinput-header-padding": "DateTimeInput",
|
|
1301
1374
|
"--bulma-dateinput-min-width": "DateTimeInput",
|
|
1302
1375
|
"--bulma-dateinput-nav-button-size": "DateTimeInput",
|
|
@@ -1666,6 +1739,22 @@
|
|
|
1666
1739
|
"--bulma-picker-popover-radius": "TimeInput",
|
|
1667
1740
|
"--bulma-picker-popover-shadow": "TimeInput",
|
|
1668
1741
|
"--bulma-picker-popover-z-index": "TimeInput",
|
|
1742
|
+
"--bulma-popover-animation-duration": "Popover",
|
|
1743
|
+
"--bulma-popover-background": "Popover",
|
|
1744
|
+
"--bulma-popover-body-padding": "Popover",
|
|
1745
|
+
"--bulma-popover-border-color": "Popover",
|
|
1746
|
+
"--bulma-popover-color": "Popover",
|
|
1747
|
+
"--bulma-popover-footer-gap": "Popover",
|
|
1748
|
+
"--bulma-popover-footer-padding": "Popover",
|
|
1749
|
+
"--bulma-popover-header-color": "Popover",
|
|
1750
|
+
"--bulma-popover-header-padding": "Popover",
|
|
1751
|
+
"--bulma-popover-header-weight": "Popover",
|
|
1752
|
+
"--bulma-popover-max-width": "Popover",
|
|
1753
|
+
"--bulma-popover-min-width": "Popover",
|
|
1754
|
+
"--bulma-popover-offset": "Popover",
|
|
1755
|
+
"--bulma-popover-radius": "Popover",
|
|
1756
|
+
"--bulma-popover-shadow": "Popover",
|
|
1757
|
+
"--bulma-popover-z-index": "Popover",
|
|
1669
1758
|
"--bulma-pre-code-font-size": "Pre",
|
|
1670
1759
|
"--bulma-pre-font-size": "Pre",
|
|
1671
1760
|
"--bulma-pre-padding": "Pre",
|
|
@@ -206,7 +206,7 @@
|
|
|
206
206
|
"name": "loading",
|
|
207
207
|
"type": "boolean",
|
|
208
208
|
"default": "false",
|
|
209
|
-
"description": "Show loading
|
|
209
|
+
"description": "Show a loading spinner in the input. Under `prefers-reduced-motion: reduce` the spinner stops and stays drawn (with bestax's CSS loaded).",
|
|
210
210
|
"required": false,
|
|
211
211
|
"inherited": false,
|
|
212
212
|
"deprecated": false
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"name": "as",
|
|
56
56
|
"type": "React.ElementType",
|
|
57
57
|
"default": null,
|
|
58
|
-
"description": "Element/component to render as. Defaults to `'a'` when `href` is set, else `'figure'`. This also decides whether the avatar is treated as interactive, which is what keeps `role=\"img\"` and the `alt=\"\"` decorative opt-out off a link or button. A custom component counts — a router link takes `to` rather than this component's `href`, so its own props cannot say — while `'a'`, `'button'`, and a custom element given an `href` count for the reason they read. If your custom component renders something that really is just a picture, say so with `role=\"img\"` and it is treated as one, `alt=\"\"` included. A truthy `aria-hidden` says it too, and so do `role=\"presentation\"` and `role=\"none\"` — though ARIA's own conflict resolution drops those two whenever the avatar still carries a name, so prefer `role=\"img\"`. A role claiming the opposite, such as `\"button\"`, says nothing here, and neither does an `href`: that settles it on its own. A genuine `'a'`/`'button'`/`href` avatar keeps its accessible name either way.",
|
|
58
|
+
"description": "Element/component to render as. Defaults to `'a'` when `href` is set, else `'figure'`. This also decides whether the avatar is treated as interactive, which is what keeps `role=\"img\"` and the `alt=\"\"` decorative opt-out off a link or button. A custom component counts — a router link takes `to` rather than this component's `href`, so its own props cannot say — while `'a'`, `'button'`, and a custom element given an `href` count for the reason they read. If your custom component renders something that really is just a picture, say so with `role=\"img\"` and it is treated as one, `alt=\"\"` included. A truthy `aria-hidden` says it too, and so do `role=\"presentation\"` and `role=\"none\"` — though ARIA's own conflict resolution drops those two whenever the avatar still carries a name, so prefer `role=\"img\"`. A role claiming the opposite, such as `\"button\"`, says nothing here, and neither does an `href`: that settles it on its own. A genuine `'a'`/`'button'`/`href` avatar keeps its accessible name either way. `'button'` renders `type=\"button\"` unless you pass `type=\"submit\"` or `type=\"reset\"`, so an avatar inside a form does not submit it.",
|
|
59
59
|
"required": false,
|
|
60
60
|
"inherited": false,
|
|
61
61
|
"deprecated": false
|
|
@@ -137,7 +137,7 @@
|
|
|
137
137
|
"name": "as",
|
|
138
138
|
"type": "React.ElementType",
|
|
139
139
|
"default": null,
|
|
140
|
-
"description": "Element/component to render as. Defaults to `'a'` when `href` is set, else `'figure'`. This also decides whether the avatar is treated as interactive, which is what keeps `role=\"img\"` and the `alt=\"\"` decorative opt-out off a link or button. A custom component counts — a router link takes `to` rather than this component's `href`, so its own props cannot say — while `'a'`, `'button'`, and a custom element given an `href` count for the reason they read. If your custom component renders something that really is just a picture, say so with `role=\"img\"` and it is treated as one, `alt=\"\"` included. A truthy `aria-hidden` says it too, and so do `role=\"presentation\"` and `role=\"none\"` — though ARIA's own conflict resolution drops those two whenever the avatar still carries a name, so prefer `role=\"img\"`. A role claiming the opposite, such as `\"button\"`, says nothing here, and neither does an `href`: that settles it on its own. A genuine `'a'`/`'button'`/`href` avatar keeps its accessible name either way.",
|
|
140
|
+
"description": "Element/component to render as. Defaults to `'a'` when `href` is set, else `'figure'`. This also decides whether the avatar is treated as interactive, which is what keeps `role=\"img\"` and the `alt=\"\"` decorative opt-out off a link or button. A custom component counts — a router link takes `to` rather than this component's `href`, so its own props cannot say — while `'a'`, `'button'`, and a custom element given an `href` count for the reason they read. If your custom component renders something that really is just a picture, say so with `role=\"img\"` and it is treated as one, `alt=\"\"` included. A truthy `aria-hidden` says it too, and so do `role=\"presentation\"` and `role=\"none\"` — though ARIA's own conflict resolution drops those two whenever the avatar still carries a name, so prefer `role=\"img\"`. A role claiming the opposite, such as `\"button\"`, says nothing here, and neither does an `href`: that settles it on its own. A genuine `'a'`/`'button'`/`href` avatar keeps its accessible name either way. `'button'` renders `type=\"button\"` unless you pass `type=\"submit\"` or `type=\"reset\"`, so an avatar inside a form does not submit it.",
|
|
141
141
|
"required": false,
|
|
142
142
|
"inherited": false,
|
|
143
143
|
"deprecated": false
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
{ "title": "Default Button", "code": "<Button>Default Button</Button>" },
|
|
9
9
|
{
|
|
10
10
|
"title": "All Colors",
|
|
11
|
-
"code": "
|
|
11
|
+
"code": "<Buttons>\n {['primary', 'link', 'info', 'success', 'warning', 'danger'].map(color => (\n <Button key={color} color={color}>\n {color.charAt(0).toUpperCase() + color.slice(1)}\n </Button>\n ))}\n</Buttons>"
|
|
12
12
|
},
|
|
13
13
|
{
|
|
14
14
|
"title": "All Sizes",
|
|
@@ -159,7 +159,7 @@
|
|
|
159
159
|
"name": "isLoading",
|
|
160
160
|
"type": "boolean",
|
|
161
161
|
"default": "false",
|
|
162
|
-
"description": "Displays a loading spinner.",
|
|
162
|
+
"description": "Displays a loading spinner. Under `prefers-reduced-motion: reduce` the spinner stops and stays drawn (with bestax's CSS loaded).",
|
|
163
163
|
"required": false,
|
|
164
164
|
"inherited": false,
|
|
165
165
|
"deprecated": false
|
|
@@ -193,7 +193,7 @@
|
|
|
193
193
|
"name": "isLoading",
|
|
194
194
|
"type": "boolean",
|
|
195
195
|
"default": "false",
|
|
196
|
-
"description": "Displays a loading spinner.",
|
|
196
|
+
"description": "Displays a loading spinner. Under `prefers-reduced-motion: reduce` the spinner stops and stays drawn (with bestax's CSS loaded).",
|
|
197
197
|
"required": false,
|
|
198
198
|
"inherited": false,
|
|
199
199
|
"deprecated": false
|
|
@@ -387,7 +387,7 @@
|
|
|
387
387
|
"name": "isLoading",
|
|
388
388
|
"type": "boolean",
|
|
389
389
|
"default": "false",
|
|
390
|
-
"description": "Displays a loading spinner.",
|
|
390
|
+
"description": "Displays a loading spinner. Under `prefers-reduced-motion: reduce` the spinner stops and stays drawn (with bestax's CSS loaded).",
|
|
391
391
|
"required": false,
|
|
392
392
|
"inherited": true,
|
|
393
393
|
"deprecated": false
|
|
@@ -397,7 +397,26 @@
|
|
|
397
397
|
"deprecated": false
|
|
398
398
|
}
|
|
399
399
|
],
|
|
400
|
-
"extraProps": [
|
|
400
|
+
"extraProps": [
|
|
401
|
+
{
|
|
402
|
+
"name": "type",
|
|
403
|
+
"type": "'button' | 'submit' | 'reset'",
|
|
404
|
+
"default": "'button'",
|
|
405
|
+
"description": "Button type. Defaults to `'button'`, so a header icon inside a form does not submit it. Pass `'submit'` or `'reset'` and yours is used; any other value, or a spread carrying `type: undefined`, renders `'button'`.",
|
|
406
|
+
"required": false,
|
|
407
|
+
"inherited": false,
|
|
408
|
+
"deprecated": false
|
|
409
|
+
},
|
|
410
|
+
{
|
|
411
|
+
"name": "aria-label",
|
|
412
|
+
"type": "string",
|
|
413
|
+
"default": "'more options'",
|
|
414
|
+
"description": "Accessible name. Pass your own to replace it. An empty one, or a spread carrying `'aria-label': undefined`, keeps the default rather than leaving the button unnamed.",
|
|
415
|
+
"required": false,
|
|
416
|
+
"inherited": false,
|
|
417
|
+
"deprecated": false
|
|
418
|
+
}
|
|
419
|
+
],
|
|
401
420
|
"catchAll": "All standard <button> attributes and Bulma helper props",
|
|
402
421
|
"types": []
|
|
403
422
|
},
|
|
@@ -117,7 +117,7 @@
|
|
|
117
117
|
"name": "arrow",
|
|
118
118
|
"type": "boolean",
|
|
119
119
|
"default": "true",
|
|
120
|
-
"description": "Show navigation arrows. Default: true.",
|
|
120
|
+
"description": "Show navigation arrows. Default: true. They render `type=\"button\"`, so a carousel inside a form is not submitted by moving between slides.",
|
|
121
121
|
"required": false,
|
|
122
122
|
"inherited": false,
|
|
123
123
|
"deprecated": false
|
|
@@ -135,7 +135,7 @@
|
|
|
135
135
|
"name": "indicator",
|
|
136
136
|
"type": "boolean",
|
|
137
137
|
"default": "true",
|
|
138
|
-
"description": "Show slide indicators. Default: true.",
|
|
138
|
+
"description": "Show slide indicators. Default: true. They render `type=\"button\"`, so a carousel inside a form is not submitted by picking a slide.",
|
|
139
139
|
"required": false,
|
|
140
140
|
"inherited": false,
|
|
141
141
|
"deprecated": false
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ClientOnly",
|
|
3
|
+
"kind": "helper",
|
|
4
|
+
"category": "helpers",
|
|
5
|
+
"slug": "helpers/clientonly",
|
|
6
|
+
"docsUrl": "https://bestax.io/docs/api/helpers/clientonly",
|
|
7
|
+
"examples": [
|
|
8
|
+
{
|
|
9
|
+
"title": "Browser-only content",
|
|
10
|
+
"code": "<ClientOnly fallback={<Skeleton variant=\"lines\" lines={1} />}>\n {() => (\n <Notification color=\"info\">\n Times are shown in{' '}\n <strong>{Intl.DateTimeFormat().resolvedOptions().timeZone}</strong>.\n </Notification>\n )}\n</ClientOnly>"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"title": "A component that needs the browser",
|
|
14
|
+
"code": "<ClientOnly fallback={<Skeleton variant=\"block\" />}>\n <MapWidget center={office} />\n</ClientOnly>"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"title": "A fallback that holds the layout",
|
|
18
|
+
"code": "<ClientOnly fallback={<Skeleton variant=\"lines\" lines={3} />}>\n {() => <RecentlyViewed items={readHistory(localStorage)} />}\n</ClientOnly>"
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"accessibility": "- Content that arrives after hydration is not announced by screen readers on its own. Keep what a reader needs on first load out of `ClientOnly`, and use it for enhancements.\n- Match the fallback's size to the content, so the page doesn't shift under someone who has started reading or scrolling.\n- Assistive technology meets the fallback until it is replaced. An empty [`Skeleton`](../elements/skeleton.md) gives it nothing to read; a text fallback such as \"Loading…\" is read out.",
|
|
22
|
+
"related": ["Modal", "Reveal", "Skeleton"],
|
|
23
|
+
"storybook": "https://bestax.io/storybook/?path=/story/helpers-clientonly--default",
|
|
24
|
+
"summary": "`ClientOnly` renders its children only in the browser, after hydration, and a `fallback` until then, so content that depends on browser-only state doesn't…",
|
|
25
|
+
"import": "import { ClientOnly } from '@allxsmith/bestax-bulma';",
|
|
26
|
+
"doc": "# ClientOnly\n\n## Overview\n\n`ClientOnly` renders its children only in the browser, after hydration, and a `fallback` until then, so content that depends on browser-only state doesn't cause a hydration mismatch.\n\nThe server render and the hydrating client render both show `fallback`, which keeps them identical; the children replace it in the commit that follows. Reach for it when the markup itself would differ between server and browser: the reader's time zone or locale, a value from `localStorage`, the viewport size, a widget that needs `window` to render at all. In an app without server rendering the children show on the first render, so wrapping something in `ClientOnly` costs nothing there.\n\nThe hook underneath, `useIsHydrated`, is exported too, for components that need the answer rather than a wrapper.\n\n---\n\n## Import\n\n```tsx\nimport { ClientOnly, useIsHydrated } from '@allxsmith/bestax-bulma';\n```\n\n---\n\n## Hooks\n\n### useIsHydrated\n\nReturns `false` during server rendering and during the hydrating client render, then `true` from the commit that follows. A component that mounts after hydration (after a route change, or in an app with no server rendering) gets `true` on its first render, so it pays for no extra render.\n\n```tsx\nfunction Greeting() {\n const hydrated = useIsHydrated();\n // localStorage only exists in the browser, so the server render and the\n // hydrating render both show the generic greeting.\n const name = hydrated ? localStorage.getItem('name') : null;\n return <Title size=\"4\">{name ? `Welcome back, ${name}` : 'Welcome'}</Title>;\n}\n```\n\n---\n\n## Usage\n\n### Browser-only content\n\nPass the content as a function and it is called only after hydration, so an expression that reads `window`, `document` or `Intl` state never runs on the server. Plain children work too, but JSX children are evaluated by the component that renders `ClientOnly`, on the server included; a function is what keeps a browser-only expression off the server.\n\n```tsx live\n<ClientOnly fallback={<Skeleton variant=\"lines\" lines={1} />}>\n {() => (\n <Notification color=\"info\">\n Times are shown in{' '}\n <strong>{Intl.DateTimeFormat().resolvedOptions().timeZone}</strong>.\n </Notification>\n )}\n</ClientOnly>\n```\n\n### A component that needs the browser\n\nA component's own render is deferred along with it, so a component child works without the function form.\n\n```tsx\n<ClientOnly fallback={<Skeleton variant=\"block\" />}>\n <MapWidget center={office} />\n</ClientOnly>\n```\n\n### A fallback that holds the layout\n\nWithout a `fallback` nothing renders until hydration, and the content pushes the page down when it arrives. A placeholder of the same size, such as a [`Skeleton`](../elements/skeleton.md), avoids the jump.\n\n```tsx\n<ClientOnly fallback={<Skeleton variant=\"lines\" lines={3} />}>\n {() => <RecentlyViewed items={readHistory(localStorage)} />}\n</ClientOnly>\n```\n\n---\n\n## Accessibility\n\n- Content that arrives after hydration is not announced by screen readers on its own. Keep what a reader needs on first load out of `ClientOnly`, and use it for enhancements.\n- Match the fallback's size to the content, so the page doesn't shift under someone who has started reading or scrolling.\n- Assistive technology meets the fallback until it is replaced. An empty [`Skeleton`](../elements/skeleton.md) gives it nothing to read; a text fallback such as \"Loading…\" is read out.\n\n---\n\n## Related Components\n\n- [`Modal`](../components/modal.md): Its `portal` prop follows the same rule, rendering inline until the page has hydrated.\n- [`Skeleton`](../elements/skeleton.md): A placeholder to pass as `fallback`.\n- [`Reveal`](../components/reveal.md): Renders its final state on the server and animates only in the browser.\n\n---\n\n## Additional Resources\n\n- [Storybook: ClientOnly Stories](https://bestax.io/storybook/?path=/story/helpers-clientonly--default)\n- [React: hydration mismatches](https://react.dev/reference/react-dom/client/hydrateRoot#handling-different-client-and-server-content)\n\n---\n\n## Props\n\n| Prop | Type | Default | Description |\n| ---------- | -------------------------------- | ------- | -------------------------------------------------------------------------------------------------------- |\n| `children` | `ReactNode` \\| `() => ReactNode` | — | Content to render once hydrated. A function is called only then, never on the server. |\n| `fallback` | `ReactNode` | `null` | Rendered on the server and during hydration instead, such as a placeholder the same size as the content. |",
|
|
27
|
+
"parts": [],
|
|
28
|
+
"cssVars": []
|
|
29
|
+
}
|
|
@@ -19,22 +19,18 @@
|
|
|
19
19
|
},
|
|
20
20
|
{
|
|
21
21
|
"title": "Controlled Mode",
|
|
22
|
-
"code": "function example() {\n const [isOpen, setIsOpen] = useState(false);\n\n return (\n <Block>\n <Block mb=\"4\">\n <Button color=\"primary\" onClick={() => setIsOpen(!isOpen)}>\n {isOpen ? 'Close' : 'Open'} Collapse\n </Button>\n <Span ml=\"4\">State: {isOpen ? 'Open' : 'Closed'}</Span>\n </Block>\n <Collapse\n open={isOpen}\n trigger={\n <Block p=\"3\" bgColor=\"white-ter\" style={{ borderRadius: '4px' }}>\n Controlled collapse (
|
|
22
|
+
"code": "function example() {\n const [isOpen, setIsOpen] = useState(false);\n\n return (\n <Block>\n <Block mb=\"4\">\n <Button color=\"primary\" onClick={() => setIsOpen(!isOpen)}>\n {isOpen ? 'Close' : 'Open'} Collapse\n </Button>\n <Span ml=\"4\">State: {isOpen ? 'Open' : 'Closed'}</Span>\n </Block>\n <Collapse\n open={isOpen}\n onOpenChange={setIsOpen}\n trigger={\n <Block p=\"3\" bgColor=\"white-ter\" style={{ borderRadius: '4px' }}>\n Controlled collapse (click here or the button above)\n </Block>\n }\n >\n <Block p=\"3\">\n <Paragraph>This collapse is controlled by external state.</Paragraph>\n </Block>\n </Collapse>\n </Block>\n );\n}"
|
|
23
23
|
},
|
|
24
24
|
{
|
|
25
25
|
"title": "Accordion",
|
|
26
|
-
"code": "function example() {\n const [openIndex, setOpenIndex] = useState(0);\n\n const items = [\n { title: 'Section 1', content: 'Content for section 1.' },\n { title: 'Section 2', content: 'Content for section 2.' },\n { title: 'Section 3', content: 'Content for section 3.' },\n ];\n\n return (\n <
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
"title": "Card Style",
|
|
30
|
-
"code": "function example() {\n return (\n <Collapse\n className=\"collapse is-card\"\n defaultOpen\n trigger={\n <Block className=\"collapse-trigger-header\">\n <Span>Card Collapse</Span>\n <Icon name=\"fas fa-chevron-down\" aria-hidden=\"true\" />\n </Block>\n }\n >\n <Paragraph>\n This collapse is styled like a card with shadow and padding.\n </Paragraph>\n <Paragraph>Perfect for FAQ sections or settings panels.</Paragraph>\n </Collapse>\n );\n}"
|
|
26
|
+
"code": "function example() {\n const [openIndex, setOpenIndex] = useState<number | null>(0);\n\n const items = [\n { title: 'Section 1', content: 'Content for section 1.' },\n { title: 'Section 2', content: 'Content for section 2.' },\n { title: 'Section 3', content: 'Content for section 3.' },\n ];\n\n return (\n <Collapses value={openIndex} onChange={setOpenIndex}>\n {items.map((item, index) => (\n <Collapse\n key={item.title}\n bordered\n trigger={\n <Block\n p=\"4\"\n display=\"flex\"\n justifyContent=\"space-between\"\n alignItems=\"center\"\n >\n <Strong>{item.title}</Strong>\n <Span aria-hidden=\"true\">{openIndex === index ? '−' : '+'}</Span>\n </Block>\n }\n >\n <Paragraph p=\"4\">{item.content}</Paragraph>\n </Collapse>\n ))}\n </Collapses>\n );\n}"
|
|
31
27
|
},
|
|
32
28
|
{
|
|
33
29
|
"title": "FAQ Example",
|
|
34
|
-
"code": "function example() {\n const faqs = [\n {\n q: 'What is Bestax?',\n a: 'Bestax is a React component library built on Bulma.',\n },\n { q: 'How do I install it?', a: 'pnpm add @allxsmith/bestax-bulma' },\n { q: 'Is it free?', a: 'Yes, Bestax is open source and free to use.' },\n ];\n\n const [
|
|
30
|
+
"code": "function example() {\n const faqs = [\n {\n q: 'What is Bestax?',\n a: 'Bestax is a React component library built on Bulma.',\n },\n { q: 'How do I install it?', a: 'pnpm add @allxsmith/bestax-bulma' },\n { q: 'Is it free?', a: 'Yes, Bestax is open source and free to use.' },\n ];\n\n const [open, setOpen] = useState<number[]>([]);\n\n return (\n <Block>\n <Title size=\"5\" mb=\"4\">\n FAQ\n </Title>\n <Collapses multiple value={open} onChange={setOpen}>\n {faqs.map((faq, index) => (\n <Collapse\n key={faq.q}\n bordered\n trigger={\n <Block p=\"4\" display=\"flex\" justifyContent=\"space-between\">\n <Strong>{faq.q}</Strong>\n <Span aria-hidden=\"true\">\n {open.includes(index) ? '▲' : '▼'}\n </Span>\n </Block>\n }\n >\n <Paragraph p=\"4\" textColor=\"grey-dark\">\n {faq.a}\n </Paragraph>\n </Collapse>\n ))}\n </Collapses>\n </Block>\n );\n}"
|
|
35
31
|
}
|
|
36
32
|
],
|
|
37
|
-
"accessibility": "- Trigger has `role=\"button\"` and `tabIndex=\"0\"` for keyboard access\n- Trigger has `aria-expanded` to indicate open/closed state\n- Trigger has `aria-controls` pointing to the content element\n- Content has `aria-hidden` matching the collapsed state\n- Supports keyboard navigation (Enter and Space to toggle)",
|
|
33
|
+
"accessibility": "- Trigger has `role=\"button\"` and `tabIndex=\"0\"` for keyboard access\n- Trigger has `aria-expanded` to indicate open/closed state\n- Trigger has `aria-controls` pointing to the content element\n- Content has `aria-hidden` matching the collapsed state, and is `inert` while closed, so its\n links and fields leave the tab order until it opens (under `fade` and `slide` a closed panel\n is only squeezed to height 0)\n- Supports keyboard navigation (Enter and Space to toggle)",
|
|
38
34
|
"related": [],
|
|
39
35
|
"storybook": null,
|
|
40
36
|
"summary": "The `Collapse` component provides an expandable/collapsible content panel.",
|
|
@@ -51,7 +47,7 @@
|
|
|
51
47
|
"name": "open",
|
|
52
48
|
"type": "boolean",
|
|
53
49
|
"default": null,
|
|
54
|
-
"description": "Controlled open state. If provided, component is controlled.",
|
|
50
|
+
"description": "Controlled open state. If provided, component is controlled, and the trigger only reports through `onOpenChange`. Inside a `Collapses` group, a Collapse that sets `open` stays yours: the group neither overrides it nor closes it when another item opens.",
|
|
55
51
|
"required": false,
|
|
56
52
|
"inherited": false,
|
|
57
53
|
"deprecated": false
|
|
@@ -60,7 +56,7 @@
|
|
|
60
56
|
"name": "defaultOpen",
|
|
61
57
|
"type": "boolean",
|
|
62
58
|
"default": "false",
|
|
63
|
-
"description": "Initial open state for uncontrolled usage.",
|
|
59
|
+
"description": "Initial open state for uncontrolled usage. Ignored inside a `Collapses` group, whose `defaultValue` decides.",
|
|
64
60
|
"required": false,
|
|
65
61
|
"inherited": false,
|
|
66
62
|
"deprecated": false
|
|
@@ -69,7 +65,7 @@
|
|
|
69
65
|
"name": "onOpen",
|
|
70
66
|
"type": "() => void",
|
|
71
67
|
"default": null,
|
|
72
|
-
"description": "
|
|
68
|
+
"description": "Called when the trigger opens the Collapse. Fires only while the Collapse keeps its own state: not when `open` is set, and not when a `Collapses` group manages it. `onOpenChange` reports in every mode.",
|
|
73
69
|
"required": false,
|
|
74
70
|
"inherited": false,
|
|
75
71
|
"deprecated": false
|
|
@@ -78,7 +74,16 @@
|
|
|
78
74
|
"name": "onClose",
|
|
79
75
|
"type": "() => void",
|
|
80
76
|
"default": null,
|
|
81
|
-
"description": "
|
|
77
|
+
"description": "Called when the trigger closes the Collapse. Fires only while the Collapse keeps its own state: not when `open` is set, and not when a `Collapses` group manages it. `onOpenChange` reports in every mode.",
|
|
78
|
+
"required": false,
|
|
79
|
+
"inherited": false,
|
|
80
|
+
"deprecated": false
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"name": "onOpenChange",
|
|
84
|
+
"type": "(open: boolean) => void",
|
|
85
|
+
"default": null,
|
|
86
|
+
"description": "Called with the state the trigger asks for (`true` to open) each time it is clicked or activated with Enter or Space, in every mode. Pair it with `open` to let the trigger drive a controlled Collapse.",
|
|
82
87
|
"required": false,
|
|
83
88
|
"inherited": false,
|
|
84
89
|
"deprecated": false
|