bestax-migrate 0.0.1

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 (47) hide show
  1. package/README.md +59 -0
  2. package/dist/cli.d.ts +22 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +225 -0
  5. package/dist/index.d.ts +7 -0
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +12 -0
  8. package/dist/report.d.ts +24 -0
  9. package/dist/report.d.ts.map +1 -0
  10. package/dist/report.js +66 -0
  11. package/dist/runner.d.ts +16 -0
  12. package/dist/runner.d.ts.map +1 -0
  13. package/dist/runner.js +69 -0
  14. package/dist/sources/react-bulma-components/deps.d.ts +9 -0
  15. package/dist/sources/react-bulma-components/deps.d.ts.map +1 -0
  16. package/dist/sources/react-bulma-components/deps.js +96 -0
  17. package/dist/sources/react-bulma-components/index.d.ts +3 -0
  18. package/dist/sources/react-bulma-components/index.d.ts.map +1 -0
  19. package/dist/sources/react-bulma-components/index.js +10 -0
  20. package/dist/sources/react-bulma-components/jsx-utils.d.ts +69 -0
  21. package/dist/sources/react-bulma-components/jsx-utils.d.ts.map +1 -0
  22. package/dist/sources/react-bulma-components/jsx-utils.js +130 -0
  23. package/dist/sources/react-bulma-components/mapping.d.ts +31 -0
  24. package/dist/sources/react-bulma-components/mapping.d.ts.map +1 -0
  25. package/dist/sources/react-bulma-components/mapping.js +852 -0
  26. package/dist/sources/react-bulma-components/props.d.ts +15 -0
  27. package/dist/sources/react-bulma-components/props.d.ts.map +1 -0
  28. package/dist/sources/react-bulma-components/props.js +124 -0
  29. package/dist/sources/react-bulma-components/responsive.d.ts +17 -0
  30. package/dist/sources/react-bulma-components/responsive.d.ts.map +1 -0
  31. package/dist/sources/react-bulma-components/responsive.js +113 -0
  32. package/dist/sources/react-bulma-components/specials.d.ts +23 -0
  33. package/dist/sources/react-bulma-components/specials.d.ts.map +1 -0
  34. package/dist/sources/react-bulma-components/specials.js +546 -0
  35. package/dist/sources/react-bulma-components/styles.d.ts +13 -0
  36. package/dist/sources/react-bulma-components/styles.d.ts.map +1 -0
  37. package/dist/sources/react-bulma-components/styles.js +199 -0
  38. package/dist/sources/react-bulma-components/transform.d.ts +19 -0
  39. package/dist/sources/react-bulma-components/transform.d.ts.map +1 -0
  40. package/dist/sources/react-bulma-components/transform.js +495 -0
  41. package/dist/sources/registry.d.ts +9 -0
  42. package/dist/sources/registry.d.ts.map +1 -0
  43. package/dist/sources/registry.js +14 -0
  44. package/dist/types.d.ts +122 -0
  45. package/dist/types.d.ts.map +1 -0
  46. package/dist/types.js +9 -0
  47. package/package.json +74 -0
@@ -0,0 +1,852 @@
1
+ /**
2
+ * Declarative react-bulma-components (v4) → @allxsmith/bestax-bulma mapping.
3
+ *
4
+ * Every entry was verified against the react-bulma-components 4.1.0 type
5
+ * declarations on one side and bulma-ui/src on the other. `special` keys are
6
+ * implemented in transform.ts — they cover structural conversions a rename
7
+ * table can't express (align-driven targets, child rewrites, unwrapping).
8
+ *
9
+ * The mapping-coverage test asserts every name in RBC_EXPORTS (and every
10
+ * compound sub listed there) resolves to an entry here, so extending coverage
11
+ * later is a table edit that cannot silently regress.
12
+ */
13
+ const DOCS = 'https://bestax.io/docs';
14
+ /** Bulma spacing values are string unions in bestax ('0'–'6'). */
15
+ const spacing = { numberToString: true };
16
+ /**
17
+ * Universal RBC modifier props (ElementProps) → bestax useBulmaClasses props.
18
+ * Applied to every element that maps to a bestax component, after the
19
+ * component's own `props` actions.
20
+ */
21
+ export const UNIVERSAL_PROPS = {
22
+ renderAs: {
23
+ // Only some bestax components are polymorphic; those get a per-component
24
+ // `rename: 'as'` override in MAPPING. Everything else is a semantic
25
+ // element where renderAs has no equivalent.
26
+ todo: 'this bestax component has no `as` prop; restructure the element instead',
27
+ },
28
+ domRef: {
29
+ todo: 'bestax-bulma components do not take domRef; use a ref on a DOM child or wrap the component',
30
+ },
31
+ // ColorProps
32
+ backgroundColor: { rename: 'bgColor' },
33
+ textColor: {},
34
+ colorVariant: {
35
+ todo: "no direct equivalent; use isLight (Button/Notification) or a color shade like textColor='primary-dark'",
36
+ },
37
+ // TypographyProps
38
+ textSize: { numberToString: true },
39
+ textAlign: {
40
+ valueMap: {
41
+ center: 'centered',
42
+ justify: 'justified',
43
+ left: 'left',
44
+ right: 'right',
45
+ },
46
+ },
47
+ textTransform: {},
48
+ textWeight: {},
49
+ textFamily: { rename: 'fontFamily' },
50
+ italic: { booleanToProp: { name: 'textTransform', value: 'italic' } },
51
+ // SpacingProps
52
+ m: spacing,
53
+ mt: spacing,
54
+ mr: spacing,
55
+ mb: spacing,
56
+ ml: spacing,
57
+ mx: spacing,
58
+ my: spacing,
59
+ p: spacing,
60
+ pt: spacing,
61
+ pr: spacing,
62
+ pb: spacing,
63
+ pl: spacing,
64
+ px: spacing,
65
+ py: spacing,
66
+ // HelperProps
67
+ clearfix: {},
68
+ pull: { rename: 'float' },
69
+ marginless: { booleanToProp: { name: 'm', value: '0' } },
70
+ paddingless: { booleanToProp: { name: 'p', value: '0' } },
71
+ overlay: {},
72
+ clipped: { booleanToProp: { name: 'overflow', value: 'clipped' } },
73
+ radiusless: { booleanToProp: { name: 'radius', value: 'radiusless' } },
74
+ shadowless: { booleanToProp: { name: 'shadow', value: 'shadowless' } },
75
+ unselectable: {
76
+ booleanToProp: { name: 'interaction', value: 'unselectable' },
77
+ },
78
+ invisible: { booleanToProp: { name: 'visibility', value: 'invisible' } },
79
+ hidden: { booleanToProp: { name: 'visibility', value: 'hidden' } },
80
+ srOnly: { booleanToProp: { name: 'visibility', value: 'sr-only' } },
81
+ // FlexboxProps carry identical names and values in bestax
82
+ flexDirection: {},
83
+ flexWrap: {},
84
+ justifyContent: {},
85
+ alignContent: {},
86
+ alignItems: {},
87
+ // ResponsiveProps.display (top-level)
88
+ display: {
89
+ valueMap: {
90
+ block: 'block',
91
+ flex: 'flex',
92
+ inline: 'inline',
93
+ 'inline-block': 'inline-block',
94
+ 'inline-flex': 'inline-flex',
95
+ },
96
+ valueTodo: {
97
+ hidden: "use visibility='hidden' (already a separate bestax prop)",
98
+ relative: 'use the boolean `relative` prop',
99
+ },
100
+ },
101
+ };
102
+ /** Breakpoint-object props flattened by the responsive pass. */
103
+ export const RESPONSIVE_BREAKPOINTS = {
104
+ mobile: 'Mobile',
105
+ tablet: 'Tablet',
106
+ desktop: 'Desktop',
107
+ widescreen: 'Widescreen',
108
+ fullhd: 'Fullhd',
109
+ // No touch/until* helper-class variants exist in bestax-bulma.
110
+ touch: null,
111
+ untilWidescreen: null,
112
+ untilFullhd: null,
113
+ };
114
+ const activeKept = { active: {} };
115
+ export const MAPPING = {
116
+ Block: { status: 'mapped', target: 'Block' },
117
+ Box: { status: 'mapped', target: 'Box' },
118
+ Breadcrumb: {
119
+ status: 'mapped',
120
+ target: 'Breadcrumb',
121
+ props: {
122
+ align: {
123
+ rename: 'alignment',
124
+ valueMap: { center: 'centered', right: 'right' },
125
+ },
126
+ separator: {},
127
+ size: {},
128
+ },
129
+ subs: {
130
+ // bestax Breadcrumb renders <ul>{children}</ul>; items are plain <li><a>.
131
+ Item: { status: 'mapped', special: 'breadcrumb-item' },
132
+ },
133
+ },
134
+ Button: {
135
+ status: 'mapped',
136
+ target: 'Button',
137
+ special: 'button',
138
+ props: {
139
+ renderAs: { rename: 'as' },
140
+ color: {
141
+ valueTodo: {
142
+ 'black-bis': 'shade colors are not Button colors in bestax; use bgColor/textColor',
143
+ 'black-ter': 'shade colors are not Button colors in bestax; use bgColor/textColor',
144
+ 'white-bis': 'shade colors are not Button colors in bestax; use bgColor/textColor',
145
+ 'white-ter': 'shade colors are not Button colors in bestax; use bgColor/textColor',
146
+ 'grey-darker': 'shade colors are not Button colors in bestax; use bgColor/textColor',
147
+ 'grey-dark': 'shade colors are not Button colors in bestax; use bgColor/textColor',
148
+ 'grey-light': 'shade colors are not Button colors in bestax; use bgColor/textColor',
149
+ 'grey-lighter': 'shade colors are not Button colors in bestax; use bgColor/textColor',
150
+ },
151
+ },
152
+ size: {},
153
+ state: {
154
+ valueMap: {
155
+ active: 'isActive',
156
+ focus: 'isFocused',
157
+ hover: 'isHovered',
158
+ },
159
+ valueToProp: true,
160
+ },
161
+ outlined: { booleanToProp: { name: 'isOutlined' } },
162
+ inverted: { booleanToProp: { name: 'isInverted' } },
163
+ loading: { booleanToProp: { name: 'isLoading' } },
164
+ fullwidth: { booleanToProp: { name: 'isFullWidth' } },
165
+ rounded: { booleanToProp: { name: 'isRounded' } },
166
+ text: { booleanToProp: { name: 'color', value: 'text' } },
167
+ isSelected: {
168
+ todo: 'no bestax equivalent (Bulma is-selected in button groups)',
169
+ },
170
+ submit: { booleanToProp: { name: 'type', value: 'submit' } },
171
+ reset: { booleanToProp: { name: 'type', value: 'reset' } },
172
+ },
173
+ subs: {
174
+ Group: {
175
+ status: 'mapped',
176
+ target: 'Buttons',
177
+ props: {
178
+ hasAddons: {},
179
+ align: {
180
+ valueMap: { center: 'isCentered', right: 'isRight' },
181
+ valueToProp: true,
182
+ },
183
+ size: {
184
+ todo: 'bestax Buttons has no group size; set size on each Button',
185
+ },
186
+ },
187
+ },
188
+ },
189
+ },
190
+ Card: {
191
+ status: 'mapped',
192
+ target: 'Card',
193
+ subs: {
194
+ Image: {
195
+ // RBC Card.Image takes ImageProps itself; bestax Card.Image wraps an
196
+ // inner <Image> — the special moves the props onto a new child.
197
+ status: 'mapped',
198
+ target: 'Card.Image',
199
+ special: 'card-image',
200
+ },
201
+ Content: { status: 'mapped', target: 'Card.Content' },
202
+ Header: {
203
+ status: 'mapped',
204
+ target: 'Card.Header',
205
+ subs: {
206
+ Title: { status: 'mapped', target: 'Card.Header.Title' },
207
+ Icon: { status: 'mapped', target: 'Card.Header.Icon' },
208
+ },
209
+ },
210
+ Footer: {
211
+ status: 'mapped',
212
+ target: 'Card.Footer',
213
+ subs: {
214
+ Item: { status: 'mapped', target: 'Card.FooterItem' },
215
+ },
216
+ },
217
+ },
218
+ },
219
+ Columns: {
220
+ status: 'mapped',
221
+ target: 'Columns',
222
+ special: 'columns',
223
+ props: {
224
+ multiline: { booleanToProp: { name: 'isMultiline' } },
225
+ centered: { booleanToProp: { name: 'isCentered' } },
226
+ vCentered: { booleanToProp: { name: 'isVCentered' } },
227
+ breakpoint: {
228
+ valueMap: { mobile: 'isMobile', desktop: 'isDesktop' },
229
+ valueToProp: true,
230
+ valueTodo: {
231
+ tablet: 'is-tablet is the Bulma default; remove the prop',
232
+ touch: 'no bestax Columns touch breakpoint',
233
+ widescreen: 'no bestax Columns widescreen breakpoint',
234
+ fullhd: 'no bestax Columns fullhd breakpoint',
235
+ },
236
+ },
237
+ gap: {},
238
+ },
239
+ subs: {
240
+ Column: {
241
+ status: 'mapped',
242
+ target: 'Column',
243
+ special: 'column',
244
+ props: {
245
+ size: {},
246
+ offset: {},
247
+ narrow: { booleanToProp: { name: 'isNarrow' } },
248
+ },
249
+ },
250
+ },
251
+ },
252
+ Container: {
253
+ status: 'mapped',
254
+ target: 'Container',
255
+ props: {
256
+ max: { booleanToProp: { name: 'isMax' } },
257
+ breakpoint: {
258
+ // 'tablet' / 'desktop' stay as breakpoint="..." (same prop in bestax)
259
+ valueMap: {
260
+ fluid: 'fluid',
261
+ widescreen: 'widescreen',
262
+ fullhd: 'fullhd',
263
+ },
264
+ valueToProp: true,
265
+ valueTodo: {
266
+ touch: 'no bestax Container touch breakpoint',
267
+ mobile: 'no bestax Container mobile breakpoint',
268
+ },
269
+ },
270
+ },
271
+ },
272
+ Content: {
273
+ status: 'mapped',
274
+ target: 'Content',
275
+ props: { size: {} },
276
+ },
277
+ Dropdown: {
278
+ status: 'partial',
279
+ target: 'Dropdown',
280
+ props: {
281
+ label: {},
282
+ color: {},
283
+ hoverable: {},
284
+ right: {},
285
+ up: {},
286
+ disabled: {},
287
+ align: { valueMap: { right: 'right' }, valueToProp: true },
288
+ closeOnSelect: { rename: 'closeOnClick' },
289
+ value: {
290
+ todo: 'bestax Dropdown is compositional: track the selection yourself and set onClick on each Dropdown.Item',
291
+ },
292
+ onChange: {
293
+ todo: 'bestax Dropdown is compositional: track the selection yourself and set onClick on each Dropdown.Item',
294
+ },
295
+ icon: { todo: 'render the icon inside the label instead' },
296
+ menuId: { drop: true },
297
+ },
298
+ subs: {
299
+ Item: {
300
+ status: 'partial',
301
+ target: 'Dropdown.Item',
302
+ props: {
303
+ renderAs: { rename: 'as' },
304
+ value: {
305
+ todo: 'bestax Dropdown.Item has no value prop; use onClick and your own state',
306
+ },
307
+ },
308
+ },
309
+ Divider: { status: 'mapped', target: 'Dropdown.Divider' },
310
+ },
311
+ },
312
+ Element: {
313
+ status: 'todo',
314
+ todo: `no generic Element in bestax-bulma; use a semantic component (Block, Box, …) with helper props, or plain JSX with classNames — see ${DOCS}/api/helpers/usebulmaclasses`,
315
+ },
316
+ Footer: {
317
+ status: 'mapped',
318
+ target: 'Footer',
319
+ props: { renderAs: { rename: 'as' } },
320
+ },
321
+ Form: {
322
+ // Namespace only — <Form> itself is never rendered in RBC.
323
+ status: 'mapped',
324
+ subs: {
325
+ Field: {
326
+ status: 'mapped',
327
+ target: 'Field',
328
+ special: 'field',
329
+ props: {
330
+ horizontal: {},
331
+ multiline: { drop: true }, // folded into grouped='multiline' by the special
332
+ kind: { drop: true },
333
+ align: { drop: true },
334
+ },
335
+ subs: {
336
+ Label: {
337
+ status: 'mapped',
338
+ target: 'FieldLabel',
339
+ props: { size: {} },
340
+ },
341
+ Body: { status: 'mapped', target: 'FieldBody' },
342
+ },
343
+ },
344
+ Control: {
345
+ status: 'mapped',
346
+ target: 'Control',
347
+ props: {
348
+ fullwidth: { booleanToProp: { name: 'isExpanded' } },
349
+ loading: { booleanToProp: { name: 'isLoading' } },
350
+ iconType: {
351
+ todo: 'use iconLeft/iconRight props on bestax Control instead',
352
+ },
353
+ },
354
+ },
355
+ Input: {
356
+ status: 'mapped',
357
+ target: 'Input',
358
+ props: {
359
+ size: {},
360
+ color: {},
361
+ isStatic: {},
362
+ rounded: { booleanToProp: { name: 'isRounded' } },
363
+ status: {
364
+ valueMap: { focus: 'isFocused', hover: 'isHovered' },
365
+ valueToProp: true,
366
+ },
367
+ },
368
+ },
369
+ Label: { status: 'mapped', special: 'plain-label' },
370
+ Textarea: {
371
+ status: 'mapped',
372
+ target: 'TextArea',
373
+ props: {
374
+ size: {},
375
+ color: {},
376
+ fixedSize: { booleanToProp: { name: 'hasFixedSize' } },
377
+ },
378
+ },
379
+ Select: {
380
+ status: 'mapped',
381
+ target: 'Select',
382
+ props: {
383
+ size: {},
384
+ color: {},
385
+ multiple: {},
386
+ loading: { booleanToProp: { name: 'isLoading' } },
387
+ fullwidth: { booleanToProp: { name: 'isFullwidth' } },
388
+ status: {
389
+ valueMap: { focus: 'isFocused', hover: 'isHovered' },
390
+ valueToProp: true,
391
+ },
392
+ },
393
+ },
394
+ Checkbox: { status: 'mapped', target: 'Checkbox' },
395
+ Radio: { status: 'mapped', target: 'Radio' },
396
+ Help: { status: 'mapped', special: 'plain-help' },
397
+ InputFile: {
398
+ status: 'partial',
399
+ target: 'File',
400
+ special: 'input-file',
401
+ props: {
402
+ color: {},
403
+ size: {},
404
+ boxed: { booleanToProp: { name: 'isBoxed' } },
405
+ fullwidth: { booleanToProp: { name: 'isFullwidth' } },
406
+ align: {
407
+ valueMap: { center: 'isCentered', right: 'isRight' },
408
+ valueToProp: true,
409
+ },
410
+ label: { rename: 'buttonLabel' },
411
+ icon: { rename: 'iconLeft' },
412
+ inputProps: { todo: 'spread these onto bestax File directly' },
413
+ },
414
+ },
415
+ },
416
+ },
417
+ Heading: {
418
+ status: 'mapped',
419
+ special: 'heading',
420
+ props: {
421
+ renderAs: { rename: 'as' },
422
+ size: { numberToString: true },
423
+ weight: { rename: 'textWeight' },
424
+ spaced: { booleanToProp: { name: 'isSpaced' } },
425
+ // `subtitle` / `heading` are consumed by the special handler.
426
+ },
427
+ },
428
+ Hero: {
429
+ status: 'mapped',
430
+ target: 'Hero',
431
+ props: {
432
+ color: {},
433
+ size: {
434
+ valueTodo: {
435
+ halfheight: 'bestax Hero has no halfheight size; set a height via CSS or use size="medium"',
436
+ },
437
+ },
438
+ gradient: {
439
+ todo: 'Bulma v1 removed is-bold gradients; delete or restyle',
440
+ },
441
+ hasNavbar: { booleanToProp: { name: 'fullheightWithNavbar' } },
442
+ },
443
+ subs: {
444
+ Header: { status: 'mapped', target: 'Hero.Head' },
445
+ Body: { status: 'mapped', target: 'Hero.Body' },
446
+ Footer: { status: 'mapped', target: 'Hero.Foot' },
447
+ },
448
+ },
449
+ Icon: {
450
+ status: 'partial',
451
+ target: 'Icon',
452
+ special: 'icon',
453
+ props: {
454
+ icon: { rename: 'name' },
455
+ color: {},
456
+ size: {
457
+ valueTodo: { auto: 'no auto size in bestax Icon; drop the prop' },
458
+ },
459
+ align: {
460
+ todo: 'inside a Control use its hasIconsLeft/iconLeft (or right) props instead',
461
+ },
462
+ text: { todo: 'wrap the icon and text in <IconText> instead' },
463
+ },
464
+ subs: {
465
+ Text: { status: 'mapped', target: 'IconText' },
466
+ },
467
+ },
468
+ Image: {
469
+ status: 'mapped',
470
+ target: 'Image',
471
+ special: 'image',
472
+ props: {
473
+ rounded: { booleanToProp: { name: 'isRounded' } },
474
+ fallback: {
475
+ todo: 'no fallback prop in bestax Image; handle onError yourself',
476
+ },
477
+ fullwidth: {
478
+ todo: 'no fullwidth prop in bestax Image; use className="is-fullwidth"',
479
+ },
480
+ },
481
+ },
482
+ Level: {
483
+ status: 'mapped',
484
+ target: 'Level',
485
+ props: {
486
+ breakpoint: {
487
+ valueMap: { mobile: 'isMobile' },
488
+ valueToProp: true,
489
+ },
490
+ },
491
+ subs: {
492
+ Side: { status: 'mapped', special: 'level-side' },
493
+ Item: {
494
+ status: 'mapped',
495
+ target: 'Level.Item',
496
+ props: { renderAs: { rename: 'as' } },
497
+ },
498
+ },
499
+ },
500
+ Loader: {
501
+ // RBC Loader is literally <div class="loader"> and Bulma v1 still ships
502
+ // that class — a plain element is the faithful conversion (bestax
503
+ // Loading is an overlay-style component, not an inline spinner).
504
+ status: 'mapped',
505
+ special: 'plain-loader',
506
+ },
507
+ Media: {
508
+ // bestax Media has no attached compounds; the parts are flat exports.
509
+ status: 'mapped',
510
+ target: 'Media',
511
+ props: { renderAs: { rename: 'as' } },
512
+ subs: {
513
+ Item: {
514
+ status: 'mapped',
515
+ special: 'media-item',
516
+ props: { renderAs: { rename: 'as' } },
517
+ },
518
+ },
519
+ },
520
+ Menu: {
521
+ status: 'mapped',
522
+ target: 'Menu',
523
+ subs: {
524
+ List: {
525
+ status: 'mapped',
526
+ target: 'Menu.List',
527
+ special: 'menu-list',
528
+ subs: {
529
+ Item: {
530
+ status: 'mapped',
531
+ target: 'Menu.Item',
532
+ props: { active: {}, renderAs: { rename: 'as' } },
533
+ },
534
+ },
535
+ },
536
+ },
537
+ },
538
+ Message: {
539
+ status: 'mapped',
540
+ target: 'Message',
541
+ props: {
542
+ color: {},
543
+ size: {
544
+ todo: 'no size prop on bestax Message; use textSize on the body',
545
+ },
546
+ },
547
+ subs: {
548
+ Header: { status: 'mapped', target: 'Message.Header' },
549
+ Body: { status: 'mapped', target: 'Message.Body' },
550
+ },
551
+ },
552
+ Modal: {
553
+ status: 'partial',
554
+ target: 'Modal',
555
+ props: {
556
+ show: { rename: 'active' },
557
+ onClose: {},
558
+ closeOnEsc: { todo: 'bestax Modal closes on Esc by default; remove' },
559
+ closeOnBlur: {
560
+ todo: 'bestax Modal background click closes when onClose is set; remove',
561
+ },
562
+ showClose: {
563
+ todo: 'bestax Modal renders the close button when onClose is set; remove',
564
+ },
565
+ document: { drop: true },
566
+ },
567
+ subs: {
568
+ Content: { status: 'mapped', target: 'Modal.Content' },
569
+ Card: {
570
+ status: 'mapped',
571
+ target: 'Modal.Card',
572
+ subs: {
573
+ Header: {
574
+ status: 'mapped',
575
+ target: 'Modal.Card.Head',
576
+ props: {
577
+ showClose: {
578
+ todo: 'render a <Delete onClick={...}/> in the head instead',
579
+ },
580
+ onClose: {
581
+ todo: 'render a <Delete onClick={...}/> in the head instead',
582
+ },
583
+ },
584
+ },
585
+ Body: { status: 'mapped', target: 'Modal.Card.Body' },
586
+ Footer: { status: 'mapped', target: 'Modal.Card.Foot' },
587
+ Title: { status: 'mapped', target: 'Modal.Card.Title' },
588
+ },
589
+ },
590
+ },
591
+ },
592
+ Navbar: {
593
+ status: 'mapped',
594
+ target: 'Navbar',
595
+ props: {
596
+ transparent: {},
597
+ fixed: {},
598
+ color: {},
599
+ active: {
600
+ todo: 'bestax Navbar.Burger/Menu take isActive; control open state there',
601
+ },
602
+ size: { todo: 'no size prop on bestax Navbar' },
603
+ },
604
+ subs: {
605
+ Brand: { status: 'mapped', target: 'Navbar.Brand' },
606
+ Burger: { status: 'mapped', target: 'Navbar.Burger' },
607
+ Menu: { status: 'mapped', target: 'Navbar.Menu' },
608
+ Item: {
609
+ status: 'mapped',
610
+ target: 'Navbar.Item',
611
+ // The special turns an Item wrapping an RBC Navbar.Dropdown into the
612
+ // bestax Navbar.Dropdown container (hoverable/active are native there).
613
+ special: 'navbar-item',
614
+ props: {
615
+ renderAs: { rename: 'as' },
616
+ active: {},
617
+ hoverable: {
618
+ todo: 'move hoverable to the bestax Navbar.Dropdown container',
619
+ },
620
+ arrowless: { todo: 'set arrowless on bestax Navbar.Link instead' },
621
+ },
622
+ },
623
+ Dropdown: {
624
+ // RBC Navbar.Dropdown is the menu (div.navbar-dropdown); bestax calls
625
+ // that Navbar.DropdownMenu. The wrapping Item becomes the container.
626
+ status: 'mapped',
627
+ target: 'Navbar.DropdownMenu',
628
+ props: {
629
+ right: {},
630
+ up: {},
631
+ boxed: {
632
+ todo: 'no boxed prop; add className="is-boxed" to Navbar.DropdownMenu',
633
+ },
634
+ },
635
+ },
636
+ Link: {
637
+ status: 'mapped',
638
+ target: 'Navbar.Link',
639
+ props: { arrowless: {}, renderAs: { rename: 'as' } },
640
+ },
641
+ Divider: { status: 'mapped', target: 'Navbar.Divider' },
642
+ Container: { status: 'mapped', special: 'navbar-container' },
643
+ },
644
+ },
645
+ Notification: {
646
+ status: 'mapped',
647
+ target: 'Notification',
648
+ props: {
649
+ color: {},
650
+ light: { booleanToProp: { name: 'isLight' } },
651
+ },
652
+ },
653
+ Pagination: {
654
+ status: 'partial',
655
+ target: 'Pagination',
656
+ props: {
657
+ current: {},
658
+ total: {},
659
+ size: {},
660
+ disabled: {},
661
+ rounded: {},
662
+ onChange: { rename: 'onPageChange' },
663
+ align: { valueMap: { center: 'centered', right: 'right' } },
664
+ delta: { todo: 'no delta prop in bestax Pagination' },
665
+ next: { todo: 'no custom next label in bestax Pagination' },
666
+ previous: { todo: 'no custom previous label in bestax Pagination' },
667
+ showPrevNext: { todo: 'no showPrevNext prop in bestax Pagination' },
668
+ showFirstLast: { todo: 'no showFirstLast prop in bestax Pagination' },
669
+ autoHide: {
670
+ todo: 'no autoHide prop in bestax Pagination; render conditionally',
671
+ },
672
+ },
673
+ },
674
+ Panel: {
675
+ status: 'mapped',
676
+ target: 'Panel',
677
+ props: { color: {} },
678
+ subs: {
679
+ Header: { status: 'mapped', target: 'Panel.Heading' },
680
+ Tabs: {
681
+ status: 'mapped',
682
+ target: 'Panel.Tabs',
683
+ subs: {
684
+ // bestax Panel.Tabs children are plain anchors.
685
+ Tab: { status: 'mapped', special: 'panel-tab' },
686
+ },
687
+ },
688
+ Block: { status: 'mapped', target: 'Panel.Block', props: activeKept },
689
+ Icon: { status: 'partial', target: 'Panel.Icon', special: 'icon' },
690
+ },
691
+ },
692
+ Progress: {
693
+ status: 'mapped',
694
+ target: 'Progress',
695
+ props: { value: {}, max: {}, size: {}, color: {} },
696
+ },
697
+ Section: {
698
+ status: 'mapped',
699
+ target: 'Section',
700
+ props: { size: {} },
701
+ },
702
+ Table: {
703
+ status: 'mapped',
704
+ target: 'Table',
705
+ props: {
706
+ striped: { booleanToProp: { name: 'isStriped' } },
707
+ bordered: { booleanToProp: { name: 'isBordered' } },
708
+ hoverable: { booleanToProp: { name: 'isHoverable' } },
709
+ size: {
710
+ valueMap: { fullwidth: 'isFullwidth', narrow: 'isNarrow' },
711
+ valueToProp: true,
712
+ },
713
+ },
714
+ subs: {
715
+ Container: { status: 'mapped', special: 'table-container' },
716
+ },
717
+ },
718
+ Tabs: {
719
+ status: 'mapped',
720
+ target: 'Tabs',
721
+ special: 'tabs',
722
+ props: {
723
+ align: { valueMap: { center: 'centered', right: 'right' } },
724
+ size: {},
725
+ fullwidth: {},
726
+ type: {
727
+ valueMap: {
728
+ toggle: 'toggle',
729
+ boxed: 'boxed',
730
+ 'toggle-rounded': 'toggle rounded',
731
+ },
732
+ valueToProp: true,
733
+ },
734
+ },
735
+ subs: {
736
+ Tab: {
737
+ status: 'mapped',
738
+ target: 'Tabs.Item',
739
+ special: 'tab-item',
740
+ props: activeKept,
741
+ },
742
+ },
743
+ },
744
+ Tag: {
745
+ status: 'mapped',
746
+ target: 'Tag',
747
+ props: {
748
+ color: {},
749
+ size: {},
750
+ rounded: { booleanToProp: { name: 'isRounded' } },
751
+ remove: { booleanToProp: { name: 'isDelete' } },
752
+ },
753
+ subs: {
754
+ Group: {
755
+ status: 'mapped',
756
+ target: 'Tags',
757
+ props: {
758
+ hasAddons: {},
759
+ gapless: { booleanToProp: { name: 'hasAddons' } },
760
+ },
761
+ },
762
+ },
763
+ },
764
+ Tile: {
765
+ status: 'todo',
766
+ todo: `Bulma v1 replaced tiles with the Grid/Cell components — see ${DOCS}/api/grid/grid and the migration guide ${DOCS}/guides/getting-started/migration/bulma-0-9-to-1`,
767
+ },
768
+ };
769
+ /**
770
+ * The complete react-bulma-components v4.1.0 public surface, vendored from its
771
+ * src/index.d.ts + per-component declarations. The mapping-coverage test walks
772
+ * this list against MAPPING, so new RBC surface can never be silently ignored.
773
+ */
774
+ export const RBC_EXPORTS = {
775
+ Block: [],
776
+ Box: [],
777
+ Breadcrumb: ['Item'],
778
+ Button: ['Group'],
779
+ Card: [
780
+ 'Image',
781
+ 'Content',
782
+ 'Header',
783
+ 'Header.Title',
784
+ 'Header.Icon',
785
+ 'Footer',
786
+ 'Footer.Item',
787
+ ],
788
+ Columns: ['Column'],
789
+ Container: [],
790
+ Content: [],
791
+ Dropdown: ['Item', 'Divider'],
792
+ Element: [],
793
+ Footer: [],
794
+ Form: [
795
+ 'Field',
796
+ 'Field.Label',
797
+ 'Field.Body',
798
+ 'Control',
799
+ 'Input',
800
+ 'Label',
801
+ 'Textarea',
802
+ 'Select',
803
+ 'Checkbox',
804
+ 'Radio',
805
+ 'Help',
806
+ 'InputFile',
807
+ ],
808
+ Heading: [],
809
+ Hero: ['Header', 'Body', 'Footer'],
810
+ Icon: ['Text'],
811
+ Image: [],
812
+ Level: ['Side', 'Item'],
813
+ Loader: [],
814
+ Media: ['Item'],
815
+ Menu: ['List', 'List.Item'],
816
+ Message: ['Header', 'Body'],
817
+ Modal: [
818
+ 'Content',
819
+ 'Card',
820
+ 'Card.Header',
821
+ 'Card.Body',
822
+ 'Card.Footer',
823
+ 'Card.Title',
824
+ ],
825
+ Navbar: [
826
+ 'Brand',
827
+ 'Burger',
828
+ 'Menu',
829
+ 'Item',
830
+ 'Dropdown',
831
+ 'Link',
832
+ 'Divider',
833
+ 'Container',
834
+ ],
835
+ Notification: [],
836
+ Pagination: [],
837
+ Panel: ['Header', 'Tabs', 'Tabs.Tab', 'Block', 'Icon'],
838
+ Progress: [],
839
+ Section: [],
840
+ Table: ['Container'],
841
+ Tabs: ['Tab'],
842
+ Tag: ['Group'],
843
+ Tile: [],
844
+ };
845
+ /** Resolve a canonical RBC path like ['Form','Field','Label'] in MAPPING. */
846
+ export function resolveMapping(path) {
847
+ let current = MAPPING[path[0]];
848
+ for (const segment of path.slice(1)) {
849
+ current = current?.subs?.[segment];
850
+ }
851
+ return current;
852
+ }