create-bestax 2.2.0 → 3.1.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/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +2 -0
- package/dist/constants.d.ts +3 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +27 -6
- package/dist/project-creator.d.ts +2 -0
- package/dist/project-creator.d.ts.map +1 -1
- package/dist/project-creator.js +27 -3
- package/dist/prompts.d.ts +1 -0
- package/dist/prompts.d.ts.map +1 -1
- package/dist/prompts.js +9 -0
- package/package.json +4 -3
- package/templates/skills/bestax-custom-component/SKILL.md +389 -0
- package/templates/skills/bestax-custom-component/references/api.md +77 -0
- package/templates/skills/bestax-custom-component/references/patterns.md +133 -0
- package/templates/skills/bestax-form/SKILL.md +209 -0
- package/templates/skills/bestax-form/references/api.md +102 -0
- package/templates/skills/bestax-form/references/patterns.md +210 -0
- package/templates/skills/bestax-layout-scaffold/SKILL.md +66 -0
- package/templates/skills/bestax-layout-scaffold/examples/app-shell.tsx +80 -0
- package/templates/skills/bestax-layout-scaffold/examples/card-grid.tsx +98 -0
- package/templates/skills/bestax-layout-scaffold/examples/centered.tsx +56 -0
- package/templates/skills/bestax-layout-scaffold/examples/landing.tsx +77 -0
- package/templates/skills/bestax-layout-scaffold/references/archetypes.md +183 -0
- package/templates/skills/bestax-layout-scaffold/references/layout-components.md +181 -0
- package/templates/skills/bestax-theming/SKILL.md +73 -0
- package/templates/skills/bestax-theming/examples/dark-mode.tsx +38 -0
- package/templates/skills/bestax-theming/examples/theme-config.tsx +58 -0
- package/templates/skills/bestax-theming/references/css-variables.md +130 -0
- package/templates/skills/bestax-theming/references/themeable-components.md +74 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Reference: helper APIs for building components
|
|
2
|
+
|
|
3
|
+
The shared helpers live in `bulma-ui/src/helpers/`. Import them from there in components.
|
|
4
|
+
|
|
5
|
+
## `useBulmaClasses(props)` — `helpers/useBulmaClasses.tsx`
|
|
6
|
+
|
|
7
|
+
Turns Bulma helper props into a class string and returns the leftover (non-helper) props.
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
const { bulmaHelperClasses, rest } = useBulmaClasses(props);
|
|
11
|
+
// bulmaHelperClasses: e.g. 'has-text-primary is-size-3 m-3'
|
|
12
|
+
// rest: every prop that was NOT a recognized helper (safe to spread on the DOM)
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
`BulmaClassesProps` is the union of all helper prop groups, composed from per-concern hooks
|
|
16
|
+
that can also be used on their own:
|
|
17
|
+
|
|
18
|
+
| Group | Hook | Representative props |
|
|
19
|
+
| ---------- | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
|
|
20
|
+
| Color | `useColorClasses` | `color`, `colorShade`, `backgroundColor`, `backgroundColorShade` |
|
|
21
|
+
| Spacing | `useSpacingClasses` | `m`, `mt`, `mr`, `mb`, `ml`, `mx`, `my`, `p`, `pt`, `pr`, `pb`, `pl`, `px`, `py` |
|
|
22
|
+
| Typography | `useTypographyClasses` | `textSize`, `textAlign`, `textTransform`, `textWeight`, `fontFamily` (+ responsive variants) |
|
|
23
|
+
| Visibility | `useVisibilityClasses` | `display`, `visibility` (+ per-viewport variants) |
|
|
24
|
+
| Flexbox | `useFlexboxClasses` | `flexDirection`, `flexWrap`, `justifyContent`, `alignItems`, `alignContent`, `alignSelf`, `flexGrow`, `flexShrink` |
|
|
25
|
+
| Other | `useOtherClasses` | `float`, `overflow`, `radius`, `shadow`, `interaction`, `cursor`, `skeleton`, `clearfix`, `relative`, `fullHeight`, `responsive` |
|
|
26
|
+
|
|
27
|
+
Because the component destructures these into `bulmaHelperClasses`, callers get the full Bulma
|
|
28
|
+
helper surface for free on every component, and `rest` stays clean for DOM spreading.
|
|
29
|
+
|
|
30
|
+
## `classNames(...)` and friends — `helpers/classNames.ts`
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
classNames('foo', ['bar', { baz: true }], { qux: false }); // => 'foo bar baz'
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Accepts strings, numbers, arrays, and objects (truthy keys included); flattens recursively and
|
|
37
|
+
de-dupes. Related exports:
|
|
38
|
+
|
|
39
|
+
- `usePrefixedClassNames(...args)` — **use this in components.** Reads `classPrefix` from the
|
|
40
|
+
`Config` context and prefixes every class. With `classPrefix="bulma-"`,
|
|
41
|
+
`usePrefixedClassNames('button', { 'is-primary': true })` → `'bulma-button bulma-is-primary'`.
|
|
42
|
+
- `prefixedClassNames(prefix, ...args)` — non-hook form; pass `undefined` for no prefix.
|
|
43
|
+
- `createPrefixedClassNames(prefix)` — factory returning a bound `classNames`.
|
|
44
|
+
|
|
45
|
+
## Valid-value constants — `helpers/bulmaClassHelpers.ts`
|
|
46
|
+
|
|
47
|
+
Re-exported through `useBulmaClasses`. Use them to type component-specific props and to drive
|
|
48
|
+
Storybook `argTypes`/tests:
|
|
49
|
+
|
|
50
|
+
`validColors`, `validColorShades`, `validSizes`, `validTextSizes`, `validAlignments`,
|
|
51
|
+
`validTextTransforms`, `validTextWeights`, `validFontFamilies`, `validDisplays`,
|
|
52
|
+
`validVisibilities`, `validFlexDirections`, `validFlexWraps`, `validJustifyContents`,
|
|
53
|
+
`validAlignContents`, `validAlignItems`, `validAlignSelfs`, `validFlexGrowShrink`,
|
|
54
|
+
`validViewports`.
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
export type MyColor = (typeof validColors)[number];
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## `Config` / `Theme` — `helpers/Config.tsx`, `helpers/Theme.tsx`
|
|
61
|
+
|
|
62
|
+
`Config` provides the runtime `classPrefix` consumed by `usePrefixedClassNames` (opt-in class
|
|
63
|
+
prefixing to avoid collisions). `Theme` overrides `--bulma-*` custom properties at runtime —
|
|
64
|
+
which is exactly why component SCSS must register its vars via `cv.register-vars` rather than
|
|
65
|
+
hard-coding values.
|
|
66
|
+
|
|
67
|
+
## SCSS utilities — from the `bulma` package
|
|
68
|
+
|
|
69
|
+
```scss
|
|
70
|
+
@use 'bulma/sass/utilities/initial-variables' as iv; // iv.$class-prefix
|
|
71
|
+
@use 'bulma/sass/utilities/css-variables' as cv; // cv.getVar, cv.register-vars
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
- `iv.$class-prefix` — the configurable class prefix; prepend to every selector.
|
|
75
|
+
- `cv.getVar("name")` — emits `var(--bulma-name)`; use for both Bulma vars (`"primary"`,
|
|
76
|
+
`"radius"`, `"scheme-main"`, `"text"`) and your own registered vars.
|
|
77
|
+
- `cv.register-vars((...))` — declares `--bulma-*` custom properties on the current selector.
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Reference: Dialog, the canonical worked example
|
|
2
|
+
|
|
3
|
+
`Dialog` is the library's reference implementation of the custom-component pattern. Read the
|
|
4
|
+
real files alongside this:
|
|
5
|
+
|
|
6
|
+
- `bulma-ui/src/components/Dialog.tsx`
|
|
7
|
+
- `bulma-ui/src/scss/components/_dialog.scss`
|
|
8
|
+
- `bulma-ui/src/components/Dialog.stories.tsx`
|
|
9
|
+
- `bulma-ui/src/components/__tests__/Dialog.test.tsx`
|
|
10
|
+
- `docs/docs/api/components/dialog.md`
|
|
11
|
+
|
|
12
|
+
## What Dialog demonstrates
|
|
13
|
+
|
|
14
|
+
### Props interface
|
|
15
|
+
|
|
16
|
+
```tsx
|
|
17
|
+
export type DialogType = 'default' | 'success' | 'danger' | 'warning' | 'info';
|
|
18
|
+
|
|
19
|
+
export interface DialogProps
|
|
20
|
+
extends
|
|
21
|
+
Omit<React.HTMLAttributes<HTMLDivElement>, 'color'>,
|
|
22
|
+
Omit<BulmaClassesProps, 'color'> {
|
|
23
|
+
isOpen: boolean;
|
|
24
|
+
title?: string;
|
|
25
|
+
message: string | React.ReactNode;
|
|
26
|
+
type?: DialogType;
|
|
27
|
+
confirmText?: string;
|
|
28
|
+
cancelText?: string;
|
|
29
|
+
onConfirm?: () => void;
|
|
30
|
+
onCancel?: () => void;
|
|
31
|
+
showCancel?: boolean;
|
|
32
|
+
canCancel?: boolean;
|
|
33
|
+
focusCancel?: boolean;
|
|
34
|
+
icon?: React.ReactNode;
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
It omits `color` from both `HTMLAttributes` and `BulmaClassesProps` and exposes its own typed
|
|
39
|
+
`type` variant instead — the standard move when a component has bespoke color/variant semantics.
|
|
40
|
+
|
|
41
|
+
### Render body
|
|
42
|
+
|
|
43
|
+
```tsx
|
|
44
|
+
export const Dialog = forwardRef<HTMLDivElement, DialogProps>(
|
|
45
|
+
(
|
|
46
|
+
{ isOpen, title, message, type = 'default', /* ... */ className, ...props },
|
|
47
|
+
ref
|
|
48
|
+
) => {
|
|
49
|
+
const { bulmaHelperClasses, rest } = useBulmaClasses(props);
|
|
50
|
+
const dialogClasses = usePrefixedClassNames('dialog', {
|
|
51
|
+
[`is-${type}`]: type !== 'default',
|
|
52
|
+
});
|
|
53
|
+
const combined = classNames(dialogClasses, bulmaHelperClasses, className);
|
|
54
|
+
// ...keyboard handling, focus management, scroll lock, render via <Modal>
|
|
55
|
+
}
|
|
56
|
+
);
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Note the order — `usePrefixedClassNames` for the component's own classes, then `classNames`
|
|
60
|
+
merges them with the helper classes and the caller's `className`. `rest` (not `props`) is what
|
|
61
|
+
gets spread onto the DOM node.
|
|
62
|
+
|
|
63
|
+
### SCSS
|
|
64
|
+
|
|
65
|
+
`_dialog.scss` is the model for the CSS-variable pattern:
|
|
66
|
+
|
|
67
|
+
```scss
|
|
68
|
+
@use 'bulma/sass/utilities/initial-variables' as iv;
|
|
69
|
+
@use 'bulma/sass/utilities/css-variables' as cv;
|
|
70
|
+
|
|
71
|
+
$dialog-width: 420px !default;
|
|
72
|
+
$dialog-radius: cv.getVar('radius') !default;
|
|
73
|
+
$dialog-background: cv.getVar('scheme-main') !default;
|
|
74
|
+
$dialog-title-color: cv.getVar('text-strong') !default;
|
|
75
|
+
|
|
76
|
+
.#{iv.$class-prefix}dialog {
|
|
77
|
+
@include cv.register-vars(
|
|
78
|
+
(
|
|
79
|
+
'dialog-width': #{$dialog-width},
|
|
80
|
+
'dialog-radius': #{$dialog-radius},
|
|
81
|
+
'dialog-background': #{$dialog-background},
|
|
82
|
+
'dialog-title-color': #{$dialog-title-color},
|
|
83
|
+
)
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.#{iv.$class-prefix}dialog {
|
|
88
|
+
width: cv.getVar('dialog-width');
|
|
89
|
+
background-color: cv.getVar('dialog-background');
|
|
90
|
+
border-radius: cv.getVar('dialog-radius');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Variant: colorize the header per type, reusing Bulma's color vars.
|
|
94
|
+
.#{iv.$class-prefix}dialog.#{iv.$class-prefix}is-success
|
|
95
|
+
.#{iv.$class-prefix}dialog-header {
|
|
96
|
+
color: cv.getVar('success');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
@media (prefers-reduced-motion: reduce) {
|
|
100
|
+
.#{iv.$class-prefix}dialog {
|
|
101
|
+
animation: none;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Takeaways:
|
|
107
|
+
|
|
108
|
+
1. Local layout values (`$dialog-width`) and Bulma references (`cv.getVar("radius")`) both get a
|
|
109
|
+
`!default` SCSS var, then are registered so they're overridable at runtime.
|
|
110
|
+
2. Multi-part components (`-header`, `-body`, `-footer`, `-title`, `-icon`) prefix **every**
|
|
111
|
+
sub-selector with `iv.$class-prefix`.
|
|
112
|
+
3. Variant classes (`is-success`, etc.) are also prefixed, and reuse Bulma's registered color
|
|
113
|
+
vars (`cv.getVar("success")`) rather than hard-coded hex.
|
|
114
|
+
|
|
115
|
+
### Beyond the basics
|
|
116
|
+
|
|
117
|
+
Dialog also shows optional patterns you can borrow when relevant:
|
|
118
|
+
|
|
119
|
+
- An **imperative API** (`dialog.alert`, `dialog.confirm`, `dialog.close`) plus a
|
|
120
|
+
`DialogContainer` for programmatic mounting, exported from the same module.
|
|
121
|
+
- **Accessibility**: `role="alertdialog"`, Escape-to-cancel, and focus management on open.
|
|
122
|
+
- **Body scroll lock** via a module-level ref count so chained/overlapping dialogs behave.
|
|
123
|
+
|
|
124
|
+
These are not required for every component — start from the simple template in `SKILL.md` and
|
|
125
|
+
add only what your component needs.
|
|
126
|
+
|
|
127
|
+
## Other components worth reading for variety
|
|
128
|
+
|
|
129
|
+
- `Switch`, `Slider`, `Rate` — components with their own typed `color`/`size`/variant unions.
|
|
130
|
+
- `Carousel`, `Tabs` — components with internal state and sub-elements.
|
|
131
|
+
|
|
132
|
+
All of them follow the same `useBulmaClasses` + `usePrefixedClassNames` + `classNames` spine and
|
|
133
|
+
the same SCSS register-vars/getVar convention shown above.
|
|
@@ -0,0 +1,209 @@
|
|
|
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 into the components via the `color`, `message`, and `messageColor` props. See
|
|
15
|
+
**Validation without a library** below.
|
|
16
|
+
|
|
17
|
+
## Use when
|
|
18
|
+
|
|
19
|
+
- Building a form out of bestax inputs, selects, checkboxes, switches, or advanced controls.
|
|
20
|
+
- Deciding between the convenience components (`<Input label=… />`) and explicit
|
|
21
|
+
`Field` + `Control` + `*Base` composition.
|
|
22
|
+
- Showing help text and error/success states on fields.
|
|
23
|
+
|
|
24
|
+
To build a brand-new input component (not just use the existing ones), use the
|
|
25
|
+
`bestax-custom-component` skill instead.
|
|
26
|
+
|
|
27
|
+
## Field / Control / Label / Help composition
|
|
28
|
+
|
|
29
|
+
Bulma forms are a three-tier structure. bestax models it directly:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
Field // container + layout (horizontal / grouped / hasAddons)
|
|
33
|
+
├── label // rendered from Field's `label` prop, or <Field.Label> when horizontal
|
|
34
|
+
└── Control // wraps ONE input; adds icons + loading
|
|
35
|
+
├── InputBase / SelectBase / TextAreaBase // the raw styled element
|
|
36
|
+
└── <p class="help">…</p> // help / validation message
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
You rarely write all of this by hand. The convenience components (`Input`, `Select`,
|
|
40
|
+
`TextArea`, …) auto-wrap themselves in `Field` + `Control` when they aren't already inside one,
|
|
41
|
+
using context (`useInsideField` / `useInsideControl`) to detect their surroundings.
|
|
42
|
+
|
|
43
|
+
```tsx
|
|
44
|
+
// Convenience: one line, auto-wrapped in Field + Control.
|
|
45
|
+
<Input label="Email" type="email" placeholder="you@example.com" />
|
|
46
|
+
|
|
47
|
+
// Explicit composition: full control over layout.
|
|
48
|
+
<Field label="Email">
|
|
49
|
+
<Control iconLeftName="envelope" hasIconsLeft>
|
|
50
|
+
<InputBase type="email" placeholder="you@example.com" />
|
|
51
|
+
</Control>
|
|
52
|
+
</Field>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Layout via Field
|
|
56
|
+
|
|
57
|
+
- `horizontal` — label and control side by side (wraps children in `Field.Body`; use
|
|
58
|
+
`Field.Label` / `Field.Body` directly for multi-control rows).
|
|
59
|
+
- `grouped` — `true | 'centered' | 'right' | 'multiline'`, controls in a row.
|
|
60
|
+
- `hasAddons` — `true | 'centered' | 'right'`, attached controls (input + button).
|
|
61
|
+
|
|
62
|
+
```tsx
|
|
63
|
+
<Field hasAddons>
|
|
64
|
+
<Control isExpanded>
|
|
65
|
+
<InputBase placeholder="Search" />
|
|
66
|
+
</Control>
|
|
67
|
+
<Control>
|
|
68
|
+
<Button color="primary">Go</Button>
|
|
69
|
+
</Control>
|
|
70
|
+
</Field>
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Component inventory
|
|
74
|
+
|
|
75
|
+
All import from `@allxsmith/bestax-bulma`. Convenience components auto-wrap Field+Control;
|
|
76
|
+
`*Base` components are the raw styled elements for explicit composition.
|
|
77
|
+
|
|
78
|
+
| Component | What it is |
|
|
79
|
+
| ------------------------------------------------------- | ------------------------------------------------------------------------- |
|
|
80
|
+
| `Field`, `Field.Label`, `Field.Body` | Field container + horizontal label/body parts. |
|
|
81
|
+
| `Control` | Wraps one input; left/right icons, `isLoading`, `isExpanded`, `size`. |
|
|
82
|
+
| `Input` / `InputBase` | Text input (convenience / raw). |
|
|
83
|
+
| `Select` / `SelectBase` | Dropdown select. |
|
|
84
|
+
| `TextArea` / `TextAreaBase` | Multiline text. |
|
|
85
|
+
| `Checkbox` / `Checkboxes` | Single checkbox / managed group (array value). |
|
|
86
|
+
| `Radio` / `Radios` | Single radio / managed single-select group. |
|
|
87
|
+
| `Switch` | Toggle switch (`isRounded`, `isThin`, `isOutlined`, RTL). |
|
|
88
|
+
| `File` | File upload input with label/message. |
|
|
89
|
+
| `Autocomplete` | Input with filtered dropdown suggestions + keyboard nav. |
|
|
90
|
+
| `Slider` | Range slider; single/dual thumbs, steps, tooltips, vertical. |
|
|
91
|
+
| `Numberinput` | Numeric input with increment/decrement, min/max, step, stepper. |
|
|
92
|
+
| `Rate` | Star rating; `max`, `precision` (half/quarter), custom icons, `disabled`. |
|
|
93
|
+
| `Taginput` | Tag/chip input; suggestions, confirm keys, closable tags. |
|
|
94
|
+
| `DateInput` / `TimeInput` / `DateTimeInput` (+ `*Base`) | Date / time / datetime pickers. |
|
|
95
|
+
|
|
96
|
+
## Common props
|
|
97
|
+
|
|
98
|
+
Across the convenience inputs (`Input`, `Select`, `TextArea`, and similar):
|
|
99
|
+
|
|
100
|
+
| Prop | Type | Purpose |
|
|
101
|
+
| -------------------------------- | --------------------------------------------------------------------- | ---------------------------------------------------------------- |
|
|
102
|
+
| `color` | `'primary' \| 'link' \| 'info' \| 'success' \| 'warning' \| 'danger'` | Visual state — use `'danger'` for errors, `'success'` for valid. |
|
|
103
|
+
| `size` | `'small' \| 'medium' \| 'large'` | Input size. |
|
|
104
|
+
| `value` / `onChange` | controlled value + handler | Standard React controlled inputs. |
|
|
105
|
+
| `defaultValue` | uncontrolled initial value | When not controlling state. |
|
|
106
|
+
| `disabled`, `readOnly` | `boolean` | Native states (`readOnly` on `*Base`). |
|
|
107
|
+
| `label` | `ReactNode` | Field label (convenience components). |
|
|
108
|
+
| `message` | `ReactNode` | Help / validation text rendered as `<p class="help">`. |
|
|
109
|
+
| `messageColor` | a Bulma color | Colors the help text (`'danger'` for errors). |
|
|
110
|
+
| `iconLeftName` / `iconRightName` | `string` | Icon shortcuts; pair with `hasIconsLeft/Right`. |
|
|
111
|
+
| `isLoading` | `boolean` | Loading indicator on the Control. |
|
|
112
|
+
|
|
113
|
+
Plus the full Bulma **helper props** (`m`, `p`, `textColor`, `display`, …) on every component
|
|
114
|
+
via `useBulmaClasses`.
|
|
115
|
+
|
|
116
|
+
## Convenience vs composed
|
|
117
|
+
|
|
118
|
+
- **Convenience** (`<Input label message … />`) — for typical, single-control fields. Fewer
|
|
119
|
+
lines, auto-wrapping, built-in `message`/`messageColor`. Default to this.
|
|
120
|
+
- **Composed** (`Field` + `Control` + `InputBase`) — when you need grouped controls, addons,
|
|
121
|
+
multiple controls per field, or custom layout. The convenience components detect they're
|
|
122
|
+
already inside a `Field`/`Control` and won't double-wrap, so you can mix the two.
|
|
123
|
+
|
|
124
|
+
## Validation without a library
|
|
125
|
+
|
|
126
|
+
There is no built-in validation. The pattern is: **own your state, compute errors yourself, and
|
|
127
|
+
reflect them with `color` + `message` + `messageColor`.**
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
import { useState } from 'react';
|
|
131
|
+
import { Input, Button } from '@allxsmith/bestax-bulma';
|
|
132
|
+
|
|
133
|
+
function SignupForm() {
|
|
134
|
+
const [email, setEmail] = useState('');
|
|
135
|
+
const [touched, setTouched] = useState(false);
|
|
136
|
+
|
|
137
|
+
const error =
|
|
138
|
+
touched && !/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(email)
|
|
139
|
+
? 'Please enter a valid email address.'
|
|
140
|
+
: undefined;
|
|
141
|
+
|
|
142
|
+
return (
|
|
143
|
+
<form
|
|
144
|
+
onSubmit={e => {
|
|
145
|
+
e.preventDefault();
|
|
146
|
+
setTouched(true);
|
|
147
|
+
if (!error && email) {
|
|
148
|
+
// submit…
|
|
149
|
+
}
|
|
150
|
+
}}
|
|
151
|
+
>
|
|
152
|
+
<Input
|
|
153
|
+
label="Email"
|
|
154
|
+
type="email"
|
|
155
|
+
value={email}
|
|
156
|
+
onChange={e => setEmail(e.target.value)}
|
|
157
|
+
onBlur={() => setTouched(true)}
|
|
158
|
+
color={error ? 'danger' : undefined}
|
|
159
|
+
message={error}
|
|
160
|
+
messageColor={error ? 'danger' : undefined}
|
|
161
|
+
iconLeftName="envelope"
|
|
162
|
+
/>
|
|
163
|
+
<Button color="primary" type="submit" mt="3">
|
|
164
|
+
Sign up
|
|
165
|
+
</Button>
|
|
166
|
+
</form>
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Rules of thumb:
|
|
172
|
+
|
|
173
|
+
- Set `color="danger"` on the input **and** `messageColor="danger"` on the help text so both the
|
|
174
|
+
control and the message read as an error. Use `'success'` to signal a valid field.
|
|
175
|
+
- Want a different validation library? Wire it up yourself — pass its `value`/`onChange`/error
|
|
176
|
+
string into these props. bestax does not prescribe one.
|
|
177
|
+
- For grouped controls, render the `<p class="help">` via the `message` prop of the convenience
|
|
178
|
+
component, or add it manually inside the `Field` when composing.
|
|
179
|
+
|
|
180
|
+
See `references/api.md` for per-component props and `references/patterns.md` for a full
|
|
181
|
+
multi-field form plus the advanced inputs.
|
|
182
|
+
|
|
183
|
+
## Reuse the shipped components
|
|
184
|
+
|
|
185
|
+
bestax ships the whole form surface — Input, Select, TextArea, Checkbox(es), Radio(s), Switch,
|
|
186
|
+
File, Autocomplete, Slider, Numberinput, Rate, Taginput, and the date/time inputs (see the
|
|
187
|
+
inventory above). **Compose these; don't hand-roll raw `<input class="input">` markup or
|
|
188
|
+
reinvent a control.** If you think a control is missing, check `bulma-ui/src/index.ts` and
|
|
189
|
+
`docs/docs/api/form/` first — it's probably already there under a different name.
|
|
190
|
+
|
|
191
|
+
## Visually inspect it in a browser
|
|
192
|
+
|
|
193
|
+
Forms have layout, spacing, and _stateful_ behavior that types and unit tests don't cover.
|
|
194
|
+
Before calling a form done, **render it and look at it**: run `npm run storybook` (in `bulma-ui`)
|
|
195
|
+
or the docs dev server, open the form, and check field alignment/spacing, the help-text/error
|
|
196
|
+
states, and the validation flow (submit empty → fields turn `danger` with messages; fix → errors
|
|
197
|
+
clear). If claude-in-chrome or Playwright is available, drive the browser and screenshot the
|
|
198
|
+
valid and error states; otherwise eyeball it yourself.
|
|
199
|
+
|
|
200
|
+
## Checklist
|
|
201
|
+
|
|
202
|
+
- [ ] Built from the shipped form components (no hand-rolled inputs / reinvented controls).
|
|
203
|
+
- [ ] Every input has an associated label (`label` prop, or a `<label htmlFor>` when composing).
|
|
204
|
+
- [ ] Controlled inputs have both `value` and `onChange` (or use `defaultValue` uncontrolled).
|
|
205
|
+
- [ ] Error state shows via `color="danger"` + `message` + `messageColor="danger"`.
|
|
206
|
+
- [ ] Grouped/addon layouts use explicit `Field` + `Control` composition.
|
|
207
|
+
- [ ] No assumption of a built-in validation/form library — state is owned by the app.
|
|
208
|
+
- [ ] **Rendered and visually inspected in a browser** — layout and the error/validation states
|
|
209
|
+
look right, not just green tests.
|
|
@@ -0,0 +1,102 @@
|
|
|
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. |
|
|
18
|
+
| `labelSize` | `'small' \| 'normal' \| 'medium' \| 'large'` | Label size. |
|
|
19
|
+
| `labelProps` | label attributes | Props for the `<label>`. |
|
|
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`, plus the Field/Control/message props. `TextArea` adds `rows` and
|
|
63
|
+
`hasFixedSize`.
|
|
64
|
+
|
|
65
|
+
## Checkbox / Checkboxes, Radio / Radios
|
|
66
|
+
|
|
67
|
+
- `Checkbox` / `Radio` — single controls with `color`, `size`, `checked`/`defaultChecked`,
|
|
68
|
+
`onChange`, `disabled`.
|
|
69
|
+
- `Checkboxes` — group wrapper managing an **array** value.
|
|
70
|
+
- `Radios` — group wrapper managing a **single** selected value.
|
|
71
|
+
|
|
72
|
+
## Switch — `form/Switch.tsx`
|
|
73
|
+
|
|
74
|
+
`color`, `size`, `checked`/`defaultChecked`, `onChange`, `isRounded`, `isThin`, `isOutlined`,
|
|
75
|
+
`passiveType`, plus RTL support.
|
|
76
|
+
|
|
77
|
+
## File — `form/File.tsx`
|
|
78
|
+
|
|
79
|
+
File input with `label`, `message`, color/size, and icon support.
|
|
80
|
+
|
|
81
|
+
## Advanced inputs
|
|
82
|
+
|
|
83
|
+
| Component | Key props |
|
|
84
|
+
| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
85
|
+
| `Autocomplete` | `data` (`string[]` or item objects), `value`, `onInput(value)` for typing, `onSelect(item)` for picks, `clearable`, `openOnFocus`, `loading`. |
|
|
86
|
+
| `Slider` | `min`, `max`, `step`, single or dual thumb (`value` number or `[number, number]`), `tooltip` (`'auto' \| 'always' \| 'hidden'`), vertical orientation, `color`, `size`. |
|
|
87
|
+
| `Numberinput` | `value`/`onChange`, `min`, `max`, `step`, increment/decrement buttons, stepper variant, `color`, `size`. |
|
|
88
|
+
| `Rate` | `value`/`onChange`, `max`, `precision` (1 / 0.5 / 0.25), `customIcon` or `iconName`, `showScore`/`showText`/`texts`, `disabled`. |
|
|
89
|
+
| `Taginput` | `value` (array)/`onChange`, autocomplete suggestions, configurable confirm keys, closable tags, `color`, `size`. |
|
|
90
|
+
|
|
91
|
+
## Date / time inputs
|
|
92
|
+
|
|
93
|
+
`DateInput`, `TimeInput`, `DateTimeInput` (convenience) and their `*Base` variants. Field/Control
|
|
94
|
+
composition like the other convenience inputs, with picker UIs (native with custom fallback).
|
|
95
|
+
|
|
96
|
+
## Validation-related props (no library)
|
|
97
|
+
|
|
98
|
+
There is no validation engine. The props you use to reflect externally-computed validation are:
|
|
99
|
+
|
|
100
|
+
- `color` — `'danger'` for an error, `'success'` for valid.
|
|
101
|
+
- `message` — the help/validation text (rendered as `<p class="help">`).
|
|
102
|
+
- `messageColor` — colors that help text to match (`'danger'`, `'success'`, …).
|