create-bestax 4.2.6 → 4.2.7

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) or rbx (v2): run the codemod, resolve its TODOs.
185
+ - **bestax-migrate** — migrate code off react-bulma-components (v4), rbx (v2) or bloomer (0.6): 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.6",
3
+ "version": "4.2.7",
4
4
  "description": "Create a new bestax-bulma project",
5
5
  "type": "module",
6
6
  "bin": {
@@ -38,7 +38,8 @@
38
38
  "commander": "^15.0.0",
39
39
  "figures": "^6.1.0",
40
40
  "fs-extra": "^11.4.0",
41
- "prompts": "^2.4.2"
41
+ "prompts": "^2.4.2",
42
+ "@allxsmith/bestax-bulma": "^5.15.0"
42
43
  },
43
44
  "devDependencies": {
44
45
  "@jest/globals": "^30.0.0",
@@ -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) or rbx (v2) — 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 or rbx 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 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.
4
4
  license: MIT
5
5
  ---
6
6
 
@@ -15,10 +15,11 @@ 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) |
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) |
22
23
 
23
24
  Everything below is written as `<source>`; substitute the argument from that table. The
24
25
  reference paths follow the same split — `references/<source>/component-map.md`,
@@ -44,7 +45,10 @@ Run these steps in order. Don't hand-convert what the codemod converts automatic
44
45
  Flags: `--css bulma|keep` for other stylesheet targets, `--no-deps` to leave
45
46
  package.json alone.
46
47
 
47
- 3. **Install** — the codemod edits package.json but never runs a package manager:
48
+ 3. **Install** — the codemod edits package.json but never runs a package manager. Resolve the
49
+ retained imports first: a component with no bestax equivalent keeps a trimmed,
50
+ TODO-annotated import of the source library, which the manifest step has just removed — so a
51
+ clean install leaves those unresolvable. The report names them in a `deps` entry.
48
52
 
49
53
  ```sh
50
54
  npm install # or pnpm/yarn
@@ -59,8 +63,8 @@ Run these steps in order. Don't hand-convert what the codemod converts automatic
59
63
  documented in the per-source `references/` pages.
60
64
 
61
65
  The report's `peer-deps` entries predict install failures: bestax-bulma needs
62
- **React 18/19** (react-bulma-components also ran on 17, and rbx peer-depended on
63
- **React 16** — upgrade react/react-dom first) and its optional Font Awesome peer wants
66
+ **React 18/19** (react-bulma-components also ran on 17, while rbx and bloomer peer-depended
67
+ on **React 16** — upgrade react/react-dom first) and its optional Font Awesome peer wants
64
68
  **FA ≥ 6.7** (an app pinned to FA 5 either upgrades or installs with
65
69
  `npm install --legacy-peer-deps`).
66
70
 
@@ -101,6 +105,14 @@ code per the references, or deliberately keep the old markup with `className` st
101
105
  become real wrapping `<Badge>` / `<Tooltip>` components. Its `as` is universal, bestax's is
102
106
  not. Because rbx pinned Bulma 0.7.5, you cross **two** Bulma majors — expect more visual
103
107
  drift than the 0.9 → 1 guide alone describes.
108
+ - **bloomer**: every export is a flat name and most become dotted bestax compounds
109
+ (`CardHeaderTitle` → `Card.Header.Title`). Most of its `is*` booleans already are bestax's
110
+ (`isActive` becomes `active` where bestax names it so; `isFullWidth` survives only on
111
+ Button, Select, Table and Tabs); the work is in `isSize`/`isColor`/`isAlign` (renamed per component), the `isDisplay`/`isHidden`
112
+ helpers (flattened, arrays and objects included), `tag` (→ `as` where bestax has one) and
113
+ `render` (always a TODO). Its icons are className-based and Font Awesome 4 — the biggest
114
+ visual risk, see `references/bloomer/unmappables.md`. The app declared its own Bulma 0.6,
115
+ which the codemod bumps; there is no pinned Bulma to free.
104
116
 
105
117
  ## Rules
106
118
 
@@ -0,0 +1,159 @@
1
+ # bloomer → bestax-bulma component map
2
+
3
+ Every bloomer export. bloomer's exports are all _flat_ names, while bestax groups the same
4
+ components into dotted compounds — so most rows here rename a flat identifier onto a
5
+ `Parent.Child` target, and the codemod imports the parent. `structural` means the codemod
6
+ rewrites the element's shape rather than renaming it (see [unmappables.md](unmappables.md) for
7
+ what each one produces). A `todo` row has no bestax counterpart — the codemod keeps the bloomer
8
+ import, annotated, so the app still runs while you convert it.
9
+
10
+ This table mirrors `MAPPING` in `bestax-migrate/src/sources/bloomer/mapping.ts`, which a
11
+ coverage test holds to bloomer's own export surface (108 exports, vendored from its
12
+ `src/index.ts`) in both directions.
13
+
14
+ | bloomer | bestax-bulma | status |
15
+ | ---------------------- | --------------------- | ------- |
16
+ | `Box` | `Box` | mapped |
17
+ | `Breadcrumb` | `Breadcrumb` | mapped |
18
+ | `BreadcrumbItem` | _structural_ | mapped |
19
+ | `Button` | `Button` | mapped |
20
+ | `Card` | `Card` | mapped |
21
+ | `CardContent` | `Card.Content` | mapped |
22
+ | `CardFooter` | `Card.Footer` | mapped |
23
+ | `CardFooterItem` | `Card.FooterItem` | mapped |
24
+ | `CardHeader` | `Card.Header` | mapped |
25
+ | `CardHeaderIcon` | `Card.Header.Icon` | mapped |
26
+ | `CardHeaderTitle` | `Card.Header.Title` | mapped |
27
+ | `CardImage` | `Card.Image` | mapped |
28
+ | `Checkbox` | `Checkbox` | mapped |
29
+ | `Column` | `Column` | mapped |
30
+ | `Columns` | `Columns` | mapped |
31
+ | `Container` | `Container` | mapped |
32
+ | `Content` | `Content` | mapped |
33
+ | `Control` | `Control` | mapped |
34
+ | `Delete` | `Delete` | mapped |
35
+ | `Dropdown` | `Dropdown` | partial |
36
+ | `DropdownContent` | — _(see unmappables)_ | todo |
37
+ | `DropdownDivider` | `Dropdown.Divider` | mapped |
38
+ | `DropdownItem` | `Dropdown.Item` | mapped |
39
+ | `DropdownMenu` | — _(see unmappables)_ | todo |
40
+ | `DropdownTrigger` | — _(see unmappables)_ | todo |
41
+ | `Field` | `Field` | mapped |
42
+ | `FieldBody` | `Field.Body` | mapped |
43
+ | `FieldLabel` | `Field.Label` | mapped |
44
+ | `Footer` | `Footer` | mapped |
45
+ | `Heading` | _structural_ | partial |
46
+ | `Help` | _structural_ | mapped |
47
+ | `Hero` | `Hero` | mapped |
48
+ | `HeroBody` | `Hero.Body` | mapped |
49
+ | `HeroFooter` | `Hero.Foot` | mapped |
50
+ | `HeroHeader` | `Hero.Head` | mapped |
51
+ | `HeroVideo` | _structural_ | mapped |
52
+ | `Icon` | `Icon` | partial |
53
+ | `Image` | `Image` | mapped |
54
+ | `Input` | `InputBase` | mapped |
55
+ | `Label` | _structural_ | mapped |
56
+ | `Level` | `Level` | mapped |
57
+ | `LevelItem` | `Level.Item` | mapped |
58
+ | `LevelLeft` | `Level.Left` | mapped |
59
+ | `LevelRight` | `Level.Right` | mapped |
60
+ | `Media` | `Media` | mapped |
61
+ | `MediaContent` | `Media.Content` | mapped |
62
+ | `MediaLeft` | `Media.Left` | mapped |
63
+ | `MediaRight` | `Media.Right` | mapped |
64
+ | `Menu` | `Menu` | mapped |
65
+ | `MenuLabel` | `Menu.Label` | mapped |
66
+ | `MenuLink` | `Menu.Item` | mapped |
67
+ | `MenuList` | `Menu.List` | mapped |
68
+ | `Message` | `Message` | mapped |
69
+ | `MessageBody` | `Message.Body` | mapped |
70
+ | `MessageHeader` | `Message.Header` | mapped |
71
+ | `Modal` | `Modal` | partial |
72
+ | `ModalBackground` | `Modal.Background` | mapped |
73
+ | `ModalCard` | `Modal.Card` | mapped |
74
+ | `ModalCardBody` | `Modal.Card.Body` | mapped |
75
+ | `ModalCardFooter` | `Modal.Card.Foot` | mapped |
76
+ | `ModalCardHeader` | `Modal.Card.Head` | mapped |
77
+ | `ModalCardTitle` | `Modal.Card.Title` | mapped |
78
+ | `ModalClose` | `Modal.Close` | mapped |
79
+ | `ModalContent` | `Modal.Content` | mapped |
80
+ | `Nav` | — _(see unmappables)_ | todo |
81
+ | `NavCenter` | — _(see unmappables)_ | todo |
82
+ | `NavItem` | — _(see unmappables)_ | todo |
83
+ | `NavLeft` | — _(see unmappables)_ | todo |
84
+ | `NavRight` | — _(see unmappables)_ | todo |
85
+ | `NavToggle` | — _(see unmappables)_ | todo |
86
+ | `Navbar` | `Navbar` | mapped |
87
+ | `NavbarBrand` | `Navbar.Brand` | mapped |
88
+ | `NavbarBurger` | `Navbar.Burger` | mapped |
89
+ | `NavbarDivider` | `Navbar.Divider` | mapped |
90
+ | `NavbarDropdown` | _structural_ | mapped |
91
+ | `NavbarEnd` | `Navbar.End` | mapped |
92
+ | `NavbarItem` | _structural_ | mapped |
93
+ | `NavbarLink` | `Navbar.Link` | mapped |
94
+ | `NavbarMenu` | `Navbar.Menu` | mapped |
95
+ | `NavbarStart` | `Navbar.Start` | mapped |
96
+ | `Notification` | `Notification` | mapped |
97
+ | `Page` | _structural_ | mapped |
98
+ | `PageControl` | _structural_ | mapped |
99
+ | `PageEllipsis` | `Pagination.Ellipsis` | mapped |
100
+ | `PageLink` | `Pagination.Link` | mapped |
101
+ | `PageList` | `Pagination.List` | mapped |
102
+ | `Pagination` | `Pagination` | mapped |
103
+ | `Panel` | `Panel` | mapped |
104
+ | `PanelBlock` | `Panel.Block` | mapped |
105
+ | `PanelHeading` | `Panel.Heading` | mapped |
106
+ | `PanelIcon` | `Panel.Icon` | partial |
107
+ | `PanelTab` | _structural_ | mapped |
108
+ | `PanelTabs` | `Panel.Tabs` | mapped |
109
+ | `Progress` | `Progress` | mapped |
110
+ | `Radio` | `Radio` | mapped |
111
+ | `Section` | `Section` | mapped |
112
+ | `Select` | `SelectBase` | mapped |
113
+ | `Subtitle` | `SubTitle` | mapped |
114
+ | `Tab` | `Tabs.Item` | mapped |
115
+ | `TabLink` | _structural_ | mapped |
116
+ | `TabList` | `Tabs.List` | mapped |
117
+ | `Table` | `Table` | mapped |
118
+ | `Tabs` | `Tabs` | mapped |
119
+ | `Tag` | `Tag` | mapped |
120
+ | `TextArea` | `TextAreaBase` | mapped |
121
+ | `Tile` | — _(see unmappables)_ | todo |
122
+ | `Title` | `Title` | mapped |
123
+ | `withHelpersModifiers` | — _(see unmappables)_ | todo |
124
+
125
+ ## The renames worth memorising
126
+
127
+ The flat-to-dotted pattern is regular — `CardHeaderTitle` → `Card.Header.Title`,
128
+ `ModalCardBody` → `Modal.Card.Body`, `NavbarBurger` → `Navbar.Burger` — with a handful of names
129
+ that change along the way:
130
+
131
+ | bloomer | bestax-bulma | why |
132
+ | ----------------- | --------------------- | ----------------------------------------------------------- |
133
+ | `Subtitle` | `SubTitle` | bestax's casing |
134
+ | `HeroHeader` | `Hero.Head` | bestax follows Bulma's `hero-head` / `hero-foot` |
135
+ | `HeroFooter` | `Hero.Foot` | |
136
+ | `ModalCardHeader` | `Modal.Card.Head` | same, for `modal-card-head` / `modal-card-foot` |
137
+ | `ModalCardFooter` | `Modal.Card.Foot` | |
138
+ | `CardFooterItem` | `Card.FooterItem` | one component in bestax, not a child of `Card.Footer` |
139
+ | `MenuLink` | `Menu.Item` | bestax's item renders the `<a>` |
140
+ | `FieldLabel` | `Field.Label` | and `FieldBody` → `Field.Body` |
141
+ | `Tab` | `Tabs.Item` | the plain `<li>`; bestax's `Tabs.Tab` is the controlled API |
142
+ | `PageLink` | `Pagination.Link` | `isCurrent` becomes `active` |
143
+ | `NavbarDropdown` | `Navbar.DropdownMenu` | bestax's `Navbar.Dropdown` is the container — see below |
144
+
145
+ ## Value-chosen targets
146
+
147
+ Some targets depend on a prop or a child, so the codemod picks them element by element:
148
+
149
+ | bloomer | becomes | decided by |
150
+ | ---------------------------------------------------- | ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------- |
151
+ | `PageControl` | `Pagination.Previous` / `Pagination.Next` | `isNext` (bloomer's default is previous) |
152
+ | `NavbarItem` | `Navbar.Item` / `Navbar.Dropdown` | `hasDropdown` |
153
+ | `Page` | _folded into its child_ / `<li>` | whether the child is a `PageLink`/`PageEllipsis`; attributes on the Page move onto the link, with a `component:Page` note |
154
+ | `PanelBlock` | `Panel.Block` / `<div class="panel-block">` | `href` — bestax's block is always an `<a>` |
155
+ | `MenuLink` in a literal `<li>` | `Menu.Item`, the `<li>` folded away | bestax's item renders its own `<li>` |
156
+ | `Breadcrumb` around a literal `<ul>` | `Breadcrumb`, the `<ul>` folded away | bestax's breadcrumb renders its own `<ul>` |
157
+ | `Icon`, `PanelIcon` | `name`/`library`/`variant` / an `<i>` child | whether the icon classes are FA5/6 or MDI |
158
+ | `Help`, `Label`, `Heading` | `<p class="help">`, `<label class="label">`, `<p class="heading">` | always plain markup |
159
+ | `BreadcrumbItem`, `PanelTab`, `TabLink`, `HeroVideo` | `<li>`, `<a>`, `<a>`, `<div class="hero-video">` | always plain markup |
@@ -0,0 +1,135 @@
1
+ # bloomer → bestax-bulma prop map
2
+
3
+ Most of bloomer's boolean modifiers are already bestax's names — `isLoading`, `isOutlined`,
4
+ `isInverted`, `isStatic`, `isHovered`, `isFocused`, `isBordered`, `isStriped`, `isNarrow`,
5
+ `isMultiline`, `isVCentered`, `isMobile`, … pass through untouched. The exceptions are in
6
+ the tables below: `isActive` becomes `active` on the components whose bestax counterpart
7
+ names it that way, `isFullWidth` survives only where bestax declares it, and a few
8
+ (`Input isActive`, `NavbarLink isActive`, `PageLink isActive`) have no counterpart and become
9
+ the Bulma class in `className` instead (see the end of this page). What else changes is the value-carrying props, the helper props every component
10
+ inherited from `withHelpersModifiers`, and the two props bestax spells differently on every
11
+ component.
12
+
13
+ ## Universal helper props
14
+
15
+ bloomer's `withHelpersModifiers` mixed these into every component.
16
+
17
+ | bloomer | bestax-bulma | note |
18
+ | --------------------------- | -------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
19
+ | `hasTextAlign="centered"` | `textAlign="centered"` | `left` / `right` / `centered` — same union |
20
+ | `hasTextColor="grey-light"` | `textColor="grey-light"`, or `className="has-text-grey-light"` | `textColor` is declared per component, not by the helper hook, so it carries over on the ~48 targets that have it and becomes the Bulma class on the rest (`Tag`, `Table`, `Hero`, `Menu`, `Breadcrumb`, `Panel`, `Icon`, `Progress`, the form controls); every Bulma 0.6 colour and shade works but `white-ter`/`white-bis` |
21
+ | `isPulled="right"` | `float="right"` | |
22
+ | `isClearfix` | `clearfix` | |
23
+ | `isOverlay` | `overlay` | |
24
+ | `isUnselectable` | `interaction="unselectable"` | |
25
+ | `isMarginless` | `m="0"` | bestax expresses the `is-*less` helpers as spacing |
26
+ | `isPaddingless` | `p="0"` | |
27
+ | `isFullWidth` | `isFullWidth` | on Button, Select, Table, Tabs; a TODO elsewhere |
28
+ | `isDisplay`, `isHidden` | `display*`, `visibility*` | flattened — see below |
29
+ | `tag` | `as` | where bestax declares one — see below |
30
+ | `render` | — | always a TODO |
31
+
32
+ ## `isDisplay` and `isHidden`
33
+
34
+ Both take three shapes in bloomer; all three flatten onto bestax's per-viewport props. bestax
35
+ declares every Bulma viewport, including `touch` and the `-only` ones, so nothing is lost:
36
+
37
+ | bloomer | bestax-bulma |
38
+ | -------------------------------------------------------------- | ------------------------------------------------------------- |
39
+ | `isDisplay="flex"` | `display="flex"` |
40
+ | `isDisplay="flex-tablet-only"` | `displayTabletOnly="flex"` |
41
+ | `isDisplay={['inline-block', 'flex-desktop']}` | `display="inline-block" displayDesktop="flex"` |
42
+ | `isDisplay={{ flex: ['default', 'tablet'], block: 'mobile' }}` | `display="flex" displayTablet="flex" displayMobile="block"` |
43
+ | `isHidden` | `visibility="hidden"` |
44
+ | `isHidden="touch"` | `visibilityTouch="hidden"` |
45
+ | `isHidden={['mobile', 'widescreen-only']}` | `visibilityMobile="hidden" visibilityWidescreenOnly="hidden"` |
46
+
47
+ Two entries that land on the same prop, a dynamic value, or a viewport bestax does not know get
48
+ a TODO; the bloomer prop is always removed, because bestax has no `isDisplay`/`isHidden` and a
49
+ leftover would be a type error rather than a no-op.
50
+
51
+ ## Value props
52
+
53
+ | bloomer | bestax-bulma |
54
+ | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
55
+ | `isColor="primary"` | `color="primary"` (every component that had it) |
56
+ | `isSize="large"` | `size="large"` — Button, Content, Delete, Icon, Input, Progress, Section, Select, Tag, TextArea, Breadcrumb, Pagination, Tabs, Field.Label, Modal.Close |
57
+ | `Title isSize={3}` | `size={3}` — bestax accepts the numbers 1–6 |
58
+ | `Subtitle isSize={4}` | `SubTitle size={4} as="h2"` — bloomer's default was an `<h2>`, bestax's is an `<h1>`, so the level is kept |
59
+ | `Image isSize="128x128"` | `size="128x128"` |
60
+ | `Image isRatio="16:9"` | `size="16by9"` (`square`→`square`, `1:1`→`1by1`, `4:3`→`4by3`, `3:2`→`3by2`, `2:1`→`2by1`) |
61
+ | `Breadcrumb isAlign` | `alignment` |
62
+ | `Breadcrumb hasSeparator` | `separator` |
63
+ | `Tabs isAlign` | `align`; `isBoxed` → `boxed`, `isToggle` → `toggle` |
64
+ | `Pagination isAlign` | `align` (`"left"` is the default and is dropped) |
65
+ | `Dropdown isAlign="right"` | `right`; `isHoverable` → `hoverable` |
66
+ | `Icon isAlign="left"` | `className="is-left"` (bestax's Icon has no align prop) |
67
+ | `Icon className="fas fa-spinner fa-spin"` | `name="spinner" library="fa" variant="solid" features="fa-spin"` — modifier classes become `features` |
68
+ | `PanelIcon className="fas fa-book"` | `Panel.Icon name="book" library="fa" variant="solid"` — same className API as `Icon` |
69
+ | `Button isLink` | `color="link"` (a TODO if `isColor` is also set) |
70
+ | `Hero isFullHeight` | `size="fullheight"` |
71
+ | `Container isFluid` | `fluid` |
72
+ | `Navbar isTransparent` | `transparent` |
73
+ | `Field isGrouped`, `isHorizontal` | `grouped` (same `boolean \| 'centered' \| 'right'`), `horizontal` |
74
+ | `FieldLabel isNormal` | `size="normal"` |
75
+ | `Control hasIcons` | `hasIconsLeft` / `hasIconsRight` (`true` sets both; an array sets each) |
76
+ | `PageLink isCurrent` | `active` |
77
+ | `isActive` on Dropdown, DropdownItem, MenuLink, Modal, NavbarBurger, NavbarMenu, NavbarItem, PanelBlock, Tab | `active` |
78
+ | `Input`, `Select`, `TextArea` | `InputBase`, `SelectBase`, `TextAreaBase` — bloomer's were bare elements; bestax's `Input`/`Select`/`TextArea` wrap themselves in `Field` and `Control`, so the bare `*Base` exports are the faithful targets and your existing `Field`/`Control` markup stays as written |
79
+
80
+ ## Column sizes
81
+
82
+ | bloomer | bestax-bulma |
83
+ | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
84
+ | `isSize={4} isOffset={2}` | `size={4} offset={2}` |
85
+ | `isSize="1/2"` | `size="half"` (`1/3`→`one-third`, `1/4`→`one-quarter`, `2/3`→`two-thirds`, `3/4`→`three-quarters`, `full`→`full`) |
86
+ | `isSize="narrow"` | `isNarrow` |
87
+ | `isSize={{ default: 'full', mobile: 8, tablet: '2/3' }}` | `size="full" sizeMobile={8} sizeTablet="two-thirds"` |
88
+ | `isSize={{ touch: 'narrow' }}` | `isNarrowTouch` — bestax has `isNarrowTouch` but no `sizeTouch`/`offsetTouch`, which become TODOs |
89
+
90
+ ## `tag` → `as`
91
+
92
+ bloomer put `tag` on nearly every component; bestax declares `as` on a subset, several of them
93
+ narrowed to a literal union, so a value outside the union is a type error you can see rather
94
+ than a silent rewrite. The components whose `tag` becomes `as`:
95
+
96
+ `Button`, `Image`, `Title`, `Subtitle`, `Footer`, `Media`, `MediaLeft`, `LevelItem`, `Control`,
97
+ `DropdownItem`,
98
+ `MenuLink`, `NavbarItem`, `NavbarLink`.
99
+
100
+ Everywhere else `tag` is left in place with a TODO. On the components that become plain markup
101
+ (`Help`, `Label`, `Heading`, `BreadcrumbItem`, `PanelTab`, `TabLink`, `Page`, `HeroVideo`) a
102
+ literal `tag` is honoured — `<Help tag="span">` becomes `<span className="help">`.
103
+
104
+ bloomer's `Button` and `Image` never took `tag` at all. Seven bloomer components — `Button`,
105
+ `Delete`, `LevelItem`, `DropdownItem`, `NavbarItem`, `PanelBlock`, `CardFooterItem` — rendered
106
+ an `<a>` whenever `href` was set, whatever `tag` said, and a `<div>` (or their default tag)
107
+ otherwise; the rest (`MenuLink`, `PageControl`, `Dropdown`, …) rendered their `tag` regardless.
108
+ The codemod keeps that: `Button` and `LevelItem` gain `as="a"` beside a literal `href`; a `tag`
109
+ next to a literal `href` is dropped on the switching targets that already render an anchor
110
+ (`Navbar.Item`, `Dropdown.Item`, `Panel.Block`); a `NavbarItem` or `DropdownItem` with neither
111
+ `href` nor `tag` gains `as="div"`, because bestax's `Navbar.Item` and `Dropdown.Item` default
112
+ to an `<a>`. A dynamic `href={expr}` was a runtime decision bloomer made and bestax cannot, so it
113
+ is flagged (`prop:href`) rather than guessed. bestax's `Panel.Block` is always an `<a>`, so only
114
+ a `PanelBlock` with `href` becomes one — the rest stay the plain `<div class="panel-block">` (or
115
+ the `tag` you gave) that bloomer rendered.
116
+
117
+ ## Helper props on parts that take none
118
+
119
+ A few bestax parts extend only React's HTML attributes and take no Bulma helper props at all:
120
+ `Pagination.Previous`/`Next`/`Ellipsis`, `Navbar.Dropdown`/`DropdownMenu`/`Divider`,
121
+ `Panel.Heading`/`Tabs`/`Block`, `Tabs.List`/`Item`, `Message.Header`/`Body` and the `Modal`
122
+ parts. A bloomer helper on one of those becomes the Bulma class in `className` — except on
123
+ `Navbar.Divider`, `Pagination.Ellipsis` and `Dropdown.Divider`, which write their own className
124
+ last or take no props at all: there the helper is named in a TODO instead, and an element
125
+ carrying a spread is left as bloomer's. Otherwise it is the Bulma class in `className` (`is-pulled-right`,
126
+ `m-0`, `is-hidden-mobile`, …), since Bulma v1 still ships every one of them; only a dynamic
127
+ value is flagged. The same conversion covers the modifiers bestax has no prop for anywhere —
128
+ `Hero isBold`, `Media isSize`, `Subtitle isSpaced`, `Input isActive`, `PanelBlock isWrapped`,
129
+ `LevelItem isFlexible`, `NavbarDivider isBoxed`, the pagination parts' `isActive`/`isFocused`.
130
+
131
+ ## Refs
132
+
133
+ bloomer forwarded no refs. bestax forwards a ref from the form controls and from `Button`,
134
+ `LinkButton`, `Modal`, `Dropdown`, `Navbar` (plus `Navbar.Burger` and `Navbar.Link`), `Dialog`,
135
+ `Sidebar`, `Toast` and `Carousel` — pass `ref` directly on those.
@@ -0,0 +1,240 @@
1
+ # Recipes for every TODO(bestax-migrate) the bloomer codemod leaves
2
+
3
+ Ordered by how often they appear when the codemod runs over bloomer's own documentation.
4
+ Resolve the comment, then delete it. Never silence a TODO without converting the code.
5
+
6
+ ## `component:Icon`, `component:PanelIcon` — Font Awesome 4 classes
7
+
8
+ bloomer's `Icon` put the icon-font classes on its own `className`, and its era was Font Awesome 4. Classes the parser can read — Font Awesome 5/6 (`fas fa-home`, `fa-solid fa-home`) and MDI
9
+ (`mdi mdi-account`) — become bestax's props automatically:
10
+
11
+ ```jsx
12
+ <Icon className="fas fa-home" isSize="large" />
13
+ <Icon name="home" library="fa" variant="solid" size="large" />
14
+ ```
15
+
16
+ Modifier classes the library documents (`fa-spin`, `fa-lg`, `mdi-24px`) become bestax's
17
+ `features`. Anything else — FA4's `fa fa-home` above all, or an app's own class beside the icon
18
+ — is moved onto an `<i>` child, which renders exactly what bloomer rendered, and flagged: bestax's optional Font Awesome peer is **6.7+**, where
19
+ many v4 names changed and brand icons moved to `variant="brands"`. Either keep FA4 loaded, or
20
+ convert to the prop form:
21
+
22
+ ```jsx
23
+ <Icon><i className="fa fa-github" aria-hidden="true" /></Icon>
24
+ <Icon name="github" library="fa" variant="brands" />
25
+ ```
26
+
27
+ `library` is `fa` | `mdi` | `ion` | `material-icons` | `material-symbols`. `PanelIcon` has the
28
+ same `className` API and converts the same way. An `Icon` with no `className` and no children
29
+ is flagged too — it gets an empty `<i>` child so it compiles until you set a `name` or a child —
30
+ and so is a `className` that is not a string (`prop:className`). An `Icon` written with children
31
+ is flagged as well: bloomer never rendered them — beside a `className` they are removed (the
32
+ classes win), without one they are kept and bestax will render them.
33
+
34
+ ## `component:Nav` — Bulma 0.4's nav
35
+
36
+ `Nav`, `NavLeft`, `NavCenter`, `NavRight`, `NavToggle` and `NavItem` (`component:NavLeft`,
37
+ `component:NavCenter`, `component:NavRight`, `component:NavToggle`, `component:NavItem`) are
38
+ Bulma 0.4's `.nav`, which Bulma removed in 0.5 — bloomer kept the components, but no stylesheet
39
+ you can install today styles them. Rebuild on `Navbar`:
40
+
41
+ ```jsx
42
+ <Nav><NavLeft><NavItem isActive>Home</NavItem></NavLeft><NavToggle /></Nav>
43
+
44
+ <Navbar>
45
+ <Navbar.Brand><Navbar.Burger /></Navbar.Brand>
46
+ <Navbar.Menu><Navbar.Start><Navbar.Item active>Home</Navbar.Item></Navbar.Start></Navbar.Menu>
47
+ </Navbar>
48
+ ```
49
+
50
+ ## `component:Tile` — Bulma v1 removed tiles
51
+
52
+ Use Grid and Cell. `Tile isAncestor` becomes `<Grid>`, `isParent`/`isChild` become `<Cell>`,
53
+ and `isSize={n}` becomes a column span:
54
+
55
+ ```jsx
56
+ <Tile isAncestor><Tile isParent isSize={4}><Tile isChild>x</Tile></Tile></Tile>
57
+ <Grid><Cell colSpan={4}>x</Cell></Grid>
58
+ ```
59
+
60
+ ## `component:Modal` — what carries over
61
+
62
+ bloomer's `Modal` was an inert shell: `isActive` toggled the class and nothing else. bestax's
63
+ `Modal` closes on Escape (calling `onClose`), locks body scroll, and traps focus **by default**,
64
+ and renders inline unless `portal` is set. So every conversion changes behaviour, and every one
65
+ is flagged. Pass `onClose` to get the close-on-Escape and background behaviour:
66
+
67
+ ```jsx
68
+ <Modal active={open} onClose={() => setOpen(false)}>
69
+ ```
70
+
71
+ or keep bloomer's inert behaviour with `closeOnEscape={false} lockScroll={false}`. Add
72
+ `portal` if the modal must escape a transformed ancestor.
73
+
74
+ ## `component:Dropdown` and its parts
75
+
76
+ bestax's `Dropdown` takes a `label` and renders its own trigger and menu, so bloomer's
77
+ `DropdownTrigger`, `DropdownMenu` and `DropdownContent` have nothing to become
78
+ (`component:DropdownTrigger`, `component:DropdownMenu`, `component:DropdownContent`). Keep the
79
+ `<DropdownItem>`s, which become `<Dropdown.Item>`:
80
+
81
+ ```jsx
82
+ <Dropdown isActive isAlign="right">
83
+ <DropdownTrigger><Button>Open</Button></DropdownTrigger>
84
+ <DropdownMenu><DropdownContent>
85
+ <DropdownItem href="/a">A</DropdownItem>
86
+ </DropdownContent></DropdownMenu>
87
+ </Dropdown>
88
+
89
+ <Dropdown label="Open" active right>
90
+ <Dropdown.Item onClick={() => navigate('/a')}>A</Dropdown.Item>
91
+ </Dropdown>
92
+ ```
93
+
94
+ bestax's `Dropdown.Item` declares no `href` (`prop:href` on a `DropdownItem`): navigate in
95
+ `onClick`, or put an `<a>` inside the item.
96
+ `isHoverable` → `hoverable`, `isActive` → `active` carry over on the `Dropdown` itself.
97
+
98
+ ## `prop:tag` — polymorphism
99
+
100
+ bestax declares `as` on only some components (the list is in [prop-map.md](prop-map.md)).
101
+ Elsewhere, render the element you wanted directly, or move the bestax component inside it:
102
+
103
+ ```jsx
104
+ <Box tag="section">…</Box>
105
+ <section><Box>…</Box></section>
106
+ ```
107
+
108
+ A dynamic `tag` on a component that becomes plain markup is flagged the same way — the plain
109
+ element takes bloomer's default tag.
110
+
111
+ ## `prop:render` — the render prop
112
+
113
+ bloomer's `render` handed the computed props (`className` included) to your own renderer:
114
+
115
+ ```jsx
116
+ <Button isColor="info" render={props => <MyButton {...props} />} />
117
+ ```
118
+
119
+ bestax has no render-prop escape hatch. Render the bestax component and put your element inside
120
+ it, or — if you need the classes on your own element — call `useBulmaClasses` in it:
121
+
122
+ ```jsx
123
+ <Button color="info" as={MyButton} />
124
+ ```
125
+
126
+ `Button`, `Navbar.Item`, `Navbar.Link` and `Menu.Item` take `as` as a custom component, which
127
+ covers the common "render as a router link" case.
128
+
129
+ ## `component:Heading` — Bulma v1 dropped `.heading`
130
+
131
+ bloomer's `Heading` is Bulma's small-caps label. It becomes the plain `<p className="heading">`
132
+ bloomer rendered, but Bulma v1 no longer ships styles for that class, so restyle it:
133
+
134
+ ```jsx
135
+ <Heading>Label</Heading>
136
+ <Title as="p" size={6} textTransform="uppercase" textWeight="semibold">Label</Title>
137
+ ```
138
+
139
+ ## `prop:isFullWidth` — not a universal helper in bestax
140
+
141
+ bloomer accepted `isFullWidth` on everything; Bulma's `is-fullwidth` only means something on a
142
+ few elements, and bestax declares `isFullWidth` on exactly those — `Button`, `Select`, `Table`,
143
+ `Tabs` — where it passes through. Elsewhere, drop it, or add `className="is-fullwidth"` if your
144
+ own CSS styled the class.
145
+
146
+ ## Modifiers bestax has no prop for — converted to classes
147
+
148
+ Bulma v1 still ships every one of these, so the codemod writes the class into `className`
149
+ instead of leaving a TODO: `Hero isBold` → `className="is-bold"`, `isHalfHeight` →
150
+ `is-halfheight`, `Media isSize="large"` → `is-large`, `Subtitle isSpaced` → `is-spaced`,
151
+ `Input isActive` → `is-active`, `NavbarLink isActive` → `is-active`, `PageLink`/`PageControl`/
152
+ `PageEllipsis` `isActive`/`isFocused`, `PanelBlock isWrapped` → `is-wrapped`, `LevelItem
153
+ isFlexible` → `is-flexible`, `NavbarDropdown`/`NavbarDivider` `isBoxed` → `is-boxed`. The same
154
+ goes for a universal helper on a part that takes no helper props (`Pagination.Previous`/`Next`/
155
+ `Ellipsis`, `Navbar.Dropdown`/`DropdownMenu`/`Divider`, `Panel.Heading`/`Tabs`/`Block`,
156
+ `Tabs.List`/`Item`, `Message.Header`/`Body`, the `Modal` parts): `isPulled="right"` →
157
+ `is-pulled-right`, `isMarginless` → `m-0`, `isHidden="mobile"` → `is-hidden-mobile`. A dynamic
158
+ value, or a dynamic `className` the class cannot be spliced into, is flagged with the class to add.
159
+
160
+ ## Props with no counterpart
161
+
162
+ Each of these is left in place with a TODO:
163
+
164
+ | prop | on | what to do |
165
+ | ------------------------- | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- |
166
+ | `isHoverable` | `NavbarItem` without `hasDropdown` | move to the `Navbar.Dropdown`, or `className="is-hoverable"` |
167
+ | `hasAddons="fullwidth"` | `Field` | `hasAddons` plus `className="has-addons-fullwidth"` |
168
+ | `isAlign` | `TabList` | set `align` on the `<Tabs>` — Bulma aligns the container |
169
+ | `isGrid` | `Columns` | Bulma removed `columns.is-grid` in 0.5; use `isMultiline` with sized columns, or `Grid` |
170
+ | `href` | `CardFooterItem`, `CardHeaderIcon`, `Delete`, `DropdownItem` | put an `<a>` inside, or handle it in `onClick` |
171
+ | `href={expr}` (dynamic) | `Button`, `LevelItem` and the other components that switched to an `<a>` on `href` | bloomer decided the element at runtime; set `as` conditionally by hand |
172
+ | `href` | `NavbarItem hasDropdown` | bestax's `Navbar.Dropdown` is the container; put the `href` on the `Navbar.Link` inside |
173
+ | `isRatio` beside `isSize` | `Image` | bestax's one `size` took the fixed size; restore the ratio if that was the point |
174
+
175
+ ## `component:MenuLink`, `component:Breadcrumb`, `component:Page` — lists bestax renders itself
176
+
177
+ bestax's `Menu.Item` renders its own `<li><a>`, its `Breadcrumb` its own `<ul>`, and its
178
+ `Pagination.Link`/`Pagination.Ellipsis` their own `<li>`. bloomer's docs wrote those elements by
179
+ hand, so the codemod folds a literal `<li>` around a `MenuLink`, a literal `<ul>` inside a
180
+ `Breadcrumb`, and a `Page` around a single link away — carrying their attributes. It flags the
181
+ shapes it cannot fold: a `MenuLink` sharing its `<li>` with other content, a `<ul>` carrying
182
+ attributes, and a `Page` whose link sits in an expression or beside siblings — remove the wrapper
183
+ by hand, or the lists nest.
184
+
185
+ ## `prop:isLink` — beside `isColor`
186
+
187
+ `isLink` is Bulma's `is-link` colour. Alone it becomes `color="link"`; beside an `isColor` there
188
+ are two colours for bestax's one `color` prop — pick one.
189
+
190
+ ## `prop:isDisplay`, `prop:isHidden`, `prop:isSize`, `prop:isOffset` — dynamic helper values
191
+
192
+ The three-shape helpers flatten only from literals. A dynamic value is dropped (bestax has no
193
+ prop of that name, so leaving it would be a type error) and flagged; set the matching bestax
194
+ prop conditionally:
195
+
196
+ ```jsx
197
+ <Box isHidden={collapsed} />
198
+ <Box visibility={collapsed ? 'hidden' : undefined} />
199
+ ```
200
+
201
+ `Column`'s `isSize`/`isOffset` follow the same rule, and a `touch` key has no `sizeTouch`
202
+ counterpart in bestax (only `isNarrowTouch`) — Bulma keeps the `is-*-touch` classes, so use
203
+ `className`.
204
+
205
+ ## `prop:hasTextColor="white-ter"` / `"white-bis"`
206
+
207
+ Two Bulma 0.6 shades bestax has no colour for. Use `white`, or a custom class. Every other colour
208
+ and shade of that era exists in bestax verbatim.
209
+
210
+ ## `value-reference` — a component used as a value
211
+
212
+ `const Wrapped = Box` and `{ Subtitle }` are rewritten to the bestax binding (`Hero.Foot`,
213
+ `SubTitle`) when the target is a plain rename, and `export { Subtitle }` becomes
214
+ `export { SubTitle as Subtitle }` so the public name survives. A re-export of a component whose
215
+ bestax counterpart is a member of a compound (`export { CardHeader }` → `Card.Header`) cannot be
216
+ expressed and is flagged; so is a barrel `export { X } from 'bloomer'` (`imports`) and a
217
+ namespace import used as a plain value (`const { Box } = B`), through which nothing was
218
+ migrated. A retained component (`Tile`, the `Nav` family,
219
+ `withHelpersModifiers`) used as a value keeps the bloomer import with this flag: migrate the
220
+ usage by hand. `withHelpersModifiers` in particular has nothing to become — every bestax
221
+ component already takes the helper props, and a custom component gets them from
222
+ `useBulmaClasses`.
223
+
224
+ ## `imports` — a bloomer import the codemod left alone
225
+
226
+ A default import (`import Bloomer from 'bloomer'`) never worked — bloomer has no default
227
+ export — and a deep import (`bloomer/lib/elements/Box`) reaches compiled internals the mapping
228
+ does not know. Convert either to a named import from `'bloomer'` and re-run the codemod.
229
+
230
+ ## `plain-element` — helper props on markup that became plain HTML
231
+
232
+ When a component becomes plain markup (`Help`, `Label`, `PanelTab`, …), bloomer's helper props
233
+ on it have no home and are dropped with this flag. Re-apply them as classes
234
+ (`className="is-pulled-right"`), or wrap the element in a bestax `Box`/`Block` that takes them.
235
+
236
+ ## Dynamic values
237
+
238
+ Any prop whose value the codemod cannot read — `isColor={c}`, `isNext={n}`, `hasIcons={sides}`,
239
+ `tag={t}`, `isTransparent={t}`, `isFullHeight={f}`, `isNormal={n}` — is either renamed as-is (when the rename is unconditional) or flagged with the
240
+ specific prop to set. The comment names it.
@@ -1,11 +1,12 @@
1
1
  # Stylesheets: pre-1 Bulma → Bulma v1 + bestax
2
2
 
3
3
  Every library `bestax-migrate` migrates from is pinned to a pre-1 Bulma: react-bulma-components
4
- to 0.9.x, rbx to 0.7.5. bestax-bulma targets Bulma v1. The codemod automates most of that
4
+ to 0.9.x, rbx to 0.7.5, and a bloomer app to whichever 0.6 it installed itself. bestax-bulma
5
+ targets Bulma v1. The codemod automates most of that
5
6
  stylesheet layer; this reference explains what it did and how to finish what it flagged.
6
7
 
7
- Coming from rbx you are crossing **two** Bulma majors rather than one, so expect more visual
8
- drift than the 0.9 → 1 notes below describe on their own.
8
+ Coming from rbx or bloomer you are crossing **two** Bulma majors rather than one, so expect more
9
+ visual drift than the 0.9 → 1 notes below describe on their own.
9
10
 
10
11
  ## What the codemod already did (default `--css bestax`)
11
12
 
@@ -15,7 +15,9 @@ FontAwesome component form, which carries no readable name.
15
15
 
16
16
  `library` is `fa` | `mdi` | `ion` | `material-icons` | `material-symbols`; `variant` is the style
17
17
  (`solid`, `regular`, `brands`, …). Icon-font children the parser _can_ read
18
- (`<i className="fas fa-home" />`) are converted automatically.
18
+ (`<i className="fas fa-home" />`) are converted automatically, with modifier classes such as
19
+ `fa-spin` carried as bestax's `features`; a child that also carries an app class of its own is
20
+ kept and flagged instead.
19
21
 
20
22
  ## `component:Tile` — Bulma v1 removed tiles
21
23