create-bestax 4.2.18 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +13 -3
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +1 -0
  4. package/dist/constants.d.ts +12 -0
  5. package/dist/constants.d.ts.map +1 -1
  6. package/dist/constants.js +69 -1
  7. package/dist/file-system.d.ts +5 -1
  8. package/dist/file-system.d.ts.map +1 -1
  9. package/dist/file-system.js +11 -1
  10. package/dist/library-range.d.ts +16 -0
  11. package/dist/library-range.d.ts.map +1 -0
  12. package/dist/library-range.js +40 -0
  13. package/dist/project-creator.d.ts +8 -0
  14. package/dist/project-creator.d.ts.map +1 -1
  15. package/dist/project-creator.js +62 -3
  16. package/dist/prompts.d.ts +1 -0
  17. package/dist/prompts.d.ts.map +1 -1
  18. package/dist/prompts.js +15 -1
  19. package/package.json +8 -8
  20. package/templates/skills/bestax-custom-component/references/component-catalog.md +5 -1
  21. package/templates/skills/bestax-form/SKILL.md +40 -15
  22. package/templates/skills/bestax-form/references/api.md +10 -8
  23. package/templates/skills/bestax-form/references/patterns.md +68 -0
  24. package/templates/skills/bestax-icons/references/icon-libraries.md +14 -1
  25. package/templates/skills/bestax-layout-scaffold/SKILL.md +31 -5
  26. package/templates/skills/bestax-layout-scaffold/references/archetypes.md +2 -2
  27. package/templates/skills/bestax-layout-scaffold/references/layout-components.md +52 -5
  28. package/templates/skills/bestax-migrate/SKILL.md +19 -5
  29. package/templates/skills/bestax-migrate/references/bloomer/component-map.md +1 -1
  30. package/templates/skills/bestax-migrate/references/bloomer/prop-map.md +9 -6
  31. package/templates/skills/bestax-migrate/references/bloomer/unmappables.md +4 -1
  32. package/templates/skills/bestax-migrate/references/bulma-classes/component-map.md +182 -105
  33. package/templates/skills/bestax-migrate/references/bulma-classes/prop-map.md +50 -17
  34. package/templates/skills/bestax-migrate/references/bulma-classes/unmappables.md +372 -64
  35. package/templates/skills/bestax-migrate/references/css-migration.md +12 -5
  36. package/templates/skills/bestax-migrate/references/rbx/prop-map.md +20 -14
  37. package/templates/skills/bestax-migrate/references/react-bulma-components/prop-map.md +27 -22
  38. package/templates/skills/bestax-migrate/references/react-bulma-components/unmappables.md +3 -3
  39. package/templates/skills/bestax-optimize/references/modular-build.md +59 -17
  40. package/templates/skills/bestax-theming/SKILL.md +22 -8
  41. package/templates/skills/bestax-theming/examples/dark-mode.tsx +100 -17
  42. package/templates/skills/bestax-theming/examples/theme-config.tsx +20 -8
  43. package/templates/skills/bestax-theming/references/css-variables.md +268 -20
  44. package/templates/skills/bestax-theming/references/themeable-components.md +4 -0
  45. package/templates/vite/README.md +2 -2
  46. package/templates/vite/_oxlintrc.json +8 -0
  47. package/templates/vite/package.json +9 -13
  48. package/templates/vite/src/main.jsx +1 -1
  49. package/templates/vite/vite.config.js +1 -1
  50. package/templates/vite-ts/README.md +2 -2
  51. package/templates/vite-ts/_oxlintrc.json +8 -0
  52. package/templates/vite-ts/package.json +11 -16
  53. package/templates/vite-ts/src/main.tsx +1 -1
  54. package/templates/vite/eslint.config.js +0 -29
  55. package/templates/vite-ts/eslint.config.js +0 -26
@@ -10,7 +10,11 @@ theming means overriding the right `--bulma-*` values.
10
10
 
11
11
  `Theme` is exported from the package and writes `--bulma-*` variables for you.
12
12
 
13
- - `isRoot` → injects the variables globally at `:root` (use once, at the app root).
13
+ - `isRoot` → injects the variables globally at `:root` (use once, at the app root). It writes
14
+ them before the browser paints what it rendered, so an app rendered in the browser has them
15
+ from its first frame of content. A server render doesn't include them, so a server-rendered
16
+ page paints with the stylesheet's values until it hydrates: put what it needs from its first
17
+ paint in CSS (path 2).
14
18
  - without `isRoot` → wraps children in a `<div>` and scopes the variables to that subtree.
15
19
  - Named props set the color/scheme HSL channels and common values (see "Theme props" below).
16
20
  - `bulmaVars` sets any other variable, keyed by its real `--bulma-*` name. It only changes
@@ -67,9 +71,8 @@ If compiling Bulma's Sass yourself, set the SCSS variables before the CSS variab
67
71
 
68
72
  ## Colors — override the H/S/L trio to recolor
69
73
 
70
- Bulma derives a color's entire palette (shades, light/dark/invert variants) from three channels.
71
- Override the trio; the rest follows automatically. For each color `<c>` ∈ `primary`, `link`,
72
- `info`, `success`, `warning`, `danger`:
74
+ Each color is three channels. For each color `<c>` ∈ `primary`, `link`, `info`, `success`,
75
+ `warning`, `danger`:
73
76
 
74
77
  | Variable | Meaning | `Theme` prop |
75
78
  | --------------- | -------------------------- | ------------------------ |
@@ -77,9 +80,105 @@ Override the trio; the rest follows automatically. For each color `<c>` ∈ `pri
77
80
  | `--bulma-<c>-s` | saturation (`%`) | `<c>S` |
78
81
  | `--bulma-<c>-l` | lightness (`%`) | `<c>L` |
79
82
 
80
- Read-only derived values (set automatically; reference if you need them): `--bulma-<c>` (the
81
- resolved color), `--bulma-<c>-invert`, `--bulma-<c>-light`, `--bulma-<c>-dark`, `--bulma-<c>-rgb`,
82
- and numeric shades `--bulma-<c>-00` … `--bulma-<c>-95`.
83
+ What a runtime trio moves: `--bulma-<c>`, the color itself, follows all three channels. Its
84
+ shades, its light and dark variants, and its invert and on-scheme colors follow the hue and
85
+ saturation, each at a lightness Bulma's Sass build wrote into the stylesheet for the color it was
86
+ given:
87
+
88
+ - the numeric shades `--bulma-<c>-00` … `--bulma-<c>-100` sit on a ramp of lightnesses
89
+ (`--bulma-<c>-<n>-l`) laid out from the built color's own, and `--bulma-<c>-light` and
90
+ `--bulma-<c>-dark` point into it. A new `-l` moves none of them, so a shade is as light as it
91
+ was before; only a Sass build lays the ramp out from a new color.
92
+ - `--bulma-<c>-invert` and `--bulma-<c>-on-scheme` take the lightnesses below, which the build
93
+ picked for contrast.
94
+
95
+ `--bulma-<c>-rgb` is the built color written out as a value, so it follows none of the trio.
96
+
97
+ ### The lightnesses Bulma's build picks for contrast
98
+
99
+ The build picks the label and text lightnesses for each color by their contrast with the color it
100
+ was given. A trio set at runtime leaves them as they were, so when a new color reads lighter or
101
+ darker than the built one, which a change of hue or saturation can do as well as a change of
102
+ lightness, set them too:
103
+
104
+ | Variable | What reads it |
105
+ | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
106
+ | `--bulma-<c>-invert-l` | the label on a solid `<c>` surface: `Button`, `Tag` and `Notification` with `color="<c>"`, a colored `Hero` or `Navbar`, … |
107
+ | `--bulma-<c>-on-scheme-l` | `<c>` text on the page: `textColor="<c>" colorShade="on-scheme"`, a colored `Message`'s body, a field's colored help text, … |
108
+
109
+ For `link`, the on-scheme lightness is also every link on the page (`--bulma-link-text`), so a new
110
+ link color that reads lighter than Bulma's own leaves the page's links pale.
111
+
112
+ bestax's stylesheet builds its primary from a dark blue, so the primary's invert is white
113
+ (`var(--bulma-primary-100-l)`). A light primary set through the trio alone keeps those white
114
+ labels: on stock Bulma's turquoise they read at under 2:1. Its on-scheme lightness was picked for
115
+ the blue too, and is too light for turquoise text on a white page. The other colors are built
116
+ from Bulma's own defaults. For a page made for stock Bulma, the bestax-migrate skill's
117
+ `references/css-migration.md` covers getting its turquoise back.
118
+
119
+ Set them alongside the trio, through `Theme`'s `bulmaVars` or in your CSS:
120
+
121
+ - **The invert** is one value for both schemes. Point it at a shade that reads on the new color: a
122
+ near-black `var(--bulma-<c>-05-l)` on a light color, a near-white `var(--bulma-<c>-100-l)` on a
123
+ dark one.
124
+ - **The on-scheme lightness** has to read on the page's background, so Bulma gives each scheme
125
+ its own. One value applies in both schemes, so give each scheme its own: on an `isRoot`
126
+ `Theme`, the on-scheme keys of `bulmaVars` take `{ light, dark }`, and `Theme` writes each
127
+ where Bulma's own value for that scheme applies. A scheme you leave out keeps the
128
+ stylesheet's value. `bestax-no-dark-mode.css` has no dark scheme, so with it give one string.
129
+
130
+ ```tsx
131
+ // Stock Bulma's turquoise, with the values from bulma/css/bulma.css.
132
+ <Theme
133
+ isRoot
134
+ primaryH="171deg"
135
+ primaryS="100%"
136
+ primaryL="41%"
137
+ bulmaVars={{
138
+ '--bulma-primary-invert-l': 'var(--bulma-primary-05-l)',
139
+ '--bulma-primary-on-scheme-l': { light: '21%', dark: '41%' },
140
+ }}
141
+ >
142
+ <App />
143
+ </Theme>
144
+ ```
145
+
146
+ A scoped `Theme` writes its variables as an inline style, which can't hold a value per scheme, so
147
+ there the on-scheme lightness takes only a string, and `{ light, dark }` is skipped with a warning
148
+ in development. Set it in your CSS instead when a scoped section needs one per scheme, or when
149
+ the page is rendered on the server, which paints before `Theme` runs. In CSS, loaded after the
150
+ library's styles, a value on `:root` wins in both schemes, so give dark mode its own value on
151
+ both of its paths:
152
+
153
+ ```css
154
+ /* Stock Bulma's turquoise, with the values from bulma/css/bulma.css. */
155
+ :root {
156
+ --bulma-primary-h: 171deg;
157
+ --bulma-primary-s: 100%;
158
+ --bulma-primary-l: 41%;
159
+ --bulma-primary-invert-l: var(--bulma-primary-05-l);
160
+ --bulma-primary-on-scheme-l: 21%;
161
+ }
162
+ [data-theme='dark'] {
163
+ --bulma-primary-on-scheme-l: 41%;
164
+ }
165
+ @media (prefers-color-scheme: dark) {
166
+ :root:not([data-theme]) {
167
+ --bulma-primary-on-scheme-l: 41%;
168
+ }
169
+ }
170
+ ```
171
+
172
+ For a color of your own, pick each value by its contrast (4.5:1 or more for text), or build
173
+ Bulma's Sass with the color (`@use 'bulma/sass' with ($primary: …)`), which computes both.
174
+
175
+ `textColor="<c>"` alone renders `has-text-<c>`, which reads the trio's own lightness, so text in a
176
+ light color on a light page takes `colorShade="on-scheme"` as well.
177
+
178
+ The build pairs each numbered shade, and the light and dark variants, with a label shade the same
179
+ way (`--bulma-<c>-<n>-invert-l`, `--bulma-<c>-light-invert-l`, `--bulma-<c>-dark-invert-l`),
180
+ picked for the hue and saturation it was given. After a change of hue, check the contrast of text
181
+ you put on a numbered shade.
83
182
 
84
183
  ## Scheme, text, background, border (light/dark surfaces)
85
184
 
@@ -178,6 +277,9 @@ lone class or the `style` prop cannot outrank:
178
277
  its own declaration — target the declaring element in your CSS:
179
278
  `.tooltip-content { --bulma-tooltip-background: … }`.
180
279
 
280
+ The `style` prop also misses on Checkbox and Radio, which put it on their hidden `<input>`; set
281
+ their variables through `className` (see their entries below).
282
+
181
283
  ### Avatar / Avatars / Badge
182
284
 
183
285
  | Variable | Default |
@@ -233,12 +335,31 @@ own-selector override rule applies.
233
335
  `--bulma-carousel-indicator-line-height`, `--bulma-carousel-indicator-line-height-mobile`,
234
336
  `--bulma-carousel-indicator-line-radius`, `--bulma-carousel-indicator-line-width`,
235
337
  `--bulma-carousel-indicator-line-width-mobile`, `--bulma-carousel-indicator-size`,
236
- `--bulma-carousel-indicator-size-mobile`, `--bulma-carousel-overlay-arrow-background`,
338
+ `--bulma-carousel-indicator-size-mobile`, `--bulma-carousel-item-gap`,
339
+ `--bulma-carousel-items-in-view`, `--bulma-carousel-items-to-show`,
340
+ `--bulma-carousel-items-to-show-desktop`, `--bulma-carousel-items-to-show-fullhd`,
341
+ `--bulma-carousel-items-to-show-mobile`, `--bulma-carousel-items-to-show-tablet`,
342
+ `--bulma-carousel-items-to-show-widescreen`, `--bulma-carousel-overlay-arrow-background`,
237
343
  `--bulma-carousel-overlay-arrow-background-hover`, `--bulma-carousel-overlay-arrow-color`,
238
344
  `--bulma-carousel-overlay-indicator-background`,
239
345
  `--bulma-carousel-overlay-indicator-background-active`,
240
346
  `--bulma-carousel-overlay-indicator-background-hover`, `--bulma-carousel-transition-duration`
241
347
 
348
+ `--bulma-carousel-item-gap` (a length, default `0px`) is the space between items in view; set it
349
+ on the carousel's own element through a class. The `--bulma-carousel-items-to-show*` variables
350
+ come from the `itemsToShow*` props, and `--bulma-carousel-items-in-view` is the one of them the
351
+ viewport picks. The props also decide how far a step moves, so set the count with the props
352
+ rather than with these variables.
353
+
354
+ The `--bulma-carousel-overlay-*` variables color the arrows, and indicators over the slides, only
355
+ while the overlay look is on: `overlayControls`, which follows `indicatorInside` unless set. The look
356
+ also puts a dark gradient band behind indicators over the slides (a `background`, not a variable),
357
+ and while it's on the arrows ignore `arrowColor`. For indicators over light slides, such as white
358
+ cards, use `<Carousel indicatorInside overlayControls={false}>`: plain colors and no band.
359
+ `overlayControls` alone gives the arrows the overlay look with the indicators below the slides. The
360
+ overlay colors default to light ones (`--bulma-white`) in either color scheme, since they sit on a
361
+ dark tint.
362
+
242
363
  ### Checkbox
243
364
 
244
365
  `--bulma-checkbox-active-color`, `--bulma-checkbox-background`, `--bulma-checkbox-border-color`,
@@ -247,6 +368,23 @@ own-selector override rule applies.
247
368
  `--bulma-checkbox-label-gap`, `--bulma-checkbox-radius`, `--bulma-checkbox-size`,
248
369
  `--bulma-checkbox-transition-duration`
249
370
 
371
+ The check mark and the mixed dash are both `--bulma-checkbox-check-color`, on the
372
+ `--bulma-checkbox-active-color` (checked) or `--bulma-checkbox-indeterminate-color` (mixed) fill,
373
+ so a dark fill needs a light check color. Set these on a class you pass through `className`, not
374
+ with `style`: Checkbox puts `style` and its other attributes on the hidden `<input>`, not on the
375
+ `.styled-checkbox` label that declares them. Name both classes in the selector
376
+ (`.styled-checkbox.my-box`, mind the class prefix) so it wins whatever order the stylesheets load
377
+ in. A `color` prop declares both fills again on `.styled-checkbox.is-<color>`, which ties with
378
+ that selector, so leave `color` unset when a class sets the fill. The unchecked border, `--bulma-checkbox-border-color`, defaults to `text-weak` so
379
+ the box holds the 3:1 WCAG asks of a control's boundary; keep a replacement at 3:1 against what
380
+ the form sits on.
381
+
382
+ `--bulma-checkbox-size` (default `1.25em`) can't take the box below 24px: the stylesheet gives the
383
+ `.check` box a `min-width` and `min-height` of 24px, WCAG 2.2's minimum target size, so with
384
+ Bulma's default font sizes the box is 24px at the default and `small` sizes. For a smaller box, set the size and also
385
+ `min-width: 0; min-height: 0` on `.styled-checkbox.my-box .check` (mind the class prefix), and keep
386
+ the label text inside the `Checkbox`, since the whole label is the click target.
387
+
250
388
  ### Collapse
251
389
 
252
390
  `--bulma-collapse-border-color`, `--bulma-collapse-group-gap`, `--bulma-collapse-header-weight`,
@@ -258,6 +396,30 @@ items of a `Collapses` group, which reads it with a 0.5rem fallback and declares
258
396
  so set it on the group or on any ancestor, `:root` included. (`Theme`'s `bulmaVars` does not
259
397
  list it, so set it in your CSS or through a `style` prop.)
260
398
 
399
+ ### Combobox
400
+
401
+ Declared on the root, `.combobox`, and again on a menu rendered with `appendToBody`,
402
+ `.combobox-menu.is-portal`, outside the root. A menu in place inherits the root's, so a value set on
403
+ `.combobox` reaches it; for a portaled one, set it on `.combobox-menu.is-portal` as well, where
404
+ they're declared. A lone `.combobox-menu` loses to that on specificity, and
405
+ `.combobox-menu.is-portal` ties, so your rule wins only when it loads after the library styles. Each
406
+ size class (`.is-small`, `.is-medium`, `.is-large`, on the root and on the menu) sets the item size
407
+ and padding, so retune a size on that class. The highlight is the link color and its invert, the
408
+ pair Bulma gives an active dropdown item, and the colors come from Bulma's tokens, so the list
409
+ follows dark mode with no override. The menu reads these rather than Bulma's `--bulma-dropdown-*`,
410
+ which Bulma declares on `.dropdown` alone.
411
+
412
+ `--bulma-combobox-check-color`, `--bulma-combobox-check-gap`, `--bulma-combobox-check-size`,
413
+ `--bulma-combobox-disabled-color`, `--bulma-combobox-divider-color`, `--bulma-combobox-empty-color`,
414
+ `--bulma-combobox-group-label-color`, `--bulma-combobox-group-label-size`,
415
+ `--bulma-combobox-group-label-weight`, `--bulma-combobox-highlight-background`,
416
+ `--bulma-combobox-highlight-color`, `--bulma-combobox-item-color`,
417
+ `--bulma-combobox-item-hover-background`, `--bulma-combobox-item-padding-x`,
418
+ `--bulma-combobox-item-padding-y`, `--bulma-combobox-item-size`, `--bulma-combobox-list-max-height`,
419
+ `--bulma-combobox-menu-background`, `--bulma-combobox-menu-border-color`,
420
+ `--bulma-combobox-menu-offset`, `--bulma-combobox-menu-padding-y`, `--bulma-combobox-menu-radius`,
421
+ `--bulma-combobox-menu-shadow`, `--bulma-combobox-menu-z-index`, `--bulma-combobox-portal-z-index`
422
+
261
423
  ### ContextMenu
262
424
 
263
425
  Both are declared on the box the menu hangs from, `.context-menu-content`, which is portaled away
@@ -368,6 +530,17 @@ Declared on the compound `.button.link-button` — see the compound-selector exc
368
530
  `--bulma-loading-overlay-opacity-opaque`, `--bulma-loading-text-color`,
369
531
  `--bulma-loading-text-size`
370
532
 
533
+ ### Menu
534
+
535
+ `Menu.Section`'s, declared on the root, `.menu`, where Bulma declares its own `--bulma-menu-*`:
536
+ the room between a section heading's words and its chevron, and the chevron's box, color and
537
+ turn. The heading itself reads Bulma's label variables (`--bulma-menu-label-color`,
538
+ `--bulma-menu-label-font-size`, `--bulma-menu-label-letter-spacing`,
539
+ `--bulma-menu-label-spacing`), so retheming the menu's labels restyles section headings too.
540
+
541
+ `--bulma-menu-section-chevron-color`, `--bulma-menu-section-chevron-duration`,
542
+ `--bulma-menu-section-chevron-size`, `--bulma-menu-section-gap`
543
+
371
544
  ### Notification
372
545
 
373
546
  `--bulma-notification-delete-padding-inline-end` is the end padding of a notification with a close
@@ -383,6 +556,16 @@ sizes. Bulma's own `--bulma-notification-*` variables set the rest.
383
556
  `--bulma-numberinput-stepper-button-hover-bg`, `--bulma-numberinput-stepper-button-hover-color`,
384
557
  `--bulma-numberinput-stepper-width`
385
558
 
559
+ ### PinInput
560
+
561
+ Declared on the row, `.pin-input`. Each box is a Bulma `.input`, so Bulma's `--bulma-input-*`
562
+ variables color it, and a box's size comes from its size class. The gap and the caret's size are
563
+ in `em`, so they follow the size of the boxes, and the caret is `currentColor`, the box's text.
564
+
565
+ `--bulma-pin-input-box-width`, `--bulma-pin-input-caret-blink-duration`,
566
+ `--bulma-pin-input-caret-color`, `--bulma-pin-input-caret-height`, `--bulma-pin-input-caret-width`,
567
+ `--bulma-pin-input-gap`
568
+
386
569
  ### Picker popover (DateInput / TimeInput / DateTimeInput / DateRangeInput)
387
570
 
388
571
  `--bulma-picker-popover-animation-duration`, `--bulma-picker-popover-background`,
@@ -410,6 +593,18 @@ them. See the constituent-element exception above.
410
593
  `--bulma-radio-border-width`, `--bulma-radio-dot-color`, `--bulma-radio-focus-shadow-size`,
411
594
  `--bulma-radio-label-gap`, `--bulma-radio-size`, `--bulma-radio-transition-duration`
412
595
 
596
+ As with Checkbox, set these on a class you pass through `className`, with both classes in the
597
+ selector (`.styled-radio.my-radio`): `style` goes to the hidden `<input>`. A `color` prop
598
+ declares `--bulma-radio-active-color` again on `.styled-radio.is-<color>`, which ties that
599
+ selector, so leave `color` unset when a class sets it. The unchecked ring, `--bulma-radio-border-color`, defaults to `text-weak` for the same 3:1 boundary
600
+ contrast.
601
+
602
+ `--bulma-radio-size` (default `1.25em`) can't take the circle below 24px: the stylesheet gives the
603
+ `.check` circle a `min-width` and `min-height` of 24px, WCAG 2.2's minimum target size, so with
604
+ Bulma's default font sizes the circle is 24px at the default and `small` sizes. For a smaller circle, set the size and also
605
+ `min-width: 0; min-height: 0` on `.styled-radio.my-radio .check` (mind the class prefix), and keep
606
+ the label text inside the `Radio`, since the whole label is the click target.
607
+
413
608
  ### Rate
414
609
 
415
610
  `--bulma-rate-color-active`, `--bulma-rate-color-hover`, `--bulma-rate-color-inactive`,
@@ -426,6 +621,19 @@ them. See the constituent-element exception above.
426
621
  `--bulma-reveal-duration`, `--bulma-reveal-easing`, `--bulma-reveal-flip-angle`,
427
622
  `--bulma-reveal-offset`, `--bulma-reveal-offset-large`, `--bulma-reveal-scale`
428
623
 
624
+ ### ScrollArea
625
+
626
+ Declared on the frame, `.scroll-area`, and read by the viewport inside it, so set them on the
627
+ frame, through `className` or `style`. `--bulma-scroll-area-scrollbar-width` takes what
628
+ `scrollbar-width` takes: `thin`, `auto` or `none`. `none` hides the bars while the area still
629
+ scrolls, which hides that it scrolls at all, so keep to `thin` or `auto`. Restyled bars owe
630
+ WCAG's 3:1, so keep a thumb color that clears it against the background in both schemes. In forced colors the browser gives the bars the system's colors
631
+ whatever these say.
632
+
633
+ `--bulma-scroll-area-fade-size`, `--bulma-scroll-area-scrollbar-width`,
634
+ `--bulma-scroll-area-thumb-color`, `--bulma-scroll-area-thumb-hover-color`,
635
+ `--bulma-scroll-area-track-color`
636
+
429
637
  ### Sidebar
430
638
 
431
639
  `--bulma-sidebar-background`, `--bulma-sidebar-close-color`,
@@ -458,6 +666,18 @@ them. See the constituent-element exception above.
458
666
  `--bulma-slider-track-height-small`, `--bulma-slider-transition-duration`,
459
667
  `--bulma-slider-vertical-height`
460
668
 
669
+ ### Splitter
670
+
671
+ Declared on the root, `.splitter`. The handle reads them, and its line and grip are borders, so a
672
+ forced-colors page keeps them and draws an active handle in `Highlight`.
673
+ `--bulma-splitter-handle-size-coarse` is the strip's width for a coarse pointer, kept at 24px or
674
+ more for WCAG 2.5.8.
675
+
676
+ `--bulma-splitter-grip-color`, `--bulma-splitter-grip-length`, `--bulma-splitter-grip-radius`,
677
+ `--bulma-splitter-grip-size`, `--bulma-splitter-handle-size`,
678
+ `--bulma-splitter-handle-size-coarse`, `--bulma-splitter-line-active-color`,
679
+ `--bulma-splitter-line-active-size`, `--bulma-splitter-line-color`, `--bulma-splitter-line-size`
680
+
461
681
  ### Steps
462
682
 
463
683
  `--bulma-steps-animation-duration`, `--bulma-steps-content-margin-top`,
@@ -597,22 +817,48 @@ custom dark-mode CSS keyed off `[data-theme='dark']` still matches, because `col
597
817
  Under dark mode Bulma flips the scheme/text/border/background lightness variables (e.g.
598
818
  `--bulma-scheme-main-l` 100% → 9%, `--bulma-text-l` 29% → 71%). Your brand color overrides from
599
819
  `Theme isRoot` or `:root` still apply on top, because they set the hue/saturation/lightness
600
- channels directly.
820
+ channels directly. Each color's on-scheme lightness is the exception: Bulma gives dark mode its
821
+ own, so a new color sets one per scheme (see "The lightnesses Bulma's build picks for contrast").
822
+
823
+ ### The scheme of the first paint
824
+
825
+ `Theme` writes the attribute before the browser paints what it rendered, but a page can paint
826
+ before the app's script runs at all: a client-rendered app (the create-bestax scaffold, for one)
827
+ can show its empty page first, and a server-rendered one shows its server HTML. That first frame
828
+ takes whatever `<html>` already carries: with nothing there, the visitor's OS scheme, which then
829
+ flips. So the scheme for that frame comes from `index.html`:
830
+
831
+ - **A scheme that never changes** goes on the `<html>` itself,
832
+ `<html lang="en" data-theme="light">`, and needs no `colorMode`.
833
+ - **A scheme the visitor picks** is written by an inline script in `<head>`, from the saved
834
+ choice or else the OS preference, before anything renders. `examples/dark-mode.tsx` has the
835
+ script and the app's side: the app starts from the attribute the script wrote, passes its
836
+ state to `Theme colorMode` for the toggle, and saves each choice in `localStorage` under the
837
+ key the script reads. Keep it a plain inline script: one with `type="module"`, like the app's
838
+ own, waits until the whole page is parsed, which can be after the first paint.
839
+
840
+ A prefixed flavor reads `data-bestax-theme`, so with one, `index.html` and the script write that
841
+ attribute as well.
842
+
843
+ Because the script always writes an attribute, custom dark-mode CSS keyed on `[data-theme='dark']`
844
+ reaches every visitor. To offer the OS preference as a third choice, both sides change. The script
845
+ writes no attribute for a saved `'system'`. The app adds `'system'` to its `ColorMode` and to what
846
+ it reads back from storage, so it passes `colorMode="system"`, which keeps the attribute off, and
847
+ its toggle becomes a choice of three, such as a `SegmentedControl`. With no attribute, Bulma's
848
+ `prefers-color-scheme` rules apply from the first frame and follow the OS when it changes, and
849
+ custom tokens then need both dark-mode paths (below).
601
850
 
602
851
  ### The single-mode contrast trap
603
852
 
604
- Because the OS preference applies whenever no `data-theme` attribute is set — the default state
605
- of every app that never configured `colorMode` — a light-only design silently breaks for any
606
- dark-mode visitor: Bulma's text goes near-white while author-defined fixed tokens stay light —
853
+ Because the OS preference applies whenever no `data-theme` attribute is set, which is the
854
+ default state of every app that never sets one, a light-only design silently breaks for any
855
+ dark-mode visitor: Bulma's text goes near-white while author-defined fixed tokens stay light,
607
856
  white text on cream. The failure is invisible unless the author's own OS is in dark mode.
608
857
 
609
- **If the design is single-mode, pin the scheme** so text can't flip out from under the palette:
610
-
611
- ```tsx
612
- <Theme isRoot colorMode="light">
613
- <App />
614
- </Theme>
615
- ```
858
+ **If the design is single-mode, pin the scheme** on the `<html>` in `index.html`
859
+ (`<html lang="en" data-theme="light">`, as above), so text can't flip out from under the palette.
860
+ `<Theme isRoot colorMode="light">` pins it too, but only once the app's script runs, so the
861
+ page can show the OS scheme before that.
616
862
 
617
863
  **If both modes are supported, never expose a fixed custom token to the flip** — derive it from
618
864
  scheme variables, or flip it yourself:
@@ -655,4 +901,6 @@ Color trios: `primaryH/primaryS/primaryL`, `linkH/linkS/linkL`, `infoH/S/L`, `su
655
901
  `darkInvertL`, `softL`, `boldL`, `softInvertL`, `boldInvertL`. Interaction deltas:
656
902
  `hoverBackgroundLDelta`, `activeBackgroundLDelta`, `hoverBorderLDelta`, `activeBorderLDelta`,
657
903
  `hoverColorLDelta`, `activeColorLDelta`, `hoverShadowADelta`, `activeShadowADelta`. Everything else:
658
- `bulmaVars={{ '--bulma-…': '…' }}`. All values are strings.
904
+ `bulmaVars={{ '--bulma-…': '…' }}`, each color's `--bulma-<c>-invert-l` and
905
+ `--bulma-<c>-on-scheme-l` included. All values are strings, except that an on-scheme key also
906
+ takes `{ light, dark }` on an `isRoot` `Theme`.
@@ -60,6 +60,7 @@ Shades (`colorShade` / `backgroundColorShade`): `00, 05, 10, … 95, invert, lig
60
60
  | `SubTitle` | — (no `color`; use `textColor`) | `1`–`6` (string or number) | `size` also sets the heading level unless `as="p"` (an `<h1>` with neither): pair `as` with `textSize` instead |
61
61
  | `Autocomplete` | `primary \| link \| info \| success \| warning \| danger` | `small \| medium \| large` | the 6 only |
62
62
  | `Checkbox` | `primary \| link \| info \| success \| warning \| danger` | `small \| normal \| medium \| large` | the 6 only |
63
+ | `Combobox` | none on the root (`Combobox.Input` takes `Input`'s `color`) | `small \| medium \| large` | sizes the field and the items together; the highlight is `--bulma-combobox-highlight-*`; `--bulma-combobox-*` |
63
64
  | `DateInput` | `primary \| link \| info \| success \| warning \| danger` | `small \| medium \| large` | also `isRounded` |
64
65
  | `DateRangeInput` | `primary \| link \| info \| success \| warning \| danger` | `small \| medium \| large` | also `isRounded`; `color` also fills the calendar range |
65
66
  | `DateTimeInput` | `primary \| link \| info \| success \| warning \| danger` | `small \| medium \| large` | also `isRounded` |
@@ -72,14 +73,17 @@ Shades (`colorShade` / `backgroundColorShade`): `00, 05, 10, … 95, invert, lig
72
73
  | `Loading` | `primary \| link \| info \| success \| warning \| danger` | `small \| medium \| large` | spinner color; default light grey |
73
74
  | `Navbar` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white` | — | — |
74
75
  | `Numberinput` | `primary \| link \| info \| success \| warning \| danger \| light \| dark` | `small \| medium \| large` | also `inputColor` (the 6) for the inner input |
76
+ | `PinInput` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white` | `small \| medium \| large` | each box is a Bulma `.input`, so `--bulma-input-*` theme it; also `isRounded`; `--bulma-pin-input-*` |
75
77
  | `Pagination` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white` | `small \| medium \| large` | **entire `color` prop deprecated** (no CSS ships; dev-warn; removal next major) |
76
78
  | `Panel` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white` | — | — |
77
79
  | `Progress` | every `validColors` member (the `-bis`/`-ter` shades and the greys deprecated: no CSS, dev-warn, removed next major — see ⚠️) | `small \| medium \| large` | — |
78
80
  | `Radio` | `primary \| link \| info \| success \| warning \| danger` | `small \| normal \| medium \| large` | the 6 only |
79
81
  | `Rate` | `primary \| link \| info \| success \| warning \| danger` | `small \| medium \| large` | the 6 only |
82
+ | `ScrollArea` | — (no `color`: the thumb is `--bulma-scroll-area-thumb-color`) | — (`--bulma-scroll-area-scrollbar-width`: `thin`, `auto` or `none`) | the browser's own bars, so forced colors gives them the system's colors; retheme through `--bulma-scroll-area-*` |
80
83
  | `SegmentedControl` | `primary \| link \| info \| success \| warning \| danger` | `small \| medium \| large` | fills only the checked segment (default `link`); `size` is the row's `are-<size>`; segments take no `color` or `size` |
81
84
  | `Select` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white` | `small \| medium \| large` | also `isRounded` |
82
85
  | `Slider` | `primary \| link \| info \| success \| warning \| danger` | `small \| medium \| large` | also `isRounded`, `isCircle` |
86
+ | `Splitter` | — (no `color`: the line is `--bulma-splitter-line-color`) | — (no `size`) | the line and grip are borders, so forced colors keeps them; retheme through `--bulma-splitter-*` |
83
87
  | `Steps` | `primary \| link \| info \| success \| warning \| danger` | `small \| medium \| large` | the 6 only |
84
88
  | `Switch` | `primary \| link \| info \| success \| warning \| danger` | `small \| normal \| medium \| large` | also `isRounded`, `isThin`, `isOutlined` |
85
89
  | `Tabs` | `primary \| link \| info \| success \| warning \| danger \| black \| dark \| light \| white` | `small \| medium \| large` | **entire `color` prop deprecated** (no CSS ships; dev-warn; removal next major) |
@@ -14,14 +14,14 @@ pnpm run dev
14
14
  - `pnpm run dev` - Start development server
15
15
  - `pnpm run build` - Build for production
16
16
  - `pnpm run preview` - Preview production build
17
- - `pnpm run lint` - Run ESLint
17
+ - `pnpm run lint` - Run Oxlint
18
18
 
19
19
  ## Features
20
20
 
21
21
  - ⚡️ Vite for lightning-fast HMR
22
22
  - 🎨 Bulma CSS framework
23
23
  - 📦 bestax-bulma component library
24
- - 🔧 ESLint pre-configured
24
+ - 🔧 Oxlint pre-configured
25
25
 
26
26
  ## Learn More
27
27
 
@@ -0,0 +1,8 @@
1
+ {
2
+ "$schema": "./node_modules/oxlint/configuration_schema.json",
3
+ "plugins": ["react", "oxc"],
4
+ "rules": {
5
+ "react/rules-of-hooks": "error",
6
+ "react/only-export-components": ["warn", { "allowConstantExport": true }]
7
+ }
8
+ }
@@ -6,24 +6,20 @@
6
6
  "scripts": {
7
7
  "dev": "vite",
8
8
  "build": "vite build",
9
- "lint": "eslint .",
9
+ "lint": "oxlint",
10
10
  "preview": "vite preview"
11
11
  },
12
12
  "dependencies": {
13
- "@allxsmith/bestax-bulma": "^5.0.0",
14
- "react": "^19.2.3",
15
- "react-dom": "^19.2.3"
13
+ "@allxsmith/bestax-bulma": "workspace:^",
14
+ "react": "^19.3.1",
15
+ "react-dom": "^19.3.1"
16
16
  },
17
17
  "devDependencies": {
18
- "@eslint/js": "^10.0.1",
19
- "@types/react": "^19.2.17",
20
- "@types/react-dom": "^19.2.3",
21
- "@vitejs/plugin-react": "^6.0.3",
22
- "eslint": "^10.5.0",
23
- "eslint-plugin-react-hooks": "^7.1.1",
24
- "eslint-plugin-react-refresh": "^0.5.3",
25
- "globals": "^17.7.0",
26
- "vite": "^8.1.0"
18
+ "@types/react": "^19.3.0",
19
+ "@types/react-dom": "^19.3.0",
20
+ "@vitejs/plugin-react": "^6.1.2",
21
+ "oxlint": "^1.89.0",
22
+ "vite": "^8.3.5"
27
23
  },
28
24
  "engines": {
29
25
  "node": "^20.19.0 || >=22.12.0"
@@ -2,7 +2,7 @@ import { StrictMode } from 'react';
2
2
  import { createRoot } from 'react-dom/client';
3
3
 
4
4
  // Bestax's stylesheet loads before the app's own CSS, so a named class in
5
- // src/App.css wins over a Bulma rule of the same weight.
5
+ // src/index.css wins over a Bulma rule of the same weight.
6
6
  import '@allxsmith/bestax-bulma/bestax.css';
7
7
  import './index.css';
8
8
  import App from './App.jsx';
@@ -1,7 +1,7 @@
1
1
  import { defineConfig } from 'vite';
2
2
  import react from '@vitejs/plugin-react';
3
3
 
4
- // https://vitejs.dev/config/
4
+ // https://vite.dev/config/
5
5
  export default defineConfig({
6
6
  plugins: [react()],
7
7
  });
@@ -14,7 +14,7 @@ pnpm run dev
14
14
  - `pnpm run dev` - Start development server
15
15
  - `pnpm run build` - Build for production
16
16
  - `pnpm run preview` - Preview production build
17
- - `pnpm run lint` - Run ESLint
17
+ - `pnpm run lint` - Run Oxlint
18
18
 
19
19
  ## Features
20
20
 
@@ -22,7 +22,7 @@ pnpm run dev
22
22
  - 🎨 Bulma CSS framework
23
23
  - 📦 bestax-bulma component library
24
24
  - 📘 TypeScript for type safety
25
- - 🔧 ESLint pre-configured
25
+ - 🔧 Oxlint pre-configured
26
26
 
27
27
  ## Learn More
28
28
 
@@ -0,0 +1,8 @@
1
+ {
2
+ "$schema": "./node_modules/oxlint/configuration_schema.json",
3
+ "plugins": ["react", "typescript", "oxc"],
4
+ "rules": {
5
+ "react/rules-of-hooks": "error",
6
+ "react/only-export-components": ["warn", { "allowConstantExport": true }]
7
+ }
8
+ }
@@ -6,27 +6,22 @@
6
6
  "scripts": {
7
7
  "dev": "vite",
8
8
  "build": "tsc -b && vite build",
9
- "lint": "eslint .",
9
+ "lint": "oxlint",
10
10
  "preview": "vite preview"
11
11
  },
12
12
  "dependencies": {
13
- "@allxsmith/bestax-bulma": "^5.0.0",
14
- "react": "^19.2.3",
15
- "react-dom": "^19.2.3"
13
+ "@allxsmith/bestax-bulma": "workspace:^",
14
+ "react": "^19.3.1",
15
+ "react-dom": "^19.3.1"
16
16
  },
17
17
  "devDependencies": {
18
- "@eslint/js": "^10.0.1",
19
- "@types/node": "^24.13.3",
20
- "@types/react": "^19.2.17",
21
- "@types/react-dom": "^19.2.3",
22
- "@vitejs/plugin-react": "^6.0.3",
23
- "eslint": "^10.5.0",
24
- "eslint-plugin-react-hooks": "^7.1.1",
25
- "eslint-plugin-react-refresh": "^0.5.3",
26
- "globals": "^17.7.0",
27
- "typescript": "^6.0.3",
28
- "typescript-eslint": "^8.62.0",
29
- "vite": "^8.1.0"
18
+ "@types/node": "^24.19.2",
19
+ "@types/react": "^19.3.0",
20
+ "@types/react-dom": "^19.3.0",
21
+ "@vitejs/plugin-react": "^6.1.2",
22
+ "oxlint": "^1.89.0",
23
+ "typescript": "~7.0.2",
24
+ "vite": "^8.3.5"
30
25
  },
31
26
  "engines": {
32
27
  "node": "^20.19.0 || >=22.12.0"
@@ -2,7 +2,7 @@ import { StrictMode } from 'react';
2
2
  import { createRoot } from 'react-dom/client';
3
3
 
4
4
  // Bestax's stylesheet loads before the app's own CSS, so a named class in
5
- // src/App.css wins over a Bulma rule of the same weight.
5
+ // src/index.css wins over a Bulma rule of the same weight.
6
6
  import '@allxsmith/bestax-bulma/bestax.css';
7
7
  import './index.css';
8
8
  import App from './App.tsx';
@@ -1,29 +0,0 @@
1
- import js from '@eslint/js';
2
- import globals from 'globals';
3
- import reactHooks from 'eslint-plugin-react-hooks';
4
- import reactRefresh from 'eslint-plugin-react-refresh';
5
-
6
- export default [
7
- { ignores: ['dist'] },
8
- js.configs.recommended,
9
- {
10
- files: ['**/*.{js,jsx}'],
11
- plugins: {
12
- 'react-hooks': reactHooks,
13
- 'react-refresh': reactRefresh,
14
- },
15
- languageOptions: {
16
- ecmaVersion: 2020,
17
- globals: globals.browser,
18
- parserOptions: {
19
- ecmaVersion: 'latest',
20
- ecmaFeatures: { jsx: true },
21
- sourceType: 'module',
22
- },
23
- },
24
- rules: {
25
- ...reactHooks.configs['recommended-latest'].rules,
26
- ...reactRefresh.configs.vite.rules,
27
- },
28
- },
29
- ];