bestax-migrate 2.4.0 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/sources/bulma-classes/class-map.d.ts +32 -4
- package/dist/sources/bulma-classes/class-map.d.ts.map +1 -1
- package/dist/sources/bulma-classes/class-map.js +224 -54
- package/dist/sources/bulma-classes/plan.d.ts +6 -0
- package/dist/sources/bulma-classes/plan.d.ts.map +1 -1
- package/dist/sources/bulma-classes/plan.js +15 -2
- package/dist/sources/bulma-classes/rules.d.ts.map +1 -1
- package/dist/sources/bulma-classes/rules.js +2 -0
- package/dist/sources/bulma-classes/transform.d.ts +3 -2
- package/dist/sources/bulma-classes/transform.d.ts.map +1 -1
- package/dist/sources/bulma-classes/transform.js +53 -13
- package/package.json +1 -1
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
* it: each root, modifier and helper here is rendered through the built
|
|
9
9
|
* library and compared with the raw markup it replaces.
|
|
10
10
|
*
|
|
11
|
-
* Data only
|
|
12
|
-
*
|
|
13
|
-
* imports only
|
|
11
|
+
* Data only: `scripts/gen-mcp-index.mjs` imports it directly for the MCP
|
|
12
|
+
* server's `lookup_bulma_classes`, so nothing Node cannot strip (no enums, no
|
|
13
|
+
* namespaces, type imports only), and a change to it wants `pnpm gen:mcp`.
|
|
14
14
|
*/
|
|
15
15
|
export interface PropWrite {
|
|
16
16
|
readonly prop: string;
|
|
@@ -37,7 +37,10 @@ export interface Modifier {
|
|
|
37
37
|
export type RootStatus = 'mapped' | 'todo' | 'plain';
|
|
38
38
|
export interface RootEntry {
|
|
39
39
|
readonly status: RootStatus;
|
|
40
|
-
/**
|
|
40
|
+
/**
|
|
41
|
+
* bestax JSX name, dotted for a part (`Hero.Body`). On a `todo` family, the
|
|
42
|
+
* component a person converts the family to by hand.
|
|
43
|
+
*/
|
|
41
44
|
readonly target?: string;
|
|
42
45
|
/** The tag the target renders with no `as`. */
|
|
43
46
|
readonly tag?: string;
|
|
@@ -60,6 +63,24 @@ export interface RootEntry {
|
|
|
60
63
|
readonly untypedAttrs?: readonly string[];
|
|
61
64
|
/** The target's props type requires children. */
|
|
62
65
|
readonly requiresChildren?: boolean;
|
|
66
|
+
/**
|
|
67
|
+
* The target renders its children inside an element of its own (`Card`
|
|
68
|
+
* inside `.card-content`) unless one of them is one of these parts, so the
|
|
69
|
+
* element converts only beside a direct child that converts to one.
|
|
70
|
+
* `whenEmpty`: it renders that element with no children too.
|
|
71
|
+
*/
|
|
72
|
+
readonly wrapsChildren?: {
|
|
73
|
+
readonly in: string;
|
|
74
|
+
readonly unless: readonly string[];
|
|
75
|
+
readonly whenEmpty?: boolean;
|
|
76
|
+
};
|
|
77
|
+
/** The target takes no helper props, so every helper class stays a class. */
|
|
78
|
+
readonly noHelpers?: boolean;
|
|
79
|
+
/**
|
|
80
|
+
* The target drops its own class when it is given a `className`, so the
|
|
81
|
+
* element converts only when it carries no other class.
|
|
82
|
+
*/
|
|
83
|
+
readonly ownClassOnly?: boolean;
|
|
63
84
|
/**
|
|
64
85
|
* Attributes the target types as numbers. A numeric string (`value="40"`)
|
|
65
86
|
* becomes a number, which renders the same; any other string refuses.
|
|
@@ -78,6 +99,13 @@ export interface RootEntry {
|
|
|
78
99
|
readonly part?: boolean;
|
|
79
100
|
/** Why a `todo` or `plain` root is what it is; `todo` messages quote it. */
|
|
80
101
|
readonly why?: string;
|
|
102
|
+
/**
|
|
103
|
+
* Modifiers left out of `modifiers` on purpose, because the prop that
|
|
104
|
+
* renders the class renders more than the class. They stay in `className`;
|
|
105
|
+
* the reason is for the MCP lookup, which would otherwise say bestax has
|
|
106
|
+
* no prop for them.
|
|
107
|
+
*/
|
|
108
|
+
readonly omits?: Readonly<Record<string, string>>;
|
|
81
109
|
}
|
|
82
110
|
export declare const COLORS: readonly ["primary", "link", "info", "success", "warning", "danger", "black", "black-bis", "black-ter", "grey-darker", "grey-dark", "grey", "grey-light", "grey-lighter", "white", "white-bis", "white-ter", "light", "dark"];
|
|
83
111
|
export declare const SIZES: readonly ["0", "1", "2", "3", "4", "5", "6", "auto"];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"class-map.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/class-map.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uCAAuC;IACvC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,MAAM,GAChB;IAAE,QAAQ,CAAC,EAAE,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AAE9E,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,CAAC;IACtC,6EAA6E;IAC7E,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AAED;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;AAErD,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B
|
|
1
|
+
{"version":3,"file":"class-map.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/class-map.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uCAAuC;IACvC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,MAAM,GAChB;IAAE,QAAQ,CAAC,EAAE,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AAE9E,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,CAAC;IACtC,6EAA6E;IAC7E,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AAED;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;AAErD,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,+CAA+C;IAC/C,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,KAAK,CAAC;IACxC,+EAA+E;IAC/E,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;IACjC,QAAQ,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;IACxD,6EAA6E;IAC7E,QAAQ,CAAC,SAAS,CAAC,EAAE,WAAW,GAAG,OAAO,GAAG,IAAI,CAAC;IAClD,mFAAmF;IACnF,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,GAAG,iBAAiB,GAAG,IAAI,CAAC;IACxD,wEAAwE;IACxE,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACrD;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1C,iDAAiD;IACjD,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IACpC;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE;QACvB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;QACnC,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;KAC9B,CAAC;IACF,6EAA6E;IAC7E,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAC7B;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAChC;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,+EAA+E;IAC/E,QAAQ,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACtD;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,oEAAoE;IACpE,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB,4EAA4E;IAC5E,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACnD;AAID,eAAO,MAAM,MAAM,+NAoBT,CAAC;AACX,eAAO,MAAM,KAAK,sDAAuD,CAAC;AAC1E,eAAO,MAAM,UAAU,8CAA+C,CAAC;AACvE,eAAO,MAAM,UAAU,qDAAsD,CAAC;AAC9E,eAAO,MAAM,eAAe,8DAKlB,CAAC;AACX,eAAO,MAAM,YAAY,4DAMf,CAAC;AACX,eAAO,MAAM,aAAa,sEAMhB,CAAC;AACX,eAAO,MAAM,QAAQ,6EAOX,CAAC;AACX,eAAO,MAAM,eAAe,6DAKlB,CAAC;AACX,eAAO,MAAM,UAAU,6CAA8C,CAAC;AACtE,eAAO,MAAM,gBAAgB,iIAWnB,CAAC;AACX,eAAO,MAAM,cAAc,2GAQjB,CAAC;AACX,eAAO,MAAM,WAAW,sFAQd,CAAC;AACX,eAAO,MAAM,WAAW,8EAOd,CAAC;AACX,eAAO,MAAM,gBAAgB,yCAA0C,CAAC;AACxE,eAAO,MAAM,SAAS,6HAUZ,CAAC;AAoDX,kFAAkF;AAClF,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAKvD;AAuDD,eAAO,MAAM,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAi2BrD,CAAC;AAcF;;;;GAIG;AACH,eAAO,MAAM,UAAU,EAAE,SAAS,MAAM,EAgDvC,CAAC;AAEF,yDAAyD;AACzD,eAAO,MAAM,YAAY,EAAE,SAAS,MAAM,EAKzC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAYrD,CAAC;AAEF,yEAAyE;AACzE,eAAO,MAAM,iBAAiB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAYzE,CAAC;AAEF,6DAA6D;AAC7D,eAAO,MAAM,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAEtD,CAAC;AAIF;;;;GAIG;AACH,MAAM,MAAM,WAAW,GACnB,YAAY,GACZ,YAAY,GACZ,SAAS,GACT,YAAY,GACZ,SAAS,GACT,YAAY,GACZ,gBAAgB,GAChB,WAAW,GACX,OAAO,CAAC;AAEZ,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;CAC3B;AA6DD,eAAO,MAAM,aAAa,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CAsGzD,CAAC;AAEH,iEAAiE;AACjE,eAAO,MAAM,YAAY,EAAE,WAAW,CAAC,MAAM,CAS3C,CAAC;AAIH;;;;;GAKG;AACH,eAAO,MAAM,WAAW,EAAE,aAAa,CAAC;IACtC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB,CA8BA,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEnE;AAiBD,qCAAqC;AACrC,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAE5D;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAGlE;AAED,qCAAqC;AACrC,wBAAgB,WAAW,CACzB,KAAK,EAAE,SAAS,EAChB,KAAK,EAAE,MAAM,GACZ,QAAQ,GAAG,SAAS,CAEtB;AAED,kDAAkD;AAClD,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAE5D;AAED,0CAA0C;AAC1C,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAE1D"}
|
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
* it: each root, modifier and helper here is rendered through the built
|
|
9
9
|
* library and compared with the raw markup it replaces.
|
|
10
10
|
*
|
|
11
|
-
* Data only
|
|
12
|
-
*
|
|
13
|
-
* imports only
|
|
11
|
+
* Data only: `scripts/gen-mcp-index.mjs` imports it directly for the MCP
|
|
12
|
+
* server's `lookup_bulma_classes`, so nothing Node cannot strip (no enums, no
|
|
13
|
+
* namespaces, type imports only), and a change to it wants `pnpm gen:mcp`.
|
|
14
14
|
*/
|
|
15
15
|
export function inTagSet(set, tag) {
|
|
16
16
|
return 'on' in set ? set.on.includes(tag) : !set.except.includes(tag);
|
|
@@ -246,7 +246,9 @@ export const ROOTS = {
|
|
|
246
246
|
'is-active': 'isActive',
|
|
247
247
|
'is-hovered': 'isHovered',
|
|
248
248
|
}),
|
|
249
|
-
|
|
249
|
+
},
|
|
250
|
+
omits: {
|
|
251
|
+
'is-disabled': 'bestax `Button` renders it through `isDisabled`, which also disables the element (`disabled`, or `aria-disabled` on a link)',
|
|
250
252
|
},
|
|
251
253
|
dropsAttr: {
|
|
252
254
|
// Kept only on the elements `disabled` means something on.
|
|
@@ -318,6 +320,86 @@ export const ROOTS = {
|
|
|
318
320
|
'size',
|
|
319
321
|
],
|
|
320
322
|
},
|
|
323
|
+
// `Card` checks its children for a part (`hasCompoundComponents` in
|
|
324
|
+
// bulma-ui's Card.tsx), and `Card.Header` for a `Card.Header.Title`
|
|
325
|
+
// (`hasHeaderTitle`), and wraps them when there is none.
|
|
326
|
+
card: {
|
|
327
|
+
...BASE,
|
|
328
|
+
target: 'Card',
|
|
329
|
+
tag: 'div',
|
|
330
|
+
wrapsChildren: {
|
|
331
|
+
in: 'card-content',
|
|
332
|
+
unless: [
|
|
333
|
+
'Card.Header',
|
|
334
|
+
'Card.Header.Icon',
|
|
335
|
+
'Card.Image',
|
|
336
|
+
'Card.Content',
|
|
337
|
+
'Card.Footer',
|
|
338
|
+
'Card.FooterItem',
|
|
339
|
+
],
|
|
340
|
+
},
|
|
341
|
+
ownProps: [
|
|
342
|
+
'textColor',
|
|
343
|
+
'color',
|
|
344
|
+
'bgColor',
|
|
345
|
+
'hasShadow',
|
|
346
|
+
'header',
|
|
347
|
+
'headerCentered',
|
|
348
|
+
'headerIcon',
|
|
349
|
+
'footer',
|
|
350
|
+
'image',
|
|
351
|
+
'imageAlt',
|
|
352
|
+
],
|
|
353
|
+
},
|
|
354
|
+
'card-header': {
|
|
355
|
+
...BASE,
|
|
356
|
+
target: 'Card.Header',
|
|
357
|
+
tag: 'header',
|
|
358
|
+
wrapsChildren: {
|
|
359
|
+
in: 'card-header-title',
|
|
360
|
+
unless: ['Card.Header.Title'],
|
|
361
|
+
whenEmpty: true,
|
|
362
|
+
},
|
|
363
|
+
ownProps: ['color', 'bgColor', 'textColor', 'centered'],
|
|
364
|
+
},
|
|
365
|
+
'card-header-title': {
|
|
366
|
+
...BASE,
|
|
367
|
+
target: 'Card.Header.Title',
|
|
368
|
+
tag: 'div',
|
|
369
|
+
modifiers: flags({ 'is-centered': 'centered' }),
|
|
370
|
+
ownProps: ['color', 'bgColor', 'textColor', 'centered'],
|
|
371
|
+
},
|
|
372
|
+
'card-header-icon': {
|
|
373
|
+
...BASE,
|
|
374
|
+
target: 'Card.Header.Icon',
|
|
375
|
+
tag: 'button',
|
|
376
|
+
defaults: { 'aria-label': 'more options' },
|
|
377
|
+
ownProps: ['color', 'bgColor', 'textColor'],
|
|
378
|
+
},
|
|
379
|
+
'card-image': {
|
|
380
|
+
...BASE,
|
|
381
|
+
target: 'Card.Image',
|
|
382
|
+
tag: 'div',
|
|
383
|
+
ownProps: ['color', 'bgColor', 'textColor'],
|
|
384
|
+
},
|
|
385
|
+
'card-content': {
|
|
386
|
+
...BASE,
|
|
387
|
+
target: 'Card.Content',
|
|
388
|
+
tag: 'div',
|
|
389
|
+
ownProps: ['color', 'bgColor', 'textColor'],
|
|
390
|
+
},
|
|
391
|
+
'card-footer': {
|
|
392
|
+
...BASE,
|
|
393
|
+
target: 'Card.Footer',
|
|
394
|
+
tag: 'footer',
|
|
395
|
+
ownProps: ['color', 'bgColor', 'textColor'],
|
|
396
|
+
},
|
|
397
|
+
'card-footer-item': {
|
|
398
|
+
...BASE,
|
|
399
|
+
target: 'Card.FooterItem',
|
|
400
|
+
tag: 'span',
|
|
401
|
+
ownProps: ['color', 'bgColor', 'textColor'],
|
|
402
|
+
},
|
|
321
403
|
columns: {
|
|
322
404
|
...BASE,
|
|
323
405
|
target: 'Columns',
|
|
@@ -568,6 +650,86 @@ export const ROOTS = {
|
|
|
568
650
|
tag: 'div',
|
|
569
651
|
ownProps: ['color', 'bgColor', 'textColor'],
|
|
570
652
|
},
|
|
653
|
+
// `Navbar` writes Bulma's own `role` and `aria-label`, so an element that
|
|
654
|
+
// already carries them renders the same.
|
|
655
|
+
navbar: {
|
|
656
|
+
...BASE,
|
|
657
|
+
target: 'Navbar',
|
|
658
|
+
tag: 'nav',
|
|
659
|
+
modifiers: {
|
|
660
|
+
...tokens('is-', COMPONENT_COLORS, 'color'),
|
|
661
|
+
...tokens('is-fixed-', ['top', 'bottom'], 'fixed'),
|
|
662
|
+
...flags({ 'is-transparent': 'transparent' }),
|
|
663
|
+
},
|
|
664
|
+
defaults: { role: 'navigation', 'aria-label': 'main navigation' },
|
|
665
|
+
ownProps: ['textColor', 'color', 'bgColor', 'transparent', 'fixed'],
|
|
666
|
+
},
|
|
667
|
+
// No background prop on these parts. Menu, Start and End spread `textColor`
|
|
668
|
+
// onto the element rather than reading it, and type `color` to six colors,
|
|
669
|
+
// so their text color stays a class.
|
|
670
|
+
'navbar-brand': {
|
|
671
|
+
...BASE,
|
|
672
|
+
target: 'Navbar.Brand',
|
|
673
|
+
tag: 'div',
|
|
674
|
+
bgColor: null,
|
|
675
|
+
ownProps: ['textColor', 'color'],
|
|
676
|
+
},
|
|
677
|
+
'navbar-menu': {
|
|
678
|
+
...BASE,
|
|
679
|
+
target: 'Navbar.Menu',
|
|
680
|
+
tag: 'div',
|
|
681
|
+
textColor: null,
|
|
682
|
+
bgColor: null,
|
|
683
|
+
modifiers: flags({ 'is-active': 'active' }),
|
|
684
|
+
ownProps: ['textColor', 'color', 'active'],
|
|
685
|
+
},
|
|
686
|
+
'navbar-start': {
|
|
687
|
+
...BASE,
|
|
688
|
+
target: 'Navbar.Start',
|
|
689
|
+
tag: 'div',
|
|
690
|
+
textColor: null,
|
|
691
|
+
bgColor: null,
|
|
692
|
+
ownProps: ['textColor', 'color'],
|
|
693
|
+
},
|
|
694
|
+
'navbar-end': {
|
|
695
|
+
...BASE,
|
|
696
|
+
target: 'Navbar.End',
|
|
697
|
+
tag: 'div',
|
|
698
|
+
textColor: null,
|
|
699
|
+
bgColor: null,
|
|
700
|
+
ownProps: ['textColor', 'color'],
|
|
701
|
+
},
|
|
702
|
+
// A `.has-dropdown` item stays a `Navbar.Item` with the class: a
|
|
703
|
+
// `Navbar.Dropdown` would hand its `.navbar-link` dropdown semantics.
|
|
704
|
+
'navbar-item': {
|
|
705
|
+
...BASE,
|
|
706
|
+
target: 'Navbar.Item',
|
|
707
|
+
tag: 'a',
|
|
708
|
+
as: 'any',
|
|
709
|
+
modifiers: flags({ 'is-active': 'active' }),
|
|
710
|
+
ownProps: ['as', 'active', 'textColor', 'bgColor'],
|
|
711
|
+
},
|
|
712
|
+
'navbar-dropdown': {
|
|
713
|
+
status: 'mapped',
|
|
714
|
+
target: 'Navbar.DropdownMenu',
|
|
715
|
+
tag: 'div',
|
|
716
|
+
textColor: null,
|
|
717
|
+
bgColor: null,
|
|
718
|
+
noHelpers: true,
|
|
719
|
+
modifiers: flags({ 'is-right': 'right', 'is-up': 'up' }),
|
|
720
|
+
ownProps: ['right', 'up'],
|
|
721
|
+
},
|
|
722
|
+
'navbar-divider': {
|
|
723
|
+
status: 'mapped',
|
|
724
|
+
target: 'Navbar.Divider',
|
|
725
|
+
tag: 'hr',
|
|
726
|
+
textColor: null,
|
|
727
|
+
bgColor: null,
|
|
728
|
+
noHelpers: true,
|
|
729
|
+
// bulma-ui's Navbar.Divider spreads `className` over its own class.
|
|
730
|
+
ownClassOnly: true,
|
|
731
|
+
ownProps: [],
|
|
732
|
+
},
|
|
571
733
|
notification: {
|
|
572
734
|
...BASE,
|
|
573
735
|
target: 'Notification',
|
|
@@ -656,7 +818,9 @@ export const ROOTS = {
|
|
|
656
818
|
'is-rounded': 'isRounded',
|
|
657
819
|
'is-hoverable': 'isHoverable',
|
|
658
820
|
}),
|
|
659
|
-
|
|
821
|
+
},
|
|
822
|
+
omits: {
|
|
823
|
+
'is-delete': 'bestax `Tag` renders it through `isDelete`, which also turns the tag into a <button>',
|
|
660
824
|
},
|
|
661
825
|
ownProps: [
|
|
662
826
|
'color',
|
|
@@ -698,51 +862,43 @@ export const ROOTS = {
|
|
|
698
862
|
ownProps: ['size', 'isSpaced', 'as', 'hasSkeleton', 'textColor', 'bgColor'],
|
|
699
863
|
},
|
|
700
864
|
// ---- Families bestax has but that do not map element by element yet ------
|
|
701
|
-
breadcrumb: todo('bestax `Breadcrumb` renders the `<ul>` itself and adds an `aria-label`'),
|
|
702
|
-
|
|
703
|
-
'
|
|
704
|
-
'
|
|
705
|
-
'
|
|
706
|
-
'
|
|
707
|
-
'
|
|
708
|
-
'
|
|
709
|
-
'
|
|
710
|
-
cell: todo('this source leaves Grid markup as written; convert it to bestax `Grid` and `Cell` by hand (`Grid isFixed` renders the `.fixed-grid` wrapper itself)'),
|
|
711
|
-
grid: todo('this source leaves Grid markup as written; convert it to bestax `Grid` and `Cell` by hand (`Grid isFixed` renders the `.fixed-grid` wrapper itself)'),
|
|
712
|
-
'fixed-grid': todo('this source leaves Grid markup as written; convert it to bestax `Grid` and `Cell` by hand (`Grid isFixed` renders the `.fixed-grid` wrapper itself)'),
|
|
713
|
-
checkbox: todo("bestax `Checkbox` renders its own styled markup, not Bulma's"),
|
|
714
|
-
checkboxes: todo('bestax `Checkboxes` renders its own `.field` and `.control` wrappers'),
|
|
715
|
-
radio: todo("bestax `Radio` renders its own styled markup, not Bulma's"),
|
|
716
|
-
radios: todo('bestax `Radios` renders its own `.field` and `.control` wrappers'),
|
|
717
|
-
field: todo('bestax form controls render their own `.field` and `.control` wrappers; see the unmappables reference'),
|
|
865
|
+
breadcrumb: todo('Breadcrumb', 'bestax `Breadcrumb` renders the `<ul>` itself and adds an `aria-label`'),
|
|
866
|
+
cell: todo('Cell', 'this source leaves Grid markup as written; convert it to bestax `Grid` and `Cell` by hand (`Grid isFixed` renders the `.fixed-grid` wrapper itself)'),
|
|
867
|
+
grid: todo('Grid', 'this source leaves Grid markup as written; convert it to bestax `Grid` and `Cell` by hand (`Grid isFixed` renders the `.fixed-grid` wrapper itself)'),
|
|
868
|
+
'fixed-grid': todo('Grid', 'this source leaves Grid markup as written; convert it to bestax `Grid` and `Cell` by hand (`Grid isFixed` renders the `.fixed-grid` wrapper itself)'),
|
|
869
|
+
checkbox: todo('Checkbox', "bestax `Checkbox` renders its own styled markup, not Bulma's"),
|
|
870
|
+
checkboxes: todo('Checkboxes', 'bestax `Checkboxes` renders its own `.field` and `.control` wrappers'),
|
|
871
|
+
radio: todo('Radio', "bestax `Radio` renders its own styled markup, not Bulma's"),
|
|
872
|
+
radios: todo('Radios', 'bestax `Radios` renders its own `.field` and `.control` wrappers'),
|
|
873
|
+
field: todo('Field', 'bestax form controls render their own `.field` and `.control` wrappers; see the unmappables reference'),
|
|
718
874
|
'field-label': part(),
|
|
719
875
|
'field-body': part(),
|
|
720
876
|
control: part(),
|
|
721
|
-
input: todo('bestax `Input` renders its own `.field` and `.control` wrappers'),
|
|
722
|
-
textarea: todo('bestax `TextArea` renders its own `.field` and `.control` wrappers'),
|
|
723
|
-
select: todo('bestax `Select` renders the `.select` wrapper and the `<select>` together'),
|
|
724
|
-
file: todo('bestax `File` renders the whole `.file-label` tree itself'),
|
|
877
|
+
input: todo('Input', 'bestax `Input` renders its own `.field` and `.control` wrappers'),
|
|
878
|
+
textarea: todo('TextArea', 'bestax `TextArea` renders its own `.field` and `.control` wrappers'),
|
|
879
|
+
select: todo('Select', 'bestax `Select` renders the `.select` wrapper and the `<select>` together'),
|
|
880
|
+
file: todo('File', 'bestax `File` renders the whole `.file-label` tree itself'),
|
|
725
881
|
'file-label': part(),
|
|
726
882
|
'file-input': part(),
|
|
727
883
|
'file-cta': part(),
|
|
728
884
|
'file-icon': part(),
|
|
729
885
|
'file-name': part(),
|
|
730
|
-
dropdown: todo('bestax `Dropdown` renders its own trigger and menu from props'),
|
|
886
|
+
dropdown: todo('Dropdown', 'bestax `Dropdown` renders its own trigger and menu from props'),
|
|
731
887
|
'dropdown-menu': part(),
|
|
732
888
|
'dropdown-content': part(),
|
|
733
889
|
'dropdown-item': part(),
|
|
734
890
|
'dropdown-divider': part(),
|
|
735
|
-
icon: todo('bestax `Icon` renders its own `<i>` and adds an `aria-label`'),
|
|
736
|
-
'icon-text': todo('bestax `IconText` pairs with `Icon`, which renders its own `<i>`'),
|
|
737
|
-
image: todo('bestax `Image` renders its own `<img>`'),
|
|
738
|
-
menu: todo('bestax `Menu.Item` renders the `<li>` and the `<a>` together'),
|
|
891
|
+
icon: todo('Icon', 'bestax `Icon` renders its own `<i>` and adds an `aria-label`'),
|
|
892
|
+
'icon-text': todo('IconText', 'bestax `IconText` pairs with `Icon`, which renders its own `<i>`'),
|
|
893
|
+
image: todo('Image', 'bestax `Image` renders its own `<img>`'),
|
|
894
|
+
menu: todo('Menu', 'bestax `Menu.Item` renders the `<li>` and the `<a>` together'),
|
|
739
895
|
'menu-label': part(),
|
|
740
896
|
'menu-list': part(),
|
|
741
897
|
'menu-item': part(),
|
|
742
|
-
message: todo('bestax `Message` always wraps its children in `.message-body`'),
|
|
898
|
+
message: todo('Message', 'bestax `Message` always wraps its children in `.message-body`'),
|
|
743
899
|
'message-header': part(),
|
|
744
900
|
'message-body': part(),
|
|
745
|
-
modal: todo('bestax `Modal` renders its own background and content parts, and adds dialog attributes'),
|
|
901
|
+
modal: todo('Modal', 'bestax `Modal` renders its own background and content parts, and adds dialog attributes'),
|
|
746
902
|
'modal-background': part(),
|
|
747
903
|
'modal-content': part(),
|
|
748
904
|
'modal-card': part(),
|
|
@@ -751,34 +907,24 @@ export const ROOTS = {
|
|
|
751
907
|
'modal-card-body': part(),
|
|
752
908
|
'modal-card-foot': part(),
|
|
753
909
|
'modal-close': part(),
|
|
754
|
-
navbar: todo('bestax `Navbar`
|
|
755
|
-
'navbar-
|
|
756
|
-
'
|
|
757
|
-
'navbar-menu': part(),
|
|
758
|
-
'navbar-start': part(),
|
|
759
|
-
'navbar-end': part(),
|
|
760
|
-
'navbar-item': part(),
|
|
761
|
-
'navbar-link': part(),
|
|
762
|
-
'navbar-dropdown': part(),
|
|
763
|
-
'navbar-divider': part(),
|
|
764
|
-
'navbar-content': part(),
|
|
765
|
-
'navbar-tabs': part(),
|
|
766
|
-
pagination: todo('bestax `Pagination` renders its own list items and adds navigation roles'),
|
|
910
|
+
'navbar-burger': todo('Navbar.Burger', 'bestax `Navbar.Burger` is a `<button>` that renders its own spans and `aria-expanded`, so rebuild the toggle with it, by hand'),
|
|
911
|
+
'navbar-link': todo('Navbar.Link', 'inside a `Navbar.Dropdown`, bestax `Navbar.Link` adds `aria-haspopup`, `aria-expanded` and keyboard handling, so convert the `.has-dropdown` item and its link together, by hand'),
|
|
912
|
+
pagination: todo('Pagination', 'bestax `Pagination` renders its own list items and adds navigation roles'),
|
|
767
913
|
'pagination-list': part(),
|
|
768
914
|
'pagination-link': part(),
|
|
769
915
|
'pagination-ellipsis': part(),
|
|
770
916
|
'pagination-previous': part(),
|
|
771
917
|
'pagination-next': part(),
|
|
772
|
-
panel: todo('bestax `Panel` parts render their own tags and attributes (`Panel.Block` is an `<a>`, `Panel.Icon` adds an `aria-label`)'),
|
|
918
|
+
panel: todo('Panel', 'bestax `Panel` parts render their own tags and attributes (`Panel.Block` is an `<a>`, `Panel.Icon` adds an `aria-label`)'),
|
|
773
919
|
'panel-heading': part(),
|
|
774
920
|
'panel-tabs': part(),
|
|
775
921
|
'panel-block': part(),
|
|
776
922
|
'panel-icon': part(),
|
|
777
923
|
'panel-list': part(),
|
|
778
|
-
tabs: todo("bestax `Tabs` renders each tab's `<li>` and `<a>` together, with tab roles"),
|
|
779
|
-
'table-container': todo('bestax renders `.table-container` from `Table isResponsive`'),
|
|
780
|
-
'skeleton-block': todo('bestax `Skeleton` renders its own markup'),
|
|
781
|
-
'skeleton-lines': todo('bestax `Skeleton` renders its own markup'),
|
|
924
|
+
tabs: todo('Tabs', "bestax `Tabs` renders each tab's `<li>` and `<a>` together, with tab roles"),
|
|
925
|
+
'table-container': todo('Table', 'bestax renders `.table-container` from `Table isResponsive`'),
|
|
926
|
+
'skeleton-block': todo('Skeleton', 'bestax `Skeleton` renders its own markup'),
|
|
927
|
+
'skeleton-lines': todo('Skeleton', 'bestax `Skeleton` renders its own markup'),
|
|
782
928
|
// ---- Valid Bulma, nothing to convert to --------------------------------------
|
|
783
929
|
// The other sources emit these on purpose where bestax has no component.
|
|
784
930
|
help: plain('bestax renders `.help` only inside its form controls'),
|
|
@@ -786,14 +932,16 @@ export const ROOTS = {
|
|
|
786
932
|
loader: plain("bestax `Loading` is an overlay, not Bulma's inline spinner"),
|
|
787
933
|
'hero-buttons': plain('a layout class inside `.hero`; bestax has no part for it'),
|
|
788
934
|
'hero-video': plain('a layout class inside `.hero`; bestax has no part for it'),
|
|
935
|
+
'navbar-content': plain('a layout class inside `.navbar`; bestax has no part for it'),
|
|
936
|
+
'navbar-tabs': plain('a layout class inside `.navbar`; bestax has no part for it'),
|
|
789
937
|
'theme-dark': plain('a theme scope; bestax sets themes through `Theme`'),
|
|
790
938
|
'theme-light': plain('a theme scope; bestax sets themes through `Theme`'),
|
|
791
939
|
fa: plain("Font Awesome's own class, styled by Bulma inside `.icon`"),
|
|
792
940
|
marginless: plain('a Bulma helper with no bestax prop'),
|
|
793
941
|
paddingless: plain('a Bulma helper with no bestax prop'),
|
|
794
942
|
};
|
|
795
|
-
function todo(why) {
|
|
796
|
-
return { status: 'todo', why };
|
|
943
|
+
function todo(target, why) {
|
|
944
|
+
return { status: 'todo', target, why };
|
|
797
945
|
}
|
|
798
946
|
function part() {
|
|
799
947
|
return { status: 'todo', part: true };
|
|
@@ -824,6 +972,23 @@ export const PRECEDENCE = [
|
|
|
824
972
|
'media-left',
|
|
825
973
|
'media-content',
|
|
826
974
|
'media-right',
|
|
975
|
+
// A part before a surface class, so the card around it still sees a part.
|
|
976
|
+
'card',
|
|
977
|
+
'card-header',
|
|
978
|
+
'card-header-title',
|
|
979
|
+
'card-header-icon',
|
|
980
|
+
'card-image',
|
|
981
|
+
'card-content',
|
|
982
|
+
'card-footer',
|
|
983
|
+
'card-footer-item',
|
|
984
|
+
'navbar',
|
|
985
|
+
'navbar-brand',
|
|
986
|
+
'navbar-menu',
|
|
987
|
+
'navbar-start',
|
|
988
|
+
'navbar-end',
|
|
989
|
+
'navbar-item',
|
|
990
|
+
'navbar-dropdown',
|
|
991
|
+
'navbar-divider',
|
|
827
992
|
'buttons',
|
|
828
993
|
'tags',
|
|
829
994
|
'button',
|
|
@@ -839,7 +1004,12 @@ export const PRECEDENCE = [
|
|
|
839
1004
|
'block',
|
|
840
1005
|
];
|
|
841
1006
|
/** Refs reach the element only through these targets. */
|
|
842
|
-
export const FORWARDS_REF = [
|
|
1007
|
+
export const FORWARDS_REF = [
|
|
1008
|
+
'Button',
|
|
1009
|
+
'Link',
|
|
1010
|
+
'Navbar',
|
|
1011
|
+
'Navbar.Item',
|
|
1012
|
+
];
|
|
843
1013
|
/**
|
|
844
1014
|
* Plain tags bestax wraps, for an element with helper classes and no root
|
|
845
1015
|
* (`<p className="has-text-centered">` → `<Paragraph textAlign="centered">`).
|
|
@@ -22,6 +22,12 @@ export interface ElementFacts {
|
|
|
22
22
|
hasRef: boolean;
|
|
23
23
|
/** Whether the element has children (JSX text, elements or expressions). */
|
|
24
24
|
hasChildren: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* The bestax components the element's child elements are, or convert to
|
|
27
|
+
* (`Card.Content`). Only a child written directly inside the element
|
|
28
|
+
* counts: one in an expression may not render.
|
|
29
|
+
*/
|
|
30
|
+
childTargets?: readonly string[];
|
|
25
31
|
/**
|
|
26
32
|
* The component this element is the only child of, if any (`Link` for
|
|
27
33
|
* `<Link href="/x"><a className="button">`), since that component can
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAiBH,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,2DAA2D;IAC3D,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B;;;OAGG;IACH,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC;IACtD,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,4EAA4E;IAC5E,WAAW,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,0CAA0C;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,KAAK,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;IACnD,4DAA4D;IAC5D,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,mEAAmE;IACnE,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,8DAA8D;IAC9D,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,IAAI;IACnB,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,KAAK,EAAE,IAAI,EAAE,CAAC;CACf;AA+BD,wBAAgB,IAAI,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAiBH,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,2DAA2D;IAC3D,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B;;;OAGG;IACH,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC;IACtD,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,4EAA4E;IAC5E,WAAW,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,0CAA0C;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,KAAK,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;IACnD,4DAA4D;IAC5D,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,mEAAmE;IACnE,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,8DAA8D;IAC9D,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,IAAI;IACnB,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,KAAK,EAAE,IAAI,EAAE,CAAC;CACf;AA+BD,wBAAgB,IAAI,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAwQ9C"}
|
|
@@ -48,7 +48,7 @@ export function plan(facts) {
|
|
|
48
48
|
todos.push({ rule: ruleId('legacy', token), message: hint });
|
|
49
49
|
}
|
|
50
50
|
// A family this source leaves as markup keeps its element as markup, even
|
|
51
|
-
// beside a class it would convert (`
|
|
51
|
+
// beside a class it would convert (`navbar box`): the family's parts carry no
|
|
52
52
|
// TODO of their own, so its outermost class is the one place it is flagged.
|
|
53
53
|
const family = tokens.find(token => {
|
|
54
54
|
const found = rootFor(token);
|
|
@@ -128,6 +128,16 @@ export function plan(facts) {
|
|
|
128
128
|
if (entry.requiresChildren && !facts.hasChildren) {
|
|
129
129
|
return refuse('children', target, `bestax \`${target}\` requires children, and this element has none; keep it as markup`);
|
|
130
130
|
}
|
|
131
|
+
const wraps = entry.wrapsChildren;
|
|
132
|
+
if (wraps &&
|
|
133
|
+
(facts.hasChildren || wraps.whenEmpty) &&
|
|
134
|
+
!facts.childTargets?.some(child => wraps.unless.includes(child))) {
|
|
135
|
+
const parts = wraps.unless.map(part => `\`${part}\``);
|
|
136
|
+
const list = parts.length > 1
|
|
137
|
+
? `${parts.slice(0, -1).join(', ')} or ${parts[parts.length - 1]}`
|
|
138
|
+
: parts[0];
|
|
139
|
+
return refuse('children', target, `bestax \`${target}\` renders its children inside a \`.${wraps.in}\` of its own unless one of them is a ${list}, so this element stays markup`);
|
|
140
|
+
}
|
|
131
141
|
if (missing.length > 0) {
|
|
132
142
|
const list = missing.map(([name, value]) => `\`${name}="${value}"\``);
|
|
133
143
|
return refuse('defaults', target, `bestax \`${target}\` renders ${list.join(' and ')} when the element does not set ${missing.length === 1 ? 'it' : 'them'}; add ${missing.length === 1 ? 'it' : 'them'} here if that is what you want, then re-run`);
|
|
@@ -164,7 +174,7 @@ export function plan(facts) {
|
|
|
164
174
|
converted.add(token);
|
|
165
175
|
continue;
|
|
166
176
|
}
|
|
167
|
-
const helper = HELPER_TOKENS.get(token);
|
|
177
|
+
const helper = entry.noHelpers ? undefined : HELPER_TOKENS.get(token);
|
|
168
178
|
if (!helper)
|
|
169
179
|
continue;
|
|
170
180
|
const prop = helper.group === 'text-color'
|
|
@@ -218,6 +228,9 @@ export function plan(facts) {
|
|
|
218
228
|
props.push(['as', as]);
|
|
219
229
|
props.push(...writes);
|
|
220
230
|
const rest = tokens.filter(token => !converted.has(token));
|
|
231
|
+
if (entry.ownClassOnly && rest.length > 0) {
|
|
232
|
+
return refuse('attr', 'className', `bestax \`${target}\` drops its own class when it is given a \`className\`, so this element's other classes would take the place of \`.${root}\`; keep it as markup`);
|
|
233
|
+
}
|
|
221
234
|
return {
|
|
222
235
|
conversion: {
|
|
223
236
|
target,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/rules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAUH,eAAO,MAAM,KAAK,EAAE,WAAW,CAAC,MAAM,CAYpC,CAAC;
|
|
1
|
+
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/rules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAUH,eAAO,MAAM,KAAK,EAAE,WAAW,CAAC,MAAM,CAYpC,CAAC;AAuBH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEnD;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAK1D"}
|
|
@@ -41,6 +41,8 @@ const VOCABULARY = new Set([
|
|
|
41
41
|
...HELPER_PROPS,
|
|
42
42
|
// Refused on every target, so no entry lists it.
|
|
43
43
|
'dangerouslySetInnerHTML',
|
|
44
|
+
// Refused where the target drops its own class for one it is given.
|
|
45
|
+
'className',
|
|
44
46
|
]);
|
|
45
47
|
export function inVocabulary(token) {
|
|
46
48
|
return VOCABULARY.has(token);
|
|
@@ -8,8 +8,9 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Passes, in order:
|
|
10
10
|
* 1. the shared stylesheet-import pass (a no-op under the default `keep`)
|
|
11
|
-
* 2. plan every element in scope; a computed
|
|
12
|
-
* strings in it and becomes a TODO, never
|
|
11
|
+
* 2. plan every element in scope, children before parents; a computed
|
|
12
|
+
* className is planned from the strings in it and becomes a TODO, never
|
|
13
|
+
* a conversion
|
|
13
14
|
* 3. file-level gates: a non-React JSX runtime, CommonJS, styled-jsx, and a
|
|
14
15
|
* Next.js server component (bestax's components are client components)
|
|
15
16
|
* 4. TODOs in reading order; conversions innermost first
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/transform.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../../src/sources/bulma-classes/transform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAW,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAmSvD,MAAM,CAAC,OAAO,UAAU,SAAS,CAC/B,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,GAAG,EACR,OAAO,GAAE,gBAAqB,GAC7B,MAAM,GAAG,SAAS,CA2SpB"}
|
|
@@ -8,8 +8,9 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Passes, in order:
|
|
10
10
|
* 1. the shared stylesheet-import pass (a no-op under the default `keep`)
|
|
11
|
-
* 2. plan every element in scope; a computed
|
|
12
|
-
* strings in it and becomes a TODO, never
|
|
11
|
+
* 2. plan every element in scope, children before parents; a computed
|
|
12
|
+
* className is planned from the strings in it and becomes a TODO, never
|
|
13
|
+
* a conversion
|
|
13
14
|
* 3. file-level gates: a non-React JSX runtime, CommonJS, styled-jsx, and a
|
|
14
15
|
* Next.js server component (bestax's components are client components)
|
|
15
16
|
* 4. TODOs in reading order; conversions innermost first
|
|
@@ -17,7 +18,7 @@
|
|
|
17
18
|
*/
|
|
18
19
|
import path from 'node:path';
|
|
19
20
|
import { addTodo, findAttr, forgetJsxParens, jsxNameParts, literalValueOf, makeAttr, renameElement, reprintDirectives, } from '../_shared/jsx-utils.js';
|
|
20
|
-
import { collectBoundNames, makeReserve, prefersTabs, } from '../_shared/imports.js';
|
|
21
|
+
import { collectBoundNames, makeReserve, prefersTabs, resolvesToBinding, } from '../_shared/imports.js';
|
|
21
22
|
import { rewriteStylesheetImports } from '../_shared/css-imports.js';
|
|
22
23
|
import { BESTAX, buildBestaxImport, placeBestaxImport, seedBestaxImport, } from '../_shared/bestax-import.js';
|
|
23
24
|
import { plan } from './plan.js';
|
|
@@ -217,6 +218,17 @@ function isContent(child) {
|
|
|
217
218
|
}
|
|
218
219
|
return true;
|
|
219
220
|
}
|
|
221
|
+
/**
|
|
222
|
+
* Whether a JSX child reaches React at all. JSX drops a comment, and text
|
|
223
|
+
* made only of spaces and tabs split by a line break; it keeps the rest.
|
|
224
|
+
* `<div> </div>` has a child, which `Card` would wrap, and so does an
|
|
225
|
+
* ` ` on its own line: `trim()` would drop it, and JSX does not.
|
|
226
|
+
*/
|
|
227
|
+
function reachesReact(child) {
|
|
228
|
+
if (child.type !== 'JSXText')
|
|
229
|
+
return isContent(child);
|
|
230
|
+
return /[^ \t\r\n]/.test(child.value) || !/[\r\n]/.test(child.value);
|
|
231
|
+
}
|
|
220
232
|
function insideForeignContent(elementPath) {
|
|
221
233
|
let current = elementPath.parent;
|
|
222
234
|
while (current) {
|
|
@@ -278,29 +290,55 @@ export default function transform(fileInfo, api, options = {}) {
|
|
|
278
290
|
// every class a converted element renders.
|
|
279
291
|
rewriteStylesheetImports(ctx, root, options.cssMode ?? 'keep');
|
|
280
292
|
// ---- 2. Plan the elements in scope ----------------------------------------
|
|
281
|
-
|
|
293
|
+
// Each local bestax name, with the component path it stands for: `Card`
|
|
294
|
+
// for `import { Card as C }`, nothing for a namespace (`B.Card`).
|
|
295
|
+
const bestaxNames = new Map();
|
|
282
296
|
root
|
|
283
297
|
.find(j.ImportDeclaration, { source: { value: BESTAX } })
|
|
284
298
|
.forEach((importPath) => {
|
|
285
299
|
for (const spec of importPath.node.specifiers ?? []) {
|
|
286
|
-
if (spec.local)
|
|
287
|
-
|
|
300
|
+
if (!spec.local)
|
|
301
|
+
continue;
|
|
302
|
+
bestaxNames.set(spec.local.name, spec.type === 'ImportSpecifier' ? [spec.imported.name] : []);
|
|
288
303
|
}
|
|
289
304
|
});
|
|
305
|
+
const bestaxLocals = new Set(bestaxNames.keys());
|
|
306
|
+
// Children are planned before their parents (reverse document order), so
|
|
307
|
+
// a parent can see what its children become: `Card` converts only beside
|
|
308
|
+
// a child that is one of its parts.
|
|
309
|
+
const planned = new Map();
|
|
310
|
+
const programScope = root.find(j.Program).paths()[0]?.scope;
|
|
311
|
+
const childTargets = (elementPath) => (elementPath.node.children ?? []).flatMap((child) => {
|
|
312
|
+
if (child.type !== 'JSXElement')
|
|
313
|
+
return [];
|
|
314
|
+
const target = planned.get(child)?.conversion?.target;
|
|
315
|
+
if (target)
|
|
316
|
+
return [target];
|
|
317
|
+
// A part the file already uses counts when its name is the bestax
|
|
318
|
+
// import, not a local that shadows it. A direct child is looked up in
|
|
319
|
+
// the element's own scope, which is the child's.
|
|
320
|
+
const parts = jsxNameParts(child.openingElement.name);
|
|
321
|
+
const owner = parts && bestaxNames.get(parts[0]);
|
|
322
|
+
if (!owner || !resolvesToBinding(elementPath, parts[0], programScope)) {
|
|
323
|
+
return [];
|
|
324
|
+
}
|
|
325
|
+
return [[...owner, ...parts.slice(1)].join('.')];
|
|
326
|
+
});
|
|
290
327
|
// `converts` is whether the element would become a component with its
|
|
291
328
|
// classes written out, so it holds for a computed className too.
|
|
292
329
|
const elements = [];
|
|
293
|
-
root.find(j.JSXElement).
|
|
330
|
+
const candidates = root.find(j.JSXElement).paths();
|
|
331
|
+
for (const elementPath of [...candidates].reverse()) {
|
|
294
332
|
const element = elementPath.node;
|
|
295
333
|
const name = element.openingElement.name;
|
|
296
334
|
if (name.type !== 'JSXIdentifier' || !INTRINSIC.test(name.name))
|
|
297
|
-
|
|
335
|
+
continue;
|
|
298
336
|
if (FOREIGN_ROOTS.has(name.name) || insideForeignContent(elementPath)) {
|
|
299
|
-
|
|
337
|
+
continue;
|
|
300
338
|
}
|
|
301
339
|
const classAttr = findAttr(element, 'className');
|
|
302
340
|
if (!classAttr)
|
|
303
|
-
|
|
341
|
+
continue;
|
|
304
342
|
const attributes = new Map();
|
|
305
343
|
for (const attr of element.openingElement.attributes ?? []) {
|
|
306
344
|
if (attr.type !== 'JSXAttribute' || attr === classAttr)
|
|
@@ -316,7 +354,8 @@ export default function transform(fileInfo, api, options = {}) {
|
|
|
316
354
|
attributes,
|
|
317
355
|
hasSpread: (element.openingElement.attributes ?? []).some((attr) => attr.type === 'JSXSpreadAttribute'),
|
|
318
356
|
hasRef: attributes.has('ref'),
|
|
319
|
-
hasChildren: (element.children ?? []).some(
|
|
357
|
+
hasChildren: (element.children ?? []).some(reachesReact),
|
|
358
|
+
childTargets: childTargets(elementPath),
|
|
320
359
|
onlyChildOf: onlyChildOf(elementPath, bestaxLocals),
|
|
321
360
|
};
|
|
322
361
|
let result = plan(facts);
|
|
@@ -336,10 +375,11 @@ export default function transform(fileInfo, api, options = {}) {
|
|
|
336
375
|
],
|
|
337
376
|
};
|
|
338
377
|
}
|
|
378
|
+
planned.set(element, result);
|
|
339
379
|
if (result.conversion || result.todos.length > 0) {
|
|
340
|
-
elements.
|
|
380
|
+
elements.unshift({ path: elementPath, plan: result, converts });
|
|
341
381
|
}
|
|
342
|
-
}
|
|
382
|
+
}
|
|
343
383
|
if (elements.length === 0)
|
|
344
384
|
return print();
|
|
345
385
|
// ---- 3. File-level gates ------------------------------------------------------
|