create-bestax 4.2.13 → 4.2.15

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 (42) hide show
  1. package/README.md +11 -7
  2. package/dist/cli.d.ts +11 -1
  3. package/dist/cli.d.ts.map +1 -1
  4. package/dist/cli.js +17 -2
  5. package/dist/constants.d.ts +9 -0
  6. package/dist/constants.d.ts.map +1 -1
  7. package/dist/constants.js +102 -31
  8. package/dist/index.js +2 -2
  9. package/dist/project-creator.d.ts +19 -0
  10. package/dist/project-creator.d.ts.map +1 -1
  11. package/dist/project-creator.js +91 -38
  12. package/package.json +3 -3
  13. package/templates/skills/bestax-custom-component/examples/stat-card.tsx +2 -2
  14. package/templates/skills/bestax-form/SKILL.md +17 -7
  15. package/templates/skills/bestax-form/references/api.md +10 -10
  16. package/templates/skills/bestax-form/references/patterns.md +9 -1
  17. package/templates/skills/bestax-icons/SKILL.md +8 -6
  18. package/templates/skills/bestax-icons/examples/icon-usage.tsx +3 -3
  19. package/templates/skills/bestax-icons/references/icon-libraries.md +12 -7
  20. package/templates/skills/bestax-layout-scaffold/examples/app-shell.tsx +1 -1
  21. package/templates/skills/bestax-layout-scaffold/examples/card-grid.tsx +0 -1
  22. package/templates/skills/bestax-layout-scaffold/examples/centered.tsx +0 -1
  23. package/templates/skills/bestax-layout-scaffold/examples/content-page.tsx +0 -1
  24. package/templates/skills/bestax-layout-scaffold/examples/landing.tsx +1 -1
  25. package/templates/skills/bestax-migrate/references/bulma-classes/component-map.md +13 -4
  26. package/templates/skills/bestax-migrate/references/bulma-classes/unmappables.md +10 -1
  27. package/templates/skills/bestax-optimize/SKILL.md +10 -6
  28. package/templates/skills/bestax-optimize/references/modular-build.md +13 -8
  29. package/templates/skills/bestax-theming/examples/dark-mode.tsx +1 -1
  30. package/templates/skills/bestax-theming/examples/theme-config.tsx +2 -2
  31. package/templates/skills/bestax-theming/references/css-variables.md +3 -1
  32. package/templates/vite/README.md +5 -6
  33. package/templates/vite/src/App.css +14 -1
  34. package/templates/vite/src/App.jsx +128 -100
  35. package/templates/vite/src/main.jsx +3 -2
  36. package/templates/vite-ts/README.md +5 -6
  37. package/templates/vite-ts/src/App.css +14 -1
  38. package/templates/vite-ts/src/App.tsx +128 -100
  39. package/templates/vite-ts/src/main.tsx +3 -2
  40. package/templates/vite-ts/tsconfig.app.json +25 -0
  41. package/templates/vite-ts/tsconfig.json +6 -25
  42. package/templates/vite-ts/tsconfig.node.json +2 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-bestax",
3
- "version": "4.2.13",
3
+ "version": "4.2.15",
4
4
  "description": "Create a new bestax-bulma project",
5
5
  "type": "module",
6
6
  "bin": {
@@ -41,7 +41,7 @@
41
41
  "prompts": "^2.4.2",
42
42
  "react": "^18.0.0 || ^19.0.0",
43
43
  "react-dom": "^18.0.0 || ^19.0.0",
44
- "@allxsmith/bestax-bulma": "^5.27.0"
44
+ "@allxsmith/bestax-bulma": "^5.27.4"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@jest/globals": "^30.0.0",
@@ -78,5 +78,5 @@
78
78
  "clean": "rimraf dist",
79
79
  "release": "npx semantic-release"
80
80
  },
81
- "readme": "# create-bestax\n\n[![npm version](https://img.shields.io/npm/v/create-bestax.svg)](https://www.npmjs.com/package/create-bestax)\n[![npm downloads](https://img.shields.io/npm/dm/create-bestax.svg)](https://www.npmjs.com/package/create-bestax)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Socket Badge](https://badge.socket.dev/npm/package/create-bestax/latest)](https://socket.dev/npm/package/create-bestax/overview)\n[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/allxsmith/bestax/badge)](https://scorecard.dev/viewer/?uri=github.com/allxsmith/bestax)\n[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/14361/badge)](https://www.bestpractices.dev/projects/14361)\n[![npm provenance](https://img.shields.io/badge/npm-provenance-3fb950.svg)](https://www.npmjs.com/package/create-bestax#provenance)\n[![Security policy](https://img.shields.io/badge/security-policy-blue.svg)](https://github.com/allxsmith/bestax/blob/main/SECURITY.md)\n\nThe scaffolder for [`@allxsmith/bestax-bulma`](https://www.npmjs.com/package/@allxsmith/bestax-bulma) — spin up a Vite app pre-wired for the **Bulma v1** React component library in one command. Picks your framework (JS or TypeScript), CSS flavor, and icon library, and can drop in the bestax **AI skills** so an agent like Claude Code knows the library from the first prompt.\n\nPart of the [bestax monorepo](https://github.com/allxsmith/bestax) — see also [`@allxsmith/bestax-bulma`](https://www.npmjs.com/package/@allxsmith/bestax-bulma) for the components themselves.\n\n## Requirements\n\n- **Node.js 22 or newer.** Node 18 and 20 are both past end-of-life. On an older runtime the\n CLI exits immediately with an explicit upgrade message.\n- npm 10 or newer (ships with Node 22), or yarn/pnpm.\n\n## Usage\n\n### Quick Start\n\n```bash\n# Using npm\nnpm create bestax@latest my-app\n\n# Using npx\nnpx create-bestax@latest my-app\n\n# Alternative naming\nnpm create bestax-bulma@latest my-app\n```\n\n### Interactive Mode\n\nRunning without arguments will prompt you for all options:\n\n```bash\nnpm create bestax@latest\n```\n\nYou'll be asked to:\n\n1. Enter a project name (and, if that directory already holds files, confirm removing them;\n nothing is removed until you have answered the last question)\n2. Select a framework (Vite or Vite + TypeScript)\n3. Choose a Bulma CSS flavor (Complete or Minimal)\n4. Select an icon library (Font Awesome, Material Icons, etc.)\n5. Choose whether to install the bestax AI skills into `.claude/skills/`\n\nEvery prompt has a flag equivalent, so the whole flow is scriptable and CI-friendly — see the options below.\n\n### Command Line Options\n\n```bash\nnpm create bestax@latest [project-directory] [options]\n```\n\n**Arguments:**\n\n- `[project-directory]` - Optional project directory name. It also becomes the `package.json`\n name, lower-cased the way `npm init` does and without a leading `_`, since npm rejects both.\n\n**Options:**\n\n- `-t, --template <template>` - Template to use: `vite` or `vite-ts` \n **Default:** `vite`\n- `-b, --bulma <flavor>` - Bulma CSS flavor:\n - `complete` - Full Bulma CSS with all components and helpers\n - `prefixed` - Prefixed version for compatibility\n - `no-helpers` - Without helper classes\n - `no-helpers-prefixed` - Prefixed without helpers\n - `no-dark-mode` - Without dark mode support \n **Default:** `complete`\n- `-i, --icon <library>` - Icon library:\n - `none` - No icon library\n - `fontawesome` - Font Awesome\n - `mdi` - Material Design Icons\n - `ionicons` - Ionicons\n - `material-icons` - Material Icons\n - `material-symbols` - Material Symbols \n **Default:** `none`\n- `--skills` / `--no-skills` - Install (or skip) the bestax AI skills into\n `.claude/skills/` (with a `CLAUDE.md`) so a Claude Code session picks them up\n automatically. When omitted you're prompted; with `-y` the default is to install.\n- `-y, --yes` - Skip prompts and use defaults or provided options. \n When used, the following defaults are selected unless overridden by flags:\n - Template: `vite`\n - Bulma flavor: `complete`\n - Icon library: `none`\n - AI skills: installed (pass `--no-skills` to opt out)\n\n `-y` never deletes files. If the target directory is not empty, the run stops, lists what is\n there, and changes nothing; add `--overwrite` to empty it first. Earlier versions emptied the\n directory under `-y` alone, so a script that relied on that now needs `--overwrite`.\n\n- `--overwrite` - Remove existing files if the target directory is not empty, without asking.\n Every other flag is checked first, so a typo stops the run before anything is deleted.\n\n**Example:**\n\n```bash\n# Create a TypeScript project with Font Awesome icons\nnpm create bestax@latest my-app -t vite-ts -i fontawesome -b complete\n\n# Use all defaults (skip prompts)\nnpm create bestax@latest my-app -y\n```\n\n## Templates\n\nAvailable templates:\n\n- `vite` - Vite + JavaScript\n- `vite-ts` - Vite + TypeScript\n\nEach template includes:\n\n- Pre-configured bestax-bulma integration (React 19)\n- The latest `@allxsmith/bestax-bulma`, which ships Bulma v1 automatically\n- Icon library support (Font Awesome, Material Design, etc.)\n- Sample components demonstrating library usage\n- Development and build scripts\n\n## For AI Tools\n\nScaffolding for an AI agent? Pass `--skills` (or accept the prompt) to drop the bestax\nAgent Skills and a `CLAUDE.md` into the new project so Claude Code, Cursor, or Copilot\nbuild the bestax way from the start. The library also ships LLM-optimized docs:\n\n- [LLMs guide](https://bestax.io/docs/guides/llms) — using bestax with Claude Code, Cursor, Copilot\n- [Agent Skills](https://bestax.io/docs/skills/intro) — teach your agent the bestax conventions\n- [llms.txt](https://bestax.io/llms.txt) (curated index) · [llms-full.txt](https://bestax.io/llms-full.txt) (full docs)\n\n## Development\n\n```bash\nnpm run build # Build the CLI\nnpm run dev # Watch mode\nnpm test # Run tests\nnpm run lint # Lint CLI source code\nnpm run typecheck # Type check CLI source code\n```\n\n**Note on Templates:** Template files in `templates/` are excluded from linting. They should be manually validated by scaffolding a test project and running lint/build there before releasing.\n\n## Hardened by default\n\nA scaffolder runs with write access to your filesystem and picks your starting dependencies, so how it is built and published matters:\n\n- **Signed provenance** — every release carries a sigstore attestation linking the tarball to the exact commit and CI run that built it. Check the **Provenance** section on the [npm page](https://www.npmjs.com/package/create-bestax#provenance), or run `npm audit signatures`.\n- **npm OIDC trusted publishing** — short-lived, per-run credentials; no long-lived `NPM_TOKEN` exists to be stolen. Release commits and tags are GPG-signed.\n- **Socket.dev scans every PR** for malware, install scripts, obfuscated code, and privilege escalation before it can reach `main`.\n- **Dependencies are a deliberate act** — install scripts are blocked unless individually allow-listed, freshly published versions are refused for 3 days, and CI installs only what the reviewed lockfile resolves.\n- **Every GitHub Action is pinned to a full commit SHA**, so a compromised action release can't roll silently into a build of this CLI.\n- **CodeQL, Dependency Review, and Dependabot** run continuously, alongside a high-severity `pnpm audit` gate.\n- **Layered AI review before merge** — [CodeRabbit](https://coderabbit.ai) plus an independent adversarial Claude review (a different model from the one writing AI-authored changes), on top of required green CI, an approving review, and a human merge.\n\nFull detail: [`SECURITY.md`](https://github.com/allxsmith/bestax/blob/main/SECURITY.md) · [Security guide](https://bestax.io/docs/guides/security)\n\n## Telemetry\n\n`create-bestax` can send one **anonymous** usage event after a successful\nscaffold — only if you opt in when asked (once, at the end of a scaffold). The\nevent is just the choices you made — template, Bulma flavor, icon library,\nskills, package manager — plus the CLI version, Node major version, and OS\nplatform; never names, IPs, machine IDs, paths, or file contents, and no\nidentifier exists that could link two events together. Opt out any time with\n`--no-telemetry`, `BESTAX_TELEMETRY=0`, or `DO_NOT_TRACK=1`.\n\nFull disclosure of every field and control: [Telemetry guide](https://bestax.io/docs/guides/telemetry)\n\n## Publishing\n\nThis package uses semantic-release with scope-based rules. Only commits with `feat(create-bestax)` or `fix(create-bestax)` will trigger releases.\n"
81
+ "readme": "# create-bestax\n\n[![npm version](https://img.shields.io/npm/v/create-bestax.svg)](https://www.npmjs.com/package/create-bestax)\n[![npm downloads](https://img.shields.io/npm/dm/create-bestax.svg)](https://www.npmjs.com/package/create-bestax)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Socket Badge](https://badge.socket.dev/npm/package/create-bestax/latest)](https://socket.dev/npm/package/create-bestax/overview)\n[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/allxsmith/bestax/badge)](https://scorecard.dev/viewer/?uri=github.com/allxsmith/bestax)\n[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/14361/badge)](https://www.bestpractices.dev/projects/14361)\n[![npm provenance](https://img.shields.io/badge/npm-provenance-3fb950.svg)](https://www.npmjs.com/package/create-bestax#provenance)\n[![Security policy](https://img.shields.io/badge/security-policy-blue.svg)](https://github.com/allxsmith/bestax/blob/main/SECURITY.md)\n\nThe scaffolder for [`@allxsmith/bestax-bulma`](https://www.npmjs.com/package/@allxsmith/bestax-bulma) — spin up a Vite app pre-wired for the **Bulma v1** React component library in one command. Picks your framework (JS or TypeScript), CSS flavor, and icon library, and can drop in the bestax **AI skills** so an agent like Claude Code knows the library from the first prompt.\n\nPart of the [bestax monorepo](https://github.com/allxsmith/bestax) — see also [`@allxsmith/bestax-bulma`](https://www.npmjs.com/package/@allxsmith/bestax-bulma) for the components themselves.\n\n## Requirements\n\n- **Node.js 22 or newer.** Node 18 and 20 are both past end-of-life. On an older runtime the\n CLI exits immediately with an explicit upgrade message.\n- npm 10 or newer (ships with Node 22), or yarn/pnpm.\n\n## Usage\n\n### Quick Start\n\n```bash\n# Using npm\nnpm create bestax@latest my-app\n\n# Using npx\nnpx create-bestax@latest my-app\n```\n\n### Interactive Mode\n\nRunning without arguments will prompt you for all options:\n\n```bash\nnpm create bestax@latest\n```\n\nYou'll be asked to:\n\n1. Enter a project name (and, if that directory already holds files, confirm removing them;\n nothing is removed until you have answered the last question)\n2. Select a framework (Vite or Vite + TypeScript)\n3. Choose a Bulma CSS flavor (the `--bulma` options below)\n4. Select an icon library (Font Awesome, Material Icons, etc.)\n5. Choose whether to install the bestax AI skills into `.claude/skills/`\n\nEvery prompt has a flag equivalent, so the whole flow is scriptable and CI-friendly — see the options below.\n\n### Command Line Options\n\n```bash\nnpm create bestax@latest [project-directory] -- [options]\n```\n\nPut the options after `--`. npm needs it to pass them on at all, and so does bun, whose\n`bun create` rejects short flags such as `-t` and `-y` itself. pnpm and Yarn 1 accept the options\nwith or without it.\n\n**Arguments:**\n\n- `[project-directory]` - Optional project directory name. It also becomes the `package.json`\n name, lower-cased the way `npm init` does and without a leading `_`, since npm rejects both.\n\n**Options:**\n\n- `-t, --template <template>` - Template to use: `vite` or `vite-ts` \n **Default:** `vite`\n- `-b, --bulma <flavor>` - Bulma CSS flavor:\n - `complete` - Full Bulma CSS with all components and helpers\n - `prefixed` - Prefixed version for compatibility\n - `no-helpers` - Without helper classes\n - `no-helpers-prefixed` - Prefixed without helpers\n - `no-dark-mode` - Without dark mode support \n **Default:** `complete`\n- `-i, --icon <library>` - Icon library:\n - `none` - No icon library\n - `fontawesome` - Font Awesome\n - `mdi` - Material Design Icons\n - `ionicons` - Ionicons\n - `material-icons` - Material Icons\n - `material-symbols` - Material Symbols \n **Default:** `none`\n- `--skills` / `--no-skills` - Install (or skip) the bestax AI skills into\n `.claude/skills/` (with a `CLAUDE.md`) so a Claude Code session picks them up\n automatically. When omitted you're prompted; with `-y` the default is to install.\n- `-y, --yes` - Skip prompts and use defaults or provided options. \n When used, the following defaults are selected unless overridden by flags:\n - Template: `vite`\n - Bulma flavor: `complete`\n - Icon library: `none`\n - AI skills: installed (pass `--no-skills` to opt out)\n\n `-y` never deletes files. If the target directory is not empty, the run stops, lists what is\n there, and changes nothing; add `--overwrite` to empty it first. Earlier versions emptied the\n directory under `-y` alone, so a script that relied on that now needs `--overwrite`.\n\n- `--overwrite` - Remove existing files if the target directory is not empty, without asking.\n Every other flag is checked first, so a typo stops the run before anything is deleted.\n\n**Example:**\n\n```bash\n# Create a TypeScript project with Font Awesome icons\nnpm create bestax@latest my-app -- -t vite-ts -i fontawesome -b complete\n\n# Use all defaults (skip prompts)\nnpm create bestax@latest my-app -- -y\n\n# The same with bun\nbun create bestax@latest my-app -- -y\n```\n\n## Templates\n\nAvailable templates:\n\n- `vite` - Vite + JavaScript\n- `vite-ts` - Vite + TypeScript\n\nEach template includes:\n\n- Pre-configured bestax-bulma integration (React 19)\n- The latest `@allxsmith/bestax-bulma`, which ships Bulma v1 automatically\n- Icon library support (Font Awesome, Material Design, etc.)\n- Sample components demonstrating library usage\n- Development and build scripts\n\n## For AI Tools\n\nScaffolding for an AI agent? Pass `--skills` (or accept the prompt) to drop the bestax\nAgent Skills and a `CLAUDE.md` into the new project so Claude Code, Cursor, or Copilot\nbuild the bestax way from the start. The library also ships LLM-optimized docs:\n\n- [LLMs guide](https://bestax.io/docs/guides/llms) — using bestax with Claude Code, Cursor, Copilot\n- [Agent Skills](https://bestax.io/docs/skills/intro) — teach your agent the bestax conventions\n- [llms.txt](https://bestax.io/llms.txt) (curated index) · [llms-full.txt](https://bestax.io/llms-full.txt) (full docs)\n\n## Development\n\n```bash\nnpm run build # Build the CLI\nnpm run dev # Watch mode\nnpm test # Run tests\nnpm run lint # Lint CLI source code\nnpm run typecheck # Type check CLI source code\n```\n\n**Note on Templates:** Template files in `templates/` are excluded from linting. They should be manually validated by scaffolding a test project and running lint/build there before releasing.\n\n## Hardened by default\n\nA scaffolder runs with write access to your filesystem and picks your starting dependencies, so how it is built and published matters:\n\n- **Signed provenance** — every release carries a sigstore attestation linking the tarball to the exact commit and CI run that built it. Check the **Provenance** section on the [npm page](https://www.npmjs.com/package/create-bestax#provenance), or run `npm audit signatures`.\n- **npm OIDC trusted publishing** — short-lived, per-run credentials; no long-lived `NPM_TOKEN` exists to be stolen. Release commits and tags are GPG-signed.\n- **Socket.dev scans every PR** for malware, install scripts, obfuscated code, and privilege escalation before it can reach `main`.\n- **Dependencies are a deliberate act** — install scripts are blocked unless individually allow-listed, freshly published versions are refused for 3 days, and CI installs only what the reviewed lockfile resolves.\n- **Every GitHub Action is pinned to a full commit SHA**, so a compromised action release can't roll silently into a build of this CLI.\n- **CodeQL, Dependency Review, and Dependabot** run continuously, alongside a high-severity `pnpm audit` gate.\n- **Layered AI review before merge** — [CodeRabbit](https://coderabbit.ai) plus an independent adversarial Claude review (a different model from the one writing AI-authored changes), on top of required green CI, an approving review, and a human merge.\n\nFull detail: [`SECURITY.md`](https://github.com/allxsmith/bestax/blob/main/SECURITY.md) · [Security guide](https://bestax.io/docs/guides/security)\n\n## Telemetry\n\n`create-bestax` can send one **anonymous** usage event after a successful\nscaffold — only if you opt in when asked (once, at the end of a scaffold). The\nevent is just the choices you made — template, Bulma flavor, icon library,\nskills, package manager — plus the CLI version, Node major version, and OS\nplatform; never names, IPs, machine IDs, paths, or file contents, and no\nidentifier exists that could link two events together. Opt out any time with\n`--no-telemetry`, `BESTAX_TELEMETRY=0`, or `DO_NOT_TRACK=1`.\n\nFull disclosure of every field and control: [Telemetry guide](https://bestax.io/docs/guides/telemetry)\n\n## Publishing\n\nThis package uses semantic-release with scope-based rules. Only commits with `feat(create-bestax)` or `fix(create-bestax)` will trigger releases.\n"
82
82
  }
@@ -64,8 +64,8 @@ export function StatCard({
64
64
  name={icon}
65
65
  size="large"
66
66
  textColor={color}
67
- // Decorative: the label below already says it, so hide it from AT —
68
- // Icon otherwise emits its default aria-label="icon". (To *label* an
67
+ // Decorative: the label below already says it, so it stays hidden
68
+ // from AT, as an Icon with no `ariaLabel` is anyway. (To *label* an
69
69
  // icon, use Icon's own camelCase `ariaLabel`; most components take
70
70
  // the plain aria-label attribute.)
71
71
  aria-hidden="true"
@@ -131,13 +131,23 @@ The `label` prop on the single-control convenience inputs (`Input`, `Select`, `T
131
131
  generated one otherwise, and an explicit `labelProps={{ htmlFor }}` wins. The wiring only
132
132
  happens when the component renders its own `Field` (nested inside one, the `label` prop is
133
133
  dropped); the date/time pickers skip it in `inline` mode and `Taginput` skips it at
134
- `maxTags` (no visible input to label). The group inputs (`Checkboxes`, `Radios`, `Rate`,
135
- `DateRangeInput`) associate their `label` too, but group-style: the wrapper gets `role="group"`/`"radiogroup"`
136
- and `aria-labelledby` pointing at the label. Composing `Field` + bases yourself also
137
- associates: `Field`'s own `label` wires to a single composed `InputBase`/`SelectBase`/
138
- `TextAreaBase` (skipped for `grouped`/`hasAddons`). Pass `labelProps={{ htmlFor }}` plus a
139
- matching `id` only when you want a stable id, or `labelProps={{ htmlFor: undefined }}` to
140
- opt out — e.g. when the labeled `Field` wraps something that is not one of those bases.
134
+ `maxTags` (no visible input to label). A `range` `Slider` points the `for` at its low thumb
135
+ and also puts the label at the start of both thumbs' names through `aria-labelledby`
136
+ ("Price range Minimum value"). Its `ariaLabel={[low, high]}` replaces those names outright, so
137
+ leave it off when a label already names the Slider. The group inputs (`Checkboxes`, `Radios`, `Rate`,
138
+ `DateRangeInput`) associate their `label` too, but group-style: the wrapper gets
139
+ `role="group"`/`"radiogroup"` and `aria-labelledby` pointing at the label. Composing yourself
140
+ also associates: a labeled `Field` names the one control it holds, whether a composed
141
+ `InputBase`/`SelectBase`/`TextAreaBase` or any input above (through the id), or a group
142
+ (through `aria-labelledby`). Either way, an `aria-label` or `aria-labelledby` you give a
143
+ group wins over the label. A `Checkbox`, `Radio` or `Switch` takes nothing from a `Field`:
144
+ each is named by its own children, so put the text there. The association is skipped for
145
+ `grouped`/`hasAddons`, and a nested `Field` starts its own scope, so a
146
+ horizontal `Field` whose body holds an inner `Field` needs `labelProps={{ htmlFor }}` plus the
147
+ control's `id` (for a group, `labelProps={{ id, htmlFor: undefined }}` plus its
148
+ `aria-labelledby`, since nothing takes the label's `for` there). Pass
149
+ `labelProps={{ htmlFor }}` plus a matching `id` only when you want a stable id, or
150
+ `labelProps={{ htmlFor: undefined }}` to opt out.
141
151
 
142
152
  ## Convenience vs composed
143
153
 
@@ -8,16 +8,16 @@ via `useBulmaClasses`.
8
8
 
9
9
  Container and layout. Compound parts: `Field.Label`, `Field.Body`.
10
10
 
11
- | Prop | Type | Notes |
12
- | ----------------------- | ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
13
- | `horizontal` | `boolean` | Label + control side by side. Auto-wraps children in `Field.Body`. |
14
- | `grouped` | `boolean \| 'centered' \| 'right' \| 'multiline'` | Controls in a row. |
15
- | `hasAddons` | `boolean \| 'centered' \| 'right'` | Attached controls. |
16
- | `narrow` | `boolean` | Constrain to content width (inside horizontal bodies). |
17
- | `label` | `ReactNode` | Convenience label; auto-associates with a single composed `InputBase`/`SelectBase`/`TextAreaBase` (skipped for `grouped`/`hasAddons`). |
18
- | `labelSize` | `'small' \| 'normal' \| 'medium' \| 'large'` | Label size. |
19
- | `labelProps` | label attributes | Props for the `<label>`. An explicit `htmlFor` (even `undefined`) takes over the association; otherwise it is set automatically. |
20
- | `textColor` / `bgColor` | Bulma color | Helper colors for the field. |
11
+ | Prop | Type | Notes |
12
+ | ----------------------- | ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
13
+ | `horizontal` | `boolean` | Label + control side by side. Auto-wraps children in `Field.Body`. |
14
+ | `grouped` | `boolean \| 'centered' \| 'right' \| 'multiline'` | Controls in a row. |
15
+ | `hasAddons` | `boolean \| 'centered' \| 'right'` | Attached controls. |
16
+ | `narrow` | `boolean` | Constrain to content width (inside horizontal bodies). |
17
+ | `label` | `ReactNode` | Names the one control it holds: a composed base or convenience input through its id, a group through `aria-labelledby` (skipped for `grouped`/`hasAddons`; a nested `Field` starts its own scope). |
18
+ | `labelSize` | `'small' \| 'normal' \| 'medium' \| 'large'` | Label size. |
19
+ | `labelProps` | label attributes | Props for the `<label>`. An explicit `htmlFor` (even `undefined`) takes over the association; otherwise it is set automatically. An `id` here is what a group's `aria-labelledby` points at. |
20
+ | `textColor` / `bgColor` | Bulma color | Helper colors for the field. |
21
21
 
22
22
  ## Control — `form/Control.tsx`
23
23
 
@@ -203,7 +203,15 @@ const [volume, setVolume] = useState(50);
203
203
  <Slider value={volume} onChange={setVolume} min={0} max={100} tooltip="auto" />;
204
204
 
205
205
  const [range, setRange] = useState<[number, number]>([20, 80]);
206
- <Slider range value={range} onChange={setRange} min={0} max={100} />;
206
+ // The label names both thumbs: "Price range Minimum value" / "... Maximum value".
207
+ <Slider
208
+ range
209
+ label="Price range"
210
+ value={range}
211
+ onChange={setRange}
212
+ min={0}
213
+ max={100}
214
+ />;
207
215
 
208
216
  // Numberinput
209
217
  const [qty, setQty] = useState(1);
@@ -89,16 +89,18 @@ to `iconLeftName`/`iconRightName` if one is given, otherwise leaving the icon co
89
89
 
90
90
  ## Accessibility
91
91
 
92
- Every `Icon` renders `aria-label` (default `"icon"`), set via its camelCase `ariaLabel` prop.
93
- Only a few components declare that prop (`Icon`, `Delete`, `Slider`, `Carousel`) — everything
94
- else takes the standard `aria-label` attribute, e.g. `<Navbar.Burger aria-label="menu" />`.
92
+ An `Icon` is decorative unless it is named: with no `ariaLabel` it renders `aria-hidden="true"`
93
+ and no name. Name it with its camelCase `ariaLabel` prop, and it renders `role="img"` with that
94
+ `aria-label`. Only a few components declare that prop (`Icon`, `Delete`, `Slider`, `Carousel`):
95
+ everything else takes the standard `aria-label` attribute, e.g.
96
+ `<Navbar.Burger aria-label="menu" />`.
95
97
 
96
98
  - **Meaningful icon** (stands alone, conveys information): pass a descriptive
97
99
  `ariaLabel="Delete item"`.
98
100
  - **Decorative icon** (next to visible text that says the same thing, e.g. inside `IconText`
99
- or a labeled `Button`): hide it from screen readers with `aria-hidden`:
100
- `<Icon name="check" aria-hidden="true" />` — otherwise "icon" (or a duplicate label) is
101
- announced alongside the text.
101
+ or a labeled `Button`): leave `ariaLabel` off, and the icon stays out of the accessible
102
+ name. An explicit `aria-hidden="true"`, as in the examples here, says the same thing.
103
+ - **Icon-only control:** name the control (`<Button aria-label="Delete item">`), not the icon.
102
104
 
103
105
  ## References
104
106
 
@@ -6,7 +6,6 @@
6
6
  // Set the library ONCE on ConfigProvider ('fa' | 'mdi' | 'ion' |
7
7
  // 'material-icons' | 'material-symbols' — Ionicons is 'ion', NOT 'ionicons');
8
8
  // every <Icon> below then omits `library`.
9
- import React from 'react';
10
9
  import {
11
10
  ConfigProvider,
12
11
  Icon,
@@ -22,7 +21,7 @@ export function IconShowcase() {
22
21
  <Box>
23
22
  <Title size="5">Meaningful icons carry their own label</Title>
24
23
  {/* Standalone icons convey information — give them a descriptive
25
- ariaLabel (the default is just "icon"). */}
24
+ ariaLabel, which also makes the icon an image. */}
26
25
  <Icon
27
26
  name="triangle-exclamation"
28
27
  textColor="warning"
@@ -34,7 +33,8 @@ export function IconShowcase() {
34
33
  Decorative icons hide from screen readers
35
34
  </Title>
36
35
  {/* Next to visible text the icon repeats the message — aria-hidden
37
- stops "icon" (or a duplicate) being announced. */}
36
+ keeps a duplicate from being announced. An Icon with no ariaLabel
37
+ renders it anyway; writing it out says so. */}
38
38
  <IconText iconProps={{ name: 'star', 'aria-hidden': 'true' }}>
39
39
  Starred
40
40
  </IconText>
@@ -2,7 +2,7 @@
2
2
 
3
3
  Facts an agent can act on for each of the five libraries `Icon` supports. The library ships no
4
4
  icon fonts: the app must install the chosen library (the `npm create bestax` scaffold's
5
- `--icon` flag does this; in an existing app, follow Setup below).
5
+ `--icon` flag wires it in; in an existing app, follow Setup below).
6
6
 
7
7
  ## How `Icon` renders
8
8
 
@@ -67,8 +67,11 @@ Set it once on `ConfigProvider` and omit `library` everywhere else.
67
67
 
68
68
  ## Google Material Icons — `'material-icons'`
69
69
 
70
- - **Setup:** `npm install material-icons` and `import 'material-icons';`.
71
- - **Scaffold flag:** `--icon material-icons`.
70
+ - **Setup:** `npm install material-icons` and `import 'material-icons/iconfont/filled.css';`, the
71
+ style `Icon` renders by default. Add `outlined.css`, `round.css`, `sharp.css` or `two-tone.css`
72
+ from `material-icons/iconfont/` for those variants; the bare `import 'material-icons';` loads
73
+ all five fonts.
74
+ - **Scaffold flag:** `--icon material-icons` (imports `filled.css` only).
72
75
  - **Names:** snake_case ligature text: `home`, `rocket_launch`, `shopping_cart`. A kebab-case
73
76
  name will not match a ligature and renders as raw text.
74
77
  - **Variants:** `filled` (default) / `outlined` / `round` / `sharp` — note **`round`**, not
@@ -77,8 +80,10 @@ Set it once on `ConfigProvider` and omit `library` everywhere else.
77
80
 
78
81
  ## Material Symbols — `'material-symbols'`
79
82
 
80
- - **Setup:** `npm install material-symbols` and `import 'material-symbols';`.
81
- - **Scaffold flag:** `--icon material-symbols`.
83
+ - **Setup:** `npm install material-symbols` and `import 'material-symbols/outlined.css';`, the
84
+ style `Icon` renders by default. Add `rounded.css` or `sharp.css` for those variants; the bare
85
+ `import 'material-symbols';` loads all three fonts.
86
+ - **Scaffold flag:** `--icon material-symbols` (imports `outlined.css` only).
82
87
  - **Names:** snake_case ligature text, same as Material Icons: `rocket_launch`.
83
88
  - **Variants:** `outlined` (default) / `rounded` / `sharp` — note **`rounded`** here vs
84
89
  Material Icons' `round`.
@@ -126,5 +131,5 @@ Multiple segments via `items`:
126
131
  />
127
132
  ```
128
133
 
129
- Icons inside `IconText` sit next to their visible text — mark them decorative with
130
- `aria-hidden` (see SKILL.md's accessibility rules).
134
+ Icons inside `IconText` sit next to their visible text, so leave them decorative: no
135
+ `ariaLabel`, or an explicit `aria-hidden` (see SKILL.md's accessibility rules).
@@ -10,7 +10,7 @@
10
10
  //
11
11
  // `ConfigProvider` wraps the shell once at the root to set the app-wide icon
12
12
  // library (so <Icon> needs no `library` prop) and, optionally, a class prefix.
13
- import React, { useEffect, useState } from 'react';
13
+ import { useEffect, useState } from 'react';
14
14
  import {
15
15
  ConfigProvider,
16
16
  Navbar,
@@ -5,7 +5,6 @@
5
5
  // it (flexGrow="1"), so short blurbs don't leave ragged card bottoms.
6
6
  // (`height: 100%` on the card would NOT work — it resolves against auto
7
7
  // height. For uniform grids, Grid/Cell gives equal heights for free.)
8
- import React from 'react';
9
8
  import {
10
9
  Section,
11
10
  Container,
@@ -1,7 +1,6 @@
1
1
  // Centered single-column page — auth, settings, focused forms.
2
2
  // A narrow column is centered with `<Columns isCentered>`; on mobile the column
3
3
  // becomes full width automatically.
4
- import React from 'react';
5
4
  import {
6
5
  Section,
7
6
  Container,
@@ -7,7 +7,6 @@
7
7
  // e.g. mt="4" (1rem) instead of style={{ marginTop: '1rem' }},
8
8
  // textAlign="centered" instead of style={{ textAlign: 'center' }},
9
9
  // textColor="grey" instead of style={{ color: '#…' }}.
10
- import React from 'react';
11
10
  import {
12
11
  ConfigProvider,
13
12
  Hero,
@@ -10,7 +10,7 @@
10
10
  // also needs the `has-navbar-fixed-top` class on <html> so the page is padded
11
11
  // below it (never an inline padding offset) — Bulma requires this and the
12
12
  // library does NOT add it for you.
13
- import React, { useEffect, useState } from 'react';
13
+ import { useEffect, useState } from 'react';
14
14
  import {
15
15
  Navbar,
16
16
  Hero,
@@ -145,7 +145,8 @@ A `.tabs` converts around its `<ul>`, and the `<li>`s and `<a>`s inside stay as
145
145
  renders its own `<a>` with tab roles and puts its label in a `<span>`, so converting the tabs
146
146
  themselves is by hand (something that sat beside the text in the `<a>`, a `Tag` say, then wants a
147
147
  `Span display="flex" alignItems="center"` around it and the label). A `.icon` converts around the
148
- `<i>` inside it when it carries an `aria-label`, which `Icon` writes otherwise.
148
+ `<i>` inside it when it carries the attribute `Icon` writes otherwise: `aria-hidden` with no name,
149
+ no `role` and no `tabIndex`, and `role="img"` beside an `aria-label` or `aria-labelledby`.
149
150
 
150
151
  A `.menu` converts with its `.menu-label`s and `.menu-list`s, and so do the items in a list. An
151
152
  item has no class to go by, so the codemod finds it by where it sits: a `<li>` whose nearest
@@ -264,20 +265,20 @@ as `items`.
264
265
 
265
266
  ```jsx
266
267
  <span className="icon-text">
267
- <span className="icon" aria-label="Home">
268
+ <span className="icon" aria-hidden="true">
268
269
  <i className="fas fa-home"></i>
269
270
  </span>
270
271
  <span>Home</span>
271
272
  </span>
272
273
  // becomes
273
- <IconText iconProps={{ library: "fa", name: "home", ariaLabel: "Home" }}>Home</IconText>
274
+ <IconText iconProps={{ library: "fa", name: "home", "aria-hidden": "true" }}>Home</IconText>
274
275
  ```
275
276
 
276
277
  The glyph is read from the `<i>`: its Font Awesome style class (`fas`, `far`, `fa-solid`, ...) or
277
278
  `mdi`, the one class that names the glyph (`fa-home` as `name: "home"`), and the rest as
278
279
  `features`. `library` is always written, so a `ConfigProvider` with another `iconLibrary` doesn't
279
280
  change what renders. The `.icon`'s own classes and attributes join the glyph's props as they
280
- would on `Icon`, with `aria-label` as `ariaLabel`.
281
+ would on `Icon`, under their own names.
281
282
 
282
283
  It converts only when every `.icon` inside converts to `Icon` on its own and holds a bare, empty
283
284
  `<i>` naming a Font Awesome or Material Design Icons glyph, and the only other children are those
@@ -320,6 +321,14 @@ renders `has-text-<color>` too, and so does `is-centered`, which `isCentered` re
320
321
  beside `isRight`. Anything else keeps it as markup with a `children:File`, `context:File` or
321
322
  `attr` TODO.
322
323
 
324
+ A `has-name` `.file` with no `.file-name` converts only with Bulma's `is-empty` written on it as a
325
+ static class, since `File` renders `is-empty` there itself whatever a condition says, so a
326
+ condition on it can't stand in. The class then goes with the rest of the tree. The `File` gets
327
+ `fileName=""`, which pins its name empty the way a `.file-name`'s text pins it to that text. With
328
+ no `fileName`, `File` would show the name of the file a user picks and drop `is-empty`, which the
329
+ markup never does. Without a static `is-empty` the `.file` stays markup with a `defaults:File` TODO
330
+ that names the class to write.
331
+
323
332
  ## Families this source leaves as markup
324
333
 
325
334
  Their markup doesn't map element by element (the bestax component renders parts of its own, or
@@ -76,7 +76,11 @@ attributes you want (usually both, with a real label), then re-run. `Navbar` ren
76
76
  `role="navigation"` and `aria-label="main navigation"`, which Bulma's own navbar markup carries;
77
77
  give the `<nav>` both, with your own label if you like. `Breadcrumb` renders
78
78
  `aria-label="breadcrumbs"`, so give its `<nav>` an `aria-label`, whatever it says.
79
- `Icon` renders `aria-label="icon"`, so give a `.icon` an `aria-label` that says what the icon means.
79
+ `Icon` hides an icon with no name, no `role` and no `tabIndex`, with `aria-hidden="true"`, and
80
+ makes one named by `aria-label` or `aria-labelledby` an image, with `role="img"`. Give a decorative
81
+ `.icon` `aria-hidden="true"`, and a meaningful one an `aria-label` that says what it means and
82
+ `role="img"`. One whose name is an expression may render with no name, so it needs a `role` of its
83
+ own.
80
84
  `Pagination` renders Bulma's own `role="navigation"` and `aria-label="pagination"`, and
81
85
  `Pagination.Previous`, `Pagination.Next` and `Pagination.Link` render `tabIndex={0}`, so give each
82
86
  element the attribute it's missing.
@@ -84,6 +88,11 @@ element the attribute it's missing.
84
88
  sets none, and `Card.Header.Icon` renders `aria-label="more options"` too. One whose `type` isn't
85
89
  `button`, `submit` or `reset` gets an `attr:type` TODO instead, since bestax writes `button` in its
86
90
  place. Write the type you mean, then re-run.
91
+ `File` renders a class rather than an attribute: Bulma's `is-empty`, on a `has-name` `.file` with
92
+ no `.file-name`, whatever a condition says. Write `is-empty` on the `.file` as a static class, then
93
+ re-run: a condition on `is-empty` can't stand in, so one already there still gets this TODO. The
94
+ `File` it becomes gets `fileName=""`, so a file the user picks leaves it as the markup was: no name
95
+ area, and `is-empty` still on.
87
96
 
88
97
  ### `drops:<Target>`
89
98
 
@@ -6,7 +6,7 @@ license: MIT
6
6
 
7
7
  # Optimizing CSS size with @allxsmith/bestax-bulma
8
8
 
9
- The JS side is tree-shakable (the **entire** library is ~49 KB min+gzip). The stylesheet is
9
+ The JS side is tree-shakable (the **entire** library is ~65 KB min+gzip). The stylesheet is
10
10
  not: a prebuilt flavor ships all of Bulma + the bestax extras regardless of which components
11
11
  the app renders. Judge stylesheet weight by the **gzipped** transfer size — never the raw
12
12
  `dist/` number.
@@ -77,10 +77,14 @@ recommending it, grep the app's source for helper props on bestax components:
77
77
 
78
78
  ## Lever 2 — modular Sass build
79
79
 
80
- Compile only the Bulma modules + bestax extras partials the app actually uses. Needs the
81
- `sass` compiler as a dev dependency (Bulma's own build tool — Vite compiles `.scss` natively):
80
+ Compile only the Bulma modules + bestax extras partials the app actually uses. Needs `bulma`
81
+ as a dependency of the app itself (under pnpm, the app's Sass can only load what the app lists)
82
+ and the `sass` compiler as a dev dependency (Bulma's own build tool — Vite compiles `.scss`
83
+ natively):
82
84
 
83
85
  ```sh
86
+ # with the project's own package manager (pnpm add, yarn add) if it isn't npm
87
+ npm install bulma
84
88
  npm install -D sass
85
89
  ```
86
90
 
@@ -114,9 +118,9 @@ partial inventory, and a worked example are in `references/modular-build.md`.
114
118
 
115
119
  ## Lever 3 — import & icon-asset hygiene (minor)
116
120
 
117
- - **Named imports.** `import * as Bestax from '@allxsmith/bestax-bulma'` defeats tree
118
- shaking. Convert to named imports (`import { Button, Card } from …`) — a JS-side saving
119
- (whole library ≈ 49 KB min+gzip), so report it honestly as minor.
121
+ - **Named imports.** Convert `import * as Bestax from '@allxsmith/bestax-bulma'` to named
122
+ imports (`import { Button, Card } from …`). Any saving is on the JS side, so report it
123
+ honestly as minor.
120
124
  - **Unused icon libraries.** Scaffolded apps may carry an icon library the app never uses:
121
125
  icon-font packages in `package.json` (`@fortawesome/fontawesome-free`, `@mdi/font`,
122
126
  `material-icons`, `material-symbols`) with their CSS imports in `src/main.*`, or Ionicons
@@ -7,11 +7,14 @@ This is the "Option C" pattern from the
7
7
  ## Prerequisites
8
8
 
9
9
  ```sh
10
+ # with the project's own package manager (pnpm add, yarn add) if it isn't npm
11
+ npm install bulma
10
12
  npm install -D sass
11
13
  ```
12
14
 
13
15
  `sass` is Bulma's own compiler, dev-only. Vite compiles `.scss` out of the box — no plugin.
14
- `bulma` is already present as a dependency of `@allxsmith/bestax-bulma`, and the library
16
+ `bulma` has to be a dependency of the app itself: bestax-bulma depends on it, but under pnpm's
17
+ default layout the app's Sass can only load the packages the app lists. The library
15
18
  publishes its SCSS sources (`src/scss` ships in the npm package, exposed via the
16
19
  `@allxsmith/bestax-bulma/scss/*` export).
17
20
 
@@ -150,11 +153,13 @@ not `flexbox` — `flexbox` holds only the alignment props. Verified failure mod
150
153
  ## Worked example — the create-bestax starter app
151
154
 
152
155
  The `npm create bestax` starter renders `Container`, `Section`, `Columns`/`Column`, `Image`,
153
- `Title`/`SubTitle`, `Box`, `Card`, `Buttons`/`Button`, and `Notification` — all stock Bulma,
154
- no bestax extras. Its helper props are `display`/`justifyContent` (visibility + flexbox),
155
- `textAlign` (typography), and `textColor` (color); it uses no spacing props. That inventory
156
- compiles to the following — verified pixel-equivalent to the prebuilt `complete` flavor in
157
- headless Chromium (light and dark), at 453 KB raw / 40 KB gzip vs 813 KB / 83 KB:
156
+ `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:
158
163
 
159
164
  ```scss
160
165
  // src/styles.scss
@@ -167,6 +172,7 @@ headless Chromium (light and dark), at 453 KB raw / 40 KB gzip vs 813 KB / 83 KB
167
172
 
168
173
  @use 'bulma/sass/elements/box';
169
174
  @use 'bulma/sass/elements/button'; // Button + Buttons
175
+ @use 'bulma/sass/elements/delete'; // Notification's close button
170
176
  @use 'bulma/sass/elements/image';
171
177
  @use 'bulma/sass/elements/notification';
172
178
  @use 'bulma/sass/elements/title'; // Title + SubTitle
@@ -176,9 +182,8 @@ headless Chromium (light and dark), at 453 KB raw / 40 KB gzip vs 813 KB / 83 KB
176
182
  @use 'bulma/sass/layout/section';
177
183
 
178
184
  @use 'bulma/sass/helpers/visibility'; // display="flex"
179
- @use 'bulma/sass/helpers/flexbox'; // justifyContent/flexGrow/flexShrink
185
+ @use 'bulma/sass/helpers/flexbox'; // flexGrow
180
186
  @use 'bulma/sass/helpers/typography'; // textAlign
181
- @use 'bulma/sass/helpers/color'; // textColor
182
187
  ```
183
188
 
184
189
  ```tsx
@@ -5,7 +5,7 @@
5
5
  // under a ConfigProvider `classPrefix`, which the prefixed flavors read. This
6
6
  // is global (even on a scoped Theme); `'system'` removes the attributes so
7
7
  // Bulma follows the OS `prefers-color-scheme`. Wrap the app once at the root.
8
- import React, { useState } from 'react';
8
+ import { useState } from 'react';
9
9
  import {
10
10
  Theme,
11
11
  Box,
@@ -6,7 +6,7 @@
6
6
  // palette. The <Theme> component writes those CSS variables for you:
7
7
  // - isRoot -> inject the variables globally at :root (use once, at the app root)
8
8
  // - without isRoot -> wrap children in a <div> and scope the variables to it
9
- import React from 'react';
9
+ import type { ReactNode } from 'react';
10
10
  import {
11
11
  Theme,
12
12
  Button,
@@ -17,7 +17,7 @@ import {
17
17
 
18
18
  // 1) Global brand theme at the app root.
19
19
  // Hue is unitless; saturation and lightness are percentages.
20
- export function ThemedApp({ children }: { children: React.ReactNode }) {
20
+ export function ThemedApp({ children }: { children: ReactNode }) {
21
21
  return (
22
22
  <Theme
23
23
  isRoot
@@ -246,7 +246,9 @@ list it, so set it in your CSS or through a `style` prop.)
246
246
  The two `range` variables paint a range calendar (`DateRangeInput`): the band between a range's
247
247
  ends, and the fainter band shown while the end is still being picked. Both are mixed from
248
248
  `--bulma-dateinput-cell-selected-bg`, so `color` and an override of the selected fill re-tint
249
- them too.
249
+ them too. Inside a band, a nearby month's day reads `--bulma-dateinput-cell-color` rather than
250
+ `--bulma-dateinput-cell-other-month-color`, and today's tint leans a fifth of the way toward
251
+ `--bulma-text-strong`, so both stay readable on the band's color.
250
252
 
251
253
  ### DateRangeInput
252
254
 
@@ -6,15 +6,15 @@ This template provides a minimal setup to get React working in Vite with HMR and
6
6
 
7
7
  ```bash
8
8
  pnpm install
9
- pnpm dev
9
+ pnpm run dev
10
10
  ```
11
11
 
12
12
  ## Available Scripts
13
13
 
14
- - `pnpm dev` - Start development server
15
- - `pnpm build` - Build for production
16
- - `pnpm preview` - Preview production build
17
- - `pnpm lint` - Run ESLint
14
+ - `pnpm run dev` - Start development server
15
+ - `pnpm run build` - Build for production
16
+ - `pnpm run preview` - Preview production build
17
+ - `pnpm run lint` - Run ESLint
18
18
 
19
19
  ## Features
20
20
 
@@ -22,7 +22,6 @@ pnpm dev
22
22
  - 🎨 Bulma CSS framework
23
23
  - 📦 bestax-bulma component library
24
24
  - 🔧 ESLint pre-configured
25
- - 🎯 Font Awesome icons included
26
25
 
27
26
  ## Learn More
28
27
 
@@ -1 +1,14 @@
1
- /* App-specific styles - keep minimal, let Bulma handle the styling */
1
+ /* App-specific styles - keep minimal, let Bulma handle the styling */
2
+
3
+ /* A link inside running text needs more than its color to stand out
4
+ (WCAG 1.4.1), and no helper prop sets an underline. */
5
+ .text-link {
6
+ text-decoration: underline;
7
+ }
8
+
9
+ /* Bulma spaces a notification from whatever follows it in the same parent,
10
+ and each notification here is alone in its status region, so the space
11
+ between two showing at once goes between their regions instead. */
12
+ .status-region:not(:empty) + .status-region:not(:empty) {
13
+ margin-top: var(--bulma-block-spacing);
14
+ }