create-bestax 4.2.17 → 4.2.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/README.md +13 -5
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +1 -1
  4. package/dist/constants.d.ts +2 -0
  5. package/dist/constants.d.ts.map +1 -1
  6. package/dist/constants.js +10 -2
  7. package/dist/display.d.ts +9 -0
  8. package/dist/display.d.ts.map +1 -1
  9. package/dist/display.js +19 -1
  10. package/dist/file-system.d.ts +21 -4
  11. package/dist/file-system.d.ts.map +1 -1
  12. package/dist/file-system.js +52 -6
  13. package/dist/library-range.d.ts +16 -0
  14. package/dist/library-range.d.ts.map +1 -0
  15. package/dist/library-range.js +40 -0
  16. package/dist/project-creator.d.ts +16 -1
  17. package/dist/project-creator.d.ts.map +1 -1
  18. package/dist/project-creator.js +39 -7
  19. package/dist/prompts.d.ts +1 -0
  20. package/dist/prompts.d.ts.map +1 -1
  21. package/dist/prompts.js +3 -2
  22. package/dist/validators.d.ts +8 -0
  23. package/dist/validators.d.ts.map +1 -1
  24. package/dist/validators.js +18 -1
  25. package/package.json +8 -8
  26. package/templates/skills/bestax-custom-component/references/component-catalog.md +5 -1
  27. package/templates/skills/bestax-form/SKILL.md +45 -16
  28. package/templates/skills/bestax-form/references/api.md +13 -8
  29. package/templates/skills/bestax-form/references/patterns.md +75 -3
  30. package/templates/skills/bestax-layout-scaffold/SKILL.md +34 -6
  31. package/templates/skills/bestax-layout-scaffold/references/archetypes.md +2 -2
  32. package/templates/skills/bestax-layout-scaffold/references/layout-components.md +52 -5
  33. package/templates/skills/bestax-migrate/SKILL.md +34 -5
  34. package/templates/skills/bestax-migrate/references/bloomer/component-map.md +1 -1
  35. package/templates/skills/bestax-migrate/references/bloomer/prop-map.md +12 -9
  36. package/templates/skills/bestax-migrate/references/bulma-classes/component-map.md +153 -105
  37. package/templates/skills/bestax-migrate/references/bulma-classes/prop-map.md +48 -17
  38. package/templates/skills/bestax-migrate/references/bulma-classes/unmappables.md +501 -16
  39. package/templates/skills/bestax-migrate/references/css-migration.md +12 -1
  40. package/templates/skills/bestax-migrate/references/rbx/prop-map.md +23 -17
  41. package/templates/skills/bestax-migrate/references/react-bulma-components/prop-map.md +27 -22
  42. package/templates/skills/bestax-migrate/references/react-bulma-components/unmappables.md +5 -5
  43. package/templates/skills/bestax-optimize/references/modular-build.md +57 -15
  44. package/templates/skills/bestax-theming/SKILL.md +19 -8
  45. package/templates/skills/bestax-theming/examples/dark-mode.tsx +99 -17
  46. package/templates/skills/bestax-theming/examples/theme-config.tsx +13 -8
  47. package/templates/skills/bestax-theming/references/css-variables.md +231 -18
  48. package/templates/skills/bestax-theming/references/themeable-components.md +4 -0
  49. package/templates/vite/package.json +1 -1
  50. package/templates/vite/src/main.jsx +1 -1
  51. package/templates/vite-ts/package.json +1 -1
  52. package/templates/vite-ts/src/main.tsx +1 -1
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: bestax-migrate
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.
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 in static HTML pages and templates styled with Bulma, 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 static HTML pages or templates styled with Bulma should become React components, 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
 
@@ -21,6 +21,7 @@ The codemod's first argument names the library you are migrating _from_. Check t
21
21
  | `rbx` v2 (abandoned 2019, pins Bulma **0.7.5** plus four extensions) | `rbx` | [`references/rbx/`](references/rbx/component-map.md) |
22
22
  | `bloomer` 0.6 (archived 2018, Bulma 0.6 era, React 16 + `create-react-class`) | `bloomer` | [`references/bloomer/`](references/bloomer/component-map.md) |
23
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) |
24
+ | Static HTML pages or templates styled with Bulma (`<div class="box">`) | `bulma-classes` | [`references/bulma-classes/`](references/bulma-classes/unmappables.md) |
24
25
 
25
26
  Everything below is written as `<source>`; substitute the argument from that table. The
26
27
  reference paths follow the same split — `references/<source>/component-map.md`,
@@ -38,6 +39,28 @@ Run these steps in order. Don't hand-convert what the codemod converts automatic
38
39
  pnpm dlx bestax-migrate <source> src/ --dry
39
40
  ```
40
41
 
42
+ For HTML pages, name a page, or walk a folder with `-e html` (`-e html,htm` for `.htm` pages
43
+ too; a plain walk skips them,
44
+ since most of it in a React project isn't a page to convert, and reports the Bulma pages it
45
+ skipped as `html-file:not-included`):
46
+
47
+ ```sh
48
+ pnpm dlx bestax-migrate bulma-classes src/pages/login/index.html --dry
49
+ pnpm dlx bestax-migrate bulma-classes -e html src/pages/ --dry
50
+ ```
51
+
52
+ Each page becomes a module beside it (`index.tsx`, or `.jsx` when the package isn't
53
+ TypeScript) whose default export is `<Name>Page`, named from the file (its folder's for an
54
+ `index.html`). The page stays as it was, and the codemod never writes over a module that's
55
+ already there, so a re-run writes nothing. Its head, its `<html>` and `<body>` attributes and
56
+ its scripts become `html-*` TODOs: put the app-wide parts in the app's `index.html` and
57
+ entry, and port each script's work into the component. Under `--css bestax` or `--css bulma`
58
+ the module imports the stylesheet in place of the page's Bulma `<link>`.
59
+
60
+ A file that fails to parse or transform is marked `✖`, listed under `failed` in the report
61
+ and left as it was, and the run exits 1 while every other file still converts. Fix that file
62
+ and run the codemod on it again. TODOs alone leave the exit code at 0.
63
+
41
64
  2. **Apply it** (same command without `--dry`), then run the project's formatter — the
42
65
  codemod preserves surrounding formatting but doesn't prettify what it rewrites.
43
66
  Besides the components, it also migrates **stylesheets** (CSS imports →
@@ -113,15 +136,21 @@ code per the references, or deliberately keep the old markup with `className` st
113
136
  drift than the 0.9 → 1 guide alone describes.
114
137
  - **bulma-classes**: there is no library to remove. An element converts only when the bestax
115
138
  component renders the same markup (tag, classes, attributes), so a converted page renders
116
- the same HTML; everything else stays as written, with a TODO when there is something to
117
- decide. Static class strings convert, and so does a `clsx` or `classnames` call of strings
118
- and conditional classes, where a condition on a flag becomes its prop (`isLoading={busy}`);
139
+ the same HTML, but for deliberate exceptions: Font Awesome's own hidden `<i>` in a `.icon`
140
+ that carries nothing else assistive tech reads becomes `Icon`, which hides the `.icon`
141
+ instead, the glyph hidden either way, and Bulma 0.9's `is-marginless` and `is-paddingless`,
142
+ which style nothing under v1, become `m="0"` and `p="0"`. Everything else stays as written, with a
143
+ TODO when there is something to decide. Static class strings convert, and so does a `clsx` or
144
+ `classnames` call of strings and conditional classes, where a condition on a flag becomes
145
+ its prop (`isLoading={busy}`);
119
146
  any other computed className gets `dynamic-class:<Target>`, naming the component the element
120
147
  would become. Files a Next.js
121
148
  App Router may render as server components are left alone (`rsc`), and the manifest gains
122
149
  `@allxsmith/bestax-bulma` while the app's Bulma and stylesheets stay (the default
123
150
  `--css keep`). Its rules are `kind:<name>` shaped; see
124
- `references/bulma-classes/unmappables.md`.
151
+ `references/bulma-classes/unmappables.md`. An HTML page converts the same way once it is JSX,
152
+ and what a component can't carry (the head, scripts, inline handlers, `<html>` and `<body>`
153
+ classes such as `has-navbar-fixed-top`) gets an `html-*` rule with its recipe there.
125
154
  - **bloomer**: every export is a flat name and most become dotted bestax compounds
126
155
  (`CardHeaderTitle` → `Card.Header.Title`). Most of its `is*` booleans already are bestax's
127
156
  (`isActive` becomes `active` where bestax names it so; `isFullWidth` becomes `isFullwidth`
@@ -151,7 +151,7 @@ Some targets depend on a prop or a child, so the codemod picks them element by e
151
151
  | `PageControl` | `Pagination.Previous` / `Pagination.Next` | `isNext` (bloomer's default is previous) |
152
152
  | `NavbarItem` | `Navbar.Item` / `Navbar.Dropdown` | `hasDropdown` |
153
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>` |
154
+ | `PanelBlock` | `Panel.Block` / _the plain block_ | the element: an `<a>`, a `<div>` or a `<label>` is the component; any other `tag`, or a dynamic one, stays plain markup |
155
155
  | `MenuLink` in a literal `<li>` | `Menu.Item`, the `<li>` folded away | bestax's item renders its own `<li>` |
156
156
  | `Breadcrumb` around a literal `<ul>` | `Breadcrumb`, the `<ul>` folded away | bestax's breadcrumb renders its own `<ul>` |
157
157
  | `Icon`, `PanelIcon` | `name`/`library`/`variant` / an `<i>` child | whether the icon classes are FA5/6 or MDI |
@@ -119,8 +119,8 @@ narrowed to a literal union, so a value outside the union is a type error you ca
119
119
  than a silent rewrite. The components whose `tag` becomes `as`:
120
120
 
121
121
  `Button`, `Image`, `Title`, `Subtitle`, `Footer`, `Media`, `MediaLeft`, `LevelItem`, `Control`,
122
- `DropdownItem`,
123
- `MenuLink`, `NavbarItem`, `NavbarLink`.
122
+ `DropdownItem`, `MenuLink`, `NavbarItem`, `NavbarLink`, `Container`, `Hero`, `HeroHeader`,
123
+ `HeroFooter`, `Panel`.
124
124
 
125
125
  Everywhere else `tag` is left in place with a TODO. On the components that become plain markup
126
126
  (`Help`, `Label`, `Heading`, `BreadcrumbItem`, `PanelTab`, `TabLink`, `Page`, `HeroVideo`) a
@@ -148,9 +148,12 @@ rendered. `Button` and `LevelItem` gain `as="a"`; on the targets that already re
148
148
  stays — each of those takes the anchor's props under its default `as`. A `NavbarItem` or
149
149
  `DropdownItem` with neither `href` nor `tag` gains `as="div"`, because bestax's `Navbar.Item`
150
150
  and `Dropdown.Item` default to an `<a>`. An empty or false `href` selected nothing in bloomer
151
- and is dropped. bestax's `Panel.Block` is always an `<a>`, so only a `PanelBlock` with `href`
152
- becomes one — the rest stay the plain `<div class="panel-block">` (or the `tag` you gave) that
153
- bloomer rendered.
151
+ and is dropped. bestax's `Panel.Block` is an `<a>` by default and a `<div>` or a `<label>`
152
+ through `as`, so a `PanelBlock` with no `href` becomes `<Panel.Block as="div">`, or
153
+ `as="label"` for `tag="label"`, and one with `tag="a"` a bare `<Panel.Block>`. One on any
154
+ other `tag` stays the plain block, on that tag, that bloomer rendered. A dynamic `tag` becomes
155
+ a plain `<div class="panel-block">` with a `prop:tag` TODO, since the codemod can't tell which
156
+ tag it names.
154
157
 
155
158
  A dynamic `href={expr}` was a runtime decision bloomer made and bestax's `as` is one element or
156
159
  the other. It resolves to the anchor, which is the branch the `href` is there for, and the
@@ -189,10 +192,10 @@ value is flagged. The same conversion covers the modifiers bestax has no prop fo
189
192
  bloomer forwarded no refs. bestax forwards a ref from the form controls, plus `Avatar`, `Button`,
190
193
  `Carousel`, `CarouselItem`, `Dialog`, `Dropdown`, `EmptyState`, `Kbd`, `Kbd.Group`, `Link`,
191
194
  `LinkButton`, `Loader`, `Menu.Item`, `Modal`, `Navbar`, `Navbar.Burger`, `Navbar.Dropdown`,
192
- `Navbar.Item`, `Navbar.Link`, `SegmentedControl`, `SegmentedControl.Segment`, `Sidebar`, `Toast` and
193
- `ToggleButton` — pass `ref` directly on those. "The form controls" means the inputs themselves: the
194
- `Field`, `Field.Label`, `Field.Body`, `Checkboxes` and `Radios` wrappers around them forward
195
- nothing.
195
+ `Navbar.Item`, `Navbar.Link`, `SegmentedControl`, `SegmentedControl.Segment`, `Sidebar`, `Timeline`,
196
+ `Timeline.Item`, `Toast`, `ToggleButton`, `TreeView` and `TreeView.Item` — pass `ref` directly on
197
+ those. "The form controls" means the inputs themselves: the `Field`, `Field.Label`, `Field.Body`,
198
+ `Checkboxes` and `Radios` wrappers around them forward nothing.
196
199
 
197
200
  A `ref` on anything else is unsupported, and the two React majors fail differently: React 18
198
201
  drops it and logs "Function components cannot be given refs", while React 19 hands it to the
@@ -4,7 +4,11 @@ For apps that style plain JSX with Bulma's classes (`<div className="columns">`)
4
4
  wrapper library. The codemod converts an element only when the bestax component renders
5
5
  **exactly the markup the element did**: same tag, same classes, same attributes. Anything else
6
6
  stays as written, with a `TODO(bestax-migrate)` when there is something to decide (see
7
- [unmappables.md](unmappables.md)).
7
+ [unmappables.md](unmappables.md)). The exceptions are deliberate. Font Awesome's own
8
+ `<i aria-hidden="true">` alone in a `.icon` that carries nothing assistive tech reads becomes
9
+ `Icon`, which puts that attribute on the `.icon` instead, since the glyph is hidden either way
10
+ (see `.icon` below). And a Bulma 0.9 helper that v1 removed, which styles nothing now, becomes
11
+ the v1 helper that does its job (the [prop map](prop-map.md) lists them).
8
12
 
9
13
  A class the codemod doesn't know, such as the app's own `pricing-card`, rides along in
10
14
  `className`, which every bestax component passes through. So does a Bulma class with no bestax
@@ -17,98 +21,104 @@ test holds it to that table. Render tests hold the table to the library itself.
17
21
  ## Components
18
22
 
19
23
  The **Tags** column is what the codemod converts the class on: an element on any other tag gets
20
- a `tag:<Target>` TODO instead of a conversion. A component's own `as` can take more. One exception:
21
- a `<label>` or `<div>` `.panel-block` stays markup with no TODO, since bestax renders those as
22
- `Panel.CheckboxBlock`, `Panel.InputBlock` and `Panel.ButtonBlock`, which build their own contents.
23
-
24
- | Bulma class | bestax-bulma | Tags |
25
- | ---------------------- | --------------------- | -------------------------------------------------------------- |
26
- | `.block` | `Block` | `<div>` only |
27
- | `.box` | `Box` | `<div>` only |
28
- | `.button` | `Button` | `<button>`, any tag via `as` |
29
- | `.buttons` | `Buttons` | `<div>` only |
30
- | `.card` | `Card` | `<div>` only |
31
- | `.card-header` | `Card.Header` | `<header>` only |
32
- | `.card-header-title` | `Card.Header.Title` | `<div>`, `<p>`, `<h2>`, `<h3>`, `<h4>` via `as` |
33
- | `.card-header-icon` | `Card.Header.Icon` | `<button>` only |
34
- | `.card-image` | `Card.Image` | `<div>` only |
35
- | `.card-content` | `Card.Content` | `<div>` only |
36
- | `.card-footer` | `Card.Footer` | `<footer>` only |
37
- | `.card-footer-item` | `Card.FooterItem` | `<span>`, `<a>`, `<button>` via `as` |
38
- | `.columns` | `Columns` | `<div>` only |
39
- | `.column` | `Column` | `<div>` only |
40
- | `.grid` | `Grid` | `<div>` only |
41
- | `.cell` | `Cell` | `<div>` only |
42
- | `.container` | `Container` | `<div>` only |
43
- | `.content` | `Content` | `<div>` only |
44
- | `.delete` | `Delete` | `<button>` only |
45
- | `.field` | `Field` | `<div>` only |
46
- | `.field-label` | `Field.Label` | `<div>` only |
47
- | `.field-body` | `Field.Body` | `<div>` only |
48
- | `.control` | `Control` | `<div>`, `<p>` via `as` |
49
- | `.input` | `InputBase` | `<input>` only |
50
- | `.textarea` | `TextAreaBase` | `<textarea>` only |
51
- | `.select` | `SelectBase` | `<div>` only |
52
- | `.footer` | `Footer` | `<footer>`, `<div>` via `as` |
53
- | `.hero` | `Hero` | `<section>` only |
54
- | `.hero-head` | `Hero.Head` | `<div>` only |
55
- | `.hero-body` | `Hero.Body` | `<div>` only |
56
- | `.hero-foot` | `Hero.Foot` | `<div>` only |
57
- | `.level` | `Level` | `<nav>` only |
58
- | `.level-left` | `Level.Left` | `<div>` only |
59
- | `.level-right` | `Level.Right` | `<div>` only |
60
- | `.level-item` | `Level.Item` | `<div>`, `<p>`, `<a>` via `as` |
61
- | `.media` | `Media` | `<article>`, `<div>` via `as` |
62
- | `.media-left` | `Media.Left` | `<figure>`, `<div>` via `as` |
63
- | `.media-content` | `Media.Content` | `<div>` only |
64
- | `.media-right` | `Media.Right` | `<div>` only |
65
- | `.navbar` | `Navbar` | `<nav>` only |
66
- | `.navbar-brand` | `Navbar.Brand` | `<div>` only |
67
- | `.navbar-menu` | `Navbar.Menu` | `<div>` only |
68
- | `.navbar-start` | `Navbar.Start` | `<div>` only |
69
- | `.navbar-end` | `Navbar.End` | `<div>` only |
70
- | `.navbar-item` | `Navbar.Item` | `<a>`, any tag via `as` |
71
- | `.navbar-dropdown` | `Navbar.DropdownMenu` | `<div>` only |
72
- | `.navbar-divider` | `Navbar.Divider` | `<hr>` only |
73
- | `.notification` | `Notification` | `<div>` only |
74
- | `.progress` | `Progress` | `<progress>` only |
75
- | `.section` | `Section` | `<section>` only |
76
- | `.subtitle` | `SubTitle` | `<h1>`, `<h2>`, `<h3>`, `<h4>`, `<h5>`, `<h6>`, `<p>` via `as` |
77
- | `.table` | `Table` | `<table>` only |
78
- | `.tag` | `Tag` | `<span>` only |
79
- | `.tags` | `Tags` | `<div>` only |
80
- | `.title` | `Title` | `<h1>`, `<h2>`, `<h3>`, `<h4>`, `<h5>`, `<h6>`, `<p>` via `as` |
81
- | `.breadcrumb` | `Breadcrumb` | `<nav>` only |
82
- | `.skeleton-block` | `Skeleton` | `<div>` only |
83
- | `.skeleton-lines` | `Skeleton` | `<div>` only |
84
- | `.file` | `File` | `<div>` only |
85
- | `.icon` | `Icon` | `<span>` only |
86
- | `.icon-text` | `IconText` | `<span>` only |
87
- | `.image` | `Image` | `<div>`, `<figure>`, `<p>` via `as` |
88
- | `.menu` | `Menu` | `<aside>` only |
89
- | `.menu-label` | `Menu.Label` | `<p>` only |
90
- | `.menu-list` | `Menu.List` | `<ul>` only |
91
- | `.modal-background` | `Modal.Background` | `<div>` only |
92
- | `.modal-content` | `Modal.Content` | `<div>` only |
93
- | `.modal-card` | `Modal.Card` | `<div>` only |
94
- | `.modal-card-head` | `Modal.Card.Head` | `<header>` only |
95
- | `.modal-card-title` | `Modal.Card.Title` | `<p>` only |
96
- | `.modal-card-body` | `Modal.Card.Body` | `<section>` only |
97
- | `.modal-card-foot` | `Modal.Card.Foot` | `<footer>` only |
98
- | `.pagination` | `Pagination` | `<nav>` only |
99
- | `.pagination-list` | `Pagination.List` | `<ul>` only |
100
- | `.pagination-previous` | `Pagination.Previous` | `<a>` only |
101
- | `.pagination-next` | `Pagination.Next` | `<a>` only |
102
- | `.pagination-link` | `Pagination.Link` | `<a>` only |
103
- | `.pagination-ellipsis` | `Pagination.Ellipsis` | `<span>` only |
104
- | `.panel` | `Panel` | `<nav>` only |
105
- | `.panel-heading` | `Panel.Heading` | `<p>` only |
106
- | `.panel-tabs` | `Panel.Tabs` | `<p>` only |
107
- | `.panel-block` | `Panel.Block` | `<a>` only |
108
- | `.tabs` | `Tabs` | `<div>` only |
109
-
110
- An element with two of these (`<div className="column box">`) becomes the layout one
111
- (`Column`), and the other class stays in `className`.
24
+ a `tag:<Target>` TODO instead of a conversion. A component's own `as` can take more.
25
+
26
+ | Bulma class | bestax-bulma | Tags |
27
+ | ---------------------- | --------------------- | ------------------------------------------------------------------------------------------------ |
28
+ | `.block` | `Block` | `<div>` only |
29
+ | `.box` | `Box` | `<div>` only |
30
+ | `.button` | `Button` | `<button>`, any tag via `as` |
31
+ | `.buttons` | `Buttons` | `<div>` only |
32
+ | `.card` | `Card` | `<div>` only |
33
+ | `.card-header` | `Card.Header` | `<header>` only |
34
+ | `.card-header-title` | `Card.Header.Title` | `<div>`, `<p>`, `<h2>`, `<h3>`, `<h4>` via `as` |
35
+ | `.card-header-icon` | `Card.Header.Icon` | `<button>` only |
36
+ | `.card-image` | `Card.Image` | `<div>` only |
37
+ | `.card-content` | `Card.Content` | `<div>` only |
38
+ | `.card-footer` | `Card.Footer` | `<footer>` only |
39
+ | `.card-footer-item` | `Card.FooterItem` | `<span>`, `<a>`, `<button>` via `as` |
40
+ | `.columns` | `Columns` | `<div>` only |
41
+ | `.column` | `Column` | `<div>` only |
42
+ | `.grid` | `Grid` | `<div>` only |
43
+ | `.cell` | `Cell` | `<div>` only |
44
+ | `.container` | `Container` | `<div>`, `<main>`, `<section>`, `<article>`, `<aside>`, `<header>`, `<footer>`, `<nav>` via `as` |
45
+ | `.content` | `Content` | `<div>` only |
46
+ | `.delete` | `Delete` | `<button>` only |
47
+ | `.field` | `Field` | `<div>` only |
48
+ | `.field-label` | `Field.Label` | `<div>` only |
49
+ | `.field-body` | `Field.Body` | `<div>` only |
50
+ | `.control` | `Control` | `<div>`, `<p>` via `as` |
51
+ | `.input` | `InputBase` | `<input>` only |
52
+ | `.textarea` | `TextAreaBase` | `<textarea>` only |
53
+ | `.select` | `SelectBase` | `<div>` only |
54
+ | `.footer` | `Footer` | `<footer>`, `<div>` via `as` |
55
+ | `.hero` | `Hero` | `<section>`, `<div>`, `<main>`, `<header>`, `<footer>`, `<article>`, `<aside>` via `as` |
56
+ | `.hero-head` | `Hero.Head` | `<div>`, `<header>`, `<nav>` via `as` |
57
+ | `.hero-body` | `Hero.Body` | `<div>` only |
58
+ | `.hero-foot` | `Hero.Foot` | `<div>`, `<footer>`, `<nav>` via `as` |
59
+ | `.level` | `Level` | `<nav>` only |
60
+ | `.level-left` | `Level.Left` | `<div>` only |
61
+ | `.level-right` | `Level.Right` | `<div>` only |
62
+ | `.level-item` | `Level.Item` | `<div>`, `<p>`, `<a>` via `as` |
63
+ | `.media` | `Media` | `<article>`, `<div>` via `as` |
64
+ | `.media-left` | `Media.Left` | `<figure>`, `<div>` via `as` |
65
+ | `.media-content` | `Media.Content` | `<div>` only |
66
+ | `.media-right` | `Media.Right` | `<div>` only |
67
+ | `.navbar` | `Navbar` | `<nav>` only |
68
+ | `.navbar-brand` | `Navbar.Brand` | `<div>` only |
69
+ | `.navbar-menu` | `Navbar.Menu` | `<div>` only |
70
+ | `.navbar-start` | `Navbar.Start` | `<div>` only |
71
+ | `.navbar-end` | `Navbar.End` | `<div>` only |
72
+ | `.navbar-item` | `Navbar.Item` | `<a>`, any tag via `as` |
73
+ | `.navbar-dropdown` | `Navbar.DropdownMenu` | `<div>` only |
74
+ | `.navbar-divider` | `Navbar.Divider` | `<hr>` only |
75
+ | `.notification` | `Notification` | `<div>` only |
76
+ | `.progress` | `Progress` | `<progress>` only |
77
+ | `.section` | `Section` | `<section>` only |
78
+ | `.subtitle` | `SubTitle` | `<h1>`, `<h2>`, `<h3>`, `<h4>`, `<h5>`, `<h6>`, `<p>` via `as` |
79
+ | `.table` | `Table` | `<table>` only |
80
+ | `.tag` | `Tag` | `<span>` only |
81
+ | `.tags` | `Tags` | `<div>` only |
82
+ | `.title` | `Title` | `<h1>`, `<h2>`, `<h3>`, `<h4>`, `<h5>`, `<h6>`, `<p>` via `as` |
83
+ | `.breadcrumb` | `Breadcrumb` | `<nav>` only |
84
+ | `.skeleton-block` | `Skeleton` | `<div>` only |
85
+ | `.skeleton-lines` | `Skeleton` | `<div>` only |
86
+ | `.file` | `File` | `<div>` only |
87
+ | `.icon` | `Icon` | `<span>` only |
88
+ | `.icon-text` | `IconText` | `<span>` only |
89
+ | `.image` | `Image` | `<div>`, `<figure>`, `<p>` via `as` |
90
+ | `.menu` | `Menu` | `<aside>` only |
91
+ | `.menu-label` | `Menu.Label` | `<p>` only |
92
+ | `.menu-list` | `Menu.List` | `<ul>` only |
93
+ | `.modal-background` | `Modal.Background` | `<div>` only |
94
+ | `.modal-content` | `Modal.Content` | `<div>` only |
95
+ | `.modal-card` | `Modal.Card` | `<div>` only |
96
+ | `.modal-card-head` | `Modal.Card.Head` | `<header>` only |
97
+ | `.modal-card-title` | `Modal.Card.Title` | `<p>` only |
98
+ | `.modal-card-body` | `Modal.Card.Body` | `<section>` only |
99
+ | `.modal-card-foot` | `Modal.Card.Foot` | `<footer>` only |
100
+ | `.pagination` | `Pagination` | `<nav>` only |
101
+ | `.pagination-list` | `Pagination.List` | `<ul>` only |
102
+ | `.pagination-previous` | `Pagination.Previous` | `<a>` only |
103
+ | `.pagination-next` | `Pagination.Next` | `<a>` only |
104
+ | `.pagination-link` | `Pagination.Link` | `<a>` only |
105
+ | `.pagination-ellipsis` | `Pagination.Ellipsis` | `<span>` only |
106
+ | `.panel` | `Panel` | `<nav>`, `<article>`, `<section>`, `<aside>`, `<div>` via `as` |
107
+ | `.panel-heading` | `Panel.Heading` | `<p>` only |
108
+ | `.panel-tabs` | `Panel.Tabs` | `<p>` only |
109
+ | `.panel-block` | `Panel.Block` | `<a>`, `<div>`, `<label>` via `as` |
110
+ | `.tabs` | `Tabs` | `<div>` only |
111
+
112
+ An element with two of these (`<div className="column box">`) becomes the one whose component
113
+ fits its tag best, and the other class stays in `className` with a `second-component:<Target>`
114
+ TODO. A component that renders the tag with no `as` beats one that reaches it only through `as`,
115
+ which beats one that can't render it, and between equals the layout one wins (`Column`). So
116
+ `<section className="hero container">` becomes a `Hero`, and `<figure className="image container">`
117
+ an `Image`, which `Container` can't render. The tag a component renders with no `as` is the one
118
+ the element's classes give it: a ratio puts `Image` on a `<figure>`, so
119
+ `<figure className="navbar-item image is-16by9">` becomes an `Image`, and
120
+ `<div className="media-left image is-1by1">` a `Media.Left`, since both reach a `<div>` only
121
+ through `as` there. A heading's size does the same for `Title` and `SubTitle`.
112
122
 
113
123
  `Card` renders its children inside a `.card-content` of its own unless one of them is one of
114
124
  its parts, and `Card.Header` its children inside a `.card-header-title` unless one of them is a
@@ -144,9 +154,36 @@ component, which could hand it a labelled Field's generated one.
144
154
  A `.tabs` converts around its `<ul>`, and the `<li>`s and `<a>`s inside stay as written: `Tabs.Tab`
145
155
  renders its own `<a>` with tab roles and puts its label in a `<span>`, so converting the tabs
146
156
  themselves is by hand (something that sat beside the text in the `<a>`, a `Tag` say, then wants a
147
- `Span display="flex" alignItems="center"` around it and the label). A `.icon` converts around the
148
- `<i>` inside it when it carries the attribute `Icon` writes otherwise: `aria-hidden` with no name,
149
- no `role` and no `tabIndex`, and `role="img"` beside an `aria-label` or `aria-labelledby`.
157
+ `Span display="flex" alignItems="center"` around it and the label). A `.icon` converts when it
158
+ carries the attribute `Icon` writes otherwise: `aria-hidden` with no name, no `role` and no
159
+ `tabIndex`, and `role="img"` beside an `aria-label` or `aria-labelledby`. When all it holds is a
160
+ bare, empty `<i>` naming a Font Awesome or Material Design Icons glyph, the `<i>` goes and its
161
+ classes become `Icon`'s props, read as `IconText` reads them (below), and the `Icon` closes itself:
162
+
163
+ ```jsx
164
+ <span className="icon is-small" aria-hidden="true">
165
+ <i className="fab fa-github fa-lg"></i>
166
+ </span>
167
+ // becomes
168
+ <Icon library="fa" name="github" variant="brands" features="fa-lg" size="small" aria-hidden="true" />
169
+ ```
170
+
171
+ Font Awesome's own markup hides the `<i>` instead, and converts the same way when the `.icon`
172
+ carries nothing but its classes, an `id`, a `style` and `data-` attributes: the `aria-hidden`
173
+ moves up onto the `.icon`, where `Icon` writes it, so the glyph is hidden either way. That is a
174
+ place a conversion changes the markup, on purpose:
175
+
176
+ ```jsx
177
+ <span className="icon is-small is-left">
178
+ <i className="fas fa-envelope" aria-hidden="true"></i>
179
+ </span>
180
+ // becomes, rendering aria-hidden="true" on the .icon
181
+ <Icon library="fa" name="envelope" size="small" className="is-left" />
182
+ ```
183
+
184
+ Around anything else, an `<i>` with an attribute of its own or an `<svg>` say, it converts around
185
+ what it holds, kept as written. Font Awesome 4's `fa` reads as `variant="fa"`, which `Icon`
186
+ renders as written.
150
187
 
151
188
  A `.menu` converts with its `.menu-label`s and `.menu-list`s, and so do the items in a list. An
152
189
  item has no class to go by, so the codemod finds it by where it sits: a `<li>` whose nearest
@@ -154,11 +191,16 @@ element is a `.menu-list`, a bestax `Menu.List`, or the bare `<ul>` nested in on
154
191
  so the `<li>`s a `.map()` renders count too. One handed to any other function doesn't, since that
155
192
  function could render it anywhere. `Menu.Item` renders the `<li>` and its `<a>`
156
193
  together, so an item converts when its `<li>` holds one `<a>` and at most one bare `<ul>` after
157
- it, which becomes a `Menu.List`. `is-active` on the `<a>` becomes `active`, and the `<li>`'s own
194
+ it, which becomes a `Menu.List`. `is-active` on the `<a>` becomes `active` beside an
195
+ `aria-current` of the `<a>`'s own, since `active` writes `aria-current="page"` otherwise; without
196
+ one, the item stays markup with an `attr:aria-current` TODO. If the item is the current page, add
197
+ `aria-current="page"` to the `<a>` and re-run. The `<li>`'s own
158
198
  classes stay in `className`, which `Menu.Item` puts on the `<li>`. It puts `id`, `title`, `role`,
159
199
  `tabIndex`, `style` and `data-testid` there too, and everything else on the `<a>`, so an item
160
200
  converts only when its attributes already sit that way. A `.menu-item` gets a
161
- `family:menu-item` TODO. `Menu.List` drops `.menu-list` on a list inside another, so a
201
+ `family:menu-item` TODO. `Menu.List` writes `role="list"` on its `<ul>`, which is the role a
202
+ list already has, so a `.menu-list` with no `role` converts, and one with another `role` stays
203
+ markup with an `attr:role` TODO. `Menu.List` drops `.menu-list` on a list inside another, so a
162
204
  `.menu-list` inside another, or around a bestax `Menu.List`, stays markup with a
163
205
  `context:Menu.List` TODO, and an item's nested list converts only inside a list that is a
164
206
  `Menu.List` or becomes one.
@@ -166,7 +208,7 @@ converts only when its attributes already sit that way. A `.menu-item` gets a
166
208
  ```tsx
167
209
  <ul className="menu-list">
168
210
  <li>
169
- <a className="is-active" href="/team">Team</a>
211
+ <a className="is-active" href="/team" aria-current="page">Team</a>
170
212
  <ul>
171
213
  <li><a href="/team/members">Members</a></li>
172
214
  </ul>
@@ -174,7 +216,7 @@ converts only when its attributes already sit that way. A `.menu-item` gets a
174
216
  </ul>
175
217
  // becomes
176
218
  <Menu.List>
177
- <Menu.Item active href="/team">
219
+ <Menu.Item active href="/team" aria-current="page">
178
220
  Team
179
221
  <Menu.List>
180
222
  <Menu.Item href="/team/members">Members</Menu.Item>
@@ -238,7 +280,8 @@ go straight inside `Breadcrumb`, and `<figure className="image is-64x64"><img sr
238
280
  one, so the `<ul>` carries nothing and the `.breadcrumb` needs an `aria-label` of its own.
239
281
  - `Image` renders its `<img>` from `src` and `alt`, so the `<img>` carries nothing else, and
240
282
  `is-rounded` on it becomes `isRounded`. The `.image` keeps its own attributes. A ratio
241
- (`is-4by3`) stays a class, since `size` would add `has-ratio` as well. Around anything else (an
283
+ (`is-4by3`) becomes `size` too. `Image` renders a ratio on a `<figure>`, so a `<figure>` needs no
284
+ `as` there and a `<div>` keeps `as="div"`. Around anything else (an
242
285
  `<img>` with more attributes, an `<iframe>`), `Image` renders its children as given, so the
243
286
  `.image` converts around them and they stay as written, as long as they're HTML elements written
244
287
  out. An empty `.image` stays markup, since `Image` would render an `<img>` of its own, and so does
@@ -340,7 +383,12 @@ button, the navbar's burger and dropdown link, the panel's icon, Radio and Radio
340
383
  ## Classes left alone
341
384
 
342
385
  `.help`, `.label`, `.hero-buttons`, `.hero-video`, `.theme-dark`, `.theme-light`, `.fa`,
343
- `.marginless`, `.paddingless`, `.navbar-content`, `.navbar-tabs` and `.panel-list` are valid
344
- Bulma with nothing in bestax to convert to. `.loader` is left alone as well, although bestax's
345
- `Loader` renders the same element: swap it in by hand for its progressbar role and accessible name.
346
- An element carrying one stays as written, and gets no TODO.
386
+ `.navbar-content`, `.navbar-tabs` and `.panel-list` are valid Bulma with nothing in bestax to
387
+ convert to. `.loader` is left alone as well, although bestax's `Loader` renders the same
388
+ element: swap it in by hand for its progressbar role and accessible name. An element carrying
389
+ one stays as written, and gets no TODO.
390
+
391
+ v1's `marginless` and `paddingless` are helpers, not components, so they don't hold an element
392
+ back: `<p className="has-text-centered marginless">` becomes
393
+ `<Paragraph textAlign="centered" className="marginless">`. They keep their names, since bestax
394
+ writes the same rules as `m-0` and `p-0`.