@bamboocss/generator 1.34.1 → 1.35.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -111,7 +111,6 @@ function generateConditions(ctx) {
111
111
  function generateCssFn(ctx) {
112
112
  const { utility, hash, prefix } = ctx;
113
113
  const { separator } = utility;
114
- const leafFallback = ctx.config.leafFallback ?? true;
115
114
  return {
116
115
  dts: outdent.outdent`
117
116
  ${ctx.file.importType("SystemStyleObject, ViewTransitionFn", "../types/index")}
@@ -160,14 +159,9 @@ function generateCssFn(ctx) {
160
159
  */
161
160
  export declare const viewTransition: ViewTransitionFn;
162
161
 
163
- /**
164
- * Internal. Emitted for the source transform, which rewrites a single dynamic style
165
- * leaf into a call to this. Not part of the authoring API.
166
- */
167
- export declare const cssLeaf: (prefix: string, prop: string, value: unknown) => string;
168
162
  `,
169
163
  js: outdent.outdent`
170
- ${ctx.file.import("cloneStyles, createCssUncached, hypenateProperty, leafClass, memo, viewTransitionClassName, withoutSpace", "../helpers")}
164
+ ${ctx.file.import("cloneStyles, createCssUncached, hypenateProperty, memo, viewTransitionClassName, withoutSpace", "../helpers")}
171
165
  ${ctx.file.import("sortConditions, finalizeConditions", "./conditions")}
172
166
  ${ctx.file.import("classNameByProp", "./utilities")}
173
167
  ${ctx.file.import("mergeCss, mergeCssUncached, resolveShorthand", "./merge-css")}
@@ -202,26 +196,6 @@ function generateCssFn(ctx) {
202
196
  // condition object would otherwise poison it for everyone after them.
203
197
  css.raw = (...styles) => cloneStyles(mergeCss(...styles))
204
198
 
205
-
206
- // Emitted for the source transform, which rewrites a single dynamic style leaf into a
207
- // call to this rather than leaving a \`css()\` behind. \`prefix\` is the class up to the
208
- // value, resolved at build time; \`prop\` names the property for the shapes \`leafClass\`
209
- // declines.
210
- ${leafFallback ? `export const cssLeaf = (prefix, prop, value) => {
211
- const className = leafClass(prefix, value)
212
- return className === undefined ? css({ [prop]: value }) : className
213
- }` : `export const cssLeaf = (prefix, prop, value) => {
214
- const className = leafClass(prefix, value)
215
- if (className === undefined) {
216
- throw new Error(
217
- \`[bamboocss] \\\`\${prop}\\\` got a \${Array.isArray(value) ? 'responsive array' : 'condition object'} from a \` +
218
- \`runtime value, and \\\`leafFallback\\\` is off. Write the conditions as a literal at the call site, so \` +
219
- \`the build resolves each branch, or set \\\`leafFallback: true\\\` to keep the runtime.\`,
220
- )
221
- }
222
- return className
223
- }`}
224
-
225
199
  // Sugar for the string form, so the feature has an import to discover, a signature to
226
200
  // hover and a name the editor can complete. The extractor evaluates the call, so the
227
201
  // value reaching \`css()\` is the same literal either way.
@@ -240,9 +214,8 @@ function generateCssFn(ctx) {
240
214
  /**
241
215
  * `mergeCss` and friends, plus the shorthand table they need.
242
216
  *
243
- * Split out of `css.mjs` because `cva` needs the merge and nothing else. While it lived
244
- * there, `cva` imported `createCss`, `cssLeaf`, `viewTransition` and the rest of the engine
245
- * to reach one function.
217
+ * Split out of `css.mjs` because `cva` needs the merge and nothing else. Keeping it separate
218
+ * prevents recipe-only imports from reaching the class-naming engine.
246
219
  *
247
220
  * The shorthand table lives here rather than beside the class names, and that is the second
248
221
  * half of the same problem. `cva` reaches `mergeCss` through `raw()` and `merge()` — both
@@ -253,8 +226,7 @@ function generateCssFn(ctx) {
253
226
  *
254
227
  * Separating them costs about 402 B gzipped in a bundle that still calls `css()` at runtime,
255
228
  * because the two halves share every property name and each now spells the list. That is the
256
- * trade, and it is the right way round: a `css()` call surviving to runtime already costs
257
- * 1,684 B for the engine behind it, and `failOnUnfolded` exists to drive that count to zero.
229
+ * trade, and it is the right way round: the Vite compiler removes authored runtime calls.
258
230
  *
259
231
  * Nothing here reaches the `styled-system/css` barrel. `css.raw(...)` is the authoring API
260
232
  * for merging style objects, and it is `mergeCss` plus the defensive clone that makes a
@@ -565,22 +537,15 @@ const declaration = outdent.default`
565
537
  export declare function cx(...args: Argument[]): string
566
538
 
567
539
  /**
568
- * Pick a recipe variant's class for a value only known at runtime.
569
- *
570
- * Emitted by the build when it folds an inline recipe call whose selection it could not
571
- * fully resolve — \`badge({ tone })\` becomes \`"badge" + cvaPick(tone, { … }, " badge--tone_a")\`.
572
- * Written by the transform, not by hand.
573
- *
574
- * The three cases are the ones \`cva\` itself distinguishes: \`undefined\` means the property
575
- * was never passed, so the recipe's default applies; a value the config declares selects
576
- * its class; anything else — including \`null\`, which \`compact\` deliberately keeps — selects
577
- * nothing, exactly as \`getRecipeClassNames\` skips a value it cannot find.
540
+ * Select a complete build-precompiled recipe StyleSet from a reduced decision table.
541
+ * Written by the source transform, not by hand.
578
542
  */
579
- export declare function cvaPick(
580
- value: unknown,
581
- classNameByValue: Record<string, string>,
582
- fallback?: string,
583
- ): string
543
+ export declare function cvaMap(
544
+ values: unknown[],
545
+ nodes: Array<[unknown, unknown, unknown[]]>,
546
+ leaves: unknown[],
547
+ root: number,
548
+ ): unknown
584
549
 
585
550
  /**
586
551
  * Split a props object into the listed keys and everything else.
@@ -616,18 +581,39 @@ function generateCx(ctx) {
616
581
  return str
617
582
  }
618
583
 
619
- // \`hasOwn\`, not a plain lookup: the table is an object literal, so \`cvaPick(v, t)\` with
620
- // \`v\` of "toString" or "constructor" would otherwise find the prototype's method and
621
- // concatenate a function into the class attribute. See the declaration for the cases.
622
- const cvaPick = (value, classNameByValue, fallback = '') => {
623
- if (value === undefined) return fallback
624
- // \`null\` before the lookup, because \`getRecipeClassNames\` rejects it on \`value == null\`
625
- // and a config may genuinely declare a variant value spelled "null".
626
- if (value === null) return ''
627
- return Object.hasOwn(classNameByValue, value) ? classNameByValue[value] : ''
584
+ // Each node is [miss, undefined, [key, child, key, child, ...]]. Children are either
585
+ // another non-negative node index or a negative leaf reference. Arrays avoid object-literal
586
+ // \`__proto__\` semantics, while string coercion matches a recipe's property lookup.
587
+ const cvaMap = (values, nodes, leaves, root) => {
588
+ let current = root
589
+ for (let i = 0; i < values.length && current >= 0; i++) {
590
+ const node = nodes[current]
591
+ if (!node) return ''
592
+
593
+ const value = values[i]
594
+ if (value === undefined) {
595
+ current = node[1]
596
+ continue
597
+ }
598
+ if (value === null) {
599
+ current = node[0]
600
+ continue
601
+ }
602
+
603
+ const key = String(value)
604
+ const entries = node[2]
605
+ let next = node[0]
606
+ for (let j = 0; j < entries.length; j += 2) {
607
+ if (entries[j] !== key) continue
608
+ next = entries[j + 1]
609
+ break
610
+ }
611
+ current = next
612
+ }
613
+ return current < 0 ? (leaves[~current] ?? '') : ''
628
614
  }
629
615
 
630
- export { cx, cvaPick, splitProps }
616
+ export { cx, cvaMap, splitProps }
631
617
  `,
632
618
  dts: declaration
633
619
  };
@@ -2286,7 +2272,7 @@ var comments = {
2286
2272
  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 /**\n * The css variable reference for a token path, or `fallback` when the path names no token.\n *\n * `token('spacing.4', '4')` is `var(--spacing-4)` where that token exists and `'4'` where it\n * does not — so a pattern can accept either a token name or a raw css value without knowing\n * the theme.\n */\n token: (path: string, fallback?: string) => string | undefined\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 * Which css properties this pattern accepts alongside its own `properties`.\n *\n * - `all` accepts any css property.\n * - `none` accepts only the pattern's declared `properties`.\n * - `{ except }` accepts any css property but the ones listed.\n *\n * One option because these were two — `strict: true` for \"none\" and an `@experimental`\n * `blocklist` for \"all but these\" — and the pair had an unrepresentable combination that\n * silently did nothing: the blocklist is applied only to the type that lists css\n * properties, which `strict: true` does not emit, so setting both dropped the blocklist.\n *\n * Types only. Nothing strips a blocked property at runtime — one passed anyway reaches\n * `transform` and emits css.\n *\n * @default 'all'\n */\n cssProps?: 'all' | 'none' | { except: LiteralUnion<CssProperty>[] }\n}\n";
2287
2273
  //#endregion
2288
2274
  //#region src/artifacts/generated/recipe.d.ts.json
2289
- 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 /** Each variant and the values it accepts. `Object.keys` it for the variant names. */\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 /** Each variant and the values it accepts. `Object.keys` it for the variant names. */\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";
2275
+ 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 /** Each variant and the values it accepts. `Object.keys` it for the variant names. */\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 * Semantic recipe name used by extraction-only integrations.\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`.\n *\n * The Vite compiler ignores this field when allocating declaration atoms: recipe identity\n * is not style identity, so identical declarations share one class across recipes.\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 /**\n * Required extraction metadata for a configured recipe: the key under which it is\n * declared in `theme.recipes`. The Vite compiler does not use it as style identity.\n */\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 /** Each variant and the values it accepts. `Object.keys` it for the variant names. */\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 * Semantic recipe name used by extraction-only integrations.\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`.\n *\n * The Vite compiler ignores this field when allocating declaration atoms: recipe and slot\n * identity do not enter generated class names.\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 in extraction-only named-rule output.\n *\n * The Vite compiler returns selected atoms directly for every slot and ignores this field.\n * In extraction-only output, 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 /**\n * Required extraction metadata for a configured recipe: the key under which it is\n * declared in `theme.slotRecipes`. The Vite compiler does not use it as style identity.\n */\n className: string\n }\n";
2290
2276
  //#endregion
2291
2277
  //#region src/artifacts/generated/selectors.d.ts.json
2292
2278
  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";
@@ -3248,8 +3234,7 @@ function setupCssIndex(ctx) {
3248
3234
  // during the bundler's transform and never typechecked, so a declaration here would buy
3249
3235
  // nothing but an autocomplete entry advertising them as API. Each stays fully typed in
3250
3236
  // the module that defines it, for anyone deep-importing on purpose.
3251
- ${ctx.file.reExport("cssLeaf", "./css")}
3252
- ${ctx.file.reExport("cvaPick, splitProps", "./cx")}
3237
+ ${ctx.file.reExport("cvaMap, splitProps", "./cx")}
3253
3238
  `,
3254
3239
  dts: outdent.default`
3255
3240
  ${ctx.file.reExportDts("css, fallback, viewTransition", "./css")}
package/dist/index.mjs CHANGED
@@ -85,7 +85,6 @@ function generateConditions(ctx) {
85
85
  function generateCssFn(ctx) {
86
86
  const { utility, hash, prefix } = ctx;
87
87
  const { separator } = utility;
88
- const leafFallback = ctx.config.leafFallback ?? true;
89
88
  return {
90
89
  dts: outdent`
91
90
  ${ctx.file.importType("SystemStyleObject, ViewTransitionFn", "../types/index")}
@@ -134,14 +133,9 @@ function generateCssFn(ctx) {
134
133
  */
135
134
  export declare const viewTransition: ViewTransitionFn;
136
135
 
137
- /**
138
- * Internal. Emitted for the source transform, which rewrites a single dynamic style
139
- * leaf into a call to this. Not part of the authoring API.
140
- */
141
- export declare const cssLeaf: (prefix: string, prop: string, value: unknown) => string;
142
136
  `,
143
137
  js: outdent`
144
- ${ctx.file.import("cloneStyles, createCssUncached, hypenateProperty, leafClass, memo, viewTransitionClassName, withoutSpace", "../helpers")}
138
+ ${ctx.file.import("cloneStyles, createCssUncached, hypenateProperty, memo, viewTransitionClassName, withoutSpace", "../helpers")}
145
139
  ${ctx.file.import("sortConditions, finalizeConditions", "./conditions")}
146
140
  ${ctx.file.import("classNameByProp", "./utilities")}
147
141
  ${ctx.file.import("mergeCss, mergeCssUncached, resolveShorthand", "./merge-css")}
@@ -176,26 +170,6 @@ function generateCssFn(ctx) {
176
170
  // condition object would otherwise poison it for everyone after them.
177
171
  css.raw = (...styles) => cloneStyles(mergeCss(...styles))
178
172
 
179
-
180
- // Emitted for the source transform, which rewrites a single dynamic style leaf into a
181
- // call to this rather than leaving a \`css()\` behind. \`prefix\` is the class up to the
182
- // value, resolved at build time; \`prop\` names the property for the shapes \`leafClass\`
183
- // declines.
184
- ${leafFallback ? `export const cssLeaf = (prefix, prop, value) => {
185
- const className = leafClass(prefix, value)
186
- return className === undefined ? css({ [prop]: value }) : className
187
- }` : `export const cssLeaf = (prefix, prop, value) => {
188
- const className = leafClass(prefix, value)
189
- if (className === undefined) {
190
- throw new Error(
191
- \`[bamboocss] \\\`\${prop}\\\` got a \${Array.isArray(value) ? 'responsive array' : 'condition object'} from a \` +
192
- \`runtime value, and \\\`leafFallback\\\` is off. Write the conditions as a literal at the call site, so \` +
193
- \`the build resolves each branch, or set \\\`leafFallback: true\\\` to keep the runtime.\`,
194
- )
195
- }
196
- return className
197
- }`}
198
-
199
173
  // Sugar for the string form, so the feature has an import to discover, a signature to
200
174
  // hover and a name the editor can complete. The extractor evaluates the call, so the
201
175
  // value reaching \`css()\` is the same literal either way.
@@ -214,9 +188,8 @@ function generateCssFn(ctx) {
214
188
  /**
215
189
  * `mergeCss` and friends, plus the shorthand table they need.
216
190
  *
217
- * Split out of `css.mjs` because `cva` needs the merge and nothing else. While it lived
218
- * there, `cva` imported `createCss`, `cssLeaf`, `viewTransition` and the rest of the engine
219
- * to reach one function.
191
+ * Split out of `css.mjs` because `cva` needs the merge and nothing else. Keeping it separate
192
+ * prevents recipe-only imports from reaching the class-naming engine.
220
193
  *
221
194
  * The shorthand table lives here rather than beside the class names, and that is the second
222
195
  * half of the same problem. `cva` reaches `mergeCss` through `raw()` and `merge()` — both
@@ -227,8 +200,7 @@ function generateCssFn(ctx) {
227
200
  *
228
201
  * Separating them costs about 402 B gzipped in a bundle that still calls `css()` at runtime,
229
202
  * because the two halves share every property name and each now spells the list. That is the
230
- * trade, and it is the right way round: a `css()` call surviving to runtime already costs
231
- * 1,684 B for the engine behind it, and `failOnUnfolded` exists to drive that count to zero.
203
+ * trade, and it is the right way round: the Vite compiler removes authored runtime calls.
232
204
  *
233
205
  * Nothing here reaches the `styled-system/css` barrel. `css.raw(...)` is the authoring API
234
206
  * for merging style objects, and it is `mergeCss` plus the defensive clone that makes a
@@ -539,22 +511,15 @@ const declaration = outdent$1`
539
511
  export declare function cx(...args: Argument[]): string
540
512
 
541
513
  /**
542
- * Pick a recipe variant's class for a value only known at runtime.
543
- *
544
- * Emitted by the build when it folds an inline recipe call whose selection it could not
545
- * fully resolve — \`badge({ tone })\` becomes \`"badge" + cvaPick(tone, { … }, " badge--tone_a")\`.
546
- * Written by the transform, not by hand.
547
- *
548
- * The three cases are the ones \`cva\` itself distinguishes: \`undefined\` means the property
549
- * was never passed, so the recipe's default applies; a value the config declares selects
550
- * its class; anything else — including \`null\`, which \`compact\` deliberately keeps — selects
551
- * nothing, exactly as \`getRecipeClassNames\` skips a value it cannot find.
514
+ * Select a complete build-precompiled recipe StyleSet from a reduced decision table.
515
+ * Written by the source transform, not by hand.
552
516
  */
553
- export declare function cvaPick(
554
- value: unknown,
555
- classNameByValue: Record<string, string>,
556
- fallback?: string,
557
- ): string
517
+ export declare function cvaMap(
518
+ values: unknown[],
519
+ nodes: Array<[unknown, unknown, unknown[]]>,
520
+ leaves: unknown[],
521
+ root: number,
522
+ ): unknown
558
523
 
559
524
  /**
560
525
  * Split a props object into the listed keys and everything else.
@@ -590,18 +555,39 @@ function generateCx(ctx) {
590
555
  return str
591
556
  }
592
557
 
593
- // \`hasOwn\`, not a plain lookup: the table is an object literal, so \`cvaPick(v, t)\` with
594
- // \`v\` of "toString" or "constructor" would otherwise find the prototype's method and
595
- // concatenate a function into the class attribute. See the declaration for the cases.
596
- const cvaPick = (value, classNameByValue, fallback = '') => {
597
- if (value === undefined) return fallback
598
- // \`null\` before the lookup, because \`getRecipeClassNames\` rejects it on \`value == null\`
599
- // and a config may genuinely declare a variant value spelled "null".
600
- if (value === null) return ''
601
- return Object.hasOwn(classNameByValue, value) ? classNameByValue[value] : ''
558
+ // Each node is [miss, undefined, [key, child, key, child, ...]]. Children are either
559
+ // another non-negative node index or a negative leaf reference. Arrays avoid object-literal
560
+ // \`__proto__\` semantics, while string coercion matches a recipe's property lookup.
561
+ const cvaMap = (values, nodes, leaves, root) => {
562
+ let current = root
563
+ for (let i = 0; i < values.length && current >= 0; i++) {
564
+ const node = nodes[current]
565
+ if (!node) return ''
566
+
567
+ const value = values[i]
568
+ if (value === undefined) {
569
+ current = node[1]
570
+ continue
571
+ }
572
+ if (value === null) {
573
+ current = node[0]
574
+ continue
575
+ }
576
+
577
+ const key = String(value)
578
+ const entries = node[2]
579
+ let next = node[0]
580
+ for (let j = 0; j < entries.length; j += 2) {
581
+ if (entries[j] !== key) continue
582
+ next = entries[j + 1]
583
+ break
584
+ }
585
+ current = next
586
+ }
587
+ return current < 0 ? (leaves[~current] ?? '') : ''
602
588
  }
603
589
 
604
- export { cx, cvaPick, splitProps }
590
+ export { cx, cvaMap, splitProps }
605
591
  `,
606
592
  dts: declaration
607
593
  };
@@ -2260,7 +2246,7 @@ var comments = {
2260
2246
  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 /**\n * The css variable reference for a token path, or `fallback` when the path names no token.\n *\n * `token('spacing.4', '4')` is `var(--spacing-4)` where that token exists and `'4'` where it\n * does not — so a pattern can accept either a token name or a raw css value without knowing\n * the theme.\n */\n token: (path: string, fallback?: string) => string | undefined\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 * Which css properties this pattern accepts alongside its own `properties`.\n *\n * - `all` accepts any css property.\n * - `none` accepts only the pattern's declared `properties`.\n * - `{ except }` accepts any css property but the ones listed.\n *\n * One option because these were two — `strict: true` for \"none\" and an `@experimental`\n * `blocklist` for \"all but these\" — and the pair had an unrepresentable combination that\n * silently did nothing: the blocklist is applied only to the type that lists css\n * properties, which `strict: true` does not emit, so setting both dropped the blocklist.\n *\n * Types only. Nothing strips a blocked property at runtime — one passed anyway reaches\n * `transform` and emits css.\n *\n * @default 'all'\n */\n cssProps?: 'all' | 'none' | { except: LiteralUnion<CssProperty>[] }\n}\n";
2261
2247
  //#endregion
2262
2248
  //#region src/artifacts/generated/recipe.d.ts.json
2263
- 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 /** Each variant and the values it accepts. `Object.keys` it for the variant names. */\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 /** Each variant and the values it accepts. `Object.keys` it for the variant names. */\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";
2249
+ 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 /** Each variant and the values it accepts. `Object.keys` it for the variant names. */\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 * Semantic recipe name used by extraction-only integrations.\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`.\n *\n * The Vite compiler ignores this field when allocating declaration atoms: recipe identity\n * is not style identity, so identical declarations share one class across recipes.\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 /**\n * Required extraction metadata for a configured recipe: the key under which it is\n * declared in `theme.recipes`. The Vite compiler does not use it as style identity.\n */\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 /** Each variant and the values it accepts. `Object.keys` it for the variant names. */\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 * Semantic recipe name used by extraction-only integrations.\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`.\n *\n * The Vite compiler ignores this field when allocating declaration atoms: recipe and slot\n * identity do not enter generated class names.\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 in extraction-only named-rule output.\n *\n * The Vite compiler returns selected atoms directly for every slot and ignores this field.\n * In extraction-only output, 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 /**\n * Required extraction metadata for a configured recipe: the key under which it is\n * declared in `theme.slotRecipes`. The Vite compiler does not use it as style identity.\n */\n className: string\n }\n";
2264
2250
  //#endregion
2265
2251
  //#region src/artifacts/generated/selectors.d.ts.json
2266
2252
  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";
@@ -3222,8 +3208,7 @@ function setupCssIndex(ctx) {
3222
3208
  // during the bundler's transform and never typechecked, so a declaration here would buy
3223
3209
  // nothing but an autocomplete entry advertising them as API. Each stays fully typed in
3224
3210
  // the module that defines it, for anyone deep-importing on purpose.
3225
- ${ctx.file.reExport("cssLeaf", "./css")}
3226
- ${ctx.file.reExport("cvaPick, splitProps", "./cx")}
3211
+ ${ctx.file.reExport("cvaMap, splitProps", "./cx")}
3227
3212
  `,
3228
3213
  dts: outdent$1`
3229
3214
  ${ctx.file.reExportDts("css, fallback, viewTransition", "./css")}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bamboocss/generator",
3
- "version": "1.34.1",
3
+ "version": "1.35.1",
4
4
  "description": "The css generator for css bamboo",
5
5
  "homepage": "https://bamboocss.com",
6
6
  "license": "MIT",
@@ -38,12 +38,12 @@
38
38
  "pluralize": "8.0.0",
39
39
  "postcss": "8.5.26",
40
40
  "ts-pattern": "5.9.0",
41
- "@bamboocss/core": "1.34.1",
42
- "@bamboocss/is-valid-prop": "^1.34.1",
43
- "@bamboocss/logger": "1.34.1",
44
- "@bamboocss/shared": "1.34.1",
45
- "@bamboocss/token-dictionary": "1.34.1",
46
- "@bamboocss/types": "1.34.1"
41
+ "@bamboocss/core": "1.35.1",
42
+ "@bamboocss/is-valid-prop": "^1.35.1",
43
+ "@bamboocss/logger": "1.35.1",
44
+ "@bamboocss/shared": "1.35.1",
45
+ "@bamboocss/token-dictionary": "1.35.1",
46
+ "@bamboocss/types": "1.35.1"
47
47
  },
48
48
  "devDependencies": {
49
49
  "@types/pluralize": "0.0.33"