bestax-mcp 0.0.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.
Files changed (144) hide show
  1. package/README.md +90 -0
  2. package/data/catalog.json +1869 -0
  3. package/data/components/Autocomplete.json +604 -0
  4. package/data/components/Avatar.json +220 -0
  5. package/data/components/Avatars.json +294 -0
  6. package/data/components/Badge.json +261 -0
  7. package/data/components/Block.json +105 -0
  8. package/data/components/Box.json +157 -0
  9. package/data/components/Breadcrumb.json +155 -0
  10. package/data/components/Button.json +599 -0
  11. package/data/components/Buttons.json +533 -0
  12. package/data/components/Card.json +506 -0
  13. package/data/components/Carousel.json +512 -0
  14. package/data/components/Cell.json +154 -0
  15. package/data/components/Checkbox.json +176 -0
  16. package/data/components/Checkboxes.json +240 -0
  17. package/data/components/Code.json +128 -0
  18. package/data/components/Collapse.json +218 -0
  19. package/data/components/Column.json +284 -0
  20. package/data/components/Columns.json +542 -0
  21. package/data/components/ConfigProvider.json +16 -0
  22. package/data/components/Container.json +149 -0
  23. package/data/components/Content.json +228 -0
  24. package/data/components/Control.json +484 -0
  25. package/data/components/DateInput.json +872 -0
  26. package/data/components/DateTimeInput.json +952 -0
  27. package/data/components/Delete.json +153 -0
  28. package/data/components/Dialog.json +285 -0
  29. package/data/components/Divider.json +68 -0
  30. package/data/components/Dropdown.json +353 -0
  31. package/data/components/Emphasis.json +99 -0
  32. package/data/components/Field.json +539 -0
  33. package/data/components/Figure.json +143 -0
  34. package/data/components/File.json +403 -0
  35. package/data/components/Footer.json +109 -0
  36. package/data/components/Grid.json +357 -0
  37. package/data/components/Hero.json +340 -0
  38. package/data/components/Icon.json +232 -0
  39. package/data/components/IconText.json +307 -0
  40. package/data/components/Image.json +166 -0
  41. package/data/components/Input.json +583 -0
  42. package/data/components/Level.json +332 -0
  43. package/data/components/Link.json +154 -0
  44. package/data/components/LinkButton.json +247 -0
  45. package/data/components/ListItem.json +101 -0
  46. package/data/components/Loading.json +323 -0
  47. package/data/components/Media.json +345 -0
  48. package/data/components/Menu.json +317 -0
  49. package/data/components/Message.json +303 -0
  50. package/data/components/Modal.json +444 -0
  51. package/data/components/Navbar.json +996 -0
  52. package/data/components/Notification.json +165 -0
  53. package/data/components/Numberinput.json +364 -0
  54. package/data/components/OrderedList.json +189 -0
  55. package/data/components/Pagination.json +619 -0
  56. package/data/components/Panel.json +582 -0
  57. package/data/components/Paragraph.json +107 -0
  58. package/data/components/Pre.json +114 -0
  59. package/data/components/Progress.json +137 -0
  60. package/data/components/Radio.json +164 -0
  61. package/data/components/Radios.json +240 -0
  62. package/data/components/Rate.json +466 -0
  63. package/data/components/Reveal.json +177 -0
  64. package/data/components/Section.json +123 -0
  65. package/data/components/Select.json +526 -0
  66. package/data/components/Sidebar.json +488 -0
  67. package/data/components/Skeleton.json +162 -0
  68. package/data/components/Slider.json +534 -0
  69. package/data/components/Span.json +100 -0
  70. package/data/components/Steps.json +452 -0
  71. package/data/components/Strong.json +105 -0
  72. package/data/components/SubTitle.json +233 -0
  73. package/data/components/Switch.json +291 -0
  74. package/data/components/Table.json +490 -0
  75. package/data/components/Tabs.json +592 -0
  76. package/data/components/Tag.json +197 -0
  77. package/data/components/Taginput.json +587 -0
  78. package/data/components/Tags.json +181 -0
  79. package/data/components/TextArea.json +483 -0
  80. package/data/components/Theme.json +65 -0
  81. package/data/components/TimeInput.json +906 -0
  82. package/data/components/Title.json +240 -0
  83. package/data/components/Toast.json +308 -0
  84. package/data/components/Tooltip.json +212 -0
  85. package/data/components/UnorderedList.json +149 -0
  86. package/data/components/Valid value constants.json +16 -0
  87. package/data/components/classNames.json +65 -0
  88. package/data/components/useBulmaClasses.json +169 -0
  89. package/data/components/usePrefixedClassNames.json +25 -0
  90. package/data/skills/bestax-custom-component/SKILL.md +196 -0
  91. package/data/skills/bestax-custom-component/examples/stat-card.tsx +105 -0
  92. package/data/skills/bestax-custom-component/references/api.md +90 -0
  93. package/data/skills/bestax-custom-component/references/component-catalog.md +149 -0
  94. package/data/skills/bestax-custom-component/references/library-contributor.md +395 -0
  95. package/data/skills/bestax-custom-component/references/patterns.md +136 -0
  96. package/data/skills/bestax-form/SKILL.md +254 -0
  97. package/data/skills/bestax-form/references/api.md +103 -0
  98. package/data/skills/bestax-form/references/patterns.md +210 -0
  99. package/data/skills/bestax-icons/SKILL.md +80 -0
  100. package/data/skills/bestax-icons/examples/icon-usage.tsx +80 -0
  101. package/data/skills/bestax-icons/references/icon-libraries.md +131 -0
  102. package/data/skills/bestax-layout-scaffold/SKILL.md +196 -0
  103. package/data/skills/bestax-layout-scaffold/examples/app-shell.tsx +86 -0
  104. package/data/skills/bestax-layout-scaffold/examples/card-grid.tsx +106 -0
  105. package/data/skills/bestax-layout-scaffold/examples/centered.tsx +56 -0
  106. package/data/skills/bestax-layout-scaffold/examples/content-page.tsx +90 -0
  107. package/data/skills/bestax-layout-scaffold/examples/landing.tsx +122 -0
  108. package/data/skills/bestax-layout-scaffold/references/archetypes.md +246 -0
  109. package/data/skills/bestax-layout-scaffold/references/layout-components.md +269 -0
  110. package/data/skills/bestax-migrate/SKILL.md +78 -0
  111. package/data/skills/bestax-migrate/references/component-map.md +91 -0
  112. package/data/skills/bestax-migrate/references/css-migration.md +100 -0
  113. package/data/skills/bestax-migrate/references/prop-map.md +48 -0
  114. package/data/skills/bestax-migrate/references/unmappables.md +124 -0
  115. package/data/skills/bestax-optimize/SKILL.md +131 -0
  116. package/data/skills/bestax-optimize/references/modular-build.md +173 -0
  117. package/data/skills/bestax-theming/SKILL.md +117 -0
  118. package/data/skills/bestax-theming/examples/dark-mode.tsx +38 -0
  119. package/data/skills/bestax-theming/examples/theme-config.tsx +60 -0
  120. package/data/skills/bestax-theming/references/css-variables.md +466 -0
  121. package/data/skills/bestax-theming/references/themeable-components.md +119 -0
  122. package/data/skills.json +148 -0
  123. package/dist/data.d.ts +131 -0
  124. package/dist/data.d.ts.map +1 -0
  125. package/dist/data.js +111 -0
  126. package/dist/format.d.ts +37 -0
  127. package/dist/format.d.ts.map +1 -0
  128. package/dist/format.js +178 -0
  129. package/dist/helper-props.d.ts +57 -0
  130. package/dist/helper-props.d.ts.map +1 -0
  131. package/dist/helper-props.js +249 -0
  132. package/dist/index.d.ts +3 -0
  133. package/dist/index.d.ts.map +1 -0
  134. package/dist/index.js +18 -0
  135. package/dist/search.d.ts +32 -0
  136. package/dist/search.d.ts.map +1 -0
  137. package/dist/search.js +194 -0
  138. package/dist/server.d.ts +28 -0
  139. package/dist/server.d.ts.map +1 -0
  140. package/dist/server.js +616 -0
  141. package/dist/version.d.ts +29 -0
  142. package/dist/version.d.ts.map +1 -0
  143. package/dist/version.js +147 -0
  144. package/package.json +70 -0
@@ -0,0 +1,254 @@
1
+ ---
2
+ name: bestax-form
3
+ description: Build forms with @allxsmith/bestax-bulma — Field/Control/Label/Help composition, inputs, selects, checkboxes, radios, switches, and advanced controls (Autocomplete, Slider, Numberinput, Rate, Taginput, File, date/time). There is no form/validation library; this skill shows the components and the validate-it-yourself error pattern. Use when building a form, wiring inputs to state, or showing validation/error state.
4
+ license: MIT
5
+ ---
6
+
7
+ # Building forms with bestax-bulma
8
+
9
+ This skill covers the form components in `@allxsmith/bestax-bulma` and how to compose them.
10
+
11
+ **Important:** bestax-bulma ships **no form/validation library** — there is no integration with
12
+ formik, react-hook-form, yup, or zod, and no `useForm`-style hook. You own your form state with
13
+ plain React (`useState` / `useReducer` or any library you choose) and feed validation results
14
+ back via each input's own `color`, `message`, and `messageColor` props on the convenience inputs
15
+ (`Input`, `Select`, `TextArea`, …). Always put validation state on the **input**: `Field` has no
16
+ `message`/`messageColor`, and although `FieldProps` types a `color`, `Field` discards it — it
17
+ renders no class, so setting it looks right and does nothing. (`FieldLabel`/`FieldBody` do honor
18
+ `color`, as the `has-text-*` helper.) See **Validation without a library** below.
19
+
20
+ ## Use when
21
+
22
+ - Building a form out of bestax inputs, selects, checkboxes, switches, or advanced controls.
23
+ - Deciding between the convenience components (`<Input label=… />`) and explicit
24
+ `Field` + `Control` + `*Base` composition.
25
+ - Showing help text and error/success states on fields.
26
+
27
+ To build a brand-new input component (not just use the existing ones), use the
28
+ `bestax-custom-component` skill instead.
29
+
30
+ ## Field / Control / Label / Help composition
31
+
32
+ Bulma forms are a three-tier structure. bestax models it directly:
33
+
34
+ ```
35
+ Field // container + layout (horizontal / grouped / hasAddons)
36
+ ├── label // rendered from Field's `label` prop, or <Field.Label> when horizontal
37
+ └── Control // wraps ONE input; adds icons + loading
38
+ ├── InputBase / SelectBase / TextAreaBase // the raw styled element
39
+ └── <p class="help">…</p> // help / validation message
40
+ ```
41
+
42
+ You rarely write all of this by hand. The convenience components (`Input`, `Select`,
43
+ `TextArea`, …) auto-wrap themselves in `Field` + `Control` when they aren't already inside one,
44
+ using context (`useInsideField` / `useInsideControl`) to detect their surroundings.
45
+
46
+ ```tsx
47
+ // Convenience: one line, auto-wrapped in Field + Control.
48
+ <Input label="Email" type="email" placeholder="you@example.com" />
49
+
50
+ // Explicit composition: full control over layout.
51
+ <Field label="Email">
52
+ <Control iconLeftName="envelope" hasIconsLeft>
53
+ <InputBase type="email" placeholder="you@example.com" />
54
+ </Control>
55
+ </Field>
56
+ ```
57
+
58
+ ### Layout via Field
59
+
60
+ - `horizontal` — label and control side by side (wraps children in `Field.Body`; use
61
+ `Field.Label` / `Field.Body` directly for multi-control rows).
62
+ - `grouped` — `true | 'centered' | 'right' | 'multiline'`, controls in a row.
63
+ - `hasAddons` — `true | 'centered' | 'right'`, attached controls (input + button).
64
+
65
+ ```tsx
66
+ <Field hasAddons>
67
+ <Control isExpanded>
68
+ <InputBase placeholder="Search" />
69
+ </Control>
70
+ <Control>
71
+ <Button color="primary">Go</Button>
72
+ </Control>
73
+ </Field>
74
+ ```
75
+
76
+ ## Component inventory
77
+
78
+ All import from `@allxsmith/bestax-bulma`. Convenience components auto-wrap Field+Control;
79
+ `*Base` components are the raw styled elements for explicit composition.
80
+
81
+ | Component | What it is |
82
+ | ------------------------------------------------------- | ------------------------------------------------------------------------- |
83
+ | `Field`, `Field.Label`, `Field.Body` | Field container + horizontal label/body parts. |
84
+ | `Control` | Wraps one input; left/right icons, `isLoading`, `isExpanded`, `size`. |
85
+ | `Input` / `InputBase` | Text input (convenience / raw). |
86
+ | `Select` / `SelectBase` | Dropdown select. |
87
+ | `TextArea` / `TextAreaBase` | Multiline text. |
88
+ | `Checkbox` / `Checkboxes` | Single checkbox / managed group (array value). |
89
+ | `Radio` / `Radios` | Single radio / managed single-select group. |
90
+ | `Switch` | Toggle switch (`isRounded`, `isThin`, `isOutlined`, RTL). |
91
+ | `File` | File upload input with label/message. |
92
+ | `Autocomplete` | Input with filtered dropdown suggestions + keyboard nav. |
93
+ | `Slider` | Range slider; single/dual thumbs, steps, tooltips, vertical. |
94
+ | `Numberinput` | Numeric input with increment/decrement, min/max, step, stepper. |
95
+ | `Rate` | Star rating; `max`, `precision` (half/quarter), custom icons, `disabled`. |
96
+ | `Taginput` | Tag/chip input; suggestions, confirm keys, closable tags. |
97
+ | `DateInput` / `TimeInput` / `DateTimeInput` (+ `*Base`) | Date / time / datetime pickers. |
98
+
99
+ ## Common props
100
+
101
+ Across the convenience inputs (`Input`, `Select`, `TextArea`, and similar):
102
+
103
+ | Prop | Type | Purpose |
104
+ | -------------------------------- | --------------------------------------------------------------------- | -------------------------------------------------------------------- |
105
+ | `color` | `'primary' \| 'link' \| 'info' \| 'success' \| 'warning' \| 'danger'` | Visual state — use `'danger'` for errors, `'success'` for valid. |
106
+ | `size` | `'small' \| 'medium' \| 'large'` | Input size. |
107
+ | `value` / `onChange` | controlled value + handler | Standard React controlled inputs. |
108
+ | `defaultValue` | uncontrolled initial value | When not controlling state. |
109
+ | `disabled`, `readOnly` | `boolean` | Native states (`readOnly` on `*Base`). |
110
+ | `label` | `ReactNode` | Field label (convenience components; auto-associated via `htmlFor`). |
111
+ | `message` | `ReactNode` | Help / validation text rendered as `<p class="help">`. |
112
+ | `messageColor` | a Bulma color | Colors the help text (`'danger'` for errors). |
113
+ | `iconLeftName` / `iconRightName` | `string` | Icon shortcuts; pair with `hasIconsLeft/Right`. |
114
+ | `isLoading` | `boolean` | Loading indicator on the Control. |
115
+
116
+ Plus the full Bulma **helper props** (`m`, `p`, `textColor`, `display`, …) on every component
117
+ via `useBulmaClasses`.
118
+
119
+ ⚠️ Full-width casing is inconsistent across the library: `Select`, `File`, and `Table` take
120
+ `isFullwidth` (lowercase w); `Button` alone takes `isFullWidth`; `Tabs` takes bare `fullwidth`.
121
+
122
+ The `label` prop on the single-control convenience inputs (`Input`, `Select`, `TextArea`,
123
+ `File`, `Numberinput`, `Slider`, `DateInput`, `TimeInput`, `DateTimeInput`, `Autocomplete`,
124
+ `Taginput`) wires `htmlFor`/`id` automatically — your `id` is used when provided, a
125
+ generated one otherwise, and an explicit `labelProps={{ htmlFor }}` wins. The wiring only
126
+ happens when the component renders its own `Field` (nested inside one, the `label` prop is
127
+ dropped); the date/time pickers skip it in `inline` mode and `Taginput` skips it at
128
+ `maxTags` (no visible input to label). The group inputs (`Checkboxes`, `Radios`, `Rate`)
129
+ associate their `label` too, but group-style: the wrapper gets `role="group"`/`"radiogroup"`
130
+ and `aria-labelledby` pointing at the label. Composing `Field` + bases yourself also
131
+ associates: `Field`'s own `label` wires to a single composed `InputBase`/`SelectBase`/
132
+ `TextAreaBase` (skipped for `grouped`/`hasAddons`). Pass `labelProps={{ htmlFor }}` plus a
133
+ matching `id` only when you want a stable id, or `labelProps={{ htmlFor: undefined }}` to
134
+ opt out — e.g. when the labeled `Field` wraps something that is not one of those bases.
135
+
136
+ ## Convenience vs composed
137
+
138
+ - **Convenience** (`<Input label message … />`) — for typical, single-control fields. Fewer
139
+ lines, auto-wrapping, built-in `message`/`messageColor`. Default to this.
140
+ - **Composed** (`Field` + `Control` + `InputBase`) — when you need grouped controls, addons,
141
+ multiple controls per field, or custom layout. The convenience components detect they're
142
+ already inside a `Field`/`Control` and won't double-wrap, so you can mix the two.
143
+
144
+ ## Validation without a library
145
+
146
+ There is no built-in validation. The pattern is: **own your state, compute errors yourself, and
147
+ reflect them with `color` + `message` + `messageColor`.**
148
+
149
+ ```tsx
150
+ import { useState } from 'react';
151
+ import { Input, Button } from '@allxsmith/bestax-bulma';
152
+
153
+ function SignupForm() {
154
+ const [email, setEmail] = useState('');
155
+ const [touched, setTouched] = useState(false);
156
+
157
+ const valid = /^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(email);
158
+ const error =
159
+ touched && !valid ? 'Please enter a valid email address.' : undefined;
160
+
161
+ return (
162
+ <form
163
+ onSubmit={e => {
164
+ e.preventDefault();
165
+ setTouched(true);
166
+ if (valid) {
167
+ // submit…
168
+ }
169
+ }}
170
+ >
171
+ <Input
172
+ label="Email"
173
+ type="email"
174
+ value={email}
175
+ onChange={e => setEmail(e.target.value)}
176
+ onBlur={() => setTouched(true)}
177
+ color={error ? 'danger' : undefined}
178
+ message={error}
179
+ messageColor={error ? 'danger' : undefined}
180
+ iconLeftName="envelope"
181
+ />
182
+ <Button color="primary" type="submit" mt="3">
183
+ Sign up
184
+ </Button>
185
+ </form>
186
+ );
187
+ }
188
+ ```
189
+
190
+ Rules of thumb:
191
+
192
+ - Set `color="danger"` on the input **and** `messageColor="danger"` on the help text so both the
193
+ control and the message read as an error. Use `'success'` to signal a valid field.
194
+ - Want a different validation library? Wire it up yourself — pass its `value`/`onChange`/error
195
+ string into these props. bestax does not prescribe one.
196
+ - For grouped controls, render the `<p class="help">` via the `message` prop of the convenience
197
+ component, or add it manually inside the `Field` when composing.
198
+
199
+ See `references/api.md` for per-component props and `references/patterns.md` for a full
200
+ multi-field form plus the advanced inputs.
201
+
202
+ ## Reuse the shipped components
203
+
204
+ bestax ships the whole form surface — Input, Select, TextArea, Checkbox(es), Radio(s), Switch,
205
+ File, Autocomplete, Slider, Numberinput, Rate, Taginput, and the date/time inputs (see the
206
+ inventory above). **Compose these; don't hand-roll raw `<input class="input">` markup or
207
+ reinvent a control.** If you think a control is missing, check `bulma-ui/src/index.ts` and
208
+ `docs/docs/api/form/` first — it's probably already there under a different name.
209
+
210
+ ## What happens after submit
211
+
212
+ A form is not finished at the last field. The two components that carry the result are easy to
213
+ miss because Bulma has something that looks close:
214
+
215
+ - **Confirmation** — `Toast`, not `Notification`/`Message`. Mount
216
+ `<ToastContainer position="top-right" />` once at the app root, then call
217
+ `toast.success('Demo booked')` from the submit handler (`.danger` for a failed submit). It
218
+ self-dismisses; a `Notification` is a static element you place and tear down yourself.
219
+ - **"Are you sure?"** — `Dialog`, not `Modal`. Mount `<DialogContainer />` at the root, then
220
+ `if (await dialog.confirm({ title: 'Delete this key?', message: '…', type: 'danger' })) …`.
221
+ It resolves to a boolean, so a destructive action stays one `if` rather than a state machine.
222
+ `Modal` is an empty shell — with it you rebuild the title, message and button row by hand.
223
+
224
+ Both also work as plain controlled components (`<Toast message … onClose>`,
225
+ `<Dialog isOpen … onConfirm onCancel>`) when the state should live in your component.
226
+
227
+ ## Visually inspect it in a browser
228
+
229
+ Forms have layout, spacing, and _stateful_ behavior that types and unit tests don't cover.
230
+ Before calling a form done, **render it and look at it**: run `pnpm storybook` (in `bulma-ui`)
231
+ or the docs dev server, open the form, and check field alignment/spacing, the help-text/error
232
+ states, and the validation flow (submit empty → fields turn `danger` with messages; fix → errors
233
+ clear). If claude-in-chrome or Playwright is available, drive the browser and screenshot the
234
+ valid and error states; otherwise eyeball it yourself. No browser at all (headless CI)? Fall
235
+ back to a production build plus a Node `renderToString` smoke render, grep the emitted HTML
236
+ for the expected classes/states, and say plainly that the visual pass is still owed.
237
+
238
+ ## Checklist
239
+
240
+ - [ ] Built from the shipped form components (no hand-rolled inputs / reinvented controls).
241
+ - [ ] Every label is programmatically associated — the convenience `label` prop, the group
242
+ inputs, and `Field` + single-base composition all do this automatically; pass
243
+ `labelProps={{ htmlFor }}` plus a matching `id` only for a stable id, and label a
244
+ multi-control `Field`'s controls individually (`aria-label`, `aria-labelledby`, or
245
+ a `<label htmlFor>` matching each control's `id`).
246
+ - [ ] Controlled inputs have both `value` and `onChange` (or use `defaultValue` uncontrolled).
247
+ - [ ] Error state shows via `color="danger"` + `message` + `messageColor="danger"`.
248
+ - [ ] Grouped/addon layouts use explicit `Field` + `Control` composition.
249
+ - [ ] No assumption of a built-in validation/form library — state is owned by the app.
250
+ - [ ] Submit feedback is a `Toast` and any "are you sure?" is a `Dialog` — not a hand-placed
251
+ `Notification` or a `Modal` you filled in yourself.
252
+ - [ ] **Rendered and visually inspected in a browser** — layout and the error/validation states
253
+ look right, not just green tests. No browser available? The `renderToString` fallback above
254
+ counts only if you grepped the emitted classes/states **and** said the visual pass is owed.
@@ -0,0 +1,103 @@
1
+ # Reference: form component props
2
+
3
+ All components import from `@allxsmith/bestax-bulma`. Source lives in `bulma-ui/src/form/`.
4
+ Every component also accepts the full Bulma helper props (`m`, `p`, `textColor`, `display`, …)
5
+ via `useBulmaClasses`.
6
+
7
+ ## Field — `form/Field.tsx`
8
+
9
+ Container and layout. Compound parts: `Field.Label`, `Field.Body`.
10
+
11
+ | Prop | Type | Notes |
12
+ | ----------------------- | ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
13
+ | `horizontal` | `boolean` | Label + control side by side. Auto-wraps children in `Field.Body`. |
14
+ | `grouped` | `boolean \| 'centered' \| 'right' \| 'multiline'` | Controls in a row. |
15
+ | `hasAddons` | `boolean \| 'centered' \| 'right'` | Attached controls. |
16
+ | `narrow` | `boolean` | Constrain to content width (inside horizontal bodies). |
17
+ | `label` | `ReactNode` | Convenience label; auto-associates with a single composed `InputBase`/`SelectBase`/`TextAreaBase` (skipped for `grouped`/`hasAddons`). |
18
+ | `labelSize` | `'small' \| 'normal' \| 'medium' \| 'large'` | Label size. |
19
+ | `labelProps` | label attributes | Props for the `<label>`. An explicit `htmlFor` (even `undefined`) takes over the association; otherwise it is set automatically. |
20
+ | `textColor` / `bgColor` | Bulma color | Helper colors for the field. |
21
+
22
+ ## Control — `form/Control.tsx`
23
+
24
+ Wraps a single input; adds icons and loading.
25
+
26
+ | Prop | Type | Notes |
27
+ | -------------------------------- | -------------------------------- | ------------------------------- |
28
+ | `hasIconsLeft` / `hasIconsRight` | `boolean` | Icon containers. |
29
+ | `iconLeft` / `iconRight` | `IconProps` | Full icon config. |
30
+ | `iconLeftName` / `iconRightName` | `string` | Icon name shortcut. |
31
+ | `iconLeftSize` / `iconRightSize` | `'small' \| 'medium' \| 'large'` | Icon size. |
32
+ | `isLoading` | `boolean` | Loading spinner on the control. |
33
+ | `isExpanded` | `boolean` | Fill available width. |
34
+ | `size` | `'small' \| 'medium' \| 'large'` | Control size. |
35
+ | `as` | `'div' \| 'p'` | Root element (default `div`). |
36
+
37
+ ## Input / InputBase — `form/Input.tsx`, `form/InputBase.tsx`
38
+
39
+ `Input` composes `Field` + `Control` + `InputBase`. Beyond `InputBase` props it adds Field-level
40
+ (`label`, `labelSize`, `labelProps`, `horizontal`), Control-level (`iconLeftName`,
41
+ `iconRightName`, `iconLeftSize`, `iconRightSize`, `hasIconsLeft`, `hasIconsRight`, `isLoading`,
42
+ `isExpanded`, `controlSize`), message (`message`, `messageColor`), and container class overrides
43
+ (`fieldClassName`, `controlClassName`).
44
+
45
+ `InputBase` props:
46
+
47
+ | Prop | Type | Notes |
48
+ | ------------------------------------- | --------------------------------------------------------------------- | ------------------------------ |
49
+ | `color` | `'primary' \| 'link' \| 'info' \| 'success' \| 'warning' \| 'danger'` | Visual state. |
50
+ | `size` | `'small' \| 'medium' \| 'large'` | Size. |
51
+ | `isRounded` | `boolean` | Pill shape. |
52
+ | `isStatic` | `boolean` | Static, read-only-styled text. |
53
+ | `isLoading` | `boolean` | Loading state. |
54
+ | `value` / `defaultValue` / `onChange` | — | Standard React input. |
55
+ | `disabled` / `readOnly` | `boolean` | Native states. |
56
+
57
+ `messageColor` accepts `'primary' | 'link' | 'info' | 'success' | 'warning' | 'danger'`.
58
+
59
+ ## Select / SelectBase, TextArea / TextAreaBase
60
+
61
+ Same convenience/raw split as Input. `Select` supports `isLoading` (on the control), `color`,
62
+ `size`, `isRounded`, `isFullwidth` (lowercase w — Button's is `isFullWidth`), `multiple` +
63
+ `multipleSize`, plus the Field/Control/message props. `TextArea` adds `rows` and
64
+ `hasFixedSize`.
65
+
66
+ ## Checkbox / Checkboxes, Radio / Radios
67
+
68
+ - `Checkbox` / `Radio` — single controls with `color`, `size`, `checked`/`defaultChecked`,
69
+ `onChange`, `disabled`.
70
+ - `Checkboxes` — group wrapper managing an **array** value.
71
+ - `Radios` — group wrapper managing a **single** selected value.
72
+
73
+ ## Switch — `form/Switch.tsx`
74
+
75
+ `color`, `size`, `checked`/`defaultChecked`, `onChange`, `isRounded`, `isThin`, `isOutlined`,
76
+ `passiveType`, plus RTL support.
77
+
78
+ ## File — `form/File.tsx`
79
+
80
+ File input with `label`, `message`, color/size, and icon support.
81
+
82
+ ## Advanced inputs
83
+
84
+ | Component | Key props |
85
+ | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
86
+ | `Autocomplete` | `data` (`string[]` or item objects), `value`, `onInput(value)` for typing, `onSelect(item)` for picks, `clearable`, `openOnFocus`, `loading`. |
87
+ | `Slider` | `min`, `max`, `step`, single or dual thumb (`value` number or `[number, number]`), `tooltip` (`'auto' \| 'always' \| 'hidden'`), vertical orientation, `color`, `size`. |
88
+ | `Numberinput` | `value`/`onChange`, `min`, `max`, `step`, increment/decrement buttons, stepper variant, `color`, `size`. |
89
+ | `Rate` | `value`/`onChange`, `max`, `precision` (1 / 0.5 / 0.25), `customIcon` or `iconName`, `showScore`/`showText`/`texts`, `disabled`. |
90
+ | `Taginput` | `value` (array)/`onChange`, autocomplete suggestions, configurable confirm keys, closable tags, `color`, `size`. |
91
+
92
+ ## Date / time inputs
93
+
94
+ `DateInput`, `TimeInput`, `DateTimeInput` (convenience) and their `*Base` variants. Field/Control
95
+ composition like the other convenience inputs, with picker UIs (native with custom fallback).
96
+
97
+ ## Validation-related props (no library)
98
+
99
+ There is no validation engine. The props you use to reflect externally-computed validation are:
100
+
101
+ - `color` — `'danger'` for an error, `'success'` for valid.
102
+ - `message` — the help/validation text (rendered as `<p class="help">`).
103
+ - `messageColor` — colors that help text to match (`'danger'`, `'success'`, …).
@@ -0,0 +1,210 @@
1
+ # Reference: form patterns
2
+
3
+ ## A complete multi-field form (controlled + manual validation)
4
+
5
+ No form library — state is plain React, validation is a function, errors surface through
6
+ `color` + `message` + `messageColor`.
7
+
8
+ ```tsx
9
+ import { useState } from 'react';
10
+ import {
11
+ Input,
12
+ Select,
13
+ TextArea,
14
+ Checkbox,
15
+ Button,
16
+ Field,
17
+ } from '@allxsmith/bestax-bulma';
18
+
19
+ interface Values {
20
+ name: string;
21
+ email: string;
22
+ country: string;
23
+ bio: string;
24
+ agree: boolean;
25
+ }
26
+
27
+ function validate(v: Values) {
28
+ const errors: Partial<Record<keyof Values, string>> = {};
29
+ if (!v.name.trim()) errors.name = 'Name is required.';
30
+ if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(v.email))
31
+ errors.email = 'Enter a valid email.';
32
+ if (!v.country) errors.country = 'Pick a country.';
33
+ if (!v.agree) errors.agree = 'You must accept the terms.';
34
+ return errors;
35
+ }
36
+
37
+ export function ProfileForm() {
38
+ const [values, setValues] = useState<Values>({
39
+ name: '',
40
+ email: '',
41
+ country: '',
42
+ bio: '',
43
+ agree: false,
44
+ });
45
+ const [submitted, setSubmitted] = useState(false);
46
+
47
+ const errors = validate(values);
48
+ const show = (k: keyof Values) => (submitted ? errors[k] : undefined);
49
+ const set = (k: keyof Values, val: Values[keyof Values]) =>
50
+ setValues(prev => ({ ...prev, [k]: val }));
51
+
52
+ return (
53
+ <form
54
+ onSubmit={e => {
55
+ e.preventDefault();
56
+ setSubmitted(true);
57
+ if (Object.keys(errors).length === 0) {
58
+ // submit values…
59
+ }
60
+ }}
61
+ >
62
+ <Input
63
+ label="Name"
64
+ value={values.name}
65
+ onChange={e => set('name', e.target.value)}
66
+ color={show('name') ? 'danger' : undefined}
67
+ message={show('name')}
68
+ messageColor="danger"
69
+ />
70
+
71
+ <Input
72
+ label="Email"
73
+ type="email"
74
+ value={values.email}
75
+ onChange={e => set('email', e.target.value)}
76
+ color={show('email') ? 'danger' : undefined}
77
+ message={show('email')}
78
+ messageColor="danger"
79
+ iconLeftName="envelope"
80
+ />
81
+
82
+ <Select
83
+ label="Country"
84
+ value={values.country}
85
+ onChange={e => set('country', e.target.value)}
86
+ color={show('country') ? 'danger' : undefined}
87
+ message={show('country')}
88
+ messageColor="danger"
89
+ >
90
+ <option value="">Select…</option>
91
+ <option value="us">United States</option>
92
+ <option value="ca">Canada</option>
93
+ </Select>
94
+
95
+ <TextArea
96
+ label="Bio"
97
+ value={values.bio}
98
+ onChange={e => set('bio', e.target.value)}
99
+ rows={3}
100
+ />
101
+
102
+ <Field>
103
+ <Checkbox
104
+ checked={values.agree}
105
+ onChange={e => set('agree', e.target.checked)}
106
+ >
107
+ {' '}
108
+ I accept the terms
109
+ </Checkbox>
110
+ {show('agree') && <p className="help is-danger">{show('agree')}</p>}
111
+ </Field>
112
+
113
+ <Button color="primary" type="submit" mt="4">
114
+ Save
115
+ </Button>
116
+ </form>
117
+ );
118
+ }
119
+ ```
120
+
121
+ Notes:
122
+
123
+ - Validation runs every render as a pure function; `submitted` gates when errors are shown so the
124
+ form isn't red before the user interacts. You could gate per-field on blur instead.
125
+ - For the checkbox the convenience `message` prop isn't used; the help text is rendered manually
126
+ inside the `Field` — a good illustration of dropping to composition when needed.
127
+
128
+ ## Grouped controls and addons
129
+
130
+ ```tsx
131
+ // Search box: input + button attached.
132
+ <Field hasAddons>
133
+ <Control isExpanded>
134
+ <InputBase placeholder="Search" />
135
+ </Control>
136
+ <Control>
137
+ <Button color="primary">Search</Button>
138
+ </Control>
139
+ </Field>
140
+
141
+ // Two controls on one row.
142
+ <Field grouped>
143
+ <Control>
144
+ <InputBase placeholder="First" />
145
+ </Control>
146
+ <Control>
147
+ <InputBase placeholder="Last" />
148
+ </Control>
149
+ </Field>
150
+ ```
151
+
152
+ ## Horizontal field with explicit label/body
153
+
154
+ ```tsx
155
+ <Field horizontal>
156
+ <Field.Label size="normal">Email</Field.Label>
157
+ <Field.Body>
158
+ <Control iconLeftName="envelope" hasIconsLeft>
159
+ <InputBase type="email" placeholder="you@example.com" />
160
+ </Control>
161
+ </Field.Body>
162
+ </Field>
163
+ ```
164
+
165
+ ## Advanced inputs
166
+
167
+ These are controlled the same way — own the value, pass `value`/`onChange`.
168
+
169
+ ```tsx
170
+ // Autocomplete — onInput fires on typing, onSelect when a suggestion is chosen.
171
+ const [city, setCity] = useState('');
172
+ <Autocomplete
173
+ value={city}
174
+ onInput={setCity}
175
+ onSelect={item =>
176
+ setCity(typeof item === 'string' ? item : (item?.value ?? ''))
177
+ }
178
+ data={['Austin', 'Boston', 'Chicago']}
179
+ openOnFocus
180
+ />;
181
+
182
+ // Slider (single and dual thumb)
183
+ const [volume, setVolume] = useState(50);
184
+ <Slider value={volume} onChange={setVolume} min={0} max={100} tooltip="auto" />;
185
+
186
+ const [range, setRange] = useState<[number, number]>([20, 80]);
187
+ <Slider range value={range} onChange={setRange} min={0} max={100} />;
188
+
189
+ // Numberinput
190
+ const [qty, setQty] = useState(1);
191
+ <Numberinput value={qty} onChange={setQty} min={1} max={10} step={1} />;
192
+
193
+ // Rate
194
+ const [stars, setStars] = useState(3);
195
+ <Rate value={stars} onChange={setStars} max={5} />;
196
+
197
+ // Taginput — tags can be strings or { value, label } objects; onChange yields TaginputTag[].
198
+ const [tags, setTags] = useState<string[]>(['react']);
199
+ <Taginput
200
+ value={tags}
201
+ onChange={next =>
202
+ setTags(next.map(t => (typeof t === 'string' ? t : t.value)))
203
+ }
204
+ data={['react', 'bulma', 'ts']}
205
+ />;
206
+ ```
207
+
208
+ Each renders inside Bulma's field/control structure already, so wrap them in a `Field` only when
209
+ you need a label or grouped layout. Reflect validation on them with the same `color` /
210
+ `message` / `messageColor` approach used for text inputs.
@@ -0,0 +1,80 @@
1
+ ---
2
+ name: bestax-icons
3
+ description: Use icons in an app built with @allxsmith/bestax-bulma — the Icon/IconText components and the five supported libraries (Font Awesome, Material Design Icons, Ionicons, Google Material Icons, Material Symbols). Use when adding an icon, choosing or configuring the app-wide icon library, fixing an icon that renders blank, pairing icons with text, or making icons accessible (decorative vs labeled).
4
+ license: MIT
5
+ ---
6
+
7
+ # Icons with @allxsmith/bestax-bulma
8
+
9
+ `Icon` renders a Bulma icon container (`span.icon`) around a glyph from any of five icon
10
+ libraries behind one normalized API. `IconText` pairs icons with text. The library ships **no
11
+ icon fonts** — the chosen library's package (or CDN script) must be installed in the app.
12
+
13
+ ## Quick start
14
+
15
+ ```tsx
16
+ import { ConfigProvider, Icon, IconText } from '@allxsmith/bestax-bulma';
17
+
18
+ // Set the library ONCE at the app root; <Icon> then never needs `library`.
19
+ <ConfigProvider iconLibrary="fa">
20
+ <App />
21
+ </ConfigProvider>;
22
+
23
+ // Inside the app:
24
+ <Icon name="rocket" ariaLabel="Launch" />;
25
+ <IconText iconProps={{ name: 'star', 'aria-hidden': 'true' }}>
26
+ Starred
27
+ </IconText>;
28
+ ```
29
+
30
+ ## The five libraries
31
+
32
+ | Library | `iconLibrary` / `library` value | Name format | Example `name` |
33
+ | ---------------------- | ------------------------------- | ---------------------------- | --------------- |
34
+ | Font Awesome (default) | `'fa'` | kebab-case, no `fa-` prefix | `rocket` |
35
+ | Material Design Icons | `'mdi'` | kebab-case, no `mdi-` prefix | `rocket-launch` |
36
+ | Ionicons | `'ion'` | kebab-case | `rocket` |
37
+ | Google Material Icons | `'material-icons'` | snake_case (a text ligature) | `rocket_launch` |
38
+ | Material Symbols | `'material-symbols'` | snake_case (a text ligature) | `rocket_launch` |
39
+
40
+ ⚠️ **The Ionicons value is `'ion'`, not `'ionicons'`.** The `npm create bestax` scaffold's
41
+ `--icon ionicons` flag maps to `iconLibrary="ion"` — passing `'ionicons'` to `ConfigProvider`
42
+ or `library` silently renders nothing.
43
+
44
+ **The same glyph has a different name per library** (`rocket` vs `rocket-launch` vs
45
+ `rocket_launch`). When an icon renders blank, the name format for the active library is the
46
+ first thing to check. A redundant `fa-`/`mdi-` prefix in `name` is tolerated (stripped), but
47
+ don't rely on it.
48
+
49
+ ## Styling
50
+
51
+ - `size` — `'small' | 'medium' | 'large'` sizes the Bulma **container** (`is-small` ≈ 1rem,
52
+ `is-medium` ≈ 2rem, `is-large` ≈ 3rem box). To scale the **glyph**, use `features`
53
+ (Font Awesome `'fa-lg'`/`'fa-2x'`) or a Bulma text-size class (`'is-size-3'`).
54
+ - `variant` — per-library style: Font Awesome `solid` (default) / `regular` / `brands` /
55
+ `light` / `duotone` / `thin`; Material Icons `filled` (default) / `outlined` / `round` /
56
+ `sharp`; Material Symbols `outlined` (default) / `rounded` / `sharp`; Ionicons `outline` /
57
+ `sharp`. MDI has no variants. Note Material **Icons** uses `round`, Material **Symbols**
58
+ uses `rounded`.
59
+ - `features` — extra library classes, string or array: `'fa-spin'`, `['fa-lg', 'fa-border']`.
60
+ - Color via the helper props: `textColor="primary"`, `textColor="danger"`, etc.
61
+
62
+ ## Accessibility
63
+
64
+ Every `Icon` renders `aria-label` (default `"icon"`), set via its camelCase `ariaLabel` prop.
65
+ Only a few components declare that prop (`Icon`, `Delete`, `Slider`, `Carousel`) — everything
66
+ else takes the standard `aria-label` attribute, e.g. `<Navbar.Burger aria-label="menu" />`.
67
+
68
+ - **Meaningful icon** (stands alone, conveys information): pass a descriptive
69
+ `ariaLabel="Delete item"`.
70
+ - **Decorative icon** (next to visible text that says the same thing, e.g. inside `IconText`
71
+ or a labeled `Button`): hide it from screen readers with `aria-hidden`:
72
+ `<Icon name="check" aria-hidden="true" />` — otherwise "icon" (or a duplicate label) is
73
+ announced alongside the text.
74
+
75
+ ## References
76
+
77
+ - `references/icon-libraries.md` — per-library setup (install/import/CDN), the full
78
+ name-format and variant tables, `features` values, and the blank-icon troubleshooting list.
79
+ - `examples/icon-usage.tsx` — runnable example: ConfigProvider setup, sizes, variants,
80
+ colors, IconText, and decorative-vs-labeled patterns.