create-bestax 3.1.3 → 3.2.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 +14 -5
- package/dist/constants.d.ts +6 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +48 -3
- package/dist/project-creator.d.ts +2 -1
- package/dist/project-creator.d.ts.map +1 -1
- package/dist/project-creator.js +10 -12
- package/package.json +1 -1
- package/templates/skills/bestax-custom-component/SKILL.md +100 -329
- package/templates/skills/bestax-custom-component/examples/stat-card.tsx +101 -0
- package/templates/skills/bestax-custom-component/references/api.md +10 -1
- package/templates/skills/bestax-custom-component/references/component-catalog.md +7 -1
- package/templates/skills/bestax-custom-component/references/library-contributor.md +395 -0
- package/templates/skills/bestax-custom-component/references/patterns.md +5 -2
- package/templates/skills/bestax-theming/references/css-variables.md +27 -0
- package/templates/skills/bestax-theming/references/themeable-components.md +12 -10
- package/templates/vite/package.json +1 -1
- package/templates/vite-ts/package.json +1 -1
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
# Reference: building a component inside the bestax monorepo
|
|
2
|
+
|
|
3
|
+
You are inside the bestax monorepo — import helpers from relative paths
|
|
4
|
+
(`../helpers/classNames`), not from the package. This is the full contributor pipeline for a
|
|
5
|
+
custom "extra" component: React + TS, the Bulma v1 SCSS pattern, stories, tests, docs, and
|
|
6
|
+
wiring. For **form** components (Field/Control/Input/etc.) use the `bestax-form` skill instead.
|
|
7
|
+
|
|
8
|
+
## File layout
|
|
9
|
+
|
|
10
|
+
Every custom component has five files. Mirror the existing names exactly (PascalCase TSX,
|
|
11
|
+
`_kebab.scss` partial):
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
bulma-ui/src/components/MyComponent.tsx # React + TS component
|
|
15
|
+
bulma-ui/src/components/MyComponent.stories.tsx # Storybook stories
|
|
16
|
+
bulma-ui/src/components/__tests__/MyComponent.test.tsx # Jest + RTL tests
|
|
17
|
+
bulma-ui/src/scss/components/_mycomponent.scss # SCSS partial
|
|
18
|
+
docs/docs/api/components/mycomponent.md # Docusaurus docs page
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Then wire two index files (see **Wiring & build**).
|
|
22
|
+
|
|
23
|
+
## Component template
|
|
24
|
+
|
|
25
|
+
Components accept Bulma helper props via `BulmaClassesProps`, run them through
|
|
26
|
+
`useBulmaClasses`, build their own classes with `usePrefixedClassNames`, and merge everything
|
|
27
|
+
with `classNames`. Spread `rest` (the non-helper props) onto the DOM node.
|
|
28
|
+
|
|
29
|
+
Use `forwardRef` when consumers need the DOM node (focus, measurement, observers) — typical
|
|
30
|
+
for interactive extras, so this template uses it. Simpler wrappers in the library are plain
|
|
31
|
+
function components; match the siblings in the target folder.
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
import React, { forwardRef } from 'react';
|
|
35
|
+
import { classNames, usePrefixedClassNames } from '../helpers/classNames';
|
|
36
|
+
import { useBulmaClasses, BulmaClassesProps } from '../helpers/useBulmaClasses';
|
|
37
|
+
|
|
38
|
+
export type MyComponentColor =
|
|
39
|
+
'primary' | 'link' | 'info' | 'success' | 'warning' | 'danger';
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Props for the MyComponent component.
|
|
43
|
+
*
|
|
44
|
+
* @property {MyComponentColor} [color] - Bulma color modifier.
|
|
45
|
+
* @property {'small' | 'medium' | 'large'} [size] - Size modifier.
|
|
46
|
+
* @property {boolean} [isActive] - Whether the component is active.
|
|
47
|
+
*/
|
|
48
|
+
export interface MyComponentProps
|
|
49
|
+
extends
|
|
50
|
+
Omit<React.HTMLAttributes<HTMLDivElement>, 'color'>,
|
|
51
|
+
Omit<BulmaClassesProps, 'color'> {
|
|
52
|
+
color?: MyComponentColor;
|
|
53
|
+
size?: 'small' | 'medium' | 'large'; // element size union — never the spacing 'validSizes' constant ('0'…'6'|'auto')
|
|
54
|
+
isActive?: boolean;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* MyComponent — short description of what it does.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* <MyComponent color="primary" size="large" isActive>Hello</MyComponent>
|
|
62
|
+
*/
|
|
63
|
+
export const MyComponent = forwardRef<HTMLDivElement, MyComponentProps>(
|
|
64
|
+
({ color, size, isActive, className, children, ...props }, ref) => {
|
|
65
|
+
// 1. Pull Bulma helper classes (m/p, text*, display, etc.) out of props.
|
|
66
|
+
const { bulmaHelperClasses, rest } = useBulmaClasses(props);
|
|
67
|
+
|
|
68
|
+
// 2. Build this component's own classes (respects the ConfigProvider classPrefix).
|
|
69
|
+
const mainClasses = usePrefixedClassNames('mycomponent', {
|
|
70
|
+
[`is-${color}`]: !!color,
|
|
71
|
+
[`is-${size}`]: !!size,
|
|
72
|
+
'is-active': !!isActive,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// 3. Merge: own classes + helper classes + caller className.
|
|
76
|
+
const combined = classNames(mainClasses, bulmaHelperClasses, className);
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<div ref={ref} className={combined} {...rest}>
|
|
80
|
+
{children}
|
|
81
|
+
</div>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
MyComponent.displayName = 'MyComponent';
|
|
87
|
+
|
|
88
|
+
export default MyComponent;
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Rules that keep components consistent:
|
|
92
|
+
|
|
93
|
+
- **Always `Omit<…, 'color'>`** from both `HTMLAttributes` and `BulmaClassesProps` when the
|
|
94
|
+
component exposes its own typed `color`, so the native/helper `color` doesn't collide.
|
|
95
|
+
- **Never hand-build class strings.** Use `usePrefixedClassNames(base, conditionalMap)` so the
|
|
96
|
+
optional `classPrefix` from `ConfigProvider` is honored, then `classNames(...)` to merge.
|
|
97
|
+
- **Spread `rest`, not `props`**, onto the DOM node — `useBulmaClasses` has already stripped the
|
|
98
|
+
helper props out of `rest`, so they don't leak to the DOM as invalid attributes.
|
|
99
|
+
- **Set `displayName`** on `forwardRef` components (needed for tests and Storybook autodocs).
|
|
100
|
+
- **Element sizing uses an inline `'small' | 'medium' | 'large'` union**, mapped to `is-small` /
|
|
101
|
+
`is-medium` / `is-large` (see `Tabs.tsx`, `Control.tsx`). Do **not** reach for the `validSizes`
|
|
102
|
+
constant — that one is `'0'…'6' | 'auto'` and exists for **spacing** helpers, not element size.
|
|
103
|
+
- **Format before you lint.** The repo enforces Prettier and ESLint fails on unformatted code.
|
|
104
|
+
Run `pnpm exec prettier --write` on your new files (or `pnpm format` from the repo root) before
|
|
105
|
+
`pnpm lint`. Copy snippets as a starting point, then let Prettier normalize them.
|
|
106
|
+
|
|
107
|
+
See `api.md` for the full helper API and `patterns.md` for the complete Dialog walkthrough.
|
|
108
|
+
|
|
109
|
+
## SCSS pattern (required)
|
|
110
|
+
|
|
111
|
+
This is the library's house convention — **the Bulma v1 CSS-variable pattern**. Do not write
|
|
112
|
+
plain hard-coded CSS or homebrew `--mycomponent-*` variables. Import Bulma's utilities, declare
|
|
113
|
+
SCSS vars with `!default`, register them as `--bulma-*` custom properties on the root selector
|
|
114
|
+
with `cv.register-vars`, then consume them with `cv.getVar`. Prefix every selector with
|
|
115
|
+
`iv.$class-prefix`.
|
|
116
|
+
|
|
117
|
+
```scss
|
|
118
|
+
// bulma-ui/src/scss/components/_mycomponent.scss
|
|
119
|
+
@use 'bulma/sass/utilities/initial-variables' as iv;
|
|
120
|
+
@use 'bulma/sass/utilities/css-variables' as cv;
|
|
121
|
+
|
|
122
|
+
// 1. SCSS variables, overridable, referencing Bulma vars via cv.getVar.
|
|
123
|
+
$mycomponent-radius: cv.getVar('radius') !default;
|
|
124
|
+
$mycomponent-background: cv.getVar('scheme-main') !default;
|
|
125
|
+
$mycomponent-color: cv.getVar('text') !default;
|
|
126
|
+
$mycomponent-padding: 1rem !default;
|
|
127
|
+
|
|
128
|
+
// 2. Register them as runtime --bulma-* custom properties on the root selector.
|
|
129
|
+
.#{iv.$class-prefix}mycomponent {
|
|
130
|
+
@include cv.register-vars(
|
|
131
|
+
(
|
|
132
|
+
'mycomponent-radius': #{$mycomponent-radius},
|
|
133
|
+
'mycomponent-background': #{$mycomponent-background},
|
|
134
|
+
'mycomponent-color': #{$mycomponent-color},
|
|
135
|
+
'mycomponent-padding': #{$mycomponent-padding},
|
|
136
|
+
)
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// 3. Consume via cv.getVar. Prefix every selector with iv.$class-prefix.
|
|
141
|
+
.#{iv.$class-prefix}mycomponent {
|
|
142
|
+
background-color: cv.getVar('mycomponent-background');
|
|
143
|
+
border-radius: cv.getVar('mycomponent-radius');
|
|
144
|
+
color: cv.getVar('mycomponent-color');
|
|
145
|
+
padding: cv.getVar('mycomponent-padding');
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Color variants reuse Bulma's registered color vars.
|
|
149
|
+
.#{iv.$class-prefix}mycomponent.#{iv.$class-prefix}is-primary {
|
|
150
|
+
background-color: cv.getVar('primary');
|
|
151
|
+
color: cv.getVar('primary-invert');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Respect reduced-motion if you animate.
|
|
155
|
+
@media (prefers-reduced-motion: reduce) {
|
|
156
|
+
.#{iv.$class-prefix}mycomponent {
|
|
157
|
+
animation: none;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Why this matters: registering vars makes the component themeable at runtime (the docs site and
|
|
163
|
+
`Theme`/`ConfigProvider` providers override `--bulma-*` properties), and the `iv.$class-prefix` keeps
|
|
164
|
+
the component working when consumers opt into a class prefix to avoid collisions.
|
|
165
|
+
|
|
166
|
+
Register **all** themable values — durations and offsets included — and prefer Bulma tokens
|
|
167
|
+
(`cv.getVar('radius-rounded')`, never `9999px`); derive dark-mode-affected surfaces from scheme
|
|
168
|
+
tokens (`scheme-main`, `text`, `border`). When the component is themeable, add rows to
|
|
169
|
+
`skills/bestax-theming/references/themeable-components.md` and `css-variables.md` in the same PR.
|
|
170
|
+
|
|
171
|
+
The canonical reference file is `bulma-ui/src/scss/components/_dialog.scss`.
|
|
172
|
+
|
|
173
|
+
## Stories
|
|
174
|
+
|
|
175
|
+
`MyComponent.stories.tsx` beside the component. Use `tags: ['autodocs']` so the JSDoc becomes
|
|
176
|
+
the docs page, declare `argTypes`, and write one named `function`-style render per variant.
|
|
177
|
+
Give every argType a `description` — enforced by a jest meta-test.
|
|
178
|
+
|
|
179
|
+
```tsx
|
|
180
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
181
|
+
import { MyComponent } from './MyComponent';
|
|
182
|
+
|
|
183
|
+
const meta: Meta<typeof MyComponent> = {
|
|
184
|
+
title: 'Components/MyComponent',
|
|
185
|
+
component: MyComponent,
|
|
186
|
+
tags: ['autodocs'],
|
|
187
|
+
argTypes: {
|
|
188
|
+
color: {
|
|
189
|
+
control: 'select',
|
|
190
|
+
options: ['primary', 'link', 'info', 'success', 'warning', 'danger'],
|
|
191
|
+
description: 'Bulma color modifier applied to the component.',
|
|
192
|
+
},
|
|
193
|
+
isActive: {
|
|
194
|
+
control: 'boolean',
|
|
195
|
+
description: 'Whether the component renders in its active state.',
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
export default meta;
|
|
200
|
+
type Story = StoryObj<typeof MyComponent>;
|
|
201
|
+
|
|
202
|
+
export const Default: Story = {
|
|
203
|
+
render: function DefaultExample() {
|
|
204
|
+
return <MyComponent>Default</MyComponent>;
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
export const Colors: Story = {
|
|
209
|
+
render: function ColorsExample() {
|
|
210
|
+
return (
|
|
211
|
+
<>
|
|
212
|
+
<MyComponent color="primary">Primary</MyComponent>
|
|
213
|
+
<MyComponent color="danger">Danger</MyComponent>
|
|
214
|
+
</>
|
|
215
|
+
);
|
|
216
|
+
},
|
|
217
|
+
};
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Tests
|
|
221
|
+
|
|
222
|
+
`__tests__/MyComponent.test.tsx`, Jest + `@testing-library/react`. Cover render, each prop →
|
|
223
|
+
class mapping, the helper-prop passthrough, ref forwarding, the ConfigProvider prefix, and any
|
|
224
|
+
interaction/a11y.
|
|
225
|
+
|
|
226
|
+
```tsx
|
|
227
|
+
import { render, screen } from '@testing-library/react';
|
|
228
|
+
import { createRef } from 'react';
|
|
229
|
+
import { MyComponent } from '../MyComponent';
|
|
230
|
+
import { ConfigProvider } from '../../helpers/Config';
|
|
231
|
+
|
|
232
|
+
describe('MyComponent', () => {
|
|
233
|
+
it('renders children', () => {
|
|
234
|
+
render(<MyComponent>Hello</MyComponent>);
|
|
235
|
+
expect(screen.getByText('Hello')).toBeInTheDocument();
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
it('applies the color modifier', () => {
|
|
239
|
+
render(<MyComponent color="primary">x</MyComponent>);
|
|
240
|
+
expect(screen.getByText('x')).toHaveClass('mycomponent', 'is-primary');
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
it('passes Bulma helper props through', () => {
|
|
244
|
+
render(<MyComponent m="3">x</MyComponent>);
|
|
245
|
+
expect(screen.getByText('x')).toHaveClass('m-3');
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it('forwards the ref', () => {
|
|
249
|
+
const ref = createRef<HTMLDivElement>();
|
|
250
|
+
render(<MyComponent ref={ref}>x</MyComponent>);
|
|
251
|
+
expect(ref.current).toBeInstanceOf(HTMLDivElement);
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
it('applies classPrefix from ConfigProvider', () => {
|
|
255
|
+
const { container } = render(
|
|
256
|
+
<ConfigProvider classPrefix="bestax-">
|
|
257
|
+
<MyComponent>x</MyComponent>
|
|
258
|
+
</ConfigProvider>
|
|
259
|
+
);
|
|
260
|
+
const el = container.querySelector('.bestax-mycomponent');
|
|
261
|
+
expect(el).toBeInTheDocument();
|
|
262
|
+
expect(el).not.toHaveClass('mycomponent');
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## Docs page
|
|
268
|
+
|
|
269
|
+
`docs/docs/api/components/mycomponent.md` — Overview, Import, a Props table, `Usage` with
|
|
270
|
+
live examples, then Accessibility, Related Components, and Additional Resources. Live code
|
|
271
|
+
blocks use the ` ```tsx live ` fence (Docusaurus live-codeblock). House rules:
|
|
272
|
+
|
|
273
|
+
- Frontmatter `title:` **must equal the exported component name** — `gen-component-catalog.mjs`
|
|
274
|
+
parses it to build the skill catalog.
|
|
275
|
+
- Headings are Title Case.
|
|
276
|
+
- Every example gets one prose sentence explaining what it shows.
|
|
277
|
+
- No inline `style={{}}` in examples — use helper props.
|
|
278
|
+
|
|
279
|
+
````md
|
|
280
|
+
---
|
|
281
|
+
title: MyComponent
|
|
282
|
+
sidebar_label: MyComponent
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
# MyComponent
|
|
286
|
+
|
|
287
|
+
## Overview
|
|
288
|
+
|
|
289
|
+
Short description of the component.
|
|
290
|
+
|
|
291
|
+
## Import
|
|
292
|
+
|
|
293
|
+
```tsx
|
|
294
|
+
import { MyComponent } from '@allxsmith/bestax-bulma';
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
## Props
|
|
298
|
+
|
|
299
|
+
| Prop | Type | Default | Description |
|
|
300
|
+
| ---------- | ---------------------------- | ------- | --------------------- |
|
|
301
|
+
| `color` | `'primary' \| 'link' \| ...` | — | Bulma color modifier. |
|
|
302
|
+
| `isActive` | `boolean` | `false` | Active state. |
|
|
303
|
+
|
|
304
|
+
## Usage
|
|
305
|
+
|
|
306
|
+
### Default
|
|
307
|
+
|
|
308
|
+
A basic MyComponent with default styling.
|
|
309
|
+
|
|
310
|
+
```tsx live
|
|
311
|
+
<MyComponent>Hello</MyComponent>
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
## Accessibility
|
|
315
|
+
|
|
316
|
+
Note roles, keyboard behavior, and reduced-motion handling.
|
|
317
|
+
|
|
318
|
+
## Related Components
|
|
319
|
+
|
|
320
|
+
- [`Tag`](../elements/tag.md) — for a small colored label instead.
|
|
321
|
+
|
|
322
|
+
## Additional Resources
|
|
323
|
+
|
|
324
|
+
- [Bulma documentation](https://bulma.io/documentation/)
|
|
325
|
+
````
|
|
326
|
+
|
|
327
|
+
> Note: the Docusaurus docs load the **built** dist CSS. After SCSS changes, run
|
|
328
|
+
> `cd bulma-ui && pnpm build` before the new styles show up in the docs site (Storybook
|
|
329
|
+
> compiles SCSS live and does not need this).
|
|
330
|
+
|
|
331
|
+
## Wiring & build
|
|
332
|
+
|
|
333
|
+
Two index files must be updated or the component won't ship:
|
|
334
|
+
|
|
335
|
+
1. **Package export** — add to `bulma-ui/src/index.ts`, in the **components** group (the file
|
|
336
|
+
groups exports by directory — keep yours next to the other `./components/*` lines):
|
|
337
|
+
```ts
|
|
338
|
+
export * from './components/MyComponent';
|
|
339
|
+
```
|
|
340
|
+
2. **SCSS bundle** — add to `bulma-ui/src/scss/components/_index.scss`:
|
|
341
|
+
```scss
|
|
342
|
+
@use 'mycomponent';
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
Then build and verify:
|
|
346
|
+
|
|
347
|
+
```sh
|
|
348
|
+
cd bulma-ui
|
|
349
|
+
pnpm exec prettier --write src/components/MyComponent.tsx src/scss/components/_mycomponent.scss
|
|
350
|
+
pnpm lint
|
|
351
|
+
pnpm test
|
|
352
|
+
pnpm build # compiles JS + the bestax/extras CSS bundles
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
Finally run `pnpm gen:catalog` from the repo root — CI's `gen:catalog:check` fails if the skill
|
|
356
|
+
component catalog is stale.
|
|
357
|
+
|
|
358
|
+
## Visually inspect it in a browser
|
|
359
|
+
|
|
360
|
+
Types and unit tests don't see layout. **Render the component and actually look at it** before
|
|
361
|
+
you call it done — spacing, padding, vertical centering, alignment, and every variant/state
|
|
362
|
+
(colors, sizes, hover/active, dark mode). Visual bugs hide from `tsc` and `@testing-library`.
|
|
363
|
+
|
|
364
|
+
1. Run a surface that renders it: `pnpm storybook` (compiles SCSS live) or the docs dev server.
|
|
365
|
+
2. Open the component and inspect it. If a browser-automation tool (claude-in-chrome, Playwright)
|
|
366
|
+
is available, drive the browser and screenshot each variant; otherwise open it yourself and
|
|
367
|
+
eyeball it.
|
|
368
|
+
3. Check the usual offenders:
|
|
369
|
+
- **Vertical centering of inline text** — `display: inline-block` + `line-height: 1` makes
|
|
370
|
+
text sit low. For chips/labels/buttons use `display: inline-flex; align-items: center;
|
|
371
|
+
justify-content: center;` with a normal `line-height` (Bulma's `Tag` is the reference).
|
|
372
|
+
- Padding/gaps look balanced; nothing clips or overflows.
|
|
373
|
+
- Every color/size variant renders; dark mode is legible.
|
|
374
|
+
|
|
375
|
+
Fix what you see, then re-inspect. A green test suite with a misaligned component is not done.
|
|
376
|
+
|
|
377
|
+
## Checklist
|
|
378
|
+
|
|
379
|
+
- [ ] **Checked the inventory first** — searched `src/index.ts` / docs / Storybook for an existing
|
|
380
|
+
match or synonym, and told the user (reuse/extend it, or confirm there's a genuine gap).
|
|
381
|
+
- [ ] `MyComponent.tsx` — `Omit<…, 'color'>`, `useBulmaClasses`, `usePrefixedClassNames`,
|
|
382
|
+
`classNames`, spread `rest`; `forwardRef` + `displayName` when consumers need the node.
|
|
383
|
+
- [ ] `_mycomponent.scss` — `@use` Bulma utilities, `$vars !default`, `cv.register-vars`,
|
|
384
|
+
`cv.getVar`, every selector prefixed with `iv.$class-prefix`.
|
|
385
|
+
- [ ] `MyComponent.stories.tsx` — `tags: ['autodocs']`, `argTypes` (each with a `description`),
|
|
386
|
+
one story per variant.
|
|
387
|
+
- [ ] `__tests__/MyComponent.test.tsx` — render, prop→class, helper passthrough, ref + ConfigProvider prefix test (required).
|
|
388
|
+
- [ ] `docs/docs/api/components/mycomponent.md` — Overview / Import / Props / `tsx live` /
|
|
389
|
+
Accessibility / Related Components / Additional Resources; frontmatter `title:` = export name.
|
|
390
|
+
- [ ] `src/index.ts` exports the component (in the `./components/*` group).
|
|
391
|
+
- [ ] `scss/components/_index.scss` `@use`s the partial.
|
|
392
|
+
- [ ] Themeable values registered; theming skill references updated in the same PR if applicable.
|
|
393
|
+
- [ ] Prettier-formatted, then `pnpm lint && pnpm test && pnpm build` pass; `pnpm gen:catalog` run.
|
|
394
|
+
- [ ] **Rendered and visually inspected in a browser** — centering/spacing/variants all look
|
|
395
|
+
right (not just green tests).
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# Reference: Dialog, the canonical worked example
|
|
2
2
|
|
|
3
|
+
**Library-contributor worked example** — the in-monorepo counterpart to `examples/stat-card.tsx`;
|
|
4
|
+
follow it together with `library-contributor.md`.
|
|
5
|
+
|
|
3
6
|
`Dialog` is the library's reference implementation of the custom-component pattern. Read the
|
|
4
7
|
real files alongside this:
|
|
5
8
|
|
|
@@ -121,8 +124,8 @@ Dialog also shows optional patterns you can borrow when relevant:
|
|
|
121
124
|
- **Accessibility**: `role="alertdialog"`, Escape-to-cancel, and focus management on open.
|
|
122
125
|
- **Body scroll lock** via a module-level ref count so chained/overlapping dialogs behave.
|
|
123
126
|
|
|
124
|
-
These are not required for every component — start from the simple template in
|
|
125
|
-
add only what your component needs.
|
|
127
|
+
These are not required for every component — start from the simple template in
|
|
128
|
+
`library-contributor.md` and add only what your component needs.
|
|
126
129
|
|
|
127
130
|
## Other components worth reading for variety
|
|
128
131
|
|
|
@@ -96,6 +96,33 @@ and numeric shades `--bulma-<c>-00` … `--bulma-<c>-95`.
|
|
|
96
96
|
| `--bulma-size-small` / `-normal` / `-medium` / `-large` | 0.75 / 1 / 1.25 / 1.5rem | via `bulmaVars` |
|
|
97
97
|
| `--bulma-weight-light/normal/medium/semibold/bold/extrabold` | 300 / 400 / 500 / 600 / 700 / 800 | via `bulmaVars` |
|
|
98
98
|
|
|
99
|
+
## Extras component variables (Avatar / Avatars / Badge)
|
|
100
|
+
|
|
101
|
+
These are registered on the component's **own selector** (`.avatar`, `.avatars`, `.badge` —
|
|
102
|
+
`.bestax-avatar` etc. with the prefixed CSS flavor), not on `:root`. A value set on a wrapping
|
|
103
|
+
ancestor — including `Theme`'s `bulmaVars` on a wrapping `Theme` — is only _inherited_ and
|
|
104
|
+
always loses to the component-level declaration, so it will NOT take effect. Working overrides
|
|
105
|
+
target the component's own element instead: redeclare on the component's own class in your CSS
|
|
106
|
+
(mind the class prefix), e.g. `.avatar { --bulma-avatar-size: 3.5rem; }`, or pass a
|
|
107
|
+
`className` and scope the override under it
|
|
108
|
+
(`.avatar.big-avatar { --bulma-avatar-size: 3.5rem; }`), or set it via the component's `style`
|
|
109
|
+
prop. Several default to core theme vars above, so they already flow through a custom theme.
|
|
110
|
+
|
|
111
|
+
| Variable | Default |
|
|
112
|
+
| ----------------------------------------------------------------- | -------------------------------- |
|
|
113
|
+
| `--bulma-avatar-size` | `48px` |
|
|
114
|
+
| `--bulma-avatar-background` / `--bulma-avatar-color` | `background` / `text` |
|
|
115
|
+
| `--bulma-avatar-weight` | `weight-semibold` |
|
|
116
|
+
| `--bulma-avatar-rounded-radius` | `radius-large` |
|
|
117
|
+
| `--bulma-avatars-ring-color` / `--bulma-avatars-ring-width` | `scheme-main` / `2px` |
|
|
118
|
+
| `--bulma-avatars-spacing` | `0.75rem` (`sm` 0.5 / `lg` 1rem) |
|
|
119
|
+
| `--bulma-badge-height` / `--bulma-badge-min-width` | `1.25em` / `1.25em` |
|
|
120
|
+
| `--bulma-badge-padding` / `--bulma-badge-font-size` | `0 0.4em` / `0.7rem` |
|
|
121
|
+
| `--bulma-badge-radius` | `radius-rounded` |
|
|
122
|
+
| `--bulma-badge-ring-color` / `--bulma-badge-ring-width` | `scheme-main` / `2px` |
|
|
123
|
+
| `--bulma-badge-dot-size` | `0.65em` |
|
|
124
|
+
| `--bulma-badge-inset-circle` / `--bulma-badge-animation-duration` | `12%` / `1.4s` |
|
|
125
|
+
|
|
99
126
|
## Dark mode (`Theme colorMode`)
|
|
100
127
|
|
|
101
128
|
Drive the light/dark scheme with the `Theme` component's **`colorMode`** prop —
|
|
@@ -28,16 +28,18 @@ Shades (`colorShade` / `backgroundColorShade`): `00, 05, 10, … 95, invert, lig
|
|
|
28
28
|
|
|
29
29
|
## Component `color` / `size` props (verbatim unions)
|
|
30
30
|
|
|
31
|
-
| Component | `color` accepts | `size` accepts
|
|
32
|
-
| -------------- | ------------------------------------------------------------------------------------------------------------- |
|
|
33
|
-
| `Button` | `primary \| link \| info \| success \| warning \| danger \| white \| light \| dark \| black \| text \| ghost` | `small \| normal \| medium \| large`
|
|
34
|
-
| `Notification` | the 17 `validColors` | —
|
|
35
|
-
| `Tag` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white` | `normal \| medium \| large`
|
|
36
|
-
| `Box` | `primary \| link \| info \| success \| warning \| danger` | —
|
|
37
|
-
| `Message` | `primary \| link \| info \| success \| warning \| danger` | —
|
|
38
|
-
| `Input` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white` | `small \| medium \| large`
|
|
39
|
-
| `
|
|
40
|
-
| `
|
|
31
|
+
| Component | `color` accepts | `size` accepts | Notes |
|
|
32
|
+
| -------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
|
|
33
|
+
| `Button` | `primary \| link \| info \| success \| warning \| danger \| white \| light \| dark \| black \| text \| ghost` | `small \| normal \| medium \| large` | adds `text`, `ghost`; also `isLight`, `isOutlined`, `isInverted`, `isRounded` |
|
|
34
|
+
| `Notification` | the 17 `validColors` | — | also `isLight` |
|
|
35
|
+
| `Tag` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white` | `normal \| medium \| large` | also `isRounded`, `isDelete`, `isHoverable` |
|
|
36
|
+
| `Box` | `primary \| link \| info \| success \| warning \| danger` | — | the 6 only; also `hasShadow` |
|
|
37
|
+
| `Message` | `primary \| link \| info \| success \| warning \| danger` | — | the 6 only |
|
|
38
|
+
| `Input` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white` | `small \| medium \| large` | also `isRounded`, `isStatic` |
|
|
39
|
+
| `Avatar` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white` | `16x16 \| 24x24 \| 32x32 \| 48x48 \| 64x64 \| 96x96 \| 128x128 \| number` | initials/icon background (auto-derived from `name` when unset); also `shape` |
|
|
40
|
+
| `Badge` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white` | — | pill background; default `danger` |
|
|
41
|
+
| `Title` | — (no `color`; use `textColor`) | `1 \| 2 \| 3 \| 4 \| 5 \| 6` | also `isSpaced` |
|
|
42
|
+
| `SubTitle` | — (no `color`; use `textColor`) | `1 \| 2 \| 3 \| 4 \| 5 \| 6` | — |
|
|
41
43
|
|
|
42
44
|
The 6 brand colors (`primary, link, info, success, warning, danger`) are the ones a custom theme
|
|
43
45
|
recolors via the HSL trios (see `css-variables.md`). The greyscale and `white`/`light`/`dark`
|