create-bestax 3.5.0 → 3.7.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.
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,KAAK,CAAC,MAAM,CAAC;CAC5B;AAED,eAAO,MAAM,SAAS,EAAE,QAAQ,EAG/B,CAAC;AAEF,eAAO,MAAM,oBAAoB,kBAAkB,CAAC;AACpD,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAC3C,eAAO,MAAM,kBAAkB,QAAsB,CAAC;AAEtD,eAAO,MAAM,QAAQ;;;;;;;wCAaQ,MAAM;uCAEP,MAAM;sCACP,MAAM;4CAEA,MAAM;;;;;CAM7B,CAAC;AASX,eAAO,MAAM,WAAW,QAed,CAAC;AAEX,eAAO,MAAM,OAAO;;;;;;CAOV,CAAC;AAOX,eAAO,MAAM,2BAA2B,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAK9D,CAAC;AAKF,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,SAAS,GACpB,aAAa,MAAM,EACnB,8BAA8B,eAAe,KAC5C,MAoEF,CAAC;AAEF,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,KAAK,CAAC,MAAM,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IAIrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,eAAO,MAAM,cAAc,EAAE,WAAW,EA6CvC,CAAC;AAEF,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,OAAO,KAAK,CAAC,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,eAAO,MAAM,aAAa,EAAE,WAAW,EA4CtC,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,KAAK,CAAC,MAAM,CAAC;CAC5B;AAED,eAAO,MAAM,SAAS,EAAE,QAAQ,EAG/B,CAAC;AAEF,eAAO,MAAM,oBAAoB,kBAAkB,CAAC;AACpD,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAC3C,eAAO,MAAM,kBAAkB,QAAsB,CAAC;AAEtD,eAAO,MAAM,QAAQ;;;;;;;wCAaQ,MAAM;uCAEP,MAAM;sCACP,MAAM;4CAEA,MAAM;;;;;CAM7B,CAAC;AASX,eAAO,MAAM,WAAW,QAed,CAAC;AAEX,eAAO,MAAM,OAAO;;;;;;CAOV,CAAC;AAOX,eAAO,MAAM,2BAA2B,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAK9D,CAAC;AAKF,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,SAAS,GACpB,aAAa,MAAM,EACnB,8BAA8B,eAAe,KAC5C,MA2EF,CAAC;AAEF,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,KAAK,CAAC,MAAM,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IAIrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,eAAO,MAAM,cAAc,EAAE,WAAW,EA6CvC,CAAC;AAEF,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,OAAO,KAAK,CAAC,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,eAAO,MAAM,aAAa,EAAE,WAAW,EA4CtC,CAAC"}
package/dist/constants.js CHANGED
@@ -99,7 +99,13 @@ ${setupLines.join('\n')}
99
99
  take a \`gap\` prop, so prefer that there).
100
100
  - Compose existing components before writing custom CSS; theme via \`Theme\` and \`--bulma-*\`
101
101
  variables, never hardcoded colors.
102
+ - \`Navbar.Burger\`/\`Navbar.Menu\` are controlled — wire \`active\` via state on both, and pair
103
+ \`Navbar fixed="top"\` with the \`has-navbar-fixed-top\` class on \`<html>\` (never an inline
104
+ padding offset).
102
105
  - There is no test runner or Storybook in this app — don't assume one.
106
+ - \`index.html\`'s \`<title>\` starts as the project name and \`README.md\` is stock template
107
+ boilerplate — once this app has a real identity, set the title (and any meta tags) to match
108
+ it and rewrite the README to describe *this* app, not the template.
103
109
 
104
110
  ## AI skills
105
111
 
@@ -112,6 +118,7 @@ automatically when the task matches:
112
118
  - **bestax-layout-scaffold** — scaffold full pages (app shell, landing, centered, card grid).
113
119
  - **bestax-icons** — icons via \`Icon\`/\`IconText\`: library setup, name formats, variants, a11y.
114
120
  - **bestax-optimize** — shrink the built CSS: measure raw+gzip, then flavor switch or a modular Sass build.
121
+ - **bestax-migrate** — migrate code off react-bulma-components (v4): run the codemod, resolve its TODOs.
115
122
 
116
123
  Prefer the library's components and these skills over hand-written Bulma markup or custom CSS.
117
124
 
@@ -20,6 +20,7 @@ export declare class ProjectCreator {
20
20
  checkExistingDirectory(targetPath: string, targetDir: string): Promise<boolean>;
21
21
  getTemplatePath(template: string): string;
22
22
  copyTemplate(template: string, targetPath: string): Promise<void>;
23
+ updateIndexHtmlTitle(targetPath: string, projectName: string): Promise<void>;
23
24
  setupSkills(targetPath: string, projectName: string, options: ClaudeMdOptions): Promise<void>;
24
25
  setupBulmaFlavor(targetPath: string, bulmaFlavor: string, template: string): Promise<void>;
25
26
  private getIconName;
@@ -1 +1 @@
1
- {"version":3,"file":"project-creator.d.ts","sourceRoot":"","sources":["../src/project-creator.ts"],"names":[],"mappings":"AA2BA,OAAO,EAOL,KAAK,eAAe,EACrB,MAAM,gBAAgB,CAAC;AAIxB,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,YAAY,CAAS;gBAEjB,YAAY,CAAC,EAAE,MAAM;IAI3B,cAAc,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAa3D,sBAAsB,CAC1B,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC;IAkBnB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAInC,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMjE,WAAW,CACf,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,IAAI,CAAC;IAqBV,gBAAgB,CACpB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC;IAmDhB,OAAO,CAAC,WAAW;IA2BnB,OAAO,CAAC,YAAY;IAYd,gBAAgB,CACpB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC;IAgJV,mBAAmB,CACvB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC;IAmEV,MAAM,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;CAwIvE"}
1
+ {"version":3,"file":"project-creator.d.ts","sourceRoot":"","sources":["../src/project-creator.ts"],"names":[],"mappings":"AA2BA,OAAO,EAOL,KAAK,eAAe,EACrB,MAAM,gBAAgB,CAAC;AAIxB,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,YAAY,CAAS;gBAEjB,YAAY,CAAC,EAAE,MAAM;IAI3B,cAAc,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAa3D,sBAAsB,CAC1B,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC;IAkBnB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAInC,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMjE,oBAAoB,CACxB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC;IAgBV,WAAW,CACf,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,IAAI,CAAC;IAqBV,gBAAgB,CACpB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC;IAmDhB,OAAO,CAAC,WAAW;IA2BnB,OAAO,CAAC,YAAY;IAYd,gBAAgB,CACpB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC;IAgJV,mBAAmB,CACvB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC;IAmEV,MAAM,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;CAyIvE"}
@@ -45,6 +45,18 @@ export class ProjectCreator {
45
45
  await ensureDirectory(targetPath);
46
46
  await copyDirectory(templatePath, targetPath);
47
47
  }
48
+ async updateIndexHtmlTitle(targetPath, projectName) {
49
+ const indexHtmlPath = path.join(targetPath, 'index.html');
50
+ if (!fs.existsSync(indexHtmlPath))
51
+ return;
52
+ const htmlContent = await fs.readFile(indexHtmlPath, 'utf8');
53
+ // projectName is validated against PROJECT_NAME_REGEX (letters, digits,
54
+ // dots, dashes, underscores only), so it needs no HTML escaping.
55
+ const updated = htmlContent.replace(/<title>[^<]*<\/title>/, `<title>${projectName}</title>`);
56
+ if (updated !== htmlContent) {
57
+ await fs.writeFile(indexHtmlPath, updated);
58
+ }
59
+ }
48
60
  async setupSkills(targetPath, projectName, options) {
49
61
  const skillsSrc = path.join(this.templatesDir, 'skills');
50
62
  if (!(await checkDirectoryExists(skillsSrc))) {
@@ -392,6 +404,7 @@ export class ProjectCreator {
392
404
  try {
393
405
  await this.copyTemplate(template, targetPath);
394
406
  await updatePackageJson(targetPath, projectName);
407
+ await this.updateIndexHtmlTitle(targetPath, projectName);
395
408
  await this.setupBulmaFlavor(targetPath, bulmaFlavor, template);
396
409
  await this.setupIconLibrary(targetPath, iconLibrary, template);
397
410
  await this.setupConfigProvider(targetPath, bulmaFlavor, iconLibrary, template);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-bestax",
3
- "version": "3.5.0",
3
+ "version": "3.7.0",
4
4
  "description": "Create a new bestax-bulma project",
5
5
  "type": "module",
6
6
  "bin": {
@@ -64,13 +64,13 @@
64
64
  "@playwright/test": "^1.57.0",
65
65
  "@types/fs-extra": "^11.0.4",
66
66
  "@types/jest": "^30.0.0",
67
- "@types/node": "^26.0.1",
67
+ "@types/node": "^26.1.1",
68
68
  "@types/prompts": "^2.4.9",
69
69
  "@types/wait-on": "^5.3.4",
70
70
  "jest": "^30.2.0",
71
71
  "ts-jest": "^29.4.6",
72
72
  "typescript": "^6.0.3",
73
- "wait-on": "^9.0.10"
73
+ "wait-on": "^9.1.0"
74
74
  },
75
75
  "publishConfig": {
76
76
  "access": "public",
@@ -45,8 +45,12 @@ Centered; a collection of items → Card grid. For mixed requests, pick the domi
45
45
  `height: 100%` on the card doesn't help — the column's height is auto).
46
46
  - Rely on Bulma's responsive defaults: `Columns` sit side by side on tablet and up and stack on
47
47
  mobile. Add responsive `size*` props only to tune the breakpoints.
48
- - For a `fixed="top"` `Navbar`, add the `has-navbar-fixed-top` class to `<html>` so content is not
49
- hidden behind it the library does not do this automatically.
48
+ - `Navbar.Burger`/`Navbar.Menu` are **controlled** — wire the same `active` state to both:
49
+ `active` on `Navbar.Menu` shows/hides the mobile menu, while `active` + `onClick` on
50
+ `Navbar.Burger` make the burger toggle it and animate. Left unwired, clicking the burger
51
+ does nothing (no error, silent failure). For a `fixed="top"` `Navbar`, add the
52
+ `has-navbar-fixed-top` class to `<html>` so content is not hidden behind it — the library
53
+ does not do this automatically, and an inline padding offset is not a substitute.
50
54
  - **Style with helper props, not inline `style`.** Use `m`/`p` spacing (`mt="4"` = 1rem),
51
55
  `textAlign="centered"`, and `textColor`/`bgColor` instead of `style={{ marginTop, textAlign,
52
56
  color }}`. Set the app-wide icon library once with `<ConfigProvider iconLibrary="…">` at the root
@@ -69,7 +73,7 @@ color }}`. Set the app-wide icon library once with `<ConfigProvider iconLibrary=
69
73
  ## Examples
70
74
 
71
75
  - `examples/app-shell.tsx` — fixed `Navbar` + sidebar `Menu` + content (dashboard).
72
- - `examples/landing.tsx` — `Hero` + `Section`s + `Footer`.
76
+ - `examples/landing.tsx` — fixed `Navbar` (controlled burger) + `Hero` + `Section`s + `Footer`.
73
77
  - `examples/centered.tsx` — centered single column (auth/settings).
74
78
  - `examples/card-grid.tsx` — multiline `Columns` of `Card`s (catalog).
75
79
  - `examples/content-page.tsx` — hero + feature cards + CTA styled with helper props (no inline
@@ -82,6 +86,7 @@ color }}`. Set the app-wide icon library once with `<ConfigProvider iconLibrary=
82
86
  - [ ] Use `Grid`/`Cell` for uniform grids (equal heights per row, free); `Columns`/`Column`
83
87
  for proportional or per-breakpoint side-by-side layout — with the flex recipe when its
84
88
  cards must match height.
89
+ - [ ] Wire `active` state to **both** `Navbar.Burger` and `Navbar.Menu` (they are controlled).
85
90
  - [ ] For a fixed navbar, add `has-navbar-fixed-top` to `<html>`.
86
91
  - [ ] Do not use `Tile` — it is not shipped.
87
92
  - [ ] Style with helper props (`mt`/`p`, `textAlign`, `textColor`), not inline `style`.
@@ -1,8 +1,18 @@
1
- // Marketing / landing page — Hero + stacked Sections + Footer.
1
+ // Marketing / landing page — fixed top Navbar + Hero + stacked Sections + Footer.
2
2
  // Each Section stacks vertically; the feature Columns collapse to one per row on
3
3
  // mobile (Bulma columns stack below the tablet breakpoint).
4
- import React from 'react';
4
+ //
5
+ // The Navbar's burger/menu is CONTROLLED: `active` on Navbar.Menu shows/hides
6
+ // the mobile menu, while `active` + `onClick` on Navbar.Burger make the burger
7
+ // toggle it and animate. Wire the same state to both — left unwired, clicking
8
+ // the burger does nothing; desktop looks fine and nothing errors, so the
9
+ // failure is silent. A fixed-top navbar
10
+ // also needs the `has-navbar-fixed-top` class on <html> so the page is padded
11
+ // below it (never an inline padding offset) — Bulma requires this and the
12
+ // library does NOT add it for you.
13
+ import React, { useEffect, useState } from 'react';
5
14
  import {
15
+ Navbar,
6
16
  Hero,
7
17
  Section,
8
18
  Container,
@@ -24,8 +34,38 @@ const FEATURES = [
24
34
  ];
25
35
 
26
36
  export default function LandingPage() {
37
+ const [menuOpen, setMenuOpen] = useState(false);
38
+
39
+ useEffect(() => {
40
+ document.documentElement.classList.add('has-navbar-fixed-top');
41
+ return () => {
42
+ document.documentElement.classList.remove('has-navbar-fixed-top');
43
+ };
44
+ }, []);
45
+
27
46
  return (
28
47
  <>
48
+ <Navbar fixed="top">
49
+ <Navbar.Brand>
50
+ <Navbar.Item href="#">Acme</Navbar.Item>
51
+ <Navbar.Burger
52
+ active={menuOpen}
53
+ onClick={() => setMenuOpen(open => !open)}
54
+ aria-label="menu"
55
+ aria-expanded={menuOpen}
56
+ />
57
+ </Navbar.Brand>
58
+ <Navbar.Menu active={menuOpen}>
59
+ <Navbar.Start>
60
+ <Navbar.Item href="#">Features</Navbar.Item>
61
+ <Navbar.Item href="#">Pricing</Navbar.Item>
62
+ </Navbar.Start>
63
+ <Navbar.End>
64
+ <Navbar.Item href="#">Sign in</Navbar.Item>
65
+ </Navbar.End>
66
+ </Navbar.Menu>
67
+ </Navbar>
68
+
29
69
  <Hero color="primary" size="medium">
30
70
  <Hero.Body>
31
71
  <Container textAlign="centered">
@@ -19,6 +19,8 @@ app".
19
19
  **Skeleton:**
20
20
 
21
21
  ```tsx
22
+ const [open, setOpen] = useState(false); // controls the burger + mobile menu
23
+
22
24
  <>
23
25
  <Navbar fixed="top" color="dark">
24
26
  <Navbar.Brand>
@@ -54,7 +56,7 @@ app".
54
56
  </Column>
55
57
  </Columns>
56
58
  </Container>
57
- </>
59
+ </>;
58
60
  ```
59
61
 
60
62
  **Required:** add `has-navbar-fixed-top` to `<html>` (see `examples/app-shell.tsx`) so content is
@@ -74,7 +76,29 @@ pricing page. The default for "build me a site/page".
74
76
  **Skeleton:**
75
77
 
76
78
  ```tsx
79
+ const [open, setOpen] = useState(false); // controls the burger + mobile menu
80
+
77
81
  <>
82
+ <Navbar fixed="top">
83
+ <Navbar.Brand>
84
+ <Navbar.Item href="#">Brand</Navbar.Item>
85
+ <Navbar.Burger
86
+ active={open}
87
+ onClick={() => setOpen(o => !o)}
88
+ aria-label="menu"
89
+ />
90
+ </Navbar.Brand>
91
+ <Navbar.Menu active={open}>
92
+ <Navbar.Start>
93
+ <Navbar.Item href="#">Features</Navbar.Item>
94
+ <Navbar.Item href="#">Pricing</Navbar.Item>
95
+ </Navbar.Start>
96
+ <Navbar.End>
97
+ <Navbar.Item href="#">Sign in</Navbar.Item>
98
+ </Navbar.End>
99
+ </Navbar.Menu>
100
+ </Navbar>
101
+
78
102
  <Hero color="primary" size="medium">
79
103
  <Hero.Body>
80
104
  <Container textAlign="centered">
@@ -110,10 +134,18 @@ pricing page. The default for "build me a site/page".
110
134
  <Content textAlign="centered">{/* footer */}</Content>
111
135
  </Container>
112
136
  </Footer>
113
- </>
137
+ </>;
114
138
  ```
115
139
 
116
- **Responsive:** `Section`s already stack vertically. The feature `Columns` collapse to one feature
140
+ **Required:** `Navbar.Burger`/`Navbar.Menu` are **controlled** wire the same `active` state to
141
+ both: `active` on `Navbar.Menu` shows/hides the mobile menu, and `active` + `onClick` on
142
+ `Navbar.Burger` make the burger toggle it and animate (a bare `<Navbar.Burger />` does nothing
143
+ when clicked, with no error). And add
144
+ `has-navbar-fixed-top` to `<html>` (see `examples/landing.tsx`) so content is not hidden behind
145
+ the fixed navbar — never an inline padding offset.
146
+
147
+ **Responsive:** the navbar collapses to a burger on mobile (`Navbar.Burger` + `Navbar.Menu active`).
148
+ `Section`s already stack vertically. The feature `Columns` collapse to one feature
117
149
  per row on mobile. Use `Hero size="large"` / `"fullheight"` for a taller hero.
118
150
 
119
151
  **Hero CTAs:** on a colored hero use **filled** buttons only — `color="light"` for the primary
@@ -0,0 +1,78 @@
1
+ ---
2
+ name: bestax-migrate
3
+ description: Migrate an existing app from react-bulma-components (v4) to @allxsmith/bestax-bulma on Bulma v1 — run the bestax-migrate codemod, then resolve every TODO(bestax-migrate) comment it leaves using the mapping references. Use when a repo imports react-bulma-components and wants to move to bestax-bulma, when TODO(bestax-migrate) comments are present in a codebase, or when asked to migrate off an unmaintained React Bulma library.
4
+ license: MIT
5
+ ---
6
+
7
+ # Migrating from react-bulma-components to bestax-bulma
8
+
9
+ `react-bulma-components` is unmaintained (last release 2022, Bulma 0.9.x).
10
+ `@allxsmith/bestax-bulma` is an actively maintained React library for **Bulma v1**. The
11
+ `bestax-migrate` codemod automates most of the conversion; this skill drives the codemod and
12
+ finishes what it flags.
13
+
14
+ ## Workflow
15
+
16
+ Run these steps in order. Don't hand-convert what the codemod converts automatically.
17
+
18
+ 1. **Dry-run the codemod** on the source directory and review the report:
19
+
20
+ ```sh
21
+ pnpm dlx bestax-migrate react-bulma-components src/ --dry
22
+ ```
23
+
24
+ 2. **Apply it** (same command without `--dry`), then run the project's formatter — the
25
+ codemod preserves surrounding formatting but doesn't prettify what it rewrites.
26
+ Besides the components, it also migrates **stylesheets** (CSS imports →
27
+ `@allxsmith/bestax-bulma/bestax.css`; SCSS `@import 'bulma/bulma'` + `$var` overrides
28
+ → `@use 'bulma/sass' with (…)` plus the bestax extras) and **package.json**
29
+ (react-bulma-components removed, bestax-bulma added, bulma → ^1, node-sass → sass).
30
+ Flags: `--css bulma|keep` for other stylesheet targets, `--no-deps` to leave
31
+ package.json alone.
32
+
33
+ 3. **Install** — the codemod edits package.json but never runs a package manager:
34
+
35
+ ```sh
36
+ npm install # or pnpm/yarn
37
+ ```
38
+
39
+ The report's `peer-deps` entries predict install failures: bestax-bulma needs
40
+ **React 18/19** (RBC also ran on 17 — upgrade react/react-dom first) and its optional
41
+ Font Awesome peer wants **FA ≥ 6.7** (an app pinned to FA 5 either upgrades or
42
+ installs with `npm install --legacy-peer-deps`).
43
+
44
+ 4. **Resolve every TODO**: `grep -rn "TODO(bestax-migrate)" src/`. Each comment names the
45
+ prop/component and a hint. Recipes for every recurring case are in
46
+ [references/unmappables.md](references/unmappables.md); the full component and prop
47
+ tables are in [references/component-map.md](references/component-map.md) and
48
+ [references/prop-map.md](references/prop-map.md). Delete each comment as you resolve it.
49
+
50
+ 5. **Finish the stylesheet layer** — flagged Sass cases (computed variables,
51
+ indented-syntax `.sass` files), CSS flavor choice, and Bulma 0.9→1 styling changes:
52
+ follow [references/css-migration.md](references/css-migration.md).
53
+
54
+ 6. **Finish**: typecheck/build, and review the rendered app side by side against the
55
+ pre-migration UI.
56
+
57
+ ## What the codemod handles vs. flags
58
+
59
+ All 32 react-bulma-components v4 components have a mapping. Imports (named, namespace, and
60
+ `const { Input } = Form` destructuring), component renames, prop renames/value conversions,
61
+ responsive breakpoint objects, CSS/SCSS stylesheet imports, and package.json dependencies
62
+ convert automatically. It flags with
63
+ `TODO(bestax-migrate)` instead of guessing: `Element` and `Tile` (no bestax equivalent —
64
+ Tile is replaced by Bulma v1's Grid), controlled `Dropdown`/`Dropdown.Item value`,
65
+ `touch`/`until*` breakpoints, dynamic prop values it can't rewrite, and props with no
66
+ bestax counterpart. Files in formats it can't parse (`.astro`, `.vue`, `.svelte`, `.mdx`)
67
+ that import react-bulma-components are reported as `unsupported-file` — migrate those by
68
+ hand with the component map. Never "fix" a TODO by silencing it — convert the code per the
69
+ references, or deliberately keep the old markup with `className` styling.
70
+
71
+ ## Rules
72
+
73
+ - The codemod is idempotent on already-migrated files (it only touches files importing
74
+ `react-bulma-components`) — safe to re-run after partial manual work.
75
+ - Don't downgrade converted props back to RBC names; bestax uses `is*` booleans
76
+ (`isLoading`), string size unions (`textSize="4"`), and `as` instead of `renderAs`.
77
+ - If a component the app uses isn't in the component map, it wasn't part of RBC v4 —
78
+ check for a local wrapper component and migrate its internals instead.
@@ -0,0 +1,91 @@
1
+ # Component map: react-bulma-components v4 → @allxsmith/bestax-bulma
2
+
3
+ Every RBC v4 export and compound sub-component, with its bestax target. **Auto** = the
4
+ codemod converts it; **Flagged** = it leaves a `TODO(bestax-migrate)` comment (see
5
+ [unmappables.md](unmappables.md) for the recipes).
6
+
7
+ ## Top-level components
8
+
9
+ | RBC | bestax | Notes |
10
+ | -------------- | -------------------------------------------- | ------------------------------------------------------------------------------------- |
11
+ | `Block` | `Block` | Auto |
12
+ | `Box` | `Box` | Auto |
13
+ | `Breadcrumb` | `Breadcrumb` | Auto; `align` → `alignment` (`center`→`centered`) |
14
+ | `Button` | `Button` | Auto; `<Button remove/>` → `<Delete/>`; see prop map |
15
+ | `Card` | `Card` | Auto |
16
+ | `Columns` | `Columns` | Auto; `breakpoint="mobile"`→`isMobile`, `multiline`→`isMultiline`, … |
17
+ | `Container` | `Container` | Auto; `breakpoint="fluid"`→`fluid`, `max`→`isMax` |
18
+ | `Content` | `Content` | Auto |
19
+ | `Dropdown` | `Dropdown` | Structure auto; controlled `value`/`onChange` flagged |
20
+ | `Element` | — | Flagged: no generic element; use a semantic component + helper props |
21
+ | `Footer` | `Footer` | Auto |
22
+ | `Form.*` | flat imports | See Form table below |
23
+ | `Heading` | `Title` / `SubTitle` / `<p class="heading">` | Auto; `subtitle` picks `SubTitle`, `heading` picks the plain element |
24
+ | `Hero` | `Hero` | Auto; `hasNavbar`→`fullheightWithNavbar`; `halfheight`/`gradient` flagged |
25
+ | `Icon` | `Icon` | `<i class="fas fa-x">` children → `name`/`library`/`variant` props; else flagged |
26
+ | `Image` | `Image` | Auto; numeric `size={128}` → `size="128x128"`, `rounded`→`isRounded` |
27
+ | `Level` | `Level` | Auto; `breakpoint="mobile"`→`isMobile` |
28
+ | `Loader` | plain `<div className="loader">` | Auto (Bulma v1 still ships the class) |
29
+ | `Media` | `Media` | Auto |
30
+ | `Menu` | `Menu` | Auto |
31
+ | `Message` | `Message` | Auto; `size` flagged |
32
+ | `Modal` | `Modal` | `show`→`active`; `closeOnEsc`/`closeOnBlur`/`showClose` flagged (defaults cover them) |
33
+ | `Navbar` | `Navbar` | Auto; see dropdown note below |
34
+ | `Notification` | `Notification` | Auto; `light`→`isLight` |
35
+ | `Pagination` | `Pagination` | `onChange`→`onPageChange`; `delta`/labels/`showFirstLast`/`autoHide` flagged |
36
+ | `Panel` | `Panel` | Auto |
37
+ | `Progress` | `Progress` | Auto |
38
+ | `Section` | `Section` | Auto |
39
+ | `Table` | `Table` | Auto; `size="fullwidth"`→`isFullwidth`, `striped`→`isStriped`, … |
40
+ | `Tabs` | `Tabs` | Auto; children wrapped in `Tabs.List`; `type="toggle-rounded"`→`toggle rounded` |
41
+ | `Tag` | `Tag` | Auto; `remove`→`isDelete`, `rounded`→`isRounded` |
42
+ | `Tile` | — | Flagged: Bulma v1 replaced tiles with `Grid`/`Cell` |
43
+
44
+ ## Compound sub-components
45
+
46
+ | RBC | bestax |
47
+ | ----------------------------------------------------------- | ------------------------------------------------------------------------ |
48
+ | `Breadcrumb.Item` | plain `<li><a href=…>` (`active` → `is-active`) |
49
+ | `Button.Group` | `Buttons` (`align="right"`→`isRight`) |
50
+ | `Card.Header` / `.Title` / `.Icon` | `Card.Header` / `.Header.Title` / `.Header.Icon` |
51
+ | `Card.Image` | `Card.Image` wrapping an inner `<Image>` |
52
+ | `Card.Content` | `Card.Content` |
53
+ | `Card.Footer` / `Card.Footer.Item` | `Card.Footer` / `Card.FooterItem` |
54
+ | `Columns.Column` | `Column` (flat import) |
55
+ | `Dropdown.Item` / `.Divider` | `Dropdown.Item` / `Dropdown.Divider` |
56
+ | `Hero.Header` / `.Body` / `.Footer` | `Hero.Head` / `Hero.Body` / `Hero.Foot` |
57
+ | `Icon.Text` | `IconText` |
58
+ | `Level.Side align` / `Level.Item` | `Level.Left` or `Level.Right` / `Level.Item` |
59
+ | `Media.Item align` | `MediaLeft` / `MediaContent` / `MediaRight` (flat) |
60
+ | `Menu.List` (+ `title`) | `Menu.List` (+ a `Menu.Label` sibling) |
61
+ | `Menu.List.Item` | `Menu.Item` |
62
+ | `Message.Header` / `.Body` | `Message.Header` / `Message.Body` |
63
+ | `Modal.Content` | `Modal.Content` |
64
+ | `Modal.Card` `.Header`/`.Body`/`.Footer`/`.Title` | `Modal.Card` `.Head`/`.Body`/`.Foot`/`.Title` |
65
+ | `Navbar.Brand`/`.Burger`/`.Menu`/`.Item`/`.Link`/`.Divider` | same names |
66
+ | `Navbar.Container align` | `Navbar.Start` / `Navbar.End` |
67
+ | `Navbar.Item` wrapping a dropdown | `Navbar.Dropdown` (container) |
68
+ | `Navbar.Dropdown` (the menu) | `Navbar.DropdownMenu` |
69
+ | `Panel.Header` | `Panel.Heading` |
70
+ | `Panel.Tabs` / `Panel.Tabs.Tab` | `Panel.Tabs` / plain `<a>` children |
71
+ | `Panel.Block` / `Panel.Icon` | `Panel.Block` / `Panel.Icon` (icon child → `name`) |
72
+ | `Table.Container` | `isResponsive` on the child `Table` (or `<div class="table-container">`) |
73
+ | `Tabs.Tab` | `Tabs.Item` (inside a generated `Tabs.List`) |
74
+ | `Tag.Group` | `Tags` (`gapless` → `hasAddons`) |
75
+
76
+ ## Form namespace → flat imports
77
+
78
+ | RBC | bestax |
79
+ | ------------------ | -------------------------------------------------------------------------------------------------------------------------------- |
80
+ | `Form.Field` | `Field` (`kind="group"`→`grouped`, `kind="addons"`→`hasAddons`, `align` folds into the value, `multiline`→`grouped="multiline"`) |
81
+ | `Form.Field.Label` | `FieldLabel` |
82
+ | `Form.Field.Body` | `FieldBody` |
83
+ | `Form.Control` | `Control` (`fullwidth`→`isExpanded`, `loading`→`isLoading`) |
84
+ | `Form.Input` | `Input` (`rounded`→`isRounded`, `status="focus"`→`isFocused`) |
85
+ | `Form.Label` | plain `<label className="label">` |
86
+ | `Form.Textarea` | `TextArea` (`fixedSize`→`hasFixedSize`) |
87
+ | `Form.Select` | `Select` (`loading`→`isLoading`, `fullwidth`→`isFullwidth`) |
88
+ | `Form.Checkbox` | `Checkbox` |
89
+ | `Form.Radio` | `Radio` |
90
+ | `Form.Help` | plain `<p className="help is-…">` (prefer Field `message`/`messageColor`) |
91
+ | `Form.InputFile` | `File` (`filename`→`fileName`+`hasName`, `boxed`→`isBoxed`, `label`→`buttonLabel`) |
@@ -0,0 +1,100 @@
1
+ # Stylesheets: Bulma 0.9 → Bulma v1 + bestax
2
+
3
+ react-bulma-components apps style with Bulma 0.9.x; bestax-bulma targets Bulma v1. The
4
+ codemod automates most of this layer — this reference explains what it did and how to
5
+ finish what it flagged.
6
+
7
+ ## What the codemod already did (default `--css bestax`)
8
+
9
+ - **CSS imports**: `bulma/css/bulma(.min).css` and v3-era
10
+ `react-bulma-components/dist/*.css` imports became the recommended combined bundle
11
+ `@allxsmith/bestax-bulma/bestax.css` (Bulma v1 + the bestax extras that themed
12
+ Radio/Checkbox and the advanced form controls need). A separate `extras.css` import
13
+ next to it is collapsed.
14
+ **Visual note**: `bestax.css` ships with `$primary` set to bestax blue (`#1e6b99`),
15
+ not Bulma's stock turquoise — `is-primary` surfaces (hero, navbar, buttons) change
16
+ color. Keep the stock Bulma look with `--css bulma`, or set your own brand color via
17
+ `--bulma-primary-*` CSS variables / a Sass build.
18
+
19
+ - **SCSS files**: Bulma 0.9's `@import 'bulma/bulma.sass'` (plus preceding
20
+ `$var: value !default;` overrides) became Bulma v1 module syntax, with simple literal
21
+ overrides folded in:
22
+
23
+ ```scss
24
+ @use 'bulma/sass' with (
25
+ $primary: #ff6b35,
26
+ $family-primary: 'Nunito',
27
+ sans-serif
28
+ );
29
+ @use '@allxsmith/bestax-bulma/scss/extras';
30
+ ```
31
+
32
+ 0.9 `_all` aggregator imports (`bulma/sass/elements/_all`) became directory modules
33
+ (`@use 'bulma/sass/elements';`). Relative node_modules paths
34
+ (`@import '../../node_modules/bulma/bulma'`, common under Parcel) keep their prefix,
35
+ and the extras `@use` then points at the shipped file
36
+ (`…/node_modules/@allxsmith/bestax-bulma/src/scss/extras`) since such toolchains
37
+ resolve raw paths, not package specifiers. Building Bulma v1 from Sass needs
38
+ **dart-sass ≥ 1.79** — the codemod's node-sass replacement installs that, but check
39
+ bundler-pinned older versions (Parcel's sass transformer pins 1.66).
40
+
41
+ - **package.json**: `react-bulma-components` removed, `@allxsmith/bestax-bulma` added,
42
+ `bulma` bumped to `^1.0.4` (or added when sources still import `bulma/…` directly),
43
+ and dead `node-sass` replaced with dart `sass`. Run the package manager's install
44
+ afterwards — the codemod never installs anything.
45
+
46
+ Flag reference: `--css bulma` keeps plain `bulma/css/bulma.min.css` and adds a separate
47
+ `@allxsmith/bestax-bulma/extras.css` import; `--css keep` leaves stylesheets alone;
48
+ `--no-deps` skips the package.json step.
49
+
50
+ ## Finishing the flagged cases
51
+
52
+ - **Computed Sass variables** (`$primary: lighten(#333, 10%);` and anything with
53
+ functions/interpolation): move them into the `with (…)` configuration by hand —
54
+ `with (…)` values must be compile-time literals, so resolve the expression or compute
55
+ it after the `@use`.
56
+ - **Indented-syntax `.sass` files**: flagged, not rewritten. Convert `@import` lines to
57
+ `@use "bulma/sass" with (…)` manually (same rules as SCSS, minus semicolons/braces).
58
+ - **Unknown 0.9 partial paths**: the v1 sass tree is `bulma/sass/{utilities,base,
59
+ elements,form,components,grid,layout,helpers,themes}` with leaf partials like
60
+ `bulma/sass/utilities/initial-variables` — find the equivalent module and `@use` it.
61
+ - **Third-party Bulma extensions** (`bulma-checkradio`, `bulma-switch`, `bulma-tooltip`,
62
+ …): flagged, left in place. These are 0.9-era add-ons — check each one's Bulma v1
63
+ compatibility. Class-based usage (`className="is-checkradio"`) keeps needing the
64
+ extension; usage that migrated to bestax components (Radio, Checkbox, the advanced
65
+ form controls) is already styled by the bestax extras, so the import can go.
66
+
67
+ ## Choosing a CSS flavor (optional)
68
+
69
+ `bestax.css` is right for almost every app. Alternatives (swap the import specifier):
70
+
71
+ | Import | Use when |
72
+ | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
73
+ | `@allxsmith/bestax-bulma/versions/bestax-prefixed.css` | class conflicts with another framework — pair with `<ConfigProvider classPrefix="bestax-">` |
74
+ | `@allxsmith/bestax-bulma/versions/bestax-no-helpers.css` | smallest CSS; **helper props like `mt="4"` stop working** |
75
+ | `@allxsmith/bestax-bulma/versions/bestax-no-helpers-prefixed.css` | both of the above |
76
+ | `@allxsmith/bestax-bulma/versions/bestax-no-dark-mode.css` | light-mode-only product |
77
+
78
+ ## Custom SCSS builds with bestax
79
+
80
+ Do **not** `@use '@allxsmith/bestax-bulma/scss/bestax'` when you need your own
81
+ `$variable` overrides — that entry pre-configures `bulma/sass` and Sass forbids
82
+ configuring a module twice. The correct pairing (what the codemod emits) is:
83
+
84
+ ```scss
85
+ @use 'bulma/sass' with (
86
+ $primary: …
87
+ );
88
+ @use '@allxsmith/bestax-bulma/scss/extras';
89
+ ```
90
+
91
+ Per-component partials also exist (`@use '@allxsmith/bestax-bulma/scss/components/dialog';`,
92
+ `…/scss/form/autocomplete`, …) for modular builds.
93
+
94
+ ## Runtime theming
95
+
96
+ Bulma v1 themes with `--bulma-*` CSS variables at runtime (dark mode is automatic).
97
+ Sass `with (…)` is for compile-time tokens; for brand/dark-mode work use the bestax
98
+ `Theme` component — see the `bestax-theming` skill and
99
+ https://bestax.io/docs/guides/getting-started/migration/bulma-0-9-to-1 for the broader
100
+ 0.9 → 1 changes (Tiles → Grid, `is-bold` gradients removed, automatic dark mode).
@@ -0,0 +1,48 @@
1
+ # Universal prop map (RBC modifier props → bestax helper props)
2
+
3
+ react-bulma-components spreads a modifier-prop set onto every component. bestax-bulma has
4
+ the same idea via `useBulmaClasses`, with these differences. The codemod applies all of
5
+ this automatically for literal values; dynamic values get TODOs.
6
+
7
+ ## Renames and value changes
8
+
9
+ | RBC | bestax |
10
+ | --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
11
+ | `renderAs` | `as` — **only** on polymorphic components (Button, Title/SubTitle, Footer, Level.Item, Media\*, Menu.Item, Navbar.Item/Link, Dropdown.Item); elsewhere flagged |
12
+ | `domRef` | flagged — use a `ref` on a DOM child instead |
13
+ | `backgroundColor` | `bgColor` |
14
+ | `textColor` | `textColor` (same) |
15
+ | `colorVariant` | flagged — use `isLight` or a color shade |
16
+ | `textSize={4}` | `textSize="4"` (string union `'1'`–`'7'`) |
17
+ | `textAlign="center"` | `textAlign="centered"` (`justify`→`justified`) |
18
+ | `textFamily` | `fontFamily` |
19
+ | `italic` | `textTransform="italic"` |
20
+ | `m/mt/…/py={3}` | `m="3"` (string union `'0'`–`'6'`) |
21
+ | `pull="right"` | `float="right"` |
22
+ | `marginless` / `paddingless` | `m="0"` / `p="0"` |
23
+ | `clipped` | `overflow="clipped"` |
24
+ | `radiusless` / `shadowless` | `radius="radiusless"` / `shadow="shadowless"` |
25
+ | `unselectable` | `interaction="unselectable"` |
26
+ | `hidden` / `invisible` / `srOnly` | `visibility="hidden"` / `"invisible"` / `"sr-only"` |
27
+ | `display="hidden"` | `visibility="hidden"` |
28
+ | `display="relative"` | boolean `relative` |
29
+ | flexbox props | same names/values (`flexDirection`, `justifyContent`, …) |
30
+ | `clearfix`, `overlay` | same |
31
+
32
+ ## Boolean modifier convention
33
+
34
+ RBC uses bare booleans (`loading`, `outlined`, `rounded`, `fullwidth`); bestax prefixes
35
+ with `is`/`has` (`isLoading`, `isOutlined`, `isRounded`, `isFullWidth`). Per-component
36
+ tables live in [component-map.md](component-map.md).
37
+
38
+ ## Responsive breakpoint objects → flat per-viewport props
39
+
40
+ | RBC | bestax |
41
+ | ----------------------------------------------------------------------------- | ----------------------------------------------------------- |
42
+ | `mobile={{ display: 'flex' }}` | `displayMobile="flex"` |
43
+ | `tablet={{ textSize: 5 }}` | `textSizeTablet="5"` |
44
+ | `desktop={{ textAlign: 'center' }}` | `textAlignDesktop="centered"` |
45
+ | `widescreen={{ invisible: true }}` | `visibilityWidescreen="invisible"` |
46
+ | `Columns.Column mobile={{ size: 4, offset: 2, narrow: true }}` | `sizeMobile={4} offsetMobile={2} isNarrowMobile` |
47
+ | `Columns tablet={{ gap: 3 }}` | `gapTablet={3}` |
48
+ | `touch={{…}}`, `untilWidescreen={{…}}`, `untilFullhd={{…}}`, `{ only: true }` | flagged — no bestax helper variants; use `className` or CSS |
@@ -0,0 +1,124 @@
1
+ # Recipes for every TODO(bestax-migrate) the codemod leaves
2
+
3
+ Work through `grep -rn "TODO(bestax-migrate)" src/` with these. Delete each comment once
4
+ the site is converted.
5
+
6
+ ## `unsupported-file` — `.astro` / `.vue` / `.svelte` / `.mdx` imports
7
+
8
+ The codemod can't parse these formats, so files in them that import
9
+ react-bulma-components are reported (not rewritten). Migrate them by hand: swap the
10
+ import to `@allxsmith/bestax-bulma` and apply the same renames the component/prop maps
11
+ describe — the mapping is identical, only the rewriting is manual.
12
+
13
+ ## `peer-deps` — install-blocking version conflicts
14
+
15
+ Reported from package.json, not a code TODO. bestax-bulma's peers: **React ^18 || ^19**
16
+ (upgrade react/react-dom before installing — RBC v4 also ran on 17) and optional
17
+ **@fortawesome/fontawesome-free ^6.7 || ^7** (FA 5 apps: upgrade, or
18
+ `npm install --legacy-peer-deps` and keep FA 5 for your own `<i>` tags).
19
+
20
+ ## `Element` — no generic element
21
+
22
+ bestax has no `Element`. Pick the semantic component (`Block`, `Box`, `Content`, …) that
23
+ matches the usage, or plain JSX with classes:
24
+
25
+ ```tsx
26
+ // Before
27
+ <Element renderAs="span" textColor="grey" m={2}>…</Element>
28
+ // After
29
+ <Span textColor="grey" m="2">…</Span> // bestax exports Span/Paragraph/Strong/etc.
30
+ ```
31
+
32
+ ## `Tile` — Bulma v1 replaced tiles with Grid
33
+
34
+ Convert ancestor/parent/child tile trees to `Grid`/`Cell` (docs:
35
+ https://bestax.io/docs/api/grid/grid):
36
+
37
+ ```tsx
38
+ // Before
39
+ <Tile kind="ancestor"><Tile kind="parent" size={8}><Tile kind="child">A</Tile></Tile></Tile>
40
+ // After
41
+ <Grid><Cell colSpan={8}>A</Cell></Grid>
42
+ ```
43
+
44
+ Match the old proportions with `Cell` span props; tiles' `vertical` becomes grid flow.
45
+
46
+ ## Controlled `Dropdown` (`value` / `onChange`, `Dropdown.Item value`)
47
+
48
+ bestax `Dropdown` is compositional — you own the selection state:
49
+
50
+ ```tsx
51
+ const [choice, setChoice] = useState('a');
52
+ <Dropdown label={labels[choice]} closeOnClick>
53
+ <Dropdown.Item active={choice === 'a'} onClick={() => setChoice('a')}>
54
+ First
55
+ </Dropdown.Item>
56
+ <Dropdown.Item active={choice === 'b'} onClick={() => setChoice('b')}>
57
+ Second
58
+ </Dropdown.Item>
59
+ </Dropdown>;
60
+ ```
61
+
62
+ ## `Pagination` extras (`delta`, `next`/`previous`, `showFirstLast`, `showPrevNext`, `autoHide`)
63
+
64
+ bestax `Pagination` renders from `total`/`current`/`onPageChange` with its own windowing.
65
+ Drop `delta` (built-in), render conditionally instead of `autoHide`
66
+ (`{total > 1 && <Pagination …/>}`), and compose `Pagination.Previous`/`Pagination.Next`
67
+ manually if custom labels are essential.
68
+
69
+ ## `Modal` (`closeOnEsc`, `closeOnBlur`, `showClose`)
70
+
71
+ bestax `Modal` already closes on Esc and background click and shows the close button
72
+ whenever `onClose` is set — usually just delete these props. To hide the close button,
73
+ omit `onClose` and render your own close control.
74
+
75
+ ## `touch` / `untilWidescreen` / `untilFullhd` / `{ only: true }` breakpoints
76
+
77
+ No bestax helper-prop variants exist. Use Bulma classes directly:
78
+ `className="is-hidden-touch"`, `is-flex-tablet-only`, etc. (all still exist in Bulma v1).
79
+
80
+ ## Icon children the parser couldn't read
81
+
82
+ bestax `Icon` renders from `name` + `library` (+ `variant` for Font Awesome styles):
83
+
84
+ ```tsx
85
+ <Icon name="github" library="fa" variant="brands" ariaLabel="GitHub" />
86
+ ```
87
+
88
+ For icon fonts other than Font Awesome/MDI, see the `bestax-icons` skill.
89
+
90
+ ## Dynamic values (`state={x}`, `textSize={n}`, `align={side}`, …)
91
+
92
+ The codemod only rewrites literals. Convert the expression at its source, e.g.:
93
+
94
+ ```tsx
95
+ // Before: <Button state={hovered ? 'hover' : undefined}>
96
+ <Button isHovered={hovered}>
97
+ // Before: <Block textSize={n}>
98
+ <Block textSize={String(n) as '1' | '2' | '3' | '4' | '5' | '6' | '7'}>
99
+ ```
100
+
101
+ ## Button shade colors (`black-bis`, `grey-light`, …) and `isSelected`
102
+
103
+ bestax `Button` colors are the semantic set + `text`/`ghost`. For shades use
104
+ `bgColor`/`textColor` (they accept the full palette incl. shades), and replace
105
+ `isSelected` with `className="is-selected"` inside grouped buttons.
106
+
107
+ ## `colorVariant` / Hero `gradient` / Hero `halfheight`
108
+
109
+ - `colorVariant="light"` → `isLight` where supported (Button, Notification), otherwise a
110
+ shade: `bgColor="primary-90"`.
111
+ - Bulma v1 removed `is-bold` hero gradients — delete `gradient` or restyle with CSS.
112
+ - `halfheight` has no bestax size; use `size="medium"` or a CSS height.
113
+
114
+ ## `domRef`
115
+
116
+ bestax components don't take `domRef`. Most don't forward refs either — attach the ref to
117
+ a DOM element inside, or wrap the component in a `<div ref={…}>`.
118
+
119
+ ## Helper props dropped from plain-element replacements
120
+
121
+ Where the codemod produced a plain element (`Form.Label` → `<label>`, `Breadcrumb.Item` →
122
+ `<li>`, `Table.Container` fallback `<div>`), Bulma helper props were dropped with a TODO.
123
+ Re-express them as classes: `m={2}` → `className="m-2"`, `textAlign="center"` →
124
+ `className="has-text-centered"`.