create-bestax 4.2.15 → 4.2.17

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 (29) hide show
  1. package/dist/constants.js +2 -2
  2. package/package.json +6 -6
  3. package/templates/skills/bestax-custom-component/SKILL.md +36 -1
  4. package/templates/skills/bestax-custom-component/references/api.md +36 -14
  5. package/templates/skills/bestax-custom-component/references/component-catalog.md +8 -2
  6. package/templates/skills/bestax-custom-component/references/library-contributor.md +4 -1
  7. package/templates/skills/bestax-form/SKILL.md +42 -29
  8. package/templates/skills/bestax-form/references/api.md +12 -10
  9. package/templates/skills/bestax-form/references/patterns.md +17 -5
  10. package/templates/skills/bestax-icons/SKILL.md +8 -1
  11. package/templates/skills/bestax-icons/references/icon-libraries.md +35 -2
  12. package/templates/skills/bestax-layout-scaffold/SKILL.md +34 -1
  13. package/templates/skills/bestax-layout-scaffold/references/archetypes.md +57 -0
  14. package/templates/skills/bestax-migrate/references/bloomer/prop-map.md +34 -8
  15. package/templates/skills/bestax-migrate/references/bloomer/unmappables.md +18 -0
  16. package/templates/skills/bestax-migrate/references/rbx/prop-map.md +31 -7
  17. package/templates/skills/bestax-migrate/references/rbx/unmappables.md +41 -14
  18. package/templates/skills/bestax-migrate/references/react-bulma-components/component-map.md +3 -3
  19. package/templates/skills/bestax-migrate/references/react-bulma-components/prop-map.md +22 -0
  20. package/templates/skills/bestax-migrate/references/react-bulma-components/unmappables.md +33 -8
  21. package/templates/skills/bestax-optimize/SKILL.md +2 -0
  22. package/templates/skills/bestax-optimize/references/modular-build.md +19 -10
  23. package/templates/skills/bestax-theming/SKILL.md +4 -1
  24. package/templates/skills/bestax-theming/references/css-variables.md +87 -2
  25. package/templates/skills/bestax-theming/references/themeable-components.md +6 -2
  26. package/templates/vite-ts/package.json +1 -0
  27. package/templates/vite-ts/tsconfig.app.json +10 -9
  28. package/templates/vite-ts/tsconfig.node.json +15 -5
  29. package/templates/vite-ts/src/vite-env.d.ts +0 -1
@@ -239,6 +239,63 @@ build the whole grid with `Grid`/`Cell` (`<Grid isFixed fixedColsMobile={1} fixe
239
239
  fixedColsDesktop={3} gap={4}>`) — CSS Grid keeps cells equal-height for free; see the
240
240
  `Grid / Cell` section in `layout-components.md`.
241
241
 
242
+ **Nothing to show:** when the collection is empty, or a search or a filter matches nothing,
243
+ render an `EmptyState` in the grid's place rather than composing one from `Box`, `Icon` and
244
+ `Title`. Its `title` is always a heading: set `titleAs` to the level under the section's own
245
+ heading. It doesn't announce itself, so a search keeps a status region beside its field the
246
+ whole time, saying the count, and "Clear search" puts focus back in the field, since the button
247
+ goes away with the empty state:
248
+
249
+ ```tsx
250
+ const searchRef = useRef<HTMLInputElement>(null);
251
+ const shown = items.filter(item =>
252
+ item.name.toLowerCase().includes(query.trim().toLowerCase())
253
+ );
254
+
255
+ <>
256
+ <Field label="Search products">
257
+ <Control>
258
+ <Input
259
+ ref={searchRef}
260
+ type="search"
261
+ value={query}
262
+ onChange={e => setQuery(e.target.value)}
263
+ />
264
+ </Control>
265
+ </Field>
266
+ {/* Always in the page, so a change to its text is announced. */}
267
+ <Paragraph role="status" aria-atomic="true" visibility="sr-only">
268
+ {shown.length === 0
269
+ ? 'No products match the search'
270
+ : `${shown.length} products`}
271
+ </Paragraph>
272
+ {shown.length === 0 ? (
273
+ <EmptyState
274
+ icon="magnifying-glass"
275
+ title={`No products match “${query}”`}
276
+ titleAs="h2"
277
+ description="Check the spelling, or clear the search."
278
+ >
279
+ <Button
280
+ onClick={() => {
281
+ setQuery('');
282
+ searchRef.current?.focus();
283
+ }}
284
+ >
285
+ Clear search
286
+ </Button>
287
+ </EmptyState>
288
+ ) : (
289
+ <Columns isMultiline>{/* the cards, as above */}</Columns>
290
+ )}
291
+ </>;
292
+ ```
293
+
294
+ With nothing in the collection at all, the same component says so and offers the first step:
295
+ `<EmptyState icon="box-open" title="No products yet" titleAs="h2" description="…">` with one
296
+ `<Button color="primary">` as its child, or two or more in `EmptyState.Actions`. While the items
297
+ load, show a `Skeleton` or a `Loader` instead, so the empty state doesn't flash first.
298
+
242
299
  ---
243
300
 
244
301
  ## Combining archetypes
@@ -54,8 +54,8 @@ leftover would be a type error rather than a no-op.
54
54
  | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
55
55
  | `isColor="primary"` | `color="primary"` (every component that had it) |
56
56
  | `isSize="large"` | `size="large"` — Button, Content, Delete, Icon, Input, Progress, Section, Select, Tag, TextArea, Breadcrumb, Pagination, Tabs, Field.Label, Modal.Close |
57
- | `Title isSize={3}` | `size={3}` — bestax accepts the numbers 1–6 |
58
- | `Subtitle isSize={4}` | `SubTitle size={4} as="h2"` — bloomer's default was an `<h2>`, bestax's is an `<h1>`, so the level is kept |
57
+ | `Title isSize={3}` | `textSize="3"`, so the `<h1>` stays an `<h1>` (see [Title and Subtitle sizes](#title-and-subtitle-sizes)) |
58
+ | `Subtitle isSize={4}` | `SubTitle textSize="4" as="h2"`: bloomer's default was an `<h2>`, bestax's is an `<h1>`, so the level is written out |
59
59
  | `Image isSize="128x128"` | `size="128x128"` |
60
60
  | `Image isRatio="16:9"` | `size="16by9"` (`square`→`square`, `1:1`→`1by1`, `4:3`→`4by3`, `3:2`→`3by2`, `2:1`→`2by1`) |
61
61
  | `Breadcrumb isAlign` | `alignment` |
@@ -77,6 +77,31 @@ leftover would be a type error rather than a no-op.
77
77
  | `isActive` on Dropdown, DropdownItem, MenuLink, Modal, NavbarBurger, NavbarMenu, NavbarItem, PanelBlock, Tab | `active` |
78
78
  | `Input`, `Select`, `TextArea` | `InputBase`, `SelectBase`, `TextAreaBase` — bloomer's were bare elements; bestax's `Input`/`Select`/`TextArea` wrap themselves in `Field` and `Control`, so the bare `*Base` exports are the faithful targets and your existing `Field`/`Control` markup stays as written |
79
79
 
80
+ ## Title and Subtitle sizes
81
+
82
+ bloomer's `Title` rendered an `<h1>` and its `Subtitle` an `<h2>` whatever `isSize` said, or
83
+ the element `tag` named. bestax's `Title` and `SubTitle` render the heading their `size` names
84
+ unless `as="p"`, so `<SubTitle size={4} as="h2">` is an `<h4>`. The codemod keeps the element
85
+ bloomer rendered:
86
+
87
+ | bloomer | bestax-bulma | renders |
88
+ | ----------------------------- | --------------------------------- | ------- |
89
+ | `<Title isSize={4}>` | `<Title textSize="4">` | `<h1>` |
90
+ | `<Title isSize={1}>` | `<Title size={1}>` | `<h1>` |
91
+ | `<Title isSize={4} tag="h2">` | `<Title textSize="4" as="h2">` | `<h2>` |
92
+ | `<Title isSize={6} tag="p">` | `<Title size={6} as="p">` | `<p>` |
93
+ | `<Subtitle>` | `<SubTitle as="h2">` | `<h2>` |
94
+ | `<Subtitle isSize={2}>` | `<SubTitle size={2}>` | `<h2>` |
95
+ | `<Subtitle isSize={4}>` | `<SubTitle textSize="4" as="h2">` | `<h2>` |
96
+
97
+ `size` stays only where it renders the same element: a `<p>`, or the heading the size names.
98
+ Everywhere else the size moves to the `textSize` helper, and so does a 7, which bestax's `size`
99
+ does not take. The helper sets the same font size through Bulma's `is-size-4` class rather than the
100
+ title's own `is-4`, so a rule of your own that targets `.title.is-4` needs the new class too.
101
+ `is-size-4` is also `!important`, so a font size your own CSS gives the title, such as
102
+ `.hero .title`, now loses to it where it used to beat `is-4`. A literal outside 1 to 7 keeps `size`
103
+ and gets a `prop:isSize` TODO.
104
+
80
105
  ## Column sizes
81
106
 
82
107
  | bloomer | bestax-bulma |
@@ -161,12 +186,13 @@ value is flagged. The same conversion covers the modifiers bestax has no prop fo
161
186
 
162
187
  ## Refs
163
188
 
164
- bloomer forwarded no refs. bestax forwards a ref from the form controls, plus `Avatar`,
165
- `Button`, `Carousel`, `CarouselItem`, `Dialog`, `Dropdown`, `Link`, `LinkButton`, `Loader`,
166
- `Menu.Item`, `Modal`, `Navbar`, `Navbar.Burger`, `Navbar.Dropdown`, `Navbar.Item`,
167
- `Navbar.Link`, `Sidebar` and `Toast` — pass `ref` directly on those. "The form controls" means
168
- the inputs themselves: the `Field`, `Field.Label`, `Field.Body`, `Checkboxes` and `Radios`
169
- wrappers around them forward nothing.
189
+ bloomer forwarded no refs. bestax forwards a ref from the form controls, plus `Avatar`, `Button`,
190
+ `Carousel`, `CarouselItem`, `Dialog`, `Dropdown`, `EmptyState`, `Kbd`, `Kbd.Group`, `Link`,
191
+ `LinkButton`, `Loader`, `Menu.Item`, `Modal`, `Navbar`, `Navbar.Burger`, `Navbar.Dropdown`,
192
+ `Navbar.Item`, `Navbar.Link`, `SegmentedControl`, `SegmentedControl.Segment`, `Sidebar`, `Toast` and
193
+ `ToggleButton` — pass `ref` directly on those. "The form controls" means the inputs themselves: the
194
+ `Field`, `Field.Label`, `Field.Body`, `Checkboxes` and `Radios` wrappers around them forward
195
+ nothing.
170
196
 
171
197
  A `ref` on anything else is unsupported, and the two React majors fail differently: React 18
172
198
  drops it and logs "Function components cannot be given refs", while React 19 hands it to the
@@ -274,6 +274,24 @@ prop conditionally:
274
274
  counterpart in bestax (only `isNarrowTouch`) — Bulma keeps the `is-*-touch` classes, so use
275
275
  `className`.
276
276
 
277
+ ## `prop:isSize` on `Title` and `Subtitle`: a size the codemod cannot carry
278
+
279
+ bloomer's `Title` and `Subtitle` kept their element at every size. bestax's render the heading
280
+ their `size` names, so a literal `isSize` moves to `textSize` to keep the level (see "Title and
281
+ Subtitle sizes" in the prop map). A dynamic one cannot move, because `textSize` takes a string,
282
+ so it becomes `size`. Pass it to `textSize` yourself:
283
+
284
+ ```jsx
285
+ <Subtitle isSize={compact ? 5 : 4}>Report</Subtitle>
286
+ <SubTitle textSize={compact ? '5' : '4'} as="h2">Report</SubTitle>
287
+ ```
288
+
289
+ A literal outside 1 to 7 has no Bulma class, and bestax renders none for it either: drop it, or set
290
+ a `textSize` from `'1'` to `'7'`.
291
+
292
+ A dynamic size beside `tag="p"` is not flagged, since bestax never turns a `<p>` into a
293
+ heading.
294
+
277
295
  ## `value-reference` — a component used as a value
278
296
 
279
297
  `const Wrapped = Box` and `{ Subtitle }` are rewritten to the bestax binding (`Hero.Foot`,
@@ -118,6 +118,29 @@ wrong:
118
118
  Note that this one does change the rendered element: rbx's `forwardRefAs` rendered the tag you
119
119
  gave it, so that really was a `<span>`, and the TODO exists to tell you the element moved.
120
120
 
121
+ ## Title sizes
122
+
123
+ rbx's `Title` rendered an `<h1>` at every size, subtitle or not, or the element `as` named.
124
+ bestax's `Title` and `SubTitle` render the heading their `size` names unless `as="p"`, so the
125
+ codemod keeps the element rbx rendered:
126
+
127
+ | rbx | bestax-bulma | renders |
128
+ | ---------------------------------- | ------------------------------ | ------- |
129
+ | `<Title size={4}>` | `<Title textSize="4">` | `<h1>` |
130
+ | `<Title size={1}>` | `<Title size={1}>` | `<h1>` |
131
+ | `<Title subtitle size={6}>` | `<SubTitle textSize="6">` | `<h1>` |
132
+ | `<Title as="h2" size={5}>` | `<Title as="h2" textSize="5">` | `<h2>` |
133
+ | `<Title as="p" subtitle size={5}>` | `<SubTitle as="p" size={5}>` | `<p>` |
134
+
135
+ `size` stays only where it renders the same element: a `<p>`, or the heading the size names.
136
+ Everywhere else the size moves to the `textSize` helper, and so does a 7, which bestax's `size`
137
+ does not take. The helper sets the same font size through Bulma's `is-size-4` class rather than the
138
+ title's own `is-4`, so a rule of your own that targets `.title.is-4` needs the new class too.
139
+ `is-size-4` is also `!important`, so a font size your own CSS gives the title, such as
140
+ `.hero .title`, now loses to it where it used to beat `is-4`. Beside a spread, which may carry
141
+ `as`, a size moves even where it names the default `<h1>`. A literal outside 1 to 7 keeps `size`
142
+ and gets a `prop:size` TODO.
143
+
121
144
  ## `href` follows `as`
122
145
 
123
146
  bestax gives an element the attributes of the tag `as` names, so `href` exists only where that
@@ -156,13 +179,14 @@ becomes.
156
179
  Beside a `ref` the element already has, a rename leaves `innerRef` in place with a `prop:innerRef`
157
180
  TODO rather than write a second `ref`; keep whichever one you meant.
158
181
 
159
- An existing `ref` is passed through untouched — which is safe only where the bestax target
160
- forwards one. rbx forwards a ref on every component; bestax does so on the form controls, plus
161
- `Avatar`, `Button`, `Carousel`, `CarouselItem`, `Dialog`, `Dropdown`, `Link`, `LinkButton`,
162
- `Loader`, `Menu.Item`, `Modal`, `Navbar`, `Navbar.Burger`, `Navbar.Dropdown`, `Navbar.Item`,
163
- `Navbar.Link`, `Sidebar` and `Toast`. "The form controls" there means the inputs themselves:
164
- the `Field`, `Field.Label`, `Field.Body`, `Checkboxes` and `Radios` wrappers around them
165
- forward nothing, and `Field` is a target this codemod emits.
182
+ An existing `ref` is passed through untouched — which is safe only where the bestax target forwards
183
+ one. rbx forwards a ref on every component; bestax does so on the form controls, plus `Avatar`,
184
+ `Button`, `Carousel`, `CarouselItem`, `Dialog`, `Dropdown`, `EmptyState`, `Kbd`, `Kbd.Group`,
185
+ `Link`, `LinkButton`, `Loader`, `Menu.Item`, `Modal`, `Navbar`, `Navbar.Burger`, `Navbar.Dropdown`,
186
+ `Navbar.Item`, `Navbar.Link`, `SegmentedControl`, `SegmentedControl.Segment`, `Sidebar`, `Toast` and
187
+ `ToggleButton`. "The form controls" there means the inputs themselves: the `Field`, `Field.Label`,
188
+ `Field.Body`, `Checkboxes` and `Radios` wrappers around them forward nothing, and `Field` is a
189
+ target this codemod emits.
166
190
 
167
191
  Carry a `ref` onto anything else — `Card`, `Box`, `Section`, `Message`, `Tabs` and most of the
168
192
  catalogue — and it is unsupported, but the two React majors fail differently. React 18 drops
@@ -171,22 +171,49 @@ converted — bestax has its own unrelated `responsive` prop (`'mobile' | 'narro
171
171
  half-emptied rbx object behind would be a type error rather than a leftover. The TODO names
172
172
  which breakpoints did not carry.
173
173
 
174
+ ## A size bestax doesn't take (`prop:size`)
175
+
176
+ `Button.Group`, `Tag.Group` and `Message` sizes carry over as written when bestax's `Buttons`,
177
+ `Tags` or `Message` takes the value. Any other value, or one the codemod can't read, stays as
178
+ written with a TODO that lists the sizes that component takes: use one of them, or drop the
179
+ prop.
180
+
181
+ A dynamic `Image.Container` size gets the same rule, since the codemod can't turn it into
182
+ bestax's `NxN` form. Set `size` on the migrated `<Image>` by hand.
183
+
184
+ ## `prop:size` on `Title`: a size the codemod cannot carry
185
+
186
+ rbx's `Title` rendered an `<h1>` at every size, subtitle or not. bestax's `Title` and `SubTitle`
187
+ render the heading their `size` names unless `as="p"`, so a literal size moves to `textSize` to
188
+ keep the level (see "Title sizes" in the prop map). A dynamic one cannot move, because
189
+ `textSize` takes a string, so it stays `size`. Pass it to `textSize` yourself:
190
+
191
+ ```jsx
192
+ <Title size={compact ? 5 : 4}>Report</Title>
193
+ <Title textSize={compact ? '5' : '4'}>Report</Title>
194
+ ```
195
+
196
+ A literal outside 1 to 7 has no Bulma class, and bestax renders none for it either: drop it, or set
197
+ a `textSize` from `'1'` to `'7'`.
198
+
199
+ The same TODO marks a `Title` that sets `size` and `textSize` both: drop `size` and let
200
+ `textSize` set the font size.
201
+
174
202
  ## Props with no counterpart
175
203
 
176
- | TODO | What to do |
177
- | -------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
178
- | `prop:closeOnBlur` on `Modal` | the migrated compound form renders `Modal.Background` as you wrote it; wire its `onClick` to your `onClose` |
179
- | `prop:selected`, `prop:text` on `Button` | `className="is-selected"`; for `is-text` use `color="ghost"` or a link |
180
- | `prop:size` on `Button.Group` / `Tags` / `Message` | set `size` on each child instead |
181
- | `prop:gradient` on `Hero` | Bulma v1 removed `is-bold` gradients; use `bgColor` or a custom class |
182
- | `prop:color`, `prop:vertical` on `Divider` | bestax's `Divider` takes only `bgColor` and renders an `<hr>` |
183
- | `component:Divider` (a labelled divider) | rbx rendered `<Divider>OR</Divider>`'s children as a centred label via `data-content`; bestax's `Divider` is a bare `<hr>` and takes no children -- React rejects children on a void element at runtime. Put the label in surrounding markup, or drop it |
184
- | `prop:direction` on `PageLoader` | no directional variant; drop it or add a class |
185
- | `prop:managed` | bestax components are uncontrolled; drive the `Modal` with `active` and `onClose` |
186
- | `prop:document` on `Modal` | bestax portals via `portal`, but it takes `true`, a selector or an element rather than a `Document` — see [Modal: what carries over](#modal-what-carries-over) |
187
- | `prop:document` on `Navbar` | bestax's `Navbar` has no `document` prop; drop it |
188
- | `badgeOutlined`, `badgeRounded`, `badgeSize` | bestax's `Badge` has no outline, pill or size variant |
189
- | `tooltipResponsive` | bestax's `Tooltip` has one `position` for all viewports |
204
+ | TODO | What to do |
205
+ | -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
206
+ | `prop:closeOnBlur` on `Modal` | the migrated compound form renders `Modal.Background` as you wrote it; wire its `onClick` to your `onClose` |
207
+ | `prop:selected`, `prop:text` on `Button` | `className="is-selected"`; for `is-text` use `color="ghost"` or a link |
208
+ | `prop:gradient` on `Hero` | Bulma v1 removed `is-bold` gradients; use `bgColor` or a custom class |
209
+ | `prop:color`, `prop:vertical` on `Divider` | bestax's `Divider` takes only `bgColor` and renders an `<hr>` |
210
+ | `component:Divider` (a labelled divider) | rbx rendered `<Divider>OR</Divider>`'s children as a centred label via `data-content`; bestax's `Divider` is a bare `<hr>` and takes no children -- React rejects children on a void element at runtime. Put the label in surrounding markup, or drop it |
211
+ | `prop:direction` on `PageLoader` | no directional variant; drop it or add a class |
212
+ | `prop:managed` | bestax components are uncontrolled; drive the `Modal` with `active` and `onClose` |
213
+ | `prop:document` on `Modal` | bestax portals via `portal`, but it takes `true`, a selector or an element rather than a `Document` — see [Modal: what carries over](#modal-what-carries-over) |
214
+ | `prop:document` on `Navbar` | bestax's `Navbar` has no `document` prop; drop it |
215
+ | `badgeOutlined`, `badgeRounded`, `badgeSize` | bestax's `Badge` has no outline, pill or size variant |
216
+ | `tooltipResponsive` | bestax's `Tooltip` has one `position` for all viewports |
190
217
 
191
218
  ## Modal: what carries over
192
219
 
@@ -20,7 +20,7 @@ codemod converts it; **Flagged** = it leaves a `TODO(bestax-migrate)` comment (s
20
20
  | `Element` | — | Flagged: no generic element; use a semantic component + helper props |
21
21
  | `Footer` | `Footer` | Auto |
22
22
  | `Form.*` | flat imports | See Form table below |
23
- | `Heading` | `Title` / `SubTitle` / `<p class="heading">` | Auto for literal `subtitle`/`heading` (by value, not presence — `subtitle={false}` is `Title`); dynamic value flagged |
23
+ | `Heading` | `Title` / `SubTitle` / `<p class="heading">` | Auto for literal `subtitle`/`heading` (by value, not presence — `subtitle={false}` is `Title`); dynamic value flagged; `size` may become `textSize` |
24
24
  | `Hero` | `Hero` | Auto; `hasNavbar`→`fullheightWithNavbar`; `halfheight`/`gradient` flagged |
25
25
  | `Icon` | `Icon` | `<i class="fas fa-x">` children → `name`/`library`/`variant` props; else flagged |
26
26
  | `Image` | `Image` | Auto; numeric `size={128}` → `size="128x128"`, `rounded`→`isRounded` |
@@ -28,7 +28,7 @@ codemod converts it; **Flagged** = it leaves a `TODO(bestax-migrate)` comment (s
28
28
  | `Loader` | plain `<div className="loader">` | Auto (Bulma v1 still ships the class); swap in bestax's `Loader` by hand for its progressbar role and accessible name |
29
29
  | `Media` | `Media` | Auto |
30
30
  | `Menu` | `Menu` | Auto |
31
- | `Message` | `Message` | Auto; `size` flagged |
31
+ | `Message` | `Message` | Auto; unknown or dynamic `size` flagged |
32
32
  | `Modal` | `Modal` | `show`→`active`, `closeOnEsc`→`closeOnEscape`; `closeOnBlur`/`showClose` flagged (compound form renders neither) |
33
33
  | `Navbar` | `Navbar` | Auto; see dropdown note below |
34
34
  | `Notification` | `Notification` | Auto; `light`→`isLight` |
@@ -46,7 +46,7 @@ codemod converts it; **Flagged** = it leaves a `TODO(bestax-migrate)` comment (s
46
46
  | RBC | bestax |
47
47
  | ----------------------------------------------------------- | ------------------------------------------------------------------------ |
48
48
  | `Breadcrumb.Item` | plain `<li><a href=…>` (`active` → `is-active`) |
49
- | `Button.Group` | `Buttons` (`align="right"`→`isRight`) |
49
+ | `Button.Group` | `Buttons` (`align="right"`→`isRight`); unknown or dynamic `size` flagged |
50
50
  | `Card.Header` / `.Title` / `.Icon` | `Card.Header` / `.Header.Title` / `.Header.Icon` |
51
51
  | `Card.Image` | `Card.Image` wrapping an inner `<Image>` |
52
52
  | `Card.Content` | `Card.Content` |
@@ -46,6 +46,28 @@ href="/x">`) keeps the element and drops the `href`, with a `prop:href` TODO. RB
46
46
  `<Button href="/x">` with no `renderAs` goes the same way: bestax's `Button` renders a
47
47
  `<button>`. Set `as="a"` to make it a link.
48
48
 
49
+ ## `Heading` sizes
50
+
51
+ RBC's `Heading` rendered an `<h1>` at every size, subtitle or not, or the element `renderAs`
52
+ named. bestax's `Title` and `SubTitle` render the heading their `size` names unless `as="p"`, so
53
+ the codemod keeps the element RBC rendered:
54
+
55
+ | RBC | bestax-bulma | renders |
56
+ | ------------------------------------------ | ------------------------------ | ------- |
57
+ | `<Heading size={4}>` | `<Title textSize="4">` | `<h1>` |
58
+ | `<Heading size={1}>` | `<Title size="1">` | `<h1>` |
59
+ | `<Heading subtitle size={6}>` | `<SubTitle textSize="6">` | `<h1>` |
60
+ | `<Heading renderAs="h2" size={5}>` | `<Title as="h2" textSize="5">` | `<h2>` |
61
+ | `<Heading renderAs="p" subtitle size={5}>` | `<SubTitle as="p" size="5">` | `<p>` |
62
+
63
+ `size` stays only where it renders the same element: a `<p>`, or the heading the size names.
64
+ Everywhere else the size moves to the `textSize` helper, and so does a 7, which bestax's `size`
65
+ does not take. The helper sets the same font size through Bulma's `is-size-4` class rather than the
66
+ title's own `is-4`, so a rule of your own that targets `.title.is-4` needs the new class too.
67
+ `is-size-4` is also `!important`, so a font size your own CSS gives the title, such as
68
+ `.hero .title`, now loses to it where it used to beat `is-4`. A literal outside 1 to 7 keeps `size`
69
+ and gets a `prop:size` TODO.
70
+
49
71
  ## Boolean modifier convention
50
72
 
51
73
  RBC uses bare booleans (`loading`, `outlined`, `rounded`, `fullwidth`); bestax prefixes
@@ -129,22 +129,47 @@ bestax `Button` colors are the semantic set + `text`/`ghost`. For shades use
129
129
  `bgColor`/`textColor` (they accept the full palette incl. shades), and replace
130
130
  `isSelected` with `className="is-selected"` inside grouped buttons.
131
131
 
132
- ## `colorVariant` / Hero `gradient` / Hero `halfheight`
132
+ ## `colorVariant` / Hero `gradient` / Hero `halfheight` (`prop:size`)
133
133
 
134
134
  - `colorVariant="light"` → `isLight` where supported (Button, Notification), otherwise a
135
135
  shade: `bgColor="primary-90"`.
136
136
  - Bulma v1 removed `is-bold` hero gradients — delete `gradient` or restyle with CSS.
137
137
  - `halfheight` has no bestax size; use `size="medium"` or a CSS height.
138
138
 
139
+ ## A size bestax doesn't take (`prop:size` on `Button.Group` and `Message`)
140
+
141
+ `Button.Group` and `Message` sizes carry over as written when bestax's `Buttons` or `Message`
142
+ takes the value. Any other value, or one the codemod can't read, stays as written with a TODO
143
+ that lists the sizes that component takes: use one of them, or drop the prop.
144
+
145
+ ## `prop:size` on `Heading`: a size the codemod cannot carry
146
+
147
+ RBC's `Heading` rendered an `<h1>` at every size, subtitle or not. bestax's `Title` and
148
+ `SubTitle` render the heading their `size` names unless `as="p"`, so a literal size moves to
149
+ `textSize` to keep the level (see "`Heading` sizes" in the prop map). A dynamic one cannot move,
150
+ because `textSize` takes a string, so it stays `size`. Pass it to `textSize` yourself:
151
+
152
+ ```jsx
153
+ <Heading size={compact ? 5 : 4}>Report</Heading>
154
+ <Title textSize={compact ? '5' : '4'}>Report</Title>
155
+ ```
156
+
157
+ A literal outside 1 to 7 has no Bulma class, and bestax renders none for it either: drop it, or set
158
+ a `textSize` from `'1'` to `'7'`.
159
+
160
+ The same TODO marks a `Heading` that sets `size` and `textSize` both: drop `size` and let
161
+ `textSize` set the font size.
162
+
139
163
  ## `domRef`
140
164
 
141
- bestax components don't take `domRef`, but many forward a plain `ref` — the form controls,
142
- plus `Avatar`, `Button`, `Carousel`, `CarouselItem`, `Dialog`, `Dropdown`, `Link`,
143
- `LinkButton`, `Loader`, `Menu.Item`, `Modal`, `Navbar`, `Navbar.Burger`, `Navbar.Dropdown`,
144
- `Navbar.Item`, `Navbar.Link`, `Sidebar` and `Toast`. On those, rename `domRef` to
145
- `ref` and it works; do not restructure the markup. "The form controls" means the inputs
146
- themselves: the `Field`, `Field.Label`, `Field.Body`, `Checkboxes` and `Radios` wrappers
147
- around them forward nothing, and `Field` is a target this codemod emits.
165
+ bestax components don't take `domRef`, but many forward a plain `ref` — the form controls, plus
166
+ `Avatar`, `Button`, `Carousel`, `CarouselItem`, `Dialog`, `Dropdown`, `EmptyState`, `Kbd`,
167
+ `Kbd.Group`, `Link`, `LinkButton`, `Loader`, `Menu.Item`, `Modal`, `Navbar`, `Navbar.Burger`,
168
+ `Navbar.Dropdown`, `Navbar.Item`, `Navbar.Link`, `SegmentedControl`, `SegmentedControl.Segment`,
169
+ `Sidebar`, `Toast` and `ToggleButton`. On those, rename `domRef` to `ref` and it works; do not
170
+ restructure the markup. "The form controls" means the inputs themselves: the `Field`, `Field.Label`,
171
+ `Field.Body`, `Checkboxes` and `Radios` wrappers around them forward nothing, and `Field` is a
172
+ target this codemod emits.
148
173
 
149
174
  Everywhere else the rename is not enough, and the two React majors differ: React 18 drops the
150
175
  ref and logs "Function components cannot be given refs", while React 19 passes it through as
@@ -126,6 +126,8 @@ partial inventory, and a worked example are in `references/modular-build.md`.
126
126
  `material-icons`, `material-symbols`) with their CSS imports in `src/main.*`, or Ionicons
127
127
  CDN `<script>` tags in `index.html`. Icon fonts often outweigh Bulma itself — if no
128
128
  `<Icon>` uses that library, delete the dependency/import/script. Pure win, no tooling.
129
+ When the app does render Material Symbols, its font can be made smaller instead of
130
+ removed: see [Making the font smaller](https://bestax.io/docs/guides/getting-started/alternative-icons#making-the-font-smaller).
129
131
 
130
132
  ## References
131
133
 
@@ -73,15 +73,15 @@ Every extras partial that exists (from the library's `src/scss/**/_index.scss`
73
73
  is **more complete** than the docs page's Option C example, which omits several):
74
74
 
75
75
  **Components** (`@allxsmith/bestax-bulma/scss/components/<name>`):
76
- `loading`, `collapse`, `tooltip`, `popover`, `steps`, `sidebar`, `toast`, `dialog`, `carousel`,
77
- `tabs`, `reveal`, `avatar`, `avatars`, `badge`
76
+ `loading`, `collapse`, `tooltip`, `popover`, `hovercard`, `contextmenu`, `steps`, `sidebar`,
77
+ `toast`, `dialog`, `carousel`, `tabs`, `reveal`, `avatar`, `avatars`, `badge`, `emptystate`
78
78
 
79
79
  **Form** (`@allxsmith/bestax-bulma/scss/form/<name>`):
80
80
  `checkbox`, `radio`, `switch`, `slider`, `numberinput`, `rate`, `autocomplete`, `taginput`,
81
81
  `picker-popover`, `dateinput`, `timeinput`, `datetimeinput`, `daterangeinput`
82
82
 
83
- **Elements** (`@allxsmith/bestax-bulma/scss/elements/<name>`): `linkbutton`, `loader`,
84
- `progress`, `skeleton`
83
+ **Elements** (`@allxsmith/bestax-bulma/scss/elements/<name>`): `kbd`, `linkbutton`, `loader`,
84
+ `notification`, `progress`, `skeleton`
85
85
 
86
86
  **Helpers** (`@allxsmith/bestax-bulma/scss/helpers/<name>`): `cursor`, `sizing`
87
87
 
@@ -96,6 +96,8 @@ Notes:
96
96
  `picker-popover` too.
97
97
  - `Popover.Close` renders a Bulma button, so an app using it needs `bulma/sass/elements/button`
98
98
  next to `scss/components/popover`.
99
+ - `ContextMenu`'s menu is Bulma's dropdown markup, so an app using it needs
100
+ `bulma/sass/components/dropdown` next to `scss/components/contextmenu`.
99
101
  - `Loader` is stock Bulma styled by `bulma/sass/elements/loader`, and the `isLoading`
100
102
  spinners on `Button`, `Control` and `Select` are Bulma's too. The `loader` extras partial
101
103
  stops all of them under `prefers-reduced-motion: reduce`, so include it next to the Bulma
@@ -105,6 +107,10 @@ Notes:
105
107
  `bulma/sass/base/skeleton`). The `progress` and `skeleton` extras partials stop the
106
108
  indeterminate bar's sweep and the skeleton pulse (`Skeleton`, the `skeleton` prop,
107
109
  `hasSkeleton`) under `prefers-reduced-motion: reduce`, the same way and in either order.
110
+ - `Notification` is stock Bulma too (`bulma/sass/elements/notification`). The `notification`
111
+ extras partial pads the end of one with a close button (`hasDelete`, or a `Delete` passed in)
112
+ so its text clears the button, so include it next to the Bulma module in any build that shows
113
+ a dismissible notification. It doesn't depend on the order of the two `@use` lines either.
108
114
  - Stock-Bulma form controls still need their Bulma module (`bulma/sass/form/…`); the extras
109
115
  form partials above style only the bestax-specific behavior.
110
116
  - Bulma component modules pull their own internal sub-elements — e.g.
@@ -154,12 +160,13 @@ not `flexbox` — `flexbox` holds only the alignment props. Verified failure mod
154
160
 
155
161
  The `npm create bestax` starter renders `Container`, `Section`, `Columns`/`Column`, `Image`,
156
162
  `Title`/`SubTitle`, `Box`, `Card`, `Buttons`/`Button`, and `Notification` with its close
157
- button: all stock Bulma, no bestax extras. Its helper props are `display` (visibility),
158
- `flexGrow` (flexbox), and `textAlign` (typography); it uses no spacing or color props. That
159
- inventory compiles to the following, verified pixel-equivalent to the prebuilt `complete`
160
- flavor in headless Chromium (light and dark, phone and desktop width, notification open), at
161
- 274 KB raw / 30 KB gzip vs 819 KB / 84 KB. Scaffolded with an icon library, the starter also
162
- needs `bulma/sass/elements/icon` for its `IconText` card titles:
163
+ button: all stock Bulma, plus the `notification` extras partial for that close button. Its
164
+ helper props are `display` (visibility), `flexGrow` (flexbox), and `textAlign` (typography);
165
+ it uses no spacing or color props. That inventory compiles to the following, verified
166
+ pixel-equivalent to the prebuilt `complete` flavor in headless Chromium (light and dark, phone
167
+ and desktop width, notification open), at 274 KB raw / 30 KB gzip vs 819 KB / 84 KB.
168
+ Scaffolded with an icon library, the starter also needs `bulma/sass/elements/icon` for its
169
+ `IconText` card titles:
163
170
 
164
171
  ```scss
165
172
  // src/styles.scss
@@ -184,6 +191,8 @@ needs `bulma/sass/elements/icon` for its `IconText` card titles:
184
191
  @use 'bulma/sass/helpers/visibility'; // display="flex"
185
192
  @use 'bulma/sass/helpers/flexbox'; // flexGrow
186
193
  @use 'bulma/sass/helpers/typography'; // textAlign
194
+
195
+ @use '@allxsmith/bestax-bulma/scss/elements/notification'; // text clears the close button
187
196
  ```
188
197
 
189
198
  ```tsx
@@ -20,7 +20,10 @@ Choose an override path:
20
20
  - **`Theme` component (runtime, preferred).** Exported from the package. Pass named HSL props
21
21
  (`primaryH`, `primaryS`, `primaryL`, …) and/or `bulmaVars={{ '--bulma-*': '…' }}` for everything
22
22
  else. Add `isRoot` to inject the variables globally at `:root` (once, at the app root); omit it to
23
- scope the variables to the wrapped subtree.
23
+ scope the variables to the wrapped subtree. A `Theme` only reaches variables the component
24
+ inherits: Bulma declares component variables such as `--bulma-card-radius` on the component's
25
+ own element, so a `Theme` value for one never applies (it warns in development). Set those on
26
+ the component with `className` or `style` instead (see `references/css-variables.md`).
24
27
  - **Plain CSS.** Set `:root { --bulma-primary-h: …; }` (or any selector) directly.
25
28
  - **Build-time Sass.** `@use 'bulma/sass' with ($primary: #1e6b99)` when compiling Bulma's Sass.
26
29