@bamboocss/generator 1.14.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.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Context, Recipes, expandNestedCss, extractParentSelectors, extractTrailingPseudos, pruneKeyframes, pruneTokenVars, stringify } from "@bamboocss/core";
2
2
  import { logger } from "@bamboocss/logger";
3
- import { BambooError, capitalize, compact, cssVarRefs, dashCase, isBoolean, isObject, mapEntries, unionType, uniq, walkObject } from "@bamboocss/shared";
3
+ import { BambooError, capitalize, compact, cssVarRefs, dashCase, groupClassName, isBoolean, isObject, mapEntries, unionType, walkObject } from "@bamboocss/shared";
4
4
  import { match } from "ts-pattern";
5
5
  import outdent$1, { outdent } from "outdent";
6
6
  import { stringify as stringify$1 } from "javascript-stringify";
@@ -81,43 +81,13 @@ function generateConditions(ctx) {
81
81
  };
82
82
  }
83
83
  //#endregion
84
- //#region src/artifacts/js/conditions.string-literal.ts
85
- function generateStringLiteralConditions(ctx) {
86
- return {
87
- js: outdent$1`
88
- ${ctx.file.import("withoutSpace", "../helpers")}
89
-
90
- export const isCondition = (val) => condRegex.test(val)
91
-
92
- const condRegex = /^@|&|&$/
93
- const selectorRegex = /&|@/
94
-
95
- export const finalizeConditions = (paths) => {
96
- return paths.map((path) => (selectorRegex.test(path) ? \`[\${withoutSpace(path.trim())}]\` : path))
97
- }
98
-
99
- export function sortConditions(paths){
100
- return paths.sort((a, b) => {
101
- const aa = isCondition(a)
102
- const bb = isCondition(b)
103
- if (aa && !bb) return 1
104
- if (!aa && bb) return -1
105
- return 0
106
- })
107
- }
108
- `,
109
- dts: outdent$1`
110
- `
111
- };
112
- }
113
- //#endregion
114
84
  //#region src/artifacts/js/css-fn.ts
115
85
  function generateCssFn(ctx) {
116
86
  const { utility, hash, prefix, conditions } = ctx;
117
87
  const { separator, getPropShorthands } = utility;
118
88
  return {
119
89
  dts: outdent`
120
- ${ctx.file.importType("SystemStyleObject", "../types/index")}
90
+ ${ctx.file.importType("SystemStyleObject, ViewTransitionFn", "../types/index")}
121
91
 
122
92
  type Styles = SystemStyleObject | undefined | null | false
123
93
 
@@ -154,6 +124,24 @@ function generateCssFn(ctx) {
154
124
  */
155
125
  export declare function fallback(preferred: string | number, ...rest: Array<string | number>): \`fallback(\${string})\`;
156
126
 
127
+ /**
128
+ * Style the View Transitions API and get back one stable class for the bag.
129
+ *
130
+ * The class is applied through \`view-transition-class\`, so the same transition can be
131
+ * shared by any number of elements. You still set \`view-transition-name\` yourself —
132
+ * it has to be unique per element, so bamboo cannot share it for you.
133
+ *
134
+ * @example
135
+ * const slide = viewTransition({
136
+ * group: { animationDuration: '0.4s' },
137
+ * old: { animationName: 'slide-out' },
138
+ * new: { animationName: 'slide-in' },
139
+ * })
140
+ *
141
+ * @see https://bamboocss.com/docs/concepts/view-transitions
142
+ */
143
+ export declare const viewTransition: ViewTransitionFn;
144
+
157
145
  /**
158
146
  * Internal. Emitted for the source transform, which rewrites a single dynamic style
159
147
  * leaf into a call to this. Not part of the authoring API.
@@ -161,8 +149,8 @@ function generateCssFn(ctx) {
161
149
  export declare const cssLeaf: (prefix: string, prop: string, value: unknown) => string;
162
150
  `,
163
151
  js: outdent`
164
- ${ctx.file.import("cloneStyles, createCss, createMergeCss, hypenateProperty, leafClass, memo, withoutSpace", "../helpers")}
165
- ${ctx.file.import("sortConditions, finalizeConditions", "./conditions")}
152
+ ${ctx.file.import("cloneStyles, createCss, createMergeCss, hypenateProperty, leafClass, memo, viewTransitionClassName, withoutSpace", "../helpers")}
153
+ ${[ctx.file.import("sortConditions, finalizeConditions", "./conditions"), ctx.config.cssMode === "grouped" ? ctx.file.import("groups", "./groups") : ""].filter(Boolean).join("\n")}
166
154
 
167
155
  const utilities = "${utility.entries().map(([prop, className]) => {
168
156
  const shorthandList = getPropShorthands(prop);
@@ -192,7 +180,7 @@ function generateCssFn(ctx) {
192
180
  `}
193
181
 
194
182
  const context = {
195
- ${[hash.className && "hash: true,", ctx.config.cssMode === "grouped" && "grouped: true,"].filter(Boolean).join("\n ")}
183
+ ${[hash.className && "hash: true,", ctx.config.cssMode === "grouped" && "grouped: true,\n knownGroups: groups,"].filter(Boolean).join("\n ")}
196
184
  conditions: {
197
185
  shift: sortConditions,
198
186
  finalize: finalizeConditions,
@@ -217,6 +205,7 @@ function generateCssFn(ctx) {
217
205
  // condition object would otherwise poison it for everyone after them.
218
206
  css.raw = (...styles) => cloneStyles(mergeCss(...styles))
219
207
 
208
+
220
209
  // Emitted for the source transform, which rewrites a single dynamic style leaf into a
221
210
  // call to this rather than leaving a \`css()\` behind. \`prefix\` is the class up to the
222
211
  // value, resolved at build time; \`prop\` is only used for the shapes \`leafClass\`
@@ -231,82 +220,30 @@ function generateCssFn(ctx) {
231
220
  // value reaching \`css()\` is the same literal either way.
232
221
  export const fallback = (...values) => \`fallback($\{values.join(', ')})\`
233
222
 
234
- export const { mergeCss, assignCss } = createMergeCss(context)
235
- `
236
- };
237
- }
238
- //#endregion
239
- //#region src/artifacts/js/css-fn.string-literal.ts
240
- function generateStringLiteralCssFn(ctx) {
241
- const { utility, hash, prefix } = ctx;
242
- const { separator } = utility;
243
- return {
244
- dts: outdent`
245
- ${ctx.file.importType("SystemStyleObject", "../types/index")}
246
-
247
- type Styles =
248
- | { raw: readonly string[] | ArrayLike<string> }
249
- | SystemStyleObject
250
- | boolean
251
- | null
252
- | undefined
253
-
254
- interface CssRawFunction {
255
- (...styles: Styles[]): SystemStyleObject
256
- }
257
-
258
- interface CssFunction {
259
- (...styles: Styles[]): string
260
-
261
- raw: CssRawFunction
262
- }
263
-
264
- export declare const css: CssFunction;
265
- `,
266
- js: outdent`
267
- ${ctx.file.import("astish, cloneStyles, createCss, isObject, mergeProps, withoutSpace", "../helpers")}
268
- ${ctx.file.import("finalizeConditions, sortConditions", "./conditions")}
269
-
270
- function transform(prop, value) {
271
- const className = \`$\{prop}${separator}$\{withoutSpace(value)}\`
272
- return { className }
273
- }
274
-
275
- const context = {
276
- hash: ${hash.className ? "true" : "false"},
277
- conditions: {
278
- shift: sortConditions,
279
- finalize: finalizeConditions,
280
- breakpoints: { keys: [] },
281
- },
282
- utility: {
283
- prefix: ${prefix.className ? JSON.stringify(prefix.className) : void 0},
284
- transform,
285
- hasShorthand: false,
286
- toHash: ${utility.toHash},
287
- resolveShorthand(prop) {
288
- return prop
289
- },
290
- }
291
- }
292
-
293
- const cssFn = createCss(context)
223
+ // The class is the whole return value — the CSS behind it was emitted at build time
224
+ // from the same options, hashed by this same function. A call the extractor never saw
225
+ // still returns a class, exactly as \`css()\` does for a value it never saw.
226
+ export const viewTransition = (options) => viewTransitionClassName(options, ${JSON.stringify(prefix.className ?? "")})
294
227
 
295
- const fn = (style) => (isObject(style) ? style : astish(style[0]))
296
- export const css = (...styles) => cssFn(mergeProps(...styles.filter(Boolean).map(fn)))
297
- // Same independence guarantee as the object-syntax css.raw(), so the public
298
- // API behaves identically across both syntaxes.
299
- css.raw = (...styles) => cloneStyles(mergeProps(...styles.filter(Boolean).map(fn)))
228
+ export const { mergeCss, assignCss } = createMergeCss(context)
300
229
  `
301
230
  };
302
231
  }
303
232
  //#endregion
304
233
  //#region src/artifacts/js/cva.ts
305
234
  function generateCvaFn(ctx) {
235
+ const { utility, hash, prefix } = ctx;
236
+ const withPrefix = prefix.className ? `(className) => className ? ${JSON.stringify(prefix.className)} + '-' + className : ${JSON.stringify(prefix.className)}` : `(className) => className`;
306
237
  return {
307
238
  js: outdent`
308
- ${ctx.file.import("cloneStyles, compact, mergeProps, memo, splitProps, uniq", "../helpers")}
309
- ${ctx.file.import("css, mergeCss", "./css")}
239
+ ${ctx.file.import("cloneStyles, compact, getRecipeClassNames, getRecipeIdentity, mergeProps, memo, splitProps, toHash, uniq", "../helpers")}
240
+ ${ctx.file.import("mergeCss", "./css")}
241
+
242
+ // What \`createCss\` does to a class name, for the recipe path: prefix it, and hash it
243
+ // when \`hash.className\` is set. The build applies the same two steps to the rules it
244
+ // emits — see \`checkNamingAgreement\`, which compares the results.
245
+ const withPrefix = ${withPrefix}
246
+ const formatRecipeClass = ${hash.className ? `(className) => withPrefix((${utility.toHash})([className], toHash))` : `withPrefix`}
310
247
 
311
248
  const defaults = (conf) => ({
312
249
  base: {},
@@ -320,6 +257,11 @@ function generateCvaFn(ctx) {
320
257
  const { base, variants, defaultVariants, compoundVariants } = defaults(config)
321
258
  const getVariantProps = (variants) => ({ ...defaultVariants, ...compact(variants) })
322
259
 
260
+ // Derived from the config, because the build derives it from the same config while
261
+ // emitting the stylesheet and the two never meet. \`className\` when the author set
262
+ // one, a hash of the styles otherwise.
263
+ const name = getRecipeIdentity(config)
264
+
323
265
  function resolve(props = {}) {
324
266
  const computedVariants = getVariantProps(props)
325
267
  let variantCss = { ...base }
@@ -328,6 +270,13 @@ function generateCvaFn(ctx) {
328
270
  variantCss = mergeCss(variantCss, variants[key][value])
329
271
  }
330
272
  }
273
+ // A recipe with no compound variants has nothing left to merge, and the merge is
274
+ // not free just because its second operand is empty: \`mergeCss\` is memoized on its
275
+ // arguments, so the call hashes the whole accumulated style object before finding
276
+ // there is nothing to do. Most recipes declare no compound variants at all, so
277
+ // this is the common shape rather than a special case.
278
+ if (compoundVariants.length === 0) return variantCss
279
+
331
280
  const compoundVariantCss = getCompoundVariantCss(compoundVariants, computedVariants)
332
281
  return mergeCss(variantCss, compoundVariantCss)
333
282
  }
@@ -352,10 +301,25 @@ function generateCvaFn(ctx) {
352
301
  //
353
302
  // \`raw\` still clones what it returns. The memoized object is shared, so handing it to a
354
303
  // caller that mutated it would poison every later call.
304
+ //
305
+ // A recipe whose variants are all boolean could index an array instead of hashing, and
306
+ // that was built and measured: +25% to +35% on \`raw()\`. It is not here because the
307
+ // trade is bad. Correctness needs the selection read from own enumerable keys only, and
308
+ // every variant to carry a boolean default so the merge order is pinned — and once that
309
+ // gate is honest, no \`cva\`/\`sva\` call site in this repo passes it, because real recipes
310
+ // mix a string variant in. The cost is unconditional: +289 B gzipped on that module for
311
+ // every consumer, qualifying or not.
355
312
  const resolveVariants = memo(resolve)
356
313
 
314
+ // The class names the build emitted rules for: the recipe's own class, plus one per
315
+ // selected variant. Not \`css(resolve(props))\` — that would name classes by property,
316
+ // and the stylesheet names this recipe's rules semantically, in the \`recipes\` layer.
317
+ //
318
+ // Compound variants are absent on purpose. Their rule selects on the variant classes
319
+ // already in this list — \`.btn--size_sm.btn--tone_a\` — so it applies without anything
320
+ // being added here, and adding a class for it would name a rule that does not exist.
357
321
  function cvaFn(props) {
358
- return css(resolve(props))
322
+ return getRecipeClassNames(name, variants, getVariantProps(props), '${utility.separator}', formatRecipeClass)
359
323
  }
360
324
 
361
325
  const variantKeys = Object.keys(variants)
@@ -414,36 +378,55 @@ function generateCvaFn(ctx) {
414
378
  }
415
379
  //#endregion
416
380
  //#region src/artifacts/js/cx.ts
417
- const dts = outdent$1`
381
+ /**
382
+ * `cx` joins class names. It does not resolve conflicts between them, in any build.
383
+ *
384
+ * It used to, when the class names happened to carry a property to compare — atomic mode
385
+ * with `hash.className` off. That made it a correctness tool in development and a plain
386
+ * join in a hashed production build, from the same source, with no error either way. An
387
+ * override that worked locally silently stopped working when it shipped.
388
+ *
389
+ * The two could not be reconciled by teaching the matcher to read hashed names.
390
+ * `cssMode: 'grouped'` names a *whole call* with one class — `toHash(['grouped', groupId])`
391
+ * — so there is no single property behind it to compare, whatever the naming scheme. As
392
+ * long as grouped exists, some builds can never merge, and a `cx` that merges in the rest
393
+ * is a behavioural difference keyed on a config flag.
394
+ *
395
+ * So precedence is decided where it can be decided the same way everywhere: by
396
+ * {@link https://bamboocss.com/docs/concepts/cascade-layers cascade layers}. A component
397
+ * whose styles a consumer will override belongs in `recipes` — write it with `cva`/`sva`,
398
+ * not bare `css()` — and the consumer's `css()` in `utilities` wins by layer, in every
399
+ * build. Two `css()` outputs joined with `cx` are in the same layer and resolve by source
400
+ * order; when you own both, merge the style objects with `css(a, b)` instead.
401
+ */
402
+ const declaration = outdent$1`
418
403
  type Argument = string | boolean | null | undefined | Argument[]
419
404
 
420
405
  /**
421
- * Join classNames into a single string, with the last conflicting utility winning.
406
+ * Join classNames into a single string.
422
407
  *
423
- * \`cx('px_4', 'px_2')\` is \`'px_2'\`: two classes that set the same property under the
424
- * same conditions cannot both apply, and which one the browser picks would otherwise
425
- * depend on their order in the stylesheet rather than on the order you passed them.
426
- * Classes bamboo did not generate are left alone, duplicates included.
408
+ * This does **not** resolve conflicts between them: \`cx('px_4', 'px_2')\` keeps both, and
409
+ * the browser picks by their order in the stylesheet rather than by the order you passed
410
+ * them. That is true of every build — atomic, hashed and grouped alike.
411
+ *
412
+ * To override a style rather than append to it, let the cascade decide: styles from
413
+ * \`cva\`/\`sva\` sit in the \`recipes\` layer and \`css()\` in \`utilities\`, so a consumer's
414
+ * \`css()\` always wins. Between two \`css()\` calls you own, merge the objects instead —
415
+ * \`css(base, override)\` resolves per property before any class name exists.
427
416
  */
428
417
  export declare function cx(...args: Argument[]): string
429
418
  `;
430
- /**
431
- * The plain concatenating \`cx\`, for when the class names carry nothing to merge on.
432
- *
433
- * With \`hash.className\` every class is an opaque hash, so there is no property to compare
434
- * and no merge to do — emitting the matcher would only cost bytes on a path that runs in
435
- * the browser on every render.
436
- */
437
- function concatOnly() {
438
- return outdent$1`
419
+ function generateCx() {
420
+ return {
421
+ js: outdent$1`
439
422
  function cx(...args) {
440
423
  let str = ''
441
424
 
442
425
  for (let i = 0; i < args.length; i++) {
443
426
  const arg = args[i]
444
427
  if (!arg) continue
445
- // Arrays are part of the declared type, so this branch has to handle them even
446
- // though it does no merging — returning '' for \`cx(['a', 'b'])\` would be a lie.
428
+ // Arrays are part of the declared type, so this branch has to handle them.
429
+ // Returning '' for \`cx(['a', 'b'])\` would be a lie.
447
430
  const part = Array.isArray(arg) ? cx(...arg) : typeof arg === 'string' ? arg : ''
448
431
  if (!part) continue
449
432
  str && (str += ' ')
@@ -453,185 +436,18 @@ function concatOnly() {
453
436
  }
454
437
 
455
438
  export { cx }
456
- `;
457
- }
458
- function generateCx(ctx) {
459
- const { utility, hash, prefix } = ctx;
460
- const separatorChar = utility.separator;
461
- const utilityClassNames = [...new Set(utility.keys().map((key) => {
462
- const withEmptyValue = utility.getClassName(utility.resolveShorthand(key), "");
463
- return withEmptyValue.endsWith(separatorChar) ? withEmptyValue.slice(0, -separatorChar.length) : withEmptyValue;
464
- }))].sort();
465
- const recipeClassNames = [...new Set(ctx.recipes.details.map((node) => node.className))].filter(Boolean).sort();
466
- if (hash.className || utilityClassNames.length === 0) return {
467
- js: concatOnly(),
468
- dts
469
- };
470
- return {
471
- js: outdent$1`
472
- const cxSeparator = ${JSON.stringify(utility.separator)}
473
- const cxPrefix = ${prefix.className ? JSON.stringify(prefix.className + "-") : "''"}
474
- const cxUtilities = new Set(${JSON.stringify(utilityClassNames.join(","))}.split(','))
475
- const cxRecipes = ${recipeClassNames.length ? `new Set(${JSON.stringify(recipeClassNames.join(","))}.split(','))` : "null"}
476
-
477
- /**
478
- * The declaration a bamboo class sets: its condition path plus the property, without the
479
- * value. Two classes sharing one are alternatives, and only the last can apply.
480
- *
481
- * \`null\` for anything that is not a bamboo class, which is then never merged.
482
- */
483
- function mergeKey(className) {
484
- let end = className.length
485
-
486
- // \`c_red\` and \`c_red!\` are the same declaration. Argument order decides between them,
487
- // which is the point of this function — the cascade would always pick the important
488
- // one no matter which the caller asked for.
489
- if (end > 0 && className.charCodeAt(end - 1) === 33) end -= 1
490
- if (end === 0) return null
491
-
492
- // The last colon ends the condition path — but only one outside brackets, since an
493
- // arbitrary selector carries its own: \`[&[data-x="a:b"]]:px_4\`.
494
- let depth = 0
495
- let lastColon = -1
496
- for (let i = 0; i < end; i++) {
497
- const code = className.charCodeAt(i)
498
- if (code === 91) depth++
499
- else if (code === 93) depth--
500
- else if (code === 58 && depth === 0) lastColon = i
501
- }
502
-
503
- // Conditions come before the prefix — \`hover:bam-px_4\` — so the prefix is skipped
504
- // after the condition path, not before it. When a prefix is configured every class
505
- // bamboo emits carries it, so one that does not is by definition someone else's.
506
- let propStart = lastColon + 1
507
- if (cxPrefix) {
508
- if (!className.startsWith(cxPrefix, propStart)) return null
509
- propStart += cxPrefix.length
510
- }
511
-
512
- // A recipe owns its whole class, bare or with a \`--variant\` suffix, whatever it
513
- // looks like to the utility matcher below.
514
- if (cxRecipes !== null) {
515
- const variantIdx = className.indexOf('--', propStart)
516
- const base = variantIdx === -1 ? className.slice(propStart, end) : className.slice(propStart, variantIdx)
517
- if (cxRecipes.has(base)) return null
518
- }
519
-
520
- // The longest registered utility name wins, not the first separator. Utility names
521
- // contain the separator themselves under \`separator: '-'\` — \`bd-w\`, \`ov-x\`,
522
- // \`translate-x\` — and their leading segment is often a utility too, so stopping at the
523
- // first \`-\` would key \`bd-w-4px\` and \`bd-c-red\` both on \`bd\` and drop one of them.
524
- let property = null
525
- let sepIdx = className.indexOf(cxSeparator, propStart)
526
- while (sepIdx > propStart && sepIdx < end) {
527
- const candidate = className.slice(propStart, sepIdx)
528
- if (cxUtilities.has(candidate)) property = candidate
529
- sepIdx = className.indexOf(cxSeparator, sepIdx + 1)
530
- }
531
-
532
- // Only a class bamboo generated for a utility. A recipe class or a hand-written one
533
- // may well contain the separator, and merging on the text before it would drop a
534
- // class the caller meant to keep.
535
- if (property === null) return null
536
-
537
- return lastColon === -1 ? property : className.slice(0, lastColon) + ':' + property
538
- }
539
-
540
- function isClassWhitespace(code) {
541
- return code === 32 || code === 9 || code === 10 || code === 12 || code === 13
542
- }
543
-
544
- function flattenParts(parts, out) {
545
- for (let i = 0; i < parts.length; i++) {
546
- const part = parts[i]
547
- if (!part) continue
548
- if (Array.isArray(part)) flattenParts(part, out)
549
- else if (typeof part === 'string') out.push(part)
550
- }
551
- }
552
-
553
- function mergeClassStrings(classes) {
554
- const seen = new Map()
555
- const order = []
556
- let id = 0
557
-
558
- for (let c = 0; c < classes.length; c++) {
559
- const cls = classes[c]
560
- let tokenStart = 0
561
-
562
- for (let i = 0; i <= cls.length; i++) {
563
- // The class attribute splits on all ASCII whitespace, not just the space, and a
564
- // multi-line template literal is an ordinary way to write one.
565
- if (i !== cls.length && !isClassWhitespace(cls.charCodeAt(i))) continue
566
- if (i === tokenStart) {
567
- tokenStart = i + 1
568
- continue
569
- }
570
-
571
- const token = cls.slice(tokenStart, i)
572
- tokenStart = i + 1
573
-
574
- const key = mergeKey(token)
575
- if (key !== null) {
576
- // Keeps the first position and the last value, so a later override lands where
577
- // the class it replaces already sat.
578
- if (!seen.has(key)) order.push(key)
579
- seen.set(key, token)
580
- } else {
581
- // Not ours to reason about — kept as written, duplicates and all.
582
- const uniqueKey = '\\0' + id++
583
- order.push(uniqueKey)
584
- seen.set(uniqueKey, token)
585
- }
586
- }
587
- }
588
-
589
- if (order.length === 0) return ''
590
- let str = seen.get(order[0])
591
- for (let i = 1; i < order.length; i++) str += ' ' + seen.get(order[i])
592
- return str
593
- }
594
-
595
- function cx() {
596
- // Everything that produces a bamboo class string — \`css()\`, a recipe, a nested \`cx\` —
597
- // emits one that is already conflict-free, so a lone string has nothing to merge and
598
- // tokenizing it is pure cost. This is the hot path: \`cx(staticClasses, props.className)\`
599
- // with no \`className\` passed.
600
- if (arguments.length === 1) {
601
- const only = arguments[0]
602
- if (typeof only === 'string') return only
603
- if (!only) return ''
604
- }
605
-
606
- const flat = []
607
- flattenParts(arguments, flat)
608
- if (flat.length === 0) return ''
609
- if (flat.length === 1) return flat[0]
610
- return mergeClassStrings(flat)
611
- }
612
-
613
- export { cx }
614
- `,
615
- dts
439
+ `,
440
+ dts: declaration
616
441
  };
617
442
  }
618
443
  //#endregion
619
- //#region src/artifacts/generated/astish.mjs.json
620
- 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";
621
- //#endregion
622
444
  //#region src/artifacts/generated/helpers.mjs.json
623
- 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\nexport { cloneStyles, compact, createCss, createMergeCss, filterBaseConditions, getPatternStyles, getSlotCompoundVariant, getSlotRecipes, hypenateProperty, isBaseCondition, isObject, leafClass, mapObject, memo, mergeProps, patternFns, splitProps, toHash, uniq, walkObject, withoutSpace };\n";
624
- //#endregion
625
- //#region src/artifacts/generated/normalize-html.mjs.json
626
- 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";
445
+ 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";
627
446
  //#endregion
628
447
  //#region src/artifacts/js/helpers.ts
629
- function generateHelpers(ctx) {
448
+ function generateHelpers() {
630
449
  return { js: outdent`
631
- ${content$10}
632
- ${ctx.isTemplateLiteralSyntax ? content$11 : ""}
633
-
634
- ${ctx.jsx.framework ? `${content$9}` : ""}
450
+ ${content$8}
635
451
 
636
452
  export function __spreadValues(a, b) {
637
453
  return { ...a, ...b }
@@ -643,74 +459,6 @@ function generateHelpers(ctx) {
643
459
  ` };
644
460
  }
645
461
  //#endregion
646
- //#region src/artifacts/generated/is-valid-prop.mjs.json
647
- 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";
648
- //#endregion
649
- //#region src/artifacts/js/is-valid-prop.ts
650
- const cssPropListRegex = /const userGenerated = ".*?"\.split\(","\);\s*const allCssProperties = "(.*?)"\.split\(","\)\.concat\(userGenerated\);/;
651
- const memoFnDeclarationRegex = /function memo(?:.+?)\n((?:var|const|let) cssPropertySelectorRegex)/s;
652
- function generateIsValidProp(ctx) {
653
- if (ctx.isTemplateLiteralSyntax) return;
654
- let content = content$8;
655
- const propertyList = content.match(cssPropListRegex);
656
- if (!propertyList) throw new BambooError("NOT_FOUND", "Could not find the property list in the prebuilt is-valid-prop module. Its bundled shape has changed.");
657
- const userProperties = match(ctx.jsx.styleProps).with("all", () => Array.from(ctx.properties)).with("minimal", () => ["css"]).with("none", () => ["css"]).exhaustive();
658
- const browserProperties = ctx.jsx.styleProps === "all" ? propertyList[1].split(",") : [];
659
- content = content.replace(cssPropListRegex, () => `const allCssProperties = "${uniq(browserProperties, userProperties).join(",")}".split(",");`);
660
- content = content.replace(memoFnDeclarationRegex, "$1");
661
- if (ctx.jsx.styleProps === "minimal" || ctx.jsx.styleProps === "none") content = content.replace("/* @__PURE__ */ memo(", "/* @__PURE__ */ (");
662
- else content = ctx.file.import("memo", "../helpers") + "\n" + content;
663
- content = ctx.file.import("splitProps", "../helpers") + "\n" + content;
664
- content += `export const splitCssProps = (props) => splitProps(props, isCssProperty)`;
665
- return {
666
- js: content,
667
- dts: outdent`
668
- import type { DistributiveOmit, HTMLBambooProps, JsxStyleProps, Pretty } from '../types';
669
-
670
- declare const isCssProperty: (value: string) => boolean;
671
-
672
- type CssPropKey = keyof JsxStyleProps
673
- type OmittedCssProps<T> = Pretty<DistributiveOmit<T, CssPropKey>>
674
-
675
- declare const splitCssProps: <T>(props: T) => [JsxStyleProps, OmittedCssProps<T>]
676
-
677
- export { isCssProperty, splitCssProps };
678
- `
679
- };
680
- }
681
- //#endregion
682
- //#region src/artifacts/js/jsx-helper.ts
683
- function generatedJsxHelpers(ctx) {
684
- return { js: match(ctx.isTemplateLiteralSyntax).with(true, () => outdent`
685
- export const getDisplayName = (Component) => {
686
- if (typeof Component === 'string') return Component
687
- return Component?.displayName || Component?.name || 'Component'
688
- }`).otherwise(() => outdent`
689
- ${ctx.file.import("isCssProperty", "./is-valid-prop")}
690
-
691
- export const defaultShouldForwardProp = (prop, variantKeys) => !variantKeys.includes(prop) && !isCssProperty(prop)
692
-
693
- export const composeShouldForwardProps = (tag, shouldForwardProp) =>
694
- tag.__shouldForwardProps__ && shouldForwardProp
695
- ? (propName) => tag.__shouldForwardProps__(propName) && shouldForwardProp(propName)
696
- : shouldForwardProp
697
-
698
- export const composeCvaFn = (cvaA, cvaB) => {
699
- if (cvaA && !cvaB) return cvaA
700
- if (!cvaA && cvaB) return cvaB
701
- if ((cvaA.__cva__ && cvaB.__cva__) || (cvaA.__recipe__ && cvaB.__recipe__)) return cvaA.merge(cvaB)
702
- const error = new TypeError('Cannot merge cva with recipe. Please use either cva or recipe.')
703
- TypeError.captureStackTrace?.(error)
704
- throw error
705
- }
706
-
707
- export const getDisplayName = (Component) => {
708
- if (typeof Component === 'string') return Component
709
- return Component?.displayName || Component?.name || 'Component'
710
- }
711
- `) };
712
- }
713
- //#endregion
714
462
  //#region src/artifacts/js/package-json.ts
715
463
  /**
716
464
  * The generated output is a plain directory, not an installed package, so bundlers
@@ -834,22 +582,12 @@ function generatePattern(ctx, filters) {
834
582
  //#region src/shared.ts
835
583
  const isBooleanValue = (value) => value === "true" || value === "false";
836
584
  const formatFunctionValue = (value) => isBooleanValue(value) ? value : `'${value}'`;
837
- const formatJsxValue = (value) => isBooleanValue(value) ? `{${value}}` : `"${value}"`;
838
585
  const buildFunctionProps = (key, value) => `${key}: ${formatFunctionValue(value)}`;
839
- const buildJsxProps = (key, value) => `${key}=${formatJsxValue(value)}`;
840
586
  const formatProps = (props, options = {}) => {
841
587
  const { keyValueSeparator = ": ", propSeparator = ", ", quoteStyle = "single" } = options;
842
588
  const quote = quoteStyle === "single" ? "'" : quoteStyle === "double" ? "\"" : "";
843
589
  return Object.entries(props).filter(([_, value]) => value != null).map(([key, value]) => `${key}${keyValueSeparator}${quote}${value}${quote}`).join(propSeparator);
844
590
  };
845
- const formatJsxComponent = (component, props) => {
846
- const formattedProps = formatProps(props, {
847
- keyValueSeparator: "=",
848
- propSeparator: " ",
849
- quoteStyle: "double"
850
- });
851
- return `<${component}${formattedProps ? " " + formattedProps : ""} />`;
852
- };
853
591
  const collectCompositionStyles = (values) => {
854
592
  const result = [];
855
593
  walkObject(values, (token, paths) => {
@@ -863,27 +601,6 @@ const collectCompositionStyles = (values) => {
863
601
  }, { stop: (v) => isObject(v) && "value" in v });
864
602
  return result;
865
603
  };
866
- /**
867
- * Generates a single JSX example based on jsxStyleProps setting
868
- */
869
- const generateJsxExample = (props, jsxStyleProps = "all", component = "Box") => {
870
- if (jsxStyleProps === "all") return formatJsxComponent(component, props);
871
- if (jsxStyleProps === "minimal") return `<${component} css={{ ${formatProps(props)} }} />`;
872
- return null;
873
- };
874
- /**
875
- * Generates function and JSX examples for a style property
876
- */
877
- const generateJsxExamples = (props, jsxStyleProps = "all", component = "Box") => {
878
- const functionExamples = [`css({ ${formatProps(props)} })`];
879
- const jsxExamples = [];
880
- const jsxExample = generateJsxExample(props, jsxStyleProps, component);
881
- if (jsxExample) jsxExamples.push(jsxExample);
882
- return {
883
- functionExamples,
884
- jsxExamples
885
- };
886
- };
887
604
  const COMPOSITION_STYLE_CONFIG = {
888
605
  "text-styles": {
889
606
  prop: "textStyle",
@@ -898,14 +615,14 @@ const COMPOSITION_STYLE_CONFIG = {
898
615
  themeKey: "animationStyles"
899
616
  }
900
617
  };
901
- function generateCompositionStyleSpec(type, theme, jsxStyleProps) {
618
+ function generateCompositionStyleSpec(type, theme) {
902
619
  const { prop, themeKey } = COMPOSITION_STYLE_CONFIG[type];
903
620
  return {
904
621
  type,
905
622
  data: collectCompositionStyles(theme?.[themeKey] ?? {}).map((style) => ({
906
623
  name: style.name,
907
624
  description: style.description,
908
- ...generateJsxExamples({ [prop]: style.name }, jsxStyleProps)
625
+ functionExamples: [`css({ ${formatProps({ [prop]: style.name })} })`]
909
626
  }))
910
627
  };
911
628
  }
@@ -924,7 +641,6 @@ function generateCreateRecipe(ctx) {
924
641
  dts: "",
925
642
  js: outdent`
926
643
  ${ctx.file.import("finalizeConditions, sortConditions", "../css/conditions")}
927
- ${ctx.file.import("css", "../css/css")}
928
644
  ${ctx.file.import("assertCompoundVariant, getCompoundVariantCss", "../css/cva")}
929
645
  ${ctx.file.import("cx", "../css/cx")}
930
646
  ${ctx.file.import("compact, createCss, splitProps, uniq, withoutSpace", "../helpers")}
@@ -938,7 +654,7 @@ function generateCreateRecipe(ctx) {
938
654
  };
939
655
  };
940
656
 
941
- const recipeFn = (variants, withCompoundVariants = true) => {
657
+ const recipeFn = (variants) => {
942
658
  const transform = (prop, value) => {
943
659
  assertCompoundVariant(name, compoundVariants, variants, prop)
944
660
 
@@ -966,11 +682,10 @@ function generateCreateRecipe(ctx) {
966
682
 
967
683
  const recipeStyles = getVariantProps(variants)
968
684
 
969
- if (withCompoundVariants) {
970
- const compoundVariantStyles = getCompoundVariantCss(compoundVariants, recipeStyles)
971
- return cx(recipeCss(recipeStyles), css(compoundVariantStyles))
972
- }
973
-
685
+ // No class for the compound variants. Their rule selects on the variant classes
686
+ // \`recipeCss\` just named — \`.btn--size_sm.btn--tone_a\` — so it applies on its own,
687
+ // and it is in the same layer as the rest of the recipe rather than atomically in
688
+ // \`utilities\` above it.
974
689
  return recipeCss(recipeStyles)
975
690
  }
976
691
 
@@ -1022,9 +737,22 @@ function generateRecipes(ctx, filters) {
1022
737
  else defaultValue = JSON.stringify(defaultValue);
1023
738
  return ctx.file.jsDocComment("", { default: defaultValue });
1024
739
  };
740
+ const slotNames = Recipes.isSlotRecipeConfig(config) ? config.slots : [];
741
+ const anchorSlotNames = Recipes.isSlotRecipeConfig(config) ? Recipes.getScopeRoots(config) : [];
1025
742
  return {
1026
743
  name: dashName,
1027
- js: match(config).when(Recipes.isSlotRecipeConfig, (config) => outdent`
744
+ js: match(config).when(Recipes.isSlotRecipeConfig, (config) => {
745
+ const anchors = Recipes.getScopeRoots(config);
746
+ /**
747
+ * Which slots each variant writes styles for.
748
+ *
749
+ * A scope reaches every slot inside an anchor's subtree. A slot under no anchor at
750
+ * all is not reached, and nothing here can detect that — reachability is a fact
751
+ * about the DOM. This is what says which slots a variant has to get to, so the
752
+ * component layer can thread the ones a scope cannot.
753
+ */
754
+ const slotsAffectedBy = Object.fromEntries(Object.entries(config.variants ?? {}).map(([variant, values]) => [variant, Array.from(new Set(Object.values(values ?? {}).flatMap((slotStyles) => Object.keys(slotStyles ?? {}))))]));
755
+ return outdent`
1028
756
  ${ctx.file.import("compact, getSlotCompoundVariant, memo, splitProps", "../helpers")}
1029
757
  ${ctx.file.import("createRecipe", "./create-recipe")}
1030
758
 
@@ -1032,11 +760,27 @@ function generateRecipes(ctx, filters) {
1032
760
  const ${baseName}CompoundVariants = ${stringify$2(compoundVariants ?? [])}
1033
761
 
1034
762
  const ${baseName}SlotNames = ${stringify$2(config.slots.map((slot) => [slot, `${config.className}__${slot}`]))}
763
+ ${anchors.length ? outdent`
764
+ /**
765
+ * Only the anchors take variants: ${anchors.map((slot) => `\`${baseName}.${slot}\``).join(", ")}.
766
+ * Every other slot's variant styles are emitted as rules scoped by a class an anchor
767
+ * carries, so that slot's class is a constant and nothing has to reach it at runtime.
768
+ */
769
+ const ${baseName}Anchors = ${JSON.stringify(anchors)}
770
+ const ${baseName}AnchorFns = /* @__PURE__ */ ${baseName}Anchors.map((slotName) => [slotName, createRecipe(\`${config.className}__\${slotName}\`, ${baseName}DefaultVariants, getSlotCompoundVariant(${baseName}CompoundVariants, slotName))])
771
+ const ${baseName}StaticSlots = /* @__PURE__ */ Object.fromEntries(
772
+ ${baseName}SlotNames.filter(([slotName]) => !${baseName}Anchors.includes(slotName)),
773
+ )
774
+
775
+ const ${baseName}Fn = memo((props = {}) => ({
776
+ ...${baseName}StaticSlots,
777
+ ...Object.fromEntries(${baseName}AnchorFns.map(([slotName, anchorFn]) => [slotName, anchorFn.recipeFn(props)])),
778
+ }))` : outdent`
1035
779
  const ${baseName}SlotFns = /* @__PURE__ */ ${baseName}SlotNames.map(([slotName, slotKey]) => [slotName, createRecipe(slotKey, ${baseName}DefaultVariants, getSlotCompoundVariant(${baseName}CompoundVariants, slotName))])
1036
780
 
1037
781
  const ${baseName}Fn = memo((props = {}) => {
1038
782
  return Object.fromEntries(${baseName}SlotFns.map(([slotName, slotFn]) => [slotName, slotFn.recipeFn(props)]))
1039
- })
783
+ })`}
1040
784
 
1041
785
  const ${baseName}VariantKeys = ${stringify$2(Object.keys(variantKeyMap))}
1042
786
  const getVariantProps = (variants) => ({ ...${baseName}DefaultVariants, ...compact(variants) })
@@ -1045,15 +789,25 @@ function generateRecipes(ctx, filters) {
1045
789
  __recipe__: false,
1046
790
  __name__: '${baseName}',
1047
791
  raw: (props) => props,
1048
- classNameMap: {},
792
+ /** Each slot's constant class, for targeting a slot in the DOM. */
793
+ classNameMap: /* @__PURE__ */ Object.fromEntries(${baseName}SlotNames),
794
+ /** The slots that enclose other slots, and so anchor their variant rules. */
795
+ scopeRoots: ${JSON.stringify(anchors)},
1049
796
  variantKeys: ${baseName}VariantKeys,
1050
797
  variantMap: ${stringify$2(variantKeyMap)},
798
+ /** Which slots each variant actually reaches, for a slot a scope cannot get to. */
799
+ slotsAffectedBy: ${stringify$2(slotsAffectedBy)},
1051
800
  splitVariantProps(props) {
1052
801
  return splitProps(props, ${baseName}VariantKeys)
1053
802
  },
1054
- getVariantProps
803
+ getVariantProps,
804
+ ${anchors.length ? outdent`
805
+ ...Object.fromEntries(${baseName}AnchorFns.map(([slotName, anchorFn]) => [slotName, anchorFn.recipeFn])),
806
+ ...${baseName}StaticSlots,
807
+ ` : ""}
1055
808
  })
1056
- `).otherwise((config) => outdent`
809
+ `;
810
+ }).otherwise((config) => outdent`
1057
811
  ${ctx.file.import("memo, splitProps", "../helpers")}
1058
812
  ${ctx.file.import("createRecipe, mergeRecipes", "./create-recipe")}
1059
813
 
@@ -1110,6 +864,13 @@ function generateRecipes(ctx, filters) {
1110
864
  variantKeys: Array<keyof ${upperName}Variant>
1111
865
  splitVariantProps<Props extends ${upperName}VariantProps>(props: Props): [${upperName}VariantProps, Pretty<DistributiveOmit<Props, keyof ${upperName}VariantProps>>]
1112
866
  getVariantProps: (props?: ${upperName}VariantProps) => ${upperName}VariantProps
867
+ ${Recipes.isSlotRecipeConfig(config) ? outdent`
868
+ /** Which slots each variant writes styles for. */
869
+ slotsAffectedBy: Record<keyof ${upperName}Variant, ${upperName}Slot[]>` : ""}
870
+ ${anchorSlotNames.length ? outdent`
871
+ /** The slots that take variants — every other one is scoped by a class an anchor carries. */
872
+ ${anchorSlotNames.map((slot) => `${slot}: (props?: ${upperName}VariantProps) => string`).join("\n")}
873
+ ${slotNames.filter((slot) => !anchorSlotNames.includes(slot)).map((slot) => `${slot}: string`).join("\n")}` : ""}
1113
874
  }
1114
875
 
1115
876
  ${ctx.file.jsDocComment(description, { deprecated })}
@@ -1123,2819 +884,283 @@ function generateRecipes(ctx, filters) {
1123
884
  function generateSvaFn(ctx) {
1124
885
  return {
1125
886
  js: outdent`
1126
- ${ctx.file.import("compact, getSlotRecipes, memo, splitProps", "../helpers")}
887
+ ${ctx.file.import("compact, getRecipeIdentity, getSlotRecipes, memo, splitProps", "../helpers")}
1127
888
  ${ctx.file.import("cva", "./cva")}
1128
889
  ${ctx.file.import("cx", "./cx")}
1129
890
 
1130
891
  export function sva(config) {
1131
- const slots = Object.entries(getSlotRecipes(config)).map(([slot, slotCva]) => [slot, cva(slotCva)])
892
+ // Named before the split, so each slot's class is \`name__slot\`. Left to
893
+ // \`getSlotRecipes\`, a config with no \`className\` gives every slot the bare slot name
894
+ // — \`root\` — which every other anonymous recipe with a \`root\` slot would share. The
895
+ // build injects the identity at the same point, for the same reason.
896
+ const name = getRecipeIdentity(config, 'sva')
897
+ const withName = { ...config, className: config.className ?? name }
898
+
899
+ const slots = Object.entries(getSlotRecipes(withName)).map(([slot, slotCva]) => [slot, cva(slotCva)])
1132
900
  const defaultVariants = config.defaultVariants ?? {}
1133
901
 
902
+ // Populated whether or not the author set a \`className\`. Every slot recipe is given
903
+ // one before the split — the identity when the config declares none — so the guard
904
+ // that used to sit here left an anonymous \`sva\` reporting no slot classes despite
905
+ // emitting them.
1134
906
  const classNameMap = slots.reduce((acc, [slot, cvaFn]) => {
1135
- if (config.className) acc[slot] = cvaFn.config.className
907
+ acc[slot] = cvaFn.config.className
1136
908
  return acc
1137
909
  }, {})
1138
910
 
1139
- function svaFn(props) {
1140
- const result = slots.map(([slot, cvaFn]) => [slot, cx(cvaFn(props), classNameMap[slot])])
1141
- return Object.fromEntries(result)
1142
- }
1143
-
1144
- function raw(props) {
1145
- const result = slots.map(([slot, cvaFn]) => [slot, cvaFn.raw(props)])
1146
- return Object.fromEntries(result)
1147
- }
1148
-
1149
- const variants = config.variants ?? {};
1150
- const variantKeys = Object.keys(variants);
1151
-
1152
- function splitVariantProps(props) {
1153
- return splitProps(props, variantKeys);
1154
- }
1155
- const getVariantProps = (variants) => ({ ...defaultVariants, ...compact(variants) })
1156
-
1157
- const variantMap = Object.fromEntries(
1158
- Object.entries(variants).map(([key, value]) => [key, Object.keys(value)])
1159
- );
1160
-
1161
- return Object.assign(memo(svaFn), {
1162
- __cva__: false,
1163
- raw,
1164
- config,
1165
- variantMap,
1166
- variantKeys,
1167
- classNameMap,
1168
- splitVariantProps,
1169
- getVariantProps,
1170
- })
1171
- }
1172
- `,
1173
- dts: outdent`
1174
- ${ctx.file.importType("SlotRecipeCreatorFn", "../types/recipe")}
1175
-
1176
- export declare const sva: SlotRecipeCreatorFn
1177
- `
1178
- };
1179
- }
1180
- //#endregion
1181
- //#region src/artifacts/js/token.ts
1182
- function generateTokenJs(ctx) {
1183
- const { tokens } = ctx;
1184
- const map = /* @__PURE__ */ new Map();
1185
- tokens.allTokens.forEach((token) => {
1186
- const { varRef, isVirtual } = token.extensions;
1187
- const value = isVirtual || token.extensions.condition !== "base" ? varRef : token.value;
1188
- map.set(token.name, {
1189
- value,
1190
- variable: varRef
1191
- });
1192
- });
1193
- const obj = Object.fromEntries(map);
1194
- return {
1195
- js: outdent$1`
1196
- const tokens = ${JSON.stringify(obj, null, 2)}
1197
-
1198
- export function token(path, fallback) {
1199
- return tokens[path]?.value || fallback
1200
- }
1201
-
1202
- function tokenVar(path, fallback) {
1203
- return tokens[path]?.variable || fallback
1204
- }
1205
-
1206
- token.var = tokenVar
1207
- `,
1208
- dts: outdent$1`
1209
- ${ctx.file.importType("Token", "./tokens")}
1210
-
1211
- export declare const token: {
1212
- (path: Token, fallback?: string): string
1213
- var: (path: Token, fallback?: string) => string
1214
- }
1215
-
1216
- ${ctx.file.exportTypeStar("./tokens")}
1217
- `
1218
- };
1219
- }
1220
- //#endregion
1221
- //#region src/artifacts/preact-jsx/jsx.ts
1222
- function generatePreactJsxFactory(ctx) {
1223
- const { factoryName, componentName } = ctx.jsx;
1224
- return { js: outdent`
1225
- import { h } from 'preact'
1226
- import { forwardRef } from 'preact/compat'
1227
- ${ctx.file.import("defaultShouldForwardProp, composeShouldForwardProps, composeCvaFn, getDisplayName", "./factory-helper")}
1228
- ${ctx.file.import("isCssProperty", "./is-valid-prop")}
1229
- ${ctx.file.import("css, cx, cva", "../css/index")}
1230
- ${ctx.file.import("splitProps, normalizeHTMLProps", "../helpers")}
1231
-
1232
- function styledFn(Dynamic, configOrCva = {}, options = {}) {
1233
- const cvaFn = configOrCva.__cva__ || configOrCva.__recipe__ ? configOrCva : cva(configOrCva)
1234
-
1235
- const forwardFn = options.shouldForwardProp || defaultShouldForwardProp
1236
- const shouldForwardProp = (prop) => {
1237
- if (options.forwardProps?.includes(prop)) return true
1238
- return forwardFn(prop, cvaFn.variantKeys)
1239
- }
1240
-
1241
- const defaultProps = Object.assign(
1242
- options.dataAttr && configOrCva.__name__ ? { 'data-recipe': configOrCva.__name__ } : {},
1243
- options.defaultProps,
1244
- )
1245
-
1246
- const __cvaFn__ = composeCvaFn(Dynamic.__cva__, cvaFn)
1247
- const __shouldForwardProps__ = composeShouldForwardProps(Dynamic, shouldForwardProp)
1248
- const __base__ = Dynamic.__base__ || Dynamic
1249
-
1250
- const ${componentName} = /* @__PURE__ */ forwardRef(function ${componentName}(props, ref) {
1251
- const { as: Element = __base__, unstyled, children, ...restProps } = props
1252
-
1253
-
1254
- // Not memoized, deliberately. \`restProps\` is rest destructuring, so it is a fresh
1255
- // object on every render and a dependency on it can never match — a memo here is a
1256
- // guaranteed miss that still costs a hook slot, a deps array and a retained cell.
1257
- const combinedProps = Object.assign({}, defaultProps, restProps)
1258
-
1259
- const [htmlProps, forwardedProps, variantProps, styleProps, elementProps] =
1260
- splitProps(combinedProps, normalizeHTMLProps.keys, __shouldForwardProps__, __cvaFn__.variantKeys, isCssProperty)
1261
-
1262
- function recipeClass() {
1263
- const { css: cssStyles, ...propStyles } = styleProps
1264
- const compoundVariantStyles = __cvaFn__.__getCompoundVariantCss__?.(variantProps)
1265
- return cx(__cvaFn__(variantProps, false), css(compoundVariantStyles, propStyles, cssStyles), combinedProps.class, combinedProps.className)
1266
- }
1267
-
1268
- function cvaClass() {
1269
- const { css: cssStyles, ...propStyles } = styleProps
1270
- const cvaStyles = __cvaFn__.raw(variantProps)
1271
- return cx(css(cvaStyles, propStyles, cssStyles), combinedProps.class, combinedProps.className)
1272
- }
1273
-
1274
- const classes = () => {
1275
- if (unstyled) {
1276
- const { css: cssStyles, ...propStyles } = styleProps
1277
- return cx(css(propStyles, cssStyles), combinedProps.class, combinedProps.className)
1278
- }
1279
- return configOrCva.__recipe__ ? recipeClass() : cvaClass()
1280
- }
1281
-
1282
- return h(Element, {
1283
- ...forwardedProps,
1284
- ...elementProps,
1285
- ...normalizeHTMLProps(htmlProps),
1286
- ref,
1287
- className: classes()
1288
- }, children ?? combinedProps.children)
1289
- })
1290
-
1291
- const name = getDisplayName(__base__)
1292
-
1293
- ${componentName}.displayName = \`${factoryName}.\${name}\`
1294
- ${componentName}.__cva__ = __cvaFn__
1295
- ${componentName}.__base__ = __base__
1296
- ${componentName}.__shouldForwardProps__ = shouldForwardProp
1297
-
1298
- return ${componentName}
1299
- }
1300
-
1301
- function createJsxFactory() {
1302
- const cache = new Map()
1303
-
1304
- return new Proxy(styledFn, {
1305
- apply(_, __, args) {
1306
- return styledFn(...args)
1307
- },
1308
- get(_, el) {
1309
- if (!cache.has(el)) {
1310
- cache.set(el, styledFn(el))
1311
- }
1312
- return cache.get(el)
1313
- },
1314
- })
1315
- }
1316
-
1317
- export const ${factoryName} = /* @__PURE__ */ createJsxFactory()
1318
- ` };
1319
- }
1320
- //#endregion
1321
- //#region src/artifacts/preact-jsx/pattern.ts
1322
- function generatePreactJsxPattern(ctx, filters) {
1323
- const { typeName, factoryName, styleProps: jsxStyleProps } = ctx.jsx;
1324
- return ctx.patterns.filterDetails(filters).map((pattern) => {
1325
- const { upperName, styleFnName, dashName, jsxName, props, blocklistType } = pattern;
1326
- const { description, jsxElement = "div", deprecated } = pattern.config;
1327
- return {
1328
- name: dashName,
1329
- js: outdent`
1330
- import { h } from 'preact'
1331
- import { forwardRef } from 'preact/compat'
1332
- ${jsxStyleProps === "minimal" ? ctx.file.import("mergeCss", "../css/css") : ""}
1333
- ${ctx.file.import("splitProps", "../helpers")}
1334
- ${ctx.file.import(styleFnName, `../patterns/${dashName}`)}
1335
- ${ctx.file.import(factoryName, "./factory")}
1336
-
1337
- export const ${jsxName} = /* @__PURE__ */ forwardRef(function ${jsxName}(props, ref) {
1338
- ${match(jsxStyleProps).with("none", () => outdent`
1339
- const [patternProps, restProps] = splitProps(props, ${JSON.stringify(props)})
1340
-
1341
- const styleProps = ${styleFnName}(patternProps)
1342
- const mergedProps = { ref, ...restProps, css: styleProps }
1343
-
1344
- return h(${factoryName}.${jsxElement}, mergedProps)
1345
- `).with("minimal", () => outdent`
1346
- const [patternProps, restProps] = splitProps(props, ${JSON.stringify(props)})
1347
-
1348
- const styleProps = ${styleFnName}(patternProps)
1349
- const cssProps = { css: mergeCss(styleProps, props.css) }
1350
- const mergedProps = { ref, ...restProps, ...cssProps }
1351
-
1352
- return h(${factoryName}.${jsxElement}, mergedProps)
1353
- `).with("all", () => outdent`
1354
- const [patternProps, restProps] = splitProps(props, ${JSON.stringify(props)})
1355
-
1356
- const styleProps = ${styleFnName}(patternProps)
1357
- const mergedProps = { ref, ...styleProps, ...restProps }
1358
-
1359
- return h(${factoryName}.${jsxElement}, mergedProps)
1360
- `).exhaustive()}
1361
- })
1362
- `,
1363
- dts: outdent`
1364
- import type { FunctionComponent } from 'preact'
1365
- ${ctx.file.importType(`${upperName}Properties`, `../patterns/${dashName}`)}
1366
- ${ctx.file.importType("DistributiveOmit", "../types/system-types")}
1367
- ${ctx.file.importType(typeName, "../types/jsx")}
1368
-
1369
- export interface ${upperName}Props extends ${upperName}Properties, DistributiveOmit<${typeName}<'${jsxElement}'>, keyof ${upperName}Properties ${blocklistType}> {}
1370
-
1371
- ${ctx.file.jsDocComment(description, { deprecated })}
1372
- export declare const ${jsxName}: FunctionComponent<${upperName}Props>
1373
- `
1374
- };
1375
- });
1376
- }
1377
- //#endregion
1378
- //#region src/artifacts/preact-jsx/types.ts
1379
- function generatePreactJsxTypes(ctx) {
1380
- const { factoryName, componentName, upperName, typeName, variantName } = ctx.jsx;
1381
- return {
1382
- jsxFactory: outdent`
1383
- import type { ${upperName} } from '../types/jsx'
1384
- export declare const ${factoryName}: ${upperName}
1385
- `,
1386
- jsxType: outdent`
1387
- import type { ComponentProps, JSX } from 'preact'
1388
- ${ctx.file.importType("RecipeDefinition, RecipeSelection, RecipeVariantRecord", "./recipe")}
1389
- ${ctx.file.importType("Assign, DistributiveOmit, DistributiveUnion, JsxHTMLProps, JsxStyleProps, Pretty", "./system-types")}
1390
-
1391
- export type ElementType = JSX.ElementType
1392
-
1393
- interface Dict {
1394
- [k: string]: unknown
1395
- }
1396
-
1397
- export type DataAttrs = Record<\`data-\${string}\`, unknown>
1398
-
1399
- export interface UnstyledProps {
1400
- /**
1401
- * Whether to remove recipe styles
1402
- */
1403
- unstyled?: boolean | undefined
1404
- }
1405
-
1406
- export interface AsProps {
1407
- /**
1408
- * The element to render as
1409
- */
1410
- as?: ElementType | undefined
1411
- }
1412
-
1413
- export interface ${componentName}<T extends ElementType, P extends Dict = {}> {
1414
- (props: JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps, Assign<JsxStyleProps, P>>): JSX.Element
1415
- displayName?: string | undefined
1416
- }
1417
-
1418
- interface RecipeFn {
1419
- __type: any
1420
- }
1421
-
1422
- export interface JsxFactoryOptions<TProps extends Dict> {
1423
- dataAttr?: boolean
1424
- defaultProps?: Partial<TProps> & DataAttrs
1425
- shouldForwardProp?: (prop: string, variantKeys: string[]) => boolean
1426
- forwardProps?: string[]
1427
- }
1428
-
1429
- export type JsxRecipeProps<T extends ElementType, P extends Dict> = JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps, P>
1430
-
1431
- export type JsxElement<T extends ElementType, P extends Dict> = T extends ${componentName}<infer A, infer B>
1432
- ? ${componentName}<A, Pretty<DistributiveUnion<P, B>>>
1433
- : ${componentName}<T, P>
1434
-
1435
- export interface JsxFactory {
1436
- <T extends ElementType>(component: T): ${componentName}<T, {}>
1437
- <T extends ElementType, P extends RecipeVariantRecord>(component: T, recipe: RecipeDefinition<P>, options?: JsxFactoryOptions<JsxRecipeProps<T, RecipeSelection<P>>>): JsxElement<
1438
- T,
1439
- RecipeSelection<P>
1440
- >
1441
- <T extends ElementType, P extends RecipeFn>(component: T, recipeFn: P, options?: JsxFactoryOptions<JsxRecipeProps<T, P['__type']>>): JsxElement<T, P['__type']>
1442
- }
1443
-
1444
- export type JsxElements = {
1445
- [K in keyof JSX.IntrinsicElements]: ${componentName}<K, {}>
1446
- }
1447
-
1448
- export type ${upperName} = JsxFactory & JsxElements
1449
-
1450
- export type ${typeName}<T extends ElementType> = JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps, JsxStyleProps>
1451
-
1452
- export type ${variantName}<T extends ${componentName}<any, any>> = T extends ${componentName}<any, infer Props> ? Props : never
1453
- `
1454
- };
1455
- }
1456
- //#endregion
1457
- //#region src/artifacts/preact-jsx/create-style-context.ts
1458
- function generatePreactCreateStyleContext(ctx) {
1459
- const { factoryName } = ctx.jsx;
1460
- return {
1461
- js: outdent`
1462
- ${ctx.file.import("cx, css, sva", "../css/index")}
1463
- ${ctx.file.import(factoryName, "./factory")}
1464
- ${ctx.file.import("getDisplayName", "./factory-helper")}
1465
- import { createContext } from 'preact'
1466
- import { useContext } from 'preact/hooks'
1467
- import { createElement, forwardRef } from 'preact/compat'
1468
-
1469
- function createSafeContext(contextName) {
1470
- const Context = createContext(undefined)
1471
- const useStyleContext = (componentName, slot) => {
1472
- const context = useContext(Context)
1473
- if (context === undefined) {
1474
- const componentInfo = componentName ? \`Component "\${componentName}"\` : 'A component'
1475
- const slotInfo = slot ? \` (slot: "\${slot}")\` : ''
1476
-
1477
- throw new Error(
1478
- \`\${componentInfo}\${slotInfo} cannot access \${contextName} because it's missing its Provider.\`
1479
- )
1480
- }
1481
- return context
1482
- }
1483
- return [Context, useStyleContext]
1484
- }
1485
-
1486
- export function createStyleContext(recipe) {
1487
- const isConfigRecipe = '__recipe__' in recipe
1488
- const recipeName = isConfigRecipe && recipe.__name__ ? recipe.__name__ : undefined
1489
- const contextName = recipeName ? \`createStyleContext("\${recipeName}")\` : 'createStyleContext'
1490
-
1491
- const [StyleContext, useStyleContext] = createSafeContext(contextName)
1492
- const svaFn = isConfigRecipe ? recipe : sva(recipe.config)
1493
-
1494
- const getResolvedProps = (props, slotStyles) => {
1495
- const { unstyled, ...restProps } = props
1496
- if (unstyled) return restProps
1497
- if (isConfigRecipe) {
1498
- return { ...restProps, className: cx(slotStyles, restProps.className) }
1499
- }
1500
- ${outdent.string(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`))}
1501
- }
1502
-
1503
- const withRootProvider = (Component, options) => {
1504
- const WithRootProvider = (props) => {
1505
- const [variantProps, otherProps] = svaFn.splitVariantProps(props)
1506
-
1507
- const slotStyles = isConfigRecipe ? svaFn(variantProps) : svaFn.raw(variantProps)
1508
- slotStyles._classNameMap = svaFn.classNameMap
1509
-
1510
- const mergedProps = options?.defaultProps
1511
- ? { ...options.defaultProps, ...otherProps }
1512
- : otherProps
1513
-
1514
- return createElement(StyleContext.Provider, {
1515
- value: slotStyles,
1516
- children: createElement(Component, mergedProps)
1517
- })
1518
- }
1519
-
1520
- const componentName = getDisplayName(Component)
1521
- WithRootProvider.displayName = \`withRootProvider(\${componentName})\`
1522
-
1523
- return WithRootProvider
1524
- }
1525
-
1526
- const withProvider = (Component, slot, options) => {
1527
- const StyledComponent = ${factoryName}(Component, {}, options)
1528
-
1529
- const WithProvider = forwardRef(function WithProvider(props, ref) {
1530
- const [variantProps, restProps] = svaFn.splitVariantProps(props)
1531
-
1532
- const slotStyles = isConfigRecipe ? svaFn(variantProps) : svaFn.raw(variantProps)
1533
- slotStyles._classNameMap = svaFn.classNameMap
1534
-
1535
- const propsWithClass = { ...restProps, className: restProps.className ?? options?.defaultProps?.className }
1536
- const resolvedProps = getResolvedProps(propsWithClass, slotStyles[slot])
1537
- return createElement(StyleContext.Provider, {
1538
- value: slotStyles,
1539
- children: createElement(StyledComponent, {
1540
- ...resolvedProps,
1541
- className: cx(resolvedProps.className, slotStyles._classNameMap[slot]),
1542
- ref,
1543
- })
1544
- })
1545
- })
1546
-
1547
- const componentName = getDisplayName(Component)
1548
- WithProvider.displayName = \`withProvider(\${componentName})\`
1549
-
1550
- return WithProvider
1551
- }
1552
-
1553
- const withContext = (Component, slot, options) => {
1554
- const StyledComponent = ${factoryName}(Component, {}, options)
1555
- const componentName = getDisplayName(Component)
1556
-
1557
- const WithContext = forwardRef(function WithContext(props, ref) {
1558
- const slotStyles = useStyleContext(componentName, slot)
1559
-
1560
- const propsWithClass = { ...props, className: props.className ?? options?.defaultProps?.className }
1561
- const resolvedProps = getResolvedProps(propsWithClass, slotStyles[slot])
1562
- return createElement(StyledComponent, {
1563
- ...resolvedProps,
1564
- className: cx(resolvedProps.className, slotStyles._classNameMap[slot]),
1565
- ref,
1566
- })
1567
- })
1568
-
1569
- WithContext.displayName = \`withContext(\${componentName})\`
1570
-
1571
- return WithContext
1572
- }
1573
-
1574
- return {
1575
- withRootProvider,
1576
- withProvider,
1577
- withContext,
1578
- }
1579
- }
1580
- `,
1581
- dts: outdent`
1582
- ${ctx.file.importType("SlotRecipeRuntimeFn, RecipeVariantProps", "../types/recipe")}
1583
- ${ctx.file.importType("JsxHTMLProps, JsxStyleProps, Assign", "../types/system-types")}
1584
- ${ctx.file.importType("JsxFactoryOptions, DataAttrs, AsProps", "../types/jsx")}
1585
- import type { ComponentType, ComponentProps, JSX } from 'preact/compat'
1586
-
1587
- interface UnstyledProps {
1588
- unstyled?: boolean | undefined
1589
- }
1590
-
1591
- interface WithProviderOptions<P = {}> {
1592
- defaultProps?: (Partial<P> & DataAttrs) | undefined
1593
- }
1594
-
1595
- type ElementType = JSX.ElementType
1596
-
1597
- type SvaFn<S extends string = any> = SlotRecipeRuntimeFn<S, any>
1598
- interface SlotRecipeFn {
1599
- __type: any
1600
- __slot: string
1601
- (props?: any): any
1602
- }
1603
- type SlotRecipe = SvaFn | SlotRecipeFn
1604
-
1605
- type InferSlot<R extends SlotRecipe> = R extends SlotRecipeFn ? R['__slot'] : R extends SvaFn<infer S> ? S : never
1606
-
1607
- type StyleContextProvider<T extends ElementType, R extends SlotRecipe> = ComponentType<
1608
- JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps, Assign<RecipeVariantProps<R>, JsxStyleProps>>
1609
- >
1610
-
1611
- type StyleContextRootProvider<T extends ElementType, R extends SlotRecipe> = ComponentType<
1612
- ComponentProps<T> & UnstyledProps & RecipeVariantProps<R>
1613
- >
1614
-
1615
- type StyleContextConsumer<T extends ElementType> = ComponentType<
1616
- JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps, JsxStyleProps>
1617
- >
1618
-
1619
- export interface StyleContext<R extends SlotRecipe> {
1620
- withRootProvider: <T extends ElementType>(
1621
- Component: T,
1622
- options?: WithProviderOptions<ComponentProps<T>> | undefined
1623
- ) => StyleContextRootProvider<T, R>
1624
- withProvider: <T extends ElementType>(
1625
- Component: T,
1626
- slot: InferSlot<R>,
1627
- options?: JsxFactoryOptions<ComponentProps<T>> | undefined
1628
- ) => StyleContextProvider<T, R>
1629
- withContext: <T extends ElementType>(
1630
- Component: T,
1631
- slot: InferSlot<R>,
1632
- options?: JsxFactoryOptions<ComponentProps<T>> | undefined
1633
- ) => StyleContextConsumer<T>
1634
- }
1635
-
1636
- export declare function createStyleContext<R extends SlotRecipe>(recipe: R): StyleContext<R>
1637
- `
1638
- };
1639
- }
1640
- //#endregion
1641
- //#region src/artifacts/preact-jsx/jsx.string-literal.ts
1642
- function generatePreactJsxStringLiteralFactory(ctx) {
1643
- const { factoryName, componentName } = ctx.jsx;
1644
- return { js: outdent`
1645
- import { h } from 'preact'
1646
- import { forwardRef } from 'preact/compat'
1647
- ${ctx.file.import("getDisplayName", "./factory-helper")}
1648
- ${ctx.file.import("css, cx", "../css/index")}
1649
-
1650
- function createStyledFn(Dynamic) {
1651
- const __base__ = Dynamic.__base__ || Dynamic
1652
- return function styledFn(template) {
1653
- const styles = css.raw(Dynamic.__styles__, template)
1654
-
1655
- const ${componentName} = /* @__PURE__ */ forwardRef(function ${componentName}(props, ref) {
1656
- const { as: Element = __base__, ...elementProps } = props
1657
-
1658
- function classes() {
1659
- return cx(css(styles), elementProps.className)
1660
- }
1661
-
1662
- return h(Element, {
1663
- ref,
1664
- ...elementProps,
1665
- className: classes(),
1666
- })
1667
- })
1668
-
1669
- const name = getDisplayName(__base__)
1670
-
1671
- ${componentName}.displayName = \`${factoryName}.\${name}\`
1672
- ${componentName}.__styles__ = styles
1673
- ${componentName}.__base__ = __base__
1674
-
1675
- return ${componentName}
1676
- }
1677
- }
1678
-
1679
- function createJsxFactory() {
1680
- const cache = new Map()
1681
-
1682
- return new Proxy(createStyledFn, {
1683
- apply(_, __, args) {
1684
- return createStyledFn(...args)
1685
- },
1686
- get(_, el) {
1687
- if (!cache.has(el)) {
1688
- cache.set(el, createStyledFn(el))
1689
- }
1690
- return cache.get(el)
1691
- },
1692
- })
1693
- }
1694
-
1695
- export const ${factoryName} = /* @__PURE__ */ createJsxFactory()
1696
- ` };
1697
- }
1698
- //#endregion
1699
- //#region src/artifacts/preact-jsx/types.string-literal.ts
1700
- function generatePreactJsxStringLiteralTypes(ctx) {
1701
- const { factoryName, componentName, upperName, typeName } = ctx.jsx;
1702
- return {
1703
- jsxFactory: outdent`
1704
- ${ctx.file.importType(upperName, "../types/jsx")}
1705
- export declare const ${factoryName}: ${upperName}
1706
- `,
1707
- jsxType: outdent`
1708
- import type { ComponentProps, JSX } from 'preact'
1709
-
1710
- export type ElementType = JSX.ElementType
1711
-
1712
- interface Dict {
1713
- [k: string]: unknown
1714
- }
1715
-
1716
- export interface AsProps {
1717
- /**
1718
- * The element to render as
1719
- */
1720
- as?: ElementType | undefined
1721
- }
1722
-
1723
- export type ${componentName}<T extends ElementType> = {
1724
- (args: { raw: readonly string[] | ArrayLike<string> }): (props: ComponentProps<T> & AsProps) => JSX.Element
1725
- displayName?: string | undefined
1726
- }
1727
-
1728
- export interface JsxFactory {
1729
- <T extends ElementType>(component: T): ${componentName}<T>
1730
- }
1731
-
1732
- export type JsxElements = {
1733
- [K in keyof JSX.IntrinsicElements]: ${componentName}<K>
1734
- }
1735
-
1736
- export type ${upperName} = JsxFactory & JsxElements
1737
-
1738
- export type ${typeName}<T extends ElementType> = ComponentProps<T>
1739
- `
1740
- };
1741
- }
1742
- //#endregion
1743
- //#region src/artifacts/qwik-jsx/jsx.ts
1744
- function generateQwikJsxFactory(ctx) {
1745
- const { factoryName, componentName } = ctx.jsx;
1746
- return { js: outdent`
1747
- import { h } from '@builder.io/qwik'
1748
- ${ctx.file.import("defaultShouldForwardProp, composeShouldForwardProps, composeCvaFn, getDisplayName", "./factory-helper")}
1749
- ${ctx.file.import("isCssProperty", "./is-valid-prop")}
1750
- ${ctx.file.import("css, cx, cva", "../css/index")}
1751
- ${ctx.file.import("splitProps, normalizeHTMLProps", "../helpers")}
1752
-
1753
- function styledFn(Dynamic, configOrCva = {}, options = {}) {
1754
- const cvaFn = configOrCva.__cva__ || configOrCva.__recipe__ ? configOrCva : cva(configOrCva)
1755
-
1756
- const forwardFn = options.shouldForwardProp || defaultShouldForwardProp
1757
- const shouldForwardProp = (prop) => {
1758
- if (options.forwardProps?.includes(prop)) return true
1759
- return forwardFn(prop, cvaFn.variantKeys)
1760
- }
1761
-
1762
- const defaultProps = Object.assign(
1763
- options.dataAttr && configOrCva.__name__ ? { 'data-recipe': configOrCva.__name__ } : {},
1764
- options.defaultProps,
1765
- )
1766
-
1767
- const __cvaFn__ = composeCvaFn(Dynamic.__cva__, cvaFn)
1768
- const __shouldForwardProps__ = composeShouldForwardProps(Dynamic, shouldForwardProp)
1769
- const __base__ = Dynamic.__base__ || Dynamic
1770
-
1771
- const ${componentName} = function ${componentName}(props) {
1772
- const { as: Element = __base__, unstyled, children, className, ...restProps } = props
1773
-
1774
- const combinedProps = Object.assign({}, defaultProps, restProps)
1775
-
1776
- const [htmlProps, forwardedProps, variantProps, styleProps, elementProps] =
1777
- splitProps(combinedProps, normalizeHTMLProps.keys, __shouldForwardProps__, __cvaFn__.variantKeys, isCssProperty)
1778
-
1779
- const { css: cssStyles, ...propStyles } = styleProps
1780
-
1781
- function recipeClass() {
1782
- const { css: cssStyles, ...propStyles } = styleProps
1783
- const compoundVariantStyles = __cvaFn__.__getCompoundVariantCss__?.(variantProps);
1784
- return cx(__cvaFn__(variantProps, false), css(compoundVariantStyles, propStyles, cssStyles), combinedProps.class, className)
1785
- }
1786
-
1787
- function cvaClass() {
1788
- const { css: cssStyles, ...propStyles } = styleProps
1789
- const cvaStyles = __cvaFn__.raw(variantProps)
1790
- return cx(css(cvaStyles, propStyles, cssStyles), combinedProps.class, className)
1791
- }
1792
-
1793
- const classes = () => {
1794
- if (unstyled) {
1795
- const { css: cssStyles, ...propStyles } = styleProps
1796
- return cx(css(propStyles, cssStyles), combinedProps.class, className)
1797
- }
1798
- return configOrCva.__recipe__ ? recipeClass() : cvaClass()
1799
- }
1800
-
1801
- return h(Element, {
1802
- ...forwardedProps,
1803
- ...elementProps,
1804
- ...normalizeHTMLProps(htmlProps),
1805
- class: classes(),
1806
- }, children ?? combinedProps.children)
1807
- }
1808
-
1809
- const name = getDisplayName(__base__)
1810
-
1811
- ${componentName}.displayName = \`${factoryName}.\${name}\`
1812
- ${componentName}.__cva__ = __cvaFn__
1813
- ${componentName}.__base__ = __base__
1814
- ${componentName}.__shouldForwardProps__ = shouldForwardProp
1815
-
1816
- return ${componentName}
1817
- }
1818
-
1819
- function createJsxFactory() {
1820
- const cache = new Map()
1821
-
1822
- return new Proxy(styledFn, {
1823
- apply(_, __, args) {
1824
- return styledFn(...args)
1825
- },
1826
- get(_, el) {
1827
- if (!cache.has(el)) {
1828
- cache.set(el, styledFn(el))
1829
- }
1830
- return cache.get(el)
1831
- },
1832
- })
1833
- }
1834
-
1835
- export const ${factoryName} = /* @__PURE__ */ createJsxFactory()
1836
-
1837
- ` };
1838
- }
1839
- //#endregion
1840
- //#region src/artifacts/qwik-jsx/pattern.ts
1841
- function generateQwikJsxPattern(ctx, filters) {
1842
- const { typeName, factoryName, styleProps: jsxStyleProps } = ctx.jsx;
1843
- return ctx.patterns.filterDetails(filters).map((pattern) => {
1844
- const { upperName, styleFnName, dashName, jsxName, props, blocklistType } = pattern;
1845
- const { description, jsxElement = "div", deprecated } = pattern.config;
1846
- return {
1847
- name: dashName,
1848
- js: outdent`
1849
- import { h } from '@builder.io/qwik'
1850
- ${jsxStyleProps === "minimal" ? ctx.file.import("mergeCss", "../css/css") : ""}
1851
- ${ctx.file.import("splitProps", "../helpers")}
1852
- ${ctx.file.import(styleFnName, `../patterns/${dashName}`)}
1853
- ${ctx.file.import(factoryName, "./factory")}
1854
-
1855
- export const ${jsxName} = /* @__PURE__ */ function ${jsxName}(props) {
1856
- ${match(jsxStyleProps).with("none", () => outdent`
1857
- const [patternProps, restProps] = splitProps(props, ${JSON.stringify(props)})
1858
-
1859
- const styleProps = ${styleFnName}(patternProps)
1860
- const mergedProps = { ref, ...restProps, css: styleProps }
1861
-
1862
- return h(${factoryName}.${jsxElement}, mergedProps)
1863
- `).with("minimal", () => outdent`
1864
- const [patternProps, restProps] = splitProps(props, ${JSON.stringify(props)})
1865
-
1866
- const styleProps = ${styleFnName}(patternProps)
1867
- const cssProps = { css: mergeCss(styleProps, props.css) }
1868
- const mergedProps = { ...restProps, ...cssProps }
1869
-
1870
- return h(${factoryName}.${jsxElement}, mergedProps)
1871
- `).with("all", () => outdent`
1872
- const [patternProps, restProps] = splitProps(props, ${JSON.stringify(props)})
1873
-
1874
- const styleProps = ${styleFnName}(patternProps)
1875
- const mergedProps = { ...styleProps, ...restProps }
1876
-
1877
- return h(${factoryName}.${jsxElement}, mergedProps)
1878
- `).exhaustive()}
1879
- }
1880
- `,
1881
- dts: outdent`
1882
- import type { Component } from '@builder.io/qwik'
1883
- ${ctx.file.importType(`${upperName}Properties`, `../patterns/${dashName}`)}
1884
- ${ctx.file.importType(typeName, "../types/jsx")}
1885
- ${ctx.file.importType("Assign, DistributiveOmit", "../types/system-types")}
1886
-
1887
- export interface ${upperName}Props extends Assign<${typeName}<'${jsxElement}'>, DistributiveOmit<${upperName}Properties, ${blocklistType || "\"\""}>> {}
1888
-
1889
- ${ctx.file.jsDocComment(description, { deprecated })}
1890
- export declare const ${jsxName}: Component<${upperName}Props>
1891
- `
1892
- };
1893
- });
1894
- }
1895
- //#endregion
1896
- //#region src/artifacts/qwik-jsx/types.ts
1897
- function generateQwikJsxTypes(ctx) {
1898
- const { factoryName, componentName, upperName, typeName, variantName } = ctx.jsx;
1899
- return {
1900
- jsxFactory: outdent`
1901
- ${ctx.file.importType(upperName, "../types/jsx")}
1902
- export declare const ${factoryName}: ${upperName}
1903
- `,
1904
- jsxType: outdent`
1905
- import type { Component, QwikIntrinsicElements } from '@builder.io/qwik'
1906
- ${ctx.file.importType("RecipeDefinition, RecipeSelection, RecipeVariantRecord", "./recipe")}
1907
- ${ctx.file.importType("Assign, DistributiveOmit, DistributiveUnion, JsxStyleProps, PatchedHTMLProps, Pretty", "./system-types")}
1908
-
1909
- export type ElementType = keyof QwikIntrinsicElements | Component<any>
1910
-
1911
- export type ComponentProps<T extends ElementType> = T extends keyof QwikIntrinsicElements
1912
- ? QwikIntrinsicElements[T]
1913
- : T extends Component<infer P>
1914
- ? P
1915
- : never
1916
-
1917
- interface Dict {
1918
- [k: string]: unknown
1919
- }
1920
-
1921
- export type DataAttrs = Record<\`data-\${string}\`, unknown>
1922
-
1923
- export interface UnstyledProps {
1924
- /**
1925
- * Whether to remove recipe styles
1926
- */
1927
- unstyled?: boolean | undefined
1928
- }
1929
-
1930
- export interface AsProps {
1931
- /**
1932
- * The element to render as
1933
- */
1934
- as?: ElementType | undefined
1935
- }
1936
-
1937
- export interface ${componentName}<T extends ElementType, P extends Dict = {}> extends Component<Assign<ComponentProps<T> & UnstyledProps & AsProps, Assign<PatchedHTMLProps, Assign<JsxStyleProps, P>>>> {}
1938
-
1939
- interface RecipeFn {
1940
- __type: any
1941
- }
1942
-
1943
- export interface JsxFactoryOptions<TProps extends Dict> {
1944
- dataAttr?: boolean
1945
- defaultProps?: Partial<TProps> & DataAttrs
1946
- shouldForwardProp?: (prop: string, variantKeys: string[]) => boolean
1947
- forwardProps?: string[]
1948
- }
1949
-
1950
- export type JsxRecipeProps<T extends ElementType, P extends Dict> = JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps, P>;
1951
-
1952
- export type JsxElement<T extends ElementType, P extends Dict> = T extends ${componentName}<infer A, infer B>
1953
- ? ${componentName}<A, Pretty<DistributiveUnion<P, B>>>
1954
- : ${componentName}<T, P>
1955
-
1956
- export interface JsxFactory {
1957
- <T extends ElementType>(component: T): ${componentName}<T, {}>
1958
- <T extends ElementType, P extends RecipeVariantRecord>(component: T, recipe: RecipeDefinition<P>, options?: JsxFactoryOptions<JsxRecipeProps<T, RecipeSelection<P>>>): JsxElement<
1959
- T,
1960
- RecipeSelection<P>
1961
- >
1962
- <T extends ElementType, P extends RecipeFn>(component: T, recipeFn: P, options?: JsxFactoryOptions<JsxRecipeProps<T, P['__type']>>): JsxElement<T, P['__type']>
1963
- }
1964
-
1965
- export type JsxElements = {
1966
- [K in keyof QwikIntrinsicElements]: ${componentName}<K, {}>
1967
- }
1968
-
1969
- export type ${upperName} = JsxFactory & JsxElements
1970
-
1971
- export type ${typeName}<T extends ElementType> = Assign<ComponentProps<T> & UnstyledProps & AsProps, JsxStyleProps>
1972
-
1973
- export type ${variantName}<T extends ${componentName}<any, any>> = T extends ${componentName}<any, infer Props> ? Props : never
1974
- `
1975
- };
1976
- }
1977
- //#endregion
1978
- //#region src/artifacts/qwik-jsx/jsx.string-literal.ts
1979
- function generateQwikJsxStringLiteralFactory(ctx) {
1980
- const { factoryName, componentName } = ctx.jsx;
1981
- return { js: outdent`
1982
- import { h } from '@builder.io/qwik'
1983
- ${ctx.file.import("getDisplayName", "./factory-helper")}
1984
- ${ctx.file.import("css, cx", "../css/index")}
1985
-
1986
- function createStyledFn(Dynamic) {
1987
- const __base__ = Dynamic.__base__ || Dynamic
1988
- return function styledFn(template) {
1989
- const styles = css.raw(Dynamic.__styles__, template)
1990
-
1991
- const ${componentName} = (props) => {
1992
- const { as: Element = __base__, ...elementProps } = props
1993
-
1994
- function classes() {
1995
- return cx(css(styles), elementProps.className)
1996
- }
1997
-
1998
- return h(Element, {
1999
- ...elementProps,
2000
- className: classes(),
2001
- })
2002
- }
2003
-
2004
- const name = getDisplayName(__base__)
2005
-
2006
- ${componentName}.displayName = \`${factoryName}.\${name}\`
2007
- ${componentName}.__styles__ = styles
2008
- ${componentName}.__base__ = __base__
2009
-
2010
- return ${componentName}
2011
- }
2012
- }
2013
-
2014
- function createJsxFactory() {
2015
- const cache = new Map()
2016
-
2017
- return new Proxy(createStyledFn, {
2018
- apply(_, __, args) {
2019
- return createStyledFn(...args)
2020
- },
2021
- get(_, el) {
2022
- if (!cache.has(el)) {
2023
- cache.set(el, createStyledFn(el))
2024
- }
2025
- return cache.get(el)
2026
- },
2027
- })
2028
- }
2029
-
2030
- export const ${factoryName} = /* @__PURE__ */ createJsxFactory()
2031
-
2032
- ` };
2033
- }
2034
- //#endregion
2035
- //#region src/artifacts/qwik-jsx/types.string-literal.ts
2036
- function generateQwikJsxStringLiteralTypes(ctx) {
2037
- const { factoryName, componentName, upperName, typeName } = ctx.jsx;
2038
- return {
2039
- jsxFactory: outdent`
2040
- ${ctx.file.importType(upperName, "../types/jsx")}
2041
- export declare const ${factoryName}: ${upperName}
2042
- `,
2043
- jsxType: outdent`
2044
- import type { Component, QwikIntrinsicElements } from '@builder.io/qwik'
2045
-
2046
- export type ElementType = keyof QwikIntrinsicElements | Component<any>
2047
-
2048
- export type ComponentProps<T extends ElementType> = T extends keyof QwikIntrinsicElements
2049
- ? QwikIntrinsicElements[T]
2050
- : T extends Component<infer P>
2051
- ? P
2052
- : never
2053
-
2054
- interface Dict {
2055
- [k: string]: unknown
2056
- }
2057
-
2058
- export interface AsProps {
2059
- /**
2060
- * The element to render as
2061
- */
2062
- as?: ElementType | undefined
2063
- }
2064
-
2065
- export type ${componentName}<T extends ElementType> = {
2066
- (args: { raw: readonly string[] | ArrayLike<string> }): (props: ComponentProps<T> & AsProps) => JSX.Element
2067
- }
2068
-
2069
- export interface JsxFactory {
2070
- <T extends ElementType>(component: T): ${componentName}<T>
2071
- }
2072
-
2073
- export type JsxElements = {
2074
- [K in keyof QwikIntrinsicElements]: ${componentName}<K>
2075
- }
2076
-
2077
- export type ${upperName} = JsxFactory & JsxElements
2078
-
2079
- export type ${typeName}<T extends ElementType> = ComponentProps<T>
2080
- `
2081
- };
2082
- }
2083
- //#endregion
2084
- //#region src/artifacts/react-jsx/jsx.ts
2085
- function generateReactJsxFactory(ctx) {
2086
- const { factoryName, componentName } = ctx.jsx;
2087
- return { js: outdent`
2088
- import { createElement, forwardRef } from 'react'
2089
- ${ctx.file.import("css, cx, cva", "../css/index")}
2090
- ${ctx.file.import("defaultShouldForwardProp, composeShouldForwardProps, composeCvaFn, getDisplayName", "./factory-helper")}
2091
- ${ctx.file.import("splitProps, normalizeHTMLProps", "../helpers")}
2092
- ${ctx.file.import("isCssProperty", "./is-valid-prop")}
2093
-
2094
- function styledFn(Dynamic, configOrCva = {}, options = {}) {
2095
- const cvaFn = configOrCva.__cva__ || configOrCva.__recipe__ ? configOrCva : cva(configOrCva)
2096
-
2097
- const forwardFn = options.shouldForwardProp || defaultShouldForwardProp
2098
- const shouldForwardProp = (prop) => {
2099
- if (options.forwardProps?.includes(prop)) return true
2100
- return forwardFn(prop, cvaFn.variantKeys)
2101
- }
2102
-
2103
- const defaultProps = Object.assign(
2104
- options.dataAttr && configOrCva.__name__ ? { 'data-recipe': configOrCva.__name__ } : {},
2105
- options.defaultProps,
2106
- )
2107
-
2108
- const __cvaFn__ = composeCvaFn(Dynamic.__cva__, cvaFn)
2109
- const __shouldForwardProps__ = composeShouldForwardProps(Dynamic, shouldForwardProp)
2110
- const __base__ = Dynamic.__base__ || Dynamic
2111
-
2112
- const ${componentName} = /* @__PURE__ */ forwardRef(function ${componentName}(props, ref) {
2113
- const { as: Element = __base__, unstyled, children, ...restProps } = props
2114
-
2115
- // Not memoized, deliberately. \`restProps\` is rest destructuring, so it is a fresh
2116
- // object on every render and a dependency on it can never match — a memo here is a
2117
- // guaranteed miss that still costs a hook slot, a deps array and a retained cell.
2118
- const combinedProps = Object.assign({}, defaultProps, restProps)
2119
-
2120
- const [htmlProps, forwardedProps, variantProps, styleProps, elementProps] =
2121
- splitProps(combinedProps, normalizeHTMLProps.keys, __shouldForwardProps__, __cvaFn__.variantKeys, isCssProperty)
2122
-
2123
- function recipeClass() {
2124
- const { css: cssStyles, ...propStyles } = styleProps
2125
- const compoundVariantStyles = __cvaFn__.__getCompoundVariantCss__?.(variantProps)
2126
- return cx(__cvaFn__(variantProps, false), css(compoundVariantStyles, propStyles, cssStyles), combinedProps.className)
2127
- }
2128
-
2129
- function cvaClass() {
2130
- const { css: cssStyles, ...propStyles } = styleProps
2131
- const cvaStyles = __cvaFn__.raw(variantProps)
2132
- return cx(css(cvaStyles, propStyles, cssStyles), combinedProps.className)
2133
- }
2134
-
2135
- const classes = () => {
2136
- if (unstyled) {
2137
- const { css: cssStyles, ...propStyles } = styleProps
2138
- return cx(css(propStyles, cssStyles), combinedProps.className)
2139
- }
2140
- return configOrCva.__recipe__ ? recipeClass() : cvaClass()
2141
- }
2142
-
2143
- return createElement(Element, {
2144
- ref,
2145
- ...forwardedProps,
2146
- ...elementProps,
2147
- ...normalizeHTMLProps(htmlProps),
2148
- className: classes(),
2149
- }, children ?? combinedProps.children)
2150
- })
2151
-
2152
- const name = getDisplayName(__base__)
2153
-
2154
- ${componentName}.displayName = \`${factoryName}.\${name}\`
2155
- ${componentName}.__cva__ = __cvaFn__
2156
- ${componentName}.__base__ = __base__
2157
- ${componentName}.__shouldForwardProps__ = shouldForwardProp
2158
-
2159
- return ${componentName}
2160
- }
2161
-
2162
- function createJsxFactory() {
2163
- const cache = new Map()
2164
-
2165
- return new Proxy(styledFn, {
2166
- apply(_, __, args) {
2167
- return styledFn(...args)
2168
- },
2169
- get(_, el) {
2170
- if (!cache.has(el)) {
2171
- cache.set(el, styledFn(el))
2172
- }
2173
- return cache.get(el)
2174
- },
2175
- })
2176
- }
2177
-
2178
- export const ${factoryName} = /* @__PURE__ */ createJsxFactory()
2179
-
2180
- ` };
2181
- }
2182
- //#endregion
2183
- //#region src/artifacts/react-jsx/pattern.ts
2184
- function generateReactJsxPattern(ctx, filters) {
2185
- const { typeName, factoryName, styleProps: jsxStyleProps } = ctx.jsx;
2186
- return ctx.patterns.filterDetails(filters).map((pattern) => {
2187
- const { upperName, styleFnName, dashName, jsxName, props, blocklistType } = pattern;
2188
- const { description, jsxElement = "div", deprecated } = pattern.config;
2189
- return {
2190
- name: dashName,
2191
- js: outdent`
2192
- import { createElement, forwardRef } from 'react'
2193
- ${jsxStyleProps === "minimal" ? ctx.file.import("mergeCss", "../css/css") : ""}
2194
- ${ctx.file.import("splitProps", "../helpers")}
2195
- ${ctx.file.import(styleFnName, `../patterns/${dashName}`)}
2196
- ${ctx.file.import(factoryName, "./factory")}
2197
-
2198
- export const ${jsxName} = /* @__PURE__ */ forwardRef(function ${jsxName}(props, ref) {
2199
- ${match(jsxStyleProps).with("none", () => outdent`
2200
- const [patternProps, restProps] = splitProps(props, ${JSON.stringify(props)})
2201
-
2202
- const styleProps = ${styleFnName}(patternProps)
2203
- const mergedProps = { ref, ...restProps, css: styleProps }
2204
-
2205
- return createElement(${factoryName}.${jsxElement}, mergedProps)
2206
- `).with("minimal", () => outdent`
2207
- const [patternProps, restProps] = splitProps(props, ${JSON.stringify(props)})
2208
-
2209
- const styleProps = ${styleFnName}(patternProps)
2210
- const cssProps = { css: mergeCss(styleProps, props.css) }
2211
- const mergedProps = { ref, ...restProps, ...cssProps }
2212
-
2213
- return createElement(${factoryName}.${jsxElement}, mergedProps)
2214
- `).with("all", () => outdent`
2215
- const [patternProps, restProps] = splitProps(props, ${JSON.stringify(props)})
2216
-
2217
- const styleProps = ${styleFnName}(patternProps)
2218
- const mergedProps = { ref, ...styleProps, ...restProps }
2219
-
2220
- return createElement(${factoryName}.${jsxElement}, mergedProps)
2221
- `).exhaustive()}
2222
- })
2223
- `,
2224
- dts: outdent`
2225
- import type { FunctionComponent } from 'react'
2226
- ${ctx.file.importType(`${upperName}Properties`, `../patterns/${dashName}`)}
2227
- ${ctx.file.importType(typeName, "../types/jsx")}
2228
- ${ctx.file.importType("DistributiveOmit", "../types/system-types")}
2229
-
2230
- export interface ${upperName}Props extends ${upperName}Properties, DistributiveOmit<${typeName}<'${jsxElement}'>, keyof ${upperName}Properties ${blocklistType}> {}
2231
-
2232
- ${ctx.file.jsDocComment(description, { deprecated })}
2233
- export declare const ${jsxName}: FunctionComponent<${upperName}Props>
2234
- `
2235
- };
2236
- });
2237
- }
2238
- //#endregion
2239
- //#region src/artifacts/react-jsx/types.ts
2240
- function generateReactJsxTypes(ctx) {
2241
- const { factoryName, componentName, upperName, typeName, variantName } = ctx.jsx;
2242
- return {
2243
- jsxFactory: outdent`
2244
- ${ctx.file.importType(upperName, "../types/jsx")}
2245
- export declare const ${factoryName}: ${upperName}
2246
- `,
2247
- jsxType: outdent`
2248
- import type { ElementType, JSX, ComponentPropsWithRef, ComponentType, Component } from 'react'
2249
- ${ctx.file.importType("RecipeDefinition, RecipeSelection, RecipeVariantRecord", "./recipe")}
2250
- ${ctx.file.importType("Assign, DistributiveOmit, DistributiveUnion, JsxHTMLProps, JsxStyleProps, Pretty", "./system-types")}
2251
-
2252
- interface Dict {
2253
- [k: string]: unknown
2254
- }
2255
-
2256
- export type DataAttrs = Record<\`data-\${string}\`, unknown>
2257
-
2258
- export interface UnstyledProps {
2259
- /**
2260
- * Whether to remove recipe styles
2261
- */
2262
- unstyled?: boolean | undefined
2263
- }
2264
-
2265
- export interface AsProps {
2266
- /**
2267
- * The element to render as
2268
- */
2269
- as?: ElementType | undefined
2270
- }
2271
-
2272
- export type ComponentProps<T extends ElementType> = T extends ComponentType<infer P> | Component<infer P>
2273
- ? JSX.LibraryManagedAttributes<T, P>
2274
- : ComponentPropsWithRef<T>
2275
-
2276
- export interface ${componentName}<T extends ElementType, P extends Dict = {}> {
2277
- (props: JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps, Assign<JsxStyleProps, P>>): JSX.Element
2278
- displayName?: string | undefined
2279
- }
2280
-
2281
- interface RecipeFn {
2282
- __type: any
2283
- }
2284
-
2285
- export interface JsxFactoryOptions<TProps extends Dict> {
2286
- dataAttr?: boolean
2287
- defaultProps?: Partial<TProps> & DataAttrs
2288
- shouldForwardProp?: (prop: string, variantKeys: string[]) => boolean
2289
- forwardProps?: string[]
2290
- }
2291
-
2292
- export type JsxRecipeProps<T extends ElementType, P extends Dict> = JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps, P>;
2293
-
2294
- export type JsxElement<T extends ElementType, P extends Dict> = T extends ${componentName}<infer A, infer B>
2295
- ? ${componentName}<A, Pretty<DistributiveUnion<P, B>>>
2296
- : ${componentName}<T, P>
2297
-
2298
- export interface JsxFactory {
2299
- <T extends ElementType>(component: T): ${componentName}<T, {}>
2300
- <T extends ElementType, P extends RecipeVariantRecord>(component: T, recipe: RecipeDefinition<P>, options?: JsxFactoryOptions<JsxRecipeProps<T, RecipeSelection<P>>>): JsxElement<
2301
- T,
2302
- RecipeSelection<P>
2303
- >
2304
- <T extends ElementType, P extends RecipeFn>(component: T, recipeFn: P, options?: JsxFactoryOptions<JsxRecipeProps<T, P['__type']>>): JsxElement<T, P['__type']>
2305
- }
2306
-
2307
- export type JsxElements = {
2308
- [K in keyof JSX.IntrinsicElements]: ${componentName}<K, {}>
2309
- }
2310
-
2311
- export type ${upperName} = JsxFactory & JsxElements
2312
-
2313
- export type ${typeName}<T extends ElementType> = JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps, JsxStyleProps>
2314
-
2315
- export type ${variantName}<T extends ${componentName}<any, any>> = T extends ${componentName}<any, infer Props> ? Props : never
2316
- `
2317
- };
2318
- }
2319
- //#endregion
2320
- //#region src/artifacts/react-jsx/create-style-context.ts
2321
- function generateReactCreateStyleContext(ctx) {
2322
- const { factoryName } = ctx.jsx;
2323
- return {
2324
- js: outdent`'use client'\n
2325
- ${ctx.file.import("cx, css, sva", "../css/index")}
2326
- ${ctx.file.import(factoryName, "./factory")}
2327
- ${ctx.file.import("getDisplayName", "./factory-helper")}
2328
- import { createContext, useContext, createElement, forwardRef } from 'react'
2329
-
2330
- function createSafeContext(contextName) {
2331
- const Context = createContext(undefined)
2332
- const useStyleContext = (componentName, slot) => {
2333
- const context = useContext(Context)
2334
- if (context === undefined) {
2335
- const componentInfo = componentName ? \`Component "\${componentName}"\` : 'A component'
2336
- const slotInfo = slot ? \` (slot: "\${slot}")\` : ''
2337
-
2338
- throw new Error(
2339
- \`\${componentInfo}\${slotInfo} cannot access \${contextName} because it's missing its Provider.\`
2340
- )
2341
- }
2342
- return context
2343
- }
2344
- return [Context, useStyleContext]
2345
- }
2346
-
2347
- export function createStyleContext(recipe) {
2348
- const isConfigRecipe = '__recipe__' in recipe
2349
- const recipeName = isConfigRecipe && recipe.__name__ ? recipe.__name__ : undefined
2350
- const contextName = recipeName ? \`createStyleContext("\${recipeName}")\` : 'createStyleContext'
2351
-
2352
- const [StyleContext, useStyleContext] = createSafeContext(contextName)
2353
- const svaFn = isConfigRecipe ? recipe : sva(recipe.config)
2354
-
2355
- const getResolvedProps = (props, slotStyles) => {
2356
- const { unstyled, ...restProps } = props
2357
- if (unstyled) return restProps
2358
- if (isConfigRecipe) {
2359
- return { ...restProps, className: cx(slotStyles, restProps.className) }
2360
- }
2361
- ${outdent.string(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`))}
2362
- }
2363
-
2364
- const withRootProvider = (Component, options) => {
2365
- const WithRootProvider = (props) => {
2366
- const [variantProps, otherProps] = svaFn.splitVariantProps(props)
2367
-
2368
- const slotStyles = isConfigRecipe ? svaFn(variantProps) : svaFn.raw(variantProps)
2369
- slotStyles._classNameMap = svaFn.classNameMap
2370
-
2371
- const mergedProps = options?.defaultProps
2372
- ? { ...options.defaultProps, ...otherProps }
2373
- : otherProps
2374
-
2375
- return createElement(StyleContext.Provider, {
2376
- value: slotStyles,
2377
- children: createElement(Component, mergedProps)
2378
- })
2379
- }
2380
-
2381
- const componentName = getDisplayName(Component)
2382
- WithRootProvider.displayName = \`withRootProvider(\${componentName})\`
2383
-
2384
- return WithRootProvider
2385
- }
2386
-
2387
- const withProvider = (Component, slot, options) => {
2388
- const StyledComponent = ${factoryName}(Component, {}, options)
2389
-
2390
- const WithProvider = forwardRef((props, ref) => {
2391
- const [variantProps, restProps] = svaFn.splitVariantProps(props)
2392
-
2393
- const slotStyles = isConfigRecipe ? svaFn(variantProps) : svaFn.raw(variantProps)
2394
- slotStyles._classNameMap = svaFn.classNameMap
2395
-
2396
- const propsWithClass = { ...restProps, className: restProps.className ?? options?.defaultProps?.className }
2397
- const resolvedProps = getResolvedProps(propsWithClass, slotStyles[slot])
2398
- return createElement(StyleContext.Provider, {
2399
- value: slotStyles,
2400
- children: createElement(StyledComponent, {
2401
- ...resolvedProps,
2402
- className: cx(resolvedProps.className, slotStyles._classNameMap[slot]),
2403
- ref,
2404
- })
2405
- })
2406
- })
2407
-
2408
- const componentName = getDisplayName(Component)
2409
- WithProvider.displayName = \`withProvider(\${componentName})\`
2410
-
2411
- return WithProvider
2412
- }
2413
-
2414
- const withContext = (Component, slot, options) => {
2415
- const StyledComponent = ${factoryName}(Component, {}, options)
2416
- const componentName = getDisplayName(Component)
2417
-
2418
- const WithContext = forwardRef((props, ref) => {
2419
- const slotStyles = useStyleContext(componentName, slot)
2420
-
2421
- const propsWithClass = { ...props, className: props.className ?? options?.defaultProps?.className }
2422
- const resolvedProps = getResolvedProps(propsWithClass, slotStyles[slot])
2423
- return createElement(StyledComponent, {
2424
- ...resolvedProps,
2425
- className: cx(resolvedProps.className, slotStyles._classNameMap[slot]),
2426
- ref,
2427
- })
2428
- })
2429
-
2430
- WithContext.displayName = \`withContext(\${componentName})\`
2431
-
2432
- return WithContext
2433
- }
2434
-
2435
- return {
2436
- withRootProvider,
2437
- withProvider,
2438
- withContext,
2439
- }
2440
- }
2441
- `,
2442
- dts: outdent`
2443
- ${ctx.file.importType("SlotRecipeRuntimeFn, RecipeVariantProps", "../types/recipe")}
2444
- ${ctx.file.importType("JsxHTMLProps, JsxStyleProps, Assign", "../types/system-types")}
2445
- ${ctx.file.importType("JsxFactoryOptions, ComponentProps, DataAttrs, AsProps", "../types/jsx")}
2446
- import type { ComponentType, ElementType } from 'react'
2447
-
2448
- interface UnstyledProps {
2449
- unstyled?: boolean | undefined
2450
- }
2451
-
2452
- type SvaFn<S extends string = any> = SlotRecipeRuntimeFn<S, any>
2453
- interface SlotRecipeFn {
2454
- __type: any
2455
- __slot: string
2456
- (props?: any): any
2457
- }
2458
- type SlotRecipe = SvaFn | SlotRecipeFn
2459
-
2460
- type InferSlot<R extends SlotRecipe> = R extends SlotRecipeFn ? R['__slot'] : R extends SvaFn<infer S> ? S : never
2461
-
2462
- interface WithProviderOptions<P = {}> {
2463
- defaultProps?: (Partial<P> & DataAttrs) | undefined
2464
- }
2465
-
2466
- type StyleContextProvider<T extends ElementType, R extends SlotRecipe> = ComponentType<
2467
- JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps, Assign<RecipeVariantProps<R>, JsxStyleProps>>
2468
- >
2469
-
2470
- type StyleContextRootProvider<T extends ElementType, R extends SlotRecipe> = ComponentType<
2471
- ComponentProps<T> & UnstyledProps & RecipeVariantProps<R>
2472
- >
2473
-
2474
- type StyleContextConsumer<T extends ElementType> = ComponentType<
2475
- JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps, JsxStyleProps>
2476
- >
2477
-
2478
- export interface StyleContext<R extends SlotRecipe> {
2479
- withRootProvider: <T extends ElementType>(
2480
- Component: T,
2481
- options?: WithProviderOptions<ComponentProps<T>> | undefined
2482
- ) => StyleContextRootProvider<T, R>
2483
- withProvider: <T extends ElementType>(
2484
- Component: T,
2485
- slot: InferSlot<R>,
2486
- options?: JsxFactoryOptions<ComponentProps<T>> | undefined
2487
- ) => StyleContextProvider<T, R>
2488
- withContext: <T extends ElementType>(
2489
- Component: T,
2490
- slot: InferSlot<R>,
2491
- options?: JsxFactoryOptions<ComponentProps<T>> | undefined
2492
- ) => StyleContextConsumer<T>
2493
- }
2494
-
2495
- export declare function createStyleContext<R extends SlotRecipe>(recipe: R): StyleContext<R>
2496
- `
2497
- };
2498
- }
2499
- //#endregion
2500
- //#region src/artifacts/react-jsx/jsx.string-literal.ts
2501
- function generateReactJsxStringLiteralFactory(ctx) {
2502
- const { factoryName, componentName } = ctx.jsx;
2503
- return { js: outdent`
2504
- import { createElement, forwardRef } from 'react'
2505
- ${ctx.file.import("getDisplayName", "./factory-helper")}
2506
- ${ctx.file.import("css, cx", "../css/index")}
2507
-
2508
- function createStyledFn(Dynamic) {
2509
- const __base__ = Dynamic.__base__ || Dynamic
2510
- return function styledFn(template) {
2511
- const styles = css.raw(Dynamic.__styles__, template)
2512
-
2513
- const ${componentName} = /* @__PURE__ */ forwardRef(function ${componentName}(props, ref) {
2514
- const { as: Element = __base__, ...elementProps } = props
2515
-
2516
- function classes() {
2517
- return cx(css(styles), elementProps.className)
2518
- }
2519
-
2520
- return createElement(Element, {
2521
- ref,
2522
- ...elementProps,
2523
- className: classes(),
2524
- })
2525
- })
2526
-
2527
- const name = getDisplayName(__base__)
2528
-
2529
- ${componentName}.displayName = \`${factoryName}.\${name}\`
2530
- ${componentName}.__styles__ = styles
2531
- ${componentName}.__base__ = __base__
2532
-
2533
- return ${componentName}
2534
- }
2535
- }
2536
-
2537
- function createJsxFactory() {
2538
- const cache = new Map()
2539
-
2540
- return new Proxy(createStyledFn, {
2541
- apply(_, __, args) {
2542
- return createStyledFn(...args)
2543
- },
2544
- get(_, el) {
2545
- if (!cache.has(el)) {
2546
- cache.set(el, createStyledFn(el))
2547
- }
2548
- return cache.get(el)
2549
- },
2550
- })
2551
- }
2552
-
2553
- export const ${factoryName} = /* @__PURE__ */ createJsxFactory()
2554
- ` };
2555
- }
2556
- //#endregion
2557
- //#region src/artifacts/react-jsx/types.string-literal.ts
2558
- function generateReactJsxStringLiteralTypes(ctx) {
2559
- const { factoryName, componentName, upperName, typeName } = ctx.jsx;
2560
- return {
2561
- jsxFactory: outdent`
2562
- ${ctx.file.importType(upperName, "../types/jsx")}
2563
- export declare const ${factoryName}: ${upperName}
2564
- `,
2565
- jsxType: outdent`
2566
- import type { ComponentPropsWithoutRef, ElementType, ElementRef, JSX, Ref } from 'react'
2567
- ${ctx.file.importType("DistributiveOmit", "../types/system-types")}
2568
-
2569
- interface Dict {
2570
- [k: string]: unknown
2571
- }
2572
-
2573
- export interface AsProps {
2574
- /**
2575
- * The element to render as
2576
- */
2577
- as?: ElementType | undefined
2578
- }
2579
-
2580
- export type ComponentProps<T extends ElementType> = DistributiveOmit<ComponentPropsWithoutRef<T>, 'ref'> & {
2581
- ref?: Ref<ElementRef<T>>
2582
- } & AsProps
2583
-
2584
- export type ${componentName}<T extends ElementType> = {
2585
- (args: { raw: readonly string[] | ArrayLike<string> }): (props: ComponentProps<T>) => JSX.Element
2586
- displayName?: string | undefined
2587
- }
2588
-
2589
- export interface JsxFactory {
2590
- <T extends ElementType>(component: T): ${componentName}<T>
2591
- }
2592
-
2593
- export type JsxElements = {
2594
- [K in keyof JSX.IntrinsicElements]: ${componentName}<K>
2595
- }
2596
-
2597
- export type ${upperName} = JsxFactory & JsxElements
2598
-
2599
- export type ${typeName}<T extends ElementType> = ComponentProps<T>
2600
- `
2601
- };
2602
- }
2603
- //#endregion
2604
- //#region src/artifacts/solid-jsx/jsx.ts
2605
- function generateSolidJsxFactory(ctx) {
2606
- const { componentName, factoryName } = ctx.jsx;
2607
- return { js: outdent`
2608
- import { createMemo, mergeProps, splitProps } from 'solid-js'
2609
- import { Dynamic, createComponent } from 'solid-js/web'
2610
- ${ctx.file.import("css, cx, cva", "../css/index")}
2611
- ${ctx.file.import("normalizeHTMLProps", "../helpers")}
2612
- ${ctx.file.import("composeCvaFn, composeShouldForwardProps, defaultShouldForwardProp, getDisplayName", "./factory-helper")}
2613
- ${ctx.file.import("isCssProperty", "./is-valid-prop")}
2614
-
2615
- function styledFn(element, configOrCva = {}, options = {}) {
2616
- const cvaFn =
2617
- configOrCva.__cva__ || configOrCva.__recipe__
2618
- ? configOrCva
2619
- : cva(configOrCva)
2620
-
2621
- const forwardFn = options.shouldForwardProp || defaultShouldForwardProp
2622
- const shouldForwardProp = (prop) => {
2623
- if (options.forwardProps?.includes(prop)) return true
2624
- return forwardFn(prop, cvaFn.variantKeys)
2625
- }
2626
-
2627
- const getDefaultProps = () => {
2628
- const baseDefaults = options.dataAttr && configOrCva.__name__
2629
- ? { 'data-recipe': configOrCva.__name__ }
2630
- : {}
2631
- const defaults = typeof options.defaultProps === 'function'
2632
- ? options.defaultProps()
2633
- : options.defaultProps
2634
- return Object.assign(baseDefaults, defaults)
2635
- }
2636
-
2637
- const __cvaFn__ = composeCvaFn(element.__cva__, cvaFn)
2638
- const __shouldForwardProps__ = composeShouldForwardProps(
2639
- element,
2640
- shouldForwardProp
2641
- )
2642
-
2643
- const ${componentName} = (props) => {
2644
- const mergedProps = mergeProps(
2645
- { as: element.__base__ || element },
2646
- getDefaultProps(),
2647
- props
2648
- )
2649
-
2650
- const [localProps, restProps] = splitProps(mergedProps, [
2651
- 'as',
2652
- 'unstyled',
2653
- 'class',
2654
- 'className',
2655
- ])
2656
-
2657
- const [htmlProps, aProps] = splitProps(restProps, normalizeHTMLProps.keys)
2658
-
2659
- const forwardedKeys = createMemo(() => {
2660
- const keys = Object.keys(aProps)
2661
- return keys.filter((prop) => __shouldForwardProps__(prop))
2662
- })
2663
-
2664
- const [forwardedProps, variantProps, bProps] = splitProps(aProps, forwardedKeys(), __cvaFn__.variantKeys)
2665
-
2666
- const cssPropKeys = createMemo(() => {
2667
- const keys = Object.keys(bProps)
2668
- return keys.filter((prop) => isCssProperty(prop))
2669
- })
2670
-
2671
- const [styleProps, elementProps] = splitProps(bProps, cssPropKeys())
2672
-
2673
- function recipeClass() {
2674
- const { css: cssStyles, ...propStyles } = styleProps
2675
- const compoundVariantStyles =
2676
- __cvaFn__.__getCompoundVariantCss__?.(variantProps)
2677
- return cx(
2678
- __cvaFn__(variantProps, false),
2679
- css(compoundVariantStyles, propStyles, cssStyles),
2680
- localProps.class,
2681
- localProps.className
2682
- )
2683
- }
2684
-
2685
- function cvaClass() {
2686
- const { css: cssStyles, ...propStyles } = styleProps
2687
- const cvaStyles = __cvaFn__.raw(variantProps)
2688
- return cx(
2689
- css(cvaStyles, propStyles, cssStyles),
2690
- localProps.class,
2691
- localProps.className
2692
- )
2693
- }
2694
-
2695
- const classes = () => {
2696
- if (localProps.unstyled) {
2697
- const { css: cssStyles, ...propStyles } = styleProps
2698
- return cx(css(propStyles, cssStyles), localProps.class, localProps.className)
2699
- }
2700
- return configOrCva.__recipe__ ? recipeClass() : cvaClass()
2701
- }
2702
-
2703
- if (forwardedProps.className) {
2704
- delete forwardedProps.className
2705
- }
2706
-
2707
- return createComponent(
2708
- Dynamic,
2709
- mergeProps(forwardedProps, elementProps, normalizeHTMLProps(htmlProps), {
2710
- get component() {
2711
- return localProps.as
2712
- },
2713
- get class() {
2714
- return classes()
2715
- },
2716
- })
2717
- )
2718
- }
2719
-
2720
- const name = getDisplayName(element)
2721
-
2722
- ${componentName}.displayName = \`${factoryName}.\${name}\`
2723
- ${componentName}.__cva__ = __cvaFn__
2724
- ${componentName}.__base__ = element
2725
- ${componentName}.__shouldForwardProps__ = shouldForwardProp
2726
-
2727
- return ${componentName}
2728
- }
2729
-
2730
- function createJsxFactory() {
2731
- const cache = new Map()
2732
-
2733
- return new Proxy(styledFn, {
2734
- apply(_, __, args) {
2735
- return styledFn(...args)
2736
- },
2737
- get(_, el) {
2738
- if (!cache.has(el)) {
2739
- cache.set(el, styledFn(el))
2740
- }
2741
- return cache.get(el)
2742
- },
2743
- })
2744
- }
2745
-
2746
- export const ${factoryName} = /* @__PURE__ */ createJsxFactory()
2747
- ` };
2748
- }
2749
- //#endregion
2750
- //#region src/artifacts/solid-jsx/pattern.ts
2751
- function generateSolidJsxPattern(ctx, filters) {
2752
- const { typeName, factoryName, styleProps: jsxStyleProps } = ctx.jsx;
2753
- return ctx.patterns.filterDetails(filters).map((pattern) => {
2754
- const { upperName, styleFnName, dashName, jsxName, props, blocklistType } = pattern;
2755
- const { description, jsxElement = "div", deprecated } = pattern.config;
2756
- return {
2757
- name: dashName,
2758
- js: outdent`
2759
- import { createMemo, mergeProps, splitProps } from 'solid-js'
2760
- import { createComponent } from 'solid-js/web'
2761
- ${jsxStyleProps === "minimal" ? ctx.file.import("mergeCss", "../css/css") : ""}
2762
- ${ctx.file.import(styleFnName, `../patterns/${dashName}`)}
2763
- ${ctx.file.import(factoryName, "./factory")}
2764
-
2765
- export const ${jsxName} = /* @__PURE__ */ function ${jsxName}(props) {
2766
- ${match(jsxStyleProps).with("none", () => outdent`
2767
- const [patternProps, restProps] = splitProps(props, ${JSON.stringify(props)})
2768
-
2769
- const cssProps = createMemo(() => {
2770
- const styleProps = ${styleFnName}(patternProps)
2771
- return { css: styleProps }
2772
- })
2773
-
2774
- const mergedProps = mergeProps(restProps, cssProps)
2775
-
2776
- return createComponent(${factoryName}.${jsxElement}, mergedProps)
2777
- `).with("minimal", () => outdent`
2778
- const [patternProps, restProps] = splitProps(props, ${JSON.stringify(props)})
2779
-
2780
- const cssProps = createMemo(() => {
2781
- const styleProps = ${styleFnName}(patternProps)
2782
- return { css: mergeCss(styleProps, props.css) }
2783
- })
2784
-
2785
- const mergedProps = mergeProps(restProps, cssProps)
2786
-
2787
- return createComponent(${factoryName}.${jsxElement}, mergedProps)
2788
- `).with("all", () => outdent`
2789
- const [patternProps, restProps] = splitProps(props, ${JSON.stringify(props)})
2790
-
2791
- const styleProps = ${styleFnName}(patternProps)
2792
- const mergedProps = mergeProps(styleProps, restProps)
2793
-
2794
- return createComponent(${factoryName}.${jsxElement}, mergedProps)
2795
- `).exhaustive()}
2796
- }
2797
- `,
2798
- dts: outdent`
2799
- import type { Component } from 'solid-js'
2800
- ${ctx.file.importType(`${upperName}Properties`, `../patterns/${dashName}`)}
2801
- ${ctx.file.importType(typeName, "../types/jsx")}
2802
- ${ctx.file.importType("DistributiveOmit", "../types/system-types")}
2803
-
2804
- export interface ${upperName}Props extends ${upperName}Properties, DistributiveOmit<${typeName}<'${jsxElement}'>, keyof ${upperName}Properties ${blocklistType}> {}
2805
-
2806
- ${ctx.file.jsDocComment(description, { deprecated })}
2807
- export declare const ${jsxName}: Component<${upperName}Props>
2808
- `
2809
- };
2810
- });
2811
- }
2812
- //#endregion
2813
- //#region src/artifacts/solid-jsx/types.ts
2814
- function generateSolidJsxTypes(ctx) {
2815
- const { factoryName, componentName, upperName, typeName, variantName } = ctx.jsx;
2816
- return {
2817
- jsxFactory: outdent`
2818
- ${ctx.file.importType(upperName, "../types/jsx")}
2819
- export declare const ${factoryName}: ${upperName}
2820
- `,
2821
- jsxType: outdent`
2822
- import type { Accessor, ComponentProps, Component, JSX } from 'solid-js'
2823
- ${ctx.file.importType("RecipeDefinition, RecipeSelection, RecipeVariantRecord", "./recipe")}
2824
- ${ctx.file.importType("Assign, DistributiveUnion, JsxHTMLProps, JsxStyleProps, Pretty", "./system-types")}
2825
-
2826
- interface Dict {
2827
- [k: string]: unknown
2828
- }
2829
-
2830
- export type DataAttrs = Record<\`data-\${string}\`, unknown>
2831
-
2832
- export interface UnstyledProps {
2833
- /**
2834
- * Whether to remove recipe styles
2835
- */
2836
- unstyled?: boolean | undefined
2837
- }
2838
-
2839
- export interface AsProps {
2840
- /**
2841
- * The element to render as
2842
- */
2843
- as?: ElementType | undefined
2844
- }
2845
-
2846
- export type ElementType = keyof JSX.IntrinsicElements | Component<any>
2847
-
2848
- export interface ${componentName}<T extends ElementType, P extends Dict = {}> {
2849
- (props: JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps, Assign<JsxStyleProps, P>>): JSX.Element
2850
- displayName?: string | undefined
2851
- }
2852
-
2853
- interface RecipeFn {
2854
- __type: any
2855
- }
2856
-
2857
- export type MaybeAccessor<T> = T | Accessor<T>
2858
-
2859
- export interface JsxFactoryOptions<TProps extends Dict> {
2860
- dataAttr?: boolean
2861
- defaultProps?: MaybeAccessor<Partial<TProps> & DataAttrs>
2862
- shouldForwardProp?: (prop: string, variantKeys: string[]) => boolean
2863
- forwardProps?: string[]
2864
- }
2865
-
2866
- export type JsxRecipeProps<T extends ElementType, P extends Dict> = JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps, P>;
2867
-
2868
- export type JsxElement<T extends ElementType, P extends Dict> = T extends ${componentName}<infer A, infer B>
2869
- ? ${componentName}<A, Pretty<DistributiveUnion<P, B>>>
2870
- : ${componentName}<T, P>
2871
-
2872
- export interface JsxFactory {
2873
- <T extends ElementType>(component: T): ${componentName}<T, {}>
2874
- <T extends ElementType, P extends RecipeVariantRecord>(component: T, recipe: RecipeDefinition<P>, options?: JsxFactoryOptions<JsxRecipeProps<T, RecipeSelection<P>>>): JsxElement<
2875
- T,
2876
- RecipeSelection<P>
2877
- >
2878
- <T extends ElementType, P extends RecipeFn>(component: T, recipeFn: P, options?: JsxFactoryOptions<JsxRecipeProps<T, P['__type']>>): JsxElement<T, P['__type']>
2879
- }
2880
-
2881
- export type JsxElements = {
2882
- [K in keyof JSX.IntrinsicElements]: ${componentName}<K, {}>
2883
- }
2884
-
2885
- export type ${upperName} = JsxFactory & JsxElements
2886
-
2887
- export type ${typeName}<T extends ElementType> = JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps, JsxStyleProps>
2888
-
2889
- export type ${variantName}<T extends ${componentName}<any, any>> = T extends ${componentName}<any, infer Props> ? Props : never
2890
- `
2891
- };
2892
- }
2893
- //#endregion
2894
- //#region src/artifacts/solid-jsx/create-style-context.ts
2895
- function generateSolidCreateStyleContext(ctx) {
2896
- const { factoryName } = ctx.jsx;
2897
- return {
2898
- js: outdent`
2899
- ${ctx.file.import("cx, css, sva", "../css/index")}
2900
- ${ctx.file.import(factoryName, "./factory")}
2901
- ${ctx.file.import("getDisplayName", "./factory-helper")}
2902
- import { createComponent, mergeProps } from 'solid-js/web'
2903
- import { createContext, createMemo, splitProps, useContext } from 'solid-js'
2904
-
2905
- function createSafeContext(contextName) {
2906
- const Context = createContext(undefined)
2907
- const useStyleContext = (componentName, slot) => {
2908
- const context = useContext(Context)
2909
- if (context === undefined) {
2910
- const componentInfo = componentName ? \`Component "\${componentName}"\` : 'A component'
2911
- const slotInfo = slot ? \` (slot: "\${slot}")\` : ''
2912
-
2913
- throw new Error(
2914
- \`\${componentInfo}\${slotInfo} cannot access \${contextName} because it's missing its Provider.\`
2915
- )
2916
- }
2917
- return context
2918
- }
2919
- return [Context, useStyleContext]
2920
- }
2921
-
2922
- export function createStyleContext(recipe) {
2923
- const isConfigRecipe = '__recipe__' in recipe
2924
- const recipeName = isConfigRecipe && recipe.__name__ ? recipe.__name__ : undefined
2925
- const contextName = recipeName ? \`createStyleContext("\${recipeName}")\` : 'createStyleContext'
2926
-
2927
- const [StyleContext, useStyleContext] = createSafeContext(contextName)
2928
- const svaFn = isConfigRecipe ? recipe : sva(recipe.config)
2929
-
2930
- const getResolvedProps = (props, slotStyles) => {
2931
- const { unstyled, ...restProps } = props
2932
- if (unstyled) return restProps
2933
- if (isConfigRecipe) {
2934
- return { ...restProps, class: cx(slotStyles, restProps.class) }
2935
- }
2936
- ${outdent.string(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`))}
2937
- }
2938
-
2939
- const withRootProvider = (Component, options) => {
2940
- const WithRootProvider = (props) => {
2941
- const [variantProps, otherProps] = svaFn.splitVariantProps(props)
2942
- const [local, propsWithoutChildren] = splitProps(otherProps, ['children'])
2943
-
2944
- const slotStyles = createMemo(() => {
2945
- const styles = isConfigRecipe ? svaFn(variantProps) : svaFn.raw(variantProps)
2946
- styles._classNameMap = svaFn.classNameMap
2947
- return styles
2948
- })
2949
-
2950
- const mergedProps = createMemo(() => {
2951
- if (!options?.defaultProps) return propsWithoutChildren
2952
- const defaults = typeof options.defaultProps === 'function'
2953
- ? options.defaultProps()
2954
- : options.defaultProps
2955
- return { ...defaults, ...propsWithoutChildren }
2956
- })
2957
-
2958
- return createComponent(StyleContext.Provider, {
2959
- get value() {
2960
- return slotStyles()
2961
- },
2962
- get children() {
2963
- return createComponent(
2964
- Component,
2965
- mergeProps(mergedProps, {
2966
- get children() {
2967
- return local.children
2968
- },
2969
- }),
2970
- )
2971
- },
2972
- })
2973
- }
2974
-
2975
- const componentName = getDisplayName(Component)
2976
- WithRootProvider.displayName = \`withRootProvider(\${componentName})\`
2977
- return WithRootProvider
2978
- }
2979
-
2980
- const withProvider = (Component, slot, options) => {
2981
- const StyledComponent = ${factoryName}(Component, {}, options)
2982
-
2983
- const WithProvider = (props) => {
2984
- const [variantProps, restProps] = svaFn.splitVariantProps(props)
2985
- const [local, propsWithoutChildren] = splitProps(restProps, ["children"])
2986
-
2987
- const slotStyles = createMemo(() => {
2988
- const styles = isConfigRecipe ? svaFn(variantProps) : svaFn.raw(variantProps)
2989
- styles._classNameMap = svaFn.classNameMap
2990
- return styles
2991
- })
2992
-
2993
- const resolvedProps = createMemo(() => {
2994
- const propsWithClass = {
2995
- ...propsWithoutChildren,
2996
- class: propsWithoutChildren.class ?? options?.defaultProps?.class,
2997
- }
2998
- const resolved = getResolvedProps(propsWithClass, slotStyles()[slot])
2999
- resolved.class = cx(resolved.class, slotStyles()._classNameMap[slot])
3000
- return resolved
3001
- })
3002
-
3003
- return createComponent(StyleContext.Provider, {
3004
- get value() {
3005
- return slotStyles()
3006
- },
3007
- get children() {
3008
- return createComponent(
3009
- StyledComponent,
3010
- mergeProps(resolvedProps, {
3011
- get children() {
3012
- return local.children
3013
- },
3014
- })
3015
- )
3016
- },
3017
- })
3018
- }
3019
-
3020
- const componentName = getDisplayName(Component)
3021
- WithProvider.displayName = \`withProvider(\${componentName})\`
3022
- return WithProvider
3023
- }
3024
-
3025
- const withContext = (Component, slot, options) => {
3026
- const StyledComponent = ${factoryName}(Component, {}, options)
3027
- const componentName = getDisplayName(Component)
3028
-
3029
- const WithContext = (props) => {
3030
- const slotStyles = useStyleContext(componentName, slot)
3031
- const [local, propsWithoutChildren] = splitProps(props, ["children"])
3032
-
3033
- const resolvedProps = createMemo(() => {
3034
- const propsWithClass = {
3035
- ...propsWithoutChildren,
3036
- class: propsWithoutChildren.class ?? options?.defaultProps?.class,
3037
- }
3038
- const resolved = getResolvedProps(propsWithClass, slotStyles[slot])
3039
- resolved.class = cx(resolved.class, slotStyles._classNameMap?.[slot])
3040
- return resolved
3041
- })
3042
-
3043
- return createComponent(
3044
- StyledComponent,
3045
- mergeProps(resolvedProps, {
3046
- get children() {
3047
- return local.children
3048
- },
3049
- })
3050
- )
3051
- }
3052
-
3053
- WithContext.displayName = \`withContext(\${componentName})\`
3054
- return WithContext
3055
- }
3056
-
3057
- return {
3058
- withRootProvider,
3059
- withProvider,
3060
- withContext,
3061
- }
3062
- }
3063
- `,
3064
- dts: outdent`
3065
- ${ctx.file.importType("SlotRecipeRuntimeFn, RecipeVariantProps", "../types/recipe")}
3066
- ${ctx.file.importType("JsxHTMLProps, JsxStyleProps, Assign", "../types/system-types")}
3067
- ${ctx.file.importType("JsxFactoryOptions, DataAttrs, MaybeAccessor, AsProps", "../types/jsx")}
3068
- import type { Component, JSX, ComponentProps } from 'solid-js'
3069
-
3070
- interface UnstyledProps {
3071
- unstyled?: boolean | undefined
3072
- }
3073
-
3074
- interface WithProviderOptions<P> {
3075
- defaultProps?: MaybeAccessor<Partial<P> & DataAttrs> | undefined
3076
- }
3077
-
3078
- type ElementType = keyof JSX.IntrinsicElements | Component<any>
3079
-
3080
- type SvaFn<S extends string = any> = SlotRecipeRuntimeFn<S, any>
3081
- interface SlotRecipeFn {
3082
- __type: any
3083
- __slot: string
3084
- (props?: any): any
3085
- }
3086
- type SlotRecipe = SvaFn | SlotRecipeFn
3087
-
3088
- type InferSlot<R extends SlotRecipe> = R extends SlotRecipeFn
3089
- ? R['__slot']
3090
- : R extends SvaFn<infer S>
3091
- ? S
3092
- : never
3093
-
3094
- type StyleContextProvider<T extends ElementType, R extends SlotRecipe> = Component<
3095
- JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps, Assign<RecipeVariantProps<R>, JsxStyleProps>>
3096
- >
3097
-
3098
- type StyleContextRootProvider<T extends ElementType, R extends SlotRecipe> = Component<
3099
- ComponentProps<T> & UnstyledProps & RecipeVariantProps<R>
3100
- >
3101
-
3102
- type StyleContextConsumer<T extends ElementType> = Component<
3103
- JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps, JsxStyleProps>
3104
- >
3105
-
3106
- export interface StyleContext<R extends SlotRecipe> {
3107
- withRootProvider: <T extends ElementType>(
3108
- Component: T,
3109
- options?: WithProviderOptions<ComponentProps<T>> | undefined
3110
- ) => StyleContextRootProvider<T, R>
3111
- withProvider: <T extends ElementType>(
3112
- Component: T,
3113
- slot: InferSlot<R>,
3114
- options?: JsxFactoryOptions<ComponentProps<T>> | undefined
3115
- ) => StyleContextProvider<T, R>
3116
- withContext: <T extends ElementType>(
3117
- Component: T,
3118
- slot: InferSlot<R>,
3119
- options?: JsxFactoryOptions<ComponentProps<T>> | undefined
3120
- ) => StyleContextConsumer<T>
3121
- }
3122
-
3123
- export declare function createStyleContext<R extends SlotRecipe>(recipe: R): StyleContext<R>
3124
- `
3125
- };
3126
- }
3127
- //#endregion
3128
- //#region src/artifacts/solid-jsx/jsx.string-literal.ts
3129
- function generateSolidJsxStringLiteralFactory(ctx) {
3130
- const { componentName, factoryName } = ctx.jsx;
3131
- return { js: outdent`
3132
- import { mergeProps, splitProps } from 'solid-js'
3133
- import { Dynamic, createComponent } from 'solid-js/web'
3134
- ${ctx.file.import("getDisplayName", "./factory-helper")}
3135
- ${ctx.file.import("css, cx", "../css/index")}
3136
-
3137
- function createStyled(element) {
3138
- const __base__ = element.__base__ || element
3139
- return function styledFn(template) {
3140
- const styles = css.raw(element.__styles__, template)
3141
-
3142
- const ${componentName} = (props) => {
3143
- const mergedProps = mergeProps({ as: __base__ }, props)
3144
- const [localProps, elementProps] = splitProps(mergedProps, ['as', 'class'])
3145
-
3146
- return createComponent(
3147
- Dynamic,
3148
- mergeProps(
3149
- {
3150
- get component() {
3151
- return localProps.as
3152
- },
3153
- get class() {
3154
- return cx(css(styles), localProps.class)
3155
- },
3156
- },
3157
- elementProps,
3158
- ),
3159
- )
3160
- }
3161
-
3162
- const name = getDisplayName(__base__)
3163
-
3164
- ${componentName}.displayName = \`${factoryName}.\${name}\`
3165
- ${componentName}.__styles__ = styles
3166
- ${componentName}.__base__ = __base__
3167
-
3168
- return ${componentName}
3169
- }
3170
- }
3171
-
3172
- function createJsxFactory() {
3173
- const cache = new Map()
3174
-
3175
- return new Proxy(createStyled, {
3176
- apply(_, __, args) {
3177
- return createStyled(...args)
3178
- },
3179
- get(_, el) {
3180
- if (!cache.has(el)) {
3181
- cache.set(el, createStyled(el))
3182
- }
3183
- return cache.get(el)
3184
- },
3185
- })
3186
- }
3187
-
3188
- export const ${factoryName} = /* @__PURE__ */ createJsxFactory()
3189
- ` };
3190
- }
3191
- //#endregion
3192
- //#region src/artifacts/solid-jsx/types.string-literal.ts
3193
- function generateSolidJsxStringLiteralTypes(ctx) {
3194
- const { factoryName, componentName, upperName, typeName } = ctx.jsx;
3195
- return {
3196
- jsxFactory: outdent`
3197
- ${ctx.file.importType(upperName, "../types/jsx")}
3198
- export declare const ${factoryName}: ${upperName}
3199
- `,
3200
- jsxType: outdent`
3201
- import type { Component, ComponentProps, JSX } from 'solid-js'
3202
-
3203
- interface Dict {
3204
- [k: string]: unknown
3205
- }
3206
-
3207
- export interface AsProps {
3208
- /**
3209
- * The element to render as
3210
- */
3211
- as?: ElementType | undefined
3212
- }
3213
-
3214
- export type ElementType<P = any> = keyof JSX.IntrinsicElements | Component<P>
3215
-
3216
- export type ${componentName}<T extends ElementType> = {
3217
- (args: { raw: readonly string[] | ArrayLike<string> }): (props: ComponentProps<T> & AsProps) => JSX.Element
3218
- displayName?: string | undefined
3219
- }
3220
-
3221
- export interface JsxFactory {
3222
- <T extends ElementType>(component: T): ${componentName}<T>
3223
- }
3224
-
3225
- export type JsxElements = {
3226
- [K in keyof JSX.IntrinsicElements]: ${componentName}<K>
3227
- }
3228
-
3229
- export type ${upperName} = JsxFactory & JsxElements
3230
-
3231
- export type ${typeName}<T extends ElementType> = ComponentProps<T>
3232
- `
3233
- };
3234
- }
3235
- //#endregion
3236
- //#region src/artifacts/vue-jsx/jsx.ts
3237
- function generateVueJsxFactory(ctx) {
3238
- const { factoryName, componentName } = ctx.jsx;
3239
- return { js: outdent`
3240
- import { defineComponent, h, computed } from 'vue'
3241
- ${ctx.file.import("defaultShouldForwardProp, composeShouldForwardProps, composeCvaFn, getDisplayName", "./factory-helper")}
3242
- ${ctx.file.import("isCssProperty", "./is-valid-prop")}
3243
- ${ctx.file.import("css, cx, cva", "../css/index")}
3244
- ${ctx.file.import("splitProps, normalizeHTMLProps", "../helpers")}
3245
-
3246
- function styledFn(Dynamic, configOrCva = {}, options = {}) {
3247
- const cvaFn = configOrCva.__cva__ || configOrCva.__recipe__ ? configOrCva : cva(configOrCva)
3248
-
3249
- const forwardFn = options.shouldForwardProp || defaultShouldForwardProp
3250
- const shouldForwardProp = (prop) => {
3251
- if (options.forwardProps?.includes(prop)) return true
3252
- return forwardFn(prop, cvaFn.variantKeys)
3253
- }
3254
-
3255
- const defaultProps = Object.assign(
3256
- options.dataAttr && configOrCva.__name__ ? { 'data-recipe': configOrCva.__name__ } : {},
3257
- options.defaultProps,
3258
- )
3259
-
3260
- const __cvaFn__ = composeCvaFn(Dynamic.__cva__, cvaFn)
3261
- const __shouldForwardProps__ = composeShouldForwardProps(Dynamic, shouldForwardProp)
3262
-
3263
- const __base__ = Dynamic.__base__ || Dynamic
3264
- const name = getDisplayName(__base__)
3265
-
3266
- const ${componentName} = defineComponent({
3267
- name: \`${factoryName}.\${name}\`,
3268
- inheritAttrs: false,
3269
- props: {
3270
- modelValue: null,
3271
- unstyled: { type: Boolean, default: false },
3272
- as: { type: [String, Object], default: __base__ }
3273
- },
3274
- setup(props, { slots, attrs, emit }) {
3275
- const combinedProps = computed(() => Object.assign({}, defaultProps, attrs))
3276
-
3277
- const splittedProps = computed(() => {
3278
- return splitProps(combinedProps.value, normalizeHTMLProps.keys, __shouldForwardProps__, __cvaFn__.variantKeys, isCssProperty)
3279
- })
3280
-
3281
- const recipeClass = computed(() => {
3282
- const [_htmlProps, _forwardedProps, variantProps, styleProps, _elementProps] = splittedProps.value
3283
- const { css: cssStyles, ...propStyles } = styleProps
3284
- const compoundVariantStyles = __cvaFn__.__getCompoundVariantCss__?.(variantProps);
3285
- return cx(__cvaFn__(variantProps, false), css(compoundVariantStyles, propStyles, cssStyles), combinedProps.value.className, combinedProps.value.class)
3286
- })
3287
-
3288
- const cvaClass = computed(() => {
3289
- const [_htmlProps, _forwardedProps, variantProps, styleProps, _elementProps] = splittedProps.value
3290
- const { css: cssStyles, ...propStyles } = styleProps
3291
- const cvaStyles = __cvaFn__.raw(variantProps)
3292
- return cx(css(cvaStyles, propStyles, cssStyles), combinedProps.value.className, combinedProps.value.class)
3293
- })
3294
-
3295
- const classes = computed(() => {
3296
- if (props.unstyled) {
3297
- const [_htmlProps, _forwardedProps, _variantProps, styleProps, _elementProps] = splittedProps.value
3298
- const { css: cssStyles, ...propStyles } = styleProps
3299
- return cx(css(propStyles, cssStyles), combinedProps.value.className, combinedProps.value.class)
3300
- }
3301
- return configOrCva.__recipe__ ? recipeClass.value : cvaClass.value
3302
- })
3303
-
3304
- const vModelProps = computed(() => {
3305
- const result = {};
3306
-
3307
- if (
3308
- props.as === 'input' &&
3309
- (props.type === 'checkbox' || props.type === 'radio')
3310
- ) {
3311
- result.checked = props.modelValue;
3312
- result.onChange = (event) => {
3313
- const checked = !event.currentTarget.checked;
3314
- emit('change', checked, event);
3315
- emit('update:modelValue', checked, event);
3316
- };
3317
- } else if (
3318
- props.as === 'input' ||
3319
- props.as === 'textarea' ||
3320
- props.as === 'select'
3321
- ) {
3322
- result.value = props.modelValue;
3323
- result.onInput = (event) => {
3324
- const value = event.currentTarget.value;
3325
- emit('input', value, event);
3326
- emit('update:modelValue', value, event);
3327
- };
3328
- }
3329
-
3330
- return result;
3331
- });
3332
-
3333
- return () => {
3334
- const [htmlProps, forwardedProps, _variantProps, _styleProps, elementProps] = splittedProps.value
3335
-
3336
- return h(
3337
- props.as,
3338
- {
3339
- ...forwardedProps,
3340
- ...elementProps,
3341
- ...normalizeHTMLProps(htmlProps),
3342
- ...vModelProps.value,
3343
- class: classes.value,
3344
- },
3345
- slots,
3346
- )
3347
- }
3348
- },
3349
- })
3350
-
3351
- ${componentName}.displayName = \`${factoryName}.\${name}\`
3352
- ${componentName}.__cva__ = __cvaFn__
3353
- ${componentName}.__base__ = __base__
3354
- ${componentName}.__shouldForwardProps__ = shouldForwardProp
3355
-
3356
- return ${componentName}
3357
- }
3358
-
3359
- 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';
3360
-
3361
- export const ${factoryName} = /* @__PURE__ */ styledFn.bind();
3362
-
3363
- tags.split(', ').forEach((tag) => {
3364
- ${factoryName}[tag] = ${factoryName}(tag);
3365
- });
3366
- ` };
3367
- }
3368
- //#endregion
3369
- //#region src/artifacts/vue-jsx/pattern.ts
3370
- function generateVueJsxPattern(ctx, filters) {
3371
- const { typeName, factoryName, styleProps: jsxStyleProps } = ctx.jsx;
3372
- return ctx.patterns.filterDetails(filters).map((pattern) => {
3373
- const { upperName, styleFnName, dashName, jsxName, props, blocklistType } = pattern;
3374
- const { description, jsxElement = "div", deprecated } = pattern.config;
3375
- return {
3376
- name: dashName,
3377
- js: outdent`
3378
- import { defineComponent, h, computed } from 'vue'
3379
- ${jsxStyleProps === "minimal" ? ctx.file.import("mergeCss", "../css/css") : ""}
3380
- ${ctx.file.import(styleFnName, `../patterns/${dashName}`)}
3381
- ${ctx.file.import(factoryName, "./factory")}
3382
-
3383
- export const ${jsxName} = /* @__PURE__ */ defineComponent({
3384
- name: '${jsxName}',
3385
- inheritAttrs: false,
3386
- props: ${JSON.stringify(props)},
3387
- setup(props, { attrs, slots }) {
3388
- ${match(jsxStyleProps).with("none", () => outdent`
3389
- const cssProps = computed(() => {
3390
- const styleProps = ${styleFnName}(props)
3391
- return { css: styleProps }
3392
- })
3393
-
3394
- return () => {
3395
- const mergedProps = { ...attrs, ...cssProps.value }
3396
- return h(${factoryName}.${jsxElement}, mergedProps, slots)
3397
- }
3398
- `).with("minimal", () => outdent`
3399
- const cssProps = computed(() => {
3400
- const styleProps = ${styleFnName}(props)
3401
- return { css: mergeCss(styleProps, attrs.css) }
3402
- })
3403
-
3404
- return () => {
3405
- const mergedProps = { ...attrs, ...cssProps.value }
3406
- return h(${factoryName}.${jsxElement}, mergedProps, slots)
3407
- }
3408
- `).with("all", () => outdent`
3409
- const styleProps = computed(() => ${styleFnName}(props))
3410
-
3411
- return () => {
3412
- const mergedProps = { ...styleProps.value, ...attrs }
3413
- return h(${factoryName}.${jsxElement}, mergedProps, slots)
3414
- }
3415
- `).exhaustive()}
3416
- }
3417
- })
3418
- `,
3419
- dts: outdent`
3420
- import type { FunctionalComponent } from 'vue'
3421
- ${ctx.file.importType(`${upperName}Properties`, `../patterns/${dashName}`)}
3422
- ${ctx.file.importType(typeName, "../types/jsx")}
3423
- ${ctx.file.importType("DistributiveOmit", "../types/system-types")}
3424
-
3425
- export interface ${upperName}Props extends ${upperName}Properties, DistributiveOmit<${typeName}<'${jsxElement}'>, keyof ${upperName}Properties ${blocklistType}> {}
3426
-
3427
- ${ctx.file.jsDocComment(description, { deprecated })}
3428
- export declare const ${jsxName}: FunctionalComponent<${upperName}Props>
3429
- `
3430
- };
3431
- });
3432
- }
3433
- //#endregion
3434
- //#region src/artifacts/vue-jsx/types.ts
3435
- function generateVueJsxTypes(ctx) {
3436
- const { factoryName, componentName, upperName, typeName, variantName } = ctx.jsx;
3437
- return {
3438
- jsxFactory: outdent`
3439
- ${ctx.file.importType(upperName, "../types/jsx")}
3440
-
3441
- export declare const ${factoryName}: ${upperName}
3442
- `,
3443
- jsxType: outdent`
3444
- import type { Component, FunctionalComponent, NativeElements } from 'vue'
3445
-
3446
- ${ctx.file.importType("RecipeDefinition, RecipeSelection, RecipeVariantRecord", "./recipe")}
3447
- ${ctx.file.importType("Assign, DistributiveOmit, DistributiveUnion, JsxHTMLProps, JsxStyleProps, Pretty", "./system-types")}
3448
-
3449
- export type IntrinsicElement = keyof NativeElements
3450
-
3451
- export type ElementType = IntrinsicElement | Component
3452
-
3453
- export type ComponentProps<T extends ElementType> = T extends IntrinsicElement
3454
- ? NativeElements[T]
3455
- : T extends Component<infer Props>
3456
- ? Props
3457
- : never
3458
-
3459
- interface Dict {
3460
- [k: string]: unknown
3461
- }
3462
-
3463
- export type DataAttrs = Record<\`data-\${string}\`, unknown>
911
+ // The slots that enclose other slots, matching \`Recipes.getScopeRoots\`. Their variant
912
+ // styles anchor \`@scope\` rules for every other slot, so only they take variants — a
913
+ // variant class on any other slot would name a rule that was never emitted.
914
+ //
915
+ // A list, because a component can span a portal and so occupy more than one subtree.
916
+ const declaredSlots = config.slots ?? []
917
+ const anchors = config.scopeRoots
918
+ ? config.scopeRoots.filter((slot) => declaredSlots.includes(slot))
919
+ : declaredSlots.includes('root') ? ['root'] : []
920
+
921
+ // \`classNameMap[slot]\` used to be joined on here, because the slot's classes were
922
+ // atomic and nothing else carried the name to target it in the DOM. The slot's cva is
923
+ // now named \`name__slot\` and returns that as its base class, so joining it again
924
+ // would just repeat it.
925
+ function svaFn(props) {
926
+ const result = slots.map(([slot, cvaFn]) => [
927
+ slot,
928
+ anchors.length && !anchors.includes(slot) ? cvaFn.config.className : cvaFn(props),
929
+ ])
930
+ return Object.fromEntries(result)
931
+ }
3464
932
 
3465
- export interface UnstyledProps {
3466
- /**
3467
- * Whether to remove recipe styles
3468
- */
3469
- unstyled?: boolean | undefined
3470
- }
933
+ function raw(props) {
934
+ const result = slots.map(([slot, cvaFn]) => [slot, cvaFn.raw(props)])
935
+ return Object.fromEntries(result)
936
+ }
3471
937
 
3472
- export interface AsProps {
3473
- /**
3474
- * The element to render as
3475
- */
3476
- as?: ElementType | undefined
3477
- }
938
+ const variants = config.variants ?? {};
939
+ const variantKeys = Object.keys(variants);
3478
940
 
3479
- export interface ${componentName}<T extends ElementType, P extends Dict = {}> extends FunctionalComponent<
3480
- JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps, Assign<JsxStyleProps, P>>
3481
- > {}
941
+ function splitVariantProps(props) {
942
+ return splitProps(props, variantKeys);
943
+ }
944
+ const getVariantProps = (variants) => ({ ...defaultVariants, ...compact(variants) })
3482
945
 
3483
- interface RecipeFn {
3484
- __type: any
3485
- }
946
+ const variantMap = Object.fromEntries(
947
+ Object.entries(variants).map(([key, value]) => [key, Object.keys(value)])
948
+ );
3486
949
 
3487
- export interface JsxFactoryOptions<TProps extends Dict> {
3488
- dataAttr?: boolean
3489
- defaultProps?: Partial<TProps> & DataAttrs
3490
- shouldForwardProp?: (prop: string, variantKeys: string[]) => boolean
3491
- forwardProps?: string[]
3492
- }
950
+ // Which slots each variant writes styles for.
951
+ //
952
+ // A scope reaches every slot inside an anchor's subtree. A slot under no anchor is
953
+ // not reached, and nothing at build time can detect that — reachability is a fact
954
+ // about the DOM. This is what says which slots a variant has to get to, so the
955
+ // component layer can thread the ones a scope cannot. Config slot recipes have always
956
+ // exposed it; an inline \`sva\` had no way to answer the question at all.
957
+ const slotsAffectedBy = Object.fromEntries(
958
+ Object.entries(variants).map(([variant, values]) => [
959
+ variant,
960
+ [...new Set(Object.values(values ?? {}).flatMap((slotStyles) => Object.keys(slotStyles ?? {})))],
961
+ ])
962
+ );
3493
963
 
3494
- export type JsxRecipeProps<T extends ElementType, P extends RecipeFn> = JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps, Assign<JsxStyleProps, P['__type']>>;
964
+ return Object.assign(memo(svaFn), {
965
+ __cva__: false,
966
+ raw,
967
+ config,
968
+ variantMap,
969
+ variantKeys,
970
+ classNameMap,
971
+ /** The slots that enclose other slots, and so anchor their variant rules. */
972
+ scopeRoots: anchors,
973
+ slotsAffectedBy,
974
+ splitVariantProps,
975
+ getVariantProps,
976
+ })
977
+ }
3495
978
 
3496
- export type JsxElement<T extends ElementType, P> = T extends ${componentName}<infer A, infer B>
3497
- ? ${componentName}<A, Pretty<DistributiveUnion<P, B>>>
3498
- : ${componentName}<T, P>
979
+ /**
980
+ * Report slots whose variant styles can never reach them.
981
+ *
982
+ * A scoped slot is styled through an \`@scope\` rule opened at an anchor, so it has to be
983
+ * rendered inside one. A slot moved out of every anchor's subtree — through a portal,
984
+ * with no second anchor named in \`scopeRoots\` — keeps its base styles and silently
985
+ * loses its variant styles. That renders *nearly* right, which is harder to notice than
986
+ * a total failure, and no build step can catch it: whether one element is inside another
987
+ * is a fact about the DOM.
988
+ *
989
+ * Checks for the anchor's *base* class rather than its variant class. An anchor always
990
+ * carries the base one; the variant class is absent whenever no variant is selected, and
991
+ * matching on it would report a slot that is correctly placed and simply unstyled.
992
+ *
993
+ * Development only — call it behind \`process.env.NODE_ENV !== 'production'\` so bundlers
994
+ * drop it, along with this function, from your production build.
995
+ *
996
+ * \`\`\`js
997
+ * import { auditSlotScopes, select } from '../styled-system/css'
998
+ *
999
+ * if (process.env.NODE_ENV !== 'production') auditSlotScopes([select], { observe: true })
1000
+ * \`\`\`
1001
+ */
1002
+ export function auditSlotScopes(recipes, options = {}) {
1003
+ const { root = typeof document === 'undefined' ? undefined : document, observe = false, onReport } = options
1004
+ if (!root) return () => {}
3499
1005
 
3500
- export interface JsxFactory {
3501
- <T extends ElementType>(component: T): ${componentName}<T, {}>
3502
- <T extends ElementType, P extends RecipeVariantRecord>(component: T, recipe: RecipeDefinition<P>, options?: JsxFactoryOptions<JsxRecipeProps<T, RecipeSelection<P>>>): JsxElement<
3503
- T,
3504
- RecipeSelection<P>
3505
- >
3506
- <T extends ElementType, P extends RecipeFn>(component: T, recipeFn: P, options?: JsxFactoryOptions<JsxRecipeProps<T, P['__type']>> ): JsxElement<T, P['__type']>
3507
- }
1006
+ const escape = (value) =>
1007
+ typeof CSS !== 'undefined' && CSS.escape ? CSS.escape(value) : value.replace(/[^\\w-]/g, '\\\\$&')
3508
1008
 
3509
- export type JsxElements = {
3510
- [K in IntrinsicElement]: ${componentName}<K, {}>
3511
- }
1009
+ const audit = () => {
1010
+ const found = []
3512
1011
 
3513
- export type ${upperName} = JsxFactory & JsxElements
1012
+ for (const recipe of recipes) {
1013
+ const anchors = recipe?.scopeRoots ?? []
1014
+ // Nothing is scoped, so every slot carries its own variant class and none of them
1015
+ // depends on where it is rendered.
1016
+ if (!anchors.length) continue
3514
1017
 
3515
- export type ${typeName}<T extends ElementType> = JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps, JsxStyleProps>
1018
+ const classNameMap = recipe.classNameMap ?? {}
1019
+ const anchorSelector = anchors
1020
+ .map((slot) => classNameMap[slot])
1021
+ .filter(Boolean)
1022
+ .map((className) => '.' + escape(className))
1023
+ .join(', ')
1024
+ if (!anchorSelector) continue
3516
1025
 
3517
- export type ${variantName}<T extends ${componentName}<any, any>> = T extends ${componentName}<any, infer Props> ? Props : never
3518
- `
3519
- };
3520
- }
3521
- //#endregion
3522
- //#region src/artifacts/vue-jsx/create-style-context.ts
3523
- function generateVueCreateStyleContext(ctx) {
3524
- const { factoryName } = ctx.jsx;
3525
- return {
3526
- js: outdent`
3527
- ${ctx.file.import("cx, css, sva", "../css/index")}
3528
- ${ctx.file.import(factoryName, "./factory")}
3529
- ${ctx.file.import("getDisplayName", "./factory-helper")}
3530
- import { defineComponent, provide, inject, computed, h } from 'vue'
3531
-
3532
- export function createStyleContext(recipe) {
3533
- const StyleContext = Symbol('StyleContext')
3534
- const isConfigRecipe = '__recipe__' in recipe
3535
- const recipeName = isConfigRecipe && recipe.__name__ ? recipe.__name__ : undefined
3536
- const contextName = recipeName ? \`createStyleContext("\${recipeName}")\` : 'createStyleContext'
3537
- const svaFn = isConfigRecipe ? recipe : sva(recipe.config)
3538
-
3539
- function useStyleContext(componentName, slot) {
3540
- const context = inject(StyleContext)
3541
- if (context === undefined) {
3542
- const componentInfo = componentName ? \`Component "\${componentName}"\` : 'A component'
3543
- const slotInfo = slot ? \` (slot: "\${slot}")\` : ''
3544
-
3545
- throw new Error(
3546
- \`\${componentInfo}\${slotInfo} cannot access \${contextName} because it's missing its Provider.\`
3547
- )
3548
- }
3549
- return context
3550
- }
3551
-
3552
- const getResolvedProps = (props, slotStyles) => {
3553
- const { unstyled, ...restProps } = props
3554
- if (unstyled) return restProps
3555
- if (isConfigRecipe) {
3556
- return { ...restProps, class: cx(slotStyles, restProps.class) }
3557
- }
3558
- ${outdent.string(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`))}
3559
- }
1026
+ const scoped = new Set(Object.values(recipe.slotsAffectedBy ?? {}).flat())
3560
1027
 
3561
- const withRootProvider = (Component, options) => {
3562
- const WithRootProvider = defineComponent({
3563
- props: svaFn.variantKeys,
3564
- setup(props, { slots }) {
3565
- const [variantProps, otherProps] = svaFn.splitVariantProps(props)
1028
+ for (const slot of scoped) {
1029
+ if (anchors.includes(slot)) continue
3566
1030
 
3567
- const slotStyles = computed(() => {
3568
- const styles = isConfigRecipe ? svaFn(variantProps) : svaFn.raw(variantProps)
3569
- styles._classNameMap = svaFn.classNameMap
3570
- return styles
3571
- })
1031
+ const className = classNameMap[slot]
1032
+ if (!className) continue
3572
1033
 
3573
- provide(StyleContext, slotStyles)
1034
+ for (const element of root.querySelectorAll('.' + escape(className))) {
1035
+ if (element.closest(anchorSelector)) continue
1036
+ found.push({ recipe: recipe.__name__, slot, className, element, anchors })
1037
+ }
1038
+ }
1039
+ }
3574
1040
 
3575
- const mergedProps = computed(() => {
3576
- if (!options?.defaultProps) return otherProps
3577
- return { ...options.defaultProps, ...otherProps }
3578
- })
1041
+ if (!found.length) return found
1042
+
1043
+ if (onReport) {
1044
+ onReport(found)
1045
+ } else {
1046
+ for (const problem of found) {
1047
+ console.warn(
1048
+ \`[bamboo] \${problem.recipe ?? 'slot recipe'}: the \\\`\${problem.slot}\\\` slot is rendered outside every \` +
1049
+ \`anchor (\${problem.anchors.join(', ')}), so its variant styles cannot reach it. \` +
1050
+ \`Add the enclosing slot to \\\`scopeRoots\\\`, or deliver the variant to this slot by hand.\`,
1051
+ problem.element,
1052
+ )
1053
+ }
1054
+ }
3579
1055
 
3580
- return () => h(Component, mergedProps.value, slots)
3581
- },
3582
- })
3583
-
3584
- const componentName = getDisplayName(Component)
3585
- WithRootProvider.displayName = \`withRootProvider(\${componentName})\`
3586
-
3587
- return WithRootProvider
1056
+ return found
3588
1057
  }
3589
1058
 
3590
- const withProvider = (Component, slot, options) => {
3591
- const StyledComponent = ${factoryName}(Component, {}, options)
3592
-
3593
- const WithProvider = defineComponent({
3594
- props: ["unstyled", ...svaFn.variantKeys],
3595
- inheritAttrs: false,
3596
- setup(inProps, { slots, attrs }) {
3597
- const props = computed(() => {
3598
- const propsWithClass = { ...inProps, ...attrs }
3599
- propsWithClass.class = propsWithClass.class ?? options?.defaultProps?.class
3600
- return propsWithClass
3601
- })
3602
- const res = computed(() => {
3603
- const [variantProps, restProps] = svaFn.splitVariantProps(props.value)
3604
- return { variantProps, restProps }
3605
- })
3606
-
3607
- const slotStyles = computed(() => {
3608
- const styles = isConfigRecipe ? svaFn(res.value.variantProps) : svaFn.raw(res.value.variantProps)
3609
- styles._classNameMap = svaFn.classNameMap
3610
- return styles
3611
- })
3612
-
3613
- provide(StyleContext, slotStyles)
3614
-
3615
- return () => {
3616
- const resolvedProps = getResolvedProps(res.value.restProps, slotStyles.value[slot])
3617
- resolvedProps.class = cx(resolvedProps.class, slotStyles.value._classNameMap[slot], attrs.class)
3618
- return h(StyledComponent, resolvedProps, slots)
3619
- }
3620
- },
3621
- })
3622
-
3623
- const componentName = getDisplayName(Component)
3624
- WithProvider.displayName = \`withProvider(\${componentName})\`
3625
-
3626
- return WithProvider
3627
- }
1059
+ audit()
3628
1060
 
3629
- const withContext = (Component, slot, options) => {
3630
- const StyledComponent = ${factoryName}(Component, {}, options)
3631
- const componentName = getDisplayName(Component)
3632
-
3633
- const WithContext = defineComponent({
3634
- props: ["unstyled"],
3635
- inheritAttrs: false,
3636
- setup(inProps, { slots, attrs }) {
3637
- const props = computed(() => {
3638
- const propsWithClass = { ...inProps, ...attrs }
3639
- propsWithClass.class = propsWithClass.class ?? options?.defaultProps?.class
3640
- return propsWithClass
3641
- })
3642
- const slotStyles = useStyleContext(componentName, slot)
3643
-
3644
- return () => {
3645
- const resolvedProps = getResolvedProps(props.value, slotStyles.value[slot])
3646
- resolvedProps.class = cx(resolvedProps.class, slotStyles.value._classNameMap[slot], attrs.class)
3647
- return h(StyledComponent, resolvedProps, slots)
3648
- }
3649
- },
1061
+ if (!observe || typeof MutationObserver === 'undefined') return () => {}
1062
+
1063
+ // Portaled content mounts after the first sweep, which is exactly the case this
1064
+ // exists to catch, so a one-shot pass would miss it.
1065
+ let queued = false
1066
+ const observer = new MutationObserver(() => {
1067
+ if (queued) return
1068
+ queued = true
1069
+ queueMicrotask(() => {
1070
+ queued = false
1071
+ audit()
3650
1072
  })
3651
-
3652
- WithContext.displayName = \`withContext(\${componentName})\`
3653
-
3654
- return WithContext
3655
- }
1073
+ })
1074
+ observer.observe(root === document ? document.documentElement : root, { childList: true, subtree: true })
3656
1075
 
3657
- return {
3658
- withRootProvider,
3659
- withProvider,
3660
- withContext,
3661
- }
1076
+ return () => observer.disconnect()
3662
1077
  }
3663
1078
  `,
3664
1079
  dts: outdent`
3665
- ${ctx.file.importType("SlotRecipeRuntimeFn, RecipeVariantProps", "../types/recipe")}
3666
- ${ctx.file.importType("JsxHTMLProps, JsxStyleProps, Assign", "../types/system-types")}
3667
- ${ctx.file.importType("JsxFactoryOptions, DataAttrs, AsProps", "../types/jsx")}
3668
- import type { Component, FunctionalComponent, NativeElements } from 'vue'
3669
-
3670
- interface UnstyledProps {
3671
- unstyled?: boolean | undefined
3672
- }
1080
+ ${ctx.file.importType("SlotRecipeCreatorFn", "../types/recipe")}
3673
1081
 
3674
- interface WithProviderOptions<P = {}> {
3675
- defaultProps?: (Partial<P> & DataAttrs) | undefined
3676
- }
1082
+ export declare const sva: SlotRecipeCreatorFn
3677
1083
 
3678
- // Add v-model support types
3679
- interface VModelProps {
3680
- modelValue?: any
3681
- 'onUpdate:modelValue'?: (value: any) => void
1084
+ export interface SlotScopeProblem {
1085
+ /** The recipe the slot belongs to, when it has a name. */
1086
+ recipe?: string
1087
+ /** The slot whose variant styles cannot reach it. */
1088
+ slot: string
1089
+ /** The constant class that slot carries. */
1090
+ className: string
1091
+ /** The element found outside every anchor. */
1092
+ element: Element
1093
+ /** The anchors that were looked for. */
1094
+ anchors: string[]
3682
1095
  }
3683
1096
 
3684
- type SvaFn<S extends string = any> = SlotRecipeRuntimeFn<S, any>
3685
- interface SlotRecipeFn {
3686
- __type: any
3687
- __slot: string
3688
- (props?: any): any
3689
- }
3690
- type SlotRecipe = SvaFn | SlotRecipeFn
3691
-
3692
- type InferSlot<R extends SlotRecipe> = R extends SlotRecipeFn ? R['__slot'] : R extends SvaFn<infer S> ? S : never
3693
-
3694
- type IntrinsicElement = keyof NativeElements
3695
- type ElementType = IntrinsicElement | Component
3696
-
3697
- type ComponentProps<T extends ElementType> = T extends IntrinsicElement
3698
- ? NativeElements[T]
3699
- : T extends Component<infer Props>
3700
- ? Props
3701
- : never
3702
-
3703
- type StyleContextProvider<T extends ElementType, R extends SlotRecipe> = FunctionalComponent<
3704
- JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps & VModelProps, Assign<RecipeVariantProps<R>, JsxStyleProps>>
3705
- >
3706
-
3707
- type StyleContextRootProvider<T extends ElementType, R extends SlotRecipe> = FunctionalComponent<
3708
- ComponentProps<T> & UnstyledProps & VModelProps & RecipeVariantProps<R>
3709
- >
3710
-
3711
- type StyleContextConsumer<T extends ElementType> = FunctionalComponent<
3712
- JsxHTMLProps<ComponentProps<T> & UnstyledProps & AsProps & VModelProps, JsxStyleProps>
3713
- >
3714
-
3715
- export interface StyleContext<R extends SlotRecipe> {
3716
- withRootProvider: <T extends ElementType>(
3717
- Component: T,
3718
- options?: WithProviderOptions<ComponentProps<T>> | undefined
3719
- ) => StyleContextRootProvider<T, R>
3720
- withProvider: <T extends ElementType>(
3721
- Component: T,
3722
- slot: InferSlot<R>,
3723
- options?: JsxFactoryOptions<ComponentProps<T>> | undefined
3724
- ) => StyleContextProvider<T, R>
3725
- withContext: <T extends ElementType>(
3726
- Component: T,
3727
- slot: InferSlot<R>,
3728
- options?: JsxFactoryOptions<ComponentProps<T>> | undefined
3729
- ) => StyleContextConsumer<T>
1097
+ export interface AuditSlotScopesOptions {
1098
+ /** Where to look. Defaults to \`document\`. */
1099
+ root?: ParentNode
1100
+ /** Re-check as the DOM changes, for content that mounts through a portal. */
1101
+ observe?: boolean
1102
+ /** Handle the findings yourself instead of warning to the console. */
1103
+ onReport?: (problems: SlotScopeProblem[]) => void
3730
1104
  }
3731
1105
 
3732
- export declare function createStyleContext<R extends SlotRecipe>(recipe: R): StyleContext<R>
1106
+ /**
1107
+ * Report slots whose variant styles can never reach them, in development.
1108
+ *
1109
+ * A scoped slot is styled through an \`@scope\` rule opened at an anchor, so it has to be
1110
+ * rendered inside one. A slot moved out of every anchor's subtree keeps its base styles
1111
+ * and silently loses its variant styles — which no build step can catch, because whether
1112
+ * one element is inside another is a fact about the DOM.
1113
+ *
1114
+ * Returns a function that stops observing.
1115
+ */
1116
+ export declare function auditSlotScopes(
1117
+ recipes: ReadonlyArray<unknown>,
1118
+ options?: AuditSlotScopesOptions,
1119
+ ): () => void
3733
1120
  `
3734
1121
  };
3735
1122
  }
3736
1123
  //#endregion
3737
- //#region src/artifacts/vue-jsx/jsx.string-literal.ts
3738
- function generateVueJsxStringLiteralFactory(ctx) {
3739
- const { componentName, factoryName } = ctx.jsx;
3740
- return { js: outdent`
3741
- import { defineComponent, h, computed } from 'vue'
3742
- ${ctx.file.import("getDisplayName", "./factory-helper")}
3743
- ${ctx.file.import("css, cx", "../css/index")}
3744
-
3745
- function createStyled(Dynamic) {
3746
- const name = getDisplayName(Dynamic)
3747
- const __base__ = Dynamic.__base__ || Dynamic
3748
-
3749
- function styledFn(template) {
3750
- const styles = css.raw(Dynamic.__styles__, template)
3751
-
3752
- const ${componentName} = defineComponent({
3753
- name: \`${factoryName}.\${name}\`,
3754
- inheritAttrs: false,
3755
- props: {
3756
- modelValue: null,
3757
- as: { type: [String, Object], default: __base__ }
3758
- },
3759
- setup(props, { slots, attrs, emit }) {
3760
- const classes = computed(() => {
3761
- return cx(css(styles), attrs.className)
3762
- })
3763
-
3764
- const vModelProps = computed(() => {
3765
- const result = {};
3766
-
3767
- if (
3768
- props.as === 'input' &&
3769
- (props.type === 'checkbox' || props.type === 'radio')
3770
- ) {
3771
- result.checked = props.modelValue;
3772
- result.onChange = (event) => {
3773
- const checked = !event.currentTarget.checked;
3774
- emit('change', checked, event);
3775
- emit('update:modelValue', checked, event);
3776
- };
3777
- } else if (
3778
- props.as === 'input' ||
3779
- props.as === 'textarea' ||
3780
- props.as === 'select'
3781
- ) {
3782
- result.value = props.modelValue;
3783
- result.onInput = (event) => {
3784
- const value = event.currentTarget.value;
3785
- emit('input', value, event);
3786
- emit('update:modelValue', value, event);
3787
- };
3788
- }
3789
-
3790
- return result;
3791
- });
3792
-
3793
- return () => {
3794
- return h(
3795
- props.as,
3796
- {
3797
- class: classes.value,
3798
- ...attrs,
3799
- ...vModelProps.value,
3800
- },
3801
- slots
3802
- )
3803
- }
3804
- },
3805
- })
3806
-
3807
- ${componentName}.__styles__ = styles
3808
- ${componentName}.__base__ = __base__
3809
-
3810
- return ${componentName}
3811
- }
3812
-
3813
- return styledFn
3814
- }
3815
-
3816
- 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';
3817
-
3818
- export const ${factoryName} = /* @__PURE__ */ createStyled.bind();
3819
-
3820
- tags.split(', ').forEach((tag) => {
3821
- ${factoryName}[tag] = createStyled(tag);
3822
- });
3823
- ` };
3824
- }
3825
- //#endregion
3826
- //#region src/artifacts/vue-jsx/types.string-literal.ts
3827
- function generateVueJsxStringLiteralTypes(ctx) {
3828
- const { factoryName, componentName, upperName, typeName } = ctx.jsx;
1124
+ //#region src/artifacts/js/token.ts
1125
+ function generateTokenJs(ctx) {
1126
+ const { tokens } = ctx;
1127
+ const map = /* @__PURE__ */ new Map();
1128
+ tokens.allTokens.forEach((token) => {
1129
+ const { varRef, isVirtual } = token.extensions;
1130
+ const value = isVirtual || token.extensions.condition !== "base" ? varRef : token.value;
1131
+ map.set(token.name, {
1132
+ value,
1133
+ variable: varRef
1134
+ });
1135
+ });
1136
+ const obj = Object.fromEntries(map);
3829
1137
  return {
3830
- jsxFactory: outdent`
3831
- ${ctx.file.importType(upperName, "../types/jsx")}
3832
-
3833
- export declare const ${factoryName}: ${upperName}
3834
- `,
3835
- jsxType: outdent`
3836
- import type { Component, FunctionalComponent, NativeElements } from 'vue'
3837
-
3838
- export type IntrinsicElement = keyof NativeElements
3839
-
3840
- export type ElementType = IntrinsicElement | Component
3841
-
3842
- export type ComponentProps<T extends ElementType> = T extends IntrinsicElement
3843
- ? NativeElements[T]
3844
- : T extends Component<infer Props>
3845
- ? Props
3846
- : never
3847
-
3848
- export interface AsProps {
3849
- /**
3850
- * The element to render as
3851
- */
3852
- as?: ElementType | undefined
3853
- }
1138
+ js: outdent$1`
1139
+ const tokens = ${JSON.stringify(obj, null, 2)}
3854
1140
 
3855
- export type ${componentName}<T extends ElementType> = {
3856
- (args: { raw: readonly string[] | ArrayLike<string> }): FunctionalComponent<ComponentProps<T> & AsProps>
3857
- }
1141
+ export function token(path, fallback) {
1142
+ return tokens[path]?.value || fallback
1143
+ }
3858
1144
 
3859
- export interface JsxFactory {
3860
- <T extends ElementType>(component: T): ${componentName}<T>
3861
- }
1145
+ function tokenVar(path, fallback) {
1146
+ return tokens[path]?.variable || fallback
1147
+ }
3862
1148
 
3863
- export type JsxElements = {
3864
- [K in IntrinsicElement]: ${componentName}<K>
3865
- }
1149
+ token.var = tokenVar
1150
+ `,
1151
+ dts: outdent$1`
1152
+ ${ctx.file.importType("Token", "./tokens")}
3866
1153
 
3867
- export type ${upperName} = JsxFactory & JsxElements
1154
+ export declare const token: {
1155
+ (path: Token, fallback?: string): string
1156
+ var: (path: Token, fallback?: string) => string
1157
+ }
3868
1158
 
3869
- export type ${typeName}<T extends ElementType> = ComponentProps<T>
1159
+ ${ctx.file.exportTypeStar("./tokens")}
3870
1160
  `
3871
1161
  };
3872
1162
  }
3873
1163
  //#endregion
3874
- //#region src/artifacts/jsx.ts
3875
- const typesMap = {
3876
- react: generateReactJsxTypes,
3877
- preact: generatePreactJsxTypes,
3878
- solid: generateSolidJsxTypes,
3879
- vue: generateVueJsxTypes,
3880
- qwik: generateQwikJsxTypes
3881
- };
3882
- const typesStringLiteralMap = {
3883
- react: generateReactJsxStringLiteralTypes,
3884
- solid: generateSolidJsxStringLiteralTypes,
3885
- qwik: generateQwikJsxStringLiteralTypes,
3886
- preact: generatePreactJsxStringLiteralTypes,
3887
- vue: generateVueJsxStringLiteralTypes
3888
- };
3889
- const isKnownFramework = (framework) => Boolean(typesMap[framework]);
3890
- function generateJsxTypes(ctx) {
3891
- if (!ctx.jsx.framework) return;
3892
- if (!isKnownFramework(ctx.jsx.framework)) return;
3893
- return (ctx.isTemplateLiteralSyntax ? typesStringLiteralMap[ctx.jsx.framework] : typesMap[ctx.jsx.framework])?.(ctx);
3894
- }
3895
- const factoryMap = {
3896
- react: generateReactJsxFactory,
3897
- solid: generateSolidJsxFactory,
3898
- preact: generatePreactJsxFactory,
3899
- vue: generateVueJsxFactory,
3900
- qwik: generateQwikJsxFactory
3901
- };
3902
- const factoryStringLiteralMap = {
3903
- react: generateReactJsxStringLiteralFactory,
3904
- solid: generateSolidJsxStringLiteralFactory,
3905
- qwik: generateQwikJsxStringLiteralFactory,
3906
- preact: generatePreactJsxStringLiteralFactory,
3907
- vue: generateVueJsxStringLiteralFactory
3908
- };
3909
- function generateJsxFactory(ctx) {
3910
- if (!ctx.jsx.framework) return;
3911
- if (!isKnownFramework(ctx.jsx.framework)) return;
3912
- return (ctx.isTemplateLiteralSyntax ? factoryStringLiteralMap[ctx.jsx.framework] : factoryMap[ctx.jsx.framework])?.(ctx);
3913
- }
3914
- const patternMap = {
3915
- react: generateReactJsxPattern,
3916
- solid: generateSolidJsxPattern,
3917
- preact: generatePreactJsxPattern,
3918
- vue: generateVueJsxPattern,
3919
- qwik: generateQwikJsxPattern
3920
- };
3921
- function generateJsxPatterns(ctx, filters) {
3922
- if (ctx.isTemplateLiteralSyntax || ctx.patterns.isEmpty() || !ctx.jsx.framework) return [];
3923
- if (!isKnownFramework(ctx.jsx.framework)) return;
3924
- return patternMap[ctx.jsx.framework](ctx, filters);
3925
- }
3926
- const createStyleContextMap = {
3927
- react: generateReactCreateStyleContext,
3928
- preact: generatePreactCreateStyleContext,
3929
- solid: generateSolidCreateStyleContext,
3930
- vue: generateVueCreateStyleContext
3931
- };
3932
- function generateJsxCreateStyleContext(ctx) {
3933
- if (ctx.isTemplateLiteralSyntax || !ctx.jsx.framework) return;
3934
- if (!isKnownFramework(ctx.jsx.framework)) return;
3935
- const generator = createStyleContextMap[ctx.jsx.framework];
3936
- return generator?.(ctx);
3937
- }
3938
- //#endregion
3939
1164
  //#region src/artifacts/generated/composition.d.ts.json
3940
1165
  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";
3941
1166
  //#endregion
@@ -4695,10 +1920,10 @@ var comments = {
4695
1920
  var content$5 = "export interface Part {\n selector: string\n}\n\nexport interface Parts {\n [key: string]: Part\n}\n";
4696
1921
  //#endregion
4697
1922
  //#region src/artifacts/generated/pattern.d.ts.json
4698
- 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 JSX element rendered by the pattern\n * @default 'div'\n */\n jsxElement?: 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 * The jsx element name this pattern will generate.\n */\n jsxName?: string\n /**\n * The jsx elements to track for this pattern. Can be string or Regexp.\n *\n * @default capitalize(pattern.name)\n * @example ['Button', 'Link', /Button$/]\n */\n jsx?: Array<string | RegExp>\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";
1923
+ 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";
4699
1924
  //#endregion
4700
1925
  //#region src/artifacts/generated/recipe.d.ts.json
4701
- 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 class name of the recipe.\n */\n className: string\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\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 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 * An optional class name that can be used to target slots in the DOM.\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 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> & RecipeConfigMeta\n";
1926
+ 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";
4702
1927
  //#endregion
4703
1928
  //#region src/artifacts/generated/selectors.d.ts.json
4704
1929
  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";
@@ -4707,7 +1932,7 @@ var content$2 = "import type { Pseudos } from './csstype'\n\ntype AriaAttributes
4707
1932
  var content$1 = "interface ConditionOptions {\n /**\n * The conditions to generate for the rule.\n * @example ['hover', 'focus']\n */\n conditions?: string[]\n /**\n * Whether to generate responsive styles for the rule.\n */\n responsive?: boolean\n}\n\nexport interface CssRule extends ConditionOptions {\n /**\n * The css properties to generate utilities for.\n * @example ['margin', 'padding']\n */\n properties: {\n [property: string]: Array<string | number>\n }\n}\n\ninterface RecipeRuleVariants {\n [variant: string]: boolean | string[]\n}\n\nexport type RecipeRuleObject = RecipeRuleVariants & ConditionOptions\nexport type RecipeRule = '*' | RecipeRuleObject\n\nexport type PatternRule = '*' | CssRule\n\nexport interface StaticCssOptions {\n /**\n * The css utility classes to generate.\n */\n css?: CssRule[]\n /**\n * The css recipes to generate.\n */\n recipes?:\n | '*'\n | {\n [recipe: string]: RecipeRule[]\n }\n /**\n * The css patterns to generate.\n */\n patterns?: {\n [pattern: string]: PatternRule[]\n }\n /**\n * The CSS themes to generate\n */\n themes?: string[]\n}\n";
4708
1933
  //#endregion
4709
1934
  //#region src/artifacts/generated/system-types.d.ts.json
4710
- var content = "import type { ConditionalValue, Nested } from './conditions'\nimport type { AtRule, Globals, PropertiesFallback } from './csstype'\nimport type { SystemProperties, CssVarProperties } from './style-props'\n\ntype String = string & {}\ntype Number = number & {}\n\nexport type Pretty<T> = { [K in keyof T]: T[K] } & {}\n\nexport type DistributiveOmit<T, K extends keyof any> = T extends unknown ? Omit<T, K> : never\n\nexport type DistributiveUnion<T, U> = {\n [K in keyof T]: K extends keyof U ? U[K] | T[K] : T[K]\n} & DistributiveOmit<U, keyof T>\n\nexport type Assign<T, U> = {\n [K in keyof T]: K extends keyof U ? U[K] : T[K]\n} & U\n\n/* -----------------------------------------------------------------------------\n * Native css properties\n * -----------------------------------------------------------------------------*/\n\ntype CornerShapeValue = 'round' | 'square' | 'bevel' | 'scoop' | 'notch' | 'squircle' | `superellipse(${number})`\n\nexport interface ModernCssProperties {\n /**\n * Controls whether the entire element should be draggable instead of its contents.\n */\n WebkitUserDrag?: Globals | 'auto' | 'element' | 'none'\n\n /**\n * Specifies whether an element can be used to drag the entire app window (Electron).\n */\n WebkitAppRegion?: Globals | 'drag' | 'no-drag'\n\n /**\n * Sets the horizontal spacing between table borders.\n */\n WebkitBorderHorizontalSpacing?: Globals | String | Number\n\n /**\n * Sets the vertical spacing between table borders.\n */\n WebkitBorderVerticalSpacing?: Globals | String | Number\n\n /**\n * Controls the display of text content for security purposes (e.g., password fields).\n */\n WebkitTextSecurity?: Globals | 'none' | 'circle' | 'disc' | 'square'\n\n /**\n * Specifies the shape of a box's corners within the area defined by the border-radius property.\n * @experimental\n * @see https://developer.mozilla.org/en-US/docs/Web/CSS/corner-shape\n */\n cornerShape?:\n | Globals\n | CornerShapeValue\n | `${CornerShapeValue} ${CornerShapeValue}`\n | `${CornerShapeValue} ${CornerShapeValue} ${CornerShapeValue}`\n | `${CornerShapeValue} ${CornerShapeValue} ${CornerShapeValue} ${CornerShapeValue}`\n | String\n}\n\nexport type CssProperty = keyof PropertiesFallback\n\nexport interface CssProperties extends PropertiesFallback<String | Number>, CssVarProperties, ModernCssProperties {}\n\nexport interface CssKeyframes {\n [name: string]: {\n [time: string]: CssProperties\n }\n}\n\n/* -----------------------------------------------------------------------------\n * Conditional css properties\n * -----------------------------------------------------------------------------*/\n\ninterface GenericProperties {\n [key: string]: ConditionalValue<String | Number | boolean>\n}\n\n/* -----------------------------------------------------------------------------\n * Native css props\n * -----------------------------------------------------------------------------*/\n\nexport type NestedCssProperties = Nested<CssProperties>\n\nexport type SystemStyleObject = Omit<Nested<SystemProperties & CssVarProperties>, 'base'>\n\nexport interface GlobalStyleObject {\n [selector: string]: SystemStyleObject\n}\nexport interface ExtendableGlobalStyleObject {\n [selector: string]: SystemStyleObject | undefined\n extend?: GlobalStyleObject | undefined\n}\n\n/* -----------------------------------------------------------------------------\n * Composition (text styles, layer styles)\n * -----------------------------------------------------------------------------*/\n\ntype FilterStyleObject<P extends string> = {\n [K in P]?: K extends keyof SystemStyleObject ? SystemStyleObject[K] : unknown\n}\n\nexport type CompositionStyleObject<Property extends string> = Nested<FilterStyleObject<Property> & CssVarProperties>\n\n/* -----------------------------------------------------------------------------\n * Font face\n * -----------------------------------------------------------------------------*/\n\nexport type GlobalFontfaceRule = Omit<AtRule.FontFaceFallback, 'src'> & Required<Pick<AtRule.FontFaceFallback, 'src'>>\n\nexport type FontfaceRule = Omit<GlobalFontfaceRule, 'fontFamily'>\n\nexport interface GlobalFontface {\n [name: string]: FontfaceRule | FontfaceRule[]\n}\n\nexport interface ExtendableGlobalFontface {\n [name: string]: FontfaceRule | FontfaceRule[] | GlobalFontface | undefined\n extend?: GlobalFontface | undefined\n}\n\n/* -----------------------------------------------------------------------------\n * Jsx style props\n * -----------------------------------------------------------------------------*/\ninterface WithCss {\n css?: SystemStyleObject | SystemStyleObject[]\n}\n\nexport type JsxStyleProps = SystemStyleObject & WithCss\n\nexport interface PatchedHTMLProps {\n htmlWidth?: string | number\n htmlHeight?: string | number\n htmlTranslate?: 'yes' | 'no' | undefined\n htmlContent?: string\n}\n\nexport type OmittedHTMLProps = 'color' | 'translate' | 'transition' | 'width' | 'height' | 'content'\n\ntype WithHTMLProps<T> = DistributiveOmit<T, OmittedHTMLProps> & PatchedHTMLProps\n\nexport type JsxHTMLProps<T extends Record<string, any>, P extends Record<string, any> = {}> = Assign<\n WithHTMLProps<T>,\n P\n>\n";
1935
+ var content = "import type { ConditionalValue, Nested } from './conditions'\nimport type { AtRule, Globals, PropertiesFallback } from './csstype'\nimport type { SystemProperties, CssVarProperties } from './style-props'\n\ntype String = string & {}\ntype Number = number & {}\n\nexport type Pretty<T> = { [K in keyof T]: T[K] } & {}\n\nexport type DistributiveOmit<T, K extends keyof any> = T extends unknown ? Omit<T, K> : never\n\nexport type DistributiveUnion<T, U> = {\n [K in keyof T]: K extends keyof U ? U[K] | T[K] : T[K]\n} & DistributiveOmit<U, keyof T>\n\nexport type Assign<T, U> = {\n [K in keyof T]: K extends keyof U ? U[K] : T[K]\n} & U\n\n/* -----------------------------------------------------------------------------\n * Native css properties\n * -----------------------------------------------------------------------------*/\n\ntype CornerShapeValue = 'round' | 'square' | 'bevel' | 'scoop' | 'notch' | 'squircle' | `superellipse(${number})`\n\nexport interface ModernCssProperties {\n /**\n * Controls whether the entire element should be draggable instead of its contents.\n */\n WebkitUserDrag?: Globals | 'auto' | 'element' | 'none'\n\n /**\n * Specifies whether an element can be used to drag the entire app window (Electron).\n */\n WebkitAppRegion?: Globals | 'drag' | 'no-drag'\n\n /**\n * Sets the horizontal spacing between table borders.\n */\n WebkitBorderHorizontalSpacing?: Globals | String | Number\n\n /**\n * Sets the vertical spacing between table borders.\n */\n WebkitBorderVerticalSpacing?: Globals | String | Number\n\n /**\n * Controls the display of text content for security purposes (e.g., password fields).\n */\n WebkitTextSecurity?: Globals | 'none' | 'circle' | 'disc' | 'square'\n\n /**\n * Specifies the shape of a box's corners within the area defined by the border-radius property.\n * @experimental\n * @see https://developer.mozilla.org/en-US/docs/Web/CSS/corner-shape\n */\n cornerShape?:\n | Globals\n | CornerShapeValue\n | `${CornerShapeValue} ${CornerShapeValue}`\n | `${CornerShapeValue} ${CornerShapeValue} ${CornerShapeValue}`\n | `${CornerShapeValue} ${CornerShapeValue} ${CornerShapeValue} ${CornerShapeValue}`\n | String\n}\n\nexport type CssProperty = keyof PropertiesFallback\n\nexport interface CssProperties extends PropertiesFallback<String | Number>, CssVarProperties, ModernCssProperties {}\n\nexport interface CssKeyframes {\n [name: string]: {\n [time: string]: CssProperties\n }\n}\n\n/* -----------------------------------------------------------------------------\n * Conditional css properties\n * -----------------------------------------------------------------------------*/\n\ninterface GenericProperties {\n [key: string]: ConditionalValue<String | Number | boolean>\n}\n\n/* -----------------------------------------------------------------------------\n * Native css props\n * -----------------------------------------------------------------------------*/\n\nexport type NestedCssProperties = Nested<CssProperties>\n\nexport type SystemStyleObject = Omit<Nested<SystemProperties & CssVarProperties>, 'base'>\n\n/**\n * The four `::view-transition-*` pseudo-elements a `viewTransition()` bag can style.\n *\n * `imagePair` is camelCase here and emitted as `::view-transition-image-pair`, matching\n * how every other property in a style object is authored.\n */\nexport interface ViewTransitionStyleObject {\n group?: SystemStyleObject\n imagePair?: SystemStyleObject\n old?: SystemStyleObject\n new?: SystemStyleObject\n}\n\nexport type ViewTransitionFn = (options: ViewTransitionStyleObject) => string\n\nexport interface GlobalStyleObject {\n [selector: string]: SystemStyleObject\n}\nexport interface ExtendableGlobalStyleObject {\n [selector: string]: SystemStyleObject | undefined\n extend?: GlobalStyleObject | undefined\n}\n\n/* -----------------------------------------------------------------------------\n * Composition (text styles, layer styles)\n * -----------------------------------------------------------------------------*/\n\ntype FilterStyleObject<P extends string> = {\n [K in P]?: K extends keyof SystemStyleObject ? SystemStyleObject[K] : unknown\n}\n\nexport type CompositionStyleObject<Property extends string> = Nested<FilterStyleObject<Property> & CssVarProperties>\n\n/* -----------------------------------------------------------------------------\n * Font face\n * -----------------------------------------------------------------------------*/\n\nexport type GlobalFontfaceRule = Omit<AtRule.FontFaceFallback, 'src'> & Required<Pick<AtRule.FontFaceFallback, 'src'>>\n\nexport type FontfaceRule = Omit<GlobalFontfaceRule, 'fontFamily'>\n\nexport interface GlobalFontface {\n [name: string]: FontfaceRule | FontfaceRule[]\n}\n\nexport interface ExtendableGlobalFontface {\n [name: string]: FontfaceRule | FontfaceRule[] | GlobalFontface | undefined\n extend?: GlobalFontface | undefined\n}\n\n/* -----------------------------------------------------------------------------\n * Jsx style props\n * -----------------------------------------------------------------------------*/\ninterface WithCss {\n css?: SystemStyleObject | SystemStyleObject[]\n}\n\nexport type JsxStyleProps = SystemStyleObject & WithCss\n\nexport interface PatchedHTMLProps {\n htmlWidth?: string | number\n htmlHeight?: string | number\n htmlTranslate?: 'yes' | 'no' | undefined\n htmlContent?: string\n}\n\nexport type OmittedHTMLProps = 'color' | 'translate' | 'transition' | 'width' | 'height' | 'content'\n\ntype WithHTMLProps<T> = DistributiveOmit<T, OmittedHTMLProps> & PatchedHTMLProps\n\nexport type JsxHTMLProps<T extends Record<string, any>, P extends Record<string, any> = {}> = Assign<\n WithHTMLProps<T>,\n P\n>\n";
4711
1936
  //#endregion
4712
1937
  //#region src/artifacts/types/generated.ts
4713
1938
  function getGeneratedTypes(ctx) {
@@ -4721,20 +1946,18 @@ function getGeneratedTypes(ctx) {
4721
1946
  selectors: ctx.file.rewriteTypeImport(content$2)
4722
1947
  };
4723
1948
  }
4724
- const jsxStyleProps = "export type JsxStyleProps = SystemStyleObject & WithCss";
4725
1949
  function getGeneratedSystemTypes(ctx) {
4726
- return { system: ctx.file.rewriteTypeImport(match(ctx.jsx.styleProps).with("all", () => content).with("minimal", () => content.replace("WithHTMLProps<T>,", "T,").replace(jsxStyleProps, "export type JsxStyleProps = WithCss")).with("none", () => content.replace("WithHTMLProps<T>,", "T,").replace(jsxStyleProps, "export type JsxStyleProps = {}")).exhaustive()) };
1950
+ return { system: ctx.file.rewriteTypeImport(content) };
4727
1951
  }
4728
1952
  //#endregion
4729
1953
  //#region src/artifacts/types/main.ts
4730
- const generateTypesEntry = (ctx, isJsxRequired) => {
1954
+ const generateTypesEntry = (ctx) => {
4731
1955
  const indexExports = [
4732
1956
  `import '${ctx.file.extDts("./global")}'`,
4733
1957
  ctx.file.exportTypeStar("./conditions"),
4734
1958
  ctx.file.exportTypeStar("./pattern"),
4735
1959
  ctx.file.exportTypeStar("./recipe"),
4736
1960
  ctx.file.exportTypeStar("./system-types"),
4737
- isJsxRequired && ctx.file.exportTypeStar("./jsx"),
4738
1961
  ctx.file.exportTypeStar("./style-props")
4739
1962
  ].filter(Boolean);
4740
1963
  return {
@@ -5239,7 +2462,7 @@ function generateThemesIndex(ctx, files) {
5239
2462
  //#endregion
5240
2463
  //#region src/artifacts/setup-artifacts.ts
5241
2464
  function setupHelpers(ctx) {
5242
- const code = generateHelpers(ctx);
2465
+ const code = generateHelpers();
5243
2466
  return {
5244
2467
  id: "helpers",
5245
2468
  files: [{
@@ -5278,21 +2501,8 @@ function setupDesignTokens(ctx) {
5278
2501
  ]
5279
2502
  };
5280
2503
  }
5281
- function setupJsxTypes(ctx) {
5282
- if (!ctx.jsx.framework) return;
5283
- const jsx = generateJsxTypes(ctx);
5284
- if (!jsx) return;
5285
- return {
5286
- id: "types-jsx",
5287
- dir: ctx.paths.types,
5288
- files: [{
5289
- file: ctx.file.extDts("jsx"),
5290
- code: jsx.jsxType
5291
- }]
5292
- };
5293
- }
5294
2504
  function setupEntryTypes(ctx) {
5295
- const entry = generateTypesEntry(ctx, Boolean(ctx.jsx.framework));
2505
+ const entry = generateTypesEntry(ctx);
5296
2506
  return {
5297
2507
  id: "types-entry",
5298
2508
  dir: ctx.paths.types,
@@ -5378,29 +2588,29 @@ function setupGeneratedSystemTypes(ctx) {
5378
2588
  };
5379
2589
  }
5380
2590
  function setupCss(ctx) {
5381
- const code = ctx.isTemplateLiteralSyntax ? generateStringLiteralCssFn(ctx) : generateCssFn(ctx);
5382
- const conditions = ctx.isTemplateLiteralSyntax ? generateStringLiteralConditions(ctx) : generateConditions(ctx);
2591
+ const code = generateCssFn(ctx);
2592
+ const conditions = generateConditions(ctx);
2593
+ const files = [
2594
+ {
2595
+ file: ctx.file.ext("conditions"),
2596
+ code: conditions.js
2597
+ },
2598
+ {
2599
+ file: ctx.file.ext("css"),
2600
+ code: code.js
2601
+ },
2602
+ {
2603
+ file: ctx.file.extDts("css"),
2604
+ code: code.dts
2605
+ }
2606
+ ];
5383
2607
  return {
5384
2608
  id: "css-fn",
5385
2609
  dir: ctx.paths.css,
5386
- files: [
5387
- {
5388
- file: ctx.file.ext("conditions"),
5389
- code: conditions.js
5390
- },
5391
- {
5392
- file: ctx.file.ext("css"),
5393
- code: code.js
5394
- },
5395
- {
5396
- file: ctx.file.extDts("css"),
5397
- code: code.dts
5398
- }
5399
- ]
2610
+ files
5400
2611
  };
5401
2612
  }
5402
2613
  function setupCva(ctx) {
5403
- if (ctx.isTemplateLiteralSyntax) return;
5404
2614
  const code = generateCvaFn(ctx);
5405
2615
  return {
5406
2616
  id: "cva",
@@ -5415,7 +2625,6 @@ function setupCva(ctx) {
5415
2625
  };
5416
2626
  }
5417
2627
  function setupSva(ctx) {
5418
- if (ctx.isTemplateLiteralSyntax) return;
5419
2628
  const code = generateSvaFn(ctx);
5420
2629
  return {
5421
2630
  id: "sva",
@@ -5430,7 +2639,7 @@ function setupSva(ctx) {
5430
2639
  };
5431
2640
  }
5432
2641
  function setupCx(ctx) {
5433
- const code = generateCx(ctx);
2642
+ const code = generateCx();
5434
2643
  return {
5435
2644
  id: "cx",
5436
2645
  dir: ctx.paths.css,
@@ -5495,7 +2704,6 @@ function setupRecipes(ctx, filters) {
5495
2704
  };
5496
2705
  }
5497
2706
  function setupPatternsIndex(ctx) {
5498
- if (ctx.isTemplateLiteralSyntax) return;
5499
2707
  const fileNames = ctx.patterns.details.map((pattern) => pattern.dashName);
5500
2708
  const index = {
5501
2709
  js: outdent$1.string(fileNames.map((file) => ctx.file.exportStar(`./${file}`)).join("\n")),
@@ -5514,7 +2722,6 @@ function setupPatternsIndex(ctx) {
5514
2722
  };
5515
2723
  }
5516
2724
  function setupPatterns(ctx, filters) {
5517
- if (ctx.isTemplateLiteralSyntax) return;
5518
2725
  const files = generatePattern(ctx, filters);
5519
2726
  if (!files) return;
5520
2727
  return {
@@ -5529,127 +2736,19 @@ function setupPatterns(ctx, filters) {
5529
2736
  }])
5530
2737
  };
5531
2738
  }
5532
- function setupJsxIsValidProp(ctx) {
5533
- if (!ctx.jsx.framework || ctx.isTemplateLiteralSyntax) return;
5534
- const isValidProp = generateIsValidProp(ctx);
5535
- return {
5536
- id: "jsx-is-valid-prop",
5537
- dir: ctx.paths.jsx,
5538
- files: [{
5539
- file: ctx.file.ext("is-valid-prop"),
5540
- code: isValidProp?.js
5541
- }, {
5542
- file: ctx.file.extDts("is-valid-prop"),
5543
- code: isValidProp?.dts
5544
- }]
5545
- };
5546
- }
5547
- function setupJsxFactory(ctx) {
5548
- if (!ctx.jsx.framework) return;
5549
- const types = generateJsxTypes(ctx);
5550
- if (!types) return;
5551
- const factory = generateJsxFactory(ctx);
5552
- if (!factory) return;
5553
- return {
5554
- id: "jsx-factory",
5555
- dir: ctx.paths.jsx,
5556
- files: [{
5557
- file: ctx.file.ext("factory"),
5558
- code: factory?.js
5559
- }, {
5560
- file: ctx.file.extDts("factory"),
5561
- code: types.jsxFactory
5562
- }]
5563
- };
5564
- }
5565
- function setupJsxHelpers(ctx) {
5566
- if (!ctx.jsx.framework) return;
5567
- const helpers = generatedJsxHelpers(ctx);
5568
- return {
5569
- id: "jsx-helpers",
5570
- dir: ctx.paths.jsx,
5571
- files: [{
5572
- file: ctx.file.ext("factory-helper"),
5573
- code: helpers.js
5574
- }]
5575
- };
5576
- }
5577
- function setupJsxPatterns(ctx, filters) {
5578
- if (!ctx.jsx.framework || ctx.isTemplateLiteralSyntax) return;
5579
- const patterns = generateJsxPatterns(ctx, filters);
5580
- if (!patterns) return;
5581
- return {
5582
- id: "jsx-patterns",
5583
- dir: ctx.paths.jsx,
5584
- files: [...patterns.flatMap((file) => [{
5585
- file: ctx.file.ext(file.name),
5586
- code: file.js
5587
- }, {
5588
- file: ctx.file.extDts(file.name),
5589
- code: file.dts
5590
- }])]
5591
- };
5592
- }
5593
- function setupJsxCreateStyleContext(ctx) {
5594
- if (!ctx.jsx.framework || ctx.isTemplateLiteralSyntax) return;
5595
- const createStyleContext = generateJsxCreateStyleContext(ctx);
5596
- if (!createStyleContext) return;
5597
- return {
5598
- id: "jsx-create-style-context",
5599
- dir: ctx.paths.jsx,
5600
- files: [{
5601
- file: ctx.file.ext("create-style-context"),
5602
- code: createStyleContext.js
5603
- }, {
5604
- file: ctx.file.extDts("create-style-context"),
5605
- code: createStyleContext.dts
5606
- }]
5607
- };
5608
- }
5609
- function setupJsxPatternsIndex(ctx) {
5610
- if (!ctx.jsx.framework) return;
5611
- const isStyleProp = !ctx.isTemplateLiteralSyntax;
5612
- const patternNames = ctx.patterns.details.map((pattern) => pattern.dashName);
5613
- const index = {
5614
- js: outdent$1`
5615
- ${ctx.file.exportStar("./factory")}
5616
- ${isStyleProp ? ctx.file.exportStar("./is-valid-prop") : ""}
5617
- ${isStyleProp && !["qwik", "svelte"].includes(ctx.jsx.framework) ? ctx.file.exportStar("./create-style-context") : ""}
5618
- ${isStyleProp ? outdent$1.string(patternNames.map((file) => ctx.file.exportStar(`./${file}`)).join("\n")) : ""}
5619
- `,
5620
- dts: outdent$1`
5621
- ${ctx.file.exportTypeStar("./factory")}
5622
- ${isStyleProp ? ctx.file.exportTypeStar("./is-valid-prop") : ""}
5623
- ${isStyleProp ? ctx.file.exportTypeStar("./create-style-context") : ""}
5624
- ${isStyleProp ? outdent$1.string(patternNames.map((file) => ctx.file.exportTypeStar(`./${file}`)).join("\n")) : ""}
5625
- ${ctx.file.exportType([ctx.jsx.typeName, ctx.jsx.componentName].join(", "), "../types/jsx")}
5626
- `
5627
- };
5628
- return {
5629
- id: "jsx-patterns-index",
5630
- dir: ctx.paths.jsx,
5631
- files: [{
5632
- file: ctx.file.ext("index"),
5633
- code: index.js
5634
- }, {
5635
- file: ctx.file.extDts("index"),
5636
- code: index.dts
5637
- }]
5638
- };
5639
- }
5640
2739
  function setupCssIndex(ctx) {
5641
2740
  const index = {
5642
2741
  js: outdent$1`
5643
2742
  ${ctx.file.exportStar("./css")}
5644
2743
  ${ctx.file.exportStar("./cx")}
5645
- ${ctx.isTemplateLiteralSyntax ? "" : ctx.file.exportStar("./cva")}
5646
- ${ctx.isTemplateLiteralSyntax ? "" : ctx.file.exportStar("./sva")}
2744
+ ${ctx.file.exportStar("./cva")}
2745
+ ${ctx.file.exportStar("./sva")}
5647
2746
  `,
5648
2747
  dts: outdent$1`
5649
2748
  ${ctx.file.exportTypeStar("./css")}
5650
2749
  ${ctx.file.exportTypeStar("./cx")}
5651
- ${ctx.isTemplateLiteralSyntax ? "" : ctx.file.exportTypeStar("./cva")}
5652
- ${ctx.isTemplateLiteralSyntax ? "" : ctx.file.exportTypeStar("./sva")}
2750
+ ${ctx.file.exportTypeStar("./cva")}
2751
+ ${ctx.file.exportTypeStar("./sva")}
5653
2752
  `
5654
2753
  };
5655
2754
  return {
@@ -5700,7 +2799,7 @@ const filterArtifactsFiles = (artifacts, filters) => {
5700
2799
  if (affected.recipes && !item.file.includes("index") && artifact?.dir?.includes("recipes")) {
5701
2800
  if (!affected.recipes.some((recipe) => item.file.includes(recipe))) return;
5702
2801
  }
5703
- if (affected.patterns && !item.file.includes("index") && (artifact?.dir?.includes("patterns") || artifact?.dir?.includes("jsx"))) {
2802
+ if (affected.patterns && !item.file.includes("index") && artifact?.dir?.includes("patterns")) {
5704
2803
  if (!affected.patterns.some((pattern) => item.file.includes(pattern))) return;
5705
2804
  }
5706
2805
  return true;
@@ -5715,7 +2814,6 @@ const entries = [
5715
2814
  ["package.json", setupPackageJson],
5716
2815
  ["helpers", setupHelpers],
5717
2816
  ["design-tokens", setupDesignTokens],
5718
- ["types-jsx", setupJsxTypes],
5719
2817
  ["types-entry", setupEntryTypes],
5720
2818
  ["types-styles", setupStyleTypes],
5721
2819
  ["types-conditions", setupConditionsTypes],
@@ -5730,12 +2828,6 @@ const entries = [
5730
2828
  ["recipes", setupRecipes],
5731
2829
  ["patterns-index", setupPatternsIndex],
5732
2830
  ["patterns", setupPatterns],
5733
- ["jsx-is-valid-prop", setupJsxIsValidProp],
5734
- ["jsx-factory", setupJsxFactory],
5735
- ["jsx-helpers", setupJsxHelpers],
5736
- ["jsx-patterns", setupJsxPatterns],
5737
- ["jsx-create-style-context", setupJsxCreateStyleContext],
5738
- ["jsx-patterns-index", setupJsxPatternsIndex],
5739
2831
  ["css-index", setupCssIndex],
5740
2832
  ["themes", setupThemes]
5741
2833
  ];
@@ -5785,6 +2877,61 @@ const generateGlobalCss = (ctx, sheet) => {
5785
2877
  sheet.processGlobalCss(globalCss);
5786
2878
  };
5787
2879
  //#endregion
2880
+ //#region src/artifacts/js/group-registry.ts
2881
+ /**
2882
+ * The grouped class names an encoder has accumulated.
2883
+ *
2884
+ * Derived through `groupClassName`, the same function the browser runtime calls — a
2885
+ * registry built any other way would be a third spelling of a name that already has two.
2886
+ * Unescaped, unlike `StyleDecoder`'s class names: this is compared against what `css()`
2887
+ * returns into a `class` attribute, not against a selector.
2888
+ *
2889
+ * Reads from the encoder rather than the decoder so it is available as soon as extraction
2890
+ * is, and so `codegen` can emit whatever is already known instead of blanking the file.
2891
+ */
2892
+ function collectGroupClassNames(ctx) {
2893
+ const names = [];
2894
+ ctx.encoder.grouped.forEach((_hashes, groupId) => {
2895
+ names.push(groupClassName(groupId, ctx.utility.toHash, ctx.utility.formatClassName));
2896
+ });
2897
+ return names.sort();
2898
+ }
2899
+ /**
2900
+ * The grouped classes the build emitted a rule for.
2901
+ *
2902
+ * Under `cssMode: 'grouped'` a class names a whole `css()` call, so the build has to have
2903
+ * seen that exact call to emit its rule. This is how the runtime tells the difference: a
2904
+ * class in here has CSS behind it, and one that is not falls back to naming its
2905
+ * declarations atomically as well.
2906
+ *
2907
+ * Written by two passes. `codegen` emits whatever the encoder already holds — usually
2908
+ * nothing, since it runs on config change before anything is extracted, but not blank when
2909
+ * it runs after a build. The CSS build then rewrites it with the set it emitted.
2910
+ *
2911
+ * An empty or stale registry is safe by construction: the runtime *adds* to the group class
2912
+ * rather than replacing it, so the worst a miss can do is name a class that matches nothing.
2913
+ */
2914
+ function generateGroupRegistry(ctx, classNames) {
2915
+ const names = classNames ?? collectGroupClassNames(ctx);
2916
+ return {
2917
+ js: outdent`
2918
+ // Generated by bamboo. Rewritten on every CSS build — do not edit.
2919
+ const packed = ${JSON.stringify(names.slice().sort().join(","))}
2920
+
2921
+ export const groups = /* @__PURE__ */ new Set(packed ? packed.split(',') : [])
2922
+ `,
2923
+ dts: outdent`
2924
+ /**
2925
+ * The grouped classes this build emitted a rule for. Internal — the generated \`css\`
2926
+ * consults it to decide whether a grouped class has CSS behind it.
2927
+ */
2928
+ export declare const groups: Set<string>;
2929
+ `
2930
+ };
2931
+ }
2932
+ /** Where the registry lives, so the writer and the importer cannot disagree about it. */
2933
+ const GROUP_REGISTRY_FILE = "groups";
2934
+ //#endregion
5788
2935
  //#region src/artifacts/css/keyframe-css.ts
5789
2936
  function generateKeyframeCss(ctx, sheet) {
5790
2937
  const { keyframes = {} } = ctx.config.theme ?? {};
@@ -5949,7 +3096,7 @@ const generateStaticCss = (ctx, sheet) => {
5949
3096
  //#endregion
5950
3097
  //#region src/spec/animation-styles.ts
5951
3098
  const generateAnimationStylesSpec = (ctx) => {
5952
- return generateCompositionStyleSpec("animation-styles", ctx.config.theme, ctx.config.jsxStyleProps);
3099
+ return generateCompositionStyleSpec("animation-styles", ctx.config.theme);
5953
3100
  };
5954
3101
  //#endregion
5955
3102
  //#region src/spec/color-palette.ts
@@ -5974,16 +3121,12 @@ const getColorPaletteExampleValues = (ctx, paletteValues) => {
5974
3121
  };
5975
3122
  const generateColorPaletteSpec = (ctx) => {
5976
3123
  if ((ctx.config.theme?.colorPalette)?.enabled === false) return null;
5977
- const jsxStyleProps = ctx.config.jsxStyleProps;
5978
3124
  const values = Array.from(ctx.tokens.view.colorPalettes.keys()).sort();
5979
3125
  if (!values.length) return null;
5980
3126
  const { examplePalette, bgToken, colorToken } = getColorPaletteExampleValues(ctx, values);
5981
3127
  const functionExamples = [];
5982
- const jsxExamples = [];
5983
3128
  const basicProps = { colorPalette: examplePalette };
5984
3129
  functionExamples.push(`css({ ${formatProps(basicProps)} })`);
5985
- const basicJsx = generateJsxExample(basicProps, jsxStyleProps);
5986
- if (basicJsx) jsxExamples.push(basicJsx);
5987
3130
  if (bgToken || colorToken) {
5988
3131
  const extendedProps = {
5989
3132
  colorPalette: examplePalette,
@@ -5991,25 +3134,17 @@ const generateColorPaletteSpec = (ctx) => {
5991
3134
  color: colorToken
5992
3135
  };
5993
3136
  functionExamples.push(`css({ ${formatProps(extendedProps)} })`);
5994
- const extendedJsx = generateJsxExample(extendedProps, jsxStyleProps);
5995
- if (extendedJsx) jsxExamples.push(extendedJsx);
5996
3137
  }
5997
3138
  return {
5998
3139
  type: "color-palette",
5999
3140
  data: {
6000
3141
  values,
6001
- functionExamples,
6002
- jsxExamples
3142
+ functionExamples
6003
3143
  }
6004
3144
  };
6005
3145
  };
6006
3146
  //#endregion
6007
3147
  //#region src/spec/conditions.ts
6008
- const generateConditionJsxExamples = (conditionName, jsxStyleProps = "all") => {
6009
- if (jsxStyleProps === "all") return [`<Box margin={{ base: '2', ${conditionName}: '4' }} />`, `<Box margin="2" ${conditionName}={{ margin: '4' }} />`];
6010
- if (jsxStyleProps === "minimal") return [`<Box css={{ margin: { base: '2', ${conditionName}: '4' } }} />`, `<Box css={{ margin: '2', ${conditionName}: { margin: '4' } }} />`];
6011
- return [];
6012
- };
6013
3148
  /**
6014
3149
  * Walk an object condition collecting every path that ends in `@slot`.
6015
3150
  * Each path is joined with spaces; multiple paths are joined with `; ` so the
@@ -6025,7 +3160,6 @@ const formatObjectCondition = (raw) => {
6025
3160
  return blocks.join("; ");
6026
3161
  };
6027
3162
  const generateConditionsSpec = (ctx) => {
6028
- const jsxStyleProps = ctx.config.jsxStyleProps;
6029
3163
  const breakpointKeys = new Set(Object.keys(ctx.conditions.breakpoints.conditions));
6030
3164
  return {
6031
3165
  type: "conditions",
@@ -6036,37 +3170,26 @@ const generateConditionsSpec = (ctx) => {
6036
3170
  return {
6037
3171
  name: conditionName,
6038
3172
  value: value ?? "",
6039
- functionExamples: [`css({ margin: { base: '2', ${conditionName}: '4' } })`, `css({ margin: '2', ${conditionName}: { margin: '4' } })`],
6040
- jsxExamples: generateConditionJsxExamples(conditionName, jsxStyleProps)
3173
+ functionExamples: [`css({ margin: { base: '2', ${conditionName}: '4' } })`, `css({ margin: '2', ${conditionName}: { margin: '4' } })`]
6041
3174
  };
6042
3175
  })
6043
3176
  };
6044
3177
  };
6045
3178
  //#endregion
6046
3179
  //#region src/spec/keyframes.ts
6047
- const generateKeyframeJsxExamples = (name, jsxStyleProps = "all") => {
6048
- const jsxExamples = [];
6049
- const example1 = generateJsxExample({ animationName: name }, jsxStyleProps);
6050
- if (example1) jsxExamples.push(example1);
6051
- const example2 = generateJsxExample({ animation: `${name} 1s ease-in-out infinite` }, jsxStyleProps);
6052
- if (example2) jsxExamples.push(example2);
6053
- return jsxExamples;
6054
- };
6055
3180
  const generateKeyframesSpec = (ctx) => {
6056
- const jsxStyleProps = ctx.config.jsxStyleProps;
6057
3181
  return {
6058
3182
  type: "keyframes",
6059
3183
  data: Object.keys(ctx.config.theme?.keyframes ?? {}).map((name) => ({
6060
3184
  name,
6061
- functionExamples: [`css({ animationName: '${name}' })`, `css({ animation: '${name} 1s ease-in-out infinite' })`],
6062
- jsxExamples: generateKeyframeJsxExamples(name, jsxStyleProps)
3185
+ functionExamples: [`css({ animationName: '${name}' })`, `css({ animation: '${name} 1s ease-in-out infinite' })`]
6063
3186
  }))
6064
3187
  };
6065
3188
  };
6066
3189
  //#endregion
6067
3190
  //#region src/spec/layer-styles.ts
6068
3191
  const generateLayerStylesSpec = (ctx) => {
6069
- return generateCompositionStyleSpec("layer-styles", ctx.config.theme, ctx.config.jsxStyleProps);
3192
+ return generateCompositionStyleSpec("layer-styles", ctx.config.theme);
6070
3193
  };
6071
3194
  //#endregion
6072
3195
  //#region src/spec/patterns.ts
@@ -6078,22 +3201,16 @@ const getExampleValue = (prop) => {
6078
3201
  return "<value>";
6079
3202
  };
6080
3203
  const generatePatternsSpec = (ctx) => {
6081
- const jsxStyleProps = ctx.config.jsxStyleProps;
6082
3204
  return {
6083
3205
  type: "patterns",
6084
3206
  data: ctx.patterns.details.map((node) => {
6085
3207
  const patternName = node.baseName;
6086
- const jsxName = node.jsxName;
6087
3208
  const properties = Object.entries(node.config.properties ?? {});
6088
3209
  const functionExamples = [];
6089
- const jsxExamples = [];
6090
- if (properties.length === 0) {
6091
- functionExamples.push(`${patternName}()`);
6092
- if (jsxStyleProps !== "none") jsxExamples.push(`<${jsxName} />`);
6093
- } else properties.forEach(([propName, prop]) => {
3210
+ if (properties.length === 0) functionExamples.push(`${patternName}()`);
3211
+ else properties.forEach(([propName, prop]) => {
6094
3212
  const exampleValue = getExampleValue(prop);
6095
3213
  functionExamples.push(`${patternName}({ ${propName}: ${exampleValue} })`);
6096
- if (jsxStyleProps !== "none") jsxExamples.push(`<${jsxName} ${propName}={${exampleValue}} />`);
6097
3214
  });
6098
3215
  const defaultValues = typeof node.config.defaultValues === "object" ? node.config.defaultValues : {};
6099
3216
  return {
@@ -6105,9 +3222,7 @@ const generatePatternsSpec = (ctx) => {
6105
3222
  description: prop.description,
6106
3223
  defaultValue: defaultValues[name]
6107
3224
  })),
6108
- jsx: jsxName,
6109
- functionExamples,
6110
- jsxExamples
3225
+ functionExamples
6111
3226
  };
6112
3227
  })
6113
3228
  };
@@ -6129,28 +3244,17 @@ const generateRecipesSpec = (ctx) => {
6129
3244
  type: "recipes",
6130
3245
  data: ctx.recipes.details.map((node) => {
6131
3246
  const recipeName = node.baseName;
6132
- const jsxName = node.jsxName;
6133
3247
  const variantKeys = Object.keys(node.variantKeyMap);
6134
3248
  const functionExamples = [];
6135
- const jsxExamples = [];
6136
- if (variantKeys.length === 0) {
6137
- functionExamples.push(`${recipeName}()`);
6138
- jsxExamples.push(`<${jsxName} />`);
6139
- } else {
3249
+ if (variantKeys.length === 0) functionExamples.push(`${recipeName}()`);
3250
+ else {
6140
3251
  variantKeys.forEach((variantKey) => {
6141
3252
  const firstValue = getFirstVariantValue(node.variantKeyMap, variantKey);
6142
- if (firstValue) {
6143
- functionExamples.push(`${recipeName}({ ${variantKey}: ${formatFunctionValue(firstValue)} })`);
6144
- jsxExamples.push(`<${jsxName} ${variantKey}=${formatJsxValue(firstValue)} />`);
6145
- }
3253
+ if (firstValue) functionExamples.push(`${recipeName}({ ${variantKey}: ${formatFunctionValue(firstValue)} })`);
6146
3254
  });
6147
3255
  if (variantKeys.length > 1) {
6148
3256
  const props = buildVariantProps(variantKeys, node.variantKeyMap, buildFunctionProps, ", ");
6149
- const jsxProps = buildVariantProps(variantKeys, node.variantKeyMap, buildJsxProps, " ");
6150
- if (props && jsxProps) {
6151
- functionExamples.push(`${recipeName}({ ${props} })`);
6152
- jsxExamples.push(`<${jsxName} ${jsxProps} />`);
6153
- }
3257
+ if (props) functionExamples.push(`${recipeName}({ ${props} })`);
6154
3258
  }
6155
3259
  }
6156
3260
  return {
@@ -6158,8 +3262,7 @@ const generateRecipesSpec = (ctx) => {
6158
3262
  description: node.config.description,
6159
3263
  variants: node.variantKeyMap,
6160
3264
  defaultVariants: node.config.defaultVariants ?? {},
6161
- functionExamples,
6162
- jsxExamples
3265
+ functionExamples
6163
3266
  };
6164
3267
  })
6165
3268
  };
@@ -6167,7 +3270,7 @@ const generateRecipesSpec = (ctx) => {
6167
3270
  //#endregion
6168
3271
  //#region src/spec/text-styles.ts
6169
3272
  const generateTextStylesSpec = (ctx) => {
6170
- return generateCompositionStyleSpec("text-styles", ctx.config.theme, ctx.config.jsxStyleProps);
3273
+ return generateCompositionStyleSpec("text-styles", ctx.config.theme);
6171
3274
  };
6172
3275
  //#endregion
6173
3276
  //#region src/spec/token-examples.ts
@@ -6196,26 +3299,21 @@ const CATEGORY_PROPERTY_MAP = {
6196
3299
  const getCategoryProperty = (category) => {
6197
3300
  return category ? CATEGORY_PROPERTY_MAP[category] ?? "color" : "color";
6198
3301
  };
6199
- const generateTokenExamples = (token, jsxStyleProps = "all") => {
3302
+ const generateTokenExamples = (token) => {
6200
3303
  const prop = getCategoryProperty(token.extensions?.category);
6201
3304
  const tokenName = token.extensions.prop;
6202
3305
  const fullTokenName = token.name;
6203
3306
  const functionExamples = [`css({ ${prop}: '${tokenName}' })`];
6204
3307
  const tokenFunctionExamples = [`token('${fullTokenName}')`];
6205
- const jsxExamples = [];
6206
- const jsxExample = generateJsxExample({ [prop]: tokenName }, jsxStyleProps);
6207
- if (jsxExample) jsxExamples.push(jsxExample);
6208
3308
  if (token.extensions.varRef) tokenFunctionExamples.push(`token.var('${fullTokenName}')`);
6209
3309
  return {
6210
3310
  functionExamples,
6211
- tokenFunctionExamples,
6212
- jsxExamples
3311
+ tokenFunctionExamples
6213
3312
  };
6214
3313
  };
6215
3314
  //#endregion
6216
3315
  //#region src/spec/themes.ts
6217
3316
  const generateThemeTokenGroups = (ctx, themeName, filterFn) => {
6218
- const jsxStyleProps = ctx.config.jsxStyleProps;
6219
3317
  const condName = "_theme" + capitalize(themeName);
6220
3318
  const themeTokens = ctx.tokens.allTokens.filter((token) => token.extensions.isVirtual && token.extensions.theme === themeName && filterFn(token));
6221
3319
  const byCategory = /* @__PURE__ */ new Map();
@@ -6228,7 +3326,7 @@ const generateThemeTokenGroups = (ctx, themeName, filterFn) => {
6228
3326
  return Array.from(byCategory.entries()).map(([category, typeTokens]) => {
6229
3327
  if (!typeTokens.length) return null;
6230
3328
  const firstToken = typeTokens[0];
6231
- const { functionExamples, tokenFunctionExamples, jsxExamples } = generateTokenExamples(firstToken, jsxStyleProps);
3329
+ const { functionExamples, tokenFunctionExamples } = generateTokenExamples(firstToken);
6232
3330
  return {
6233
3331
  type: category,
6234
3332
  values: typeTokens.map((token) => {
@@ -6248,8 +3346,7 @@ const generateThemeTokenGroups = (ctx, themeName, filterFn) => {
6248
3346
  };
6249
3347
  }),
6250
3348
  tokenFunctionExamples,
6251
- functionExamples,
6252
- jsxExamples
3349
+ functionExamples
6253
3350
  };
6254
3351
  }).filter(Boolean);
6255
3352
  };
@@ -6270,14 +3367,13 @@ const generateThemesSpec = (ctx) => {
6270
3367
  //#endregion
6271
3368
  //#region src/spec/tokens.ts
6272
3369
  const generateTokensSpec = (ctx) => {
6273
- const jsxStyleProps = ctx.config.jsxStyleProps;
6274
3370
  return {
6275
3371
  type: "tokens",
6276
3372
  data: Array.from(ctx.tokens.view.categoryMap.entries()).map(([category, tokenMap]) => {
6277
3373
  const typeTokens = Array.from(tokenMap.values()).filter((token) => !token.extensions.isSemantic && !token.extensions.isVirtual && !token.extensions.conditions && !token.extensions.isNegative);
6278
3374
  if (!typeTokens.length) return null;
6279
3375
  const firstToken = typeTokens[0];
6280
- const { functionExamples, tokenFunctionExamples, jsxExamples } = generateTokenExamples(firstToken, jsxStyleProps);
3376
+ const { functionExamples, tokenFunctionExamples } = generateTokenExamples(firstToken);
6281
3377
  return {
6282
3378
  type: category,
6283
3379
  values: typeTokens.map((token) => ({
@@ -6288,21 +3384,19 @@ const generateTokensSpec = (ctx) => {
6288
3384
  cssVar: token.extensions.varRef
6289
3385
  })),
6290
3386
  tokenFunctionExamples,
6291
- functionExamples,
6292
- jsxExamples
3387
+ functionExamples
6293
3388
  };
6294
3389
  }).filter(Boolean)
6295
3390
  };
6296
3391
  };
6297
3392
  const generateSemanticTokensSpec = (ctx) => {
6298
- const jsxStyleProps = ctx.config.jsxStyleProps;
6299
3393
  return {
6300
3394
  type: "semantic-tokens",
6301
3395
  data: Array.from(ctx.tokens.view.categoryMap.entries()).map(([category, tokenMap]) => {
6302
3396
  const typeTokens = Array.from(tokenMap.values()).filter((token) => (token.extensions.isSemantic || token.extensions.conditions) && !token.extensions.isVirtual);
6303
3397
  if (!typeTokens.length) return null;
6304
3398
  const firstToken = typeTokens[0];
6305
- const { functionExamples, tokenFunctionExamples, jsxExamples } = generateTokenExamples(firstToken, jsxStyleProps);
3399
+ const { functionExamples, tokenFunctionExamples } = generateTokenExamples(firstToken);
6306
3400
  return {
6307
3401
  type: category,
6308
3402
  values: typeTokens.map((token) => {
@@ -6322,8 +3416,7 @@ const generateSemanticTokensSpec = (ctx) => {
6322
3416
  };
6323
3417
  }),
6324
3418
  tokenFunctionExamples,
6325
- functionExamples,
6326
- jsxExamples
3419
+ functionExamples
6327
3420
  };
6328
3421
  }).filter(Boolean)
6329
3422
  };
@@ -6489,6 +3582,20 @@ var Generator = class extends Context {
6489
3582
  getParserCss = (decoder) => {
6490
3583
  return generateParserCss(this, decoder);
6491
3584
  };
3585
+ /**
3586
+ * The grouped class names this build emitted a rule for.
3587
+ *
3588
+ * Derived from the encoder rather than the decoder, so it is available as soon as
3589
+ * extraction finishes and before a stylesheet exists. Both sides go through
3590
+ * `groupClassName`, which is the same function the browser runtime calls — a registry
3591
+ * built any other way would be a third spelling of a name that already has two.
3592
+ *
3593
+ * Unescaped, unlike `StyleDecoder`'s class names: this is compared against what `css()`
3594
+ * returns into a `class` attribute, not against a selector. A grouped class is an opaque
3595
+ * hash, so the two only differ in principle, but the principle is the one that matters
3596
+ * here — the registry is only useful if it holds exactly what the runtime will ask about.
3597
+ */
3598
+ getGroupRegistry = () => collectGroupClassNames(this);
6492
3599
  getCss = (stylesheet) => {
6493
3600
  let css = (stylesheet ?? this.createSheet()).toCss({ minify: this.config.minify });
6494
3601
  if (this.hooks["cssgen:done"]) css = this.hooks["cssgen:done"]({
@@ -6632,4 +3739,4 @@ var Generator = class extends Context {
6632
3739
  };
6633
3740
  };
6634
3741
  //#endregion
6635
- export { Generator, getThemeCss };
3742
+ export { GROUP_REGISTRY_FILE, Generator, generateGroupRegistry, getThemeCss };