create-bestax 4.2.11 → 4.2.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/constants.js CHANGED
@@ -182,7 +182,7 @@ automatically when the task matches:
182
182
  - **bestax-layout-scaffold** — scaffold full pages (app shell, landing, centered, card grid).
183
183
  - **bestax-icons** — icons via \`Icon\`/\`IconText\`: library setup, name formats, variants, a11y.
184
184
  - **bestax-optimize** — shrink the built CSS: measure raw+gzip, then flavor switch or a modular Sass build.
185
- - **bestax-migrate** — migrate code off react-bulma-components (v4), rbx (v2) or bloomer (0.6): run the codemod, resolve its TODOs.
185
+ - **bestax-migrate** — migrate code off react-bulma-components (v4), rbx (v2), bloomer (0.6) or raw Bulma classNames: run the codemod, resolve its TODOs.
186
186
 
187
187
  Prefer the library's components and these skills over hand-written Bulma markup or custom CSS.
188
188
  Read skill \`references/\` files with absolute paths — the shell's cwd is not stable between commands.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-bestax",
3
- "version": "4.2.11",
3
+ "version": "4.2.12",
4
4
  "description": "Create a new bestax-bulma project",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: bestax-migrate
3
- description: Migrate an existing app from an unmaintained React Bulma library — react-bulma-components (v4), rbx (v2) or bloomer (0.6) — to @allxsmith/bestax-bulma on Bulma v1. Run the bestax-migrate codemod, then resolve every TODO(bestax-migrate) comment it leaves using the per-source mapping references. Use when a repo imports react-bulma-components, rbx or bloomer 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.
3
+ description: Migrate an existing React app to @allxsmith/bestax-bulma on Bulma v1, from raw Bulma CSS classes on plain JSX (className="button is-primary") or from an unmaintained React Bulma library (react-bulma-components v4, rbx v2, bloomer 0.6). Run the bestax-migrate codemod, then resolve every TODO(bestax-migrate) comment it leaves using the per-source mapping references. Use when a React app styles its markup with Bulma classes and wants bestax components instead, when a repo imports react-bulma-components, rbx or bloomer, when TODO(bestax-migrate) comments are present in a codebase, or when asked to convert Bulma classNames to bestax-bulma.
4
4
  license: MIT
5
5
  ---
6
6
 
@@ -15,11 +15,12 @@ this skill drives the codemod and finishes what it flags.
15
15
  The codemod's first argument names the library you are migrating _from_. Check the app's
16
16
  `package.json` and imports:
17
17
 
18
- | Source | Argument | References |
19
- | ----------------------------------------------------------------------------- | ------------------------ | ------------------------------------------------------------------------------------------ |
20
- | `react-bulma-components` v4 (unmaintained since 2022, Bulma 0.9.x) | `react-bulma-components` | [`references/react-bulma-components/`](references/react-bulma-components/component-map.md) |
21
- | `rbx` v2 (abandoned 2019, pins Bulma **0.7.5** plus four extensions) | `rbx` | [`references/rbx/`](references/rbx/component-map.md) |
22
- | `bloomer` 0.6 (archived 2018, Bulma 0.6 era, React 16 + `create-react-class`) | `bloomer` | [`references/bloomer/`](references/bloomer/component-map.md) |
18
+ | Source | Argument | References |
19
+ | -------------------------------------------------------------------------------- | ------------------------ | ------------------------------------------------------------------------------------------ |
20
+ | `react-bulma-components` v4 (unmaintained since 2022, Bulma 0.9.x) | `react-bulma-components` | [`references/react-bulma-components/`](references/react-bulma-components/component-map.md) |
21
+ | `rbx` v2 (abandoned 2019, pins Bulma **0.7.5** plus four extensions) | `rbx` | [`references/rbx/`](references/rbx/component-map.md) |
22
+ | `bloomer` 0.6 (archived 2018, Bulma 0.6 era, React 16 + `create-react-class`) | `bloomer` | [`references/bloomer/`](references/bloomer/component-map.md) |
23
+ | Raw Bulma classes on plain JSX (`<div className="box">`), no React Bulma library | `bulma-classes` | [`references/bulma-classes/`](references/bulma-classes/component-map.md) |
23
24
 
24
25
  Everything below is written as `<source>`; substitute the argument from that table. The
25
26
  reference paths follow the same split — `references/<source>/component-map.md`,
@@ -43,7 +44,9 @@ Run these steps in order. Don't hand-convert what the codemod converts automatic
43
44
  `@allxsmith/bestax-bulma/bestax.css`; SCSS `@import 'bulma/bulma'` + `$var` overrides
44
45
  → `@use 'bulma/sass' with (…)` plus the bestax extras) and **package.json**.
45
46
  Flags: `--css bulma|keep` for other stylesheet targets, `--no-deps` to leave
46
- package.json alone.
47
+ package.json alone. `bulma-classes` is the exception: it defaults to `--css keep`,
48
+ because the app's own Bulma already styles every class it converts, so its stylesheets
49
+ and Bulma version stay unless you pass `--css bestax` or `--css bulma`.
47
50
 
48
51
  3. **Install** — the codemod edits package.json but never runs a package manager. Resolve the
49
52
  retained imports first: a component with no bestax equivalent keeps a trimmed,
@@ -105,6 +108,15 @@ code per the references, or deliberately keep the old markup with `className` st
105
108
  become real wrapping `<Badge>` / `<Tooltip>` components. Its `as` is universal, bestax's is
106
109
  not. Because rbx pinned Bulma 0.7.5, you cross **two** Bulma majors — expect more visual
107
110
  drift than the 0.9 → 1 guide alone describes.
111
+ - **bulma-classes**: there is no library to remove. An element converts only when the bestax
112
+ component renders the same markup (tag, classes, attributes), so a converted page renders
113
+ the same HTML; everything else stays as written, with a TODO when there is something to
114
+ decide. Only static class strings convert (`clsx(...)` and ternaries get
115
+ `dynamic-class:<Target>`, naming the component the element would become), files a Next.js
116
+ App Router may render as server components are left alone (`rsc`), and the manifest gains
117
+ `@allxsmith/bestax-bulma` while the app's Bulma and stylesheets stay (the default
118
+ `--css keep`). Its rules are `kind:<name>` shaped; see
119
+ `references/bulma-classes/unmappables.md`.
108
120
  - **bloomer**: every export is a flat name and most become dotted bestax compounds
109
121
  (`CardHeaderTitle` → `Card.Header.Title`). Most of its `is*` booleans already are bestax's
110
122
  (`isActive` becomes `active` where bestax names it so; `isFullWidth` survives only on
@@ -116,8 +128,9 @@ code per the references, or deliberately keep the old markup with `className` st
116
128
 
117
129
  ## Rules
118
130
 
119
- - The codemod is idempotent on already-migrated files (it only touches files importing the
120
- source library) — safe to re-run after partial manual work.
131
+ - The codemod is safe to re-run after partial manual work: a library source only touches files
132
+ that still import the library, and `bulma-classes` skips elements that are already
133
+ components and never repeats a TODO it already wrote.
121
134
  - Don't downgrade converted props back to the old names; bestax uses `is*` booleans
122
135
  (`isLoading`), string size unions (`textSize="4"`), and `as` rather than `renderAs`.
123
136
  - If a component the app uses isn't in the component map, it wasn't part of that library's
@@ -0,0 +1,93 @@
1
+ # Bulma classes → bestax-bulma component map
2
+
3
+ For apps that style plain JSX with Bulma's classes (`<div className="columns">`), not a React
4
+ wrapper library. The codemod converts an element only when the bestax component renders
5
+ **exactly the markup the element did**: same tag, same classes, same attributes. Anything else
6
+ stays as written, with a `TODO(bestax-migrate)` when there is something to decide (see
7
+ [unmappables.md](unmappables.md)).
8
+
9
+ A class the codemod doesn't know, such as the app's own `pricing-card`, rides along in
10
+ `className`, which every bestax component passes through. So does a Bulma class with no bestax
11
+ prop. Converting `<a className="button is-primary my-cta">` gives
12
+ `<Button as="a" color="primary" className="my-cta">`, and it renders the same `<a>`.
13
+
14
+ This table mirrors `ROOTS` in `bestax-migrate/src/sources/bulma-classes/class-map.ts`, and a
15
+ test holds it to that table. Render tests hold the table to the library itself.
16
+
17
+ ## Components
18
+
19
+ The **Tags** column is what the component can render: an element on any other tag gets a
20
+ `tag:<Target>` TODO instead of a conversion.
21
+
22
+ | Bulma class | bestax-bulma | Tags |
23
+ | ---------------- | --------------- | -------------------------------------------------------------- |
24
+ | `.block` | `Block` | `<div>` only |
25
+ | `.box` | `Box` | `<div>` only |
26
+ | `.button` | `Button` | `<button>`, any tag via `as` |
27
+ | `.buttons` | `Buttons` | `<div>` only |
28
+ | `.columns` | `Columns` | `<div>` only |
29
+ | `.column` | `Column` | `<div>` only |
30
+ | `.container` | `Container` | `<div>` only |
31
+ | `.content` | `Content` | `<div>` only |
32
+ | `.delete` | `Delete` | `<button>` only |
33
+ | `.footer` | `Footer` | `<footer>`, `<div>` via `as` |
34
+ | `.hero` | `Hero` | `<section>` only |
35
+ | `.hero-head` | `Hero.Head` | `<div>` only |
36
+ | `.hero-body` | `Hero.Body` | `<div>` only |
37
+ | `.hero-foot` | `Hero.Foot` | `<div>` only |
38
+ | `.level` | `Level` | `<nav>` only |
39
+ | `.level-left` | `Level.Left` | `<div>` only |
40
+ | `.level-right` | `Level.Right` | `<div>` only |
41
+ | `.level-item` | `Level.Item` | `<div>`, `<p>`, `<a>` via `as` |
42
+ | `.media` | `Media` | `<article>`, `<div>` via `as` |
43
+ | `.media-left` | `Media.Left` | `<figure>`, `<div>` via `as` |
44
+ | `.media-content` | `Media.Content` | `<div>` only |
45
+ | `.media-right` | `Media.Right` | `<div>` only |
46
+ | `.notification` | `Notification` | `<div>` only |
47
+ | `.progress` | `Progress` | `<progress>` only |
48
+ | `.section` | `Section` | `<section>` only |
49
+ | `.subtitle` | `SubTitle` | `<h1>`, `<h2>`, `<h3>`, `<h4>`, `<h5>`, `<h6>`, `<p>` via `as` |
50
+ | `.table` | `Table` | `<table>` only |
51
+ | `.tag` | `Tag` | `<span>` only |
52
+ | `.tags` | `Tags` | `<div>` only |
53
+ | `.title` | `Title` | `<h1>`, `<h2>`, `<h3>`, `<h4>`, `<h5>`, `<h6>`, `<p>` via `as` |
54
+
55
+ An element with two of these (`<div className="column box">`) becomes the layout one
56
+ (`Column`), and the other class stays in `className`.
57
+
58
+ ## Plain tags with helper classes
59
+
60
+ A tag bestax wraps becomes that wrapper when at least one of its classes converts to a helper
61
+ prop: `<p className="has-text-centered mt-4">` → `<Paragraph textAlign="centered" mt="4">`.
62
+
63
+ | Tag | bestax-bulma |
64
+ | ---------- | --------------- |
65
+ | `<p>` | `Paragraph` |
66
+ | `<span>` | `Span` |
67
+ | `<strong>` | `Strong` |
68
+ | `<em>` | `Emphasis` |
69
+ | `<code>` | `Code` |
70
+ | `<pre>` | `Pre` |
71
+ | `<a>` | `Link` |
72
+ | `<li>` | `ListItem` |
73
+ | `<ol>` | `OrderedList` |
74
+ | `<ul>` | `UnorderedList` |
75
+ | `<figure>` | `Figure` |
76
+
77
+ bestax has no plain `<div>` wrapper, so `<div className="is-flex mt-4">` stays as it is, with
78
+ no TODO: it is valid Bulma, and nothing unsafe was skipped.
79
+
80
+ ## Families this source leaves as markup
81
+
82
+ Their markup doesn't map element by element (the bestax component renders parts of its own, or
83
+ adds attributes), so the family's outermost class gets a `family:<class>` TODO and the markup
84
+ stays. [unmappables.md](unmappables.md) has the recipe for each. The families are Breadcrumb,
85
+ Card, Checkbox, Checkboxes, Dropdown, Field (and Input, TextArea, Select, File), Grid and Cell,
86
+ Icon and IconText, Image, Menu, Message, Modal, Navbar, Pagination, Panel, Radio, Radios,
87
+ Skeleton, `.table-container` and Tabs.
88
+
89
+ ## Classes left alone
90
+
91
+ `.help`, `.label`, `.loader`, `.hero-buttons`, `.hero-video`, `.theme-dark`, `.theme-light`,
92
+ `.fa`, `.marginless` and `.paddingless` are valid Bulma with nothing in bestax to convert to.
93
+ An element carrying one stays as written, and gets no TODO.
@@ -0,0 +1,153 @@
1
+ # Bulma classes → bestax-bulma prop map
2
+
3
+ Which class becomes which prop, per component, then the helper classes every component takes.
4
+ A class that becomes no prop stays in `className`. So does a second class for a prop already
5
+ written (`is-small is-large` keeps `is-large`), so the element still renders both.
6
+
7
+ `{viewport}` is one of `mobile`, `tablet`, `desktop`, `widescreen`, `fullhd` unless a row says
8
+ otherwise, and the prop takes the matching suffix: `is-6-tablet` → `sizeTablet="6"`.
9
+
10
+ ## Component classes
11
+
12
+ ### `.button` → `Button`
13
+
14
+ | Classes | Prop |
15
+ | ------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- |
16
+ | `is-primary`, `is-link`, `is-info`, `is-success`, `is-warning`, `is-danger`, `is-white`, `is-dark`, `is-black`, `is-text`, `is-ghost` | `color` |
17
+ | `is-small`, `is-normal`, `is-medium`, `is-large` | `size` |
18
+ | `is-light` | `isLight` |
19
+ | `is-rounded`, `is-loading`, `is-static`, `is-outlined`, `is-inverted` | `isRounded`, `isLoading`, `isStatic`, `isOutlined`, `isInverted` |
20
+ | `is-focused`, `is-active`, `is-hovered` | `isFocused`, `isActive`, `isHovered` |
21
+ | `is-fullwidth` | `isFullwidth` |
22
+
23
+ `is-disabled` stays a class: `isDisabled` also writes `disabled` or `aria-disabled`, which the
24
+ element did not have. On any tag but `<button>`, bestax takes the element's `as`
25
+ (`<a className="button">` → `<Button as="a">`).
26
+
27
+ ### `.buttons` → `Buttons`, `.tags` → `Tags`
28
+
29
+ | Classes | Prop |
30
+ | -------------------------------------- | ----------------------------------- |
31
+ | `is-centered`, `is-right` (Buttons) | `isCentered`, `isRight` |
32
+ | `has-addons` | `hasAddons` |
33
+ | `are-small`, `are-medium`, `are-large` | `size` (Tags: `medium` and `large`) |
34
+
35
+ ### `.columns` → `Columns`
36
+
37
+ | Classes | Prop |
38
+ | ---------------------------------------------------------------------- | ----------------------------------------------------------------- |
39
+ | `is-centered`, `is-gapless`, `is-multiline`, `is-mobile`, `is-desktop` | `isCentered`, `isGapless`, `isMultiline`, `isMobile`, `isDesktop` |
40
+ | `is-vcentered` | `isVCentered` |
41
+ | `is-0` … `is-8` | `gap` |
42
+ | `is-0-{viewport}` … `is-8-{viewport}` | `gap{Viewport}` |
43
+
44
+ ### `.column` → `Column`
45
+
46
+ Sizes are `1` to `12`, `full`, `half`, `one-third`, `two-thirds`, `one-quarter`,
47
+ `three-quarters`, `one-fifth`, `two-fifths`, `three-fifths` and `four-fifths`.
48
+
49
+ | Classes | Prop |
50
+ | ----------------------------------------- | ------------------------------------- |
51
+ | `is-{size}` | `size` |
52
+ | `is-{size}-{viewport}` | `size{Viewport}` |
53
+ | `is-offset-{size}` (no `full`) | `offset` |
54
+ | `is-offset-{size}-{viewport}` | `offset{Viewport}` |
55
+ | `is-narrow` | `isNarrow` |
56
+ | `is-narrow-{viewport}`, `is-narrow-touch` | `isNarrow{Viewport}`, `isNarrowTouch` |
57
+
58
+ ### `.container` → `Container`
59
+
60
+ | Classes | Prop |
61
+ | ------------------------------------------------------ | ------------------------------- |
62
+ | `is-fluid`, `is-widescreen`, `is-fullhd` | `fluid`, `widescreen`, `fullhd` |
63
+ | `is-max-tablet`, `is-max-desktop`, `is-max-widescreen` | `breakpoint` and `isMax` |
64
+
65
+ ### `.title` → `Title`, `.subtitle` → `SubTitle`
66
+
67
+ | Classes | Prop |
68
+ | ------------------- | ---------------------------------------------- |
69
+ | `is-1` … `is-6` | `size`, only on the matching `<hN>` or a `<p>` |
70
+ | `is-spaced` (Title) | `isSpaced` |
71
+ | `has-skeleton` | `hasSkeleton` |
72
+
73
+ bestax picks the heading from `size` (`size="3"` renders an `<h3>`) unless `as="p"`. So on an
74
+ `<h2>`, `is-4` stays a class and the element becomes `<Title as="h2" className="is-4">`, which
75
+ renders the same `<h2>`.
76
+
77
+ ### Other components
78
+
79
+ | Component | Classes | Prop |
80
+ | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
81
+ | `.content` → `Content` | `is-small`, `is-medium`, `is-large` | `size` |
82
+ | `.delete` → `Delete` | `is-small`, `is-medium`, `is-large` | `size` |
83
+ | `.hero` → `Hero` | `is-primary`, `is-link`, `is-info`, `is-success`, `is-warning`, `is-danger`, `is-black`, `is-white`, `is-light`, `is-dark` | `color` |
84
+ | `.hero` → `Hero` | `is-small`, `is-medium`, `is-large`, `is-fullheight`, `is-fullheight-with-navbar` | `size` |
85
+ | `.level` → `Level` | `is-mobile` | `isMobile` |
86
+ | `.notification` → `Notification` | `is-primary`, `is-link`, `is-info`, `is-success`, `is-warning`, `is-danger`, `is-black`, `is-white`, `is-dark` | `color` |
87
+ | `.notification` → `Notification` | `is-light` | `isLight` |
88
+ | `.progress` → `Progress` | the ten `.hero` colors | `color` |
89
+ | `.progress` → `Progress` | `is-small`, `is-medium`, `is-large` | `size` |
90
+ | `.section` → `Section` | `is-medium`, `is-large` | `size` |
91
+ | `.table` → `Table` | `is-bordered`, `is-striped`, `is-narrow`, `is-hoverable`, `is-fullwidth` | `isBordered`, `isStriped`, `isNarrow`, `isHoverable`, `isFullwidth` |
92
+ | `.tag` → `Tag` | `is-primary`, `is-link`, `is-info`, `is-success`, `is-warning`, `is-danger`, `is-black`, `is-dark`, `is-white` | `color` |
93
+ | `.tag` → `Tag` | `is-light`, `is-rounded`, `is-hoverable` | `isLight`, `isRounded`, `isHoverable` |
94
+ | `.tag` → `Tag` | `is-medium`, `is-large` | `size` |
95
+
96
+ `Progress` takes `value` and `max` as numbers: `value="40"` becomes `value={40}`. An
97
+ expression (`value={percent}`) carries over as written, so if it holds a string the migrated
98
+ file fails to typecheck while still rendering the same; wrap it in `Number(…)`. `Delete`
99
+ converts only with `type` and `aria-label` set (see `defaults:<Target>` in the unmappables),
100
+ and a `type="button"` is dropped, since bestax renders it by itself. `.tag`'s `is-delete` stays
101
+ a class: `isDelete` turns the tag into a `<button>`.
102
+
103
+ ## Helper classes
104
+
105
+ These convert on every component above and on the plain-tag wrappers.
106
+
107
+ Colors are `primary`, `link`, `info`, `success`, `warning`, `danger`, `black`, `black-bis`,
108
+ `black-ter`, `grey-darker`, `grey-dark`, `grey`, `grey-light`, `grey-lighter`, `white`,
109
+ `white-bis`, `white-ter`, `light`, `dark`, `inherit` and `current`.
110
+
111
+ | Classes | Prop |
112
+ | --------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
113
+ | `m-{n}`, `mt-{n}`, `mr-{n}`, `mb-{n}`, `ml-{n}`, `mx-{n}`, `my-{n}` (`0` to `6`, `auto`) | `m`, `mt`, `mr`, `mb`, `ml`, `mx`, `my` |
114
+ | `p-{n}`, `pt-{n}`, `pr-{n}`, `pb-{n}`, `pl-{n}`, `px-{n}`, `py-{n}` | `p`, `pt`, `pr`, `pb`, `pl`, `px`, `py` |
115
+ | `has-text-{color}` | `textColor` (on `Table`, `color`) |
116
+ | `has-background-{color}` | `bgColor` (on `Tag`, `backgroundColor`) |
117
+ | `is-size-1` … `is-size-7`, and `-{viewport}` | `textSize`, `textSize{Viewport}` |
118
+ | `has-text-centered`, `-justified`, `-left`, `-right`, and `-{viewport}` | `textAlign`, `textAlign{Viewport}` |
119
+ | `is-capitalized`, `is-lowercase`, `is-uppercase`, `is-italic` | `textTransform` |
120
+ | `has-text-weight-light`, `-normal`, `-medium`, `-semibold`, `-bold` | `textWeight` |
121
+ | `is-family-sans-serif`, `-monospace`, `-primary`, `-secondary`, `-code` | `fontFamily` |
122
+ | `is-block`, `is-flex`, `is-inline`, `is-inline-block`, `is-inline-flex`, `is-grid` | `display` |
123
+ | the same with any of the nine viewports, `touch` and the `-only` ones included | `display{Viewport}` |
124
+ | `is-hidden`, `is-invisible`, `is-sr-only` | `visibility` |
125
+ | `is-hidden-{viewport}`, `is-invisible-{viewport}`, all nine viewports | `visibility{Viewport}` |
126
+ | `is-flex-direction-*`, `is-flex-wrap-*`, `is-justify-content-*`, `is-align-content-*`, `is-align-items-*` | `flexDirection`, `flexWrap`, `justifyContent`, `alignContent`, `alignItems` |
127
+ | `is-align-self-*`, `is-flex-grow-*`, `is-flex-shrink-*` | `alignSelf`, `flexGrow`, `flexShrink` |
128
+ | `is-pulled-left`, `is-pulled-right` | `float` |
129
+ | `is-clipped` | `overflow="clipped"` |
130
+ | `is-overlay`, `is-skeleton`, `is-clearfix`, `is-relative` | `overlay`, `skeleton`, `clearfix`, `relative` |
131
+ | `is-unselectable`, `is-clickable` | `interaction` |
132
+ | `is-radiusless`, `is-shadowless` | `radius`, `shadow` |
133
+ | `is-mobile`, `is-narrow` (where the component has no prop of its own for them) | `responsive` |
134
+
135
+ Where a component renders a color class through no typed prop, the class stays: `has-text-*`
136
+ on `Hero`, `Progress`, `Tag` and `Tags`; `has-background-*` on `Notification`, `Progress`,
137
+ `Table` and `Tags`.
138
+
139
+ Some classes stay put because of how bestax renders them:
140
+
141
+ - A base `display` class next to a per-viewport one (`is-flex is-block-mobile`) keeps the base
142
+ class: bestax drops the base `display` whenever a per-viewport one is set.
143
+ - The flex-container classes (`is-justify-content-*` and the others in that row) convert only
144
+ beside a flex `display` prop, the only place bestax renders them.
145
+ - `is-hidden` becomes `visibility="hidden"`, which renders the same class and doesn't interact
146
+ with `display`.
147
+
148
+ ## Classes that stay classes
149
+
150
+ Color shades (`has-text-primary-65`), the `-touch` and `-only` breakpoints of text size and
151
+ alignment, Grid and `.image` modifiers, and the Bulma helpers with no bestax prop
152
+ (`is-display-*`, `is-overflow-*`, `is-position-*`, `is-float-*`, `has-radius-*`, …) stay in
153
+ `className`. They render exactly as before.
@@ -0,0 +1,170 @@
1
+ # Bulma classes → bestax-bulma: what the codemod leaves for you
2
+
3
+ Every `TODO(bestax-migrate)` this source writes, by rule, with what to do about it. The markup
4
+ under a TODO is exactly as it was, so the app still renders the same while you work through
5
+ them. The rule after the colon names a Bulma class, a bestax component or prop, or an
6
+ attribute, never one of your own classes.
7
+
8
+ ## An element it would not convert
9
+
10
+ ### `spread:<Target>`
11
+
12
+ The element spreads props (`<div className="box" {...rest}>`). A spread can carry anything,
13
+ and bestax reads some names as its own props: a spread `className` merges with the component's
14
+ classes, where on the plain element it replaced them. Convert by hand once you know what the
15
+ spread carries, or leave it.
16
+
17
+ ### `ref:<Target>`
18
+
19
+ The element has a `ref`, and the bestax component doesn't forward one, so the ref would stop
20
+ reaching the DOM node. Only `Button` and `Link` forward refs among the components this source
21
+ converts. Keep the element as markup.
22
+
23
+ ### `tag:<Target>`
24
+
25
+ bestax renders that component on a fixed tag, or a short list of them through `as` (see the
26
+ **Tags** column in [component-map.md](component-map.md)), and this element is on another one:
27
+ `<div className="section">`, `<p className="notification">`. Changing the tag changes the
28
+ markup, so decide whether you want it; if you do, change it and re-run.
29
+
30
+ ### `attr:<prop>`
31
+
32
+ An attribute on the element is also a prop of the bestax component, which would read it
33
+ differently: `<div className="box" color="red">` would lose its `color` attribute to Box's text
34
+ color. Rename or drop the attribute, then re-run.
35
+
36
+ It also covers an attribute the component's props type rejects. `Delete` takes no `type`
37
+ (`type="button"` is the one value that converts, because `Delete` renders it anyway), and
38
+ `Progress` types `value` and `max` as numbers, so `value="half"` stays. A number converts only
39
+ when it is spelled the way it renders (`value="40"`, not `value="040"`).
40
+
41
+ `attr:dangerouslySetInnerHTML` is the same kind of refusal: the element sets its own content,
42
+ and some bestax components render content of their own beside `children`, which React
43
+ rejects. Keep the element as markup.
44
+
45
+ ### `defaults:<Target>`
46
+
47
+ The component renders attributes of its own when the element doesn't set them. `Delete`
48
+ renders `type="button"` and `aria-label="Close"`. On a bare `<button className="delete">`,
49
+ converting would add both, changing a submit button inside a form into a plain button. Add the
50
+ attributes you want (usually both, with a real label), then re-run.
51
+
52
+ ### `drops:<Target>`
53
+
54
+ The component drops an attribute on this tag. Most of these do nothing there anyway: `Button`
55
+ drops `href`, `target` and `rel` on a `<button>`, and `Level.Item` keeps link attributes only
56
+ on an `<a>`. Remove the attribute, then re-run.
57
+
58
+ `disabled` is the exception. `Button` drops it on a tag with no disabled state
59
+ (`<a className="button" disabled>`), but Bulma greys out a disabled `.button` on any tag, so
60
+ dropping it would change how the element looks. Keep that element as markup.
61
+
62
+ ### `children:<Target>`
63
+
64
+ The component's props type requires children, and the element has none (`Buttons`). An empty
65
+ `.buttons` does nothing; delete it or give it buttons.
66
+
67
+ ### `only-child:<Target>`
68
+
69
+ The element is the only child of another component (`<Link href="/x"><a className="button">`),
70
+ which may reach into it with `cloneElement`: next/link's legacy behavior, a tooltip, a Radix
71
+ `asChild` trigger. A bestax component would not take those props or that ref the same way.
72
+ Convert it by hand if the parent only renders its children.
73
+
74
+ ### `dynamic-class:<Target>`
75
+
76
+ The `className` is computed (`clsx(...)`, a ternary, a template with expressions), and with
77
+ its classes written out the element would become bestax `<Target>`. The codemod converts
78
+ static strings only. Convert by hand with the [prop map](prop-map.md), turning each condition
79
+ into the prop:
80
+
81
+ ```tsx
82
+ // before
83
+ <button className={clsx('button', busy && 'is-loading')}>Save</button>
84
+ // after
85
+ <Button isLoading={busy}>Save</Button>
86
+ ```
87
+
88
+ The classes in a computed `className` still count for every other rule: a `clsx('box')` on a
89
+ `<span>` gets `tag:Box`, and a `clsx('card', …)` gets `family:card`.
90
+
91
+ ## A family it leaves as markup: `family:<class>`
92
+
93
+ The bestax component renders parts of its own, or adds attributes, so a one-element-at-a-time
94
+ conversion would change the markup. Convert the whole family by hand, and look at the result
95
+ in the browser:
96
+
97
+ - **`family:card`**: `Card` wraps any child that is not one of its parts in `.card-content`.
98
+ Use its parts, `Card.Header` (with `Card.Header.Title` and `Card.Header.Icon`),
99
+ `Card.Image`, `Card.Content`, `Card.Footer` and `Card.FooterItem`, together.
100
+ - **`family:navbar`**: `Navbar` adds `role="navigation"` and an `aria-label`, and
101
+ `Navbar.Burger` renders its own three spans. Its parts are `Navbar.Brand`, `Navbar.Item`,
102
+ `Navbar.Link`, `Navbar.Burger`, `Navbar.Menu`, `Navbar.Start`, `Navbar.End`,
103
+ `Navbar.Dropdown`, `Navbar.DropdownMenu` and `Navbar.Divider`.
104
+ - **`family:field`**, **`family:input`**, **`family:textarea`**, **`family:select`**,
105
+ **`family:file`**: bestax's form controls render their own `.field` and `.control` wrappers
106
+ (and `File` its whole `.file-label` tree). Replace the whole `.field` block with the
107
+ control, not each element in it. See the `bestax-form` skill.
108
+ - **`family:checkbox`**, **`family:radio`**, **`family:checkboxes`**, **`family:radios`**:
109
+ bestax renders its own styled checkbox and radio markup, not Bulma's.
110
+ - **`family:modal`**: `Modal` renders its own background and content parts, and adds dialog
111
+ attributes. Rebuild it with `Modal` and its parts, and drive it with its open prop.
112
+ - **`family:dropdown`**: `Dropdown` renders its own trigger and menu from props.
113
+ - **`family:icon`**, **`family:icon-text`**: `Icon` renders its own `<i>` and adds an
114
+ `aria-label`. See the `bestax-icons` skill for its library and name props.
115
+ - **`family:image`**: `Image` renders its own `<img>`.
116
+ - **`family:menu`**: `Menu.Item` renders the `<li>` and the `<a>` together.
117
+ - **`family:message`**: `Message` always wraps its children in `.message-body`.
118
+ - **`family:pagination`**, **`family:panel`**, **`family:tabs`**, **`family:breadcrumb`**:
119
+ each renders list items, links or roles of its own. Rebuild them from the component's docs.
120
+ - **`family:grid`**, **`family:cell`**, **`family:fixed-grid`**: this source leaves Grid markup
121
+ as written. `Grid` and `Cell` convert by hand; `Grid isFixed` renders the `.fixed-grid`
122
+ wrapper itself.
123
+ - **`family:table-container`**: bestax renders `.table-container` from `Table isResponsive`.
124
+ - **`family:skeleton-block`**, **`family:skeleton-lines`**: `Skeleton` renders its own markup.
125
+
126
+ ## A class Bulma v1 removed: `legacy:<class>`
127
+
128
+ `legacy:tile`: Bulma v1 has no tiles. Rebuild the layout with `Grid` and `Cell`; the Bulma
129
+ 0.9 to 1 guide shows the translation. Until then the element has no styles at all under
130
+ Bulma v1.
131
+
132
+ ## A whole file it left alone
133
+
134
+ These come only when the file has an element the codemod would convert (a computed className
135
+ counts), so a re-run after the fix has something to do. A non-React file gets `jsx-runtime`
136
+ alone: every other TODO names a React component to use.
137
+
138
+ - **`rsc`**: the file is in a Next.js App Router project (a package with `next` and an
139
+ `app/` directory) and has no `'use client'`, so it may render as a server component, and
140
+ bestax's components are client components. That covers files outside `app/` too: a
141
+ component under `components/` is a server component when a server page renders it. Files
142
+ under `pages/` are always client code and convert. Add `'use client'` if the file can be a
143
+ client module (no `async` component, no server-only calls), then re-run.
144
+ - **`styled-jsx`**: the component scopes its styles with `<style jsx>`, which adds its scoping
145
+ class to plain elements and not to an imported component, so a converted element would lose
146
+ its styles. Move those
147
+ styles out of `<style jsx>`, or scope them with `:global()`, then re-run.
148
+ - **`imports`**: the file is CommonJS (`require` or `module.exports`, no ES `import` or
149
+ `export`), and the codemod adds an ES `import`. Move the file to ES modules, then re-run.
150
+ - **`jsx-runtime`**: the file's JSX isn't React's: a `@jsx` pragma or `@jsxImportSource` naming
151
+ another runtime (Preact, Solid), or a package that sets one in its tsconfig or depends on one
152
+ instead of React. bestax-bulma components are React components.
153
+
154
+ ## Things that get no TODO
155
+
156
+ - Helper classes on a `<div>` (`<div className="is-flex mt-4">`): bestax has no plain `<div>`
157
+ wrapper, and the classes are valid Bulma, so the element stays.
158
+ - `.help`, `.label`, `.loader` and the other classes in the component map's "left alone" list.
159
+ - A class with no bestax prop on a converted element: it stays in `className`.
160
+
161
+ ## After the codemod
162
+
163
+ Class order changes on converted elements (bestax writes its own classes first), so snapshot
164
+ tests that compare class strings will churn while the rendered page stays the same. Update the
165
+ snapshots after reviewing the diff.
166
+
167
+ If the build runs PurgeCSS, the report says so: a converted element's classes now come from
168
+ bestax's code, some of them built from props at runtime (`mt="4"` renders `mt-4`), so the
169
+ PurgeCSS config has to scan bestax's dist and safelist those patterns. The docs' optimizing CSS
170
+ guide has the config.
@@ -8,7 +8,14 @@ stylesheet layer; this reference explains what it did and how to finish what it
8
8
  Coming from rbx or bloomer you are crossing **two** Bulma majors rather than one, so expect more
9
9
  visual drift than the 0.9 → 1 notes below describe on their own.
10
10
 
11
- ## What the codemod already did (default `--css bestax`)
11
+ An app that writes Bulma's classes directly (`bulma-classes`) keeps its stylesheet by
12
+ default: that source runs as `--css keep`, because the app's own Bulma already styles every
13
+ class a converted element renders, so its stylesheet imports, Sass and Bulma version stay as
14
+ they were. Moving to Bulma v1 is a separate step, taken with `--css bestax` or `--css bulma`.
15
+ From a 0.9.x it then follows these notes as written; on Bulma v1 already, only the bundle
16
+ choice below applies.
17
+
18
+ ## What the codemod already did (`--css bestax`, the library sources' default)
12
19
 
13
20
  - **CSS imports**: `bulma/css/bulma(.min).css` and v3-era
14
21
  the source library's own CSS imports (`react-bulma-components/dist/*.css`,