create-bestax 4.2.11 → 4.2.13

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 (48) hide show
  1. package/README.md +11 -2
  2. package/dist/cli.d.ts +2 -2
  3. package/dist/cli.d.ts.map +1 -1
  4. package/dist/cli.js +3 -2
  5. package/dist/constants.d.ts +7 -1
  6. package/dist/constants.d.ts.map +1 -1
  7. package/dist/constants.js +19 -4
  8. package/dist/file-system.d.ts +7 -0
  9. package/dist/file-system.d.ts.map +1 -1
  10. package/dist/file-system.js +15 -0
  11. package/dist/project-creator.d.ts +21 -1
  12. package/dist/project-creator.d.ts.map +1 -1
  13. package/dist/project-creator.js +84 -51
  14. package/dist/prompts.d.ts +7 -2
  15. package/dist/prompts.d.ts.map +1 -1
  16. package/dist/prompts.js +8 -3
  17. package/dist/validators.d.ts +7 -0
  18. package/dist/validators.d.ts.map +1 -1
  19. package/dist/validators.js +13 -1
  20. package/package.json +6 -3
  21. package/templates/skills/bestax-custom-component/SKILL.md +21 -4
  22. package/templates/skills/bestax-custom-component/examples/stat-card.tsx +1 -2
  23. package/templates/skills/bestax-custom-component/references/api.md +103 -11
  24. package/templates/skills/bestax-custom-component/references/component-catalog.md +12 -5
  25. package/templates/skills/bestax-custom-component/references/library-contributor.md +23 -0
  26. package/templates/skills/bestax-form/SKILL.md +28 -17
  27. package/templates/skills/bestax-form/references/api.md +83 -23
  28. package/templates/skills/bestax-form/references/patterns.md +19 -0
  29. package/templates/skills/bestax-layout-scaffold/SKILL.md +17 -4
  30. package/templates/skills/bestax-layout-scaffold/references/layout-components.md +22 -15
  31. package/templates/skills/bestax-migrate/SKILL.md +32 -14
  32. package/templates/skills/bestax-migrate/references/bloomer/prop-map.md +9 -9
  33. package/templates/skills/bestax-migrate/references/bloomer/unmappables.md +19 -2
  34. package/templates/skills/bestax-migrate/references/bulma-classes/component-map.md +337 -0
  35. package/templates/skills/bestax-migrate/references/bulma-classes/prop-map.md +230 -0
  36. package/templates/skills/bestax-migrate/references/bulma-classes/unmappables.md +348 -0
  37. package/templates/skills/bestax-migrate/references/css-migration.md +8 -1
  38. package/templates/skills/bestax-migrate/references/rbx/component-map.md +15 -15
  39. package/templates/skills/bestax-migrate/references/rbx/prop-map.md +17 -19
  40. package/templates/skills/bestax-migrate/references/rbx/unmappables.md +17 -0
  41. package/templates/skills/bestax-migrate/references/react-bulma-components/component-map.md +34 -34
  42. package/templates/skills/bestax-migrate/references/react-bulma-components/unmappables.md +34 -7
  43. package/templates/skills/bestax-optimize/SKILL.md +3 -2
  44. package/templates/skills/bestax-optimize/references/modular-build.md +25 -5
  45. package/templates/skills/bestax-theming/SKILL.md +4 -3
  46. package/templates/skills/bestax-theming/examples/dark-mode.tsx +4 -3
  47. package/templates/skills/bestax-theming/references/css-variables.md +49 -8
  48. package/templates/skills/bestax-theming/references/themeable-components.md +12 -10
@@ -0,0 +1,337 @@
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 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`.
112
+
113
+ `Card` renders its children inside a `.card-content` of its own unless one of them is one of
114
+ its parts, and `Card.Header` its children inside a `.card-header-title` unless one of them is a
115
+ `Card.Header.Title`. So a `.card` with children converts only when one of the elements written directly
116
+ inside it converts to a part (or already is one), and a `.card-header` only when its title
117
+ does. Otherwise it gets a `children:<Target>` TODO. Bulma's own example card, with its
118
+ `<p className="card-header-title">` and `<a className="card-footer-item">` links, converts through
119
+ `as`. A `.card-footer-item` `<button>` converts only with its `type` written out as `button`,
120
+ `submit` or `reset`, since `Card.FooterItem` writes `type="button"` on a button in place of
121
+ anything else.
122
+
123
+ `Navbar` writes `role="navigation"` and `aria-label="main navigation"`, the attributes Bulma's
124
+ own navbar carries, so a `.navbar` that sets both converts (whatever the label says), and one
125
+ that doesn't gets a `defaults:Navbar` TODO. A `.navbar-item` `<button>` converts only with its
126
+ `type` written out as `button`, `submit` or `reset`, since `Navbar.Item` writes `type="button"` on
127
+ a button in place of anything else. A `.has-dropdown` item becomes a `Navbar.Item` that
128
+ keeps `has-dropdown` as a class, because a `Navbar.Dropdown` would give the `.navbar-link` inside
129
+ it dropdown semantics the markup didn't have. That link and the `.navbar-burger` stay markup with
130
+ a `family:<class>` TODO; converting either means building the dropdown or the toggle with bestax,
131
+ by hand.
132
+
133
+ Form markup converts piece by piece: `.field` to `Field`, `.control` to `Control`, the input
134
+ and textarea to `InputBase` and `TextAreaBase`, the controls without wrappers of their own, and a
135
+ `.select` with its `<select>` to `SelectBase` (below). A `.label` and a `.help` stay as they
136
+ are. An input's or a select's color (`is-danger`) stays a class, because `color` renders
137
+ `has-text-<color>` on it too. A `.field.is-horizontal` converts once its
138
+ `.field-label` and `.field-body` do, since `Field` wraps anything else in a `.field-body` of its
139
+ own. `Field` and `Control` tell bestax's form controls inside them to skip their own wrappers, so a
140
+ `.field` or `.control` that already holds a bestax component stays markup with a
141
+ `context:<Target>` TODO, and so does an input with no `id` inside a bestax `Field` or any other
142
+ component, which could hand it a labelled Field's generated one.
143
+
144
+ A `.tabs` converts around its `<ul>`, and the `<li>`s and `<a>`s inside stay as written: `Tabs.Tab`
145
+ renders its own `<a>` with tab roles and puts its label in a `<span>`, so converting the tabs
146
+ 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 an `aria-label`, which `Icon` writes otherwise.
149
+
150
+ A `.menu` converts with its `.menu-label`s and `.menu-list`s, and so do the items in a list. An
151
+ item has no class to go by, so the codemod finds it by where it sits: a `<li>` whose nearest
152
+ element is a `.menu-list`, a bestax `Menu.List`, or the bare `<ul>` nested in one of those items,
153
+ so the `<li>`s a `.map()` renders count too. One handed to any other function doesn't, since that
154
+ function could render it anywhere. `Menu.Item` renders the `<li>` and its `<a>`
155
+ together, so an item converts when its `<li>` holds one `<a>` and at most one bare `<ul>` after
156
+ it, which becomes a `Menu.List`. `is-active` on the `<a>` becomes `active`, and the `<li>`'s own
157
+ classes stay in `className`, which `Menu.Item` puts on the `<li>`. It puts `id`, `title`, `role`,
158
+ `tabIndex`, `style` and `data-testid` there too, and everything else on the `<a>`, so an item
159
+ converts only when its attributes already sit that way. A `.menu-item` gets a
160
+ `family:menu-item` TODO. `Menu.List` drops `.menu-list` on a list inside another, so a
161
+ `.menu-list` inside another, or around a bestax `Menu.List`, stays markup with a
162
+ `context:Menu.List` TODO, and an item's nested list converts only inside a list that is a
163
+ `Menu.List` or becomes one.
164
+
165
+ ```tsx
166
+ <ul className="menu-list">
167
+ <li>
168
+ <a className="is-active" href="/team">Team</a>
169
+ <ul>
170
+ <li><a href="/team/members">Members</a></li>
171
+ </ul>
172
+ </li>
173
+ </ul>
174
+ // becomes
175
+ <Menu.List>
176
+ <Menu.Item active href="/team">
177
+ Team
178
+ <Menu.List>
179
+ <Menu.Item href="/team/members">Members</Menu.Item>
180
+ </Menu.List>
181
+ </Menu.Item>
182
+ </Menu.List>
183
+ ```
184
+
185
+ ## Plain tags with helper classes
186
+
187
+ A tag bestax wraps becomes that wrapper when at least one of its classes converts to a helper
188
+ prop: `<p className="has-text-centered mt-4">` → `<Paragraph textAlign="centered" mt="4">`.
189
+
190
+ | Tag | bestax-bulma |
191
+ | ---------- | --------------- |
192
+ | `<p>` | `Paragraph` |
193
+ | `<span>` | `Span` |
194
+ | `<strong>` | `Strong` |
195
+ | `<em>` | `Emphasis` |
196
+ | `<code>` | `Code` |
197
+ | `<pre>` | `Pre` |
198
+ | `<a>` | `Link` |
199
+ | `<li>` | `ListItem` |
200
+ | `<ol>` | `OrderedList` |
201
+ | `<ul>` | `UnorderedList` |
202
+ | `<figure>` | `Figure` |
203
+
204
+ bestax has no plain `<div>` wrapper, so `<div className="is-flex mt-4">` stays as it is, with
205
+ no TODO: it is valid Bulma, and nothing unsafe was skipped.
206
+
207
+ ## Wrappers a component renders
208
+
209
+ Some wrappers are rendered by the component inside them, from a prop. The codemod folds the
210
+ wrapper into that component: the wrapper goes, and its class and modifiers become the
211
+ component's props (`<div className="fixed-grid has-3-cols">` around a `.grid` becomes
212
+ `<Grid isFixed fixedCols={3}>`).
213
+
214
+ | Bulma class | bestax-bulma |
215
+ | ------------------ | -------------------- |
216
+ | `.table-container` | `Table isResponsive` |
217
+ | `.fixed-grid` | `Grid isFixed` |
218
+
219
+ The component renders the wrapper bare, so it folds only when it holds that one element and
220
+ nothing else, and carries no attribute and no class but its own modifiers. Otherwise it stays
221
+ with a `children:<Target>` or `attr` TODO.
222
+
223
+ ## An element a component renders inside itself
224
+
225
+ `SelectBase` renders the `<select>` inside `.select` itself, `Breadcrumb` the `<ul>` inside
226
+ `.breadcrumb`, and `Image` the `<img>` inside `.image`. So each converts together with that one
227
+ element, and the component takes its place: `<div className="select is-small"><select name="plan">`
228
+ becomes `<SelectBase size="small" name="plan">` around the same `<option>`s, a breadcrumb's `<li>`s
229
+ go straight inside `Breadcrumb`, and `<figure className="image is-64x64"><img src="a.png">` becomes
230
+ `<Image as="figure" size="64x64" src="a.png" />`.
231
+
232
+ - `SelectBase` puts the attributes it's given on the `<select>`, so the `<select>`'s own move up
233
+ and the `.select` can carry none but a `key`. `is-hovered` and `is-focused` on the `<select>`
234
+ become `isHovered` and `isFocused`, a `multiple` `<select>` converts inside `.select.is-multiple`
235
+ as `multiple`, and its `size` becomes `multipleSize`.
236
+ - `Breadcrumb` renders its `<ul>` bare, and writes `aria-label="breadcrumbs"` unless it's given
237
+ one, so the `<ul>` carries nothing and the `.breadcrumb` needs an `aria-label` of its own.
238
+ - `Image` renders its `<img>` from `src` and `alt`, so the `<img>` carries nothing else, and
239
+ `is-rounded` on it becomes `isRounded`. The `.image` keeps its own attributes. A ratio
240
+ (`is-4by3`) stays a class, since `size` would add `has-ratio` as well. Around anything else (an
241
+ `<img>` with more attributes, an `<iframe>`), `Image` renders its children as given, so the
242
+ `.image` converts around them and they stay as written, as long as they're HTML elements written
243
+ out. An empty `.image` stays markup, since `Image` would render an `<img>` of its own, and so does
244
+ one around an expression (`{src && <img />}`), which can come out empty.
245
+
246
+ For `SelectBase` and `Breadcrumb`, anything else keeps both as markup, with a `children:<Target>`, `attr` or `defaults:<Target>`
247
+ TODO.
248
+
249
+ ## Children a component renders from a count
250
+
251
+ `Skeleton variant="lines"` renders `.skeleton-lines`' empty `<div>`s itself, `lines` of them. So
252
+ a `.skeleton-lines` whose children are just bare, empty `<div>`s becomes
253
+ `<Skeleton variant="lines" lines={N} />`, and the `<div>`s go. A class, an attribute or anything
254
+ inside one of them, or anything else beside them, keeps the element as markup with a
255
+ `children:Skeleton` TODO. A `.skeleton-block` converts like any other element, content and all.
256
+ `Skeleton` takes no helper props, so a helper class on either stays in `className`.
257
+
258
+ ## Icons a component builds from props
259
+
260
+ `IconText` builds its icons from props, so an `.icon-text` converts together with what's inside
261
+ it: each `.icon` becomes one icon's props, and a bare `<span>` of text right after one becomes that
262
+ icon's text. One icon is written as `iconProps`, with its text as the children, and more than one
263
+ as `items`.
264
+
265
+ ```jsx
266
+ <span className="icon-text">
267
+ <span className="icon" aria-label="Home">
268
+ <i className="fas fa-home"></i>
269
+ </span>
270
+ <span>Home</span>
271
+ </span>
272
+ // becomes
273
+ <IconText iconProps={{ library: "fa", name: "home", ariaLabel: "Home" }}>Home</IconText>
274
+ ```
275
+
276
+ The glyph is read from the `<i>`: its Font Awesome style class (`fas`, `far`, `fa-solid`, ...) or
277
+ `mdi`, the one class that names the glyph (`fa-home` as `name: "home"`), and the rest as
278
+ `features`. `library` is always written, so a `ConfigProvider` with another `iconLibrary` doesn't
279
+ change what renders. The `.icon`'s own classes and attributes join the glyph's props as they
280
+ would on `Icon`, with `aria-label` as `ariaLabel`.
281
+
282
+ It converts only when every `.icon` inside converts to `Icon` on its own and holds a bare, empty
283
+ `<i>` naming a Font Awesome or Material Design Icons glyph, and the only other children are those
284
+ texts, bare and static. Anything else keeps it as markup with a `children:IconText` TODO, and the
285
+ `.icon`s inside convert on their own.
286
+
287
+ ## A tree a component renders from props
288
+
289
+ `File` renders the whole `.file` tree from props, so a `.file` converts together with everything
290
+ inside it. The `<input>`'s attributes become `File`'s own (it puts the ones it doesn't read on the
291
+ `<input>`), its other classes become `inputClassName`, the `.file-label` `<span>`'s content becomes
292
+ `buttonLabel` (left out when it's `File`'s own default, `Choose a file…`), each `.file-icon`'s
293
+ content becomes `iconLeft` or `iconRight`, and the `.file-name`'s text becomes `fileName` beside
294
+ `hasName`.
295
+
296
+ ```jsx
297
+ <div className="field">
298
+ <div className="file has-name">
299
+ <label className="file-label">
300
+ <input className="file-input" type="file" name="cv" />
301
+ <span className="file-cta">
302
+ <span className="file-icon"><i className="fas fa-upload"></i></span>
303
+ <span className="file-label">Upload</span>
304
+ </span>
305
+ <span className="file-name">cv.pdf</span>
306
+ </label>
307
+ </div>
308
+ </div>
309
+ // becomes
310
+ <Field>
311
+ <File hasName name="cv" buttonLabel="Upload" iconLeft={<i className="fas fa-upload"></i>} fileName="cv.pdf" />
312
+ </Field>
313
+ ```
314
+
315
+ It converts only inside a `Field`, a bestax one already in the file or a `.field` that converts
316
+ in the same run, since outside one `File` renders a `.field` of its own. The tree has to be exactly
317
+ the one `File` renders, and the `.file` itself can carry no attribute but a `key`, since `File`
318
+ puts the attributes it's given on its `<input>`. A color class stays a class, since `color`
319
+ renders `has-text-<color>` too, and so does `is-centered`, which `isCentered` renders nothing of
320
+ beside `isRight`. Anything else keeps it as markup with a `children:File`, `context:File` or
321
+ `attr` TODO.
322
+
323
+ ## Families this source leaves as markup
324
+
325
+ Their markup doesn't map element by element (the bestax component renders parts of its own, or
326
+ adds attributes), so the family's outermost class gets a `family:<class>` TODO and the markup
327
+ stays. [unmappables.md](unmappables.md) has the recipe for each. The families are Checkbox,
328
+ Checkboxes, Dropdown, the menu's `.menu-item`, Message, Modal's root and close
329
+ button, the navbar's burger and dropdown link, the panel's icon, Radio and Radios.
330
+
331
+ ## Classes left alone
332
+
333
+ `.help`, `.label`, `.hero-buttons`, `.hero-video`, `.theme-dark`, `.theme-light`, `.fa`,
334
+ `.marginless`, `.paddingless`, `.navbar-content`, `.navbar-tabs` and `.panel-list` are valid
335
+ Bulma with nothing in bestax to convert to. `.loader` is left alone as well, although bestax's
336
+ `Loader` renders the same element: swap it in by hand for its progressbar role and accessible name.
337
+ An element carrying one stays as written, and gets no TODO.
@@ -0,0 +1,230 @@
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
+ | `.breadcrumb` → `Breadcrumb` | `is-centered`, `is-right` | `alignment` |
82
+ | `.breadcrumb` → `Breadcrumb` | `has-arrow-separator`, `has-bullet-separator`, `has-dot-separator`, `has-succeeds-separator` | `separator` |
83
+ | `.breadcrumb` → `Breadcrumb` | `is-small`, `is-medium`, `is-large` | `size` |
84
+ | `.card-header-title` → `Card.Header.Title` | `is-centered` | `centered` |
85
+ | `.content` → `Content` | `is-small`, `is-medium`, `is-large` | `size` |
86
+ | `.delete` → `Delete` | `is-small`, `is-medium`, `is-large` | `size` |
87
+ | `.field` → `Field` | `is-horizontal`, `is-grouped`, `has-addons`, `is-narrow` | `horizontal`, `grouped`, `hasAddons`, `narrow` |
88
+ | `.grid` → `Grid` | `is-gap-{step}`, `is-column-gap-{step}`, `is-row-gap-{step}`, `0` to `8` in half steps (`is-gap-1.5`) | `gap`, `columnGap`, `rowGap` |
89
+ | `.grid` → `Grid` | `is-col-min-{1-32}` | `minCol` (a number: `minCol={8}`) |
90
+ | `.fixed-grid` → `Grid isFixed` (folded) | `has-{1-12}-cols`, `has-{1-12}-cols-{viewport}`, `has-auto-count` | `fixedCols`, `fixedCols{Viewport}` (numbers: `fixedCols={3}`), `fixedCols="auto"` |
91
+ | `.cell` → `Cell` | `is-col-start-{n}`, `is-col-from-end-{n}`, `is-col-span-{n}`, `is-row-start-{n}`, `is-row-from-end-{n}`, `is-row-span-{n}`, for `n` from 1 to 12 | `colStart`, `colFromEnd`, `colSpan`, `rowStart`, `rowFromEnd`, `rowSpan` (numbers: `colSpan={2}`) |
92
+ | `.field-label` → `Field.Label` | `is-small`, `is-normal`, `is-medium`, `is-large` | `size` |
93
+ | `.control` → `Control` | `has-icons-left`, `has-icons-right`, `is-loading`, `is-expanded` | `hasIconsLeft`, `hasIconsRight`, `isLoading`, `isExpanded` |
94
+ | `.control` → `Control`, `.input` → `InputBase`, `.textarea` → `TextAreaBase` | `is-small`, `is-medium`, `is-large` | `size` |
95
+ | `.input` → `InputBase`, `.textarea` → `TextAreaBase` | `is-rounded`, `is-static`, `is-hovered`, `is-focused` | `isRounded`, `isStatic`, `isHovered`, `isFocused` |
96
+ | `.input` → `InputBase` | `is-loading` | `isLoading` |
97
+ | `.textarea` → `TextAreaBase` | `is-active`, `has-fixed-size` | `isActive`, `hasFixedSize` |
98
+ | `.select` → `SelectBase` | `is-small`, `is-medium`, `is-large` | `size` |
99
+ | `.select` → `SelectBase` | `is-rounded`, `is-loading`, `is-active`, `is-fullwidth` | `isRounded`, `isLoading`, `isActive`, `isFullwidth` |
100
+ | `.select` → `SelectBase` | `is-multiple`, around a `<select multiple>` | `multiple` (the `<select>`'s `size` becomes the number `multipleSize`) |
101
+ | `.file` → `File` | `is-small`, `is-medium`, `is-large` | `size` |
102
+ | `.file` → `File` | `is-boxed`, `is-fullwidth`, `has-name`, `is-right` | `isBoxed`, `isFullwidth`, `hasName`, `isRight` |
103
+ | the `<select>` inside `.select` | `is-hovered`, `is-focused` | `isHovered`, `isFocused` |
104
+ | `.hero` → `Hero` | `is-primary`, `is-link`, `is-info`, `is-success`, `is-warning`, `is-danger`, `is-black`, `is-white`, `is-light`, `is-dark` | `color` |
105
+ | `.hero` → `Hero` | `is-small`, `is-medium`, `is-large`, `is-fullheight`, `is-fullheight-with-navbar` | `size` |
106
+ | `.image` → `Image` | `is-16x16`, `is-24x24`, `is-32x32`, `is-48x48`, `is-64x64`, `is-96x96`, `is-128x128`, `is-square` | `size` (a ratio such as `is-4by3` stays a class, since `size` would add `has-ratio`) |
107
+ | the `<img>` inside `.image` | `is-rounded` | `isRounded` |
108
+ | `.icon` → `Icon` | `is-small`, `is-medium`, `is-large` | `size` |
109
+ | `.tabs` → `Tabs` | `is-centered`, `is-right`, `is-left` | `align` |
110
+ | `.tabs` → `Tabs` | `is-small`, `is-medium`, `is-large` | `size` |
111
+ | `.tabs` → `Tabs` | `is-fullwidth`, `is-boxed`, `is-toggle`, `is-toggle-rounded` | `isFullwidth`, `boxed`, `toggle`, `rounded` (`is-<color>` stays a class: `color` is deprecated) |
112
+ | the `<a>` in a menu item → `Menu.Item` | `is-active` | `active` |
113
+ | `.pagination` → `Pagination` | `is-small`, `is-medium`, `is-large` | `size` |
114
+ | `.pagination` → `Pagination` | `is-centered`, `is-right`, `is-rounded` | `align`, `rounded` (`is-<color>` stays a class: `color` is deprecated) |
115
+ | `.pagination-link` → `Pagination.Link` | `is-current`, beside an `aria-current` of the element's own | `active` (without one, it stays a class; `is-disabled` stays a class) |
116
+ | `.level` → `Level` | `is-mobile` | `isMobile` |
117
+ | `.navbar` → `Navbar` | the ten `.hero` colors | `color` |
118
+ | `.navbar` → `Navbar` | `is-fixed-top`, `is-fixed-bottom` | `fixed` (`top`, `bottom`) |
119
+ | `.navbar` → `Navbar` | `is-transparent` | `transparent` |
120
+ | `.navbar-menu` → `Navbar.Menu`, `.navbar-item` → `Navbar.Item` | `is-active` | `active` |
121
+ | `.navbar-dropdown` → `Navbar.DropdownMenu` | `is-right`, `is-up` | `right`, `up` |
122
+ | `.notification` → `Notification` | `is-primary`, `is-link`, `is-info`, `is-success`, `is-warning`, `is-danger`, `is-black`, `is-white`, `is-dark` | `color` |
123
+ | `.notification` → `Notification` | `is-light` | `isLight` |
124
+ | `.progress` → `Progress` | the ten `.hero` colors | `color` |
125
+ | `.progress` → `Progress` | `is-small`, `is-medium`, `is-large` | `size` |
126
+ | `.section` → `Section` | `is-medium`, `is-large` | `size` |
127
+ | `.skeleton-lines` → `Skeleton variant="lines"` | its bare, empty `<div>`s | `lines` (their count, as a number: `lines={5}`) |
128
+ | `.table` → `Table` | `is-bordered`, `is-striped`, `is-narrow`, `is-hoverable`, `is-fullwidth` | `isBordered`, `isStriped`, `isNarrow`, `isHoverable`, `isFullwidth` |
129
+ | `.tag` → `Tag` | `is-primary`, `is-link`, `is-info`, `is-success`, `is-warning`, `is-danger`, `is-black`, `is-dark`, `is-white` | `color` |
130
+ | `.tag` → `Tag` | `is-light`, `is-rounded`, `is-hoverable` | `isLight`, `isRounded`, `isHoverable` |
131
+ | `.tag` → `Tag` | `is-medium`, `is-large` | `size` |
132
+
133
+ `Progress` takes `value` and `max` as numbers: `value="40"` becomes `value={40}`. An
134
+ expression (`value={percent}`) carries over as written, so if it holds a string the migrated
135
+ file fails to typecheck while still rendering the same; wrap it in `Number(…)`. `Delete`
136
+ converts only with `type` and `aria-label` set (see `defaults:<Target>` in the unmappables),
137
+ and a `type="button"` is dropped, since bestax renders it by itself. `Card.Header.Icon` likewise
138
+ converts only with an `aria-label` and a `type` of `button`, `submit` or `reset`, since it renders
139
+ `aria-label="more options"` and `type="button"` otherwise.
140
+ `.tag`'s `is-delete` stays a class: `isDelete` turns the tag into a `<button>`. `.navbar`'s
141
+ `is-spaced` and `has-shadow`, and a `.navbar-item`'s `has-dropdown` and `is-hoverable`, stay
142
+ classes too: bestax has no prop for them on those components. So do a `.field`'s
143
+ `has-addons-centered`, `has-addons-right` and `is-grouped-*`, because the `hasAddons` and
144
+ `grouped` values that render them render `has-addons` and `is-grouped` as well, and an input's,
145
+ textarea's or select's color, because `color` renders `has-text-<color>` on it too. On a
146
+ `.columns`, the gap helpers (`is-gap-*`, `is-column-gap-*`, `is-row-gap-*`) stay classes as well:
147
+ `Columns`' own `gap` is its gutter (`is-<step>`), and it leaves the column and row gap helpers out.
148
+
149
+ ## Helper classes
150
+
151
+ These convert on every component above and on the plain-tag wrappers.
152
+
153
+ Colors are `primary`, `link`, `info`, `success`, `warning`, `danger`, `black`, `black-bis`,
154
+ `black-ter`, `grey-darker`, `grey-dark`, `grey`, `grey-light`, `grey-lighter`, `white`,
155
+ `white-bis`, `white-ter`, `light`, `dark`, `inherit` and `current`. Gap steps are `0` to `8` in
156
+ half steps (`0`, `0.5`, `1`, … `7.5`, `8`). Overflow values are `auto`, `clip`, `hidden`, `scroll`
157
+ and `visible`. Ratios are `1by1`, `5by4`, `4by3`, `3by2`, `5by3`, `16by9`, `2by1`, `3by1`,
158
+ `4by5`, `3by4`, `2by3`, `3by5`, `9by16`, `1by2` and `1by3`.
159
+
160
+ | Classes | Prop |
161
+ | --------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
162
+ | `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` |
163
+ | `p-{n}`, `pt-{n}`, `pr-{n}`, `pb-{n}`, `pl-{n}`, `px-{n}`, `py-{n}` | `p`, `pt`, `pr`, `pb`, `pl`, `px`, `py` |
164
+ | `has-text-{color}` | `textColor` (on `Menu`, `Menu.Label`, `Menu.List` and `Table`, `color`) |
165
+ | `has-background-{color}` | `bgColor` (on `Menu`, `Menu.Label`, `Menu.List`, `Tag`, `File`, `InputBase`, `TextAreaBase` and `SelectBase`, `backgroundColor`) |
166
+ | `is-size-1` … `is-size-7`, and `-{viewport}` | `textSize`, `textSize{Viewport}` |
167
+ | `has-text-centered`, `-justified`, `-left`, `-right`, and `-{viewport}` | `textAlign`, `textAlign{Viewport}` |
168
+ | `is-capitalized`, `is-lowercase`, `is-uppercase`, `is-italic` | `textTransform` |
169
+ | `has-text-weight-light`, `-normal`, `-medium`, `-semibold`, `-bold` | `textWeight` |
170
+ | `is-family-sans-serif`, `-monospace`, `-primary`, `-secondary`, `-code` | `fontFamily` |
171
+ | `is-block`, `is-flex`, `is-inline`, `is-inline-block`, `is-inline-flex`, `is-grid` | `display` |
172
+ | the same with any of the nine viewports, `touch` and the `-only` ones included | `display{Viewport}` |
173
+ | `is-hidden`, `is-invisible`, `is-sr-only` | `visibility` |
174
+ | `is-hidden-{viewport}`, `is-invisible-{viewport}`, all nine viewports | `visibility{Viewport}` |
175
+ | `is-flex-direction-*`, `is-flex-wrap-*`, `is-justify-content-*`, `is-align-content-*`, `is-align-items-*` | `flexDirection`, `flexWrap`, `justifyContent`, `alignContent`, `alignItems` |
176
+ | `is-align-self-*`, `is-flex-grow-*`, `is-flex-shrink-*` | `alignSelf`, `flexGrow`, `flexShrink` |
177
+ | `is-pulled-left`, `is-pulled-right` | `float` |
178
+ | `is-gap-{step}`, `is-column-gap-{step}`, `is-row-gap-{step}` | `gap`, `columnGap`, `rowGap` |
179
+ | `is-gapless` | `gapless` |
180
+ | `is-position-absolute`, `-fixed`, `-relative`, `-static`, `-sticky` | `pos` |
181
+ | `is-relative` | `relative` |
182
+ | `is-clipped` | `overflow="clipped"` |
183
+ | `is-overflow-{value}`, `is-overflow-x-{value}`, `is-overflow-y-{value}` | `overflow`, `overflowX`, `overflowY` |
184
+ | `is-overlay`, `is-skeleton`, `is-clearfix` | `overlay`, `skeleton`, `clearfix` |
185
+ | `is-unselectable`, `is-clickable` | `interaction` |
186
+ | `is-radiusless`, `has-radius-small`, `-normal`, `-large`, `-rounded` | `radius` |
187
+ | `is-shadowless` | `shadow` |
188
+ | `is-aspect-ratio-{ratio}` | `aspectRatio` |
189
+ | `is-mobile`, `is-narrow` (where the component has no prop of its own for them) | `responsive` |
190
+
191
+ Where a component renders a color class through no typed prop, the class stays: `has-text-*`
192
+ on `Breadcrumb`, `Hero`, `Navbar.DropdownMenu`, `Navbar.Divider`, `Field.Label`, `Field.Body`,
193
+ `Control`, `File`, `InputBase`, `TextAreaBase`, `SelectBase`, `Progress`, `Skeleton`, `Tag`, `Tags`,
194
+ `Modal.Background`, `Modal.Content`, `Modal.Card`, `Modal.Card.Head`, `Modal.Card.Title`,
195
+ `Modal.Card.Body`, `Modal.Card.Foot`, `Pagination.Previous`, `Pagination.Next`,
196
+ `Pagination.Ellipsis`, `Panel`, `Panel.Heading`, `Panel.Tabs`, `Panel.Block` and `Tabs`;
197
+ `has-background-*` on `Breadcrumb`,
198
+ `Navbar.Brand`, `Navbar.Menu`, `Navbar.Start`, `Navbar.End`, `Navbar.DropdownMenu`,
199
+ `Navbar.Divider`, `Field.Label`, `Field.Body`, `Control`, `Notification`, `Progress`, `Skeleton`,
200
+ `Table`, `Tags`, `Modal.Background`, `Modal.Content`, `Modal.Card`, `Modal.Card.Head`,
201
+ `Modal.Card.Title`, `Modal.Card.Body`, `Modal.Card.Foot`, `Pagination.Previous`,
202
+ `Pagination.Next`, `Pagination.Ellipsis`, `Panel`, `Panel.Heading`, `Panel.Tabs`, `Panel.Block`
203
+ and `Tabs`. `Navbar.DropdownMenu`, `Navbar.Divider`, `Field.Label`, `Field.Body`, `Control`,
204
+ `Skeleton`, Modal's parts, `Pagination.Previous`, `Pagination.Next`, `Pagination.Ellipsis`,
205
+ `Panel.Heading`, `Panel.Tabs` and `Panel.Block` take no helper props the way the codemod needs, so every helper class on them
206
+ stays. A `.panel`'s `is-<color>` stays a class too, since `Panel`'s `color` renders
207
+ `has-text-<color>` beside it.
208
+
209
+ Some classes stay put because of how bestax renders them:
210
+
211
+ - A base `display` class next to a per-viewport one (`is-flex is-block-mobile`) keeps the base
212
+ class: bestax drops the base `display` whenever a per-viewport one is set.
213
+ - The flex-container classes (`is-justify-content-*` and the others in that row) convert only
214
+ beside a flex `display` prop, the only place bestax renders them.
215
+ - `is-gapless` beside an `is-gap-*` keeps its class: bestax drops `gapless` when a `gap` is set.
216
+ On a `.grid` both convert, since `Grid`'s own `gap` renders its class beside `gapless`.
217
+ - `is-relative` beside an `is-position-*` keeps its class: `pos` decides the position, and bestax
218
+ drops `relative` beside it. `is-overlay` converts beside either.
219
+ - A both-axes overflow (`is-overflow-hidden`, `is-clipped`) beside an `is-overflow-x-*` or
220
+ `is-overflow-y-*` keeps its class: beside an axis prop, bestax writes `overflow` per axis
221
+ instead of as its own class.
222
+ - `is-hidden` becomes `visibility="hidden"`, which renders the same class and doesn't interact
223
+ with `display`.
224
+
225
+ ## Classes that stay classes
226
+
227
+ Color shades (`has-text-primary-65`), the `-touch` and `-only` breakpoints of text size and
228
+ alignment, Grid and `.image` modifiers away from their own element, an `.image` ratio, and the
229
+ Bulma helpers bestax has no prop for (`is-display-*`, `is-visibility-*`, `is-float-*`,
230
+ `is-clear-*`, …) stay in `className`. They render exactly as before.