@bamboocss/generator 1.15.0 → 1.16.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/index.cjs +484 -3398
- package/dist/index.d.cts +38 -1
- package/dist/index.d.mts +38 -1
- package/dist/index.mjs +484 -3400
- package/package.json +7 -7
package/dist/index.cjs
CHANGED
|
@@ -107,36 +107,6 @@ function generateConditions(ctx) {
|
|
|
107
107
|
};
|
|
108
108
|
}
|
|
109
109
|
//#endregion
|
|
110
|
-
//#region src/artifacts/js/conditions.string-literal.ts
|
|
111
|
-
function generateStringLiteralConditions(ctx) {
|
|
112
|
-
return {
|
|
113
|
-
js: outdent.default`
|
|
114
|
-
${ctx.file.import("withoutSpace", "../helpers")}
|
|
115
|
-
|
|
116
|
-
export const isCondition = (val) => condRegex.test(val)
|
|
117
|
-
|
|
118
|
-
const condRegex = /^@|&|&$/
|
|
119
|
-
const selectorRegex = /&|@/
|
|
120
|
-
|
|
121
|
-
export const finalizeConditions = (paths) => {
|
|
122
|
-
return paths.map((path) => (selectorRegex.test(path) ? \`[\${withoutSpace(path.trim())}]\` : path))
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
export function sortConditions(paths){
|
|
126
|
-
return paths.sort((a, b) => {
|
|
127
|
-
const aa = isCondition(a)
|
|
128
|
-
const bb = isCondition(b)
|
|
129
|
-
if (aa && !bb) return 1
|
|
130
|
-
if (!aa && bb) return -1
|
|
131
|
-
return 0
|
|
132
|
-
})
|
|
133
|
-
}
|
|
134
|
-
`,
|
|
135
|
-
dts: outdent.default`
|
|
136
|
-
`
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
//#endregion
|
|
140
110
|
//#region src/artifacts/js/css-fn.ts
|
|
141
111
|
function generateCssFn(ctx) {
|
|
142
112
|
const { utility, hash, prefix, conditions } = ctx;
|
|
@@ -206,7 +176,7 @@ function generateCssFn(ctx) {
|
|
|
206
176
|
`,
|
|
207
177
|
js: outdent.outdent`
|
|
208
178
|
${ctx.file.import("cloneStyles, createCss, createMergeCss, hypenateProperty, leafClass, memo, viewTransitionClassName, withoutSpace", "../helpers")}
|
|
209
|
-
${ctx.file.import("sortConditions, finalizeConditions", "./conditions")}
|
|
179
|
+
${[ctx.file.import("sortConditions, finalizeConditions", "./conditions"), ctx.config.cssMode === "grouped" ? ctx.file.import("groups", "./groups") : ""].filter(Boolean).join("\n")}
|
|
210
180
|
|
|
211
181
|
const utilities = "${utility.entries().map(([prop, className]) => {
|
|
212
182
|
const shorthandList = getPropShorthands(prop);
|
|
@@ -236,7 +206,7 @@ function generateCssFn(ctx) {
|
|
|
236
206
|
`}
|
|
237
207
|
|
|
238
208
|
const context = {
|
|
239
|
-
${[hash.className && "hash: true,", ctx.config.cssMode === "grouped" && "grouped: true,"].filter(Boolean).join("\n ")}
|
|
209
|
+
${[hash.className && "hash: true,", ctx.config.cssMode === "grouped" && "grouped: true,\n knownGroups: groups,"].filter(Boolean).join("\n ")}
|
|
240
210
|
conditions: {
|
|
241
211
|
shift: sortConditions,
|
|
242
212
|
finalize: finalizeConditions,
|
|
@@ -261,6 +231,7 @@ function generateCssFn(ctx) {
|
|
|
261
231
|
// condition object would otherwise poison it for everyone after them.
|
|
262
232
|
css.raw = (...styles) => cloneStyles(mergeCss(...styles))
|
|
263
233
|
|
|
234
|
+
|
|
264
235
|
// Emitted for the source transform, which rewrites a single dynamic style leaf into a
|
|
265
236
|
// call to this rather than leaving a \`css()\` behind. \`prefix\` is the class up to the
|
|
266
237
|
// value, resolved at build time; \`prop\` is only used for the shapes \`leafClass\`
|
|
@@ -285,77 +256,20 @@ function generateCssFn(ctx) {
|
|
|
285
256
|
};
|
|
286
257
|
}
|
|
287
258
|
//#endregion
|
|
288
|
-
//#region src/artifacts/js/css-fn.string-literal.ts
|
|
289
|
-
function generateStringLiteralCssFn(ctx) {
|
|
290
|
-
const { utility, hash, prefix } = ctx;
|
|
291
|
-
const { separator } = utility;
|
|
292
|
-
return {
|
|
293
|
-
dts: outdent.outdent`
|
|
294
|
-
${ctx.file.importType("SystemStyleObject", "../types/index")}
|
|
295
|
-
|
|
296
|
-
type Styles =
|
|
297
|
-
| { raw: readonly string[] | ArrayLike<string> }
|
|
298
|
-
| SystemStyleObject
|
|
299
|
-
| boolean
|
|
300
|
-
| null
|
|
301
|
-
| undefined
|
|
302
|
-
|
|
303
|
-
interface CssRawFunction {
|
|
304
|
-
(...styles: Styles[]): SystemStyleObject
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
interface CssFunction {
|
|
308
|
-
(...styles: Styles[]): string
|
|
309
|
-
|
|
310
|
-
raw: CssRawFunction
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
export declare const css: CssFunction;
|
|
314
|
-
`,
|
|
315
|
-
js: outdent.outdent`
|
|
316
|
-
${ctx.file.import("astish, cloneStyles, createCss, isObject, mergeProps, withoutSpace", "../helpers")}
|
|
317
|
-
${ctx.file.import("finalizeConditions, sortConditions", "./conditions")}
|
|
318
|
-
|
|
319
|
-
function transform(prop, value) {
|
|
320
|
-
const className = \`$\{prop}${separator}$\{withoutSpace(value)}\`
|
|
321
|
-
return { className }
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
const context = {
|
|
325
|
-
hash: ${hash.className ? "true" : "false"},
|
|
326
|
-
conditions: {
|
|
327
|
-
shift: sortConditions,
|
|
328
|
-
finalize: finalizeConditions,
|
|
329
|
-
breakpoints: { keys: [] },
|
|
330
|
-
},
|
|
331
|
-
utility: {
|
|
332
|
-
prefix: ${prefix.className ? JSON.stringify(prefix.className) : void 0},
|
|
333
|
-
transform,
|
|
334
|
-
hasShorthand: false,
|
|
335
|
-
toHash: ${utility.toHash},
|
|
336
|
-
resolveShorthand(prop) {
|
|
337
|
-
return prop
|
|
338
|
-
},
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
const cssFn = createCss(context)
|
|
343
|
-
|
|
344
|
-
const fn = (style) => (isObject(style) ? style : astish(style[0]))
|
|
345
|
-
export const css = (...styles) => cssFn(mergeProps(...styles.filter(Boolean).map(fn)))
|
|
346
|
-
// Same independence guarantee as the object-syntax css.raw(), so the public
|
|
347
|
-
// API behaves identically across both syntaxes.
|
|
348
|
-
css.raw = (...styles) => cloneStyles(mergeProps(...styles.filter(Boolean).map(fn)))
|
|
349
|
-
`
|
|
350
|
-
};
|
|
351
|
-
}
|
|
352
|
-
//#endregion
|
|
353
259
|
//#region src/artifacts/js/cva.ts
|
|
354
260
|
function generateCvaFn(ctx) {
|
|
261
|
+
const { utility, hash, prefix } = ctx;
|
|
262
|
+
const withPrefix = prefix.className ? `(className) => className ? ${JSON.stringify(prefix.className)} + '-' + className : ${JSON.stringify(prefix.className)}` : `(className) => className`;
|
|
355
263
|
return {
|
|
356
264
|
js: outdent.outdent`
|
|
357
|
-
${ctx.file.import("cloneStyles, compact, mergeProps, memo, splitProps, uniq", "../helpers")}
|
|
358
|
-
${ctx.file.import("
|
|
265
|
+
${ctx.file.import("cloneStyles, compact, getRecipeClassNames, getRecipeIdentity, mergeProps, memo, splitProps, toHash, uniq", "../helpers")}
|
|
266
|
+
${ctx.file.import("mergeCss", "./css")}
|
|
267
|
+
|
|
268
|
+
// What \`createCss\` does to a class name, for the recipe path: prefix it, and hash it
|
|
269
|
+
// when \`hash.className\` is set. The build applies the same two steps to the rules it
|
|
270
|
+
// emits — see \`checkNamingAgreement\`, which compares the results.
|
|
271
|
+
const withPrefix = ${withPrefix}
|
|
272
|
+
const formatRecipeClass = ${hash.className ? `(className) => withPrefix((${utility.toHash})([className], toHash))` : `withPrefix`}
|
|
359
273
|
|
|
360
274
|
const defaults = (conf) => ({
|
|
361
275
|
base: {},
|
|
@@ -369,6 +283,11 @@ function generateCvaFn(ctx) {
|
|
|
369
283
|
const { base, variants, defaultVariants, compoundVariants } = defaults(config)
|
|
370
284
|
const getVariantProps = (variants) => ({ ...defaultVariants, ...compact(variants) })
|
|
371
285
|
|
|
286
|
+
// Derived from the config, because the build derives it from the same config while
|
|
287
|
+
// emitting the stylesheet and the two never meet. \`className\` when the author set
|
|
288
|
+
// one, a hash of the styles otherwise.
|
|
289
|
+
const name = getRecipeIdentity(config)
|
|
290
|
+
|
|
372
291
|
function resolve(props = {}) {
|
|
373
292
|
const computedVariants = getVariantProps(props)
|
|
374
293
|
let variantCss = { ...base }
|
|
@@ -377,6 +296,13 @@ function generateCvaFn(ctx) {
|
|
|
377
296
|
variantCss = mergeCss(variantCss, variants[key][value])
|
|
378
297
|
}
|
|
379
298
|
}
|
|
299
|
+
// A recipe with no compound variants has nothing left to merge, and the merge is
|
|
300
|
+
// not free just because its second operand is empty: \`mergeCss\` is memoized on its
|
|
301
|
+
// arguments, so the call hashes the whole accumulated style object before finding
|
|
302
|
+
// there is nothing to do. Most recipes declare no compound variants at all, so
|
|
303
|
+
// this is the common shape rather than a special case.
|
|
304
|
+
if (compoundVariants.length === 0) return variantCss
|
|
305
|
+
|
|
380
306
|
const compoundVariantCss = getCompoundVariantCss(compoundVariants, computedVariants)
|
|
381
307
|
return mergeCss(variantCss, compoundVariantCss)
|
|
382
308
|
}
|
|
@@ -401,10 +327,25 @@ function generateCvaFn(ctx) {
|
|
|
401
327
|
//
|
|
402
328
|
// \`raw\` still clones what it returns. The memoized object is shared, so handing it to a
|
|
403
329
|
// caller that mutated it would poison every later call.
|
|
330
|
+
//
|
|
331
|
+
// A recipe whose variants are all boolean could index an array instead of hashing, and
|
|
332
|
+
// that was built and measured: +25% to +35% on \`raw()\`. It is not here because the
|
|
333
|
+
// trade is bad. Correctness needs the selection read from own enumerable keys only, and
|
|
334
|
+
// every variant to carry a boolean default so the merge order is pinned — and once that
|
|
335
|
+
// gate is honest, no \`cva\`/\`sva\` call site in this repo passes it, because real recipes
|
|
336
|
+
// mix a string variant in. The cost is unconditional: +289 B gzipped on that module for
|
|
337
|
+
// every consumer, qualifying or not.
|
|
404
338
|
const resolveVariants = memo(resolve)
|
|
405
339
|
|
|
340
|
+
// The class names the build emitted rules for: the recipe's own class, plus one per
|
|
341
|
+
// selected variant. Not \`css(resolve(props))\` — that would name classes by property,
|
|
342
|
+
// and the stylesheet names this recipe's rules semantically, in the \`recipes\` layer.
|
|
343
|
+
//
|
|
344
|
+
// Compound variants are absent on purpose. Their rule selects on the variant classes
|
|
345
|
+
// already in this list — \`.btn--size_sm.btn--tone_a\` — so it applies without anything
|
|
346
|
+
// being added here, and adding a class for it would name a rule that does not exist.
|
|
406
347
|
function cvaFn(props) {
|
|
407
|
-
return
|
|
348
|
+
return getRecipeClassNames(name, variants, getVariantProps(props), '${utility.separator}', formatRecipeClass)
|
|
408
349
|
}
|
|
409
350
|
|
|
410
351
|
const variantKeys = Object.keys(variants)
|
|
@@ -463,36 +404,55 @@ function generateCvaFn(ctx) {
|
|
|
463
404
|
}
|
|
464
405
|
//#endregion
|
|
465
406
|
//#region src/artifacts/js/cx.ts
|
|
466
|
-
|
|
407
|
+
/**
|
|
408
|
+
* `cx` joins class names. It does not resolve conflicts between them, in any build.
|
|
409
|
+
*
|
|
410
|
+
* It used to, when the class names happened to carry a property to compare — atomic mode
|
|
411
|
+
* with `hash.className` off. That made it a correctness tool in development and a plain
|
|
412
|
+
* join in a hashed production build, from the same source, with no error either way. An
|
|
413
|
+
* override that worked locally silently stopped working when it shipped.
|
|
414
|
+
*
|
|
415
|
+
* The two could not be reconciled by teaching the matcher to read hashed names.
|
|
416
|
+
* `cssMode: 'grouped'` names a *whole call* with one class — `toHash(['grouped', groupId])`
|
|
417
|
+
* — so there is no single property behind it to compare, whatever the naming scheme. As
|
|
418
|
+
* long as grouped exists, some builds can never merge, and a `cx` that merges in the rest
|
|
419
|
+
* is a behavioural difference keyed on a config flag.
|
|
420
|
+
*
|
|
421
|
+
* So precedence is decided where it can be decided the same way everywhere: by
|
|
422
|
+
* {@link https://bamboocss.com/docs/concepts/cascade-layers cascade layers}. A component
|
|
423
|
+
* whose styles a consumer will override belongs in `recipes` — write it with `cva`/`sva`,
|
|
424
|
+
* not bare `css()` — and the consumer's `css()` in `utilities` wins by layer, in every
|
|
425
|
+
* build. Two `css()` outputs joined with `cx` are in the same layer and resolve by source
|
|
426
|
+
* order; when you own both, merge the style objects with `css(a, b)` instead.
|
|
427
|
+
*/
|
|
428
|
+
const declaration = outdent.default`
|
|
467
429
|
type Argument = string | boolean | null | undefined | Argument[]
|
|
468
430
|
|
|
469
431
|
/**
|
|
470
|
-
* Join classNames into a single string
|
|
432
|
+
* Join classNames into a single string.
|
|
471
433
|
*
|
|
472
|
-
* \`cx('px_4', 'px_2')\`
|
|
473
|
-
*
|
|
474
|
-
*
|
|
475
|
-
*
|
|
434
|
+
* This does **not** resolve conflicts between them: \`cx('px_4', 'px_2')\` keeps both, and
|
|
435
|
+
* the browser picks by their order in the stylesheet rather than by the order you passed
|
|
436
|
+
* them. That is true of every build — atomic, hashed and grouped alike.
|
|
437
|
+
*
|
|
438
|
+
* To override a style rather than append to it, let the cascade decide: styles from
|
|
439
|
+
* \`cva\`/\`sva\` sit in the \`recipes\` layer and \`css()\` in \`utilities\`, so a consumer's
|
|
440
|
+
* \`css()\` always wins. Between two \`css()\` calls you own, merge the objects instead —
|
|
441
|
+
* \`css(base, override)\` resolves per property before any class name exists.
|
|
476
442
|
*/
|
|
477
443
|
export declare function cx(...args: Argument[]): string
|
|
478
444
|
`;
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
* With \`hash.className\` every class is an opaque hash, so there is no property to compare
|
|
483
|
-
* and no merge to do — emitting the matcher would only cost bytes on a path that runs in
|
|
484
|
-
* the browser on every render.
|
|
485
|
-
*/
|
|
486
|
-
function concatOnly() {
|
|
487
|
-
return outdent.default`
|
|
445
|
+
function generateCx() {
|
|
446
|
+
return {
|
|
447
|
+
js: outdent.default`
|
|
488
448
|
function cx(...args) {
|
|
489
449
|
let str = ''
|
|
490
450
|
|
|
491
451
|
for (let i = 0; i < args.length; i++) {
|
|
492
452
|
const arg = args[i]
|
|
493
453
|
if (!arg) continue
|
|
494
|
-
// Arrays are part of the declared type, so this branch has to handle them
|
|
495
|
-
//
|
|
454
|
+
// Arrays are part of the declared type, so this branch has to handle them.
|
|
455
|
+
// Returning '' for \`cx(['a', 'b'])\` would be a lie.
|
|
496
456
|
const part = Array.isArray(arg) ? cx(...arg) : typeof arg === 'string' ? arg : ''
|
|
497
457
|
if (!part) continue
|
|
498
458
|
str && (str += ' ')
|
|
@@ -502,185 +462,18 @@ function concatOnly() {
|
|
|
502
462
|
}
|
|
503
463
|
|
|
504
464
|
export { cx }
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
function generateCx(ctx) {
|
|
508
|
-
const { utility, hash, prefix } = ctx;
|
|
509
|
-
const separatorChar = utility.separator;
|
|
510
|
-
const utilityClassNames = [...new Set(utility.keys().map((key) => {
|
|
511
|
-
const withEmptyValue = utility.getClassName(utility.resolveShorthand(key), "");
|
|
512
|
-
return withEmptyValue.endsWith(separatorChar) ? withEmptyValue.slice(0, -separatorChar.length) : withEmptyValue;
|
|
513
|
-
}))].sort();
|
|
514
|
-
const recipeClassNames = [...new Set(ctx.recipes.details.map((node) => node.className))].filter(Boolean).sort();
|
|
515
|
-
if (hash.className || utilityClassNames.length === 0) return {
|
|
516
|
-
js: concatOnly(),
|
|
517
|
-
dts
|
|
518
|
-
};
|
|
519
|
-
return {
|
|
520
|
-
js: outdent.default`
|
|
521
|
-
const cxSeparator = ${JSON.stringify(utility.separator)}
|
|
522
|
-
const cxPrefix = ${prefix.className ? JSON.stringify(prefix.className + "-") : "''"}
|
|
523
|
-
const cxUtilities = new Set(${JSON.stringify(utilityClassNames.join(","))}.split(','))
|
|
524
|
-
const cxRecipes = ${recipeClassNames.length ? `new Set(${JSON.stringify(recipeClassNames.join(","))}.split(','))` : "null"}
|
|
525
|
-
|
|
526
|
-
/**
|
|
527
|
-
* The declaration a bamboo class sets: its condition path plus the property, without the
|
|
528
|
-
* value. Two classes sharing one are alternatives, and only the last can apply.
|
|
529
|
-
*
|
|
530
|
-
* \`null\` for anything that is not a bamboo class, which is then never merged.
|
|
531
|
-
*/
|
|
532
|
-
function mergeKey(className) {
|
|
533
|
-
let end = className.length
|
|
534
|
-
|
|
535
|
-
// \`c_red\` and \`c_red!\` are the same declaration. Argument order decides between them,
|
|
536
|
-
// which is the point of this function — the cascade would always pick the important
|
|
537
|
-
// one no matter which the caller asked for.
|
|
538
|
-
if (end > 0 && className.charCodeAt(end - 1) === 33) end -= 1
|
|
539
|
-
if (end === 0) return null
|
|
540
|
-
|
|
541
|
-
// The last colon ends the condition path — but only one outside brackets, since an
|
|
542
|
-
// arbitrary selector carries its own: \`[&[data-x="a:b"]]:px_4\`.
|
|
543
|
-
let depth = 0
|
|
544
|
-
let lastColon = -1
|
|
545
|
-
for (let i = 0; i < end; i++) {
|
|
546
|
-
const code = className.charCodeAt(i)
|
|
547
|
-
if (code === 91) depth++
|
|
548
|
-
else if (code === 93) depth--
|
|
549
|
-
else if (code === 58 && depth === 0) lastColon = i
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
// Conditions come before the prefix — \`hover:bam-px_4\` — so the prefix is skipped
|
|
553
|
-
// after the condition path, not before it. When a prefix is configured every class
|
|
554
|
-
// bamboo emits carries it, so one that does not is by definition someone else's.
|
|
555
|
-
let propStart = lastColon + 1
|
|
556
|
-
if (cxPrefix) {
|
|
557
|
-
if (!className.startsWith(cxPrefix, propStart)) return null
|
|
558
|
-
propStart += cxPrefix.length
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
// A recipe owns its whole class, bare or with a \`--variant\` suffix, whatever it
|
|
562
|
-
// looks like to the utility matcher below.
|
|
563
|
-
if (cxRecipes !== null) {
|
|
564
|
-
const variantIdx = className.indexOf('--', propStart)
|
|
565
|
-
const base = variantIdx === -1 ? className.slice(propStart, end) : className.slice(propStart, variantIdx)
|
|
566
|
-
if (cxRecipes.has(base)) return null
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
// The longest registered utility name wins, not the first separator. Utility names
|
|
570
|
-
// contain the separator themselves under \`separator: '-'\` — \`bd-w\`, \`ov-x\`,
|
|
571
|
-
// \`translate-x\` — and their leading segment is often a utility too, so stopping at the
|
|
572
|
-
// first \`-\` would key \`bd-w-4px\` and \`bd-c-red\` both on \`bd\` and drop one of them.
|
|
573
|
-
let property = null
|
|
574
|
-
let sepIdx = className.indexOf(cxSeparator, propStart)
|
|
575
|
-
while (sepIdx > propStart && sepIdx < end) {
|
|
576
|
-
const candidate = className.slice(propStart, sepIdx)
|
|
577
|
-
if (cxUtilities.has(candidate)) property = candidate
|
|
578
|
-
sepIdx = className.indexOf(cxSeparator, sepIdx + 1)
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
// Only a class bamboo generated for a utility. A recipe class or a hand-written one
|
|
582
|
-
// may well contain the separator, and merging on the text before it would drop a
|
|
583
|
-
// class the caller meant to keep.
|
|
584
|
-
if (property === null) return null
|
|
585
|
-
|
|
586
|
-
return lastColon === -1 ? property : className.slice(0, lastColon) + ':' + property
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
function isClassWhitespace(code) {
|
|
590
|
-
return code === 32 || code === 9 || code === 10 || code === 12 || code === 13
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
function flattenParts(parts, out) {
|
|
594
|
-
for (let i = 0; i < parts.length; i++) {
|
|
595
|
-
const part = parts[i]
|
|
596
|
-
if (!part) continue
|
|
597
|
-
if (Array.isArray(part)) flattenParts(part, out)
|
|
598
|
-
else if (typeof part === 'string') out.push(part)
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
function mergeClassStrings(classes) {
|
|
603
|
-
const seen = new Map()
|
|
604
|
-
const order = []
|
|
605
|
-
let id = 0
|
|
606
|
-
|
|
607
|
-
for (let c = 0; c < classes.length; c++) {
|
|
608
|
-
const cls = classes[c]
|
|
609
|
-
let tokenStart = 0
|
|
610
|
-
|
|
611
|
-
for (let i = 0; i <= cls.length; i++) {
|
|
612
|
-
// The class attribute splits on all ASCII whitespace, not just the space, and a
|
|
613
|
-
// multi-line template literal is an ordinary way to write one.
|
|
614
|
-
if (i !== cls.length && !isClassWhitespace(cls.charCodeAt(i))) continue
|
|
615
|
-
if (i === tokenStart) {
|
|
616
|
-
tokenStart = i + 1
|
|
617
|
-
continue
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
const token = cls.slice(tokenStart, i)
|
|
621
|
-
tokenStart = i + 1
|
|
622
|
-
|
|
623
|
-
const key = mergeKey(token)
|
|
624
|
-
if (key !== null) {
|
|
625
|
-
// Keeps the first position and the last value, so a later override lands where
|
|
626
|
-
// the class it replaces already sat.
|
|
627
|
-
if (!seen.has(key)) order.push(key)
|
|
628
|
-
seen.set(key, token)
|
|
629
|
-
} else {
|
|
630
|
-
// Not ours to reason about — kept as written, duplicates and all.
|
|
631
|
-
const uniqueKey = '\\0' + id++
|
|
632
|
-
order.push(uniqueKey)
|
|
633
|
-
seen.set(uniqueKey, token)
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
if (order.length === 0) return ''
|
|
639
|
-
let str = seen.get(order[0])
|
|
640
|
-
for (let i = 1; i < order.length; i++) str += ' ' + seen.get(order[i])
|
|
641
|
-
return str
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
function cx() {
|
|
645
|
-
// Everything that produces a bamboo class string — \`css()\`, a recipe, a nested \`cx\` —
|
|
646
|
-
// emits one that is already conflict-free, so a lone string has nothing to merge and
|
|
647
|
-
// tokenizing it is pure cost. This is the hot path: \`cx(staticClasses, props.className)\`
|
|
648
|
-
// with no \`className\` passed.
|
|
649
|
-
if (arguments.length === 1) {
|
|
650
|
-
const only = arguments[0]
|
|
651
|
-
if (typeof only === 'string') return only
|
|
652
|
-
if (!only) return ''
|
|
653
|
-
}
|
|
654
|
-
|
|
655
|
-
const flat = []
|
|
656
|
-
flattenParts(arguments, flat)
|
|
657
|
-
if (flat.length === 0) return ''
|
|
658
|
-
if (flat.length === 1) return flat[0]
|
|
659
|
-
return mergeClassStrings(flat)
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
export { cx }
|
|
663
|
-
`,
|
|
664
|
-
dts
|
|
465
|
+
`,
|
|
466
|
+
dts: declaration
|
|
665
467
|
};
|
|
666
468
|
}
|
|
667
469
|
//#endregion
|
|
668
|
-
//#region src/artifacts/generated/astish.mjs.json
|
|
669
|
-
var content$11 = "//#region src/astish.ts\nconst newRule = /(?:([\\u0080-\\uFFFF\\w-%@]+) *:? *([^{;]+?);|([^;}{]*?) *{)|(}\\s*)/g;\nconst ruleClean = /\\/\\*[^]*?\\*\\/| +/g;\nconst ruleNewline = /\\n+/g;\nconst empty = \" \";\nconst astish = (val, tree = [{}]) => {\n if (!val) return tree[0];\n let block, left;\n while (block = newRule.exec(val.replace(ruleClean, \"\"))) if (block[4]) tree.shift();\n else if (block[3]) {\n left = block[3].replace(ruleNewline, empty).trim();\n if (!left.includes(\"&\") && !left.startsWith(\"@\")) left = \"& \" + left;\n tree.unshift(tree[0][left] = tree[0][left] || {});\n } else tree[0][block[1]] = block[2].replace(ruleNewline, empty).trim();\n return tree[0];\n};\n//#endregion\nexport { astish };\n";
|
|
670
|
-
//#endregion
|
|
671
470
|
//#region src/artifacts/generated/helpers.mjs.json
|
|
672
|
-
var content$10 = "//#region src/assert.ts\nfunction isObject(value) {\n return typeof value === \"object\" && value != null && !Array.isArray(value);\n}\nconst isObjectOrArray = (obj) => typeof obj === \"object\" && obj !== null;\n//#endregion\n//#region src/condition.ts\nconst isBaseCondition = (v) => v === \"base\";\nfunction filterBaseConditions(c) {\n return c.slice().filter((v) => !isBaseCondition(v));\n}\n//#endregion\n//#region src/hash.ts\nfunction toChar(code) {\n return String.fromCharCode(code + (code > 25 ? 39 : 97));\n}\nfunction toName(code) {\n let name = \"\";\n let x;\n for (x = Math.abs(code); x > 52; x = x / 52 | 0) name = toChar(x % 52) + name;\n return toChar(x % 52) + name;\n}\nfunction toPhash(h, x) {\n let i = x.length;\n while (i) h = h * 33 ^ x.charCodeAt(--i);\n return h;\n}\nfunction toHash(value) {\n return toName(toPhash(5381, value) >>> 0);\n}\n//#endregion\n//#region src/important.ts\nconst importantRegex = /\\s*!(important)?/i;\nconst whitespaceRegex = /\\s/;\n/**\n* Collapse every run of whitespace to a single space, which is what the class name is\n* built from. Exported because `leafClass` has to reproduce this exact pipeline, and a\n* second copy of it would be free to drift from the one `createCss` runs.\n*/\nfunction sanitize(value) {\n if (typeof value !== \"string\") return value;\n const collapsed = whitespaceRegex.test(value) ? value.replaceAll(/[\\n\\s]+/g, \" \") : value;\n return collapsed.includes(\"\\0\") ? collapsed.replaceAll(\"\\0\", \"\") : collapsed;\n}\nfunction isImportant(value) {\n if (typeof value !== \"string\") return false;\n return value.includes(\"!\") && importantRegex.test(value);\n}\nfunction withoutImportant(value) {\n if (typeof value !== \"string\") return value;\n if (!value.includes(\"!\")) return value.trim();\n return value.replace(importantRegex, \"\").trim();\n}\nfunction withoutSpace(str) {\n if (typeof str !== \"string\") return str;\n return str.includes(\" \") ? str.replaceAll(\" \", \"_\") : str;\n}\n//#endregion\n//#region src/memo.ts\n/**\n* Bounded argument memo used by the generated runtime (`css`, patterns, `cva`, recipes).\n*\n* Two regimes, picked per call:\n*\n* - Arguments that are flat (objects of primitives) take a cheap structural hash\n* and are confirmed with an exact comparison, so a hash collision can never\n* serve the wrong result. This is the shape `css({ ... })` has.\n* - Anything nested falls back to `JSON.stringify`, which V8 does faster than a\n* JS walk.\n*\n* The second point is the counter-intuitive one, and it has been measured rather\n* than assumed. Extending the structural hash to recurse — so nested styles could\n* take the fast path too — is *slower*, because it trades one native serialization\n* for two JS walks (hash, then the deep equality that confirms it). Over 10k\n* iterations per shape:\n*\n* shape stringify recursive hash + deep equal\n* flat 1.06ms 2.09ms\n* _hover 1.00ms 2.16ms\n* responsive 1.23ms 2.15ms\n* realistic 2.32ms 5.84ms\n* nested 3 deep 1.22ms 2.35ms\n*\n* So a nested `css()` call costing several times a flat one is not a defect here.\n* It is the floor for a value-keyed memo in JS, and the way to avoid it is to not\n* make the call — see the build-time fold in `@bamboocss/vite`.\n*\n* Both regimes key on *values*, never on object identity: mutating a style object\n* between calls changes its hash, so the next call misses and recomputes rather\n* than serving a stale class. Keying nested arguments on the identity of the inner\n* objects would skip serialization entirely, but it cannot detect a mutation, and\n* \"same object, different contents\" is exactly what a style object built per render\n* looks like.\n*\n* Both caches are bounded. An unbounded memo is a leak in any long-lived process\n* (SSR), where the set of distinct style objects grows without limit.\n*/\n/**\n* Distinct hashes held per memoized function before the cache rotates.\n*\n* This bounds *buckets*, not entries: a bucket keeps up to `MAX_BUCKET` colliding\n* argument lists, so the ceiling is `MAX_ENTRIES * MAX_BUCKET` live entries, and\n* twice that across both generations, since the previous one is retained until the\n* next rotation. Collisions are rare in practice, so the realistic figure is close\n* to `MAX_ENTRIES` — but the worst case is what matters when sizing a long-lived\n* process, so state it plainly.\n*\n* Rotation beats evicting the oldest key: single-key eviction is worst-case for a\n* working set that cycles, because it drops exactly the entry about to be needed.\n* Measured on a cycling set of 20k styles, one-at-a-time eviction cost ~719ns/op\n* against ~189ns unbounded, while rotation holds ~274ns. On realistic skewed\n* access rotation is at or below the unbounded cost.\n*/\nconst MAX_ENTRIES = 1e3;\n/** Entries kept per hash bucket, to bound the cost of a collision scan. */\nconst MAX_BUCKET = 8;\n/**\n* DJB2 over the arguments' own keys and primitive values.\n* Returns `null` for anything nested, which routes the call to the string key.\n*/\nconst flatHashOrNull = (args) => {\n let h = 5381;\n for (let a = 0; a < args.length; a++) {\n const obj = args[a];\n if (obj === null || typeof obj !== \"object\") {\n const t = typeof obj;\n if (t === \"string\") for (let i = 0; i < obj.length; i++) h = h * 33 ^ obj.charCodeAt(i);\n else if (t === \"number\") h = h * 33 ^ (obj | 0);\n else if (t === \"boolean\") h = h * 33 ^ (obj ? 991 : 997);\n else h = h * 33 ^ 3;\n continue;\n }\n if (Array.isArray(obj)) h = h * 33 ^ 7;\n else {\n const proto = Object.getPrototypeOf(obj);\n if (proto !== Object.prototype && proto !== null) return null;\n }\n for (const k in obj) {\n const v = obj[k];\n const tv = typeof v;\n if (v !== null && tv === \"object\") return null;\n for (let i = 0; i < k.length; i++) h = h * 33 ^ k.charCodeAt(i);\n if (tv === \"string\") for (let i = 0; i < v.length; i++) h = h * 33 ^ v.charCodeAt(i);\n else if (tv === \"number\") h = h * 33 ^ (v | 0);\n else if (tv === \"boolean\") h = h * 33 ^ (v ? 991 : 997);\n else h = h * 33 ^ 2;\n }\n }\n return h >>> 0;\n};\n/**\n* Value snapshot of the arguments, taken once at insert.\n*\n* The cache must not hold the caller's objects: a style object can capture a much\n* larger graph, and keeping it alive until the cache rotates changes GC behaviour\n* for code that never asked to be cached. Only the flat path reaches here, so a\n* shallow copy contains primitives only and retains nothing.\n*\n* Comparing against a copy also removes the last way a mutation could be missed.\n* Were the caller's own object stored, `oa === ob` would short-circuit the value\n* comparison, and a mutation that happened to preserve the hash would return the\n* stale entry. Against a copy that check can only ever be true for equal\n* primitives.\n*/\nconst snapshotArgs = (args) => {\n const values = [];\n const counts = [];\n for (let i = 0; i < args.length; i++) {\n const o = args[i];\n if (o !== null && typeof o === \"object\") {\n const copy = Array.isArray(o) ? [] : {};\n let n = 0;\n for (const k in o) {\n copy[k] = o[k];\n n++;\n }\n values.push(copy);\n counts.push(n);\n } else {\n values.push(o);\n counts.push(0);\n }\n }\n return {\n values,\n counts\n };\n};\n/**\n* Exact match, so a `flatHashOrNull` collision is resolved rather than trusted.\n* `bCounts` is the cached side's key count; comparing against it avoids the\n* `Object.keys()` allocation this would otherwise make on every cache hit.\n*/\nconst flatArgsEqual = (a, b, bCounts) => {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n const oa = a[i];\n const ob = b[i];\n if (oa === ob) continue;\n if (oa === null || ob === null || typeof oa !== \"object\" || typeof ob !== \"object\") return false;\n if (Array.isArray(oa) !== Array.isArray(ob)) return false;\n let n = 0;\n for (const k in oa) {\n if (oa[k] !== ob[k]) return false;\n n++;\n }\n if (n !== bCounts[i]) return false;\n }\n return true;\n};\nconst memo = (fn) => {\n let buckets = /* @__PURE__ */ new Map();\n let priorBuckets = /* @__PURE__ */ new Map();\n let strings = /* @__PURE__ */ new Map();\n let priorStrings = /* @__PURE__ */ new Map();\n /**\n * One scalar argument, keyed directly.\n *\n * This is the shape of the hottest callers — `isCssProperty(prop)` runs per prop\n * per render — and a plain map lookup beats hashing, bucket scanning and\n * snapshotting for it. Distinct types stay distinct keys, so `1` and `'1'` do not\n * share an entry.\n */\n let scalars = /* @__PURE__ */ new Map();\n let priorScalars = /* @__PURE__ */ new Map();\n const scan = (bucket, args) => {\n if (bucket) for (let i = 0; i < bucket.length; i++) {\n const entry = bucket[i];\n if (flatArgsEqual(args, entry.values, entry.counts)) return entry;\n }\n };\n const get = (...args) => {\n if (args.length === 1) {\n const only = args[0];\n if (only === null || typeof only !== \"object\") {\n if (scalars.has(only)) return scalars.get(only);\n if (priorScalars.has(only)) {\n const promoted = priorScalars.get(only);\n scalars.set(only, promoted);\n return promoted;\n }\n const out = fn(only);\n scalars.set(only, out);\n if (scalars.size > MAX_ENTRIES) {\n priorScalars = scalars;\n scalars = /* @__PURE__ */ new Map();\n }\n return out;\n }\n }\n const hash = flatHashOrNull(args);\n if (hash !== null) {\n let bucket = buckets.get(hash);\n const hit = scan(bucket, args);\n if (hit) return hit.out;\n const priorHit = scan(priorBuckets.get(hash), args);\n if (priorHit) {\n if (!bucket) {\n bucket = [];\n buckets.set(hash, bucket);\n }\n bucket.push(priorHit);\n if (bucket.length > MAX_BUCKET) bucket.shift();\n return priorHit.out;\n }\n const snap = snapshotArgs(args);\n const out = fn(...args);\n if (!bucket) {\n bucket = [];\n buckets.set(hash, bucket);\n }\n bucket.push({\n values: snap.values,\n counts: snap.counts,\n out\n });\n if (bucket.length > MAX_BUCKET) bucket.shift();\n if (buckets.size > MAX_ENTRIES) {\n priorBuckets = buckets;\n buckets = /* @__PURE__ */ new Map();\n }\n return out;\n }\n const key = JSON.stringify(args);\n if (strings.has(key)) return strings.get(key);\n if (priorStrings.has(key)) {\n const promoted = priorStrings.get(key);\n strings.set(key, promoted);\n return promoted;\n }\n const out = fn(...args);\n strings.set(key, out);\n if (strings.size > MAX_ENTRIES) {\n priorStrings = strings;\n strings = /* @__PURE__ */ new Map();\n }\n return out;\n };\n return get;\n};\n//#endregion\n//#region src/merge-props.ts\nconst MERGE_OMIT = new Set([\n \"__proto__\",\n \"constructor\",\n \"prototype\"\n]);\nfunction mergeProps(...sources) {\n return sources.reduce((prev, obj) => {\n if (!obj) return prev;\n Object.keys(obj).forEach((key) => {\n if (MERGE_OMIT.has(key)) return;\n const prevValue = prev[key];\n const value = obj[key];\n if (isObject(prevValue) && isObject(value)) prev[key] = mergeProps(prevValue, value);\n else prev[key] = value;\n });\n return prev;\n }, {});\n}\n//#endregion\n//#region src/walk-object.ts\nconst isNotNullish = (element) => element != null;\nfunction walkObject(target, predicate, options = {}) {\n const { stop, getKey } = options;\n function inner(value, path = []) {\n if (isObjectOrArray(value)) {\n const result = {};\n for (const [prop, child] of Object.entries(value)) {\n const key = getKey?.(prop, child) ?? prop;\n const childPath = [...path, key];\n if (stop?.(value, childPath)) return predicate(value, path);\n const next = inner(child, childPath);\n if (isNotNullish(next)) result[key] = next;\n }\n return result;\n }\n return predicate(value, path);\n }\n return inner(target);\n}\nfunction mapObject(obj, fn) {\n if (Array.isArray(obj)) return obj.map((value) => fn(value));\n if (!isObject(obj)) return fn(obj);\n return walkObject(obj, (value) => fn(value));\n}\n//#endregion\n//#region src/normalize-style-object.ts\nfunction toResponsiveObject(values, breakpoints) {\n return values.reduce((acc, current, index) => {\n const key = breakpoints[index];\n if (current != null) acc[key] = current;\n return acc;\n }, {});\n}\n/**\n* Whether walking the object would only rebuild it.\n*\n* Normalizing does three things: it renames a shorthand to its longhand, expands a responsive\n* array into a breakpoint object, and drops nullish leaves. A flat object of plain values\n* written in longhand needs none of them, and that is most of what `css()` is handed — but it\n* still paid for a full rebuild plus a path array per key.\n*\n* Every clause has to be exact, since a false positive returns an object the walk would have\n* changed. Nullish is one of them: a leaf the walk removes must not survive, or a later merge\n* would see it override the value beneath it. The array check is another, and it is on the\n* container as well as the values — `stop` is handed the container, so an array arriving at\n* the top level becomes a breakpoint object rather than being walked into.\n*\n* `for...in` reads inherited keys the walk ignores, which is safe in the only direction it can\n* be wrong — an extra key can send this to the slow path, never past it.\n*\n* It does read every value, as `compactStyles` and the argument memo already do, so an\n* accessor prop is read once more than before. Style props are values by the time they get\n* here and reading one has no effect, but it is the reason this cannot be reordered to read\n* lazily.\n*/\nfunction needsNoNormalizing(styles, resolveShorthand) {\n if (Array.isArray(styles)) return false;\n for (const key in styles) {\n const value = styles[key];\n if (value == null || typeof value === \"object\") return false;\n if (resolveShorthand !== void 0 && resolveShorthand(key) !== key) return false;\n }\n return true;\n}\n/**\n* The result may be the argument itself rather than a fresh object, so callers have to treat\n* it as read-only. Every one of them does today: merging accumulates into its own object and\n* the two `raw()` helpers clone at the boundary.\n*/\nfunction normalizeStyleObject(styles, context, shorthand = true) {\n const { utility, conditions } = context;\n const { hasShorthand, resolveShorthand } = utility;\n if (needsNoNormalizing(styles, shorthand && hasShorthand ? resolveShorthand : void 0)) return styles;\n return walkObject(styles, (value) => {\n return Array.isArray(value) ? toResponsiveObject(value, conditions.breakpoints.keys) : value;\n }, {\n stop: (value) => Array.isArray(value),\n getKey: shorthand ? (prop) => hasShorthand ? resolveShorthand(prop) : prop : void 0\n });\n}\n//#endregion\n//#region src/classname.ts\nconst fallbackCondition = {\n shift: (v) => v,\n finalize: (v) => v,\n breakpoints: { keys: [] }\n};\nconst ENTRY_SEP = \"]___[\";\nconst COND_SEP = \"<___>\";\nfunction createCss(context) {\n const { utility, hash, grouped, conditions: conds = fallbackCondition } = context;\n const { prefix } = utility;\n const formatClassName = prefix ? (str) => str ? `${prefix}-${str}` : prefix : (str) => str || \"\";\n const hashFn = (conditions, className) => {\n if (hash) {\n const baseArray = [...conds.finalize(conditions), className];\n return formatClassName(utility.toHash(baseArray, toHash));\n }\n const finalized = conds.finalize(conditions);\n if (finalized.length === 0) return formatClassName(className);\n return [...finalized, formatClassName(className)].join(\":\");\n };\n if (grouped) return memo(({ base, ...styles } = {}) => {\n const normalizedObject = normalizeStyleObject(Object.assign(styles, base), context);\n const hashes = [];\n walkObject(normalizedObject, (value, paths) => {\n if (value == null) return;\n const [prop, ...allConditions] = conds.shift(paths);\n const conditions = filterBaseConditions(allConditions);\n const parts = [`${prop}${ENTRY_SEP}value:${value}`];\n if (conditions.length) parts.push(`cond:${conditions.join(COND_SEP)}`);\n hashes.push(parts.join(ENTRY_SEP));\n });\n if (hashes.length === 0) return \"\";\n hashes.sort();\n const groupId = hashes.join(\"|\");\n return formatClassName(utility.toHash([\"grouped\", groupId], toHash));\n });\n return memo(({ base, ...styles } = {}) => {\n const normalizedObject = normalizeStyleObject(Object.assign(styles, base), context);\n const classNames = /* @__PURE__ */ new Set();\n walkObject(normalizedObject, (value, paths) => {\n if (value == null) return;\n const important = isImportant(value);\n const [prop, ...allConditions] = conds.shift(paths);\n let className = hashFn(filterBaseConditions(allConditions), utility.transform(prop, withoutImportant(sanitize(value))).className);\n if (important) className = `${className}!`;\n classNames.add(className);\n });\n return Array.from(classNames).join(\" \");\n });\n}\n/**\n* Whether a style object carries anything `compact` would have kept.\n*\n* The question `compactStyles` asks is only ever \"is this empty once undefined values are\n* dropped\", but it used to answer it by building the compacted object and then a key array\n* for it, then throwing both away. `Object.keys` enumerates exactly what `compact`'s\n* `Object.entries` did — own, enumerable, string-keyed — so this is the same predicate\n* without the two allocations, and it stops at the first value that settles it.\n*/\nfunction hasDefinedValue(style) {\n const keys = Object.keys(style);\n for (let i = 0; i < keys.length; i++) if (style[keys[i]] !== void 0) return true;\n return false;\n}\nfunction compactStyles(...styles) {\n return styles.flat().filter((style) => isObject(style) && hasDefinedValue(style));\n}\nfunction createMergeCss(context) {\n function resolve(styles) {\n const allStyles = compactStyles(...styles);\n if (allStyles.length === 1) return allStyles;\n return allStyles.map((style) => normalizeStyleObject(style, context));\n }\n function mergeCss(...styles) {\n return mergeProps(...resolve(styles));\n }\n function assignCss(...styles) {\n return Object.assign({}, ...resolve(styles));\n }\n return {\n mergeCss: memo(mergeCss),\n assignCss\n };\n}\n//#endregion\n//#region src/clone-styles.ts\nconst OMIT = new Set([\n \"__proto__\",\n \"constructor\",\n \"prototype\"\n]);\n/**\n* Independent copy of a style object, nested condition blocks included.\n*\n* Merged style objects are cached, so anything handed to user code has to be\n* copied first: a caller mutating what it received would otherwise change what\n* every later caller reads back. `css.raw()` and `cva.raw()` are those boundaries.\n*\n* Kept separate from `mergeProps` deliberately. Merging is on the hot path — it\n* runs on every `css()` cache miss and on every render of a pattern component\n* under `jsxStyleProps: 'minimal'` — and copying there charges every caller for a\n* guarantee only the two `raw()` helpers need. Measured on a realistic style\n* object (5 base properties, 4 condition blocks) that was roughly twice the cost\n* of merging alone.\n*/\nfunction cloneStyles(styles) {\n if (Array.isArray(styles)) return styles.map((value) => cloneStyles(value));\n if (!isObject(styles)) return styles;\n const out = {};\n for (const key of Object.keys(styles)) {\n if (OMIT.has(key)) continue;\n out[key] = cloneStyles(styles[key]);\n }\n return out;\n}\n//#endregion\n//#region src/compact.ts\nfunction compact(value) {\n return Object.fromEntries(Object.entries(value ?? {}).filter(([_, value]) => value !== void 0));\n}\n//#endregion\n//#region src/leaf-class.ts\n/**\n* The class a single dynamic style leaf resolves to, given the prefix its property and\n* condition path produce.\n*\n* ## Why this can exist at all\n*\n* `css()` builds a class from the value alone — `utility.transform` is string\n* construction over a static map, and nothing consults which rules were actually emitted.\n* So `css({ color: tone })` already returns `c_<tone>` for a value the extractor never\n* saw, with no CSS behind it. Reproducing that string here cannot be less correct than\n* the call it replaces; it just skips the object literal, the merge and the memo.\n*\n* ## Why it is not a template literal\n*\n* Three shapes do not reduce to `prefix + value`, and all three return `undefined` so the\n* caller runs `css()` instead:\n*\n* - An array is expanded to a responsive object by `normalizeStyleObject`, so it produces\n* one class per breakpoint rather than one class.\n* - An object is a condition block, walked into for the same reason.\n* - `null` and `undefined` are skipped by the walk entirely, which is an empty string\n* rather than a class — that one is answered here, since it needs no `css()` call.\n*\n* ## Why the character scan\n*\n* The remaining work — collapsing whitespace, stripping `!important`, turning spaces into\n* underscores — is three regexes, and paying them per call makes this *slower* than a\n* memo hit. Almost no token value contains whitespace or `!`, so one scan for the\n* characters that make any of it necessary sends the common value straight to a\n* concatenation. A false positive only costs the slow path, so the scan errs wide.\n*/\nfunction leafClass(prefix, value) {\n if (value == null) return \"\";\n const type = typeof value;\n if (type === \"number\" || type === \"boolean\") return `${prefix}${value}`;\n if (type !== \"string\") return void 0;\n const str = value;\n for (let index = 0; index < str.length; index++) {\n const code = str.charCodeAt(index);\n if (code <= 33 || code === 160 || code === 5760 || code >= 8192) return slowLeaf(prefix, str);\n }\n return `${prefix}${str}`;\n}\n/** The full pipeline `createCss` runs, for a value that needs it. */\nfunction slowLeaf(prefix, value) {\n const important = isImportant(value);\n const className = `${prefix}${withoutSpace(withoutImportant(sanitize(value)))}`;\n return important ? `${className}!` : className;\n}\n//#endregion\n//#region src/hypenate-property.ts\nconst wordRegex = /([A-Z])/g;\nconst msRegex = /^ms-/;\nconst hypenateProperty = memo((property) => {\n if (property.startsWith(\"--\")) return property;\n return property.replace(wordRegex, \"-$1\").replace(msRegex, \"-ms-\").toLowerCase();\n});\n//#endregion\n//#region src/is-css-function.ts\nconst fnRegExp = new RegExp(`^(${[\n \"min\",\n \"max\",\n \"clamp\",\n \"calc\"\n].join(\"|\")})\\\\(.*\\\\)`);\nconst isCssFunction = (v) => typeof v === \"string\" && fnRegExp.test(v);\n//#endregion\n//#region src/is-css-unit.ts\nconst lengthUnitsPattern = `(?:${\"cm,mm,Q,in,pc,pt,px,em,ex,ch,rem,lh,rlh,vw,vh,vmin,vmax,vb,vi,svw,svh,lvw,lvh,dvw,dvh,cqw,cqh,cqi,cqb,cqmin,cqmax,%\".split(\",\").join(\"|\")})`;\nconst lengthRegExp = new RegExp(`^[+-]?[0-9]*.?[0-9]+(?:[eE][+-]?[0-9]+)?${lengthUnitsPattern}$`);\nconst isCssUnit = (v) => typeof v === \"string\" && lengthRegExp.test(v);\n//#endregion\n//#region src/is-css-var.ts\nconst isCssVar = (v) => typeof v === \"string\" && /^var\\(--.+\\)$/.test(v);\n//#endregion\n//#region src/pattern-fns.ts\nconst patternFns = {\n map: mapObject,\n isCssFunction,\n isCssVar,\n isCssUnit\n};\nconst getPatternStyles = (pattern, styles) => {\n if (!pattern?.defaultValues) return styles;\n const defaults = typeof pattern.defaultValues === \"function\" ? pattern.defaultValues(styles) : pattern.defaultValues;\n return Object.assign({}, defaults, compact(styles));\n};\n//#endregion\n//#region src/slot.ts\nconst getSlotRecipes = (recipe = {}) => {\n const init = (slot) => ({\n className: [recipe.className, slot].filter(Boolean).join(\"__\"),\n base: recipe.base?.[slot] ?? {},\n variants: {},\n defaultVariants: recipe.defaultVariants ?? {},\n compoundVariants: recipe.compoundVariants ? getSlotCompoundVariant(recipe.compoundVariants, slot) : []\n });\n const recipeParts = (recipe.slots ?? []).map((slot) => [slot, init(slot)]);\n for (const [variantsKey, variantsSpec] of Object.entries(recipe.variants ?? {})) for (const [variantKey, variantSpec] of Object.entries(variantsSpec)) recipeParts.forEach(([slot, slotRecipe]) => {\n slotRecipe.variants[variantsKey] ??= {};\n slotRecipe.variants[variantsKey][variantKey] = variantSpec[slot] ?? {};\n });\n return Object.fromEntries(recipeParts);\n};\nconst getSlotCompoundVariant = (compoundVariants, slotName) => compoundVariants.filter((compoundVariant) => compoundVariant.css[slotName]).map((compoundVariant) => ({\n ...compoundVariant,\n css: compoundVariant.css[slotName]\n}));\n//#endregion\n//#region src/split-props.ts\n/**\n* Deal a props object into one bucket per key group, plus a final bucket for the rest.\n* A key goes to the first group that claims it.\n*\n* ## Why the descriptor is read per key rather than in bulk\n*\n* This used to call `Object.getOwnPropertyDescriptors` for the whole object and\n* `defineProperty` for every key it moved. Copying plain values instead is 2.4–2.9x faster\n* on the shapes that allow it, but it is only correct where props are data — and they are\n* not always. Solid compiles props to accessors, so reading one eagerly runs whatever it\n* wraps: splitting a component's props would construct its children before the surrounding\n* provider exists.\n*\n* So the descriptor is fetched per key, and the value path is taken only when it changes\n* nothing observable. An accessor keeps its laziness, a non-enumerable key keeps its\n* invisibility, and `__proto__` is defined rather than assigned so it stays an own\n* property instead of reaching the prototype setter.\n*\n* The one thing the value path drops is `writable`/`configurable`, so a bucket key taken\n* from frozen props is writable where it used to be frozen. Nothing here relies on that,\n* and preserving it would mean `defineProperty` on the common path — the cost this exists\n* to avoid. Keys that take the descriptor path keep theirs, so a bucket can be\n* inconsistent in that one respect.\n*\n* Key order within a bucket is preserved exactly. It is not cosmetic: `cva` merges\n* variant props in iteration order, and the parser reads the rest bucket as the style\n* props it encodes, so order reaches the emitted CSS.\n*/\nfunction splitProps(props, ...keys) {\n const allKeys = Object.getOwnPropertyNames(props);\n const own = new Set(allKeys);\n const taken = /* @__PURE__ */ new Set();\n const split = (group) => {\n const clone = {};\n for (let i = 0; i < group.length; i++) {\n const key = group[i];\n if (taken.has(key) || !own.has(key)) continue;\n const descriptor = Object.getOwnPropertyDescriptor(props, key);\n if (!descriptor) continue;\n if (\"get\" in descriptor || \"set\" in descriptor || !descriptor.enumerable || key === \"__proto__\") Object.defineProperty(clone, key, descriptor);\n else clone[key] = descriptor.value;\n taken.add(key);\n }\n return clone;\n };\n /**\n * The predicate is called with the key alone.\n *\n * Handing it to `filter` passes `(key, index, allKeys)`. A one-parameter predicate cannot\n * see the extras, but a memoized one reads its whole argument list — and the predicates\n * that arrive here are memoized, `isCssProperty` among them. So the memo hashed the entire\n * key array once per prop, and keyed its cache on it: two elements with different prop sets\n * shared no entry even for the same prop name.\n *\n * Worth ~9.7x on that path, and nothing at all on a plain predicate — which is why the\n * bench below it needs a memoized case to see this at all.\n *\n * A loop rather than `filter((k) => key(k))` because the wrapper allocates a closure per\n * group. The two measure the same to within noise; the loop just does not need one.\n */\n const matching = (predicate) => {\n const group = [];\n for (let i = 0; i < allKeys.length; i++) {\n const key = allKeys[i];\n if (predicate(key)) group.push(key);\n }\n return group;\n };\n return keys.map((key) => split(Array.isArray(key) ? key : matching(key))).concat(split(allKeys));\n}\n//#endregion\n//#region src/uniq.ts\nconst uniq = (...items) => {\n const set = items.reduce((acc, currItems) => {\n if (currItems) currItems.forEach((item) => acc.add(item));\n return acc;\n }, /* @__PURE__ */ new Set([]));\n return Array.from(set);\n};\n//#endregion\n//#region src/view-transition.ts\n/**\n* The slots a `viewTransition()` bag accepts, in the order they are emitted.\n*\n* Anything else in the options object is ignored — including by the hash, so adding a\n* comment key or spreading an unrelated object does not fork the class name.\n*/\nconst viewTransitionSlots = [\n \"group\",\n \"imagePair\",\n \"old\",\n \"new\"\n];\n/**\n* Serialize a value with object keys sorted, so two style objects that differ only in\n* authoring order hash to the same class.\n*\n* Values JSON has no encoding for (`undefined`, functions, symbols) serialize as `null`\n* rather than being dropped. Nothing reaches here holding one — `filterSlots` removes\n* nullish slots, and the extractor drops nullish leaves — so this is only a floor: it\n* keeps a hole in an array from shifting the elements after it.\n*\n* Not exported. The name promises a general-purpose stable serializer, and this is not\n* one; `viewTransitionClassName` is the whole reason it exists.\n*/\nfunction stableStringify(value) {\n if (value === null) return \"null\";\n const type = typeof value;\n if (type === \"boolean\") return value ? \"true\" : \"false\";\n if (type === \"number\") return Number.isFinite(value) ? String(value) : \"null\";\n if (type === \"string\") return JSON.stringify(value);\n if (Array.isArray(value)) {\n let out = \"[\";\n for (let index = 0; index < value.length; index++) {\n if (index) out += \",\";\n out += stableStringify(value[index]);\n }\n return out + \"]\";\n }\n if (type === \"object\") {\n const keys = Object.keys(value).sort();\n let out = \"{\";\n for (let index = 0; index < keys.length; index++) {\n if (index) out += \",\";\n const key = keys[index];\n out += JSON.stringify(key) + \":\" + stableStringify(value[key]);\n }\n return out + \"}\";\n }\n return \"null\";\n}\n/**\n* Keep the four known slots, dropping any that is nullish.\n*\n* Both halves of the contract have to agree on what an empty slot is, and only one of\n* them gets a choice. The extractor evaluates the source, and a nullish property is gone\n* from what it hands over — `{ new: undefined }` and `{}` reach the build identically.\n* So absent, `undefined` and `null` collapse here too, and `new: enabled ? {…} : null`\n* hashes to the bag it actually styles.\n*/\nfunction filterSlots(options) {\n const filtered = {};\n if (!options || typeof options !== \"object\") return filtered;\n for (const slot of viewTransitionSlots) {\n const value = options[slot];\n if (value != null) filtered[slot] = value;\n }\n return filtered;\n}\n/**\n* The class a `viewTransition()` call resolves to.\n*\n* This is the whole contract between the build and the runtime: the extractor hashes the\n* options it found in the source, the generated `viewTransition()` hashes the options it\n* is called with, and the CSS only reaches the element if the two agree. They agree by\n* construction — both call this function — but only over what the extractor can see. A\n* value it cannot resolve statically is absent from its side and present on the runtime's,\n* which is why a bag has to be a static object literal to be styled at all.\n*\n* The class is used twice, as the `view-transition-class` value and as the argument to\n* `::view-transition-*(.cls)`, so the prefix applies to both.\n*/\nfunction viewTransitionClassName(options, prefix = \"\") {\n const base = \"vt_\" + toHash(stableStringify(filterSlots(options)));\n return prefix ? prefix + \"-\" + base : base;\n}\n//#endregion\nexport { cloneStyles, compact, createCss, createMergeCss, filterBaseConditions, getPatternStyles, getSlotCompoundVariant, getSlotRecipes, hypenateProperty, isBaseCondition, isObject, leafClass, mapObject, memo, mergeProps, patternFns, splitProps, toHash, uniq, viewTransitionClassName, walkObject, withoutSpace };\n";
|
|
673
|
-
//#endregion
|
|
674
|
-
//#region src/artifacts/generated/normalize-html.mjs.json
|
|
675
|
-
var content$9 = "//#region src/normalize-html.ts\nconst htmlProps = [\n \"htmlSize\",\n \"htmlTranslate\",\n \"htmlWidth\",\n \"htmlHeight\"\n];\nfunction convert(key) {\n return htmlProps.includes(key) ? key.replace(\"html\", \"\").toLowerCase() : key;\n}\nfunction normalizeHTMLProps(props) {\n return Object.fromEntries(Object.entries(props).map(([key, value]) => [convert(key), value]));\n}\nnormalizeHTMLProps.keys = htmlProps;\n//#endregion\nexport { normalizeHTMLProps };\n";
|
|
471
|
+
var content$8 = "//#region src/assert.ts\nfunction isObject(value) {\n return typeof value === \"object\" && value != null && !Array.isArray(value);\n}\nconst isObjectOrArray = (obj) => typeof obj === \"object\" && obj !== null;\n//#endregion\n//#region src/condition.ts\nconst isBaseCondition = (v) => v === \"base\";\nfunction filterBaseConditions(c) {\n return c.slice().filter((v) => !isBaseCondition(v));\n}\n//#endregion\n//#region src/hash.ts\nfunction toChar(code) {\n return String.fromCharCode(code + (code > 25 ? 39 : 97));\n}\nfunction toName(code) {\n let name = \"\";\n let x;\n for (x = Math.abs(code); x > 52; x = x / 52 | 0) name = toChar(x % 52) + name;\n return toChar(x % 52) + name;\n}\nfunction toPhash(h, x) {\n let i = x.length;\n while (i) h = h * 33 ^ x.charCodeAt(--i);\n return h;\n}\nfunction toHash(value) {\n return toName(toPhash(5381, value) >>> 0);\n}\n//#endregion\n//#region src/important.ts\nconst importantRegex = /\\s*!(important)?/i;\nconst whitespaceRegex = /\\s/;\n/**\n* Collapse every run of whitespace to a single space, which is what the class name is\n* built from. Exported because `leafClass` has to reproduce this exact pipeline, and a\n* second copy of it would be free to drift from the one `createCss` runs.\n*/\nfunction sanitize(value) {\n if (typeof value !== \"string\") return value;\n const collapsed = whitespaceRegex.test(value) ? value.replaceAll(/[\\n\\s]+/g, \" \") : value;\n return collapsed.includes(\"\\0\") ? collapsed.replaceAll(\"\\0\", \"\") : collapsed;\n}\nfunction isImportant(value) {\n if (typeof value !== \"string\") return false;\n return value.includes(\"!\") && importantRegex.test(value);\n}\nfunction withoutImportant(value) {\n if (typeof value !== \"string\") return value;\n if (!value.includes(\"!\")) return value.trim();\n return value.replace(importantRegex, \"\").trim();\n}\nfunction withoutSpace(str) {\n if (typeof str !== \"string\") return str;\n return str.includes(\" \") ? str.replaceAll(\" \", \"_\") : str;\n}\n//#endregion\n//#region src/memo.ts\n/**\n* Bounded argument memo used by the generated runtime (`css`, patterns, `cva`, recipes).\n*\n* Two regimes, picked per call:\n*\n* - Arguments that are flat (objects of primitives) take a cheap structural hash\n* and are confirmed with an exact comparison, so a hash collision can never\n* serve the wrong result. This is the shape `css({ ... })` has.\n* - Anything nested falls back to `JSON.stringify`, which V8 does faster than a\n* JS walk.\n*\n* The second point is the counter-intuitive one, and it has been measured rather\n* than assumed. Extending the structural hash to recurse — so nested styles could\n* take the fast path too — is *slower*, because it trades one native serialization\n* for two JS walks (hash, then the deep equality that confirms it). Over 10k\n* iterations per shape:\n*\n* shape stringify recursive hash + deep equal\n* flat 1.06ms 2.09ms\n* _hover 1.00ms 2.16ms\n* responsive 1.23ms 2.15ms\n* realistic 2.32ms 5.84ms\n* nested 3 deep 1.22ms 2.35ms\n*\n* So a nested `css()` call costing several times a flat one is not a defect here.\n* It is the floor for a value-keyed memo in JS, and the way to avoid it is to not\n* make the call — see the build-time fold in `@bamboocss/vite`.\n*\n* Both regimes key on *values*, never on object identity: mutating a style object\n* between calls changes its hash, so the next call misses and recomputes rather\n* than serving a stale class. Keying nested arguments on the identity of the inner\n* objects would skip serialization entirely, but it cannot detect a mutation, and\n* \"same object, different contents\" is exactly what a style object built per render\n* looks like.\n*\n* Both caches are bounded. An unbounded memo is a leak in any long-lived process\n* (SSR), where the set of distinct style objects grows without limit.\n*/\n/**\n* Distinct hashes held per memoized function before the cache rotates.\n*\n* This bounds *buckets*, not entries: a bucket keeps up to `MAX_BUCKET` colliding\n* argument lists, so the ceiling is `MAX_ENTRIES * MAX_BUCKET` live entries, and\n* twice that across both generations, since the previous one is retained until the\n* next rotation. Collisions are rare in practice, so the realistic figure is close\n* to `MAX_ENTRIES` — but the worst case is what matters when sizing a long-lived\n* process, so state it plainly.\n*\n* Rotation beats evicting the oldest key: single-key eviction is worst-case for a\n* working set that cycles, because it drops exactly the entry about to be needed.\n* Measured on a cycling set of 20k styles, one-at-a-time eviction cost ~719ns/op\n* against ~189ns unbounded, while rotation holds ~274ns. On realistic skewed\n* access rotation is at or below the unbounded cost.\n*/\nconst MAX_ENTRIES = 1e3;\n/** Entries kept per hash bucket, to bound the cost of a collision scan. */\nconst MAX_BUCKET = 8;\n/**\n* DJB2 over the arguments' own keys and primitive values.\n* Returns `null` for anything nested, which routes the call to the string key.\n*/\nconst flatHashOrNull = (args) => {\n let h = 5381;\n for (let a = 0; a < args.length; a++) {\n const obj = args[a];\n if (obj === null || typeof obj !== \"object\") {\n const t = typeof obj;\n if (t === \"string\") for (let i = 0; i < obj.length; i++) h = h * 33 ^ obj.charCodeAt(i);\n else if (t === \"number\") h = h * 33 ^ (obj | 0);\n else if (t === \"boolean\") h = h * 33 ^ (obj ? 991 : 997);\n else h = h * 33 ^ 3;\n continue;\n }\n if (Array.isArray(obj)) h = h * 33 ^ 7;\n else {\n const proto = Object.getPrototypeOf(obj);\n if (proto !== Object.prototype && proto !== null) return null;\n }\n for (const k in obj) {\n const v = obj[k];\n const tv = typeof v;\n if (v !== null && tv === \"object\") return null;\n for (let i = 0; i < k.length; i++) h = h * 33 ^ k.charCodeAt(i);\n if (tv === \"string\") for (let i = 0; i < v.length; i++) h = h * 33 ^ v.charCodeAt(i);\n else if (tv === \"number\") h = h * 33 ^ (v | 0);\n else if (tv === \"boolean\") h = h * 33 ^ (v ? 991 : 997);\n else h = h * 33 ^ 2;\n }\n }\n return h >>> 0;\n};\n/**\n* Value snapshot of the arguments, taken once at insert.\n*\n* The cache must not hold the caller's objects: a style object can capture a much\n* larger graph, and keeping it alive until the cache rotates changes GC behaviour\n* for code that never asked to be cached. Only the flat path reaches here, so a\n* shallow copy contains primitives only and retains nothing.\n*\n* Comparing against a copy also removes the last way a mutation could be missed.\n* Were the caller's own object stored, `oa === ob` would short-circuit the value\n* comparison, and a mutation that happened to preserve the hash would return the\n* stale entry. Against a copy that check can only ever be true for equal\n* primitives.\n*/\nconst snapshotArgs = (args) => {\n const values = [];\n const counts = [];\n for (let i = 0; i < args.length; i++) {\n const o = args[i];\n if (o !== null && typeof o === \"object\") {\n const copy = Array.isArray(o) ? [] : {};\n let n = 0;\n for (const k in o) {\n copy[k] = o[k];\n n++;\n }\n values.push(copy);\n counts.push(n);\n } else {\n values.push(o);\n counts.push(0);\n }\n }\n return {\n values,\n counts\n };\n};\n/**\n* Exact match, so a `flatHashOrNull` collision is resolved rather than trusted.\n* `bCounts` is the cached side's key count; comparing against it avoids the\n* `Object.keys()` allocation this would otherwise make on every cache hit.\n*/\nconst flatArgsEqual = (a, b, bCounts) => {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n const oa = a[i];\n const ob = b[i];\n if (oa === ob) continue;\n if (oa === null || ob === null || typeof oa !== \"object\" || typeof ob !== \"object\") return false;\n if (Array.isArray(oa) !== Array.isArray(ob)) return false;\n let n = 0;\n for (const k in oa) {\n if (oa[k] !== ob[k]) return false;\n n++;\n }\n if (n !== bCounts[i]) return false;\n }\n return true;\n};\nconst memo = (fn) => {\n let buckets = /* @__PURE__ */ new Map();\n let priorBuckets = /* @__PURE__ */ new Map();\n let strings = /* @__PURE__ */ new Map();\n let priorStrings = /* @__PURE__ */ new Map();\n /**\n * One scalar argument, keyed directly.\n *\n * This is the shape of the hottest callers — `isCssProperty(prop)` runs per prop\n * per render — and a plain map lookup beats hashing, bucket scanning and\n * snapshotting for it. Distinct types stay distinct keys, so `1` and `'1'` do not\n * share an entry.\n */\n let scalars = /* @__PURE__ */ new Map();\n let priorScalars = /* @__PURE__ */ new Map();\n const scan = (bucket, args) => {\n if (bucket) for (let i = 0; i < bucket.length; i++) {\n const entry = bucket[i];\n if (flatArgsEqual(args, entry.values, entry.counts)) return entry;\n }\n };\n const get = (...args) => {\n if (args.length === 1) {\n const only = args[0];\n if (only === null || typeof only !== \"object\") {\n if (scalars.has(only)) return scalars.get(only);\n if (priorScalars.has(only)) {\n const promoted = priorScalars.get(only);\n scalars.set(only, promoted);\n return promoted;\n }\n const out = fn(only);\n scalars.set(only, out);\n if (scalars.size > MAX_ENTRIES) {\n priorScalars = scalars;\n scalars = /* @__PURE__ */ new Map();\n }\n return out;\n }\n }\n const hash = flatHashOrNull(args);\n if (hash !== null) {\n let bucket = buckets.get(hash);\n const hit = scan(bucket, args);\n if (hit) return hit.out;\n const priorHit = scan(priorBuckets.get(hash), args);\n if (priorHit) {\n if (!bucket) {\n bucket = [];\n buckets.set(hash, bucket);\n }\n bucket.push(priorHit);\n if (bucket.length > MAX_BUCKET) bucket.shift();\n return priorHit.out;\n }\n const snap = snapshotArgs(args);\n const out = fn(...args);\n if (!bucket) {\n bucket = [];\n buckets.set(hash, bucket);\n }\n bucket.push({\n values: snap.values,\n counts: snap.counts,\n out\n });\n if (bucket.length > MAX_BUCKET) bucket.shift();\n if (buckets.size > MAX_ENTRIES) {\n priorBuckets = buckets;\n buckets = /* @__PURE__ */ new Map();\n }\n return out;\n }\n const key = JSON.stringify(args);\n if (strings.has(key)) return strings.get(key);\n if (priorStrings.has(key)) {\n const promoted = priorStrings.get(key);\n strings.set(key, promoted);\n return promoted;\n }\n const out = fn(...args);\n strings.set(key, out);\n if (strings.size > MAX_ENTRIES) {\n priorStrings = strings;\n strings = /* @__PURE__ */ new Map();\n }\n return out;\n };\n return get;\n};\n//#endregion\n//#region src/merge-props.ts\nconst MERGE_OMIT = new Set([\n \"__proto__\",\n \"constructor\",\n \"prototype\"\n]);\nfunction mergeProps(...sources) {\n return sources.reduce((prev, obj) => {\n if (!obj) return prev;\n Object.keys(obj).forEach((key) => {\n if (MERGE_OMIT.has(key)) return;\n const prevValue = prev[key];\n const value = obj[key];\n if (isObject(prevValue) && isObject(value)) prev[key] = mergeProps(prevValue, value);\n else prev[key] = value;\n });\n return prev;\n }, {});\n}\n//#endregion\n//#region src/walk-object.ts\nconst isNotNullish = (element) => element != null;\nfunction walkObject(target, predicate, options = {}) {\n const { stop, getKey } = options;\n function inner(value, path = []) {\n if (isObjectOrArray(value)) {\n const result = {};\n for (const [prop, child] of Object.entries(value)) {\n const key = getKey?.(prop, child) ?? prop;\n const childPath = [...path, key];\n if (stop?.(value, childPath)) return predicate(value, path);\n const next = inner(child, childPath);\n if (isNotNullish(next)) result[key] = next;\n }\n return result;\n }\n return predicate(value, path);\n }\n return inner(target);\n}\nfunction mapObject(obj, fn) {\n if (Array.isArray(obj)) return obj.map((value) => fn(value));\n if (!isObject(obj)) return fn(obj);\n return walkObject(obj, (value) => fn(value));\n}\n//#endregion\n//#region src/normalize-style-object.ts\nfunction toResponsiveObject(values, breakpoints) {\n return values.reduce((acc, current, index) => {\n const key = breakpoints[index];\n if (current != null) acc[key] = current;\n return acc;\n }, {});\n}\n/**\n* Whether walking the object would only rebuild it.\n*\n* Normalizing does three things: it renames a shorthand to its longhand, expands a responsive\n* array into a breakpoint object, and drops nullish leaves. A flat object of plain values\n* written in longhand needs none of them, and that is most of what `css()` is handed — but it\n* still paid for a full rebuild plus a path array per key.\n*\n* Every clause has to be exact, since a false positive returns an object the walk would have\n* changed. Nullish is one of them: a leaf the walk removes must not survive, or a later merge\n* would see it override the value beneath it. The array check is another, and it is on the\n* container as well as the values — `stop` is handed the container, so an array arriving at\n* the top level becomes a breakpoint object rather than being walked into.\n*\n* `for...in` reads inherited keys the walk ignores, which is safe in the only direction it can\n* be wrong — an extra key can send this to the slow path, never past it.\n*\n* It does read every value, as `compactStyles` and the argument memo already do, so an\n* accessor prop is read once more than before. Style props are values by the time they get\n* here and reading one has no effect, but it is the reason this cannot be reordered to read\n* lazily.\n*/\nfunction needsNoNormalizing(styles, resolveShorthand) {\n if (Array.isArray(styles)) return false;\n for (const key in styles) {\n const value = styles[key];\n if (value == null || typeof value === \"object\") return false;\n if (resolveShorthand !== void 0 && resolveShorthand(key) !== key) return false;\n }\n return true;\n}\n/**\n* The result may be the argument itself rather than a fresh object, so callers have to treat\n* it as read-only. Every one of them does today: merging accumulates into its own object and\n* the two `raw()` helpers clone at the boundary.\n*/\nfunction normalizeStyleObject(styles, context, shorthand = true) {\n const { utility, conditions } = context;\n const { hasShorthand, resolveShorthand } = utility;\n if (needsNoNormalizing(styles, shorthand && hasShorthand ? resolveShorthand : void 0)) return styles;\n return walkObject(styles, (value) => {\n return Array.isArray(value) ? toResponsiveObject(value, conditions.breakpoints.keys) : value;\n }, {\n stop: (value) => Array.isArray(value),\n getKey: shorthand ? (prop) => hasShorthand ? resolveShorthand(prop) : prop : void 0\n });\n}\n//#endregion\n//#region src/classname.ts\nconst fallbackCondition = {\n shift: (v) => v,\n finalize: (v) => v,\n breakpoints: { keys: [] }\n};\nconst ENTRY_SEP = \"]___[\";\nconst COND_SEP = \"<___>\";\n/**\n* The class a whole grouped `css()` call resolves to, given its group id.\n*\n* Shared with `StyleDecoder.collectGrouped` on purpose: both sides name this class, and\n* deriving it twice is what let `hash.className` re-hash on the build side only, leaving\n* every grouped element carrying a class no rule was emitted for.\n*\n* A group id already digests every declaration in the call, so it is hashed exactly once\n* and `hash.className` is deliberately not consulted — that option shortens *utility*\n* class names, and a grouped class is not one. The build `esc()`s the result for a\n* selector; the runtime does not. That asymmetry belongs to the callers.\n*/\nfunction groupClassName(groupId, toHashFn, formatClassName) {\n return formatClassName(toHashFn([\"grouped\", groupId], toHash));\n}\nfunction createCss(context) {\n const { utility, hash, grouped, conditions: conds = fallbackCondition } = context;\n const { prefix } = utility;\n const formatClassName = prefix ? (str) => str ? `${prefix}-${str}` : prefix : (str) => str || \"\";\n const hashFn = (conditions, className) => {\n if (hash) {\n const baseArray = [...conds.finalize(conditions), className];\n return formatClassName(utility.toHash(baseArray, toHash));\n }\n const finalized = conds.finalize(conditions);\n if (finalized.length === 0) return formatClassName(className);\n return [...finalized, formatClassName(className)].join(\":\");\n };\n /** One declaration, kept only when there is a fallback that might need to name it. */\n const atomicName = (prop, value, conditions) => {\n const important = isImportant(value);\n const className = hashFn(conditions, utility.transform(prop, withoutImportant(sanitize(value))).className);\n return important ? `${className}!` : className;\n };\n if (grouped) {\n const { knownGroups } = context;\n return memo(({ base, ...styles } = {}) => {\n const normalizedObject = normalizeStyleObject(Object.assign(styles, base), context);\n const hashes = [];\n const leaves = knownGroups ? [] : void 0;\n walkObject(normalizedObject, (value, paths) => {\n if (value == null) return;\n const [prop, ...allConditions] = conds.shift(paths);\n const conditions = filterBaseConditions(allConditions);\n const parts = [`${prop}${ENTRY_SEP}value:${value}`];\n if (conditions.length) parts.push(`cond:${conditions.join(COND_SEP)}`);\n hashes.push(parts.join(ENTRY_SEP));\n leaves?.push([\n prop,\n value,\n conditions\n ]);\n });\n if (hashes.length === 0) return \"\";\n hashes.sort();\n const className = groupClassName(hashes.join(\"|\"), utility.toHash, formatClassName);\n if (!leaves || knownGroups.has(className)) return className;\n const classNames = new Set([className]);\n for (const [prop, value, conditions] of leaves) classNames.add(atomicName(prop, value, conditions));\n return Array.from(classNames).join(\" \");\n });\n }\n return memo(({ base, ...styles } = {}) => {\n const normalizedObject = normalizeStyleObject(Object.assign(styles, base), context);\n const classNames = /* @__PURE__ */ new Set();\n walkObject(normalizedObject, (value, paths) => {\n if (value == null) return;\n const [prop, ...allConditions] = conds.shift(paths);\n classNames.add(atomicName(prop, value, filterBaseConditions(allConditions)));\n });\n return Array.from(classNames).join(\" \");\n });\n}\n/**\n* Whether a style object carries anything `compact` would have kept.\n*\n* The question `compactStyles` asks is only ever \"is this empty once undefined values are\n* dropped\", but it used to answer it by building the compacted object and then a key array\n* for it, then throwing both away. `Object.keys` enumerates exactly what `compact`'s\n* `Object.entries` did — own, enumerable, string-keyed — so this is the same predicate\n* without the two allocations, and it stops at the first value that settles it.\n*/\nfunction hasDefinedValue(style) {\n const keys = Object.keys(style);\n for (let i = 0; i < keys.length; i++) if (style[keys[i]] !== void 0) return true;\n return false;\n}\nfunction compactStyles(...styles) {\n return styles.flat().filter((style) => isObject(style) && hasDefinedValue(style));\n}\nfunction createMergeCss(context) {\n function resolve(styles) {\n const allStyles = compactStyles(...styles);\n if (allStyles.length === 1) return allStyles;\n return allStyles.map((style) => normalizeStyleObject(style, context));\n }\n function mergeCss(...styles) {\n return mergeProps(...resolve(styles));\n }\n function assignCss(...styles) {\n return Object.assign({}, ...resolve(styles));\n }\n return {\n mergeCss: memo(mergeCss),\n assignCss\n };\n}\n//#endregion\n//#region src/clone-styles.ts\nconst OMIT = new Set([\n \"__proto__\",\n \"constructor\",\n \"prototype\"\n]);\n/**\n* Independent copy of a style object, nested condition blocks included.\n*\n* Merged style objects are cached, so anything handed to user code has to be\n* copied first: a caller mutating what it received would otherwise change what\n* every later caller reads back. `css.raw()` and `cva.raw()` are those boundaries.\n*\n* Kept separate from `mergeProps` deliberately. Merging is on the hot path — it\n* runs on every `css()` cache miss and on every render of a pattern component\n* under `jsxStyleProps: 'minimal'` — and copying there charges every caller for a\n* guarantee only the two `raw()` helpers need. Measured on a realistic style\n* object (5 base properties, 4 condition blocks) that was roughly twice the cost\n* of merging alone.\n*/\nfunction cloneStyles(styles) {\n if (Array.isArray(styles)) return styles.map((value) => cloneStyles(value));\n if (!isObject(styles)) return styles;\n const out = {};\n for (const key of Object.keys(styles)) {\n if (OMIT.has(key)) continue;\n out[key] = cloneStyles(styles[key]);\n }\n return out;\n}\n//#endregion\n//#region src/compact.ts\nfunction compact(value) {\n return Object.fromEntries(Object.entries(value ?? {}).filter(([_, value]) => value !== void 0));\n}\n//#endregion\n//#region src/leaf-class.ts\n/**\n* The class a single dynamic style leaf resolves to, given the prefix its property and\n* condition path produce.\n*\n* ## Why this can exist at all\n*\n* `css()` builds a class from the value alone — `utility.transform` is string\n* construction over a static map, and nothing consults which rules were actually emitted.\n* So `css({ color: tone })` already returns `c_<tone>` for a value the extractor never\n* saw, with no CSS behind it. Reproducing that string here cannot be less correct than\n* the call it replaces; it just skips the object literal, the merge and the memo.\n*\n* ## Why it is not a template literal\n*\n* Three shapes do not reduce to `prefix + value`, and all three return `undefined` so the\n* caller runs `css()` instead:\n*\n* - An array is expanded to a responsive object by `normalizeStyleObject`, so it produces\n* one class per breakpoint rather than one class.\n* - An object is a condition block, walked into for the same reason.\n* - `null` and `undefined` are skipped by the walk entirely, which is an empty string\n* rather than a class — that one is answered here, since it needs no `css()` call.\n*\n* ## Why the character scan\n*\n* The remaining work — collapsing whitespace, stripping `!important`, turning spaces into\n* underscores — is three regexes, and paying them per call makes this *slower* than a\n* memo hit. Almost no token value contains whitespace or `!`, so one scan for the\n* characters that make any of it necessary sends the common value straight to a\n* concatenation. A false positive only costs the slow path, so the scan errs wide.\n*/\nfunction leafClass(prefix, value) {\n if (value == null) return \"\";\n const type = typeof value;\n if (type === \"number\" || type === \"boolean\") return `${prefix}${value}`;\n if (type !== \"string\") return void 0;\n const str = value;\n for (let index = 0; index < str.length; index++) {\n const code = str.charCodeAt(index);\n if (code <= 33 || code === 160 || code === 5760 || code >= 8192) return slowLeaf(prefix, str);\n }\n return `${prefix}${str}`;\n}\n/** The full pipeline `createCss` runs, for a value that needs it. */\nfunction slowLeaf(prefix, value) {\n const important = isImportant(value);\n const className = `${prefix}${withoutSpace(withoutImportant(sanitize(value)))}`;\n return important ? `${className}!` : className;\n}\n//#endregion\n//#region src/hypenate-property.ts\nconst wordRegex = /([A-Z])/g;\nconst msRegex = /^ms-/;\nconst hypenateProperty = memo((property) => {\n if (property.startsWith(\"--\")) return property;\n return property.replace(wordRegex, \"-$1\").replace(msRegex, \"-ms-\").toLowerCase();\n});\n//#endregion\n//#region src/recipe-identity.ts\n/** The fields that decide what CSS a recipe produces. Anything else is metadata. */\nconst STYLE_FIELDS = [\n \"base\",\n \"variants\",\n \"compoundVariants\",\n \"defaultVariants\"\n];\n/**\n* A serialization that depends on the config's *content* and not on how it was written.\n*\n* Object keys are sorted, so reordering two variants in the source does not rename every\n* class the recipe emits. Arrays keep their order, because `compoundVariants` is precedence\n* ordered and two orderings are two different recipes.\n*\n* A function serializes to `null` rather than to its source. `JSON.stringify` already drops\n* them, and stringifying instead would key the name on whether the bundle was minified —\n* the same build-dependent divergence that `cx` was changed to avoid. Nothing that survives\n* static extraction is a function, so there is no real config this loses information about.\n*/\nconst stable = (value) => {\n if (value === null || typeof value !== \"object\") return JSON.stringify(value) ?? \"null\";\n if (Array.isArray(value)) return `[${value.map(stable).join(\",\")}]`;\n const source = value;\n return `{${Object.keys(source).sort().map((key) => `${JSON.stringify(key)}:${stable(source[key])}`).join(\",\")}}`;\n};\n/**\n* The name an inline `cva`/`sva` emits its classes under — `button--size_sm`, where this\n* returns the `button`.\n*\n* A config recipe gets its name from the key it is declared under. An inline one has no\n* such key, and the two places that need the name never meet: the build derives it while\n* emitting the stylesheet, the runtime derives it again in the browser. So it has to come\n* from something both of them see, which leaves the config object itself.\n*\n* Deriving it from the *binding* — `const button = cva(...)` — was the obvious alternative\n* and does not work. Only the build can see that binding; handing it to the runtime means\n* rewriting the call, and then a pipeline without that transform names classes differently\n* from one with it. An optional `className` gets the same readable output with none of\n* that, because it travels inside the config to both sides.\n*\n* `className` is the field a config recipe already names itself with, and it means the same\n* thing here — the prefix every class the recipe emits is built from. An inline recipe that\n* declares one is indistinguishable in the stylesheet from a recipe declared in config.\n*/\nconst getRecipeIdentity = (config, prefix = \"cva\") => {\n const declared = config?.className;\n if (typeof declared === \"string\" && declared) return declared;\n const styles = {};\n for (const field of STYLE_FIELDS) {\n const value = config?.[field];\n if (value !== void 0) styles[field] = value;\n }\n return `${prefix}_${toHash(stable(styles))}`;\n};\n/**\n* The classes a recipe puts on an element: its own, plus one per selected variant.\n*\n* Lives here rather than in the generated `cva` because the build has to be able to check\n* it. `checkNamingAgreement` derives class names both ways and compares them, and it can\n* only do that against the code the browser actually runs — a second implementation written\n* to match would agree with itself and prove nothing.\n*\n* Compound variants are absent by design. Their rule selects on the variant classes already\n* in this list, so it applies without a class of its own.\n*/\nconst getRecipeClassNames = (name, variants, selection, separator = \"_\", format = (className) => className) => {\n let result = format(name);\n for (const variant of Object.keys(variants ?? {})) {\n const value = selection[variant];\n if (value == null) continue;\n if (variants?.[variant]?.[value] == null) continue;\n result += ` ${format(`${name}--${variant}${separator}${withoutSpace(value)}`)}`;\n }\n return result;\n};\n//#endregion\n//#region src/is-css-function.ts\nconst fnRegExp = new RegExp(`^(${[\n \"min\",\n \"max\",\n \"clamp\",\n \"calc\"\n].join(\"|\")})\\\\(.*\\\\)`);\nconst isCssFunction = (v) => typeof v === \"string\" && fnRegExp.test(v);\n//#endregion\n//#region src/is-css-unit.ts\nconst lengthUnitsPattern = `(?:${\"cm,mm,Q,in,pc,pt,px,em,ex,ch,rem,lh,rlh,vw,vh,vmin,vmax,vb,vi,svw,svh,lvw,lvh,dvw,dvh,cqw,cqh,cqi,cqb,cqmin,cqmax,%\".split(\",\").join(\"|\")})`;\nconst lengthRegExp = new RegExp(`^[+-]?[0-9]*.?[0-9]+(?:[eE][+-]?[0-9]+)?${lengthUnitsPattern}$`);\nconst isCssUnit = (v) => typeof v === \"string\" && lengthRegExp.test(v);\n//#endregion\n//#region src/is-css-var.ts\nconst isCssVar = (v) => typeof v === \"string\" && /^var\\(--.+\\)$/.test(v);\n//#endregion\n//#region src/pattern-fns.ts\nconst patternFns = {\n map: mapObject,\n isCssFunction,\n isCssVar,\n isCssUnit\n};\nconst getPatternStyles = (pattern, styles) => {\n if (!pattern?.defaultValues) return styles;\n const defaults = typeof pattern.defaultValues === \"function\" ? pattern.defaultValues(styles) : pattern.defaultValues;\n return Object.assign({}, defaults, compact(styles));\n};\n//#endregion\n//#region src/slot.ts\nconst getSlotRecipes = (recipe = {}) => {\n const init = (slot) => ({\n className: [recipe.className, slot].filter(Boolean).join(\"__\"),\n base: recipe.base?.[slot] ?? {},\n variants: {},\n defaultVariants: recipe.defaultVariants ?? {},\n compoundVariants: recipe.compoundVariants ? getSlotCompoundVariant(recipe.compoundVariants, slot) : []\n });\n const recipeParts = (recipe.slots ?? []).map((slot) => [slot, init(slot)]);\n for (const [variantsKey, variantsSpec] of Object.entries(recipe.variants ?? {})) for (const [variantKey, variantSpec] of Object.entries(variantsSpec)) recipeParts.forEach(([slot, slotRecipe]) => {\n slotRecipe.variants[variantsKey] ??= {};\n slotRecipe.variants[variantsKey][variantKey] = variantSpec[slot] ?? {};\n });\n return Object.fromEntries(recipeParts);\n};\nconst getSlotCompoundVariant = (compoundVariants, slotName) => compoundVariants.filter((compoundVariant) => compoundVariant.css[slotName]).map((compoundVariant) => ({\n ...compoundVariant,\n css: compoundVariant.css[slotName]\n}));\n//#endregion\n//#region src/split-props.ts\n/**\n* Deal a props object into one bucket per key group, plus a final bucket for the rest.\n* A key goes to the first group that claims it.\n*\n* ## Why the descriptor is read per key rather than in bulk\n*\n* This used to call `Object.getOwnPropertyDescriptors` for the whole object and\n* `defineProperty` for every key it moved. Copying plain values instead is 2.4–2.9x faster\n* on the shapes that allow it, but it is only correct where props are data — and they are\n* not always. Solid compiles props to accessors, so reading one eagerly runs whatever it\n* wraps: splitting a component's props would construct its children before the surrounding\n* provider exists.\n*\n* So the descriptor is fetched per key, and the value path is taken only when it changes\n* nothing observable. An accessor keeps its laziness, a non-enumerable key keeps its\n* invisibility, and `__proto__` is defined rather than assigned so it stays an own\n* property instead of reaching the prototype setter.\n*\n* The one thing the value path drops is `writable`/`configurable`, so a bucket key taken\n* from frozen props is writable where it used to be frozen. Nothing here relies on that,\n* and preserving it would mean `defineProperty` on the common path — the cost this exists\n* to avoid. Keys that take the descriptor path keep theirs, so a bucket can be\n* inconsistent in that one respect.\n*\n* Key order within a bucket is preserved exactly. It is not cosmetic: `cva` merges\n* variant props in iteration order, and the parser reads the rest bucket as the style\n* props it encodes, so order reaches the emitted CSS.\n*/\nfunction splitProps(props, ...keys) {\n const allKeys = Object.getOwnPropertyNames(props);\n const own = new Set(allKeys);\n const taken = /* @__PURE__ */ new Set();\n const split = (group) => {\n const clone = {};\n for (let i = 0; i < group.length; i++) {\n const key = group[i];\n if (taken.has(key) || !own.has(key)) continue;\n const descriptor = Object.getOwnPropertyDescriptor(props, key);\n if (!descriptor) continue;\n if (\"get\" in descriptor || \"set\" in descriptor || !descriptor.enumerable || key === \"__proto__\") Object.defineProperty(clone, key, descriptor);\n else clone[key] = descriptor.value;\n taken.add(key);\n }\n return clone;\n };\n /**\n * The predicate is called with the key alone.\n *\n * Handing it to `filter` passes `(key, index, allKeys)`. A one-parameter predicate cannot\n * see the extras, but a memoized one reads its whole argument list — and the predicates\n * that arrive here are memoized, `isCssProperty` among them. So the memo hashed the entire\n * key array once per prop, and keyed its cache on it: two elements with different prop sets\n * shared no entry even for the same prop name.\n *\n * Worth ~9.7x on that path, and nothing at all on a plain predicate — which is why the\n * bench below it needs a memoized case to see this at all.\n *\n * A loop rather than `filter((k) => key(k))` because the wrapper allocates a closure per\n * group. The two measure the same to within noise; the loop just does not need one.\n */\n const matching = (predicate) => {\n const group = [];\n for (let i = 0; i < allKeys.length; i++) {\n const key = allKeys[i];\n if (predicate(key)) group.push(key);\n }\n return group;\n };\n return keys.map((key) => split(Array.isArray(key) ? key : matching(key))).concat(split(allKeys));\n}\n//#endregion\n//#region src/uniq.ts\nconst uniq = (...items) => {\n const set = items.reduce((acc, currItems) => {\n if (currItems) currItems.forEach((item) => acc.add(item));\n return acc;\n }, /* @__PURE__ */ new Set([]));\n return Array.from(set);\n};\n//#endregion\n//#region src/view-transition.ts\n/**\n* The slots a `viewTransition()` bag accepts, in the order they are emitted.\n*\n* Anything else in the options object is ignored — including by the hash, so adding a\n* comment key or spreading an unrelated object does not fork the class name.\n*/\nconst viewTransitionSlots = [\n \"group\",\n \"imagePair\",\n \"old\",\n \"new\"\n];\n/**\n* Serialize a value with object keys sorted, so two style objects that differ only in\n* authoring order hash to the same class.\n*\n* Values JSON has no encoding for (`undefined`, functions, symbols) serialize as `null`\n* rather than being dropped. Nothing reaches here holding one — `filterSlots` removes\n* nullish slots, and the extractor drops nullish leaves — so this is only a floor: it\n* keeps a hole in an array from shifting the elements after it.\n*\n* Not exported. The name promises a general-purpose stable serializer, and this is not\n* one; `viewTransitionClassName` is the whole reason it exists.\n*/\nfunction stableStringify(value) {\n if (value === null) return \"null\";\n const type = typeof value;\n if (type === \"boolean\") return value ? \"true\" : \"false\";\n if (type === \"number\") return Number.isFinite(value) ? String(value) : \"null\";\n if (type === \"string\") return JSON.stringify(value);\n if (Array.isArray(value)) {\n let out = \"[\";\n for (let index = 0; index < value.length; index++) {\n if (index) out += \",\";\n out += stableStringify(value[index]);\n }\n return out + \"]\";\n }\n if (type === \"object\") {\n const keys = Object.keys(value).sort();\n let out = \"{\";\n for (let index = 0; index < keys.length; index++) {\n if (index) out += \",\";\n const key = keys[index];\n out += JSON.stringify(key) + \":\" + stableStringify(value[key]);\n }\n return out + \"}\";\n }\n return \"null\";\n}\n/**\n* Keep the four known slots, dropping any that is nullish.\n*\n* Both halves of the contract have to agree on what an empty slot is, and only one of\n* them gets a choice. The extractor evaluates the source, and a nullish property is gone\n* from what it hands over — `{ new: undefined }` and `{}` reach the build identically.\n* So absent, `undefined` and `null` collapse here too, and `new: enabled ? {…} : null`\n* hashes to the bag it actually styles.\n*/\nfunction filterSlots(options) {\n const filtered = {};\n if (!options || typeof options !== \"object\") return filtered;\n for (const slot of viewTransitionSlots) {\n const value = options[slot];\n if (value != null) filtered[slot] = value;\n }\n return filtered;\n}\n/**\n* The class a `viewTransition()` call resolves to.\n*\n* This is the whole contract between the build and the runtime: the extractor hashes the\n* options it found in the source, the generated `viewTransition()` hashes the options it\n* is called with, and the CSS only reaches the element if the two agree. They agree by\n* construction — both call this function — but only over what the extractor can see. A\n* value it cannot resolve statically is absent from its side and present on the runtime's,\n* which is why a bag has to be a static object literal to be styled at all.\n*\n* The class is used twice, as the `view-transition-class` value and as the argument to\n* `::view-transition-*(.cls)`, so the prefix applies to both.\n*/\nfunction viewTransitionClassName(options, prefix = \"\") {\n const base = \"vt_\" + toHash(stableStringify(filterSlots(options)));\n return prefix ? prefix + \"-\" + base : base;\n}\n//#endregion\nexport { cloneStyles, compact, createCss, createMergeCss, filterBaseConditions, getPatternStyles, getRecipeClassNames, getRecipeIdentity, getSlotCompoundVariant, getSlotRecipes, hypenateProperty, isBaseCondition, isObject, leafClass, mapObject, memo, mergeProps, patternFns, splitProps, toHash, uniq, viewTransitionClassName, walkObject, withoutSpace };\n";
|
|
676
472
|
//#endregion
|
|
677
473
|
//#region src/artifacts/js/helpers.ts
|
|
678
|
-
function generateHelpers(
|
|
474
|
+
function generateHelpers() {
|
|
679
475
|
return { js: outdent.outdent`
|
|
680
|
-
${content$
|
|
681
|
-
${ctx.isTemplateLiteralSyntax ? content$11 : ""}
|
|
682
|
-
|
|
683
|
-
${ctx.jsx.framework ? `${content$9}` : ""}
|
|
476
|
+
${content$8}
|
|
684
477
|
|
|
685
478
|
export function __spreadValues(a, b) {
|
|
686
479
|
return { ...a, ...b }
|
|
@@ -692,74 +485,6 @@ function generateHelpers(ctx) {
|
|
|
692
485
|
` };
|
|
693
486
|
}
|
|
694
487
|
//#endregion
|
|
695
|
-
//#region src/artifacts/generated/is-valid-prop.mjs.json
|
|
696
|
-
var content$8 = "//#region src/index.ts\nconst userGenerated = \"\".split(\",\");\nconst allCssProperties = \"WebkitAppearance,WebkitBorderBefore,WebkitBorderBeforeColor,WebkitBorderBeforeStyle,WebkitBorderBeforeWidth,WebkitBoxReflect,WebkitLineClamp,WebkitMask,WebkitMaskAttachment,WebkitMaskClip,WebkitMaskComposite,WebkitMaskImage,WebkitMaskOrigin,WebkitMaskPosition,WebkitMaskPositionX,WebkitMaskPositionY,WebkitMaskRepeat,WebkitMaskRepeatX,WebkitMaskRepeatY,WebkitMaskSize,WebkitOverflowScrolling,WebkitTapHighlightColor,WebkitTextFillColor,WebkitTextStroke,WebkitTextStrokeColor,WebkitTextStrokeWidth,WebkitTouchCallout,WebkitUserModify,WebkitUserSelect,accentColor,alignContent,alignItems,alignSelf,alignTracks,all,anchorName,anchorScope,animation,animationComposition,animationDelay,animationDirection,animationDuration,animationFillMode,animationIterationCount,animationName,animationPlayState,animationRange,animationRangeEnd,animationRangeStart,animationTimeline,animationTimingFunction,appearance,aspectRatio,backdropFilter,backfaceVisibility,background,backgroundAttachment,backgroundBlendMode,backgroundClip,backgroundColor,backgroundImage,backgroundOrigin,backgroundPosition,backgroundPositionX,backgroundPositionY,backgroundRepeat,backgroundSize,blockSize,border,borderBlock,borderBlockColor,borderBlockEnd,borderBlockEndColor,borderBlockEndStyle,borderBlockEndWidth,borderBlockStart,borderBlockStartColor,borderBlockStartStyle,borderBlockStartWidth,borderBlockStyle,borderBlockWidth,borderBottom,borderBottomColor,borderBottomLeftRadius,borderBottomRightRadius,borderBottomStyle,borderBottomWidth,borderCollapse,borderColor,borderEndEndRadius,borderEndStartRadius,borderImage,borderImageOutset,borderImageRepeat,borderImageSlice,borderImageSource,borderImageWidth,borderInline,borderInlineColor,borderInlineEnd,borderInlineEndColor,borderInlineEndStyle,borderInlineEndWidth,borderInlineStart,borderInlineStartColor,borderInlineStartStyle,borderInlineStartWidth,borderInlineStyle,borderInlineWidth,borderLeft,borderLeftColor,borderLeftStyle,borderLeftWidth,borderRadius,borderRight,borderRightColor,borderRightStyle,borderRightWidth,borderSpacing,borderStartEndRadius,borderStartStartRadius,borderStyle,borderTop,borderTopColor,borderTopLeftRadius,borderTopRightRadius,borderTopStyle,borderTopWidth,borderWidth,bottom,boxAlign,boxDecorationBreak,boxDirection,boxFlex,boxFlexGroup,boxLines,boxOrdinalGroup,boxOrient,boxPack,boxShadow,boxSizing,breakAfter,breakBefore,breakInside,captionSide,caret,caretColor,caretShape,clear,clip,clipPath,clipRule,color,colorInterpolationFilters,colorScheme,columnCount,columnFill,columnGap,columnRule,columnRuleColor,columnRuleStyle,columnRuleWidth,columnSpan,columnWidth,columns,contain,containIntrinsicBlockSize,containIntrinsicHeight,containIntrinsicInlineSize,containIntrinsicSize,containIntrinsicWidth,container,containerName,containerType,content,contentVisibility,cornerShape,counterIncrement,counterReset,counterSet,cursor,cx,cy,d,direction,display,dominantBaseline,emptyCells,fieldSizing,fill,fillOpacity,fillRule,filter,flex,flexBasis,flexDirection,flexFlow,flexGrow,flexShrink,flexWrap,float,floodColor,floodOpacity,font,fontFamily,fontFeatureSettings,fontKerning,fontLanguageOverride,fontOpticalSizing,fontPalette,fontSize,fontSizeAdjust,fontSmooth,fontStretch,fontStyle,fontSynthesis,fontSynthesisPosition,fontSynthesisSmallCaps,fontSynthesisStyle,fontSynthesisWeight,fontVariant,fontVariantAlternates,fontVariantCaps,fontVariantEastAsian,fontVariantEmoji,fontVariantLigatures,fontVariantNumeric,fontVariantPosition,fontVariationSettings,fontWeight,forcedColorAdjust,gap,grid,gridArea,gridAutoColumns,gridAutoFlow,gridAutoRows,gridColumn,gridColumnEnd,gridColumnGap,gridColumnStart,gridGap,gridRow,gridRowEnd,gridRowGap,gridRowStart,gridTemplate,gridTemplateAreas,gridTemplateColumns,gridTemplateRows,hangingPunctuation,height,hyphenateCharacter,hyphenateLimitChars,hyphens,imageOrientation,imageRendering,imageResolution,imeMode,initialLetter,initialLetterAlign,inlineSize,inset,insetBlock,insetBlockEnd,insetBlockStart,insetInline,insetInlineEnd,insetInlineStart,interpolateSize,isolation,justifyContent,justifyItems,justifySelf,justifyTracks,left,letterSpacing,lightingColor,lineBreak,lineClamp,lineHeight,lineHeightStep,listStyle,listStyleImage,listStylePosition,listStyleType,margin,marginBlock,marginBlockEnd,marginBlockStart,marginBottom,marginInline,marginInlineEnd,marginInlineStart,marginLeft,marginRight,marginTop,marginTrim,marker,markerEnd,markerMid,markerStart,mask,maskBorder,maskBorderMode,maskBorderOutset,maskBorderRepeat,maskBorderSlice,maskBorderSource,maskBorderWidth,maskClip,maskComposite,maskImage,maskMode,maskOrigin,maskPosition,maskRepeat,maskSize,maskType,masonryAutoFlow,mathDepth,mathShift,mathStyle,maxBlockSize,maxHeight,maxInlineSize,maxLines,maxWidth,minBlockSize,minHeight,minInlineSize,minWidth,mixBlendMode,objectFit,objectPosition,offset,offsetAnchor,offsetDistance,offsetPath,offsetPosition,offsetRotate,opacity,order,orphans,outline,outlineColor,outlineOffset,outlineStyle,outlineWidth,overflow,overflowAnchor,overflowBlock,overflowClipBox,overflowClipMargin,overflowInline,overflowWrap,overflowX,overflowY,overlay,overscrollBehavior,overscrollBehaviorBlock,overscrollBehaviorInline,overscrollBehaviorX,overscrollBehaviorY,padding,paddingBlock,paddingBlockEnd,paddingBlockStart,paddingBottom,paddingInline,paddingInlineEnd,paddingInlineStart,paddingLeft,paddingRight,paddingTop,page,pageBreakAfter,pageBreakBefore,pageBreakInside,paintOrder,perspective,perspectiveOrigin,placeContent,placeItems,placeSelf,pointerEvents,position,positionAnchor,positionArea,positionTry,positionTryFallbacks,positionTryOrder,positionVisibility,printColorAdjust,quotes,r,resize,right,rotate,rowGap,rubyAlign,rubyMerge,rubyPosition,rx,ry,scale,scrollBehavior,scrollMargin,scrollMarginBlock,scrollMarginBlockEnd,scrollMarginBlockStart,scrollMarginBottom,scrollMarginInline,scrollMarginInlineEnd,scrollMarginInlineStart,scrollMarginLeft,scrollMarginRight,scrollMarginTop,scrollPadding,scrollPaddingBlock,scrollPaddingBlockEnd,scrollPaddingBlockStart,scrollPaddingBottom,scrollPaddingInline,scrollPaddingInlineEnd,scrollPaddingInlineStart,scrollPaddingLeft,scrollPaddingRight,scrollPaddingTop,scrollSnapAlign,scrollSnapCoordinate,scrollSnapDestination,scrollSnapPointsX,scrollSnapPointsY,scrollSnapStop,scrollSnapType,scrollSnapTypeX,scrollSnapTypeY,scrollTimeline,scrollTimelineAxis,scrollTimelineName,scrollbarColor,scrollbarGutter,scrollbarWidth,shapeImageThreshold,shapeMargin,shapeOutside,shapeRendering,stopColor,stopOpacity,stroke,strokeDasharray,strokeDashoffset,strokeLinecap,strokeLinejoin,strokeMiterlimit,strokeOpacity,strokeWidth,tabSize,tableLayout,textAlign,textAlignLast,textAnchor,textBox,textBoxEdge,textBoxTrim,textCombineUpright,textDecoration,textDecorationColor,textDecorationLine,textDecorationSkip,textDecorationSkipInk,textDecorationStyle,textDecorationThickness,textEmphasis,textEmphasisColor,textEmphasisPosition,textEmphasisStyle,textIndent,textJustify,textOrientation,textOverflow,textRendering,textShadow,textSizeAdjust,textSpacingTrim,textTransform,textUnderlineOffset,textUnderlinePosition,textWrap,textWrapMode,textWrapStyle,timelineScope,top,touchAction,transform,transformBox,transformOrigin,transformStyle,transition,transitionBehavior,transitionDelay,transitionDuration,transitionProperty,transitionTimingFunction,translate,unicodeBidi,userSelect,vectorEffect,verticalAlign,viewTimeline,viewTimelineAxis,viewTimelineInset,viewTimelineName,viewTransitionName,visibility,whiteSpace,whiteSpaceCollapse,widows,width,willChange,wordBreak,wordSpacing,wordWrap,writingMode,x,y,zIndex,zoom,alignmentBaseline,baselineShift,colorInterpolation,colorRendering,glyphOrientationVertical\".split(\",\").concat(userGenerated);\nconst properties = new Map(allCssProperties.map((prop) => [prop, true]));\nfunction memo(fn) {\n const cache = Object.create(null);\n return (arg) => {\n if (cache[arg] === void 0) cache[arg] = fn(arg);\n return cache[arg];\n };\n}\nconst cssPropertySelectorRegex = /&|@/;\nconst isCssProperty = /* @__PURE__ */ memo((prop) => {\n return properties.has(prop) || prop.startsWith(\"--\") || cssPropertySelectorRegex.test(prop);\n});\n//#endregion\nexport { allCssProperties, isCssProperty };\n";
|
|
697
|
-
//#endregion
|
|
698
|
-
//#region src/artifacts/js/is-valid-prop.ts
|
|
699
|
-
const cssPropListRegex = /const userGenerated = ".*?"\.split\(","\);\s*const allCssProperties = "(.*?)"\.split\(","\)\.concat\(userGenerated\);/;
|
|
700
|
-
const memoFnDeclarationRegex = /function memo(?:.+?)\n((?:var|const|let) cssPropertySelectorRegex)/s;
|
|
701
|
-
function generateIsValidProp(ctx) {
|
|
702
|
-
if (ctx.isTemplateLiteralSyntax) return;
|
|
703
|
-
let content = content$8;
|
|
704
|
-
const propertyList = content.match(cssPropListRegex);
|
|
705
|
-
if (!propertyList) throw new _bamboocss_shared.BambooError("NOT_FOUND", "Could not find the property list in the prebuilt is-valid-prop module. Its bundled shape has changed.");
|
|
706
|
-
const userProperties = (0, ts_pattern.match)(ctx.jsx.styleProps).with("all", () => Array.from(ctx.properties)).with("minimal", () => ["css"]).with("none", () => ["css"]).exhaustive();
|
|
707
|
-
const browserProperties = ctx.jsx.styleProps === "all" ? propertyList[1].split(",") : [];
|
|
708
|
-
content = content.replace(cssPropListRegex, () => `const allCssProperties = "${(0, _bamboocss_shared.uniq)(browserProperties, userProperties).join(",")}".split(",");`);
|
|
709
|
-
content = content.replace(memoFnDeclarationRegex, "$1");
|
|
710
|
-
if (ctx.jsx.styleProps === "minimal" || ctx.jsx.styleProps === "none") content = content.replace("/* @__PURE__ */ memo(", "/* @__PURE__ */ (");
|
|
711
|
-
else content = ctx.file.import("memo", "../helpers") + "\n" + content;
|
|
712
|
-
content = ctx.file.import("splitProps", "../helpers") + "\n" + content;
|
|
713
|
-
content += `export const splitCssProps = (props) => splitProps(props, isCssProperty)`;
|
|
714
|
-
return {
|
|
715
|
-
js: content,
|
|
716
|
-
dts: outdent.outdent`
|
|
717
|
-
import type { DistributiveOmit, HTMLBambooProps, JsxStyleProps, Pretty } from '../types';
|
|
718
|
-
|
|
719
|
-
declare const isCssProperty: (value: string) => boolean;
|
|
720
|
-
|
|
721
|
-
type CssPropKey = keyof JsxStyleProps
|
|
722
|
-
type OmittedCssProps<T> = Pretty<DistributiveOmit<T, CssPropKey>>
|
|
723
|
-
|
|
724
|
-
declare const splitCssProps: <T>(props: T) => [JsxStyleProps, OmittedCssProps<T>]
|
|
725
|
-
|
|
726
|
-
export { isCssProperty, splitCssProps };
|
|
727
|
-
`
|
|
728
|
-
};
|
|
729
|
-
}
|
|
730
|
-
//#endregion
|
|
731
|
-
//#region src/artifacts/js/jsx-helper.ts
|
|
732
|
-
function generatedJsxHelpers(ctx) {
|
|
733
|
-
return { js: (0, ts_pattern.match)(ctx.isTemplateLiteralSyntax).with(true, () => outdent.outdent`
|
|
734
|
-
export const getDisplayName = (Component) => {
|
|
735
|
-
if (typeof Component === 'string') return Component
|
|
736
|
-
return Component?.displayName || Component?.name || 'Component'
|
|
737
|
-
}`).otherwise(() => outdent.outdent`
|
|
738
|
-
${ctx.file.import("isCssProperty", "./is-valid-prop")}
|
|
739
|
-
|
|
740
|
-
export const defaultShouldForwardProp = (prop, variantKeys) => !variantKeys.includes(prop) && !isCssProperty(prop)
|
|
741
|
-
|
|
742
|
-
export const composeShouldForwardProps = (tag, shouldForwardProp) =>
|
|
743
|
-
tag.__shouldForwardProps__ && shouldForwardProp
|
|
744
|
-
? (propName) => tag.__shouldForwardProps__(propName) && shouldForwardProp(propName)
|
|
745
|
-
: shouldForwardProp
|
|
746
|
-
|
|
747
|
-
export const composeCvaFn = (cvaA, cvaB) => {
|
|
748
|
-
if (cvaA && !cvaB) return cvaA
|
|
749
|
-
if (!cvaA && cvaB) return cvaB
|
|
750
|
-
if ((cvaA.__cva__ && cvaB.__cva__) || (cvaA.__recipe__ && cvaB.__recipe__)) return cvaA.merge(cvaB)
|
|
751
|
-
const error = new TypeError('Cannot merge cva with recipe. Please use either cva or recipe.')
|
|
752
|
-
TypeError.captureStackTrace?.(error)
|
|
753
|
-
throw error
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
export const getDisplayName = (Component) => {
|
|
757
|
-
if (typeof Component === 'string') return Component
|
|
758
|
-
return Component?.displayName || Component?.name || 'Component'
|
|
759
|
-
}
|
|
760
|
-
`) };
|
|
761
|
-
}
|
|
762
|
-
//#endregion
|
|
763
488
|
//#region src/artifacts/js/package-json.ts
|
|
764
489
|
/**
|
|
765
490
|
* The generated output is a plain directory, not an installed package, so bundlers
|
|
@@ -883,22 +608,12 @@ function generatePattern(ctx, filters) {
|
|
|
883
608
|
//#region src/shared.ts
|
|
884
609
|
const isBooleanValue = (value) => value === "true" || value === "false";
|
|
885
610
|
const formatFunctionValue = (value) => isBooleanValue(value) ? value : `'${value}'`;
|
|
886
|
-
const formatJsxValue = (value) => isBooleanValue(value) ? `{${value}}` : `"${value}"`;
|
|
887
611
|
const buildFunctionProps = (key, value) => `${key}: ${formatFunctionValue(value)}`;
|
|
888
|
-
const buildJsxProps = (key, value) => `${key}=${formatJsxValue(value)}`;
|
|
889
612
|
const formatProps = (props, options = {}) => {
|
|
890
613
|
const { keyValueSeparator = ": ", propSeparator = ", ", quoteStyle = "single" } = options;
|
|
891
614
|
const quote = quoteStyle === "single" ? "'" : quoteStyle === "double" ? "\"" : "";
|
|
892
615
|
return Object.entries(props).filter(([_, value]) => value != null).map(([key, value]) => `${key}${keyValueSeparator}${quote}${value}${quote}`).join(propSeparator);
|
|
893
616
|
};
|
|
894
|
-
const formatJsxComponent = (component, props) => {
|
|
895
|
-
const formattedProps = formatProps(props, {
|
|
896
|
-
keyValueSeparator: "=",
|
|
897
|
-
propSeparator: " ",
|
|
898
|
-
quoteStyle: "double"
|
|
899
|
-
});
|
|
900
|
-
return `<${component}${formattedProps ? " " + formattedProps : ""} />`;
|
|
901
|
-
};
|
|
902
617
|
const collectCompositionStyles = (values) => {
|
|
903
618
|
const result = [];
|
|
904
619
|
(0, _bamboocss_shared.walkObject)(values, (token, paths) => {
|
|
@@ -912,27 +627,6 @@ const collectCompositionStyles = (values) => {
|
|
|
912
627
|
}, { stop: (v) => (0, _bamboocss_shared.isObject)(v) && "value" in v });
|
|
913
628
|
return result;
|
|
914
629
|
};
|
|
915
|
-
/**
|
|
916
|
-
* Generates a single JSX example based on jsxStyleProps setting
|
|
917
|
-
*/
|
|
918
|
-
const generateJsxExample = (props, jsxStyleProps = "all", component = "Box") => {
|
|
919
|
-
if (jsxStyleProps === "all") return formatJsxComponent(component, props);
|
|
920
|
-
if (jsxStyleProps === "minimal") return `<${component} css={{ ${formatProps(props)} }} />`;
|
|
921
|
-
return null;
|
|
922
|
-
};
|
|
923
|
-
/**
|
|
924
|
-
* Generates function and JSX examples for a style property
|
|
925
|
-
*/
|
|
926
|
-
const generateJsxExamples = (props, jsxStyleProps = "all", component = "Box") => {
|
|
927
|
-
const functionExamples = [`css({ ${formatProps(props)} })`];
|
|
928
|
-
const jsxExamples = [];
|
|
929
|
-
const jsxExample = generateJsxExample(props, jsxStyleProps, component);
|
|
930
|
-
if (jsxExample) jsxExamples.push(jsxExample);
|
|
931
|
-
return {
|
|
932
|
-
functionExamples,
|
|
933
|
-
jsxExamples
|
|
934
|
-
};
|
|
935
|
-
};
|
|
936
630
|
const COMPOSITION_STYLE_CONFIG = {
|
|
937
631
|
"text-styles": {
|
|
938
632
|
prop: "textStyle",
|
|
@@ -947,14 +641,14 @@ const COMPOSITION_STYLE_CONFIG = {
|
|
|
947
641
|
themeKey: "animationStyles"
|
|
948
642
|
}
|
|
949
643
|
};
|
|
950
|
-
function generateCompositionStyleSpec(type, theme
|
|
644
|
+
function generateCompositionStyleSpec(type, theme) {
|
|
951
645
|
const { prop, themeKey } = COMPOSITION_STYLE_CONFIG[type];
|
|
952
646
|
return {
|
|
953
647
|
type,
|
|
954
648
|
data: collectCompositionStyles(theme?.[themeKey] ?? {}).map((style) => ({
|
|
955
649
|
name: style.name,
|
|
956
650
|
description: style.description,
|
|
957
|
-
|
|
651
|
+
functionExamples: [`css({ ${formatProps({ [prop]: style.name })} })`]
|
|
958
652
|
}))
|
|
959
653
|
};
|
|
960
654
|
}
|
|
@@ -973,7 +667,6 @@ function generateCreateRecipe(ctx) {
|
|
|
973
667
|
dts: "",
|
|
974
668
|
js: outdent.outdent`
|
|
975
669
|
${ctx.file.import("finalizeConditions, sortConditions", "../css/conditions")}
|
|
976
|
-
${ctx.file.import("css", "../css/css")}
|
|
977
670
|
${ctx.file.import("assertCompoundVariant, getCompoundVariantCss", "../css/cva")}
|
|
978
671
|
${ctx.file.import("cx", "../css/cx")}
|
|
979
672
|
${ctx.file.import("compact, createCss, splitProps, uniq, withoutSpace", "../helpers")}
|
|
@@ -987,7 +680,7 @@ function generateCreateRecipe(ctx) {
|
|
|
987
680
|
};
|
|
988
681
|
};
|
|
989
682
|
|
|
990
|
-
const recipeFn = (variants
|
|
683
|
+
const recipeFn = (variants) => {
|
|
991
684
|
const transform = (prop, value) => {
|
|
992
685
|
assertCompoundVariant(name, compoundVariants, variants, prop)
|
|
993
686
|
|
|
@@ -1015,11 +708,10 @@ function generateCreateRecipe(ctx) {
|
|
|
1015
708
|
|
|
1016
709
|
const recipeStyles = getVariantProps(variants)
|
|
1017
710
|
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
711
|
+
// No class for the compound variants. Their rule selects on the variant classes
|
|
712
|
+
// \`recipeCss\` just named — \`.btn--size_sm.btn--tone_a\` — so it applies on its own,
|
|
713
|
+
// and it is in the same layer as the rest of the recipe rather than atomically in
|
|
714
|
+
// \`utilities\` above it.
|
|
1023
715
|
return recipeCss(recipeStyles)
|
|
1024
716
|
}
|
|
1025
717
|
|
|
@@ -1071,9 +763,22 @@ function generateRecipes(ctx, filters) {
|
|
|
1071
763
|
else defaultValue = JSON.stringify(defaultValue);
|
|
1072
764
|
return ctx.file.jsDocComment("", { default: defaultValue });
|
|
1073
765
|
};
|
|
766
|
+
const slotNames = _bamboocss_core.Recipes.isSlotRecipeConfig(config) ? config.slots : [];
|
|
767
|
+
const anchorSlotNames = _bamboocss_core.Recipes.isSlotRecipeConfig(config) ? _bamboocss_core.Recipes.getScopeRoots(config) : [];
|
|
1074
768
|
return {
|
|
1075
769
|
name: dashName,
|
|
1076
|
-
js: (0, ts_pattern.match)(config).when(_bamboocss_core.Recipes.isSlotRecipeConfig, (config) =>
|
|
770
|
+
js: (0, ts_pattern.match)(config).when(_bamboocss_core.Recipes.isSlotRecipeConfig, (config) => {
|
|
771
|
+
const anchors = _bamboocss_core.Recipes.getScopeRoots(config);
|
|
772
|
+
/**
|
|
773
|
+
* Which slots each variant writes styles for.
|
|
774
|
+
*
|
|
775
|
+
* A scope reaches every slot inside an anchor's subtree. A slot under no anchor at
|
|
776
|
+
* all is not reached, and nothing here can detect that — reachability is a fact
|
|
777
|
+
* about the DOM. This is what says which slots a variant has to get to, so the
|
|
778
|
+
* component layer can thread the ones a scope cannot.
|
|
779
|
+
*/
|
|
780
|
+
const slotsAffectedBy = Object.fromEntries(Object.entries(config.variants ?? {}).map(([variant, values]) => [variant, Array.from(new Set(Object.values(values ?? {}).flatMap((slotStyles) => Object.keys(slotStyles ?? {}))))]));
|
|
781
|
+
return outdent.outdent`
|
|
1077
782
|
${ctx.file.import("compact, getSlotCompoundVariant, memo, splitProps", "../helpers")}
|
|
1078
783
|
${ctx.file.import("createRecipe", "./create-recipe")}
|
|
1079
784
|
|
|
@@ -1081,11 +786,27 @@ function generateRecipes(ctx, filters) {
|
|
|
1081
786
|
const ${baseName}CompoundVariants = ${stringify$2(compoundVariants ?? [])}
|
|
1082
787
|
|
|
1083
788
|
const ${baseName}SlotNames = ${stringify$2(config.slots.map((slot) => [slot, `${config.className}__${slot}`]))}
|
|
789
|
+
${anchors.length ? outdent.outdent`
|
|
790
|
+
/**
|
|
791
|
+
* Only the anchors take variants: ${anchors.map((slot) => `\`${baseName}.${slot}\``).join(", ")}.
|
|
792
|
+
* Every other slot's variant styles are emitted as rules scoped by a class an anchor
|
|
793
|
+
* carries, so that slot's class is a constant and nothing has to reach it at runtime.
|
|
794
|
+
*/
|
|
795
|
+
const ${baseName}Anchors = ${JSON.stringify(anchors)}
|
|
796
|
+
const ${baseName}AnchorFns = /* @__PURE__ */ ${baseName}Anchors.map((slotName) => [slotName, createRecipe(\`${config.className}__\${slotName}\`, ${baseName}DefaultVariants, getSlotCompoundVariant(${baseName}CompoundVariants, slotName))])
|
|
797
|
+
const ${baseName}StaticSlots = /* @__PURE__ */ Object.fromEntries(
|
|
798
|
+
${baseName}SlotNames.filter(([slotName]) => !${baseName}Anchors.includes(slotName)),
|
|
799
|
+
)
|
|
800
|
+
|
|
801
|
+
const ${baseName}Fn = memo((props = {}) => ({
|
|
802
|
+
...${baseName}StaticSlots,
|
|
803
|
+
...Object.fromEntries(${baseName}AnchorFns.map(([slotName, anchorFn]) => [slotName, anchorFn.recipeFn(props)])),
|
|
804
|
+
}))` : outdent.outdent`
|
|
1084
805
|
const ${baseName}SlotFns = /* @__PURE__ */ ${baseName}SlotNames.map(([slotName, slotKey]) => [slotName, createRecipe(slotKey, ${baseName}DefaultVariants, getSlotCompoundVariant(${baseName}CompoundVariants, slotName))])
|
|
1085
806
|
|
|
1086
807
|
const ${baseName}Fn = memo((props = {}) => {
|
|
1087
808
|
return Object.fromEntries(${baseName}SlotFns.map(([slotName, slotFn]) => [slotName, slotFn.recipeFn(props)]))
|
|
1088
|
-
})
|
|
809
|
+
})`}
|
|
1089
810
|
|
|
1090
811
|
const ${baseName}VariantKeys = ${stringify$2(Object.keys(variantKeyMap))}
|
|
1091
812
|
const getVariantProps = (variants) => ({ ...${baseName}DefaultVariants, ...compact(variants) })
|
|
@@ -1094,15 +815,25 @@ function generateRecipes(ctx, filters) {
|
|
|
1094
815
|
__recipe__: false,
|
|
1095
816
|
__name__: '${baseName}',
|
|
1096
817
|
raw: (props) => props,
|
|
1097
|
-
|
|
818
|
+
/** Each slot's constant class, for targeting a slot in the DOM. */
|
|
819
|
+
classNameMap: /* @__PURE__ */ Object.fromEntries(${baseName}SlotNames),
|
|
820
|
+
/** The slots that enclose other slots, and so anchor their variant rules. */
|
|
821
|
+
scopeRoots: ${JSON.stringify(anchors)},
|
|
1098
822
|
variantKeys: ${baseName}VariantKeys,
|
|
1099
823
|
variantMap: ${stringify$2(variantKeyMap)},
|
|
824
|
+
/** Which slots each variant actually reaches, for a slot a scope cannot get to. */
|
|
825
|
+
slotsAffectedBy: ${stringify$2(slotsAffectedBy)},
|
|
1100
826
|
splitVariantProps(props) {
|
|
1101
827
|
return splitProps(props, ${baseName}VariantKeys)
|
|
1102
828
|
},
|
|
1103
|
-
getVariantProps
|
|
829
|
+
getVariantProps,
|
|
830
|
+
${anchors.length ? outdent.outdent`
|
|
831
|
+
...Object.fromEntries(${baseName}AnchorFns.map(([slotName, anchorFn]) => [slotName, anchorFn.recipeFn])),
|
|
832
|
+
...${baseName}StaticSlots,
|
|
833
|
+
` : ""}
|
|
1104
834
|
})
|
|
1105
|
-
|
|
835
|
+
`;
|
|
836
|
+
}).otherwise((config) => outdent.outdent`
|
|
1106
837
|
${ctx.file.import("memo, splitProps", "../helpers")}
|
|
1107
838
|
${ctx.file.import("createRecipe, mergeRecipes", "./create-recipe")}
|
|
1108
839
|
|
|
@@ -1159,6 +890,13 @@ function generateRecipes(ctx, filters) {
|
|
|
1159
890
|
variantKeys: Array<keyof ${upperName}Variant>
|
|
1160
891
|
splitVariantProps<Props extends ${upperName}VariantProps>(props: Props): [${upperName}VariantProps, Pretty<DistributiveOmit<Props, keyof ${upperName}VariantProps>>]
|
|
1161
892
|
getVariantProps: (props?: ${upperName}VariantProps) => ${upperName}VariantProps
|
|
893
|
+
${_bamboocss_core.Recipes.isSlotRecipeConfig(config) ? outdent.outdent`
|
|
894
|
+
/** Which slots each variant writes styles for. */
|
|
895
|
+
slotsAffectedBy: Record<keyof ${upperName}Variant, ${upperName}Slot[]>` : ""}
|
|
896
|
+
${anchorSlotNames.length ? outdent.outdent`
|
|
897
|
+
/** The slots that take variants — every other one is scoped by a class an anchor carries. */
|
|
898
|
+
${anchorSlotNames.map((slot) => `${slot}: (props?: ${upperName}VariantProps) => string`).join("\n")}
|
|
899
|
+
${slotNames.filter((slot) => !anchorSlotNames.includes(slot)).map((slot) => `${slot}: string`).join("\n")}` : ""}
|
|
1162
900
|
}
|
|
1163
901
|
|
|
1164
902
|
${ctx.file.jsDocComment(description, { deprecated })}
|
|
@@ -1172,2819 +910,283 @@ function generateRecipes(ctx, filters) {
|
|
|
1172
910
|
function generateSvaFn(ctx) {
|
|
1173
911
|
return {
|
|
1174
912
|
js: outdent.outdent`
|
|
1175
|
-
${ctx.file.import("compact, getSlotRecipes, memo, splitProps", "../helpers")}
|
|
913
|
+
${ctx.file.import("compact, getRecipeIdentity, getSlotRecipes, memo, splitProps", "../helpers")}
|
|
1176
914
|
${ctx.file.import("cva", "./cva")}
|
|
1177
915
|
${ctx.file.import("cx", "./cx")}
|
|
1178
916
|
|
|
1179
917
|
export function sva(config) {
|
|
1180
|
-
|
|
918
|
+
// Named before the split, so each slot's class is \`name__slot\`. Left to
|
|
919
|
+
// \`getSlotRecipes\`, a config with no \`className\` gives every slot the bare slot name
|
|
920
|
+
// — \`root\` — which every other anonymous recipe with a \`root\` slot would share. The
|
|
921
|
+
// build injects the identity at the same point, for the same reason.
|
|
922
|
+
const name = getRecipeIdentity(config, 'sva')
|
|
923
|
+
const withName = { ...config, className: config.className ?? name }
|
|
924
|
+
|
|
925
|
+
const slots = Object.entries(getSlotRecipes(withName)).map(([slot, slotCva]) => [slot, cva(slotCva)])
|
|
1181
926
|
const defaultVariants = config.defaultVariants ?? {}
|
|
1182
927
|
|
|
928
|
+
// Populated whether or not the author set a \`className\`. Every slot recipe is given
|
|
929
|
+
// one before the split — the identity when the config declares none — so the guard
|
|
930
|
+
// that used to sit here left an anonymous \`sva\` reporting no slot classes despite
|
|
931
|
+
// emitting them.
|
|
1183
932
|
const classNameMap = slots.reduce((acc, [slot, cvaFn]) => {
|
|
1184
|
-
|
|
933
|
+
acc[slot] = cvaFn.config.className
|
|
1185
934
|
return acc
|
|
1186
935
|
}, {})
|
|
1187
936
|
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
return Object.assign(memo(svaFn), {
|
|
1211
|
-
__cva__: false,
|
|
1212
|
-
raw,
|
|
1213
|
-
config,
|
|
1214
|
-
variantMap,
|
|
1215
|
-
variantKeys,
|
|
1216
|
-
classNameMap,
|
|
1217
|
-
splitVariantProps,
|
|
1218
|
-
getVariantProps,
|
|
1219
|
-
})
|
|
1220
|
-
}
|
|
1221
|
-
`,
|
|
1222
|
-
dts: outdent.outdent`
|
|
1223
|
-
${ctx.file.importType("SlotRecipeCreatorFn", "../types/recipe")}
|
|
1224
|
-
|
|
1225
|
-
export declare const sva: SlotRecipeCreatorFn
|
|
1226
|
-
`
|
|
1227
|
-
};
|
|
1228
|
-
}
|
|
1229
|
-
//#endregion
|
|
1230
|
-
//#region src/artifacts/js/token.ts
|
|
1231
|
-
function generateTokenJs(ctx) {
|
|
1232
|
-
const { tokens } = ctx;
|
|
1233
|
-
const map = /* @__PURE__ */ new Map();
|
|
1234
|
-
tokens.allTokens.forEach((token) => {
|
|
1235
|
-
const { varRef, isVirtual } = token.extensions;
|
|
1236
|
-
const value = isVirtual || token.extensions.condition !== "base" ? varRef : token.value;
|
|
1237
|
-
map.set(token.name, {
|
|
1238
|
-
value,
|
|
1239
|
-
variable: varRef
|
|
1240
|
-
});
|
|
1241
|
-
});
|
|
1242
|
-
const obj = Object.fromEntries(map);
|
|
1243
|
-
return {
|
|
1244
|
-
js: outdent.default`
|
|
1245
|
-
const tokens = ${JSON.stringify(obj, null, 2)}
|
|
1246
|
-
|
|
1247
|
-
export function token(path, fallback) {
|
|
1248
|
-
return tokens[path]?.value || fallback
|
|
1249
|
-
}
|
|
1250
|
-
|
|
1251
|
-
function tokenVar(path, fallback) {
|
|
1252
|
-
return tokens[path]?.variable || fallback
|
|
1253
|
-
}
|
|
1254
|
-
|
|
1255
|
-
token.var = tokenVar
|
|
1256
|
-
`,
|
|
1257
|
-
dts: outdent.default`
|
|
1258
|
-
${ctx.file.importType("Token", "./tokens")}
|
|
1259
|
-
|
|
1260
|
-
export declare const token: {
|
|
1261
|
-
(path: Token, fallback?: string): string
|
|
1262
|
-
var: (path: Token, fallback?: string) => string
|
|
1263
|
-
}
|
|
1264
|
-
|
|
1265
|
-
${ctx.file.exportTypeStar("./tokens")}
|
|
1266
|
-
`
|
|
1267
|
-
};
|
|
1268
|
-
}
|
|
1269
|
-
//#endregion
|
|
1270
|
-
//#region src/artifacts/preact-jsx/jsx.ts
|
|
1271
|
-
function generatePreactJsxFactory(ctx) {
|
|
1272
|
-
const { factoryName, componentName } = ctx.jsx;
|
|
1273
|
-
return { js: outdent.outdent`
|
|
1274
|
-
import { h } from 'preact'
|
|
1275
|
-
import { forwardRef } from 'preact/compat'
|
|
1276
|
-
${ctx.file.import("defaultShouldForwardProp, composeShouldForwardProps, composeCvaFn, getDisplayName", "./factory-helper")}
|
|
1277
|
-
${ctx.file.import("isCssProperty", "./is-valid-prop")}
|
|
1278
|
-
${ctx.file.import("css, cx, cva", "../css/index")}
|
|
1279
|
-
${ctx.file.import("splitProps, normalizeHTMLProps", "../helpers")}
|
|
1280
|
-
|
|
1281
|
-
function styledFn(Dynamic, configOrCva = {}, options = {}) {
|
|
1282
|
-
const cvaFn = configOrCva.__cva__ || configOrCva.__recipe__ ? configOrCva : cva(configOrCva)
|
|
1283
|
-
|
|
1284
|
-
const forwardFn = options.shouldForwardProp || defaultShouldForwardProp
|
|
1285
|
-
const shouldForwardProp = (prop) => {
|
|
1286
|
-
if (options.forwardProps?.includes(prop)) return true
|
|
1287
|
-
return forwardFn(prop, cvaFn.variantKeys)
|
|
1288
|
-
}
|
|
1289
|
-
|
|
1290
|
-
const defaultProps = Object.assign(
|
|
1291
|
-
options.dataAttr && configOrCva.__name__ ? { 'data-recipe': configOrCva.__name__ } : {},
|
|
1292
|
-
options.defaultProps,
|
|
1293
|
-
)
|
|
1294
|
-
|
|
1295
|
-
const __cvaFn__ = composeCvaFn(Dynamic.__cva__, cvaFn)
|
|
1296
|
-
const __shouldForwardProps__ = composeShouldForwardProps(Dynamic, shouldForwardProp)
|
|
1297
|
-
const __base__ = Dynamic.__base__ || Dynamic
|
|
1298
|
-
|
|
1299
|
-
const ${componentName} = /* @__PURE__ */ forwardRef(function ${componentName}(props, ref) {
|
|
1300
|
-
const { as: Element = __base__, unstyled, children, ...restProps } = props
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
// Not memoized, deliberately. \`restProps\` is rest destructuring, so it is a fresh
|
|
1304
|
-
// object on every render and a dependency on it can never match — a memo here is a
|
|
1305
|
-
// guaranteed miss that still costs a hook slot, a deps array and a retained cell.
|
|
1306
|
-
const combinedProps = Object.assign({}, defaultProps, restProps)
|
|
1307
|
-
|
|
1308
|
-
const [htmlProps, forwardedProps, variantProps, styleProps, elementProps] =
|
|
1309
|
-
splitProps(combinedProps, normalizeHTMLProps.keys, __shouldForwardProps__, __cvaFn__.variantKeys, isCssProperty)
|
|
1310
|
-
|
|
1311
|
-
function recipeClass() {
|
|
1312
|
-
const { css: cssStyles, ...propStyles } = styleProps
|
|
1313
|
-
const compoundVariantStyles = __cvaFn__.__getCompoundVariantCss__?.(variantProps)
|
|
1314
|
-
return cx(__cvaFn__(variantProps, false), css(compoundVariantStyles, propStyles, cssStyles), combinedProps.class, combinedProps.className)
|
|
1315
|
-
}
|
|
1316
|
-
|
|
1317
|
-
function cvaClass() {
|
|
1318
|
-
const { css: cssStyles, ...propStyles } = styleProps
|
|
1319
|
-
const cvaStyles = __cvaFn__.raw(variantProps)
|
|
1320
|
-
return cx(css(cvaStyles, propStyles, cssStyles), combinedProps.class, combinedProps.className)
|
|
1321
|
-
}
|
|
1322
|
-
|
|
1323
|
-
const classes = () => {
|
|
1324
|
-
if (unstyled) {
|
|
1325
|
-
const { css: cssStyles, ...propStyles } = styleProps
|
|
1326
|
-
return cx(css(propStyles, cssStyles), combinedProps.class, combinedProps.className)
|
|
1327
|
-
}
|
|
1328
|
-
return configOrCva.__recipe__ ? recipeClass() : cvaClass()
|
|
1329
|
-
}
|
|
1330
|
-
|
|
1331
|
-
return h(Element, {
|
|
1332
|
-
...forwardedProps,
|
|
1333
|
-
...elementProps,
|
|
1334
|
-
...normalizeHTMLProps(htmlProps),
|
|
1335
|
-
ref,
|
|
1336
|
-
className: classes()
|
|
1337
|
-
}, children ?? combinedProps.children)
|
|
1338
|
-
})
|
|
1339
|
-
|
|
1340
|
-
const name = getDisplayName(__base__)
|
|
1341
|
-
|
|
1342
|
-
${componentName}.displayName = \`${factoryName}.\${name}\`
|
|
1343
|
-
${componentName}.__cva__ = __cvaFn__
|
|
1344
|
-
${componentName}.__base__ = __base__
|
|
1345
|
-
${componentName}.__shouldForwardProps__ = shouldForwardProp
|
|
1346
|
-
|
|
1347
|
-
return ${componentName}
|
|
1348
|
-
}
|
|
1349
|
-
|
|
1350
|
-
function createJsxFactory() {
|
|
1351
|
-
const cache = new Map()
|
|
1352
|
-
|
|
1353
|
-
return new Proxy(styledFn, {
|
|
1354
|
-
apply(_, __, args) {
|
|
1355
|
-
return styledFn(...args)
|
|
1356
|
-
},
|
|
1357
|
-
get(_, el) {
|
|
1358
|
-
if (!cache.has(el)) {
|
|
1359
|
-
cache.set(el, styledFn(el))
|
|
1360
|
-
}
|
|
1361
|
-
return cache.get(el)
|
|
1362
|
-
},
|
|
1363
|
-
})
|
|
1364
|
-
}
|
|
1365
|
-
|
|
1366
|
-
export const ${factoryName} = /* @__PURE__ */ createJsxFactory()
|
|
1367
|
-
` };
|
|
1368
|
-
}
|
|
1369
|
-
//#endregion
|
|
1370
|
-
//#region src/artifacts/preact-jsx/pattern.ts
|
|
1371
|
-
function generatePreactJsxPattern(ctx, filters) {
|
|
1372
|
-
const { typeName, factoryName, styleProps: jsxStyleProps } = ctx.jsx;
|
|
1373
|
-
return ctx.patterns.filterDetails(filters).map((pattern) => {
|
|
1374
|
-
const { upperName, styleFnName, dashName, jsxName, props, blocklistType } = pattern;
|
|
1375
|
-
const { description, jsxElement = "div", deprecated } = pattern.config;
|
|
1376
|
-
return {
|
|
1377
|
-
name: dashName,
|
|
1378
|
-
js: outdent.outdent`
|
|
1379
|
-
import { h } from 'preact'
|
|
1380
|
-
import { forwardRef } from 'preact/compat'
|
|
1381
|
-
${jsxStyleProps === "minimal" ? ctx.file.import("mergeCss", "../css/css") : ""}
|
|
1382
|
-
${ctx.file.import("splitProps", "../helpers")}
|
|
1383
|
-
${ctx.file.import(styleFnName, `../patterns/${dashName}`)}
|
|
1384
|
-
${ctx.file.import(factoryName, "./factory")}
|
|
1385
|
-
|
|
1386
|
-
export const ${jsxName} = /* @__PURE__ */ forwardRef(function ${jsxName}(props, ref) {
|
|
1387
|
-
${(0, ts_pattern.match)(jsxStyleProps).with("none", () => outdent.outdent`
|
|
1388
|
-
const [patternProps, restProps] = splitProps(props, ${JSON.stringify(props)})
|
|
1389
|
-
|
|
1390
|
-
const styleProps = ${styleFnName}(patternProps)
|
|
1391
|
-
const mergedProps = { ref, ...restProps, css: styleProps }
|
|
1392
|
-
|
|
1393
|
-
return h(${factoryName}.${jsxElement}, mergedProps)
|
|
1394
|
-
`).with("minimal", () => outdent.outdent`
|
|
1395
|
-
const [patternProps, restProps] = splitProps(props, ${JSON.stringify(props)})
|
|
1396
|
-
|
|
1397
|
-
const styleProps = ${styleFnName}(patternProps)
|
|
1398
|
-
const cssProps = { css: mergeCss(styleProps, props.css) }
|
|
1399
|
-
const mergedProps = { ref, ...restProps, ...cssProps }
|
|
1400
|
-
|
|
1401
|
-
return h(${factoryName}.${jsxElement}, mergedProps)
|
|
1402
|
-
`).with("all", () => outdent.outdent`
|
|
1403
|
-
const [patternProps, restProps] = splitProps(props, ${JSON.stringify(props)})
|
|
1404
|
-
|
|
1405
|
-
const styleProps = ${styleFnName}(patternProps)
|
|
1406
|
-
const mergedProps = { ref, ...styleProps, ...restProps }
|
|
1407
|
-
|
|
1408
|
-
return h(${factoryName}.${jsxElement}, mergedProps)
|
|
1409
|
-
`).exhaustive()}
|
|
1410
|
-
})
|
|
1411
|
-
`,
|
|
1412
|
-
dts: outdent.outdent`
|
|
1413
|
-
import type { FunctionComponent } from 'preact'
|
|
1414
|
-
${ctx.file.importType(`${upperName}Properties`, `../patterns/${dashName}`)}
|
|
1415
|
-
${ctx.file.importType("DistributiveOmit", "../types/system-types")}
|
|
1416
|
-
${ctx.file.importType(typeName, "../types/jsx")}
|
|
1417
|
-
|
|
1418
|
-
export interface ${upperName}Props extends ${upperName}Properties, DistributiveOmit<${typeName}<'${jsxElement}'>, keyof ${upperName}Properties ${blocklistType}> {}
|
|
1419
|
-
|
|
1420
|
-
${ctx.file.jsDocComment(description, { deprecated })}
|
|
1421
|
-
export declare const ${jsxName}: FunctionComponent<${upperName}Props>
|
|
1422
|
-
`
|
|
1423
|
-
};
|
|
1424
|
-
});
|
|
1425
|
-
}
|
|
1426
|
-
//#endregion
|
|
1427
|
-
//#region src/artifacts/preact-jsx/types.ts
|
|
1428
|
-
function generatePreactJsxTypes(ctx) {
|
|
1429
|
-
const { factoryName, componentName, upperName, typeName, variantName } = ctx.jsx;
|
|
1430
|
-
return {
|
|
1431
|
-
jsxFactory: outdent.outdent`
|
|
1432
|
-
import type { ${upperName} } from '../types/jsx'
|
|
1433
|
-
export declare const ${factoryName}: ${upperName}
|
|
1434
|
-
`,
|
|
1435
|
-
jsxType: outdent.outdent`
|
|
1436
|
-
import type { ComponentProps, JSX } from 'preact'
|
|
1437
|
-
${ctx.file.importType("RecipeDefinition, RecipeSelection, RecipeVariantRecord", "./recipe")}
|
|
1438
|
-
${ctx.file.importType("Assign, DistributiveOmit, DistributiveUnion, JsxHTMLProps, JsxStyleProps, Pretty", "./system-types")}
|
|
1439
|
-
|
|
1440
|
-
export type ElementType = JSX.ElementType
|
|
1441
|
-
|
|
1442
|
-
interface Dict {
|
|
1443
|
-
[k: string]: unknown
|
|
1444
|
-
}
|
|
1445
|
-
|
|
1446
|
-
export type DataAttrs = Record<\`data-\${string}\`, unknown>
|
|
1447
|
-
|
|
1448
|
-
export interface UnstyledProps {
|
|
1449
|
-
/**
|
|
1450
|
-
* Whether to remove recipe styles
|
|
1451
|
-
*/
|
|
1452
|
-
unstyled?: boolean | undefined
|
|
1453
|
-
}
|
|
1454
|
-
|
|
1455
|
-
export interface AsProps {
|
|
1456
|
-
/**
|
|
1457
|
-
* The element to render as
|
|
1458
|
-
*/
|
|
1459
|
-
as?: ElementType | undefined
|
|
1460
|
-
}
|
|
1461
|
-
|
|
1462
|
-
export interface ${componentName}<T extends ElementType, P extends Dict = {}> {
|
|
1463
|
-
(props: JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps, Assign<JsxStyleProps, P>>): JSX.Element
|
|
1464
|
-
displayName?: string | undefined
|
|
1465
|
-
}
|
|
1466
|
-
|
|
1467
|
-
interface RecipeFn {
|
|
1468
|
-
__type: any
|
|
1469
|
-
}
|
|
1470
|
-
|
|
1471
|
-
export interface JsxFactoryOptions<TProps extends Dict> {
|
|
1472
|
-
dataAttr?: boolean
|
|
1473
|
-
defaultProps?: Partial<TProps> & DataAttrs
|
|
1474
|
-
shouldForwardProp?: (prop: string, variantKeys: string[]) => boolean
|
|
1475
|
-
forwardProps?: string[]
|
|
1476
|
-
}
|
|
1477
|
-
|
|
1478
|
-
export type JsxRecipeProps<T extends ElementType, P extends Dict> = JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps, P>
|
|
1479
|
-
|
|
1480
|
-
export type JsxElement<T extends ElementType, P extends Dict> = T extends ${componentName}<infer A, infer B>
|
|
1481
|
-
? ${componentName}<A, Pretty<DistributiveUnion<P, B>>>
|
|
1482
|
-
: ${componentName}<T, P>
|
|
1483
|
-
|
|
1484
|
-
export interface JsxFactory {
|
|
1485
|
-
<T extends ElementType>(component: T): ${componentName}<T, {}>
|
|
1486
|
-
<T extends ElementType, P extends RecipeVariantRecord>(component: T, recipe: RecipeDefinition<P>, options?: JsxFactoryOptions<JsxRecipeProps<T, RecipeSelection<P>>>): JsxElement<
|
|
1487
|
-
T,
|
|
1488
|
-
RecipeSelection<P>
|
|
1489
|
-
>
|
|
1490
|
-
<T extends ElementType, P extends RecipeFn>(component: T, recipeFn: P, options?: JsxFactoryOptions<JsxRecipeProps<T, P['__type']>>): JsxElement<T, P['__type']>
|
|
1491
|
-
}
|
|
1492
|
-
|
|
1493
|
-
export type JsxElements = {
|
|
1494
|
-
[K in keyof JSX.IntrinsicElements]: ${componentName}<K, {}>
|
|
1495
|
-
}
|
|
1496
|
-
|
|
1497
|
-
export type ${upperName} = JsxFactory & JsxElements
|
|
1498
|
-
|
|
1499
|
-
export type ${typeName}<T extends ElementType> = JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps, JsxStyleProps>
|
|
1500
|
-
|
|
1501
|
-
export type ${variantName}<T extends ${componentName}<any, any>> = T extends ${componentName}<any, infer Props> ? Props : never
|
|
1502
|
-
`
|
|
1503
|
-
};
|
|
1504
|
-
}
|
|
1505
|
-
//#endregion
|
|
1506
|
-
//#region src/artifacts/preact-jsx/create-style-context.ts
|
|
1507
|
-
function generatePreactCreateStyleContext(ctx) {
|
|
1508
|
-
const { factoryName } = ctx.jsx;
|
|
1509
|
-
return {
|
|
1510
|
-
js: outdent.outdent`
|
|
1511
|
-
${ctx.file.import("cx, css, sva", "../css/index")}
|
|
1512
|
-
${ctx.file.import(factoryName, "./factory")}
|
|
1513
|
-
${ctx.file.import("getDisplayName", "./factory-helper")}
|
|
1514
|
-
import { createContext } from 'preact'
|
|
1515
|
-
import { useContext } from 'preact/hooks'
|
|
1516
|
-
import { createElement, forwardRef } from 'preact/compat'
|
|
1517
|
-
|
|
1518
|
-
function createSafeContext(contextName) {
|
|
1519
|
-
const Context = createContext(undefined)
|
|
1520
|
-
const useStyleContext = (componentName, slot) => {
|
|
1521
|
-
const context = useContext(Context)
|
|
1522
|
-
if (context === undefined) {
|
|
1523
|
-
const componentInfo = componentName ? \`Component "\${componentName}"\` : 'A component'
|
|
1524
|
-
const slotInfo = slot ? \` (slot: "\${slot}")\` : ''
|
|
1525
|
-
|
|
1526
|
-
throw new Error(
|
|
1527
|
-
\`\${componentInfo}\${slotInfo} cannot access \${contextName} because it's missing its Provider.\`
|
|
1528
|
-
)
|
|
1529
|
-
}
|
|
1530
|
-
return context
|
|
1531
|
-
}
|
|
1532
|
-
return [Context, useStyleContext]
|
|
1533
|
-
}
|
|
1534
|
-
|
|
1535
|
-
export function createStyleContext(recipe) {
|
|
1536
|
-
const isConfigRecipe = '__recipe__' in recipe
|
|
1537
|
-
const recipeName = isConfigRecipe && recipe.__name__ ? recipe.__name__ : undefined
|
|
1538
|
-
const contextName = recipeName ? \`createStyleContext("\${recipeName}")\` : 'createStyleContext'
|
|
1539
|
-
|
|
1540
|
-
const [StyleContext, useStyleContext] = createSafeContext(contextName)
|
|
1541
|
-
const svaFn = isConfigRecipe ? recipe : sva(recipe.config)
|
|
1542
|
-
|
|
1543
|
-
const getResolvedProps = (props, slotStyles) => {
|
|
1544
|
-
const { unstyled, ...restProps } = props
|
|
1545
|
-
if (unstyled) return restProps
|
|
1546
|
-
if (isConfigRecipe) {
|
|
1547
|
-
return { ...restProps, className: cx(slotStyles, restProps.className) }
|
|
1548
|
-
}
|
|
1549
|
-
${outdent.outdent.string((0, ts_pattern.match)(ctx.config.jsxStyleProps).with("all", () => `return { ...slotStyles, ...restProps }`).with("minimal", () => `return { ...restProps, css: css.raw(slotStyles, restProps.css) }`).with("none", () => `return { ...restProps, className: cx(css(slotStyles), restProps.className) }`).otherwise(() => `return restProps`))}
|
|
1550
|
-
}
|
|
1551
|
-
|
|
1552
|
-
const withRootProvider = (Component, options) => {
|
|
1553
|
-
const WithRootProvider = (props) => {
|
|
1554
|
-
const [variantProps, otherProps] = svaFn.splitVariantProps(props)
|
|
1555
|
-
|
|
1556
|
-
const slotStyles = isConfigRecipe ? svaFn(variantProps) : svaFn.raw(variantProps)
|
|
1557
|
-
slotStyles._classNameMap = svaFn.classNameMap
|
|
1558
|
-
|
|
1559
|
-
const mergedProps = options?.defaultProps
|
|
1560
|
-
? { ...options.defaultProps, ...otherProps }
|
|
1561
|
-
: otherProps
|
|
1562
|
-
|
|
1563
|
-
return createElement(StyleContext.Provider, {
|
|
1564
|
-
value: slotStyles,
|
|
1565
|
-
children: createElement(Component, mergedProps)
|
|
1566
|
-
})
|
|
1567
|
-
}
|
|
1568
|
-
|
|
1569
|
-
const componentName = getDisplayName(Component)
|
|
1570
|
-
WithRootProvider.displayName = \`withRootProvider(\${componentName})\`
|
|
1571
|
-
|
|
1572
|
-
return WithRootProvider
|
|
1573
|
-
}
|
|
1574
|
-
|
|
1575
|
-
const withProvider = (Component, slot, options) => {
|
|
1576
|
-
const StyledComponent = ${factoryName}(Component, {}, options)
|
|
1577
|
-
|
|
1578
|
-
const WithProvider = forwardRef(function WithProvider(props, ref) {
|
|
1579
|
-
const [variantProps, restProps] = svaFn.splitVariantProps(props)
|
|
1580
|
-
|
|
1581
|
-
const slotStyles = isConfigRecipe ? svaFn(variantProps) : svaFn.raw(variantProps)
|
|
1582
|
-
slotStyles._classNameMap = svaFn.classNameMap
|
|
1583
|
-
|
|
1584
|
-
const propsWithClass = { ...restProps, className: restProps.className ?? options?.defaultProps?.className }
|
|
1585
|
-
const resolvedProps = getResolvedProps(propsWithClass, slotStyles[slot])
|
|
1586
|
-
return createElement(StyleContext.Provider, {
|
|
1587
|
-
value: slotStyles,
|
|
1588
|
-
children: createElement(StyledComponent, {
|
|
1589
|
-
...resolvedProps,
|
|
1590
|
-
className: cx(resolvedProps.className, slotStyles._classNameMap[slot]),
|
|
1591
|
-
ref,
|
|
1592
|
-
})
|
|
1593
|
-
})
|
|
1594
|
-
})
|
|
1595
|
-
|
|
1596
|
-
const componentName = getDisplayName(Component)
|
|
1597
|
-
WithProvider.displayName = \`withProvider(\${componentName})\`
|
|
1598
|
-
|
|
1599
|
-
return WithProvider
|
|
1600
|
-
}
|
|
1601
|
-
|
|
1602
|
-
const withContext = (Component, slot, options) => {
|
|
1603
|
-
const StyledComponent = ${factoryName}(Component, {}, options)
|
|
1604
|
-
const componentName = getDisplayName(Component)
|
|
1605
|
-
|
|
1606
|
-
const WithContext = forwardRef(function WithContext(props, ref) {
|
|
1607
|
-
const slotStyles = useStyleContext(componentName, slot)
|
|
1608
|
-
|
|
1609
|
-
const propsWithClass = { ...props, className: props.className ?? options?.defaultProps?.className }
|
|
1610
|
-
const resolvedProps = getResolvedProps(propsWithClass, slotStyles[slot])
|
|
1611
|
-
return createElement(StyledComponent, {
|
|
1612
|
-
...resolvedProps,
|
|
1613
|
-
className: cx(resolvedProps.className, slotStyles._classNameMap[slot]),
|
|
1614
|
-
ref,
|
|
1615
|
-
})
|
|
1616
|
-
})
|
|
1617
|
-
|
|
1618
|
-
WithContext.displayName = \`withContext(\${componentName})\`
|
|
1619
|
-
|
|
1620
|
-
return WithContext
|
|
1621
|
-
}
|
|
1622
|
-
|
|
1623
|
-
return {
|
|
1624
|
-
withRootProvider,
|
|
1625
|
-
withProvider,
|
|
1626
|
-
withContext,
|
|
1627
|
-
}
|
|
1628
|
-
}
|
|
1629
|
-
`,
|
|
1630
|
-
dts: outdent.outdent`
|
|
1631
|
-
${ctx.file.importType("SlotRecipeRuntimeFn, RecipeVariantProps", "../types/recipe")}
|
|
1632
|
-
${ctx.file.importType("JsxHTMLProps, JsxStyleProps, Assign", "../types/system-types")}
|
|
1633
|
-
${ctx.file.importType("JsxFactoryOptions, DataAttrs, AsProps", "../types/jsx")}
|
|
1634
|
-
import type { ComponentType, ComponentProps, JSX } from 'preact/compat'
|
|
1635
|
-
|
|
1636
|
-
interface UnstyledProps {
|
|
1637
|
-
unstyled?: boolean | undefined
|
|
1638
|
-
}
|
|
1639
|
-
|
|
1640
|
-
interface WithProviderOptions<P = {}> {
|
|
1641
|
-
defaultProps?: (Partial<P> & DataAttrs) | undefined
|
|
1642
|
-
}
|
|
1643
|
-
|
|
1644
|
-
type ElementType = JSX.ElementType
|
|
1645
|
-
|
|
1646
|
-
type SvaFn<S extends string = any> = SlotRecipeRuntimeFn<S, any>
|
|
1647
|
-
interface SlotRecipeFn {
|
|
1648
|
-
__type: any
|
|
1649
|
-
__slot: string
|
|
1650
|
-
(props?: any): any
|
|
1651
|
-
}
|
|
1652
|
-
type SlotRecipe = SvaFn | SlotRecipeFn
|
|
1653
|
-
|
|
1654
|
-
type InferSlot<R extends SlotRecipe> = R extends SlotRecipeFn ? R['__slot'] : R extends SvaFn<infer S> ? S : never
|
|
1655
|
-
|
|
1656
|
-
type StyleContextProvider<T extends ElementType, R extends SlotRecipe> = ComponentType<
|
|
1657
|
-
JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps, Assign<RecipeVariantProps<R>, JsxStyleProps>>
|
|
1658
|
-
>
|
|
1659
|
-
|
|
1660
|
-
type StyleContextRootProvider<T extends ElementType, R extends SlotRecipe> = ComponentType<
|
|
1661
|
-
ComponentProps<T> & UnstyledProps & RecipeVariantProps<R>
|
|
1662
|
-
>
|
|
1663
|
-
|
|
1664
|
-
type StyleContextConsumer<T extends ElementType> = ComponentType<
|
|
1665
|
-
JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps, JsxStyleProps>
|
|
1666
|
-
>
|
|
1667
|
-
|
|
1668
|
-
export interface StyleContext<R extends SlotRecipe> {
|
|
1669
|
-
withRootProvider: <T extends ElementType>(
|
|
1670
|
-
Component: T,
|
|
1671
|
-
options?: WithProviderOptions<ComponentProps<T>> | undefined
|
|
1672
|
-
) => StyleContextRootProvider<T, R>
|
|
1673
|
-
withProvider: <T extends ElementType>(
|
|
1674
|
-
Component: T,
|
|
1675
|
-
slot: InferSlot<R>,
|
|
1676
|
-
options?: JsxFactoryOptions<ComponentProps<T>> | undefined
|
|
1677
|
-
) => StyleContextProvider<T, R>
|
|
1678
|
-
withContext: <T extends ElementType>(
|
|
1679
|
-
Component: T,
|
|
1680
|
-
slot: InferSlot<R>,
|
|
1681
|
-
options?: JsxFactoryOptions<ComponentProps<T>> | undefined
|
|
1682
|
-
) => StyleContextConsumer<T>
|
|
1683
|
-
}
|
|
1684
|
-
|
|
1685
|
-
export declare function createStyleContext<R extends SlotRecipe>(recipe: R): StyleContext<R>
|
|
1686
|
-
`
|
|
1687
|
-
};
|
|
1688
|
-
}
|
|
1689
|
-
//#endregion
|
|
1690
|
-
//#region src/artifacts/preact-jsx/jsx.string-literal.ts
|
|
1691
|
-
function generatePreactJsxStringLiteralFactory(ctx) {
|
|
1692
|
-
const { factoryName, componentName } = ctx.jsx;
|
|
1693
|
-
return { js: outdent.outdent`
|
|
1694
|
-
import { h } from 'preact'
|
|
1695
|
-
import { forwardRef } from 'preact/compat'
|
|
1696
|
-
${ctx.file.import("getDisplayName", "./factory-helper")}
|
|
1697
|
-
${ctx.file.import("css, cx", "../css/index")}
|
|
1698
|
-
|
|
1699
|
-
function createStyledFn(Dynamic) {
|
|
1700
|
-
const __base__ = Dynamic.__base__ || Dynamic
|
|
1701
|
-
return function styledFn(template) {
|
|
1702
|
-
const styles = css.raw(Dynamic.__styles__, template)
|
|
1703
|
-
|
|
1704
|
-
const ${componentName} = /* @__PURE__ */ forwardRef(function ${componentName}(props, ref) {
|
|
1705
|
-
const { as: Element = __base__, ...elementProps } = props
|
|
1706
|
-
|
|
1707
|
-
function classes() {
|
|
1708
|
-
return cx(css(styles), elementProps.className)
|
|
1709
|
-
}
|
|
1710
|
-
|
|
1711
|
-
return h(Element, {
|
|
1712
|
-
ref,
|
|
1713
|
-
...elementProps,
|
|
1714
|
-
className: classes(),
|
|
1715
|
-
})
|
|
1716
|
-
})
|
|
1717
|
-
|
|
1718
|
-
const name = getDisplayName(__base__)
|
|
1719
|
-
|
|
1720
|
-
${componentName}.displayName = \`${factoryName}.\${name}\`
|
|
1721
|
-
${componentName}.__styles__ = styles
|
|
1722
|
-
${componentName}.__base__ = __base__
|
|
1723
|
-
|
|
1724
|
-
return ${componentName}
|
|
1725
|
-
}
|
|
1726
|
-
}
|
|
1727
|
-
|
|
1728
|
-
function createJsxFactory() {
|
|
1729
|
-
const cache = new Map()
|
|
1730
|
-
|
|
1731
|
-
return new Proxy(createStyledFn, {
|
|
1732
|
-
apply(_, __, args) {
|
|
1733
|
-
return createStyledFn(...args)
|
|
1734
|
-
},
|
|
1735
|
-
get(_, el) {
|
|
1736
|
-
if (!cache.has(el)) {
|
|
1737
|
-
cache.set(el, createStyledFn(el))
|
|
1738
|
-
}
|
|
1739
|
-
return cache.get(el)
|
|
1740
|
-
},
|
|
1741
|
-
})
|
|
1742
|
-
}
|
|
1743
|
-
|
|
1744
|
-
export const ${factoryName} = /* @__PURE__ */ createJsxFactory()
|
|
1745
|
-
` };
|
|
1746
|
-
}
|
|
1747
|
-
//#endregion
|
|
1748
|
-
//#region src/artifacts/preact-jsx/types.string-literal.ts
|
|
1749
|
-
function generatePreactJsxStringLiteralTypes(ctx) {
|
|
1750
|
-
const { factoryName, componentName, upperName, typeName } = ctx.jsx;
|
|
1751
|
-
return {
|
|
1752
|
-
jsxFactory: outdent.outdent`
|
|
1753
|
-
${ctx.file.importType(upperName, "../types/jsx")}
|
|
1754
|
-
export declare const ${factoryName}: ${upperName}
|
|
1755
|
-
`,
|
|
1756
|
-
jsxType: outdent.outdent`
|
|
1757
|
-
import type { ComponentProps, JSX } from 'preact'
|
|
1758
|
-
|
|
1759
|
-
export type ElementType = JSX.ElementType
|
|
1760
|
-
|
|
1761
|
-
interface Dict {
|
|
1762
|
-
[k: string]: unknown
|
|
1763
|
-
}
|
|
1764
|
-
|
|
1765
|
-
export interface AsProps {
|
|
1766
|
-
/**
|
|
1767
|
-
* The element to render as
|
|
1768
|
-
*/
|
|
1769
|
-
as?: ElementType | undefined
|
|
1770
|
-
}
|
|
1771
|
-
|
|
1772
|
-
export type ${componentName}<T extends ElementType> = {
|
|
1773
|
-
(args: { raw: readonly string[] | ArrayLike<string> }): (props: ComponentProps<T> & AsProps) => JSX.Element
|
|
1774
|
-
displayName?: string | undefined
|
|
1775
|
-
}
|
|
1776
|
-
|
|
1777
|
-
export interface JsxFactory {
|
|
1778
|
-
<T extends ElementType>(component: T): ${componentName}<T>
|
|
1779
|
-
}
|
|
1780
|
-
|
|
1781
|
-
export type JsxElements = {
|
|
1782
|
-
[K in keyof JSX.IntrinsicElements]: ${componentName}<K>
|
|
1783
|
-
}
|
|
1784
|
-
|
|
1785
|
-
export type ${upperName} = JsxFactory & JsxElements
|
|
1786
|
-
|
|
1787
|
-
export type ${typeName}<T extends ElementType> = ComponentProps<T>
|
|
1788
|
-
`
|
|
1789
|
-
};
|
|
1790
|
-
}
|
|
1791
|
-
//#endregion
|
|
1792
|
-
//#region src/artifacts/qwik-jsx/jsx.ts
|
|
1793
|
-
function generateQwikJsxFactory(ctx) {
|
|
1794
|
-
const { factoryName, componentName } = ctx.jsx;
|
|
1795
|
-
return { js: outdent.outdent`
|
|
1796
|
-
import { h } from '@builder.io/qwik'
|
|
1797
|
-
${ctx.file.import("defaultShouldForwardProp, composeShouldForwardProps, composeCvaFn, getDisplayName", "./factory-helper")}
|
|
1798
|
-
${ctx.file.import("isCssProperty", "./is-valid-prop")}
|
|
1799
|
-
${ctx.file.import("css, cx, cva", "../css/index")}
|
|
1800
|
-
${ctx.file.import("splitProps, normalizeHTMLProps", "../helpers")}
|
|
1801
|
-
|
|
1802
|
-
function styledFn(Dynamic, configOrCva = {}, options = {}) {
|
|
1803
|
-
const cvaFn = configOrCva.__cva__ || configOrCva.__recipe__ ? configOrCva : cva(configOrCva)
|
|
1804
|
-
|
|
1805
|
-
const forwardFn = options.shouldForwardProp || defaultShouldForwardProp
|
|
1806
|
-
const shouldForwardProp = (prop) => {
|
|
1807
|
-
if (options.forwardProps?.includes(prop)) return true
|
|
1808
|
-
return forwardFn(prop, cvaFn.variantKeys)
|
|
1809
|
-
}
|
|
1810
|
-
|
|
1811
|
-
const defaultProps = Object.assign(
|
|
1812
|
-
options.dataAttr && configOrCva.__name__ ? { 'data-recipe': configOrCva.__name__ } : {},
|
|
1813
|
-
options.defaultProps,
|
|
1814
|
-
)
|
|
1815
|
-
|
|
1816
|
-
const __cvaFn__ = composeCvaFn(Dynamic.__cva__, cvaFn)
|
|
1817
|
-
const __shouldForwardProps__ = composeShouldForwardProps(Dynamic, shouldForwardProp)
|
|
1818
|
-
const __base__ = Dynamic.__base__ || Dynamic
|
|
1819
|
-
|
|
1820
|
-
const ${componentName} = function ${componentName}(props) {
|
|
1821
|
-
const { as: Element = __base__, unstyled, children, className, ...restProps } = props
|
|
1822
|
-
|
|
1823
|
-
const combinedProps = Object.assign({}, defaultProps, restProps)
|
|
1824
|
-
|
|
1825
|
-
const [htmlProps, forwardedProps, variantProps, styleProps, elementProps] =
|
|
1826
|
-
splitProps(combinedProps, normalizeHTMLProps.keys, __shouldForwardProps__, __cvaFn__.variantKeys, isCssProperty)
|
|
1827
|
-
|
|
1828
|
-
const { css: cssStyles, ...propStyles } = styleProps
|
|
1829
|
-
|
|
1830
|
-
function recipeClass() {
|
|
1831
|
-
const { css: cssStyles, ...propStyles } = styleProps
|
|
1832
|
-
const compoundVariantStyles = __cvaFn__.__getCompoundVariantCss__?.(variantProps);
|
|
1833
|
-
return cx(__cvaFn__(variantProps, false), css(compoundVariantStyles, propStyles, cssStyles), combinedProps.class, className)
|
|
1834
|
-
}
|
|
1835
|
-
|
|
1836
|
-
function cvaClass() {
|
|
1837
|
-
const { css: cssStyles, ...propStyles } = styleProps
|
|
1838
|
-
const cvaStyles = __cvaFn__.raw(variantProps)
|
|
1839
|
-
return cx(css(cvaStyles, propStyles, cssStyles), combinedProps.class, className)
|
|
1840
|
-
}
|
|
1841
|
-
|
|
1842
|
-
const classes = () => {
|
|
1843
|
-
if (unstyled) {
|
|
1844
|
-
const { css: cssStyles, ...propStyles } = styleProps
|
|
1845
|
-
return cx(css(propStyles, cssStyles), combinedProps.class, className)
|
|
1846
|
-
}
|
|
1847
|
-
return configOrCva.__recipe__ ? recipeClass() : cvaClass()
|
|
1848
|
-
}
|
|
1849
|
-
|
|
1850
|
-
return h(Element, {
|
|
1851
|
-
...forwardedProps,
|
|
1852
|
-
...elementProps,
|
|
1853
|
-
...normalizeHTMLProps(htmlProps),
|
|
1854
|
-
class: classes(),
|
|
1855
|
-
}, children ?? combinedProps.children)
|
|
1856
|
-
}
|
|
1857
|
-
|
|
1858
|
-
const name = getDisplayName(__base__)
|
|
1859
|
-
|
|
1860
|
-
${componentName}.displayName = \`${factoryName}.\${name}\`
|
|
1861
|
-
${componentName}.__cva__ = __cvaFn__
|
|
1862
|
-
${componentName}.__base__ = __base__
|
|
1863
|
-
${componentName}.__shouldForwardProps__ = shouldForwardProp
|
|
1864
|
-
|
|
1865
|
-
return ${componentName}
|
|
1866
|
-
}
|
|
1867
|
-
|
|
1868
|
-
function createJsxFactory() {
|
|
1869
|
-
const cache = new Map()
|
|
1870
|
-
|
|
1871
|
-
return new Proxy(styledFn, {
|
|
1872
|
-
apply(_, __, args) {
|
|
1873
|
-
return styledFn(...args)
|
|
1874
|
-
},
|
|
1875
|
-
get(_, el) {
|
|
1876
|
-
if (!cache.has(el)) {
|
|
1877
|
-
cache.set(el, styledFn(el))
|
|
1878
|
-
}
|
|
1879
|
-
return cache.get(el)
|
|
1880
|
-
},
|
|
1881
|
-
})
|
|
1882
|
-
}
|
|
1883
|
-
|
|
1884
|
-
export const ${factoryName} = /* @__PURE__ */ createJsxFactory()
|
|
1885
|
-
|
|
1886
|
-
` };
|
|
1887
|
-
}
|
|
1888
|
-
//#endregion
|
|
1889
|
-
//#region src/artifacts/qwik-jsx/pattern.ts
|
|
1890
|
-
function generateQwikJsxPattern(ctx, filters) {
|
|
1891
|
-
const { typeName, factoryName, styleProps: jsxStyleProps } = ctx.jsx;
|
|
1892
|
-
return ctx.patterns.filterDetails(filters).map((pattern) => {
|
|
1893
|
-
const { upperName, styleFnName, dashName, jsxName, props, blocklistType } = pattern;
|
|
1894
|
-
const { description, jsxElement = "div", deprecated } = pattern.config;
|
|
1895
|
-
return {
|
|
1896
|
-
name: dashName,
|
|
1897
|
-
js: outdent.outdent`
|
|
1898
|
-
import { h } from '@builder.io/qwik'
|
|
1899
|
-
${jsxStyleProps === "minimal" ? ctx.file.import("mergeCss", "../css/css") : ""}
|
|
1900
|
-
${ctx.file.import("splitProps", "../helpers")}
|
|
1901
|
-
${ctx.file.import(styleFnName, `../patterns/${dashName}`)}
|
|
1902
|
-
${ctx.file.import(factoryName, "./factory")}
|
|
1903
|
-
|
|
1904
|
-
export const ${jsxName} = /* @__PURE__ */ function ${jsxName}(props) {
|
|
1905
|
-
${(0, ts_pattern.match)(jsxStyleProps).with("none", () => outdent.outdent`
|
|
1906
|
-
const [patternProps, restProps] = splitProps(props, ${JSON.stringify(props)})
|
|
1907
|
-
|
|
1908
|
-
const styleProps = ${styleFnName}(patternProps)
|
|
1909
|
-
const mergedProps = { ref, ...restProps, css: styleProps }
|
|
1910
|
-
|
|
1911
|
-
return h(${factoryName}.${jsxElement}, mergedProps)
|
|
1912
|
-
`).with("minimal", () => outdent.outdent`
|
|
1913
|
-
const [patternProps, restProps] = splitProps(props, ${JSON.stringify(props)})
|
|
1914
|
-
|
|
1915
|
-
const styleProps = ${styleFnName}(patternProps)
|
|
1916
|
-
const cssProps = { css: mergeCss(styleProps, props.css) }
|
|
1917
|
-
const mergedProps = { ...restProps, ...cssProps }
|
|
1918
|
-
|
|
1919
|
-
return h(${factoryName}.${jsxElement}, mergedProps)
|
|
1920
|
-
`).with("all", () => outdent.outdent`
|
|
1921
|
-
const [patternProps, restProps] = splitProps(props, ${JSON.stringify(props)})
|
|
1922
|
-
|
|
1923
|
-
const styleProps = ${styleFnName}(patternProps)
|
|
1924
|
-
const mergedProps = { ...styleProps, ...restProps }
|
|
1925
|
-
|
|
1926
|
-
return h(${factoryName}.${jsxElement}, mergedProps)
|
|
1927
|
-
`).exhaustive()}
|
|
1928
|
-
}
|
|
1929
|
-
`,
|
|
1930
|
-
dts: outdent.outdent`
|
|
1931
|
-
import type { Component } from '@builder.io/qwik'
|
|
1932
|
-
${ctx.file.importType(`${upperName}Properties`, `../patterns/${dashName}`)}
|
|
1933
|
-
${ctx.file.importType(typeName, "../types/jsx")}
|
|
1934
|
-
${ctx.file.importType("Assign, DistributiveOmit", "../types/system-types")}
|
|
1935
|
-
|
|
1936
|
-
export interface ${upperName}Props extends Assign<${typeName}<'${jsxElement}'>, DistributiveOmit<${upperName}Properties, ${blocklistType || "\"\""}>> {}
|
|
1937
|
-
|
|
1938
|
-
${ctx.file.jsDocComment(description, { deprecated })}
|
|
1939
|
-
export declare const ${jsxName}: Component<${upperName}Props>
|
|
1940
|
-
`
|
|
1941
|
-
};
|
|
1942
|
-
});
|
|
1943
|
-
}
|
|
1944
|
-
//#endregion
|
|
1945
|
-
//#region src/artifacts/qwik-jsx/types.ts
|
|
1946
|
-
function generateQwikJsxTypes(ctx) {
|
|
1947
|
-
const { factoryName, componentName, upperName, typeName, variantName } = ctx.jsx;
|
|
1948
|
-
return {
|
|
1949
|
-
jsxFactory: outdent.outdent`
|
|
1950
|
-
${ctx.file.importType(upperName, "../types/jsx")}
|
|
1951
|
-
export declare const ${factoryName}: ${upperName}
|
|
1952
|
-
`,
|
|
1953
|
-
jsxType: outdent.outdent`
|
|
1954
|
-
import type { Component, QwikIntrinsicElements } from '@builder.io/qwik'
|
|
1955
|
-
${ctx.file.importType("RecipeDefinition, RecipeSelection, RecipeVariantRecord", "./recipe")}
|
|
1956
|
-
${ctx.file.importType("Assign, DistributiveOmit, DistributiveUnion, JsxStyleProps, PatchedHTMLProps, Pretty", "./system-types")}
|
|
1957
|
-
|
|
1958
|
-
export type ElementType = keyof QwikIntrinsicElements | Component<any>
|
|
1959
|
-
|
|
1960
|
-
export type ComponentProps<T extends ElementType> = T extends keyof QwikIntrinsicElements
|
|
1961
|
-
? QwikIntrinsicElements[T]
|
|
1962
|
-
: T extends Component<infer P>
|
|
1963
|
-
? P
|
|
1964
|
-
: never
|
|
1965
|
-
|
|
1966
|
-
interface Dict {
|
|
1967
|
-
[k: string]: unknown
|
|
1968
|
-
}
|
|
1969
|
-
|
|
1970
|
-
export type DataAttrs = Record<\`data-\${string}\`, unknown>
|
|
1971
|
-
|
|
1972
|
-
export interface UnstyledProps {
|
|
1973
|
-
/**
|
|
1974
|
-
* Whether to remove recipe styles
|
|
1975
|
-
*/
|
|
1976
|
-
unstyled?: boolean | undefined
|
|
1977
|
-
}
|
|
1978
|
-
|
|
1979
|
-
export interface AsProps {
|
|
1980
|
-
/**
|
|
1981
|
-
* The element to render as
|
|
1982
|
-
*/
|
|
1983
|
-
as?: ElementType | undefined
|
|
1984
|
-
}
|
|
1985
|
-
|
|
1986
|
-
export interface ${componentName}<T extends ElementType, P extends Dict = {}> extends Component<Assign<ComponentProps<T> & UnstyledProps & AsProps, Assign<PatchedHTMLProps, Assign<JsxStyleProps, P>>>> {}
|
|
1987
|
-
|
|
1988
|
-
interface RecipeFn {
|
|
1989
|
-
__type: any
|
|
1990
|
-
}
|
|
1991
|
-
|
|
1992
|
-
export interface JsxFactoryOptions<TProps extends Dict> {
|
|
1993
|
-
dataAttr?: boolean
|
|
1994
|
-
defaultProps?: Partial<TProps> & DataAttrs
|
|
1995
|
-
shouldForwardProp?: (prop: string, variantKeys: string[]) => boolean
|
|
1996
|
-
forwardProps?: string[]
|
|
1997
|
-
}
|
|
1998
|
-
|
|
1999
|
-
export type JsxRecipeProps<T extends ElementType, P extends Dict> = JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps, P>;
|
|
2000
|
-
|
|
2001
|
-
export type JsxElement<T extends ElementType, P extends Dict> = T extends ${componentName}<infer A, infer B>
|
|
2002
|
-
? ${componentName}<A, Pretty<DistributiveUnion<P, B>>>
|
|
2003
|
-
: ${componentName}<T, P>
|
|
2004
|
-
|
|
2005
|
-
export interface JsxFactory {
|
|
2006
|
-
<T extends ElementType>(component: T): ${componentName}<T, {}>
|
|
2007
|
-
<T extends ElementType, P extends RecipeVariantRecord>(component: T, recipe: RecipeDefinition<P>, options?: JsxFactoryOptions<JsxRecipeProps<T, RecipeSelection<P>>>): JsxElement<
|
|
2008
|
-
T,
|
|
2009
|
-
RecipeSelection<P>
|
|
2010
|
-
>
|
|
2011
|
-
<T extends ElementType, P extends RecipeFn>(component: T, recipeFn: P, options?: JsxFactoryOptions<JsxRecipeProps<T, P['__type']>>): JsxElement<T, P['__type']>
|
|
2012
|
-
}
|
|
2013
|
-
|
|
2014
|
-
export type JsxElements = {
|
|
2015
|
-
[K in keyof QwikIntrinsicElements]: ${componentName}<K, {}>
|
|
2016
|
-
}
|
|
2017
|
-
|
|
2018
|
-
export type ${upperName} = JsxFactory & JsxElements
|
|
2019
|
-
|
|
2020
|
-
export type ${typeName}<T extends ElementType> = Assign<ComponentProps<T> & UnstyledProps & AsProps, JsxStyleProps>
|
|
2021
|
-
|
|
2022
|
-
export type ${variantName}<T extends ${componentName}<any, any>> = T extends ${componentName}<any, infer Props> ? Props : never
|
|
2023
|
-
`
|
|
2024
|
-
};
|
|
2025
|
-
}
|
|
2026
|
-
//#endregion
|
|
2027
|
-
//#region src/artifacts/qwik-jsx/jsx.string-literal.ts
|
|
2028
|
-
function generateQwikJsxStringLiteralFactory(ctx) {
|
|
2029
|
-
const { factoryName, componentName } = ctx.jsx;
|
|
2030
|
-
return { js: outdent.outdent`
|
|
2031
|
-
import { h } from '@builder.io/qwik'
|
|
2032
|
-
${ctx.file.import("getDisplayName", "./factory-helper")}
|
|
2033
|
-
${ctx.file.import("css, cx", "../css/index")}
|
|
2034
|
-
|
|
2035
|
-
function createStyledFn(Dynamic) {
|
|
2036
|
-
const __base__ = Dynamic.__base__ || Dynamic
|
|
2037
|
-
return function styledFn(template) {
|
|
2038
|
-
const styles = css.raw(Dynamic.__styles__, template)
|
|
2039
|
-
|
|
2040
|
-
const ${componentName} = (props) => {
|
|
2041
|
-
const { as: Element = __base__, ...elementProps } = props
|
|
2042
|
-
|
|
2043
|
-
function classes() {
|
|
2044
|
-
return cx(css(styles), elementProps.className)
|
|
2045
|
-
}
|
|
2046
|
-
|
|
2047
|
-
return h(Element, {
|
|
2048
|
-
...elementProps,
|
|
2049
|
-
className: classes(),
|
|
2050
|
-
})
|
|
2051
|
-
}
|
|
2052
|
-
|
|
2053
|
-
const name = getDisplayName(__base__)
|
|
2054
|
-
|
|
2055
|
-
${componentName}.displayName = \`${factoryName}.\${name}\`
|
|
2056
|
-
${componentName}.__styles__ = styles
|
|
2057
|
-
${componentName}.__base__ = __base__
|
|
2058
|
-
|
|
2059
|
-
return ${componentName}
|
|
2060
|
-
}
|
|
2061
|
-
}
|
|
2062
|
-
|
|
2063
|
-
function createJsxFactory() {
|
|
2064
|
-
const cache = new Map()
|
|
2065
|
-
|
|
2066
|
-
return new Proxy(createStyledFn, {
|
|
2067
|
-
apply(_, __, args) {
|
|
2068
|
-
return createStyledFn(...args)
|
|
2069
|
-
},
|
|
2070
|
-
get(_, el) {
|
|
2071
|
-
if (!cache.has(el)) {
|
|
2072
|
-
cache.set(el, createStyledFn(el))
|
|
2073
|
-
}
|
|
2074
|
-
return cache.get(el)
|
|
2075
|
-
},
|
|
2076
|
-
})
|
|
2077
|
-
}
|
|
2078
|
-
|
|
2079
|
-
export const ${factoryName} = /* @__PURE__ */ createJsxFactory()
|
|
2080
|
-
|
|
2081
|
-
` };
|
|
2082
|
-
}
|
|
2083
|
-
//#endregion
|
|
2084
|
-
//#region src/artifacts/qwik-jsx/types.string-literal.ts
|
|
2085
|
-
function generateQwikJsxStringLiteralTypes(ctx) {
|
|
2086
|
-
const { factoryName, componentName, upperName, typeName } = ctx.jsx;
|
|
2087
|
-
return {
|
|
2088
|
-
jsxFactory: outdent.outdent`
|
|
2089
|
-
${ctx.file.importType(upperName, "../types/jsx")}
|
|
2090
|
-
export declare const ${factoryName}: ${upperName}
|
|
2091
|
-
`,
|
|
2092
|
-
jsxType: outdent.outdent`
|
|
2093
|
-
import type { Component, QwikIntrinsicElements } from '@builder.io/qwik'
|
|
2094
|
-
|
|
2095
|
-
export type ElementType = keyof QwikIntrinsicElements | Component<any>
|
|
2096
|
-
|
|
2097
|
-
export type ComponentProps<T extends ElementType> = T extends keyof QwikIntrinsicElements
|
|
2098
|
-
? QwikIntrinsicElements[T]
|
|
2099
|
-
: T extends Component<infer P>
|
|
2100
|
-
? P
|
|
2101
|
-
: never
|
|
2102
|
-
|
|
2103
|
-
interface Dict {
|
|
2104
|
-
[k: string]: unknown
|
|
2105
|
-
}
|
|
2106
|
-
|
|
2107
|
-
export interface AsProps {
|
|
2108
|
-
/**
|
|
2109
|
-
* The element to render as
|
|
2110
|
-
*/
|
|
2111
|
-
as?: ElementType | undefined
|
|
2112
|
-
}
|
|
2113
|
-
|
|
2114
|
-
export type ${componentName}<T extends ElementType> = {
|
|
2115
|
-
(args: { raw: readonly string[] | ArrayLike<string> }): (props: ComponentProps<T> & AsProps) => JSX.Element
|
|
2116
|
-
}
|
|
2117
|
-
|
|
2118
|
-
export interface JsxFactory {
|
|
2119
|
-
<T extends ElementType>(component: T): ${componentName}<T>
|
|
2120
|
-
}
|
|
2121
|
-
|
|
2122
|
-
export type JsxElements = {
|
|
2123
|
-
[K in keyof QwikIntrinsicElements]: ${componentName}<K>
|
|
2124
|
-
}
|
|
2125
|
-
|
|
2126
|
-
export type ${upperName} = JsxFactory & JsxElements
|
|
2127
|
-
|
|
2128
|
-
export type ${typeName}<T extends ElementType> = ComponentProps<T>
|
|
2129
|
-
`
|
|
2130
|
-
};
|
|
2131
|
-
}
|
|
2132
|
-
//#endregion
|
|
2133
|
-
//#region src/artifacts/react-jsx/jsx.ts
|
|
2134
|
-
function generateReactJsxFactory(ctx) {
|
|
2135
|
-
const { factoryName, componentName } = ctx.jsx;
|
|
2136
|
-
return { js: outdent.outdent`
|
|
2137
|
-
import { createElement, forwardRef } from 'react'
|
|
2138
|
-
${ctx.file.import("css, cx, cva", "../css/index")}
|
|
2139
|
-
${ctx.file.import("defaultShouldForwardProp, composeShouldForwardProps, composeCvaFn, getDisplayName", "./factory-helper")}
|
|
2140
|
-
${ctx.file.import("splitProps, normalizeHTMLProps", "../helpers")}
|
|
2141
|
-
${ctx.file.import("isCssProperty", "./is-valid-prop")}
|
|
2142
|
-
|
|
2143
|
-
function styledFn(Dynamic, configOrCva = {}, options = {}) {
|
|
2144
|
-
const cvaFn = configOrCva.__cva__ || configOrCva.__recipe__ ? configOrCva : cva(configOrCva)
|
|
2145
|
-
|
|
2146
|
-
const forwardFn = options.shouldForwardProp || defaultShouldForwardProp
|
|
2147
|
-
const shouldForwardProp = (prop) => {
|
|
2148
|
-
if (options.forwardProps?.includes(prop)) return true
|
|
2149
|
-
return forwardFn(prop, cvaFn.variantKeys)
|
|
2150
|
-
}
|
|
2151
|
-
|
|
2152
|
-
const defaultProps = Object.assign(
|
|
2153
|
-
options.dataAttr && configOrCva.__name__ ? { 'data-recipe': configOrCva.__name__ } : {},
|
|
2154
|
-
options.defaultProps,
|
|
2155
|
-
)
|
|
2156
|
-
|
|
2157
|
-
const __cvaFn__ = composeCvaFn(Dynamic.__cva__, cvaFn)
|
|
2158
|
-
const __shouldForwardProps__ = composeShouldForwardProps(Dynamic, shouldForwardProp)
|
|
2159
|
-
const __base__ = Dynamic.__base__ || Dynamic
|
|
2160
|
-
|
|
2161
|
-
const ${componentName} = /* @__PURE__ */ forwardRef(function ${componentName}(props, ref) {
|
|
2162
|
-
const { as: Element = __base__, unstyled, children, ...restProps } = props
|
|
2163
|
-
|
|
2164
|
-
// Not memoized, deliberately. \`restProps\` is rest destructuring, so it is a fresh
|
|
2165
|
-
// object on every render and a dependency on it can never match — a memo here is a
|
|
2166
|
-
// guaranteed miss that still costs a hook slot, a deps array and a retained cell.
|
|
2167
|
-
const combinedProps = Object.assign({}, defaultProps, restProps)
|
|
2168
|
-
|
|
2169
|
-
const [htmlProps, forwardedProps, variantProps, styleProps, elementProps] =
|
|
2170
|
-
splitProps(combinedProps, normalizeHTMLProps.keys, __shouldForwardProps__, __cvaFn__.variantKeys, isCssProperty)
|
|
2171
|
-
|
|
2172
|
-
function recipeClass() {
|
|
2173
|
-
const { css: cssStyles, ...propStyles } = styleProps
|
|
2174
|
-
const compoundVariantStyles = __cvaFn__.__getCompoundVariantCss__?.(variantProps)
|
|
2175
|
-
return cx(__cvaFn__(variantProps, false), css(compoundVariantStyles, propStyles, cssStyles), combinedProps.className)
|
|
2176
|
-
}
|
|
2177
|
-
|
|
2178
|
-
function cvaClass() {
|
|
2179
|
-
const { css: cssStyles, ...propStyles } = styleProps
|
|
2180
|
-
const cvaStyles = __cvaFn__.raw(variantProps)
|
|
2181
|
-
return cx(css(cvaStyles, propStyles, cssStyles), combinedProps.className)
|
|
2182
|
-
}
|
|
2183
|
-
|
|
2184
|
-
const classes = () => {
|
|
2185
|
-
if (unstyled) {
|
|
2186
|
-
const { css: cssStyles, ...propStyles } = styleProps
|
|
2187
|
-
return cx(css(propStyles, cssStyles), combinedProps.className)
|
|
2188
|
-
}
|
|
2189
|
-
return configOrCva.__recipe__ ? recipeClass() : cvaClass()
|
|
2190
|
-
}
|
|
2191
|
-
|
|
2192
|
-
return createElement(Element, {
|
|
2193
|
-
ref,
|
|
2194
|
-
...forwardedProps,
|
|
2195
|
-
...elementProps,
|
|
2196
|
-
...normalizeHTMLProps(htmlProps),
|
|
2197
|
-
className: classes(),
|
|
2198
|
-
}, children ?? combinedProps.children)
|
|
2199
|
-
})
|
|
2200
|
-
|
|
2201
|
-
const name = getDisplayName(__base__)
|
|
2202
|
-
|
|
2203
|
-
${componentName}.displayName = \`${factoryName}.\${name}\`
|
|
2204
|
-
${componentName}.__cva__ = __cvaFn__
|
|
2205
|
-
${componentName}.__base__ = __base__
|
|
2206
|
-
${componentName}.__shouldForwardProps__ = shouldForwardProp
|
|
2207
|
-
|
|
2208
|
-
return ${componentName}
|
|
2209
|
-
}
|
|
2210
|
-
|
|
2211
|
-
function createJsxFactory() {
|
|
2212
|
-
const cache = new Map()
|
|
2213
|
-
|
|
2214
|
-
return new Proxy(styledFn, {
|
|
2215
|
-
apply(_, __, args) {
|
|
2216
|
-
return styledFn(...args)
|
|
2217
|
-
},
|
|
2218
|
-
get(_, el) {
|
|
2219
|
-
if (!cache.has(el)) {
|
|
2220
|
-
cache.set(el, styledFn(el))
|
|
2221
|
-
}
|
|
2222
|
-
return cache.get(el)
|
|
2223
|
-
},
|
|
2224
|
-
})
|
|
2225
|
-
}
|
|
2226
|
-
|
|
2227
|
-
export const ${factoryName} = /* @__PURE__ */ createJsxFactory()
|
|
2228
|
-
|
|
2229
|
-
` };
|
|
2230
|
-
}
|
|
2231
|
-
//#endregion
|
|
2232
|
-
//#region src/artifacts/react-jsx/pattern.ts
|
|
2233
|
-
function generateReactJsxPattern(ctx, filters) {
|
|
2234
|
-
const { typeName, factoryName, styleProps: jsxStyleProps } = ctx.jsx;
|
|
2235
|
-
return ctx.patterns.filterDetails(filters).map((pattern) => {
|
|
2236
|
-
const { upperName, styleFnName, dashName, jsxName, props, blocklistType } = pattern;
|
|
2237
|
-
const { description, jsxElement = "div", deprecated } = pattern.config;
|
|
2238
|
-
return {
|
|
2239
|
-
name: dashName,
|
|
2240
|
-
js: outdent.outdent`
|
|
2241
|
-
import { createElement, forwardRef } from 'react'
|
|
2242
|
-
${jsxStyleProps === "minimal" ? ctx.file.import("mergeCss", "../css/css") : ""}
|
|
2243
|
-
${ctx.file.import("splitProps", "../helpers")}
|
|
2244
|
-
${ctx.file.import(styleFnName, `../patterns/${dashName}`)}
|
|
2245
|
-
${ctx.file.import(factoryName, "./factory")}
|
|
2246
|
-
|
|
2247
|
-
export const ${jsxName} = /* @__PURE__ */ forwardRef(function ${jsxName}(props, ref) {
|
|
2248
|
-
${(0, ts_pattern.match)(jsxStyleProps).with("none", () => outdent.outdent`
|
|
2249
|
-
const [patternProps, restProps] = splitProps(props, ${JSON.stringify(props)})
|
|
2250
|
-
|
|
2251
|
-
const styleProps = ${styleFnName}(patternProps)
|
|
2252
|
-
const mergedProps = { ref, ...restProps, css: styleProps }
|
|
2253
|
-
|
|
2254
|
-
return createElement(${factoryName}.${jsxElement}, mergedProps)
|
|
2255
|
-
`).with("minimal", () => outdent.outdent`
|
|
2256
|
-
const [patternProps, restProps] = splitProps(props, ${JSON.stringify(props)})
|
|
2257
|
-
|
|
2258
|
-
const styleProps = ${styleFnName}(patternProps)
|
|
2259
|
-
const cssProps = { css: mergeCss(styleProps, props.css) }
|
|
2260
|
-
const mergedProps = { ref, ...restProps, ...cssProps }
|
|
2261
|
-
|
|
2262
|
-
return createElement(${factoryName}.${jsxElement}, mergedProps)
|
|
2263
|
-
`).with("all", () => outdent.outdent`
|
|
2264
|
-
const [patternProps, restProps] = splitProps(props, ${JSON.stringify(props)})
|
|
2265
|
-
|
|
2266
|
-
const styleProps = ${styleFnName}(patternProps)
|
|
2267
|
-
const mergedProps = { ref, ...styleProps, ...restProps }
|
|
2268
|
-
|
|
2269
|
-
return createElement(${factoryName}.${jsxElement}, mergedProps)
|
|
2270
|
-
`).exhaustive()}
|
|
2271
|
-
})
|
|
2272
|
-
`,
|
|
2273
|
-
dts: outdent.outdent`
|
|
2274
|
-
import type { FunctionComponent } from 'react'
|
|
2275
|
-
${ctx.file.importType(`${upperName}Properties`, `../patterns/${dashName}`)}
|
|
2276
|
-
${ctx.file.importType(typeName, "../types/jsx")}
|
|
2277
|
-
${ctx.file.importType("DistributiveOmit", "../types/system-types")}
|
|
2278
|
-
|
|
2279
|
-
export interface ${upperName}Props extends ${upperName}Properties, DistributiveOmit<${typeName}<'${jsxElement}'>, keyof ${upperName}Properties ${blocklistType}> {}
|
|
2280
|
-
|
|
2281
|
-
${ctx.file.jsDocComment(description, { deprecated })}
|
|
2282
|
-
export declare const ${jsxName}: FunctionComponent<${upperName}Props>
|
|
2283
|
-
`
|
|
2284
|
-
};
|
|
2285
|
-
});
|
|
2286
|
-
}
|
|
2287
|
-
//#endregion
|
|
2288
|
-
//#region src/artifacts/react-jsx/types.ts
|
|
2289
|
-
function generateReactJsxTypes(ctx) {
|
|
2290
|
-
const { factoryName, componentName, upperName, typeName, variantName } = ctx.jsx;
|
|
2291
|
-
return {
|
|
2292
|
-
jsxFactory: outdent.outdent`
|
|
2293
|
-
${ctx.file.importType(upperName, "../types/jsx")}
|
|
2294
|
-
export declare const ${factoryName}: ${upperName}
|
|
2295
|
-
`,
|
|
2296
|
-
jsxType: outdent.outdent`
|
|
2297
|
-
import type { ElementType, JSX, ComponentPropsWithRef, ComponentType, Component } from 'react'
|
|
2298
|
-
${ctx.file.importType("RecipeDefinition, RecipeSelection, RecipeVariantRecord", "./recipe")}
|
|
2299
|
-
${ctx.file.importType("Assign, DistributiveOmit, DistributiveUnion, JsxHTMLProps, JsxStyleProps, Pretty", "./system-types")}
|
|
2300
|
-
|
|
2301
|
-
interface Dict {
|
|
2302
|
-
[k: string]: unknown
|
|
2303
|
-
}
|
|
2304
|
-
|
|
2305
|
-
export type DataAttrs = Record<\`data-\${string}\`, unknown>
|
|
2306
|
-
|
|
2307
|
-
export interface UnstyledProps {
|
|
2308
|
-
/**
|
|
2309
|
-
* Whether to remove recipe styles
|
|
2310
|
-
*/
|
|
2311
|
-
unstyled?: boolean | undefined
|
|
2312
|
-
}
|
|
2313
|
-
|
|
2314
|
-
export interface AsProps {
|
|
2315
|
-
/**
|
|
2316
|
-
* The element to render as
|
|
2317
|
-
*/
|
|
2318
|
-
as?: ElementType | undefined
|
|
2319
|
-
}
|
|
2320
|
-
|
|
2321
|
-
export type ComponentProps<T extends ElementType> = T extends ComponentType<infer P> | Component<infer P>
|
|
2322
|
-
? JSX.LibraryManagedAttributes<T, P>
|
|
2323
|
-
: ComponentPropsWithRef<T>
|
|
2324
|
-
|
|
2325
|
-
export interface ${componentName}<T extends ElementType, P extends Dict = {}> {
|
|
2326
|
-
(props: JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps, Assign<JsxStyleProps, P>>): JSX.Element
|
|
2327
|
-
displayName?: string | undefined
|
|
2328
|
-
}
|
|
2329
|
-
|
|
2330
|
-
interface RecipeFn {
|
|
2331
|
-
__type: any
|
|
2332
|
-
}
|
|
2333
|
-
|
|
2334
|
-
export interface JsxFactoryOptions<TProps extends Dict> {
|
|
2335
|
-
dataAttr?: boolean
|
|
2336
|
-
defaultProps?: Partial<TProps> & DataAttrs
|
|
2337
|
-
shouldForwardProp?: (prop: string, variantKeys: string[]) => boolean
|
|
2338
|
-
forwardProps?: string[]
|
|
2339
|
-
}
|
|
2340
|
-
|
|
2341
|
-
export type JsxRecipeProps<T extends ElementType, P extends Dict> = JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps, P>;
|
|
2342
|
-
|
|
2343
|
-
export type JsxElement<T extends ElementType, P extends Dict> = T extends ${componentName}<infer A, infer B>
|
|
2344
|
-
? ${componentName}<A, Pretty<DistributiveUnion<P, B>>>
|
|
2345
|
-
: ${componentName}<T, P>
|
|
2346
|
-
|
|
2347
|
-
export interface JsxFactory {
|
|
2348
|
-
<T extends ElementType>(component: T): ${componentName}<T, {}>
|
|
2349
|
-
<T extends ElementType, P extends RecipeVariantRecord>(component: T, recipe: RecipeDefinition<P>, options?: JsxFactoryOptions<JsxRecipeProps<T, RecipeSelection<P>>>): JsxElement<
|
|
2350
|
-
T,
|
|
2351
|
-
RecipeSelection<P>
|
|
2352
|
-
>
|
|
2353
|
-
<T extends ElementType, P extends RecipeFn>(component: T, recipeFn: P, options?: JsxFactoryOptions<JsxRecipeProps<T, P['__type']>>): JsxElement<T, P['__type']>
|
|
2354
|
-
}
|
|
2355
|
-
|
|
2356
|
-
export type JsxElements = {
|
|
2357
|
-
[K in keyof JSX.IntrinsicElements]: ${componentName}<K, {}>
|
|
2358
|
-
}
|
|
2359
|
-
|
|
2360
|
-
export type ${upperName} = JsxFactory & JsxElements
|
|
2361
|
-
|
|
2362
|
-
export type ${typeName}<T extends ElementType> = JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps, JsxStyleProps>
|
|
2363
|
-
|
|
2364
|
-
export type ${variantName}<T extends ${componentName}<any, any>> = T extends ${componentName}<any, infer Props> ? Props : never
|
|
2365
|
-
`
|
|
2366
|
-
};
|
|
2367
|
-
}
|
|
2368
|
-
//#endregion
|
|
2369
|
-
//#region src/artifacts/react-jsx/create-style-context.ts
|
|
2370
|
-
function generateReactCreateStyleContext(ctx) {
|
|
2371
|
-
const { factoryName } = ctx.jsx;
|
|
2372
|
-
return {
|
|
2373
|
-
js: outdent.outdent`'use client'\n
|
|
2374
|
-
${ctx.file.import("cx, css, sva", "../css/index")}
|
|
2375
|
-
${ctx.file.import(factoryName, "./factory")}
|
|
2376
|
-
${ctx.file.import("getDisplayName", "./factory-helper")}
|
|
2377
|
-
import { createContext, useContext, createElement, forwardRef } from 'react'
|
|
2378
|
-
|
|
2379
|
-
function createSafeContext(contextName) {
|
|
2380
|
-
const Context = createContext(undefined)
|
|
2381
|
-
const useStyleContext = (componentName, slot) => {
|
|
2382
|
-
const context = useContext(Context)
|
|
2383
|
-
if (context === undefined) {
|
|
2384
|
-
const componentInfo = componentName ? \`Component "\${componentName}"\` : 'A component'
|
|
2385
|
-
const slotInfo = slot ? \` (slot: "\${slot}")\` : ''
|
|
2386
|
-
|
|
2387
|
-
throw new Error(
|
|
2388
|
-
\`\${componentInfo}\${slotInfo} cannot access \${contextName} because it's missing its Provider.\`
|
|
2389
|
-
)
|
|
2390
|
-
}
|
|
2391
|
-
return context
|
|
2392
|
-
}
|
|
2393
|
-
return [Context, useStyleContext]
|
|
2394
|
-
}
|
|
2395
|
-
|
|
2396
|
-
export function createStyleContext(recipe) {
|
|
2397
|
-
const isConfigRecipe = '__recipe__' in recipe
|
|
2398
|
-
const recipeName = isConfigRecipe && recipe.__name__ ? recipe.__name__ : undefined
|
|
2399
|
-
const contextName = recipeName ? \`createStyleContext("\${recipeName}")\` : 'createStyleContext'
|
|
2400
|
-
|
|
2401
|
-
const [StyleContext, useStyleContext] = createSafeContext(contextName)
|
|
2402
|
-
const svaFn = isConfigRecipe ? recipe : sva(recipe.config)
|
|
2403
|
-
|
|
2404
|
-
const getResolvedProps = (props, slotStyles) => {
|
|
2405
|
-
const { unstyled, ...restProps } = props
|
|
2406
|
-
if (unstyled) return restProps
|
|
2407
|
-
if (isConfigRecipe) {
|
|
2408
|
-
return { ...restProps, className: cx(slotStyles, restProps.className) }
|
|
2409
|
-
}
|
|
2410
|
-
${outdent.outdent.string((0, ts_pattern.match)(ctx.config.jsxStyleProps).with("all", () => `return { ...slotStyles, ...restProps }`).with("minimal", () => `return { ...restProps, css: css.raw(slotStyles, restProps.css) }`).with("none", () => `return { ...restProps, className: cx(css(slotStyles), restProps.className) }`).otherwise(() => `return restProps`))}
|
|
2411
|
-
}
|
|
2412
|
-
|
|
2413
|
-
const withRootProvider = (Component, options) => {
|
|
2414
|
-
const WithRootProvider = (props) => {
|
|
2415
|
-
const [variantProps, otherProps] = svaFn.splitVariantProps(props)
|
|
2416
|
-
|
|
2417
|
-
const slotStyles = isConfigRecipe ? svaFn(variantProps) : svaFn.raw(variantProps)
|
|
2418
|
-
slotStyles._classNameMap = svaFn.classNameMap
|
|
2419
|
-
|
|
2420
|
-
const mergedProps = options?.defaultProps
|
|
2421
|
-
? { ...options.defaultProps, ...otherProps }
|
|
2422
|
-
: otherProps
|
|
2423
|
-
|
|
2424
|
-
return createElement(StyleContext.Provider, {
|
|
2425
|
-
value: slotStyles,
|
|
2426
|
-
children: createElement(Component, mergedProps)
|
|
2427
|
-
})
|
|
2428
|
-
}
|
|
2429
|
-
|
|
2430
|
-
const componentName = getDisplayName(Component)
|
|
2431
|
-
WithRootProvider.displayName = \`withRootProvider(\${componentName})\`
|
|
2432
|
-
|
|
2433
|
-
return WithRootProvider
|
|
2434
|
-
}
|
|
2435
|
-
|
|
2436
|
-
const withProvider = (Component, slot, options) => {
|
|
2437
|
-
const StyledComponent = ${factoryName}(Component, {}, options)
|
|
2438
|
-
|
|
2439
|
-
const WithProvider = forwardRef((props, ref) => {
|
|
2440
|
-
const [variantProps, restProps] = svaFn.splitVariantProps(props)
|
|
2441
|
-
|
|
2442
|
-
const slotStyles = isConfigRecipe ? svaFn(variantProps) : svaFn.raw(variantProps)
|
|
2443
|
-
slotStyles._classNameMap = svaFn.classNameMap
|
|
2444
|
-
|
|
2445
|
-
const propsWithClass = { ...restProps, className: restProps.className ?? options?.defaultProps?.className }
|
|
2446
|
-
const resolvedProps = getResolvedProps(propsWithClass, slotStyles[slot])
|
|
2447
|
-
return createElement(StyleContext.Provider, {
|
|
2448
|
-
value: slotStyles,
|
|
2449
|
-
children: createElement(StyledComponent, {
|
|
2450
|
-
...resolvedProps,
|
|
2451
|
-
className: cx(resolvedProps.className, slotStyles._classNameMap[slot]),
|
|
2452
|
-
ref,
|
|
2453
|
-
})
|
|
2454
|
-
})
|
|
2455
|
-
})
|
|
2456
|
-
|
|
2457
|
-
const componentName = getDisplayName(Component)
|
|
2458
|
-
WithProvider.displayName = \`withProvider(\${componentName})\`
|
|
2459
|
-
|
|
2460
|
-
return WithProvider
|
|
2461
|
-
}
|
|
2462
|
-
|
|
2463
|
-
const withContext = (Component, slot, options) => {
|
|
2464
|
-
const StyledComponent = ${factoryName}(Component, {}, options)
|
|
2465
|
-
const componentName = getDisplayName(Component)
|
|
2466
|
-
|
|
2467
|
-
const WithContext = forwardRef((props, ref) => {
|
|
2468
|
-
const slotStyles = useStyleContext(componentName, slot)
|
|
2469
|
-
|
|
2470
|
-
const propsWithClass = { ...props, className: props.className ?? options?.defaultProps?.className }
|
|
2471
|
-
const resolvedProps = getResolvedProps(propsWithClass, slotStyles[slot])
|
|
2472
|
-
return createElement(StyledComponent, {
|
|
2473
|
-
...resolvedProps,
|
|
2474
|
-
className: cx(resolvedProps.className, slotStyles._classNameMap[slot]),
|
|
2475
|
-
ref,
|
|
2476
|
-
})
|
|
2477
|
-
})
|
|
2478
|
-
|
|
2479
|
-
WithContext.displayName = \`withContext(\${componentName})\`
|
|
2480
|
-
|
|
2481
|
-
return WithContext
|
|
2482
|
-
}
|
|
2483
|
-
|
|
2484
|
-
return {
|
|
2485
|
-
withRootProvider,
|
|
2486
|
-
withProvider,
|
|
2487
|
-
withContext,
|
|
2488
|
-
}
|
|
2489
|
-
}
|
|
2490
|
-
`,
|
|
2491
|
-
dts: outdent.outdent`
|
|
2492
|
-
${ctx.file.importType("SlotRecipeRuntimeFn, RecipeVariantProps", "../types/recipe")}
|
|
2493
|
-
${ctx.file.importType("JsxHTMLProps, JsxStyleProps, Assign", "../types/system-types")}
|
|
2494
|
-
${ctx.file.importType("JsxFactoryOptions, ComponentProps, DataAttrs, AsProps", "../types/jsx")}
|
|
2495
|
-
import type { ComponentType, ElementType } from 'react'
|
|
2496
|
-
|
|
2497
|
-
interface UnstyledProps {
|
|
2498
|
-
unstyled?: boolean | undefined
|
|
2499
|
-
}
|
|
2500
|
-
|
|
2501
|
-
type SvaFn<S extends string = any> = SlotRecipeRuntimeFn<S, any>
|
|
2502
|
-
interface SlotRecipeFn {
|
|
2503
|
-
__type: any
|
|
2504
|
-
__slot: string
|
|
2505
|
-
(props?: any): any
|
|
2506
|
-
}
|
|
2507
|
-
type SlotRecipe = SvaFn | SlotRecipeFn
|
|
2508
|
-
|
|
2509
|
-
type InferSlot<R extends SlotRecipe> = R extends SlotRecipeFn ? R['__slot'] : R extends SvaFn<infer S> ? S : never
|
|
2510
|
-
|
|
2511
|
-
interface WithProviderOptions<P = {}> {
|
|
2512
|
-
defaultProps?: (Partial<P> & DataAttrs) | undefined
|
|
2513
|
-
}
|
|
2514
|
-
|
|
2515
|
-
type StyleContextProvider<T extends ElementType, R extends SlotRecipe> = ComponentType<
|
|
2516
|
-
JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps, Assign<RecipeVariantProps<R>, JsxStyleProps>>
|
|
2517
|
-
>
|
|
2518
|
-
|
|
2519
|
-
type StyleContextRootProvider<T extends ElementType, R extends SlotRecipe> = ComponentType<
|
|
2520
|
-
ComponentProps<T> & UnstyledProps & RecipeVariantProps<R>
|
|
2521
|
-
>
|
|
2522
|
-
|
|
2523
|
-
type StyleContextConsumer<T extends ElementType> = ComponentType<
|
|
2524
|
-
JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps, JsxStyleProps>
|
|
2525
|
-
>
|
|
2526
|
-
|
|
2527
|
-
export interface StyleContext<R extends SlotRecipe> {
|
|
2528
|
-
withRootProvider: <T extends ElementType>(
|
|
2529
|
-
Component: T,
|
|
2530
|
-
options?: WithProviderOptions<ComponentProps<T>> | undefined
|
|
2531
|
-
) => StyleContextRootProvider<T, R>
|
|
2532
|
-
withProvider: <T extends ElementType>(
|
|
2533
|
-
Component: T,
|
|
2534
|
-
slot: InferSlot<R>,
|
|
2535
|
-
options?: JsxFactoryOptions<ComponentProps<T>> | undefined
|
|
2536
|
-
) => StyleContextProvider<T, R>
|
|
2537
|
-
withContext: <T extends ElementType>(
|
|
2538
|
-
Component: T,
|
|
2539
|
-
slot: InferSlot<R>,
|
|
2540
|
-
options?: JsxFactoryOptions<ComponentProps<T>> | undefined
|
|
2541
|
-
) => StyleContextConsumer<T>
|
|
2542
|
-
}
|
|
2543
|
-
|
|
2544
|
-
export declare function createStyleContext<R extends SlotRecipe>(recipe: R): StyleContext<R>
|
|
2545
|
-
`
|
|
2546
|
-
};
|
|
2547
|
-
}
|
|
2548
|
-
//#endregion
|
|
2549
|
-
//#region src/artifacts/react-jsx/jsx.string-literal.ts
|
|
2550
|
-
function generateReactJsxStringLiteralFactory(ctx) {
|
|
2551
|
-
const { factoryName, componentName } = ctx.jsx;
|
|
2552
|
-
return { js: outdent.outdent`
|
|
2553
|
-
import { createElement, forwardRef } from 'react'
|
|
2554
|
-
${ctx.file.import("getDisplayName", "./factory-helper")}
|
|
2555
|
-
${ctx.file.import("css, cx", "../css/index")}
|
|
2556
|
-
|
|
2557
|
-
function createStyledFn(Dynamic) {
|
|
2558
|
-
const __base__ = Dynamic.__base__ || Dynamic
|
|
2559
|
-
return function styledFn(template) {
|
|
2560
|
-
const styles = css.raw(Dynamic.__styles__, template)
|
|
2561
|
-
|
|
2562
|
-
const ${componentName} = /* @__PURE__ */ forwardRef(function ${componentName}(props, ref) {
|
|
2563
|
-
const { as: Element = __base__, ...elementProps } = props
|
|
2564
|
-
|
|
2565
|
-
function classes() {
|
|
2566
|
-
return cx(css(styles), elementProps.className)
|
|
2567
|
-
}
|
|
2568
|
-
|
|
2569
|
-
return createElement(Element, {
|
|
2570
|
-
ref,
|
|
2571
|
-
...elementProps,
|
|
2572
|
-
className: classes(),
|
|
2573
|
-
})
|
|
2574
|
-
})
|
|
2575
|
-
|
|
2576
|
-
const name = getDisplayName(__base__)
|
|
2577
|
-
|
|
2578
|
-
${componentName}.displayName = \`${factoryName}.\${name}\`
|
|
2579
|
-
${componentName}.__styles__ = styles
|
|
2580
|
-
${componentName}.__base__ = __base__
|
|
2581
|
-
|
|
2582
|
-
return ${componentName}
|
|
2583
|
-
}
|
|
2584
|
-
}
|
|
2585
|
-
|
|
2586
|
-
function createJsxFactory() {
|
|
2587
|
-
const cache = new Map()
|
|
2588
|
-
|
|
2589
|
-
return new Proxy(createStyledFn, {
|
|
2590
|
-
apply(_, __, args) {
|
|
2591
|
-
return createStyledFn(...args)
|
|
2592
|
-
},
|
|
2593
|
-
get(_, el) {
|
|
2594
|
-
if (!cache.has(el)) {
|
|
2595
|
-
cache.set(el, createStyledFn(el))
|
|
2596
|
-
}
|
|
2597
|
-
return cache.get(el)
|
|
2598
|
-
},
|
|
2599
|
-
})
|
|
2600
|
-
}
|
|
2601
|
-
|
|
2602
|
-
export const ${factoryName} = /* @__PURE__ */ createJsxFactory()
|
|
2603
|
-
` };
|
|
2604
|
-
}
|
|
2605
|
-
//#endregion
|
|
2606
|
-
//#region src/artifacts/react-jsx/types.string-literal.ts
|
|
2607
|
-
function generateReactJsxStringLiteralTypes(ctx) {
|
|
2608
|
-
const { factoryName, componentName, upperName, typeName } = ctx.jsx;
|
|
2609
|
-
return {
|
|
2610
|
-
jsxFactory: outdent.outdent`
|
|
2611
|
-
${ctx.file.importType(upperName, "../types/jsx")}
|
|
2612
|
-
export declare const ${factoryName}: ${upperName}
|
|
2613
|
-
`,
|
|
2614
|
-
jsxType: outdent.outdent`
|
|
2615
|
-
import type { ComponentPropsWithoutRef, ElementType, ElementRef, JSX, Ref } from 'react'
|
|
2616
|
-
${ctx.file.importType("DistributiveOmit", "../types/system-types")}
|
|
2617
|
-
|
|
2618
|
-
interface Dict {
|
|
2619
|
-
[k: string]: unknown
|
|
2620
|
-
}
|
|
2621
|
-
|
|
2622
|
-
export interface AsProps {
|
|
2623
|
-
/**
|
|
2624
|
-
* The element to render as
|
|
2625
|
-
*/
|
|
2626
|
-
as?: ElementType | undefined
|
|
2627
|
-
}
|
|
2628
|
-
|
|
2629
|
-
export type ComponentProps<T extends ElementType> = DistributiveOmit<ComponentPropsWithoutRef<T>, 'ref'> & {
|
|
2630
|
-
ref?: Ref<ElementRef<T>>
|
|
2631
|
-
} & AsProps
|
|
2632
|
-
|
|
2633
|
-
export type ${componentName}<T extends ElementType> = {
|
|
2634
|
-
(args: { raw: readonly string[] | ArrayLike<string> }): (props: ComponentProps<T>) => JSX.Element
|
|
2635
|
-
displayName?: string | undefined
|
|
2636
|
-
}
|
|
2637
|
-
|
|
2638
|
-
export interface JsxFactory {
|
|
2639
|
-
<T extends ElementType>(component: T): ${componentName}<T>
|
|
2640
|
-
}
|
|
2641
|
-
|
|
2642
|
-
export type JsxElements = {
|
|
2643
|
-
[K in keyof JSX.IntrinsicElements]: ${componentName}<K>
|
|
2644
|
-
}
|
|
2645
|
-
|
|
2646
|
-
export type ${upperName} = JsxFactory & JsxElements
|
|
2647
|
-
|
|
2648
|
-
export type ${typeName}<T extends ElementType> = ComponentProps<T>
|
|
2649
|
-
`
|
|
2650
|
-
};
|
|
2651
|
-
}
|
|
2652
|
-
//#endregion
|
|
2653
|
-
//#region src/artifacts/solid-jsx/jsx.ts
|
|
2654
|
-
function generateSolidJsxFactory(ctx) {
|
|
2655
|
-
const { componentName, factoryName } = ctx.jsx;
|
|
2656
|
-
return { js: outdent.outdent`
|
|
2657
|
-
import { createMemo, mergeProps, splitProps } from 'solid-js'
|
|
2658
|
-
import { Dynamic, createComponent } from 'solid-js/web'
|
|
2659
|
-
${ctx.file.import("css, cx, cva", "../css/index")}
|
|
2660
|
-
${ctx.file.import("normalizeHTMLProps", "../helpers")}
|
|
2661
|
-
${ctx.file.import("composeCvaFn, composeShouldForwardProps, defaultShouldForwardProp, getDisplayName", "./factory-helper")}
|
|
2662
|
-
${ctx.file.import("isCssProperty", "./is-valid-prop")}
|
|
2663
|
-
|
|
2664
|
-
function styledFn(element, configOrCva = {}, options = {}) {
|
|
2665
|
-
const cvaFn =
|
|
2666
|
-
configOrCva.__cva__ || configOrCva.__recipe__
|
|
2667
|
-
? configOrCva
|
|
2668
|
-
: cva(configOrCva)
|
|
2669
|
-
|
|
2670
|
-
const forwardFn = options.shouldForwardProp || defaultShouldForwardProp
|
|
2671
|
-
const shouldForwardProp = (prop) => {
|
|
2672
|
-
if (options.forwardProps?.includes(prop)) return true
|
|
2673
|
-
return forwardFn(prop, cvaFn.variantKeys)
|
|
2674
|
-
}
|
|
2675
|
-
|
|
2676
|
-
const getDefaultProps = () => {
|
|
2677
|
-
const baseDefaults = options.dataAttr && configOrCva.__name__
|
|
2678
|
-
? { 'data-recipe': configOrCva.__name__ }
|
|
2679
|
-
: {}
|
|
2680
|
-
const defaults = typeof options.defaultProps === 'function'
|
|
2681
|
-
? options.defaultProps()
|
|
2682
|
-
: options.defaultProps
|
|
2683
|
-
return Object.assign(baseDefaults, defaults)
|
|
2684
|
-
}
|
|
2685
|
-
|
|
2686
|
-
const __cvaFn__ = composeCvaFn(element.__cva__, cvaFn)
|
|
2687
|
-
const __shouldForwardProps__ = composeShouldForwardProps(
|
|
2688
|
-
element,
|
|
2689
|
-
shouldForwardProp
|
|
2690
|
-
)
|
|
2691
|
-
|
|
2692
|
-
const ${componentName} = (props) => {
|
|
2693
|
-
const mergedProps = mergeProps(
|
|
2694
|
-
{ as: element.__base__ || element },
|
|
2695
|
-
getDefaultProps(),
|
|
2696
|
-
props
|
|
2697
|
-
)
|
|
2698
|
-
|
|
2699
|
-
const [localProps, restProps] = splitProps(mergedProps, [
|
|
2700
|
-
'as',
|
|
2701
|
-
'unstyled',
|
|
2702
|
-
'class',
|
|
2703
|
-
'className',
|
|
2704
|
-
])
|
|
2705
|
-
|
|
2706
|
-
const [htmlProps, aProps] = splitProps(restProps, normalizeHTMLProps.keys)
|
|
2707
|
-
|
|
2708
|
-
const forwardedKeys = createMemo(() => {
|
|
2709
|
-
const keys = Object.keys(aProps)
|
|
2710
|
-
return keys.filter((prop) => __shouldForwardProps__(prop))
|
|
2711
|
-
})
|
|
2712
|
-
|
|
2713
|
-
const [forwardedProps, variantProps, bProps] = splitProps(aProps, forwardedKeys(), __cvaFn__.variantKeys)
|
|
2714
|
-
|
|
2715
|
-
const cssPropKeys = createMemo(() => {
|
|
2716
|
-
const keys = Object.keys(bProps)
|
|
2717
|
-
return keys.filter((prop) => isCssProperty(prop))
|
|
2718
|
-
})
|
|
2719
|
-
|
|
2720
|
-
const [styleProps, elementProps] = splitProps(bProps, cssPropKeys())
|
|
2721
|
-
|
|
2722
|
-
function recipeClass() {
|
|
2723
|
-
const { css: cssStyles, ...propStyles } = styleProps
|
|
2724
|
-
const compoundVariantStyles =
|
|
2725
|
-
__cvaFn__.__getCompoundVariantCss__?.(variantProps)
|
|
2726
|
-
return cx(
|
|
2727
|
-
__cvaFn__(variantProps, false),
|
|
2728
|
-
css(compoundVariantStyles, propStyles, cssStyles),
|
|
2729
|
-
localProps.class,
|
|
2730
|
-
localProps.className
|
|
2731
|
-
)
|
|
2732
|
-
}
|
|
2733
|
-
|
|
2734
|
-
function cvaClass() {
|
|
2735
|
-
const { css: cssStyles, ...propStyles } = styleProps
|
|
2736
|
-
const cvaStyles = __cvaFn__.raw(variantProps)
|
|
2737
|
-
return cx(
|
|
2738
|
-
css(cvaStyles, propStyles, cssStyles),
|
|
2739
|
-
localProps.class,
|
|
2740
|
-
localProps.className
|
|
2741
|
-
)
|
|
2742
|
-
}
|
|
2743
|
-
|
|
2744
|
-
const classes = () => {
|
|
2745
|
-
if (localProps.unstyled) {
|
|
2746
|
-
const { css: cssStyles, ...propStyles } = styleProps
|
|
2747
|
-
return cx(css(propStyles, cssStyles), localProps.class, localProps.className)
|
|
2748
|
-
}
|
|
2749
|
-
return configOrCva.__recipe__ ? recipeClass() : cvaClass()
|
|
2750
|
-
}
|
|
2751
|
-
|
|
2752
|
-
if (forwardedProps.className) {
|
|
2753
|
-
delete forwardedProps.className
|
|
2754
|
-
}
|
|
2755
|
-
|
|
2756
|
-
return createComponent(
|
|
2757
|
-
Dynamic,
|
|
2758
|
-
mergeProps(forwardedProps, elementProps, normalizeHTMLProps(htmlProps), {
|
|
2759
|
-
get component() {
|
|
2760
|
-
return localProps.as
|
|
2761
|
-
},
|
|
2762
|
-
get class() {
|
|
2763
|
-
return classes()
|
|
2764
|
-
},
|
|
2765
|
-
})
|
|
2766
|
-
)
|
|
2767
|
-
}
|
|
2768
|
-
|
|
2769
|
-
const name = getDisplayName(element)
|
|
2770
|
-
|
|
2771
|
-
${componentName}.displayName = \`${factoryName}.\${name}\`
|
|
2772
|
-
${componentName}.__cva__ = __cvaFn__
|
|
2773
|
-
${componentName}.__base__ = element
|
|
2774
|
-
${componentName}.__shouldForwardProps__ = shouldForwardProp
|
|
2775
|
-
|
|
2776
|
-
return ${componentName}
|
|
2777
|
-
}
|
|
2778
|
-
|
|
2779
|
-
function createJsxFactory() {
|
|
2780
|
-
const cache = new Map()
|
|
2781
|
-
|
|
2782
|
-
return new Proxy(styledFn, {
|
|
2783
|
-
apply(_, __, args) {
|
|
2784
|
-
return styledFn(...args)
|
|
2785
|
-
},
|
|
2786
|
-
get(_, el) {
|
|
2787
|
-
if (!cache.has(el)) {
|
|
2788
|
-
cache.set(el, styledFn(el))
|
|
2789
|
-
}
|
|
2790
|
-
return cache.get(el)
|
|
2791
|
-
},
|
|
2792
|
-
})
|
|
2793
|
-
}
|
|
2794
|
-
|
|
2795
|
-
export const ${factoryName} = /* @__PURE__ */ createJsxFactory()
|
|
2796
|
-
` };
|
|
2797
|
-
}
|
|
2798
|
-
//#endregion
|
|
2799
|
-
//#region src/artifacts/solid-jsx/pattern.ts
|
|
2800
|
-
function generateSolidJsxPattern(ctx, filters) {
|
|
2801
|
-
const { typeName, factoryName, styleProps: jsxStyleProps } = ctx.jsx;
|
|
2802
|
-
return ctx.patterns.filterDetails(filters).map((pattern) => {
|
|
2803
|
-
const { upperName, styleFnName, dashName, jsxName, props, blocklistType } = pattern;
|
|
2804
|
-
const { description, jsxElement = "div", deprecated } = pattern.config;
|
|
2805
|
-
return {
|
|
2806
|
-
name: dashName,
|
|
2807
|
-
js: outdent.outdent`
|
|
2808
|
-
import { createMemo, mergeProps, splitProps } from 'solid-js'
|
|
2809
|
-
import { createComponent } from 'solid-js/web'
|
|
2810
|
-
${jsxStyleProps === "minimal" ? ctx.file.import("mergeCss", "../css/css") : ""}
|
|
2811
|
-
${ctx.file.import(styleFnName, `../patterns/${dashName}`)}
|
|
2812
|
-
${ctx.file.import(factoryName, "./factory")}
|
|
2813
|
-
|
|
2814
|
-
export const ${jsxName} = /* @__PURE__ */ function ${jsxName}(props) {
|
|
2815
|
-
${(0, ts_pattern.match)(jsxStyleProps).with("none", () => outdent.outdent`
|
|
2816
|
-
const [patternProps, restProps] = splitProps(props, ${JSON.stringify(props)})
|
|
2817
|
-
|
|
2818
|
-
const cssProps = createMemo(() => {
|
|
2819
|
-
const styleProps = ${styleFnName}(patternProps)
|
|
2820
|
-
return { css: styleProps }
|
|
2821
|
-
})
|
|
2822
|
-
|
|
2823
|
-
const mergedProps = mergeProps(restProps, cssProps)
|
|
2824
|
-
|
|
2825
|
-
return createComponent(${factoryName}.${jsxElement}, mergedProps)
|
|
2826
|
-
`).with("minimal", () => outdent.outdent`
|
|
2827
|
-
const [patternProps, restProps] = splitProps(props, ${JSON.stringify(props)})
|
|
2828
|
-
|
|
2829
|
-
const cssProps = createMemo(() => {
|
|
2830
|
-
const styleProps = ${styleFnName}(patternProps)
|
|
2831
|
-
return { css: mergeCss(styleProps, props.css) }
|
|
2832
|
-
})
|
|
2833
|
-
|
|
2834
|
-
const mergedProps = mergeProps(restProps, cssProps)
|
|
2835
|
-
|
|
2836
|
-
return createComponent(${factoryName}.${jsxElement}, mergedProps)
|
|
2837
|
-
`).with("all", () => outdent.outdent`
|
|
2838
|
-
const [patternProps, restProps] = splitProps(props, ${JSON.stringify(props)})
|
|
2839
|
-
|
|
2840
|
-
const styleProps = ${styleFnName}(patternProps)
|
|
2841
|
-
const mergedProps = mergeProps(styleProps, restProps)
|
|
2842
|
-
|
|
2843
|
-
return createComponent(${factoryName}.${jsxElement}, mergedProps)
|
|
2844
|
-
`).exhaustive()}
|
|
2845
|
-
}
|
|
2846
|
-
`,
|
|
2847
|
-
dts: outdent.outdent`
|
|
2848
|
-
import type { Component } from 'solid-js'
|
|
2849
|
-
${ctx.file.importType(`${upperName}Properties`, `../patterns/${dashName}`)}
|
|
2850
|
-
${ctx.file.importType(typeName, "../types/jsx")}
|
|
2851
|
-
${ctx.file.importType("DistributiveOmit", "../types/system-types")}
|
|
2852
|
-
|
|
2853
|
-
export interface ${upperName}Props extends ${upperName}Properties, DistributiveOmit<${typeName}<'${jsxElement}'>, keyof ${upperName}Properties ${blocklistType}> {}
|
|
2854
|
-
|
|
2855
|
-
${ctx.file.jsDocComment(description, { deprecated })}
|
|
2856
|
-
export declare const ${jsxName}: Component<${upperName}Props>
|
|
2857
|
-
`
|
|
2858
|
-
};
|
|
2859
|
-
});
|
|
2860
|
-
}
|
|
2861
|
-
//#endregion
|
|
2862
|
-
//#region src/artifacts/solid-jsx/types.ts
|
|
2863
|
-
function generateSolidJsxTypes(ctx) {
|
|
2864
|
-
const { factoryName, componentName, upperName, typeName, variantName } = ctx.jsx;
|
|
2865
|
-
return {
|
|
2866
|
-
jsxFactory: outdent.outdent`
|
|
2867
|
-
${ctx.file.importType(upperName, "../types/jsx")}
|
|
2868
|
-
export declare const ${factoryName}: ${upperName}
|
|
2869
|
-
`,
|
|
2870
|
-
jsxType: outdent.outdent`
|
|
2871
|
-
import type { Accessor, ComponentProps, Component, JSX } from 'solid-js'
|
|
2872
|
-
${ctx.file.importType("RecipeDefinition, RecipeSelection, RecipeVariantRecord", "./recipe")}
|
|
2873
|
-
${ctx.file.importType("Assign, DistributiveUnion, JsxHTMLProps, JsxStyleProps, Pretty", "./system-types")}
|
|
2874
|
-
|
|
2875
|
-
interface Dict {
|
|
2876
|
-
[k: string]: unknown
|
|
2877
|
-
}
|
|
2878
|
-
|
|
2879
|
-
export type DataAttrs = Record<\`data-\${string}\`, unknown>
|
|
2880
|
-
|
|
2881
|
-
export interface UnstyledProps {
|
|
2882
|
-
/**
|
|
2883
|
-
* Whether to remove recipe styles
|
|
2884
|
-
*/
|
|
2885
|
-
unstyled?: boolean | undefined
|
|
2886
|
-
}
|
|
2887
|
-
|
|
2888
|
-
export interface AsProps {
|
|
2889
|
-
/**
|
|
2890
|
-
* The element to render as
|
|
2891
|
-
*/
|
|
2892
|
-
as?: ElementType | undefined
|
|
2893
|
-
}
|
|
2894
|
-
|
|
2895
|
-
export type ElementType = keyof JSX.IntrinsicElements | Component<any>
|
|
2896
|
-
|
|
2897
|
-
export interface ${componentName}<T extends ElementType, P extends Dict = {}> {
|
|
2898
|
-
(props: JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps, Assign<JsxStyleProps, P>>): JSX.Element
|
|
2899
|
-
displayName?: string | undefined
|
|
2900
|
-
}
|
|
2901
|
-
|
|
2902
|
-
interface RecipeFn {
|
|
2903
|
-
__type: any
|
|
2904
|
-
}
|
|
2905
|
-
|
|
2906
|
-
export type MaybeAccessor<T> = T | Accessor<T>
|
|
2907
|
-
|
|
2908
|
-
export interface JsxFactoryOptions<TProps extends Dict> {
|
|
2909
|
-
dataAttr?: boolean
|
|
2910
|
-
defaultProps?: MaybeAccessor<Partial<TProps> & DataAttrs>
|
|
2911
|
-
shouldForwardProp?: (prop: string, variantKeys: string[]) => boolean
|
|
2912
|
-
forwardProps?: string[]
|
|
2913
|
-
}
|
|
2914
|
-
|
|
2915
|
-
export type JsxRecipeProps<T extends ElementType, P extends Dict> = JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps, P>;
|
|
2916
|
-
|
|
2917
|
-
export type JsxElement<T extends ElementType, P extends Dict> = T extends ${componentName}<infer A, infer B>
|
|
2918
|
-
? ${componentName}<A, Pretty<DistributiveUnion<P, B>>>
|
|
2919
|
-
: ${componentName}<T, P>
|
|
2920
|
-
|
|
2921
|
-
export interface JsxFactory {
|
|
2922
|
-
<T extends ElementType>(component: T): ${componentName}<T, {}>
|
|
2923
|
-
<T extends ElementType, P extends RecipeVariantRecord>(component: T, recipe: RecipeDefinition<P>, options?: JsxFactoryOptions<JsxRecipeProps<T, RecipeSelection<P>>>): JsxElement<
|
|
2924
|
-
T,
|
|
2925
|
-
RecipeSelection<P>
|
|
2926
|
-
>
|
|
2927
|
-
<T extends ElementType, P extends RecipeFn>(component: T, recipeFn: P, options?: JsxFactoryOptions<JsxRecipeProps<T, P['__type']>>): JsxElement<T, P['__type']>
|
|
2928
|
-
}
|
|
2929
|
-
|
|
2930
|
-
export type JsxElements = {
|
|
2931
|
-
[K in keyof JSX.IntrinsicElements]: ${componentName}<K, {}>
|
|
2932
|
-
}
|
|
2933
|
-
|
|
2934
|
-
export type ${upperName} = JsxFactory & JsxElements
|
|
2935
|
-
|
|
2936
|
-
export type ${typeName}<T extends ElementType> = JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps, JsxStyleProps>
|
|
2937
|
-
|
|
2938
|
-
export type ${variantName}<T extends ${componentName}<any, any>> = T extends ${componentName}<any, infer Props> ? Props : never
|
|
2939
|
-
`
|
|
2940
|
-
};
|
|
2941
|
-
}
|
|
2942
|
-
//#endregion
|
|
2943
|
-
//#region src/artifacts/solid-jsx/create-style-context.ts
|
|
2944
|
-
function generateSolidCreateStyleContext(ctx) {
|
|
2945
|
-
const { factoryName } = ctx.jsx;
|
|
2946
|
-
return {
|
|
2947
|
-
js: outdent.outdent`
|
|
2948
|
-
${ctx.file.import("cx, css, sva", "../css/index")}
|
|
2949
|
-
${ctx.file.import(factoryName, "./factory")}
|
|
2950
|
-
${ctx.file.import("getDisplayName", "./factory-helper")}
|
|
2951
|
-
import { createComponent, mergeProps } from 'solid-js/web'
|
|
2952
|
-
import { createContext, createMemo, splitProps, useContext } from 'solid-js'
|
|
2953
|
-
|
|
2954
|
-
function createSafeContext(contextName) {
|
|
2955
|
-
const Context = createContext(undefined)
|
|
2956
|
-
const useStyleContext = (componentName, slot) => {
|
|
2957
|
-
const context = useContext(Context)
|
|
2958
|
-
if (context === undefined) {
|
|
2959
|
-
const componentInfo = componentName ? \`Component "\${componentName}"\` : 'A component'
|
|
2960
|
-
const slotInfo = slot ? \` (slot: "\${slot}")\` : ''
|
|
2961
|
-
|
|
2962
|
-
throw new Error(
|
|
2963
|
-
\`\${componentInfo}\${slotInfo} cannot access \${contextName} because it's missing its Provider.\`
|
|
2964
|
-
)
|
|
2965
|
-
}
|
|
2966
|
-
return context
|
|
2967
|
-
}
|
|
2968
|
-
return [Context, useStyleContext]
|
|
2969
|
-
}
|
|
2970
|
-
|
|
2971
|
-
export function createStyleContext(recipe) {
|
|
2972
|
-
const isConfigRecipe = '__recipe__' in recipe
|
|
2973
|
-
const recipeName = isConfigRecipe && recipe.__name__ ? recipe.__name__ : undefined
|
|
2974
|
-
const contextName = recipeName ? \`createStyleContext("\${recipeName}")\` : 'createStyleContext'
|
|
2975
|
-
|
|
2976
|
-
const [StyleContext, useStyleContext] = createSafeContext(contextName)
|
|
2977
|
-
const svaFn = isConfigRecipe ? recipe : sva(recipe.config)
|
|
2978
|
-
|
|
2979
|
-
const getResolvedProps = (props, slotStyles) => {
|
|
2980
|
-
const { unstyled, ...restProps } = props
|
|
2981
|
-
if (unstyled) return restProps
|
|
2982
|
-
if (isConfigRecipe) {
|
|
2983
|
-
return { ...restProps, class: cx(slotStyles, restProps.class) }
|
|
2984
|
-
}
|
|
2985
|
-
${outdent.outdent.string((0, ts_pattern.match)(ctx.config.jsxStyleProps).with("all", () => `return { ...slotStyles, ...restProps }`).with("minimal", () => `return { ...restProps, css: css.raw(slotStyles, restProps.css) }`).with("none", () => `return { ...restProps, class: cx(css(slotStyles), restProps.class) }`).otherwise(() => `return restProps`))}
|
|
2986
|
-
}
|
|
2987
|
-
|
|
2988
|
-
const withRootProvider = (Component, options) => {
|
|
2989
|
-
const WithRootProvider = (props) => {
|
|
2990
|
-
const [variantProps, otherProps] = svaFn.splitVariantProps(props)
|
|
2991
|
-
const [local, propsWithoutChildren] = splitProps(otherProps, ['children'])
|
|
2992
|
-
|
|
2993
|
-
const slotStyles = createMemo(() => {
|
|
2994
|
-
const styles = isConfigRecipe ? svaFn(variantProps) : svaFn.raw(variantProps)
|
|
2995
|
-
styles._classNameMap = svaFn.classNameMap
|
|
2996
|
-
return styles
|
|
2997
|
-
})
|
|
2998
|
-
|
|
2999
|
-
const mergedProps = createMemo(() => {
|
|
3000
|
-
if (!options?.defaultProps) return propsWithoutChildren
|
|
3001
|
-
const defaults = typeof options.defaultProps === 'function'
|
|
3002
|
-
? options.defaultProps()
|
|
3003
|
-
: options.defaultProps
|
|
3004
|
-
return { ...defaults, ...propsWithoutChildren }
|
|
3005
|
-
})
|
|
3006
|
-
|
|
3007
|
-
return createComponent(StyleContext.Provider, {
|
|
3008
|
-
get value() {
|
|
3009
|
-
return slotStyles()
|
|
3010
|
-
},
|
|
3011
|
-
get children() {
|
|
3012
|
-
return createComponent(
|
|
3013
|
-
Component,
|
|
3014
|
-
mergeProps(mergedProps, {
|
|
3015
|
-
get children() {
|
|
3016
|
-
return local.children
|
|
3017
|
-
},
|
|
3018
|
-
}),
|
|
3019
|
-
)
|
|
3020
|
-
},
|
|
3021
|
-
})
|
|
3022
|
-
}
|
|
3023
|
-
|
|
3024
|
-
const componentName = getDisplayName(Component)
|
|
3025
|
-
WithRootProvider.displayName = \`withRootProvider(\${componentName})\`
|
|
3026
|
-
return WithRootProvider
|
|
3027
|
-
}
|
|
3028
|
-
|
|
3029
|
-
const withProvider = (Component, slot, options) => {
|
|
3030
|
-
const StyledComponent = ${factoryName}(Component, {}, options)
|
|
3031
|
-
|
|
3032
|
-
const WithProvider = (props) => {
|
|
3033
|
-
const [variantProps, restProps] = svaFn.splitVariantProps(props)
|
|
3034
|
-
const [local, propsWithoutChildren] = splitProps(restProps, ["children"])
|
|
3035
|
-
|
|
3036
|
-
const slotStyles = createMemo(() => {
|
|
3037
|
-
const styles = isConfigRecipe ? svaFn(variantProps) : svaFn.raw(variantProps)
|
|
3038
|
-
styles._classNameMap = svaFn.classNameMap
|
|
3039
|
-
return styles
|
|
3040
|
-
})
|
|
3041
|
-
|
|
3042
|
-
const resolvedProps = createMemo(() => {
|
|
3043
|
-
const propsWithClass = {
|
|
3044
|
-
...propsWithoutChildren,
|
|
3045
|
-
class: propsWithoutChildren.class ?? options?.defaultProps?.class,
|
|
3046
|
-
}
|
|
3047
|
-
const resolved = getResolvedProps(propsWithClass, slotStyles()[slot])
|
|
3048
|
-
resolved.class = cx(resolved.class, slotStyles()._classNameMap[slot])
|
|
3049
|
-
return resolved
|
|
3050
|
-
})
|
|
3051
|
-
|
|
3052
|
-
return createComponent(StyleContext.Provider, {
|
|
3053
|
-
get value() {
|
|
3054
|
-
return slotStyles()
|
|
3055
|
-
},
|
|
3056
|
-
get children() {
|
|
3057
|
-
return createComponent(
|
|
3058
|
-
StyledComponent,
|
|
3059
|
-
mergeProps(resolvedProps, {
|
|
3060
|
-
get children() {
|
|
3061
|
-
return local.children
|
|
3062
|
-
},
|
|
3063
|
-
})
|
|
3064
|
-
)
|
|
3065
|
-
},
|
|
3066
|
-
})
|
|
3067
|
-
}
|
|
3068
|
-
|
|
3069
|
-
const componentName = getDisplayName(Component)
|
|
3070
|
-
WithProvider.displayName = \`withProvider(\${componentName})\`
|
|
3071
|
-
return WithProvider
|
|
3072
|
-
}
|
|
3073
|
-
|
|
3074
|
-
const withContext = (Component, slot, options) => {
|
|
3075
|
-
const StyledComponent = ${factoryName}(Component, {}, options)
|
|
3076
|
-
const componentName = getDisplayName(Component)
|
|
3077
|
-
|
|
3078
|
-
const WithContext = (props) => {
|
|
3079
|
-
const slotStyles = useStyleContext(componentName, slot)
|
|
3080
|
-
const [local, propsWithoutChildren] = splitProps(props, ["children"])
|
|
3081
|
-
|
|
3082
|
-
const resolvedProps = createMemo(() => {
|
|
3083
|
-
const propsWithClass = {
|
|
3084
|
-
...propsWithoutChildren,
|
|
3085
|
-
class: propsWithoutChildren.class ?? options?.defaultProps?.class,
|
|
3086
|
-
}
|
|
3087
|
-
const resolved = getResolvedProps(propsWithClass, slotStyles[slot])
|
|
3088
|
-
resolved.class = cx(resolved.class, slotStyles._classNameMap?.[slot])
|
|
3089
|
-
return resolved
|
|
3090
|
-
})
|
|
3091
|
-
|
|
3092
|
-
return createComponent(
|
|
3093
|
-
StyledComponent,
|
|
3094
|
-
mergeProps(resolvedProps, {
|
|
3095
|
-
get children() {
|
|
3096
|
-
return local.children
|
|
3097
|
-
},
|
|
3098
|
-
})
|
|
3099
|
-
)
|
|
3100
|
-
}
|
|
3101
|
-
|
|
3102
|
-
WithContext.displayName = \`withContext(\${componentName})\`
|
|
3103
|
-
return WithContext
|
|
3104
|
-
}
|
|
3105
|
-
|
|
3106
|
-
return {
|
|
3107
|
-
withRootProvider,
|
|
3108
|
-
withProvider,
|
|
3109
|
-
withContext,
|
|
3110
|
-
}
|
|
3111
|
-
}
|
|
3112
|
-
`,
|
|
3113
|
-
dts: outdent.outdent`
|
|
3114
|
-
${ctx.file.importType("SlotRecipeRuntimeFn, RecipeVariantProps", "../types/recipe")}
|
|
3115
|
-
${ctx.file.importType("JsxHTMLProps, JsxStyleProps, Assign", "../types/system-types")}
|
|
3116
|
-
${ctx.file.importType("JsxFactoryOptions, DataAttrs, MaybeAccessor, AsProps", "../types/jsx")}
|
|
3117
|
-
import type { Component, JSX, ComponentProps } from 'solid-js'
|
|
3118
|
-
|
|
3119
|
-
interface UnstyledProps {
|
|
3120
|
-
unstyled?: boolean | undefined
|
|
3121
|
-
}
|
|
3122
|
-
|
|
3123
|
-
interface WithProviderOptions<P> {
|
|
3124
|
-
defaultProps?: MaybeAccessor<Partial<P> & DataAttrs> | undefined
|
|
3125
|
-
}
|
|
3126
|
-
|
|
3127
|
-
type ElementType = keyof JSX.IntrinsicElements | Component<any>
|
|
3128
|
-
|
|
3129
|
-
type SvaFn<S extends string = any> = SlotRecipeRuntimeFn<S, any>
|
|
3130
|
-
interface SlotRecipeFn {
|
|
3131
|
-
__type: any
|
|
3132
|
-
__slot: string
|
|
3133
|
-
(props?: any): any
|
|
3134
|
-
}
|
|
3135
|
-
type SlotRecipe = SvaFn | SlotRecipeFn
|
|
3136
|
-
|
|
3137
|
-
type InferSlot<R extends SlotRecipe> = R extends SlotRecipeFn
|
|
3138
|
-
? R['__slot']
|
|
3139
|
-
: R extends SvaFn<infer S>
|
|
3140
|
-
? S
|
|
3141
|
-
: never
|
|
3142
|
-
|
|
3143
|
-
type StyleContextProvider<T extends ElementType, R extends SlotRecipe> = Component<
|
|
3144
|
-
JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps, Assign<RecipeVariantProps<R>, JsxStyleProps>>
|
|
3145
|
-
>
|
|
3146
|
-
|
|
3147
|
-
type StyleContextRootProvider<T extends ElementType, R extends SlotRecipe> = Component<
|
|
3148
|
-
ComponentProps<T> & UnstyledProps & RecipeVariantProps<R>
|
|
3149
|
-
>
|
|
3150
|
-
|
|
3151
|
-
type StyleContextConsumer<T extends ElementType> = Component<
|
|
3152
|
-
JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps, JsxStyleProps>
|
|
3153
|
-
>
|
|
3154
|
-
|
|
3155
|
-
export interface StyleContext<R extends SlotRecipe> {
|
|
3156
|
-
withRootProvider: <T extends ElementType>(
|
|
3157
|
-
Component: T,
|
|
3158
|
-
options?: WithProviderOptions<ComponentProps<T>> | undefined
|
|
3159
|
-
) => StyleContextRootProvider<T, R>
|
|
3160
|
-
withProvider: <T extends ElementType>(
|
|
3161
|
-
Component: T,
|
|
3162
|
-
slot: InferSlot<R>,
|
|
3163
|
-
options?: JsxFactoryOptions<ComponentProps<T>> | undefined
|
|
3164
|
-
) => StyleContextProvider<T, R>
|
|
3165
|
-
withContext: <T extends ElementType>(
|
|
3166
|
-
Component: T,
|
|
3167
|
-
slot: InferSlot<R>,
|
|
3168
|
-
options?: JsxFactoryOptions<ComponentProps<T>> | undefined
|
|
3169
|
-
) => StyleContextConsumer<T>
|
|
3170
|
-
}
|
|
3171
|
-
|
|
3172
|
-
export declare function createStyleContext<R extends SlotRecipe>(recipe: R): StyleContext<R>
|
|
3173
|
-
`
|
|
3174
|
-
};
|
|
3175
|
-
}
|
|
3176
|
-
//#endregion
|
|
3177
|
-
//#region src/artifacts/solid-jsx/jsx.string-literal.ts
|
|
3178
|
-
function generateSolidJsxStringLiteralFactory(ctx) {
|
|
3179
|
-
const { componentName, factoryName } = ctx.jsx;
|
|
3180
|
-
return { js: outdent.outdent`
|
|
3181
|
-
import { mergeProps, splitProps } from 'solid-js'
|
|
3182
|
-
import { Dynamic, createComponent } from 'solid-js/web'
|
|
3183
|
-
${ctx.file.import("getDisplayName", "./factory-helper")}
|
|
3184
|
-
${ctx.file.import("css, cx", "../css/index")}
|
|
3185
|
-
|
|
3186
|
-
function createStyled(element) {
|
|
3187
|
-
const __base__ = element.__base__ || element
|
|
3188
|
-
return function styledFn(template) {
|
|
3189
|
-
const styles = css.raw(element.__styles__, template)
|
|
3190
|
-
|
|
3191
|
-
const ${componentName} = (props) => {
|
|
3192
|
-
const mergedProps = mergeProps({ as: __base__ }, props)
|
|
3193
|
-
const [localProps, elementProps] = splitProps(mergedProps, ['as', 'class'])
|
|
3194
|
-
|
|
3195
|
-
return createComponent(
|
|
3196
|
-
Dynamic,
|
|
3197
|
-
mergeProps(
|
|
3198
|
-
{
|
|
3199
|
-
get component() {
|
|
3200
|
-
return localProps.as
|
|
3201
|
-
},
|
|
3202
|
-
get class() {
|
|
3203
|
-
return cx(css(styles), localProps.class)
|
|
3204
|
-
},
|
|
3205
|
-
},
|
|
3206
|
-
elementProps,
|
|
3207
|
-
),
|
|
3208
|
-
)
|
|
3209
|
-
}
|
|
3210
|
-
|
|
3211
|
-
const name = getDisplayName(__base__)
|
|
3212
|
-
|
|
3213
|
-
${componentName}.displayName = \`${factoryName}.\${name}\`
|
|
3214
|
-
${componentName}.__styles__ = styles
|
|
3215
|
-
${componentName}.__base__ = __base__
|
|
3216
|
-
|
|
3217
|
-
return ${componentName}
|
|
3218
|
-
}
|
|
3219
|
-
}
|
|
3220
|
-
|
|
3221
|
-
function createJsxFactory() {
|
|
3222
|
-
const cache = new Map()
|
|
3223
|
-
|
|
3224
|
-
return new Proxy(createStyled, {
|
|
3225
|
-
apply(_, __, args) {
|
|
3226
|
-
return createStyled(...args)
|
|
3227
|
-
},
|
|
3228
|
-
get(_, el) {
|
|
3229
|
-
if (!cache.has(el)) {
|
|
3230
|
-
cache.set(el, createStyled(el))
|
|
3231
|
-
}
|
|
3232
|
-
return cache.get(el)
|
|
3233
|
-
},
|
|
3234
|
-
})
|
|
3235
|
-
}
|
|
3236
|
-
|
|
3237
|
-
export const ${factoryName} = /* @__PURE__ */ createJsxFactory()
|
|
3238
|
-
` };
|
|
3239
|
-
}
|
|
3240
|
-
//#endregion
|
|
3241
|
-
//#region src/artifacts/solid-jsx/types.string-literal.ts
|
|
3242
|
-
function generateSolidJsxStringLiteralTypes(ctx) {
|
|
3243
|
-
const { factoryName, componentName, upperName, typeName } = ctx.jsx;
|
|
3244
|
-
return {
|
|
3245
|
-
jsxFactory: outdent.outdent`
|
|
3246
|
-
${ctx.file.importType(upperName, "../types/jsx")}
|
|
3247
|
-
export declare const ${factoryName}: ${upperName}
|
|
3248
|
-
`,
|
|
3249
|
-
jsxType: outdent.outdent`
|
|
3250
|
-
import type { Component, ComponentProps, JSX } from 'solid-js'
|
|
3251
|
-
|
|
3252
|
-
interface Dict {
|
|
3253
|
-
[k: string]: unknown
|
|
3254
|
-
}
|
|
3255
|
-
|
|
3256
|
-
export interface AsProps {
|
|
3257
|
-
/**
|
|
3258
|
-
* The element to render as
|
|
3259
|
-
*/
|
|
3260
|
-
as?: ElementType | undefined
|
|
3261
|
-
}
|
|
3262
|
-
|
|
3263
|
-
export type ElementType<P = any> = keyof JSX.IntrinsicElements | Component<P>
|
|
3264
|
-
|
|
3265
|
-
export type ${componentName}<T extends ElementType> = {
|
|
3266
|
-
(args: { raw: readonly string[] | ArrayLike<string> }): (props: ComponentProps<T> & AsProps) => JSX.Element
|
|
3267
|
-
displayName?: string | undefined
|
|
3268
|
-
}
|
|
3269
|
-
|
|
3270
|
-
export interface JsxFactory {
|
|
3271
|
-
<T extends ElementType>(component: T): ${componentName}<T>
|
|
3272
|
-
}
|
|
3273
|
-
|
|
3274
|
-
export type JsxElements = {
|
|
3275
|
-
[K in keyof JSX.IntrinsicElements]: ${componentName}<K>
|
|
3276
|
-
}
|
|
3277
|
-
|
|
3278
|
-
export type ${upperName} = JsxFactory & JsxElements
|
|
3279
|
-
|
|
3280
|
-
export type ${typeName}<T extends ElementType> = ComponentProps<T>
|
|
3281
|
-
`
|
|
3282
|
-
};
|
|
3283
|
-
}
|
|
3284
|
-
//#endregion
|
|
3285
|
-
//#region src/artifacts/vue-jsx/jsx.ts
|
|
3286
|
-
function generateVueJsxFactory(ctx) {
|
|
3287
|
-
const { factoryName, componentName } = ctx.jsx;
|
|
3288
|
-
return { js: outdent.outdent`
|
|
3289
|
-
import { defineComponent, h, computed } from 'vue'
|
|
3290
|
-
${ctx.file.import("defaultShouldForwardProp, composeShouldForwardProps, composeCvaFn, getDisplayName", "./factory-helper")}
|
|
3291
|
-
${ctx.file.import("isCssProperty", "./is-valid-prop")}
|
|
3292
|
-
${ctx.file.import("css, cx, cva", "../css/index")}
|
|
3293
|
-
${ctx.file.import("splitProps, normalizeHTMLProps", "../helpers")}
|
|
3294
|
-
|
|
3295
|
-
function styledFn(Dynamic, configOrCva = {}, options = {}) {
|
|
3296
|
-
const cvaFn = configOrCva.__cva__ || configOrCva.__recipe__ ? configOrCva : cva(configOrCva)
|
|
3297
|
-
|
|
3298
|
-
const forwardFn = options.shouldForwardProp || defaultShouldForwardProp
|
|
3299
|
-
const shouldForwardProp = (prop) => {
|
|
3300
|
-
if (options.forwardProps?.includes(prop)) return true
|
|
3301
|
-
return forwardFn(prop, cvaFn.variantKeys)
|
|
3302
|
-
}
|
|
3303
|
-
|
|
3304
|
-
const defaultProps = Object.assign(
|
|
3305
|
-
options.dataAttr && configOrCva.__name__ ? { 'data-recipe': configOrCva.__name__ } : {},
|
|
3306
|
-
options.defaultProps,
|
|
3307
|
-
)
|
|
3308
|
-
|
|
3309
|
-
const __cvaFn__ = composeCvaFn(Dynamic.__cva__, cvaFn)
|
|
3310
|
-
const __shouldForwardProps__ = composeShouldForwardProps(Dynamic, shouldForwardProp)
|
|
3311
|
-
|
|
3312
|
-
const __base__ = Dynamic.__base__ || Dynamic
|
|
3313
|
-
const name = getDisplayName(__base__)
|
|
3314
|
-
|
|
3315
|
-
const ${componentName} = defineComponent({
|
|
3316
|
-
name: \`${factoryName}.\${name}\`,
|
|
3317
|
-
inheritAttrs: false,
|
|
3318
|
-
props: {
|
|
3319
|
-
modelValue: null,
|
|
3320
|
-
unstyled: { type: Boolean, default: false },
|
|
3321
|
-
as: { type: [String, Object], default: __base__ }
|
|
3322
|
-
},
|
|
3323
|
-
setup(props, { slots, attrs, emit }) {
|
|
3324
|
-
const combinedProps = computed(() => Object.assign({}, defaultProps, attrs))
|
|
3325
|
-
|
|
3326
|
-
const splittedProps = computed(() => {
|
|
3327
|
-
return splitProps(combinedProps.value, normalizeHTMLProps.keys, __shouldForwardProps__, __cvaFn__.variantKeys, isCssProperty)
|
|
3328
|
-
})
|
|
3329
|
-
|
|
3330
|
-
const recipeClass = computed(() => {
|
|
3331
|
-
const [_htmlProps, _forwardedProps, variantProps, styleProps, _elementProps] = splittedProps.value
|
|
3332
|
-
const { css: cssStyles, ...propStyles } = styleProps
|
|
3333
|
-
const compoundVariantStyles = __cvaFn__.__getCompoundVariantCss__?.(variantProps);
|
|
3334
|
-
return cx(__cvaFn__(variantProps, false), css(compoundVariantStyles, propStyles, cssStyles), combinedProps.value.className, combinedProps.value.class)
|
|
3335
|
-
})
|
|
3336
|
-
|
|
3337
|
-
const cvaClass = computed(() => {
|
|
3338
|
-
const [_htmlProps, _forwardedProps, variantProps, styleProps, _elementProps] = splittedProps.value
|
|
3339
|
-
const { css: cssStyles, ...propStyles } = styleProps
|
|
3340
|
-
const cvaStyles = __cvaFn__.raw(variantProps)
|
|
3341
|
-
return cx(css(cvaStyles, propStyles, cssStyles), combinedProps.value.className, combinedProps.value.class)
|
|
3342
|
-
})
|
|
3343
|
-
|
|
3344
|
-
const classes = computed(() => {
|
|
3345
|
-
if (props.unstyled) {
|
|
3346
|
-
const [_htmlProps, _forwardedProps, _variantProps, styleProps, _elementProps] = splittedProps.value
|
|
3347
|
-
const { css: cssStyles, ...propStyles } = styleProps
|
|
3348
|
-
return cx(css(propStyles, cssStyles), combinedProps.value.className, combinedProps.value.class)
|
|
3349
|
-
}
|
|
3350
|
-
return configOrCva.__recipe__ ? recipeClass.value : cvaClass.value
|
|
3351
|
-
})
|
|
3352
|
-
|
|
3353
|
-
const vModelProps = computed(() => {
|
|
3354
|
-
const result = {};
|
|
3355
|
-
|
|
3356
|
-
if (
|
|
3357
|
-
props.as === 'input' &&
|
|
3358
|
-
(props.type === 'checkbox' || props.type === 'radio')
|
|
3359
|
-
) {
|
|
3360
|
-
result.checked = props.modelValue;
|
|
3361
|
-
result.onChange = (event) => {
|
|
3362
|
-
const checked = !event.currentTarget.checked;
|
|
3363
|
-
emit('change', checked, event);
|
|
3364
|
-
emit('update:modelValue', checked, event);
|
|
3365
|
-
};
|
|
3366
|
-
} else if (
|
|
3367
|
-
props.as === 'input' ||
|
|
3368
|
-
props.as === 'textarea' ||
|
|
3369
|
-
props.as === 'select'
|
|
3370
|
-
) {
|
|
3371
|
-
result.value = props.modelValue;
|
|
3372
|
-
result.onInput = (event) => {
|
|
3373
|
-
const value = event.currentTarget.value;
|
|
3374
|
-
emit('input', value, event);
|
|
3375
|
-
emit('update:modelValue', value, event);
|
|
3376
|
-
};
|
|
3377
|
-
}
|
|
3378
|
-
|
|
3379
|
-
return result;
|
|
3380
|
-
});
|
|
3381
|
-
|
|
3382
|
-
return () => {
|
|
3383
|
-
const [htmlProps, forwardedProps, _variantProps, _styleProps, elementProps] = splittedProps.value
|
|
3384
|
-
|
|
3385
|
-
return h(
|
|
3386
|
-
props.as,
|
|
3387
|
-
{
|
|
3388
|
-
...forwardedProps,
|
|
3389
|
-
...elementProps,
|
|
3390
|
-
...normalizeHTMLProps(htmlProps),
|
|
3391
|
-
...vModelProps.value,
|
|
3392
|
-
class: classes.value,
|
|
3393
|
-
},
|
|
3394
|
-
slots,
|
|
3395
|
-
)
|
|
3396
|
-
}
|
|
3397
|
-
},
|
|
3398
|
-
})
|
|
3399
|
-
|
|
3400
|
-
${componentName}.displayName = \`${factoryName}.\${name}\`
|
|
3401
|
-
${componentName}.__cva__ = __cvaFn__
|
|
3402
|
-
${componentName}.__base__ = __base__
|
|
3403
|
-
${componentName}.__shouldForwardProps__ = shouldForwardProp
|
|
3404
|
-
|
|
3405
|
-
return ${componentName}
|
|
3406
|
-
}
|
|
3407
|
-
|
|
3408
|
-
const tags = 'a, abbr, address, area, article, aside, audio, b, base, bdi, bdo, big, blockquote, body, br, button, canvas, caption, cite, code, col, colgroup, data, datalist, dd, del, details, dfn, dialog, div, dl, dt, em, embed, fieldset, figcaption, figure, footer, form, h1, h2, h3, h4, h5, h6, head, header, hgroup, hr, html, i, iframe, img, input, ins, kbd, keygen, label, legend, li, link, main, map, mark, marquee, menu, menuitem, meta, meter, nav, noscript, object, ol, optgroup, option, output, p, param, picture, pre, progress, q, rp, rt, ruby, s, samp, script, section, select, small, source, span, strong, style, sub, summary, sup, table, tbody, td, textarea, tfoot, th, thead, time, title, tr, track, u, ul, var, video, wbr, circle, clipPath, defs, ellipse, foreignObject, g, image, line, linearGradient, mask, path, pattern, polygon, polyline, radialGradient, rect, stop, svg, text, tspan';
|
|
3409
|
-
|
|
3410
|
-
export const ${factoryName} = /* @__PURE__ */ styledFn.bind();
|
|
3411
|
-
|
|
3412
|
-
tags.split(', ').forEach((tag) => {
|
|
3413
|
-
${factoryName}[tag] = ${factoryName}(tag);
|
|
3414
|
-
});
|
|
3415
|
-
` };
|
|
3416
|
-
}
|
|
3417
|
-
//#endregion
|
|
3418
|
-
//#region src/artifacts/vue-jsx/pattern.ts
|
|
3419
|
-
function generateVueJsxPattern(ctx, filters) {
|
|
3420
|
-
const { typeName, factoryName, styleProps: jsxStyleProps } = ctx.jsx;
|
|
3421
|
-
return ctx.patterns.filterDetails(filters).map((pattern) => {
|
|
3422
|
-
const { upperName, styleFnName, dashName, jsxName, props, blocklistType } = pattern;
|
|
3423
|
-
const { description, jsxElement = "div", deprecated } = pattern.config;
|
|
3424
|
-
return {
|
|
3425
|
-
name: dashName,
|
|
3426
|
-
js: outdent.outdent`
|
|
3427
|
-
import { defineComponent, h, computed } from 'vue'
|
|
3428
|
-
${jsxStyleProps === "minimal" ? ctx.file.import("mergeCss", "../css/css") : ""}
|
|
3429
|
-
${ctx.file.import(styleFnName, `../patterns/${dashName}`)}
|
|
3430
|
-
${ctx.file.import(factoryName, "./factory")}
|
|
3431
|
-
|
|
3432
|
-
export const ${jsxName} = /* @__PURE__ */ defineComponent({
|
|
3433
|
-
name: '${jsxName}',
|
|
3434
|
-
inheritAttrs: false,
|
|
3435
|
-
props: ${JSON.stringify(props)},
|
|
3436
|
-
setup(props, { attrs, slots }) {
|
|
3437
|
-
${(0, ts_pattern.match)(jsxStyleProps).with("none", () => outdent.outdent`
|
|
3438
|
-
const cssProps = computed(() => {
|
|
3439
|
-
const styleProps = ${styleFnName}(props)
|
|
3440
|
-
return { css: styleProps }
|
|
3441
|
-
})
|
|
3442
|
-
|
|
3443
|
-
return () => {
|
|
3444
|
-
const mergedProps = { ...attrs, ...cssProps.value }
|
|
3445
|
-
return h(${factoryName}.${jsxElement}, mergedProps, slots)
|
|
3446
|
-
}
|
|
3447
|
-
`).with("minimal", () => outdent.outdent`
|
|
3448
|
-
const cssProps = computed(() => {
|
|
3449
|
-
const styleProps = ${styleFnName}(props)
|
|
3450
|
-
return { css: mergeCss(styleProps, attrs.css) }
|
|
3451
|
-
})
|
|
3452
|
-
|
|
3453
|
-
return () => {
|
|
3454
|
-
const mergedProps = { ...attrs, ...cssProps.value }
|
|
3455
|
-
return h(${factoryName}.${jsxElement}, mergedProps, slots)
|
|
3456
|
-
}
|
|
3457
|
-
`).with("all", () => outdent.outdent`
|
|
3458
|
-
const styleProps = computed(() => ${styleFnName}(props))
|
|
3459
|
-
|
|
3460
|
-
return () => {
|
|
3461
|
-
const mergedProps = { ...styleProps.value, ...attrs }
|
|
3462
|
-
return h(${factoryName}.${jsxElement}, mergedProps, slots)
|
|
3463
|
-
}
|
|
3464
|
-
`).exhaustive()}
|
|
3465
|
-
}
|
|
3466
|
-
})
|
|
3467
|
-
`,
|
|
3468
|
-
dts: outdent.outdent`
|
|
3469
|
-
import type { FunctionalComponent } from 'vue'
|
|
3470
|
-
${ctx.file.importType(`${upperName}Properties`, `../patterns/${dashName}`)}
|
|
3471
|
-
${ctx.file.importType(typeName, "../types/jsx")}
|
|
3472
|
-
${ctx.file.importType("DistributiveOmit", "../types/system-types")}
|
|
3473
|
-
|
|
3474
|
-
export interface ${upperName}Props extends ${upperName}Properties, DistributiveOmit<${typeName}<'${jsxElement}'>, keyof ${upperName}Properties ${blocklistType}> {}
|
|
3475
|
-
|
|
3476
|
-
${ctx.file.jsDocComment(description, { deprecated })}
|
|
3477
|
-
export declare const ${jsxName}: FunctionalComponent<${upperName}Props>
|
|
3478
|
-
`
|
|
3479
|
-
};
|
|
3480
|
-
});
|
|
3481
|
-
}
|
|
3482
|
-
//#endregion
|
|
3483
|
-
//#region src/artifacts/vue-jsx/types.ts
|
|
3484
|
-
function generateVueJsxTypes(ctx) {
|
|
3485
|
-
const { factoryName, componentName, upperName, typeName, variantName } = ctx.jsx;
|
|
3486
|
-
return {
|
|
3487
|
-
jsxFactory: outdent.outdent`
|
|
3488
|
-
${ctx.file.importType(upperName, "../types/jsx")}
|
|
3489
|
-
|
|
3490
|
-
export declare const ${factoryName}: ${upperName}
|
|
3491
|
-
`,
|
|
3492
|
-
jsxType: outdent.outdent`
|
|
3493
|
-
import type { Component, FunctionalComponent, NativeElements } from 'vue'
|
|
3494
|
-
|
|
3495
|
-
${ctx.file.importType("RecipeDefinition, RecipeSelection, RecipeVariantRecord", "./recipe")}
|
|
3496
|
-
${ctx.file.importType("Assign, DistributiveOmit, DistributiveUnion, JsxHTMLProps, JsxStyleProps, Pretty", "./system-types")}
|
|
3497
|
-
|
|
3498
|
-
export type IntrinsicElement = keyof NativeElements
|
|
3499
|
-
|
|
3500
|
-
export type ElementType = IntrinsicElement | Component
|
|
3501
|
-
|
|
3502
|
-
export type ComponentProps<T extends ElementType> = T extends IntrinsicElement
|
|
3503
|
-
? NativeElements[T]
|
|
3504
|
-
: T extends Component<infer Props>
|
|
3505
|
-
? Props
|
|
3506
|
-
: never
|
|
3507
|
-
|
|
3508
|
-
interface Dict {
|
|
3509
|
-
[k: string]: unknown
|
|
3510
|
-
}
|
|
3511
|
-
|
|
3512
|
-
export type DataAttrs = Record<\`data-\${string}\`, unknown>
|
|
937
|
+
// The slots that enclose other slots, matching \`Recipes.getScopeRoots\`. Their variant
|
|
938
|
+
// styles anchor \`@scope\` rules for every other slot, so only they take variants — a
|
|
939
|
+
// variant class on any other slot would name a rule that was never emitted.
|
|
940
|
+
//
|
|
941
|
+
// A list, because a component can span a portal and so occupy more than one subtree.
|
|
942
|
+
const declaredSlots = config.slots ?? []
|
|
943
|
+
const anchors = config.scopeRoots
|
|
944
|
+
? config.scopeRoots.filter((slot) => declaredSlots.includes(slot))
|
|
945
|
+
: declaredSlots.includes('root') ? ['root'] : []
|
|
946
|
+
|
|
947
|
+
// \`classNameMap[slot]\` used to be joined on here, because the slot's classes were
|
|
948
|
+
// atomic and nothing else carried the name to target it in the DOM. The slot's cva is
|
|
949
|
+
// now named \`name__slot\` and returns that as its base class, so joining it again
|
|
950
|
+
// would just repeat it.
|
|
951
|
+
function svaFn(props) {
|
|
952
|
+
const result = slots.map(([slot, cvaFn]) => [
|
|
953
|
+
slot,
|
|
954
|
+
anchors.length && !anchors.includes(slot) ? cvaFn.config.className : cvaFn(props),
|
|
955
|
+
])
|
|
956
|
+
return Object.fromEntries(result)
|
|
957
|
+
}
|
|
3513
958
|
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
unstyled?: boolean | undefined
|
|
3519
|
-
}
|
|
959
|
+
function raw(props) {
|
|
960
|
+
const result = slots.map(([slot, cvaFn]) => [slot, cvaFn.raw(props)])
|
|
961
|
+
return Object.fromEntries(result)
|
|
962
|
+
}
|
|
3520
963
|
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
* The element to render as
|
|
3524
|
-
*/
|
|
3525
|
-
as?: ElementType | undefined
|
|
3526
|
-
}
|
|
964
|
+
const variants = config.variants ?? {};
|
|
965
|
+
const variantKeys = Object.keys(variants);
|
|
3527
966
|
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
967
|
+
function splitVariantProps(props) {
|
|
968
|
+
return splitProps(props, variantKeys);
|
|
969
|
+
}
|
|
970
|
+
const getVariantProps = (variants) => ({ ...defaultVariants, ...compact(variants) })
|
|
3531
971
|
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
972
|
+
const variantMap = Object.fromEntries(
|
|
973
|
+
Object.entries(variants).map(([key, value]) => [key, Object.keys(value)])
|
|
974
|
+
);
|
|
3535
975
|
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
976
|
+
// Which slots each variant writes styles for.
|
|
977
|
+
//
|
|
978
|
+
// A scope reaches every slot inside an anchor's subtree. A slot under no anchor is
|
|
979
|
+
// not reached, and nothing at build time can detect that — reachability is a fact
|
|
980
|
+
// about the DOM. This is what says which slots a variant has to get to, so the
|
|
981
|
+
// component layer can thread the ones a scope cannot. Config slot recipes have always
|
|
982
|
+
// exposed it; an inline \`sva\` had no way to answer the question at all.
|
|
983
|
+
const slotsAffectedBy = Object.fromEntries(
|
|
984
|
+
Object.entries(variants).map(([variant, values]) => [
|
|
985
|
+
variant,
|
|
986
|
+
[...new Set(Object.values(values ?? {}).flatMap((slotStyles) => Object.keys(slotStyles ?? {})))],
|
|
987
|
+
])
|
|
988
|
+
);
|
|
3542
989
|
|
|
3543
|
-
|
|
990
|
+
return Object.assign(memo(svaFn), {
|
|
991
|
+
__cva__: false,
|
|
992
|
+
raw,
|
|
993
|
+
config,
|
|
994
|
+
variantMap,
|
|
995
|
+
variantKeys,
|
|
996
|
+
classNameMap,
|
|
997
|
+
/** The slots that enclose other slots, and so anchor their variant rules. */
|
|
998
|
+
scopeRoots: anchors,
|
|
999
|
+
slotsAffectedBy,
|
|
1000
|
+
splitVariantProps,
|
|
1001
|
+
getVariantProps,
|
|
1002
|
+
})
|
|
1003
|
+
}
|
|
3544
1004
|
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
1005
|
+
/**
|
|
1006
|
+
* Report slots whose variant styles can never reach them.
|
|
1007
|
+
*
|
|
1008
|
+
* A scoped slot is styled through an \`@scope\` rule opened at an anchor, so it has to be
|
|
1009
|
+
* rendered inside one. A slot moved out of every anchor's subtree — through a portal,
|
|
1010
|
+
* with no second anchor named in \`scopeRoots\` — keeps its base styles and silently
|
|
1011
|
+
* loses its variant styles. That renders *nearly* right, which is harder to notice than
|
|
1012
|
+
* a total failure, and no build step can catch it: whether one element is inside another
|
|
1013
|
+
* is a fact about the DOM.
|
|
1014
|
+
*
|
|
1015
|
+
* Checks for the anchor's *base* class rather than its variant class. An anchor always
|
|
1016
|
+
* carries the base one; the variant class is absent whenever no variant is selected, and
|
|
1017
|
+
* matching on it would report a slot that is correctly placed and simply unstyled.
|
|
1018
|
+
*
|
|
1019
|
+
* Development only — call it behind \`process.env.NODE_ENV !== 'production'\` so bundlers
|
|
1020
|
+
* drop it, along with this function, from your production build.
|
|
1021
|
+
*
|
|
1022
|
+
* \`\`\`js
|
|
1023
|
+
* import { auditSlotScopes, select } from '../styled-system/css'
|
|
1024
|
+
*
|
|
1025
|
+
* if (process.env.NODE_ENV !== 'production') auditSlotScopes([select], { observe: true })
|
|
1026
|
+
* \`\`\`
|
|
1027
|
+
*/
|
|
1028
|
+
export function auditSlotScopes(recipes, options = {}) {
|
|
1029
|
+
const { root = typeof document === 'undefined' ? undefined : document, observe = false, onReport } = options
|
|
1030
|
+
if (!root) return () => {}
|
|
3548
1031
|
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
<T extends ElementType, P extends RecipeVariantRecord>(component: T, recipe: RecipeDefinition<P>, options?: JsxFactoryOptions<JsxRecipeProps<T, RecipeSelection<P>>>): JsxElement<
|
|
3552
|
-
T,
|
|
3553
|
-
RecipeSelection<P>
|
|
3554
|
-
>
|
|
3555
|
-
<T extends ElementType, P extends RecipeFn>(component: T, recipeFn: P, options?: JsxFactoryOptions<JsxRecipeProps<T, P['__type']>> ): JsxElement<T, P['__type']>
|
|
3556
|
-
}
|
|
1032
|
+
const escape = (value) =>
|
|
1033
|
+
typeof CSS !== 'undefined' && CSS.escape ? CSS.escape(value) : value.replace(/[^\\w-]/g, '\\\\$&')
|
|
3557
1034
|
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
}
|
|
1035
|
+
const audit = () => {
|
|
1036
|
+
const found = []
|
|
3561
1037
|
|
|
3562
|
-
|
|
1038
|
+
for (const recipe of recipes) {
|
|
1039
|
+
const anchors = recipe?.scopeRoots ?? []
|
|
1040
|
+
// Nothing is scoped, so every slot carries its own variant class and none of them
|
|
1041
|
+
// depends on where it is rendered.
|
|
1042
|
+
if (!anchors.length) continue
|
|
3563
1043
|
|
|
3564
|
-
|
|
1044
|
+
const classNameMap = recipe.classNameMap ?? {}
|
|
1045
|
+
const anchorSelector = anchors
|
|
1046
|
+
.map((slot) => classNameMap[slot])
|
|
1047
|
+
.filter(Boolean)
|
|
1048
|
+
.map((className) => '.' + escape(className))
|
|
1049
|
+
.join(', ')
|
|
1050
|
+
if (!anchorSelector) continue
|
|
3565
1051
|
|
|
3566
|
-
|
|
3567
|
-
`
|
|
3568
|
-
};
|
|
3569
|
-
}
|
|
3570
|
-
//#endregion
|
|
3571
|
-
//#region src/artifacts/vue-jsx/create-style-context.ts
|
|
3572
|
-
function generateVueCreateStyleContext(ctx) {
|
|
3573
|
-
const { factoryName } = ctx.jsx;
|
|
3574
|
-
return {
|
|
3575
|
-
js: outdent.outdent`
|
|
3576
|
-
${ctx.file.import("cx, css, sva", "../css/index")}
|
|
3577
|
-
${ctx.file.import(factoryName, "./factory")}
|
|
3578
|
-
${ctx.file.import("getDisplayName", "./factory-helper")}
|
|
3579
|
-
import { defineComponent, provide, inject, computed, h } from 'vue'
|
|
3580
|
-
|
|
3581
|
-
export function createStyleContext(recipe) {
|
|
3582
|
-
const StyleContext = Symbol('StyleContext')
|
|
3583
|
-
const isConfigRecipe = '__recipe__' in recipe
|
|
3584
|
-
const recipeName = isConfigRecipe && recipe.__name__ ? recipe.__name__ : undefined
|
|
3585
|
-
const contextName = recipeName ? \`createStyleContext("\${recipeName}")\` : 'createStyleContext'
|
|
3586
|
-
const svaFn = isConfigRecipe ? recipe : sva(recipe.config)
|
|
3587
|
-
|
|
3588
|
-
function useStyleContext(componentName, slot) {
|
|
3589
|
-
const context = inject(StyleContext)
|
|
3590
|
-
if (context === undefined) {
|
|
3591
|
-
const componentInfo = componentName ? \`Component "\${componentName}"\` : 'A component'
|
|
3592
|
-
const slotInfo = slot ? \` (slot: "\${slot}")\` : ''
|
|
3593
|
-
|
|
3594
|
-
throw new Error(
|
|
3595
|
-
\`\${componentInfo}\${slotInfo} cannot access \${contextName} because it's missing its Provider.\`
|
|
3596
|
-
)
|
|
3597
|
-
}
|
|
3598
|
-
return context
|
|
3599
|
-
}
|
|
3600
|
-
|
|
3601
|
-
const getResolvedProps = (props, slotStyles) => {
|
|
3602
|
-
const { unstyled, ...restProps } = props
|
|
3603
|
-
if (unstyled) return restProps
|
|
3604
|
-
if (isConfigRecipe) {
|
|
3605
|
-
return { ...restProps, class: cx(slotStyles, restProps.class) }
|
|
3606
|
-
}
|
|
3607
|
-
${outdent.outdent.string((0, ts_pattern.match)(ctx.config.jsxStyleProps).with("all", () => `return { ...slotStyles, ...restProps }`).with("minimal", () => `return { ...restProps, css: css.raw(slotStyles, restProps.css) }`).with("none", () => `return { ...restProps, class: cx(css(slotStyles), restProps.class) }`).otherwise(() => `return restProps`))}
|
|
3608
|
-
}
|
|
1052
|
+
const scoped = new Set(Object.values(recipe.slotsAffectedBy ?? {}).flat())
|
|
3609
1053
|
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
props: svaFn.variantKeys,
|
|
3613
|
-
setup(props, { slots }) {
|
|
3614
|
-
const [variantProps, otherProps] = svaFn.splitVariantProps(props)
|
|
1054
|
+
for (const slot of scoped) {
|
|
1055
|
+
if (anchors.includes(slot)) continue
|
|
3615
1056
|
|
|
3616
|
-
const
|
|
3617
|
-
|
|
3618
|
-
styles._classNameMap = svaFn.classNameMap
|
|
3619
|
-
return styles
|
|
3620
|
-
})
|
|
1057
|
+
const className = classNameMap[slot]
|
|
1058
|
+
if (!className) continue
|
|
3621
1059
|
|
|
3622
|
-
|
|
1060
|
+
for (const element of root.querySelectorAll('.' + escape(className))) {
|
|
1061
|
+
if (element.closest(anchorSelector)) continue
|
|
1062
|
+
found.push({ recipe: recipe.__name__, slot, className, element, anchors })
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
3623
1066
|
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
1067
|
+
if (!found.length) return found
|
|
1068
|
+
|
|
1069
|
+
if (onReport) {
|
|
1070
|
+
onReport(found)
|
|
1071
|
+
} else {
|
|
1072
|
+
for (const problem of found) {
|
|
1073
|
+
console.warn(
|
|
1074
|
+
\`[bamboo] \${problem.recipe ?? 'slot recipe'}: the \\\`\${problem.slot}\\\` slot is rendered outside every \` +
|
|
1075
|
+
\`anchor (\${problem.anchors.join(', ')}), so its variant styles cannot reach it. \` +
|
|
1076
|
+
\`Add the enclosing slot to \\\`scopeRoots\\\`, or deliver the variant to this slot by hand.\`,
|
|
1077
|
+
problem.element,
|
|
1078
|
+
)
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
3628
1081
|
|
|
3629
|
-
|
|
3630
|
-
},
|
|
3631
|
-
})
|
|
3632
|
-
|
|
3633
|
-
const componentName = getDisplayName(Component)
|
|
3634
|
-
WithRootProvider.displayName = \`withRootProvider(\${componentName})\`
|
|
3635
|
-
|
|
3636
|
-
return WithRootProvider
|
|
1082
|
+
return found
|
|
3637
1083
|
}
|
|
3638
1084
|
|
|
3639
|
-
|
|
3640
|
-
const StyledComponent = ${factoryName}(Component, {}, options)
|
|
3641
|
-
|
|
3642
|
-
const WithProvider = defineComponent({
|
|
3643
|
-
props: ["unstyled", ...svaFn.variantKeys],
|
|
3644
|
-
inheritAttrs: false,
|
|
3645
|
-
setup(inProps, { slots, attrs }) {
|
|
3646
|
-
const props = computed(() => {
|
|
3647
|
-
const propsWithClass = { ...inProps, ...attrs }
|
|
3648
|
-
propsWithClass.class = propsWithClass.class ?? options?.defaultProps?.class
|
|
3649
|
-
return propsWithClass
|
|
3650
|
-
})
|
|
3651
|
-
const res = computed(() => {
|
|
3652
|
-
const [variantProps, restProps] = svaFn.splitVariantProps(props.value)
|
|
3653
|
-
return { variantProps, restProps }
|
|
3654
|
-
})
|
|
3655
|
-
|
|
3656
|
-
const slotStyles = computed(() => {
|
|
3657
|
-
const styles = isConfigRecipe ? svaFn(res.value.variantProps) : svaFn.raw(res.value.variantProps)
|
|
3658
|
-
styles._classNameMap = svaFn.classNameMap
|
|
3659
|
-
return styles
|
|
3660
|
-
})
|
|
3661
|
-
|
|
3662
|
-
provide(StyleContext, slotStyles)
|
|
3663
|
-
|
|
3664
|
-
return () => {
|
|
3665
|
-
const resolvedProps = getResolvedProps(res.value.restProps, slotStyles.value[slot])
|
|
3666
|
-
resolvedProps.class = cx(resolvedProps.class, slotStyles.value._classNameMap[slot], attrs.class)
|
|
3667
|
-
return h(StyledComponent, resolvedProps, slots)
|
|
3668
|
-
}
|
|
3669
|
-
},
|
|
3670
|
-
})
|
|
3671
|
-
|
|
3672
|
-
const componentName = getDisplayName(Component)
|
|
3673
|
-
WithProvider.displayName = \`withProvider(\${componentName})\`
|
|
3674
|
-
|
|
3675
|
-
return WithProvider
|
|
3676
|
-
}
|
|
1085
|
+
audit()
|
|
3677
1086
|
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
return propsWithClass
|
|
3690
|
-
})
|
|
3691
|
-
const slotStyles = useStyleContext(componentName, slot)
|
|
3692
|
-
|
|
3693
|
-
return () => {
|
|
3694
|
-
const resolvedProps = getResolvedProps(props.value, slotStyles.value[slot])
|
|
3695
|
-
resolvedProps.class = cx(resolvedProps.class, slotStyles.value._classNameMap[slot], attrs.class)
|
|
3696
|
-
return h(StyledComponent, resolvedProps, slots)
|
|
3697
|
-
}
|
|
3698
|
-
},
|
|
1087
|
+
if (!observe || typeof MutationObserver === 'undefined') return () => {}
|
|
1088
|
+
|
|
1089
|
+
// Portaled content mounts after the first sweep, which is exactly the case this
|
|
1090
|
+
// exists to catch, so a one-shot pass would miss it.
|
|
1091
|
+
let queued = false
|
|
1092
|
+
const observer = new MutationObserver(() => {
|
|
1093
|
+
if (queued) return
|
|
1094
|
+
queued = true
|
|
1095
|
+
queueMicrotask(() => {
|
|
1096
|
+
queued = false
|
|
1097
|
+
audit()
|
|
3699
1098
|
})
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
return WithContext
|
|
3704
|
-
}
|
|
1099
|
+
})
|
|
1100
|
+
observer.observe(root === document ? document.documentElement : root, { childList: true, subtree: true })
|
|
3705
1101
|
|
|
3706
|
-
return
|
|
3707
|
-
withRootProvider,
|
|
3708
|
-
withProvider,
|
|
3709
|
-
withContext,
|
|
3710
|
-
}
|
|
1102
|
+
return () => observer.disconnect()
|
|
3711
1103
|
}
|
|
3712
1104
|
`,
|
|
3713
1105
|
dts: outdent.outdent`
|
|
3714
|
-
${ctx.file.importType("
|
|
3715
|
-
${ctx.file.importType("JsxHTMLProps, JsxStyleProps, Assign", "../types/system-types")}
|
|
3716
|
-
${ctx.file.importType("JsxFactoryOptions, DataAttrs, AsProps", "../types/jsx")}
|
|
3717
|
-
import type { Component, FunctionalComponent, NativeElements } from 'vue'
|
|
3718
|
-
|
|
3719
|
-
interface UnstyledProps {
|
|
3720
|
-
unstyled?: boolean | undefined
|
|
3721
|
-
}
|
|
1106
|
+
${ctx.file.importType("SlotRecipeCreatorFn", "../types/recipe")}
|
|
3722
1107
|
|
|
3723
|
-
|
|
3724
|
-
defaultProps?: (Partial<P> & DataAttrs) | undefined
|
|
3725
|
-
}
|
|
1108
|
+
export declare const sva: SlotRecipeCreatorFn
|
|
3726
1109
|
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
1110
|
+
export interface SlotScopeProblem {
|
|
1111
|
+
/** The recipe the slot belongs to, when it has a name. */
|
|
1112
|
+
recipe?: string
|
|
1113
|
+
/** The slot whose variant styles cannot reach it. */
|
|
1114
|
+
slot: string
|
|
1115
|
+
/** The constant class that slot carries. */
|
|
1116
|
+
className: string
|
|
1117
|
+
/** The element found outside every anchor. */
|
|
1118
|
+
element: Element
|
|
1119
|
+
/** The anchors that were looked for. */
|
|
1120
|
+
anchors: string[]
|
|
3731
1121
|
}
|
|
3732
1122
|
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
type InferSlot<R extends SlotRecipe> = R extends SlotRecipeFn ? R['__slot'] : R extends SvaFn<infer S> ? S : never
|
|
3742
|
-
|
|
3743
|
-
type IntrinsicElement = keyof NativeElements
|
|
3744
|
-
type ElementType = IntrinsicElement | Component
|
|
3745
|
-
|
|
3746
|
-
type ComponentProps<T extends ElementType> = T extends IntrinsicElement
|
|
3747
|
-
? NativeElements[T]
|
|
3748
|
-
: T extends Component<infer Props>
|
|
3749
|
-
? Props
|
|
3750
|
-
: never
|
|
3751
|
-
|
|
3752
|
-
type StyleContextProvider<T extends ElementType, R extends SlotRecipe> = FunctionalComponent<
|
|
3753
|
-
JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps & VModelProps, Assign<RecipeVariantProps<R>, JsxStyleProps>>
|
|
3754
|
-
>
|
|
3755
|
-
|
|
3756
|
-
type StyleContextRootProvider<T extends ElementType, R extends SlotRecipe> = FunctionalComponent<
|
|
3757
|
-
ComponentProps<T> & UnstyledProps & VModelProps & RecipeVariantProps<R>
|
|
3758
|
-
>
|
|
3759
|
-
|
|
3760
|
-
type StyleContextConsumer<T extends ElementType> = FunctionalComponent<
|
|
3761
|
-
JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps & VModelProps, JsxStyleProps>
|
|
3762
|
-
>
|
|
3763
|
-
|
|
3764
|
-
export interface StyleContext<R extends SlotRecipe> {
|
|
3765
|
-
withRootProvider: <T extends ElementType>(
|
|
3766
|
-
Component: T,
|
|
3767
|
-
options?: WithProviderOptions<ComponentProps<T>> | undefined
|
|
3768
|
-
) => StyleContextRootProvider<T, R>
|
|
3769
|
-
withProvider: <T extends ElementType>(
|
|
3770
|
-
Component: T,
|
|
3771
|
-
slot: InferSlot<R>,
|
|
3772
|
-
options?: JsxFactoryOptions<ComponentProps<T>> | undefined
|
|
3773
|
-
) => StyleContextProvider<T, R>
|
|
3774
|
-
withContext: <T extends ElementType>(
|
|
3775
|
-
Component: T,
|
|
3776
|
-
slot: InferSlot<R>,
|
|
3777
|
-
options?: JsxFactoryOptions<ComponentProps<T>> | undefined
|
|
3778
|
-
) => StyleContextConsumer<T>
|
|
1123
|
+
export interface AuditSlotScopesOptions {
|
|
1124
|
+
/** Where to look. Defaults to \`document\`. */
|
|
1125
|
+
root?: ParentNode
|
|
1126
|
+
/** Re-check as the DOM changes, for content that mounts through a portal. */
|
|
1127
|
+
observe?: boolean
|
|
1128
|
+
/** Handle the findings yourself instead of warning to the console. */
|
|
1129
|
+
onReport?: (problems: SlotScopeProblem[]) => void
|
|
3779
1130
|
}
|
|
3780
1131
|
|
|
3781
|
-
|
|
1132
|
+
/**
|
|
1133
|
+
* Report slots whose variant styles can never reach them, in development.
|
|
1134
|
+
*
|
|
1135
|
+
* A scoped slot is styled through an \`@scope\` rule opened at an anchor, so it has to be
|
|
1136
|
+
* rendered inside one. A slot moved out of every anchor's subtree keeps its base styles
|
|
1137
|
+
* and silently loses its variant styles — which no build step can catch, because whether
|
|
1138
|
+
* one element is inside another is a fact about the DOM.
|
|
1139
|
+
*
|
|
1140
|
+
* Returns a function that stops observing.
|
|
1141
|
+
*/
|
|
1142
|
+
export declare function auditSlotScopes(
|
|
1143
|
+
recipes: ReadonlyArray<unknown>,
|
|
1144
|
+
options?: AuditSlotScopesOptions,
|
|
1145
|
+
): () => void
|
|
3782
1146
|
`
|
|
3783
1147
|
};
|
|
3784
1148
|
}
|
|
3785
1149
|
//#endregion
|
|
3786
|
-
//#region src/artifacts/
|
|
3787
|
-
function
|
|
3788
|
-
const {
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
const styles = css.raw(Dynamic.__styles__, template)
|
|
3800
|
-
|
|
3801
|
-
const ${componentName} = defineComponent({
|
|
3802
|
-
name: \`${factoryName}.\${name}\`,
|
|
3803
|
-
inheritAttrs: false,
|
|
3804
|
-
props: {
|
|
3805
|
-
modelValue: null,
|
|
3806
|
-
as: { type: [String, Object], default: __base__ }
|
|
3807
|
-
},
|
|
3808
|
-
setup(props, { slots, attrs, emit }) {
|
|
3809
|
-
const classes = computed(() => {
|
|
3810
|
-
return cx(css(styles), attrs.className)
|
|
3811
|
-
})
|
|
3812
|
-
|
|
3813
|
-
const vModelProps = computed(() => {
|
|
3814
|
-
const result = {};
|
|
3815
|
-
|
|
3816
|
-
if (
|
|
3817
|
-
props.as === 'input' &&
|
|
3818
|
-
(props.type === 'checkbox' || props.type === 'radio')
|
|
3819
|
-
) {
|
|
3820
|
-
result.checked = props.modelValue;
|
|
3821
|
-
result.onChange = (event) => {
|
|
3822
|
-
const checked = !event.currentTarget.checked;
|
|
3823
|
-
emit('change', checked, event);
|
|
3824
|
-
emit('update:modelValue', checked, event);
|
|
3825
|
-
};
|
|
3826
|
-
} else if (
|
|
3827
|
-
props.as === 'input' ||
|
|
3828
|
-
props.as === 'textarea' ||
|
|
3829
|
-
props.as === 'select'
|
|
3830
|
-
) {
|
|
3831
|
-
result.value = props.modelValue;
|
|
3832
|
-
result.onInput = (event) => {
|
|
3833
|
-
const value = event.currentTarget.value;
|
|
3834
|
-
emit('input', value, event);
|
|
3835
|
-
emit('update:modelValue', value, event);
|
|
3836
|
-
};
|
|
3837
|
-
}
|
|
3838
|
-
|
|
3839
|
-
return result;
|
|
3840
|
-
});
|
|
3841
|
-
|
|
3842
|
-
return () => {
|
|
3843
|
-
return h(
|
|
3844
|
-
props.as,
|
|
3845
|
-
{
|
|
3846
|
-
class: classes.value,
|
|
3847
|
-
...attrs,
|
|
3848
|
-
...vModelProps.value,
|
|
3849
|
-
},
|
|
3850
|
-
slots
|
|
3851
|
-
)
|
|
3852
|
-
}
|
|
3853
|
-
},
|
|
3854
|
-
})
|
|
3855
|
-
|
|
3856
|
-
${componentName}.__styles__ = styles
|
|
3857
|
-
${componentName}.__base__ = __base__
|
|
3858
|
-
|
|
3859
|
-
return ${componentName}
|
|
3860
|
-
}
|
|
3861
|
-
|
|
3862
|
-
return styledFn
|
|
3863
|
-
}
|
|
3864
|
-
|
|
3865
|
-
const tags = 'a, abbr, address, area, article, aside, audio, b, base, bdi, bdo, big, blockquote, body, br, button, canvas, caption, cite, code, col, colgroup, data, datalist, dd, del, details, dfn, dialog, div, dl, dt, em, embed, fieldset, figcaption, figure, footer, form, h1, h2, h3, h4, h5, h6, head, header, hgroup, hr, html, i, iframe, img, input, ins, kbd, keygen, label, legend, li, link, main, map, mark, marquee, menu, menuitem, meta, meter, nav, noscript, object, ol, optgroup, option, output, p, param, picture, pre, progress, q, rp, rt, ruby, s, samp, script, section, select, small, source, span, strong, style, sub, summary, sup, table, tbody, td, textarea, tfoot, th, thead, time, title, tr, track, u, ul, var, video, wbr, circle, clipPath, defs, ellipse, foreignObject, g, image, line, linearGradient, mask, path, pattern, polygon, polyline, radialGradient, rect, stop, svg, text, tspan';
|
|
3866
|
-
|
|
3867
|
-
export const ${factoryName} = /* @__PURE__ */ createStyled.bind();
|
|
3868
|
-
|
|
3869
|
-
tags.split(', ').forEach((tag) => {
|
|
3870
|
-
${factoryName}[tag] = createStyled(tag);
|
|
3871
|
-
});
|
|
3872
|
-
` };
|
|
3873
|
-
}
|
|
3874
|
-
//#endregion
|
|
3875
|
-
//#region src/artifacts/vue-jsx/types.string-literal.ts
|
|
3876
|
-
function generateVueJsxStringLiteralTypes(ctx) {
|
|
3877
|
-
const { factoryName, componentName, upperName, typeName } = ctx.jsx;
|
|
1150
|
+
//#region src/artifacts/js/token.ts
|
|
1151
|
+
function generateTokenJs(ctx) {
|
|
1152
|
+
const { tokens } = ctx;
|
|
1153
|
+
const map = /* @__PURE__ */ new Map();
|
|
1154
|
+
tokens.allTokens.forEach((token) => {
|
|
1155
|
+
const { varRef, isVirtual } = token.extensions;
|
|
1156
|
+
const value = isVirtual || token.extensions.condition !== "base" ? varRef : token.value;
|
|
1157
|
+
map.set(token.name, {
|
|
1158
|
+
value,
|
|
1159
|
+
variable: varRef
|
|
1160
|
+
});
|
|
1161
|
+
});
|
|
1162
|
+
const obj = Object.fromEntries(map);
|
|
3878
1163
|
return {
|
|
3879
|
-
|
|
3880
|
-
${
|
|
3881
|
-
|
|
3882
|
-
export declare const ${factoryName}: ${upperName}
|
|
3883
|
-
`,
|
|
3884
|
-
jsxType: outdent.outdent`
|
|
3885
|
-
import type { Component, FunctionalComponent, NativeElements } from 'vue'
|
|
3886
|
-
|
|
3887
|
-
export type IntrinsicElement = keyof NativeElements
|
|
3888
|
-
|
|
3889
|
-
export type ElementType = IntrinsicElement | Component
|
|
3890
|
-
|
|
3891
|
-
export type ComponentProps<T extends ElementType> = T extends IntrinsicElement
|
|
3892
|
-
? NativeElements[T]
|
|
3893
|
-
: T extends Component<infer Props>
|
|
3894
|
-
? Props
|
|
3895
|
-
: never
|
|
3896
|
-
|
|
3897
|
-
export interface AsProps {
|
|
3898
|
-
/**
|
|
3899
|
-
* The element to render as
|
|
3900
|
-
*/
|
|
3901
|
-
as?: ElementType | undefined
|
|
3902
|
-
}
|
|
1164
|
+
js: outdent.default`
|
|
1165
|
+
const tokens = ${JSON.stringify(obj, null, 2)}
|
|
3903
1166
|
|
|
3904
|
-
export
|
|
3905
|
-
|
|
3906
|
-
}
|
|
1167
|
+
export function token(path, fallback) {
|
|
1168
|
+
return tokens[path]?.value || fallback
|
|
1169
|
+
}
|
|
3907
1170
|
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
}
|
|
1171
|
+
function tokenVar(path, fallback) {
|
|
1172
|
+
return tokens[path]?.variable || fallback
|
|
1173
|
+
}
|
|
3911
1174
|
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
1175
|
+
token.var = tokenVar
|
|
1176
|
+
`,
|
|
1177
|
+
dts: outdent.default`
|
|
1178
|
+
${ctx.file.importType("Token", "./tokens")}
|
|
3915
1179
|
|
|
3916
|
-
export
|
|
1180
|
+
export declare const token: {
|
|
1181
|
+
(path: Token, fallback?: string): string
|
|
1182
|
+
var: (path: Token, fallback?: string) => string
|
|
1183
|
+
}
|
|
3917
1184
|
|
|
3918
|
-
|
|
1185
|
+
${ctx.file.exportTypeStar("./tokens")}
|
|
3919
1186
|
`
|
|
3920
1187
|
};
|
|
3921
1188
|
}
|
|
3922
1189
|
//#endregion
|
|
3923
|
-
//#region src/artifacts/jsx.ts
|
|
3924
|
-
const typesMap = {
|
|
3925
|
-
react: generateReactJsxTypes,
|
|
3926
|
-
preact: generatePreactJsxTypes,
|
|
3927
|
-
solid: generateSolidJsxTypes,
|
|
3928
|
-
vue: generateVueJsxTypes,
|
|
3929
|
-
qwik: generateQwikJsxTypes
|
|
3930
|
-
};
|
|
3931
|
-
const typesStringLiteralMap = {
|
|
3932
|
-
react: generateReactJsxStringLiteralTypes,
|
|
3933
|
-
solid: generateSolidJsxStringLiteralTypes,
|
|
3934
|
-
qwik: generateQwikJsxStringLiteralTypes,
|
|
3935
|
-
preact: generatePreactJsxStringLiteralTypes,
|
|
3936
|
-
vue: generateVueJsxStringLiteralTypes
|
|
3937
|
-
};
|
|
3938
|
-
const isKnownFramework = (framework) => Boolean(typesMap[framework]);
|
|
3939
|
-
function generateJsxTypes(ctx) {
|
|
3940
|
-
if (!ctx.jsx.framework) return;
|
|
3941
|
-
if (!isKnownFramework(ctx.jsx.framework)) return;
|
|
3942
|
-
return (ctx.isTemplateLiteralSyntax ? typesStringLiteralMap[ctx.jsx.framework] : typesMap[ctx.jsx.framework])?.(ctx);
|
|
3943
|
-
}
|
|
3944
|
-
const factoryMap = {
|
|
3945
|
-
react: generateReactJsxFactory,
|
|
3946
|
-
solid: generateSolidJsxFactory,
|
|
3947
|
-
preact: generatePreactJsxFactory,
|
|
3948
|
-
vue: generateVueJsxFactory,
|
|
3949
|
-
qwik: generateQwikJsxFactory
|
|
3950
|
-
};
|
|
3951
|
-
const factoryStringLiteralMap = {
|
|
3952
|
-
react: generateReactJsxStringLiteralFactory,
|
|
3953
|
-
solid: generateSolidJsxStringLiteralFactory,
|
|
3954
|
-
qwik: generateQwikJsxStringLiteralFactory,
|
|
3955
|
-
preact: generatePreactJsxStringLiteralFactory,
|
|
3956
|
-
vue: generateVueJsxStringLiteralFactory
|
|
3957
|
-
};
|
|
3958
|
-
function generateJsxFactory(ctx) {
|
|
3959
|
-
if (!ctx.jsx.framework) return;
|
|
3960
|
-
if (!isKnownFramework(ctx.jsx.framework)) return;
|
|
3961
|
-
return (ctx.isTemplateLiteralSyntax ? factoryStringLiteralMap[ctx.jsx.framework] : factoryMap[ctx.jsx.framework])?.(ctx);
|
|
3962
|
-
}
|
|
3963
|
-
const patternMap = {
|
|
3964
|
-
react: generateReactJsxPattern,
|
|
3965
|
-
solid: generateSolidJsxPattern,
|
|
3966
|
-
preact: generatePreactJsxPattern,
|
|
3967
|
-
vue: generateVueJsxPattern,
|
|
3968
|
-
qwik: generateQwikJsxPattern
|
|
3969
|
-
};
|
|
3970
|
-
function generateJsxPatterns(ctx, filters) {
|
|
3971
|
-
if (ctx.isTemplateLiteralSyntax || ctx.patterns.isEmpty() || !ctx.jsx.framework) return [];
|
|
3972
|
-
if (!isKnownFramework(ctx.jsx.framework)) return;
|
|
3973
|
-
return patternMap[ctx.jsx.framework](ctx, filters);
|
|
3974
|
-
}
|
|
3975
|
-
const createStyleContextMap = {
|
|
3976
|
-
react: generateReactCreateStyleContext,
|
|
3977
|
-
preact: generatePreactCreateStyleContext,
|
|
3978
|
-
solid: generateSolidCreateStyleContext,
|
|
3979
|
-
vue: generateVueCreateStyleContext
|
|
3980
|
-
};
|
|
3981
|
-
function generateJsxCreateStyleContext(ctx) {
|
|
3982
|
-
if (ctx.isTemplateLiteralSyntax || !ctx.jsx.framework) return;
|
|
3983
|
-
if (!isKnownFramework(ctx.jsx.framework)) return;
|
|
3984
|
-
const generator = createStyleContextMap[ctx.jsx.framework];
|
|
3985
|
-
return generator?.(ctx);
|
|
3986
|
-
}
|
|
3987
|
-
//#endregion
|
|
3988
1190
|
//#region src/artifacts/generated/composition.d.ts.json
|
|
3989
1191
|
var content$7 = "import type { CompositionStyleObject } from './system-types'\n\ninterface Token<T> {\n value: T\n description?: string\n}\n\ninterface Recursive<T> {\n [key: string]: Recursive<T> | T\n}\n\n/* -----------------------------------------------------------------------------\n * Text styles\n * -----------------------------------------------------------------------------*/\n\ntype TextStyleProperty =\n | 'color'\n | 'direction'\n | 'font'\n | 'fontFamily'\n | 'fontFeatureSettings'\n | 'fontKerning'\n | 'fontLanguageOverride'\n | 'fontOpticalSizing'\n | 'fontPalette'\n | 'fontSize'\n | 'fontSizeAdjust'\n | 'fontStretch'\n | 'fontStyle'\n | 'fontSynthesis'\n | 'fontVariant'\n | 'fontVariantAlternates'\n | 'fontVariantCaps'\n | 'fontVariantLigatures'\n | 'fontVariantNumeric'\n | 'fontVariantPosition'\n | 'fontVariationSettings'\n | 'fontWeight'\n | 'hangingPunctuation'\n | 'hypens'\n | 'hyphenateCharacter'\n | 'hyphenateLimitChars'\n | 'letterSpacing'\n | 'lineBreak'\n | 'lineHeight'\n | 'quotes'\n | 'overflowWrap'\n | 'tabSize'\n | 'textAlign'\n | 'textAlignLast'\n | 'textBox'\n | 'textBoxEdge'\n | 'textBoxTrim'\n | 'textCombineUpright'\n | 'textDecoration'\n | 'textDecorationColor'\n | 'textDecorationLine'\n | 'textDecorationSkip'\n | 'textDecorationSkipBox'\n | 'textDecorationSkipInk'\n | 'textDecorationSkipInset'\n | 'textDecorationStyle'\n | 'textDecorationThickness'\n | 'textEmphasis'\n | 'textEmphasisColor'\n | 'textEmphasisPosition'\n | 'textEmphasisStyle'\n | 'textIndent'\n | 'textJustify'\n | 'textOrientation'\n | 'textOverflow'\n | 'textRendering'\n | 'textShadow'\n | 'textStroke'\n | 'textStrokeColor'\n | 'textStrokeWidth'\n | 'textTransform'\n | 'textUnderlineOffset'\n | 'textUnderlinePosition'\n | 'textWrap'\n | 'textWrapMode'\n | 'textWrapStyle'\n | 'unicodeBidi'\n | 'verticalAlign'\n | 'whiteSpace'\n | 'wordBreak'\n | 'wordSpacing'\n | 'writingMode'\n\nexport type TextStyle = CompositionStyleObject<TextStyleProperty>\n\nexport type TextStyles = Recursive<Token<TextStyle>>\n\n/* -----------------------------------------------------------------------------\n * Layer styles\n * -----------------------------------------------------------------------------*/\n\ntype LogicalPlacement = 'Inline' | 'Block' | 'InlineStart' | 'InlineEnd' | 'BlockStart' | 'BlockEnd'\n\ntype PhysicalPlacement = 'Top' | 'Right' | 'Bottom' | 'Left'\n\ntype Placement = PhysicalPlacement | LogicalPlacement\n\ntype Radius =\n | `Top${'Right' | 'Left'}`\n | `Bottom${'Right' | 'Left'}`\n | `Start${'Start' | 'End'}`\n | `End${'Start' | 'End'}`\n\ntype LayerStyleProperty =\n | 'aspectRatio'\n | 'background'\n | 'backgroundColor'\n | 'backgroundImage'\n | 'border'\n | 'borderColor'\n | 'borderImage'\n | 'borderImageOutset'\n | 'borderImageRepeat'\n | 'borderImageSlice'\n | 'borderImageSource'\n | 'borderImageWidth'\n | 'borderRadius'\n | 'borderStyle'\n | 'borderWidth'\n | `border${Placement}`\n | `border${Placement}Color`\n | `border${Placement}Style`\n | `border${Placement}Width`\n | 'borderRadius'\n | `border${Radius}Radius`\n | 'boxShadow'\n | 'boxShadowColor'\n | 'clipPath'\n | 'color'\n | 'contain'\n | 'content'\n | 'contentVisibility'\n | 'cursor'\n | 'display'\n | 'filter'\n | 'backdropFilter'\n | 'height'\n | 'width'\n | 'minHeight'\n | 'minWidth'\n | 'maxHeight'\n | 'maxWidth'\n | `margin${Placement}`\n | 'inset'\n | `inset${LogicalPlacement}`\n | Lowercase<PhysicalPlacement>\n | 'isolation'\n | 'mask'\n | 'maskClip'\n | 'maskComposite'\n | 'maskImage'\n | 'maskMode'\n | 'maskOrigin'\n | 'maskPosition'\n | 'maskRepeat'\n | 'maskSize'\n | 'mixBlendMode'\n | 'objectFit'\n | 'objectPosition'\n | 'opacity'\n | 'outline'\n | 'outlineColor'\n | 'outlineOffset'\n | 'outlineStyle'\n | 'outlineWidth'\n | 'overflow'\n | 'overflowX'\n | 'overflowY'\n | 'padding'\n | `padding${Placement}`\n | 'pointerEvents'\n | 'position'\n | 'resize'\n | 'transform'\n | 'transition'\n | 'visibility'\n | 'willChange'\n | 'zIndex'\n | 'backgroundBlendMode'\n | 'backgroundAttachment'\n | 'backgroundClip'\n | 'backgroundOrigin'\n | 'backgroundPosition'\n | 'backgroundRepeat'\n | 'backgroundSize'\n\nexport type LayerStyle = CompositionStyleObject<LayerStyleProperty>\n\nexport type LayerStyles = Recursive<Token<LayerStyle>>\n\n/* -----------------------------------------------------------------------------\n * Motion styles\n * -----------------------------------------------------------------------------*/\n\ntype AnimationStyleProperty =\n | 'animation'\n | 'animationComposition'\n | 'animationDelay'\n | 'animationDirection'\n | 'animationDuration'\n | 'animationFillMode'\n | 'animationIterationCount'\n | 'animationName'\n | 'animationPlayState'\n | 'animationTimingFunction'\n | 'animationRange'\n | 'animationRangeStart'\n | 'animationRangeEnd'\n | 'animationTimeline'\n | 'transformOrigin'\n\nexport type AnimationStyle = CompositionStyleObject<AnimationStyleProperty>\n\nexport type AnimationStyles = Recursive<Token<AnimationStyle>>\n\nexport interface CompositionStyles {\n textStyles: TextStyles\n layerStyles: LayerStyles\n animationStyles: AnimationStyles\n}\n";
|
|
3990
1192
|
//#endregion
|
|
@@ -4744,10 +1946,10 @@ var comments = {
|
|
|
4744
1946
|
var content$5 = "export interface Part {\n selector: string\n}\n\nexport interface Parts {\n [key: string]: Part\n}\n";
|
|
4745
1947
|
//#endregion
|
|
4746
1948
|
//#region src/artifacts/generated/pattern.d.ts.json
|
|
4747
|
-
var content$4 = "import type { CssProperty, SystemStyleObject } from './system-types'\nimport type { TokenCategory } from '../tokens'\n\ntype Primitive = string | number | boolean | null | undefined\ntype LiteralUnion<T, K extends Primitive = string> = T | (K & Record<never, never>)\n\nexport type PatternProperty =\n | { type: 'property'; value: CssProperty; description?: string }\n | { type: 'enum'; value: string[]; description?: string }\n | { type: 'token'; value: TokenCategory; property?: CssProperty; description?: string }\n | { type: 'string' | 'boolean' | 'number'; description?: string }\n\nexport interface PatternHelpers {\n map: (value: any, fn: (value: string) => string | undefined) => any\n isCssUnit: (value: any) => boolean\n isCssVar: (value: any) => boolean\n isCssFunction: (value: any) => boolean\n}\n\nexport interface PatternProperties {\n [key: string]: PatternProperty\n}\n\ntype InferProps<T> = Record<LiteralUnion<keyof T>, any>\n\nexport type PatternDefaultValue<T> = Partial<InferProps<T>>\n\nexport type PatternDefaultValueFn<T> = (props: InferProps<T>) => PatternDefaultValue<T>\n\nexport interface PatternConfig<T extends PatternProperties = PatternProperties> {\n /**\n * The description of the pattern. This will be used in the JSDoc comment.\n */\n description?: string\n /**\n * The
|
|
1949
|
+
var content$4 = "import type { CssProperty, SystemStyleObject } from './system-types'\nimport type { TokenCategory } from '../tokens'\n\ntype Primitive = string | number | boolean | null | undefined\ntype LiteralUnion<T, K extends Primitive = string> = T | (K & Record<never, never>)\n\nexport type PatternProperty =\n | { type: 'property'; value: CssProperty; description?: string }\n | { type: 'enum'; value: string[]; description?: string }\n | { type: 'token'; value: TokenCategory; property?: CssProperty; description?: string }\n | { type: 'string' | 'boolean' | 'number'; description?: string }\n\nexport interface PatternHelpers {\n map: (value: any, fn: (value: string) => string | undefined) => any\n isCssUnit: (value: any) => boolean\n isCssVar: (value: any) => boolean\n isCssFunction: (value: any) => boolean\n}\n\nexport interface PatternProperties {\n [key: string]: PatternProperty\n}\n\ntype InferProps<T> = Record<LiteralUnion<keyof T>, any>\n\nexport type PatternDefaultValue<T> = Partial<InferProps<T>>\n\nexport type PatternDefaultValueFn<T> = (props: InferProps<T>) => PatternDefaultValue<T>\n\nexport interface PatternConfig<T extends PatternProperties = PatternProperties> {\n /**\n * The description of the pattern. This will be used in the JSDoc comment.\n */\n description?: string\n /**\n * The properties of the pattern.\n */\n properties?: T\n /**\n * The default values of the pattern.\n */\n defaultValues?: PatternDefaultValue<T> | PatternDefaultValueFn<T>\n /**\n * The css object this pattern will generate.\n */\n transform?: (props: InferProps<T>, helpers: PatternHelpers) => SystemStyleObject\n /**\n * Whether the pattern is deprecated.\n */\n deprecated?: boolean | string\n /**\n * Whether to only generate types for the specified properties.\n * This will disallow css properties\n */\n strict?: boolean\n /**\n * @experimental\n * Disallow certain css properties for this pattern\n */\n blocklist?: LiteralUnion<CssProperty>[]\n}\n";
|
|
4748
1950
|
//#endregion
|
|
4749
1951
|
//#region src/artifacts/generated/recipe.d.ts.json
|
|
4750
|
-
var content$3 = "import type { RecipeRule } from './static-css'\nimport type { SystemStyleObject, DistributiveOmit, Pretty } from './system-types'\n\ntype StringToBoolean<T> = T extends 'true' | 'false' ? boolean : T\n\nexport type RecipeVariantRecord = Record<any, Record<any, SystemStyleObject>>\n\nexport type RecipeSelection<T extends RecipeVariantRecord> = keyof any extends keyof T\n ? {}\n : {\n [K in keyof T]?: StringToBoolean<keyof T[K]> | undefined\n }\n\nexport type RecipeVariantFn<T extends RecipeVariantRecord> = (props?: RecipeSelection<T>) => string\n\n/**\n * Extract the variant as optional props from a `cva` function.\n * Intended to be used with a JSX component, prefer `RecipeVariant` for a more strict type.\n */\nexport type RecipeVariantProps<\n T extends RecipeVariantFn<RecipeVariantRecord> | SlotRecipeVariantFn<string, SlotRecipeVariantRecord<string>>,\n> = Pretty<Parameters<T>[0]>\n\n/**\n * Extract the variants from a `cva` function.\n */\nexport type RecipeVariant<\n T extends RecipeVariantFn<RecipeVariantRecord> | SlotRecipeVariantFn<string, SlotRecipeVariantRecord<string>>,\n> = Exclude<Pretty<Required<RecipeVariantProps<T>>>, undefined>\n\ntype RecipeVariantMap<T extends RecipeVariantRecord> = {\n [K in keyof T]: Array<keyof T[K]>\n}\n\n/* -----------------------------------------------------------------------------\n * Recipe / Standard\n * -----------------------------------------------------------------------------*/\n\nexport interface RecipeRuntimeFn<T extends RecipeVariantRecord> extends RecipeVariantFn<T> {\n __type: RecipeSelection<T>\n variantKeys: (keyof T)[]\n variantMap: RecipeVariantMap<T>\n raw: (props?: RecipeSelection<T>) => SystemStyleObject\n config: RecipeConfig<T>\n splitVariantProps<Props extends RecipeSelection<T>>(\n props: Props,\n ): [RecipeSelection<T>, Pretty<DistributiveOmit<Props, keyof T>>]\n getVariantProps: (props?: RecipeSelection<T>) => RecipeSelection<T>\n}\n\ntype OneOrMore<T> = T | Array<T>\n\nexport type RecipeCompoundSelection<T> = {\n [K in keyof T]?: OneOrMore<StringToBoolean<keyof T[K]>> | undefined\n}\n\nexport type RecipeCompoundVariant<T> = T & {\n css: SystemStyleObject\n}\n\nexport interface RecipeDefinition<T extends RecipeVariantRecord = RecipeVariantRecord> {\n /**\n * The base styles of the recipe.\n */\n base?: SystemStyleObject\n /**\n * Whether the recipe is deprecated.\n */\n deprecated?: boolean | string\n /**\n * The multi-variant styles of the recipe.\n */\n variants?: T\n /**\n * The default variants of the recipe.\n */\n defaultVariants?: RecipeSelection<T>\n /**\n * The styles to apply when a combination of variants is selected.\n */\n compoundVariants?: Pretty<RecipeCompoundVariant<RecipeCompoundSelection<T>>>[]\n}\n\nexport type RecipeCreatorFn = <T extends RecipeVariantRecord>(config: RecipeDefinition<T>) => RecipeRuntimeFn<T>\n\ninterface RecipeConfigMeta {\n /**\n * The
|
|
1952
|
+
var content$3 = "import type { RecipeRule } from './static-css'\nimport type { SystemStyleObject, DistributiveOmit, Pretty } from './system-types'\n\ntype StringToBoolean<T> = T extends 'true' | 'false' ? boolean : T\n\nexport type RecipeVariantRecord = Record<any, Record<any, SystemStyleObject>>\n\nexport type RecipeSelection<T extends RecipeVariantRecord> = keyof any extends keyof T\n ? {}\n : {\n [K in keyof T]?: StringToBoolean<keyof T[K]> | undefined\n }\n\nexport type RecipeVariantFn<T extends RecipeVariantRecord> = (props?: RecipeSelection<T>) => string\n\n/**\n * Extract the variant as optional props from a `cva` function.\n * Intended to be used with a JSX component, prefer `RecipeVariant` for a more strict type.\n */\nexport type RecipeVariantProps<\n T extends RecipeVariantFn<RecipeVariantRecord> | SlotRecipeVariantFn<string, SlotRecipeVariantRecord<string>>,\n> = Pretty<Parameters<T>[0]>\n\n/**\n * Extract the variants from a `cva` function.\n */\nexport type RecipeVariant<\n T extends RecipeVariantFn<RecipeVariantRecord> | SlotRecipeVariantFn<string, SlotRecipeVariantRecord<string>>,\n> = Exclude<Pretty<Required<RecipeVariantProps<T>>>, undefined>\n\ntype RecipeVariantMap<T extends RecipeVariantRecord> = {\n [K in keyof T]: Array<keyof T[K]>\n}\n\n/* -----------------------------------------------------------------------------\n * Recipe / Standard\n * -----------------------------------------------------------------------------*/\n\nexport interface RecipeRuntimeFn<T extends RecipeVariantRecord> extends RecipeVariantFn<T> {\n __type: RecipeSelection<T>\n variantKeys: (keyof T)[]\n variantMap: RecipeVariantMap<T>\n raw: (props?: RecipeSelection<T>) => SystemStyleObject\n config: RecipeConfig<T>\n splitVariantProps<Props extends RecipeSelection<T>>(\n props: Props,\n ): [RecipeSelection<T>, Pretty<DistributiveOmit<Props, keyof T>>]\n getVariantProps: (props?: RecipeSelection<T>) => RecipeSelection<T>\n}\n\ntype OneOrMore<T> = T | Array<T>\n\nexport type RecipeCompoundSelection<T> = {\n [K in keyof T]?: OneOrMore<StringToBoolean<keyof T[K]>> | undefined\n}\n\nexport type RecipeCompoundVariant<T> = T & {\n css: SystemStyleObject\n}\n\nexport interface RecipeDefinition<T extends RecipeVariantRecord = RecipeVariantRecord> {\n /**\n * The base styles of the recipe.\n */\n base?: SystemStyleObject\n /**\n * The prefix every class this recipe emits is built from — `button` gives `button` for\n * the base styles and `button--size_sm` for a variant.\n *\n * Required for a recipe declared in `theme.recipes`, where it is the key it is declared\n * under. Optional for an inline `cva`, which is otherwise named by hashing its own\n * config: `cva_a1b2c3--size_sm`. Setting it buys readable class names and nothing else —\n * the CSS is identical either way.\n *\n * It has to be unique across every recipe in the build. Two recipes sharing a name emit\n * rules under the same selectors, and the later one wins for any variant they both\n * declare.\n */\n className?: string\n /**\n * Whether the recipe is deprecated.\n */\n deprecated?: boolean | string\n /**\n * The multi-variant styles of the recipe.\n */\n variants?: T\n /**\n * The default variants of the recipe.\n */\n defaultVariants?: RecipeSelection<T>\n /**\n * The styles to apply when a combination of variants is selected.\n */\n compoundVariants?: Pretty<RecipeCompoundVariant<RecipeCompoundSelection<T>>>[]\n}\n\nexport type RecipeCreatorFn = <T extends RecipeVariantRecord>(config: RecipeDefinition<T>) => RecipeRuntimeFn<T>\n\ninterface RecipeConfigMeta {\n /**\n * The description of the recipe. This will be used in the JSDoc comment.\n */\n description?: string\n /**\n * The jsx elements to track for this recipe. Can be string or Regexp.\n *\n * @default capitalize(recipe.name)\n * @example ['Button', 'Link', /Button$/]\n */\n jsx?: Array<string | RegExp>\n /**\n * Variants to pre-generate, will be include in the final `config.staticCss`\n */\n staticCss?: RecipeRule[]\n}\n\nexport interface RecipeConfig<T extends RecipeVariantRecord = RecipeVariantRecord>\n extends RecipeDefinition<T>, RecipeConfigMeta {\n /** Optional on `RecipeDefinition`, where an inline `cva` falls back to hashing its config. A recipe declared in `theme.recipes` always has one — the key it is declared under. */\n className: string\n}\n\n/* -----------------------------------------------------------------------------\n * Recipe / Slot\n * -----------------------------------------------------------------------------*/\n\ntype SlotRecord<S extends string, T> = Partial<Record<S, T>>\n\nexport type SlotRecipeVariantRecord<S extends string> = Record<any, Record<any, SlotRecord<S, SystemStyleObject>>>\n\nexport type SlotRecipeVariantFn<S extends string, T extends RecipeVariantRecord> = (\n props?: RecipeSelection<T>,\n) => SlotRecord<S, string>\n\nexport interface SlotRecipeRuntimeFn<\n S extends string,\n T extends SlotRecipeVariantRecord<S>,\n> extends SlotRecipeVariantFn<S, T> {\n raw: (props?: RecipeSelection<T>) => Record<S, SystemStyleObject>\n variantKeys: (keyof T)[]\n variantMap: RecipeVariantMap<T>\n /** The config this recipe was created from. */\n config: SlotRecipeDefinition<S, T>\n /** Each slot's constant class, for targeting a slot in the DOM. */\n classNameMap: Partial<Record<S, string>>\n /**\n * Which slots each variant writes styles for.\n *\n * A variant's styles reach a slot through a scope opened at an anchor, which covers every\n * slot in that anchor's subtree. A slot under no anchor — moved out by a portal, with no\n * second anchor named in `scopeRoots` — is not reached, and nothing at build time can\n * detect that. This says which slots a variant has to get to, so whatever a scope cannot\n * reach can be threaded by hand.\n */\n slotsAffectedBy: Record<keyof T, S[]>\n splitVariantProps<Props extends RecipeSelection<T>>(\n props: Props,\n ): [RecipeSelection<T>, Pretty<DistributiveOmit<Props, keyof T>>]\n getVariantProps: (props?: RecipeSelection<T>) => RecipeSelection<T>\n}\n\nexport type SlotRecipeCompoundVariant<S extends string, T> = T & {\n css: SlotRecord<S, SystemStyleObject>\n}\n\nexport interface SlotRecipeDefinition<\n S extends string = string,\n T extends SlotRecipeVariantRecord<S> = SlotRecipeVariantRecord<S>,\n> {\n /**\n * The prefix every class this recipe emits is built from, and the name to target its\n * slots in the DOM by — `checkbox` gives `checkbox__control` for a slot and\n * `checkbox__control--size_md` for that slot under a variant.\n *\n * Required for a recipe declared in `theme.slotRecipes`, where it is the key it is\n * declared under. Optional for an inline `sva`, which is otherwise named by hashing its\n * own config. Setting it buys readable class names and nothing else — the CSS is\n * identical either way.\n *\n * It has to be unique across every recipe in the build.\n */\n className?: string\n /**\n * Whether the recipe is deprecated.\n */\n deprecated?: boolean | string\n /**\n * The parts/slots of the recipe.\n */\n slots: S[] | Readonly<S[]>\n /**\n * The slots that enclose other slots, used to scope their variant styles.\n *\n * A slot recipe's variants are chosen once, at the top, but the slots that react to them\n * are authored by the consumer somewhere below. Naming the enclosing slots lets the build\n * emit their variant styles as rules scoped by a class those slots already carry, so\n * nothing has to be delivered to a slot at runtime and every other slot's class is a\n * constant.\n *\n * A list, because a portal is a real discontinuity in the tree and no CSS mechanism\n * crosses one. A `<Select>` occupies two disjoint subtrees — the trigger side under\n * `root`, the listbox side under a portaled `positioner` — and a variant writes styles\n * into both. One anchor can only ever reach one of them.\n *\n * ```ts\n * scopeRoots: ['root', 'positioner']\n * ```\n *\n * Each named slot takes variant props; every other slot's class is a constant. The build\n * emits each non-anchor slot's variant rules under *every* anchor, and only the anchor\n * that is genuinely an ancestor matches — so the DOM shape never has to be declared.\n *\n * Defaults to `['root']` when a slot by that name exists. Set `[]` to turn scoping off\n * and give every slot a variant class of its own, which is what a recipe whose slots are\n * siblings wants.\n *\n * A slot under *no* anchor is still unreachable, and nothing at build time can detect\n * that — reachability is a fact about the DOM. `recipe.slotsAffectedBy` says which slots\n * a variant writes to, for whatever still needs threading by hand.\n */\n scopeRoots?: S[] | Readonly<S[]>\n /**\n * The base styles of the recipe.\n */\n base?: SlotRecord<S, SystemStyleObject>\n /**\n * The multi-variant styles of the recipe.\n */\n variants?: T\n /**\n * The default variants of the recipe.\n */\n defaultVariants?: RecipeSelection<T>\n /**\n * The styles to apply when a combination of variants is selected.\n */\n compoundVariants?: Pretty<SlotRecipeCompoundVariant<S, RecipeCompoundSelection<T>>>[]\n}\n\nexport type SlotRecipeCreatorFn = <S extends string, T extends SlotRecipeVariantRecord<S>>(\n config: SlotRecipeDefinition<S, T>,\n) => SlotRecipeRuntimeFn<S, T>\n\nexport type SlotRecipeConfig<\n S extends string = string,\n T extends SlotRecipeVariantRecord<S> = SlotRecipeVariantRecord<S>,\n> = SlotRecipeDefinition<S, T> &\n RecipeConfigMeta & {\n /** Optional on `SlotRecipeDefinition`, where an inline `sva` falls back to hashing its config. A recipe declared in `theme.slotRecipes` always has one — the key it is declared under. */\n className: string\n }\n";
|
|
4751
1953
|
//#endregion
|
|
4752
1954
|
//#region src/artifacts/generated/selectors.d.ts.json
|
|
4753
1955
|
var content$2 = "import type { Pseudos } from './csstype'\n\ntype AriaAttributes =\n | '[aria-disabled]'\n | '[aria-hidden]'\n | '[aria-invalid]'\n | '[aria-readonly]'\n | '[aria-required]'\n | '[aria-selected]'\n | '[aria-checked]'\n | '[aria-expanded]'\n | '[aria-pressed]'\n | `[aria-current=${'page' | 'step' | 'location' | 'date' | 'time'}]`\n | '[aria-invalid]'\n | `[aria-sort=${'ascending' | 'descending'}]`\n\ntype DataAttributes =\n | '[data-selected]'\n | '[data-highlighted]'\n | '[data-hover]'\n | '[data-active]'\n | '[data-checked]'\n | '[data-disabled]'\n | '[data-readonly]'\n | '[data-focus]'\n | '[data-focus-visible]'\n | '[data-focus-visible-added]'\n | '[data-invalid]'\n | '[data-pressed]'\n | '[data-expanded]'\n | '[data-grabbed]'\n | '[data-dragged]'\n | '[data-orientation=horizontal]'\n | '[data-orientation=vertical]'\n | '[data-in-range]'\n | '[data-out-of-range]'\n | '[data-placeholder-shown]'\n | `[data-part=${string}]`\n | `[data-attr=${string}]`\n | `[data-placement=${string}]`\n | `[data-theme=${string}]`\n | `[data-size=${string}]`\n | `[data-state=${string}]`\n | '[data-empty]'\n | '[data-loading]'\n | '[data-loaded]'\n | '[data-enter]'\n | '[data-entering]'\n | '[data-exited]'\n | '[data-exiting]'\n\ntype AttributeSelector = `&${Pseudos | DataAttributes | AriaAttributes}`\ntype ParentSelector = `${DataAttributes | AriaAttributes} &`\n\ntype AtRuleType = 'media' | 'layer' | 'container' | 'supports' | 'page' | 'scope' | 'starting-style'\n\nexport type AnySelector = `${string}&` | `&${string}` | `@${AtRuleType}${string}`\nexport type Selectors = AttributeSelector | ParentSelector\n";
|
|
@@ -4770,20 +1972,18 @@ function getGeneratedTypes(ctx) {
|
|
|
4770
1972
|
selectors: ctx.file.rewriteTypeImport(content$2)
|
|
4771
1973
|
};
|
|
4772
1974
|
}
|
|
4773
|
-
const jsxStyleProps = "export type JsxStyleProps = SystemStyleObject & WithCss";
|
|
4774
1975
|
function getGeneratedSystemTypes(ctx) {
|
|
4775
|
-
return { system: ctx.file.rewriteTypeImport(
|
|
1976
|
+
return { system: ctx.file.rewriteTypeImport(content) };
|
|
4776
1977
|
}
|
|
4777
1978
|
//#endregion
|
|
4778
1979
|
//#region src/artifacts/types/main.ts
|
|
4779
|
-
const generateTypesEntry = (ctx
|
|
1980
|
+
const generateTypesEntry = (ctx) => {
|
|
4780
1981
|
const indexExports = [
|
|
4781
1982
|
`import '${ctx.file.extDts("./global")}'`,
|
|
4782
1983
|
ctx.file.exportTypeStar("./conditions"),
|
|
4783
1984
|
ctx.file.exportTypeStar("./pattern"),
|
|
4784
1985
|
ctx.file.exportTypeStar("./recipe"),
|
|
4785
1986
|
ctx.file.exportTypeStar("./system-types"),
|
|
4786
|
-
isJsxRequired && ctx.file.exportTypeStar("./jsx"),
|
|
4787
1987
|
ctx.file.exportTypeStar("./style-props")
|
|
4788
1988
|
].filter(Boolean);
|
|
4789
1989
|
return {
|
|
@@ -5288,7 +2488,7 @@ function generateThemesIndex(ctx, files) {
|
|
|
5288
2488
|
//#endregion
|
|
5289
2489
|
//#region src/artifacts/setup-artifacts.ts
|
|
5290
2490
|
function setupHelpers(ctx) {
|
|
5291
|
-
const code = generateHelpers(
|
|
2491
|
+
const code = generateHelpers();
|
|
5292
2492
|
return {
|
|
5293
2493
|
id: "helpers",
|
|
5294
2494
|
files: [{
|
|
@@ -5327,21 +2527,8 @@ function setupDesignTokens(ctx) {
|
|
|
5327
2527
|
]
|
|
5328
2528
|
};
|
|
5329
2529
|
}
|
|
5330
|
-
function setupJsxTypes(ctx) {
|
|
5331
|
-
if (!ctx.jsx.framework) return;
|
|
5332
|
-
const jsx = generateJsxTypes(ctx);
|
|
5333
|
-
if (!jsx) return;
|
|
5334
|
-
return {
|
|
5335
|
-
id: "types-jsx",
|
|
5336
|
-
dir: ctx.paths.types,
|
|
5337
|
-
files: [{
|
|
5338
|
-
file: ctx.file.extDts("jsx"),
|
|
5339
|
-
code: jsx.jsxType
|
|
5340
|
-
}]
|
|
5341
|
-
};
|
|
5342
|
-
}
|
|
5343
2530
|
function setupEntryTypes(ctx) {
|
|
5344
|
-
const entry = generateTypesEntry(ctx
|
|
2531
|
+
const entry = generateTypesEntry(ctx);
|
|
5345
2532
|
return {
|
|
5346
2533
|
id: "types-entry",
|
|
5347
2534
|
dir: ctx.paths.types,
|
|
@@ -5427,29 +2614,29 @@ function setupGeneratedSystemTypes(ctx) {
|
|
|
5427
2614
|
};
|
|
5428
2615
|
}
|
|
5429
2616
|
function setupCss(ctx) {
|
|
5430
|
-
const code =
|
|
5431
|
-
const conditions =
|
|
2617
|
+
const code = generateCssFn(ctx);
|
|
2618
|
+
const conditions = generateConditions(ctx);
|
|
2619
|
+
const files = [
|
|
2620
|
+
{
|
|
2621
|
+
file: ctx.file.ext("conditions"),
|
|
2622
|
+
code: conditions.js
|
|
2623
|
+
},
|
|
2624
|
+
{
|
|
2625
|
+
file: ctx.file.ext("css"),
|
|
2626
|
+
code: code.js
|
|
2627
|
+
},
|
|
2628
|
+
{
|
|
2629
|
+
file: ctx.file.extDts("css"),
|
|
2630
|
+
code: code.dts
|
|
2631
|
+
}
|
|
2632
|
+
];
|
|
5432
2633
|
return {
|
|
5433
2634
|
id: "css-fn",
|
|
5434
2635
|
dir: ctx.paths.css,
|
|
5435
|
-
files
|
|
5436
|
-
{
|
|
5437
|
-
file: ctx.file.ext("conditions"),
|
|
5438
|
-
code: conditions.js
|
|
5439
|
-
},
|
|
5440
|
-
{
|
|
5441
|
-
file: ctx.file.ext("css"),
|
|
5442
|
-
code: code.js
|
|
5443
|
-
},
|
|
5444
|
-
{
|
|
5445
|
-
file: ctx.file.extDts("css"),
|
|
5446
|
-
code: code.dts
|
|
5447
|
-
}
|
|
5448
|
-
]
|
|
2636
|
+
files
|
|
5449
2637
|
};
|
|
5450
2638
|
}
|
|
5451
2639
|
function setupCva(ctx) {
|
|
5452
|
-
if (ctx.isTemplateLiteralSyntax) return;
|
|
5453
2640
|
const code = generateCvaFn(ctx);
|
|
5454
2641
|
return {
|
|
5455
2642
|
id: "cva",
|
|
@@ -5464,7 +2651,6 @@ function setupCva(ctx) {
|
|
|
5464
2651
|
};
|
|
5465
2652
|
}
|
|
5466
2653
|
function setupSva(ctx) {
|
|
5467
|
-
if (ctx.isTemplateLiteralSyntax) return;
|
|
5468
2654
|
const code = generateSvaFn(ctx);
|
|
5469
2655
|
return {
|
|
5470
2656
|
id: "sva",
|
|
@@ -5479,7 +2665,7 @@ function setupSva(ctx) {
|
|
|
5479
2665
|
};
|
|
5480
2666
|
}
|
|
5481
2667
|
function setupCx(ctx) {
|
|
5482
|
-
const code = generateCx(
|
|
2668
|
+
const code = generateCx();
|
|
5483
2669
|
return {
|
|
5484
2670
|
id: "cx",
|
|
5485
2671
|
dir: ctx.paths.css,
|
|
@@ -5544,7 +2730,6 @@ function setupRecipes(ctx, filters) {
|
|
|
5544
2730
|
};
|
|
5545
2731
|
}
|
|
5546
2732
|
function setupPatternsIndex(ctx) {
|
|
5547
|
-
if (ctx.isTemplateLiteralSyntax) return;
|
|
5548
2733
|
const fileNames = ctx.patterns.details.map((pattern) => pattern.dashName);
|
|
5549
2734
|
const index = {
|
|
5550
2735
|
js: outdent.default.string(fileNames.map((file) => ctx.file.exportStar(`./${file}`)).join("\n")),
|
|
@@ -5563,7 +2748,6 @@ function setupPatternsIndex(ctx) {
|
|
|
5563
2748
|
};
|
|
5564
2749
|
}
|
|
5565
2750
|
function setupPatterns(ctx, filters) {
|
|
5566
|
-
if (ctx.isTemplateLiteralSyntax) return;
|
|
5567
2751
|
const files = generatePattern(ctx, filters);
|
|
5568
2752
|
if (!files) return;
|
|
5569
2753
|
return {
|
|
@@ -5578,127 +2762,19 @@ function setupPatterns(ctx, filters) {
|
|
|
5578
2762
|
}])
|
|
5579
2763
|
};
|
|
5580
2764
|
}
|
|
5581
|
-
function setupJsxIsValidProp(ctx) {
|
|
5582
|
-
if (!ctx.jsx.framework || ctx.isTemplateLiteralSyntax) return;
|
|
5583
|
-
const isValidProp = generateIsValidProp(ctx);
|
|
5584
|
-
return {
|
|
5585
|
-
id: "jsx-is-valid-prop",
|
|
5586
|
-
dir: ctx.paths.jsx,
|
|
5587
|
-
files: [{
|
|
5588
|
-
file: ctx.file.ext("is-valid-prop"),
|
|
5589
|
-
code: isValidProp?.js
|
|
5590
|
-
}, {
|
|
5591
|
-
file: ctx.file.extDts("is-valid-prop"),
|
|
5592
|
-
code: isValidProp?.dts
|
|
5593
|
-
}]
|
|
5594
|
-
};
|
|
5595
|
-
}
|
|
5596
|
-
function setupJsxFactory(ctx) {
|
|
5597
|
-
if (!ctx.jsx.framework) return;
|
|
5598
|
-
const types = generateJsxTypes(ctx);
|
|
5599
|
-
if (!types) return;
|
|
5600
|
-
const factory = generateJsxFactory(ctx);
|
|
5601
|
-
if (!factory) return;
|
|
5602
|
-
return {
|
|
5603
|
-
id: "jsx-factory",
|
|
5604
|
-
dir: ctx.paths.jsx,
|
|
5605
|
-
files: [{
|
|
5606
|
-
file: ctx.file.ext("factory"),
|
|
5607
|
-
code: factory?.js
|
|
5608
|
-
}, {
|
|
5609
|
-
file: ctx.file.extDts("factory"),
|
|
5610
|
-
code: types.jsxFactory
|
|
5611
|
-
}]
|
|
5612
|
-
};
|
|
5613
|
-
}
|
|
5614
|
-
function setupJsxHelpers(ctx) {
|
|
5615
|
-
if (!ctx.jsx.framework) return;
|
|
5616
|
-
const helpers = generatedJsxHelpers(ctx);
|
|
5617
|
-
return {
|
|
5618
|
-
id: "jsx-helpers",
|
|
5619
|
-
dir: ctx.paths.jsx,
|
|
5620
|
-
files: [{
|
|
5621
|
-
file: ctx.file.ext("factory-helper"),
|
|
5622
|
-
code: helpers.js
|
|
5623
|
-
}]
|
|
5624
|
-
};
|
|
5625
|
-
}
|
|
5626
|
-
function setupJsxPatterns(ctx, filters) {
|
|
5627
|
-
if (!ctx.jsx.framework || ctx.isTemplateLiteralSyntax) return;
|
|
5628
|
-
const patterns = generateJsxPatterns(ctx, filters);
|
|
5629
|
-
if (!patterns) return;
|
|
5630
|
-
return {
|
|
5631
|
-
id: "jsx-patterns",
|
|
5632
|
-
dir: ctx.paths.jsx,
|
|
5633
|
-
files: [...patterns.flatMap((file) => [{
|
|
5634
|
-
file: ctx.file.ext(file.name),
|
|
5635
|
-
code: file.js
|
|
5636
|
-
}, {
|
|
5637
|
-
file: ctx.file.extDts(file.name),
|
|
5638
|
-
code: file.dts
|
|
5639
|
-
}])]
|
|
5640
|
-
};
|
|
5641
|
-
}
|
|
5642
|
-
function setupJsxCreateStyleContext(ctx) {
|
|
5643
|
-
if (!ctx.jsx.framework || ctx.isTemplateLiteralSyntax) return;
|
|
5644
|
-
const createStyleContext = generateJsxCreateStyleContext(ctx);
|
|
5645
|
-
if (!createStyleContext) return;
|
|
5646
|
-
return {
|
|
5647
|
-
id: "jsx-create-style-context",
|
|
5648
|
-
dir: ctx.paths.jsx,
|
|
5649
|
-
files: [{
|
|
5650
|
-
file: ctx.file.ext("create-style-context"),
|
|
5651
|
-
code: createStyleContext.js
|
|
5652
|
-
}, {
|
|
5653
|
-
file: ctx.file.extDts("create-style-context"),
|
|
5654
|
-
code: createStyleContext.dts
|
|
5655
|
-
}]
|
|
5656
|
-
};
|
|
5657
|
-
}
|
|
5658
|
-
function setupJsxPatternsIndex(ctx) {
|
|
5659
|
-
if (!ctx.jsx.framework) return;
|
|
5660
|
-
const isStyleProp = !ctx.isTemplateLiteralSyntax;
|
|
5661
|
-
const patternNames = ctx.patterns.details.map((pattern) => pattern.dashName);
|
|
5662
|
-
const index = {
|
|
5663
|
-
js: outdent.default`
|
|
5664
|
-
${ctx.file.exportStar("./factory")}
|
|
5665
|
-
${isStyleProp ? ctx.file.exportStar("./is-valid-prop") : ""}
|
|
5666
|
-
${isStyleProp && !["qwik", "svelte"].includes(ctx.jsx.framework) ? ctx.file.exportStar("./create-style-context") : ""}
|
|
5667
|
-
${isStyleProp ? outdent.default.string(patternNames.map((file) => ctx.file.exportStar(`./${file}`)).join("\n")) : ""}
|
|
5668
|
-
`,
|
|
5669
|
-
dts: outdent.default`
|
|
5670
|
-
${ctx.file.exportTypeStar("./factory")}
|
|
5671
|
-
${isStyleProp ? ctx.file.exportTypeStar("./is-valid-prop") : ""}
|
|
5672
|
-
${isStyleProp ? ctx.file.exportTypeStar("./create-style-context") : ""}
|
|
5673
|
-
${isStyleProp ? outdent.default.string(patternNames.map((file) => ctx.file.exportTypeStar(`./${file}`)).join("\n")) : ""}
|
|
5674
|
-
${ctx.file.exportType([ctx.jsx.typeName, ctx.jsx.componentName].join(", "), "../types/jsx")}
|
|
5675
|
-
`
|
|
5676
|
-
};
|
|
5677
|
-
return {
|
|
5678
|
-
id: "jsx-patterns-index",
|
|
5679
|
-
dir: ctx.paths.jsx,
|
|
5680
|
-
files: [{
|
|
5681
|
-
file: ctx.file.ext("index"),
|
|
5682
|
-
code: index.js
|
|
5683
|
-
}, {
|
|
5684
|
-
file: ctx.file.extDts("index"),
|
|
5685
|
-
code: index.dts
|
|
5686
|
-
}]
|
|
5687
|
-
};
|
|
5688
|
-
}
|
|
5689
2765
|
function setupCssIndex(ctx) {
|
|
5690
2766
|
const index = {
|
|
5691
2767
|
js: outdent.default`
|
|
5692
2768
|
${ctx.file.exportStar("./css")}
|
|
5693
2769
|
${ctx.file.exportStar("./cx")}
|
|
5694
|
-
${ctx.
|
|
5695
|
-
${ctx.
|
|
2770
|
+
${ctx.file.exportStar("./cva")}
|
|
2771
|
+
${ctx.file.exportStar("./sva")}
|
|
5696
2772
|
`,
|
|
5697
2773
|
dts: outdent.default`
|
|
5698
2774
|
${ctx.file.exportTypeStar("./css")}
|
|
5699
2775
|
${ctx.file.exportTypeStar("./cx")}
|
|
5700
|
-
${ctx.
|
|
5701
|
-
${ctx.
|
|
2776
|
+
${ctx.file.exportTypeStar("./cva")}
|
|
2777
|
+
${ctx.file.exportTypeStar("./sva")}
|
|
5702
2778
|
`
|
|
5703
2779
|
};
|
|
5704
2780
|
return {
|
|
@@ -5749,7 +2825,7 @@ const filterArtifactsFiles = (artifacts, filters) => {
|
|
|
5749
2825
|
if (affected.recipes && !item.file.includes("index") && artifact?.dir?.includes("recipes")) {
|
|
5750
2826
|
if (!affected.recipes.some((recipe) => item.file.includes(recipe))) return;
|
|
5751
2827
|
}
|
|
5752
|
-
if (affected.patterns && !item.file.includes("index") &&
|
|
2828
|
+
if (affected.patterns && !item.file.includes("index") && artifact?.dir?.includes("patterns")) {
|
|
5753
2829
|
if (!affected.patterns.some((pattern) => item.file.includes(pattern))) return;
|
|
5754
2830
|
}
|
|
5755
2831
|
return true;
|
|
@@ -5764,7 +2840,6 @@ const entries = [
|
|
|
5764
2840
|
["package.json", setupPackageJson],
|
|
5765
2841
|
["helpers", setupHelpers],
|
|
5766
2842
|
["design-tokens", setupDesignTokens],
|
|
5767
|
-
["types-jsx", setupJsxTypes],
|
|
5768
2843
|
["types-entry", setupEntryTypes],
|
|
5769
2844
|
["types-styles", setupStyleTypes],
|
|
5770
2845
|
["types-conditions", setupConditionsTypes],
|
|
@@ -5779,12 +2854,6 @@ const entries = [
|
|
|
5779
2854
|
["recipes", setupRecipes],
|
|
5780
2855
|
["patterns-index", setupPatternsIndex],
|
|
5781
2856
|
["patterns", setupPatterns],
|
|
5782
|
-
["jsx-is-valid-prop", setupJsxIsValidProp],
|
|
5783
|
-
["jsx-factory", setupJsxFactory],
|
|
5784
|
-
["jsx-helpers", setupJsxHelpers],
|
|
5785
|
-
["jsx-patterns", setupJsxPatterns],
|
|
5786
|
-
["jsx-create-style-context", setupJsxCreateStyleContext],
|
|
5787
|
-
["jsx-patterns-index", setupJsxPatternsIndex],
|
|
5788
2857
|
["css-index", setupCssIndex],
|
|
5789
2858
|
["themes", setupThemes]
|
|
5790
2859
|
];
|
|
@@ -5834,6 +2903,61 @@ const generateGlobalCss = (ctx, sheet) => {
|
|
|
5834
2903
|
sheet.processGlobalCss(globalCss);
|
|
5835
2904
|
};
|
|
5836
2905
|
//#endregion
|
|
2906
|
+
//#region src/artifacts/js/group-registry.ts
|
|
2907
|
+
/**
|
|
2908
|
+
* The grouped class names an encoder has accumulated.
|
|
2909
|
+
*
|
|
2910
|
+
* Derived through `groupClassName`, the same function the browser runtime calls — a
|
|
2911
|
+
* registry built any other way would be a third spelling of a name that already has two.
|
|
2912
|
+
* Unescaped, unlike `StyleDecoder`'s class names: this is compared against what `css()`
|
|
2913
|
+
* returns into a `class` attribute, not against a selector.
|
|
2914
|
+
*
|
|
2915
|
+
* Reads from the encoder rather than the decoder so it is available as soon as extraction
|
|
2916
|
+
* is, and so `codegen` can emit whatever is already known instead of blanking the file.
|
|
2917
|
+
*/
|
|
2918
|
+
function collectGroupClassNames(ctx) {
|
|
2919
|
+
const names = [];
|
|
2920
|
+
ctx.encoder.grouped.forEach((_hashes, groupId) => {
|
|
2921
|
+
names.push((0, _bamboocss_shared.groupClassName)(groupId, ctx.utility.toHash, ctx.utility.formatClassName));
|
|
2922
|
+
});
|
|
2923
|
+
return names.sort();
|
|
2924
|
+
}
|
|
2925
|
+
/**
|
|
2926
|
+
* The grouped classes the build emitted a rule for.
|
|
2927
|
+
*
|
|
2928
|
+
* Under `cssMode: 'grouped'` a class names a whole `css()` call, so the build has to have
|
|
2929
|
+
* seen that exact call to emit its rule. This is how the runtime tells the difference: a
|
|
2930
|
+
* class in here has CSS behind it, and one that is not falls back to naming its
|
|
2931
|
+
* declarations atomically as well.
|
|
2932
|
+
*
|
|
2933
|
+
* Written by two passes. `codegen` emits whatever the encoder already holds — usually
|
|
2934
|
+
* nothing, since it runs on config change before anything is extracted, but not blank when
|
|
2935
|
+
* it runs after a build. The CSS build then rewrites it with the set it emitted.
|
|
2936
|
+
*
|
|
2937
|
+
* An empty or stale registry is safe by construction: the runtime *adds* to the group class
|
|
2938
|
+
* rather than replacing it, so the worst a miss can do is name a class that matches nothing.
|
|
2939
|
+
*/
|
|
2940
|
+
function generateGroupRegistry(ctx, classNames) {
|
|
2941
|
+
const names = classNames ?? collectGroupClassNames(ctx);
|
|
2942
|
+
return {
|
|
2943
|
+
js: outdent.outdent`
|
|
2944
|
+
// Generated by bamboo. Rewritten on every CSS build — do not edit.
|
|
2945
|
+
const packed = ${JSON.stringify(names.slice().sort().join(","))}
|
|
2946
|
+
|
|
2947
|
+
export const groups = /* @__PURE__ */ new Set(packed ? packed.split(',') : [])
|
|
2948
|
+
`,
|
|
2949
|
+
dts: outdent.outdent`
|
|
2950
|
+
/**
|
|
2951
|
+
* The grouped classes this build emitted a rule for. Internal — the generated \`css\`
|
|
2952
|
+
* consults it to decide whether a grouped class has CSS behind it.
|
|
2953
|
+
*/
|
|
2954
|
+
export declare const groups: Set<string>;
|
|
2955
|
+
`
|
|
2956
|
+
};
|
|
2957
|
+
}
|
|
2958
|
+
/** Where the registry lives, so the writer and the importer cannot disagree about it. */
|
|
2959
|
+
const GROUP_REGISTRY_FILE = "groups";
|
|
2960
|
+
//#endregion
|
|
5837
2961
|
//#region src/artifacts/css/keyframe-css.ts
|
|
5838
2962
|
function generateKeyframeCss(ctx, sheet) {
|
|
5839
2963
|
const { keyframes = {} } = ctx.config.theme ?? {};
|
|
@@ -5998,7 +3122,7 @@ const generateStaticCss = (ctx, sheet) => {
|
|
|
5998
3122
|
//#endregion
|
|
5999
3123
|
//#region src/spec/animation-styles.ts
|
|
6000
3124
|
const generateAnimationStylesSpec = (ctx) => {
|
|
6001
|
-
return generateCompositionStyleSpec("animation-styles", ctx.config.theme
|
|
3125
|
+
return generateCompositionStyleSpec("animation-styles", ctx.config.theme);
|
|
6002
3126
|
};
|
|
6003
3127
|
//#endregion
|
|
6004
3128
|
//#region src/spec/color-palette.ts
|
|
@@ -6023,16 +3147,12 @@ const getColorPaletteExampleValues = (ctx, paletteValues) => {
|
|
|
6023
3147
|
};
|
|
6024
3148
|
const generateColorPaletteSpec = (ctx) => {
|
|
6025
3149
|
if ((ctx.config.theme?.colorPalette)?.enabled === false) return null;
|
|
6026
|
-
const jsxStyleProps = ctx.config.jsxStyleProps;
|
|
6027
3150
|
const values = Array.from(ctx.tokens.view.colorPalettes.keys()).sort();
|
|
6028
3151
|
if (!values.length) return null;
|
|
6029
3152
|
const { examplePalette, bgToken, colorToken } = getColorPaletteExampleValues(ctx, values);
|
|
6030
3153
|
const functionExamples = [];
|
|
6031
|
-
const jsxExamples = [];
|
|
6032
3154
|
const basicProps = { colorPalette: examplePalette };
|
|
6033
3155
|
functionExamples.push(`css({ ${formatProps(basicProps)} })`);
|
|
6034
|
-
const basicJsx = generateJsxExample(basicProps, jsxStyleProps);
|
|
6035
|
-
if (basicJsx) jsxExamples.push(basicJsx);
|
|
6036
3156
|
if (bgToken || colorToken) {
|
|
6037
3157
|
const extendedProps = {
|
|
6038
3158
|
colorPalette: examplePalette,
|
|
@@ -6040,25 +3160,17 @@ const generateColorPaletteSpec = (ctx) => {
|
|
|
6040
3160
|
color: colorToken
|
|
6041
3161
|
};
|
|
6042
3162
|
functionExamples.push(`css({ ${formatProps(extendedProps)} })`);
|
|
6043
|
-
const extendedJsx = generateJsxExample(extendedProps, jsxStyleProps);
|
|
6044
|
-
if (extendedJsx) jsxExamples.push(extendedJsx);
|
|
6045
3163
|
}
|
|
6046
3164
|
return {
|
|
6047
3165
|
type: "color-palette",
|
|
6048
3166
|
data: {
|
|
6049
3167
|
values,
|
|
6050
|
-
functionExamples
|
|
6051
|
-
jsxExamples
|
|
3168
|
+
functionExamples
|
|
6052
3169
|
}
|
|
6053
3170
|
};
|
|
6054
3171
|
};
|
|
6055
3172
|
//#endregion
|
|
6056
3173
|
//#region src/spec/conditions.ts
|
|
6057
|
-
const generateConditionJsxExamples = (conditionName, jsxStyleProps = "all") => {
|
|
6058
|
-
if (jsxStyleProps === "all") return [`<Box margin={{ base: '2', ${conditionName}: '4' }} />`, `<Box margin="2" ${conditionName}={{ margin: '4' }} />`];
|
|
6059
|
-
if (jsxStyleProps === "minimal") return [`<Box css={{ margin: { base: '2', ${conditionName}: '4' } }} />`, `<Box css={{ margin: '2', ${conditionName}: { margin: '4' } }} />`];
|
|
6060
|
-
return [];
|
|
6061
|
-
};
|
|
6062
3174
|
/**
|
|
6063
3175
|
* Walk an object condition collecting every path that ends in `@slot`.
|
|
6064
3176
|
* Each path is joined with spaces; multiple paths are joined with `; ` so the
|
|
@@ -6074,7 +3186,6 @@ const formatObjectCondition = (raw) => {
|
|
|
6074
3186
|
return blocks.join("; ");
|
|
6075
3187
|
};
|
|
6076
3188
|
const generateConditionsSpec = (ctx) => {
|
|
6077
|
-
const jsxStyleProps = ctx.config.jsxStyleProps;
|
|
6078
3189
|
const breakpointKeys = new Set(Object.keys(ctx.conditions.breakpoints.conditions));
|
|
6079
3190
|
return {
|
|
6080
3191
|
type: "conditions",
|
|
@@ -6085,37 +3196,26 @@ const generateConditionsSpec = (ctx) => {
|
|
|
6085
3196
|
return {
|
|
6086
3197
|
name: conditionName,
|
|
6087
3198
|
value: value ?? "",
|
|
6088
|
-
functionExamples: [`css({ margin: { base: '2', ${conditionName}: '4' } })`, `css({ margin: '2', ${conditionName}: { margin: '4' } })`]
|
|
6089
|
-
jsxExamples: generateConditionJsxExamples(conditionName, jsxStyleProps)
|
|
3199
|
+
functionExamples: [`css({ margin: { base: '2', ${conditionName}: '4' } })`, `css({ margin: '2', ${conditionName}: { margin: '4' } })`]
|
|
6090
3200
|
};
|
|
6091
3201
|
})
|
|
6092
3202
|
};
|
|
6093
3203
|
};
|
|
6094
3204
|
//#endregion
|
|
6095
3205
|
//#region src/spec/keyframes.ts
|
|
6096
|
-
const generateKeyframeJsxExamples = (name, jsxStyleProps = "all") => {
|
|
6097
|
-
const jsxExamples = [];
|
|
6098
|
-
const example1 = generateJsxExample({ animationName: name }, jsxStyleProps);
|
|
6099
|
-
if (example1) jsxExamples.push(example1);
|
|
6100
|
-
const example2 = generateJsxExample({ animation: `${name} 1s ease-in-out infinite` }, jsxStyleProps);
|
|
6101
|
-
if (example2) jsxExamples.push(example2);
|
|
6102
|
-
return jsxExamples;
|
|
6103
|
-
};
|
|
6104
3206
|
const generateKeyframesSpec = (ctx) => {
|
|
6105
|
-
const jsxStyleProps = ctx.config.jsxStyleProps;
|
|
6106
3207
|
return {
|
|
6107
3208
|
type: "keyframes",
|
|
6108
3209
|
data: Object.keys(ctx.config.theme?.keyframes ?? {}).map((name) => ({
|
|
6109
3210
|
name,
|
|
6110
|
-
functionExamples: [`css({ animationName: '${name}' })`, `css({ animation: '${name} 1s ease-in-out infinite' })`]
|
|
6111
|
-
jsxExamples: generateKeyframeJsxExamples(name, jsxStyleProps)
|
|
3211
|
+
functionExamples: [`css({ animationName: '${name}' })`, `css({ animation: '${name} 1s ease-in-out infinite' })`]
|
|
6112
3212
|
}))
|
|
6113
3213
|
};
|
|
6114
3214
|
};
|
|
6115
3215
|
//#endregion
|
|
6116
3216
|
//#region src/spec/layer-styles.ts
|
|
6117
3217
|
const generateLayerStylesSpec = (ctx) => {
|
|
6118
|
-
return generateCompositionStyleSpec("layer-styles", ctx.config.theme
|
|
3218
|
+
return generateCompositionStyleSpec("layer-styles", ctx.config.theme);
|
|
6119
3219
|
};
|
|
6120
3220
|
//#endregion
|
|
6121
3221
|
//#region src/spec/patterns.ts
|
|
@@ -6127,22 +3227,16 @@ const getExampleValue = (prop) => {
|
|
|
6127
3227
|
return "<value>";
|
|
6128
3228
|
};
|
|
6129
3229
|
const generatePatternsSpec = (ctx) => {
|
|
6130
|
-
const jsxStyleProps = ctx.config.jsxStyleProps;
|
|
6131
3230
|
return {
|
|
6132
3231
|
type: "patterns",
|
|
6133
3232
|
data: ctx.patterns.details.map((node) => {
|
|
6134
3233
|
const patternName = node.baseName;
|
|
6135
|
-
const jsxName = node.jsxName;
|
|
6136
3234
|
const properties = Object.entries(node.config.properties ?? {});
|
|
6137
3235
|
const functionExamples = [];
|
|
6138
|
-
|
|
6139
|
-
|
|
6140
|
-
functionExamples.push(`${patternName}()`);
|
|
6141
|
-
if (jsxStyleProps !== "none") jsxExamples.push(`<${jsxName} />`);
|
|
6142
|
-
} else properties.forEach(([propName, prop]) => {
|
|
3236
|
+
if (properties.length === 0) functionExamples.push(`${patternName}()`);
|
|
3237
|
+
else properties.forEach(([propName, prop]) => {
|
|
6143
3238
|
const exampleValue = getExampleValue(prop);
|
|
6144
3239
|
functionExamples.push(`${patternName}({ ${propName}: ${exampleValue} })`);
|
|
6145
|
-
if (jsxStyleProps !== "none") jsxExamples.push(`<${jsxName} ${propName}={${exampleValue}} />`);
|
|
6146
3240
|
});
|
|
6147
3241
|
const defaultValues = typeof node.config.defaultValues === "object" ? node.config.defaultValues : {};
|
|
6148
3242
|
return {
|
|
@@ -6154,9 +3248,7 @@ const generatePatternsSpec = (ctx) => {
|
|
|
6154
3248
|
description: prop.description,
|
|
6155
3249
|
defaultValue: defaultValues[name]
|
|
6156
3250
|
})),
|
|
6157
|
-
|
|
6158
|
-
functionExamples,
|
|
6159
|
-
jsxExamples
|
|
3251
|
+
functionExamples
|
|
6160
3252
|
};
|
|
6161
3253
|
})
|
|
6162
3254
|
};
|
|
@@ -6178,28 +3270,17 @@ const generateRecipesSpec = (ctx) => {
|
|
|
6178
3270
|
type: "recipes",
|
|
6179
3271
|
data: ctx.recipes.details.map((node) => {
|
|
6180
3272
|
const recipeName = node.baseName;
|
|
6181
|
-
const jsxName = node.jsxName;
|
|
6182
3273
|
const variantKeys = Object.keys(node.variantKeyMap);
|
|
6183
3274
|
const functionExamples = [];
|
|
6184
|
-
|
|
6185
|
-
|
|
6186
|
-
functionExamples.push(`${recipeName}()`);
|
|
6187
|
-
jsxExamples.push(`<${jsxName} />`);
|
|
6188
|
-
} else {
|
|
3275
|
+
if (variantKeys.length === 0) functionExamples.push(`${recipeName}()`);
|
|
3276
|
+
else {
|
|
6189
3277
|
variantKeys.forEach((variantKey) => {
|
|
6190
3278
|
const firstValue = getFirstVariantValue(node.variantKeyMap, variantKey);
|
|
6191
|
-
if (firstValue) {
|
|
6192
|
-
functionExamples.push(`${recipeName}({ ${variantKey}: ${formatFunctionValue(firstValue)} })`);
|
|
6193
|
-
jsxExamples.push(`<${jsxName} ${variantKey}=${formatJsxValue(firstValue)} />`);
|
|
6194
|
-
}
|
|
3279
|
+
if (firstValue) functionExamples.push(`${recipeName}({ ${variantKey}: ${formatFunctionValue(firstValue)} })`);
|
|
6195
3280
|
});
|
|
6196
3281
|
if (variantKeys.length > 1) {
|
|
6197
3282
|
const props = buildVariantProps(variantKeys, node.variantKeyMap, buildFunctionProps, ", ");
|
|
6198
|
-
|
|
6199
|
-
if (props && jsxProps) {
|
|
6200
|
-
functionExamples.push(`${recipeName}({ ${props} })`);
|
|
6201
|
-
jsxExamples.push(`<${jsxName} ${jsxProps} />`);
|
|
6202
|
-
}
|
|
3283
|
+
if (props) functionExamples.push(`${recipeName}({ ${props} })`);
|
|
6203
3284
|
}
|
|
6204
3285
|
}
|
|
6205
3286
|
return {
|
|
@@ -6207,8 +3288,7 @@ const generateRecipesSpec = (ctx) => {
|
|
|
6207
3288
|
description: node.config.description,
|
|
6208
3289
|
variants: node.variantKeyMap,
|
|
6209
3290
|
defaultVariants: node.config.defaultVariants ?? {},
|
|
6210
|
-
functionExamples
|
|
6211
|
-
jsxExamples
|
|
3291
|
+
functionExamples
|
|
6212
3292
|
};
|
|
6213
3293
|
})
|
|
6214
3294
|
};
|
|
@@ -6216,7 +3296,7 @@ const generateRecipesSpec = (ctx) => {
|
|
|
6216
3296
|
//#endregion
|
|
6217
3297
|
//#region src/spec/text-styles.ts
|
|
6218
3298
|
const generateTextStylesSpec = (ctx) => {
|
|
6219
|
-
return generateCompositionStyleSpec("text-styles", ctx.config.theme
|
|
3299
|
+
return generateCompositionStyleSpec("text-styles", ctx.config.theme);
|
|
6220
3300
|
};
|
|
6221
3301
|
//#endregion
|
|
6222
3302
|
//#region src/spec/token-examples.ts
|
|
@@ -6245,26 +3325,21 @@ const CATEGORY_PROPERTY_MAP = {
|
|
|
6245
3325
|
const getCategoryProperty = (category) => {
|
|
6246
3326
|
return category ? CATEGORY_PROPERTY_MAP[category] ?? "color" : "color";
|
|
6247
3327
|
};
|
|
6248
|
-
const generateTokenExamples = (token
|
|
3328
|
+
const generateTokenExamples = (token) => {
|
|
6249
3329
|
const prop = getCategoryProperty(token.extensions?.category);
|
|
6250
3330
|
const tokenName = token.extensions.prop;
|
|
6251
3331
|
const fullTokenName = token.name;
|
|
6252
3332
|
const functionExamples = [`css({ ${prop}: '${tokenName}' })`];
|
|
6253
3333
|
const tokenFunctionExamples = [`token('${fullTokenName}')`];
|
|
6254
|
-
const jsxExamples = [];
|
|
6255
|
-
const jsxExample = generateJsxExample({ [prop]: tokenName }, jsxStyleProps);
|
|
6256
|
-
if (jsxExample) jsxExamples.push(jsxExample);
|
|
6257
3334
|
if (token.extensions.varRef) tokenFunctionExamples.push(`token.var('${fullTokenName}')`);
|
|
6258
3335
|
return {
|
|
6259
3336
|
functionExamples,
|
|
6260
|
-
tokenFunctionExamples
|
|
6261
|
-
jsxExamples
|
|
3337
|
+
tokenFunctionExamples
|
|
6262
3338
|
};
|
|
6263
3339
|
};
|
|
6264
3340
|
//#endregion
|
|
6265
3341
|
//#region src/spec/themes.ts
|
|
6266
3342
|
const generateThemeTokenGroups = (ctx, themeName, filterFn) => {
|
|
6267
|
-
const jsxStyleProps = ctx.config.jsxStyleProps;
|
|
6268
3343
|
const condName = "_theme" + (0, _bamboocss_shared.capitalize)(themeName);
|
|
6269
3344
|
const themeTokens = ctx.tokens.allTokens.filter((token) => token.extensions.isVirtual && token.extensions.theme === themeName && filterFn(token));
|
|
6270
3345
|
const byCategory = /* @__PURE__ */ new Map();
|
|
@@ -6277,7 +3352,7 @@ const generateThemeTokenGroups = (ctx, themeName, filterFn) => {
|
|
|
6277
3352
|
return Array.from(byCategory.entries()).map(([category, typeTokens]) => {
|
|
6278
3353
|
if (!typeTokens.length) return null;
|
|
6279
3354
|
const firstToken = typeTokens[0];
|
|
6280
|
-
const { functionExamples, tokenFunctionExamples
|
|
3355
|
+
const { functionExamples, tokenFunctionExamples } = generateTokenExamples(firstToken);
|
|
6281
3356
|
return {
|
|
6282
3357
|
type: category,
|
|
6283
3358
|
values: typeTokens.map((token) => {
|
|
@@ -6297,8 +3372,7 @@ const generateThemeTokenGroups = (ctx, themeName, filterFn) => {
|
|
|
6297
3372
|
};
|
|
6298
3373
|
}),
|
|
6299
3374
|
tokenFunctionExamples,
|
|
6300
|
-
functionExamples
|
|
6301
|
-
jsxExamples
|
|
3375
|
+
functionExamples
|
|
6302
3376
|
};
|
|
6303
3377
|
}).filter(Boolean);
|
|
6304
3378
|
};
|
|
@@ -6319,14 +3393,13 @@ const generateThemesSpec = (ctx) => {
|
|
|
6319
3393
|
//#endregion
|
|
6320
3394
|
//#region src/spec/tokens.ts
|
|
6321
3395
|
const generateTokensSpec = (ctx) => {
|
|
6322
|
-
const jsxStyleProps = ctx.config.jsxStyleProps;
|
|
6323
3396
|
return {
|
|
6324
3397
|
type: "tokens",
|
|
6325
3398
|
data: Array.from(ctx.tokens.view.categoryMap.entries()).map(([category, tokenMap]) => {
|
|
6326
3399
|
const typeTokens = Array.from(tokenMap.values()).filter((token) => !token.extensions.isSemantic && !token.extensions.isVirtual && !token.extensions.conditions && !token.extensions.isNegative);
|
|
6327
3400
|
if (!typeTokens.length) return null;
|
|
6328
3401
|
const firstToken = typeTokens[0];
|
|
6329
|
-
const { functionExamples, tokenFunctionExamples
|
|
3402
|
+
const { functionExamples, tokenFunctionExamples } = generateTokenExamples(firstToken);
|
|
6330
3403
|
return {
|
|
6331
3404
|
type: category,
|
|
6332
3405
|
values: typeTokens.map((token) => ({
|
|
@@ -6337,21 +3410,19 @@ const generateTokensSpec = (ctx) => {
|
|
|
6337
3410
|
cssVar: token.extensions.varRef
|
|
6338
3411
|
})),
|
|
6339
3412
|
tokenFunctionExamples,
|
|
6340
|
-
functionExamples
|
|
6341
|
-
jsxExamples
|
|
3413
|
+
functionExamples
|
|
6342
3414
|
};
|
|
6343
3415
|
}).filter(Boolean)
|
|
6344
3416
|
};
|
|
6345
3417
|
};
|
|
6346
3418
|
const generateSemanticTokensSpec = (ctx) => {
|
|
6347
|
-
const jsxStyleProps = ctx.config.jsxStyleProps;
|
|
6348
3419
|
return {
|
|
6349
3420
|
type: "semantic-tokens",
|
|
6350
3421
|
data: Array.from(ctx.tokens.view.categoryMap.entries()).map(([category, tokenMap]) => {
|
|
6351
3422
|
const typeTokens = Array.from(tokenMap.values()).filter((token) => (token.extensions.isSemantic || token.extensions.conditions) && !token.extensions.isVirtual);
|
|
6352
3423
|
if (!typeTokens.length) return null;
|
|
6353
3424
|
const firstToken = typeTokens[0];
|
|
6354
|
-
const { functionExamples, tokenFunctionExamples
|
|
3425
|
+
const { functionExamples, tokenFunctionExamples } = generateTokenExamples(firstToken);
|
|
6355
3426
|
return {
|
|
6356
3427
|
type: category,
|
|
6357
3428
|
values: typeTokens.map((token) => {
|
|
@@ -6371,8 +3442,7 @@ const generateSemanticTokensSpec = (ctx) => {
|
|
|
6371
3442
|
};
|
|
6372
3443
|
}),
|
|
6373
3444
|
tokenFunctionExamples,
|
|
6374
|
-
functionExamples
|
|
6375
|
-
jsxExamples
|
|
3445
|
+
functionExamples
|
|
6376
3446
|
};
|
|
6377
3447
|
}).filter(Boolean)
|
|
6378
3448
|
};
|
|
@@ -6538,6 +3608,20 @@ var Generator = class extends _bamboocss_core.Context {
|
|
|
6538
3608
|
getParserCss = (decoder) => {
|
|
6539
3609
|
return generateParserCss(this, decoder);
|
|
6540
3610
|
};
|
|
3611
|
+
/**
|
|
3612
|
+
* The grouped class names this build emitted a rule for.
|
|
3613
|
+
*
|
|
3614
|
+
* Derived from the encoder rather than the decoder, so it is available as soon as
|
|
3615
|
+
* extraction finishes and before a stylesheet exists. Both sides go through
|
|
3616
|
+
* `groupClassName`, which is the same function the browser runtime calls — a registry
|
|
3617
|
+
* built any other way would be a third spelling of a name that already has two.
|
|
3618
|
+
*
|
|
3619
|
+
* Unescaped, unlike `StyleDecoder`'s class names: this is compared against what `css()`
|
|
3620
|
+
* returns into a `class` attribute, not against a selector. A grouped class is an opaque
|
|
3621
|
+
* hash, so the two only differ in principle, but the principle is the one that matters
|
|
3622
|
+
* here — the registry is only useful if it holds exactly what the runtime will ask about.
|
|
3623
|
+
*/
|
|
3624
|
+
getGroupRegistry = () => collectGroupClassNames(this);
|
|
6541
3625
|
getCss = (stylesheet) => {
|
|
6542
3626
|
let css = (stylesheet ?? this.createSheet()).toCss({ minify: this.config.minify });
|
|
6543
3627
|
if (this.hooks["cssgen:done"]) css = this.hooks["cssgen:done"]({
|
|
@@ -6681,5 +3765,7 @@ var Generator = class extends _bamboocss_core.Context {
|
|
|
6681
3765
|
};
|
|
6682
3766
|
};
|
|
6683
3767
|
//#endregion
|
|
3768
|
+
exports.GROUP_REGISTRY_FILE = GROUP_REGISTRY_FILE;
|
|
6684
3769
|
exports.Generator = Generator;
|
|
3770
|
+
exports.generateGroupRegistry = generateGroupRegistry;
|
|
6685
3771
|
exports.getThemeCss = getThemeCss;
|