@bamboocss/generator 1.46.3 → 1.47.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -109,8 +109,6 @@ function generateConditions(ctx) {
109
109
  //#endregion
110
110
  //#region src/artifacts/js/css-fn.ts
111
111
  function generateCssFn(ctx) {
112
- const { utility, hash, prefix } = ctx;
113
- const { separator } = utility;
114
112
  return {
115
113
  dts: outdent.outdent`
116
114
  ${ctx.file.importType("SystemStyleObject, ViewTransitionFn", "../types/index")}
@@ -161,39 +159,12 @@ function generateCssFn(ctx) {
161
159
 
162
160
  `,
163
161
  js: outdent.outdent`
164
- ${ctx.file.import("cloneStyles, createCssUncached, hypenateProperty, memo, viewTransitionClassName, withoutSpace", "../helpers")}
165
- ${ctx.file.import("sortConditions, finalizeConditions", "./conditions")}
166
- ${ctx.file.import("classNameByProp", "./utilities")}
167
- ${ctx.file.import("mergeCss, mergeCssUncached, resolveShorthand", "./merge-css")}
168
-
169
- const context = {
170
- ${hash.className ? "hash: true," : ""}
171
- conditions: {
172
- shift: sortConditions,
173
- finalize: finalizeConditions,
174
- },
175
- utility: {
176
- ${prefix.className ? "prefix: " + JSON.stringify(prefix.className) + "," : ""}
177
- transform: ${utility.hasShorthand ? `(prop, value) => {
178
- const key = resolveShorthand(prop)
179
- const propKey = classNameByProp.get(key) || hypenateProperty(key)
180
- return { className: \`$\{propKey}${separator}$\{withoutSpace(value)}\` }
181
- }` : `(key, value) => ({ className: \`$\{classNameByProp.get(key) || hypenateProperty(key)}${separator}$\{withoutSpace(value)}\` })`},
182
- ${utility.hasShorthand ? "hasShorthand: true," : ""}
183
- toHash: ${utility.toHash},
184
- resolveShorthand: ${utility.hasShorthand ? "resolveShorthand" : "prop => prop"},
185
- }
186
- }
162
+ ${ctx.file.import("cloneStyles, uncompiledStyle", "../helpers")}
163
+ ${ctx.file.import("mergeCss", "./merge-css")}
187
164
 
188
- const cssFn = createCssUncached(context)
189
- // \`createCssUncached\` and \`mergeCssUncached\` rather than their cached forms: this
190
- // callback runs only when the memo above it missed, and a miss means these arguments
191
- // have not been seen — so a second cache keyed on the same arguments, or on the merge
192
- // derived from them, can only miss too, after paying for the lookup.
193
- export const css = /* @__PURE__ */ memo((...styles) => cssFn(mergeCssUncached(...styles)))
194
- // The cached merge here, since \`raw\` is called straight from user code with no memo
195
- // above it. The merged result is cached and shared, so a caller mutating a nested
196
- // condition object would otherwise poison it for everyone after them.
165
+ export const css = (..._styles) => uncompiledStyle('css')
166
+ // \`raw\` is a style object, not a class string. The compiler leaves it; \`css(css.raw(...))\`
167
+ // is what has to fold.
197
168
  css.raw = (...styles) => cloneStyles(mergeCss(...styles))
198
169
 
199
170
  // Sugar for the string form, so the feature has an import to discover, a signature to
@@ -201,10 +172,7 @@ function generateCssFn(ctx) {
201
172
  // value reaching \`css()\` is the same literal either way.
202
173
  export const fallback = (...values) => \`fallback($\{values.join(', ')})\`
203
174
 
204
- // The class is the whole return value — the CSS behind it was emitted at build time
205
- // from the same options, hashed by this same function. A call the extractor never saw
206
- // still returns a class, exactly as \`css()\` does for a value it never saw.
207
- export const viewTransition = (options) => viewTransitionClassName(options, ${JSON.stringify(prefix.className ?? "")})
175
+ export const viewTransition = (_options) => uncompiledStyle('viewTransition')
208
176
 
209
177
  `
210
178
  };
@@ -310,7 +278,7 @@ function generateCvaFn(ctx) {
310
278
  const withPrefix = prefix.className ? `(className) => className ? ${JSON.stringify(prefix.className)} + '-' + className : ${JSON.stringify(prefix.className)}` : `(className) => className`;
311
279
  return {
312
280
  js: outdent.outdent`
313
- ${ctx.file.import("cloneStyles, compact, getRecipeClassNames, getRecipeIdentity, mergeProps, memo, splitProps, toHash, uniq", "../helpers")}
281
+ ${ctx.file.import("cloneStyles, compact, getRecipeIdentity, mergeProps, memo, splitProps, toHash, uniq, uncompiledStyle", "../helpers")}
314
282
  ${ctx.file.import("mergeCss", "./merge-css")}
315
283
  ${ctx.file.import("cx", "./cx")}
316
284
 
@@ -380,8 +348,8 @@ function generateCvaFn(ctx) {
380
348
  // Compound variants are absent on purpose. Their rule selects on the variant classes
381
349
  // already in this list — \`.btn--size_sm.btn--tone_a\` — so it applies without anything
382
350
  // being added here, and adding a class for it would name a rule that does not exist.
383
- function cvaFn(props) {
384
- return getRecipeClassNames(name, variants, getVariantProps(props), '${utility.separator}', formatRecipeClass)
351
+ function cvaFn(_props) {
352
+ return uncompiledStyle('cva')
385
353
  }
386
354
 
387
355
  const variantKeys = Object.keys(variants)
@@ -634,6 +602,18 @@ function generateHelpers() {
634
602
  export function __objRest(source, exclude) {
635
603
  return Object.fromEntries(Object.entries(source).filter(([key]) => !exclude.includes(key)))
636
604
  }
605
+
606
+ /**
607
+ * Style-producing calls compile away. Hitting this means \`@bamboocss/vite\` did not fold
608
+ * the call — missing plugin, a file outside \`include\`, or a shape the compiler rejects.
609
+ */
610
+ export function uncompiledStyle(name) {
611
+ throw new Error(
612
+ 'bamboocss: ' +
613
+ name +
614
+ '() was not compiled. Add \`bamboocss()\` from \`@bamboocss/vite\` and import \`virtual:bamboo.css\`. See https://bamboocss.com/docs/installation/vite',
615
+ )
616
+ }
637
617
  ` };
638
618
  }
639
619
  //#endregion
@@ -752,7 +732,7 @@ function generatePattern(ctx, filters) {
752
732
  transform,
753
733
  defaultValues
754
734
  })) ?? "";
755
- const helperImports = ["getPatternStyles, createPatternFns, memo"];
735
+ const helperImports = ["getPatternStyles, createPatternFns"];
756
736
  if (patternConfigFn.includes("__spreadValues")) helperImports.push("__spreadValues");
757
737
  if (patternConfigFn.includes("__objRest")) helperImports.push("__objRest");
758
738
  return {
@@ -785,8 +765,7 @@ function generatePattern(ctx, filters) {
785
765
 
786
766
  `,
787
767
  js: outdent.outdent`
788
- ${ctx.file.import(helperImports.join(", "), "../helpers")}
789
- ${ctx.file.import("css", "../css/index")}
768
+ ${ctx.file.import([...helperImports, "uncompiledStyle"].join(", "), "../helpers")}
790
769
  ${ctx.file.import("token", "../tokens/index")}
791
770
 
792
771
  /**
@@ -806,7 +785,7 @@ function generatePattern(ctx, filters) {
806
785
  return ${baseName}Config.transform(_styles, patternHelpers)
807
786
  }
808
787
 
809
- export const ${baseName} = /* @__PURE__ */ memo((styles) => css(${styleFnName}(styles)))
788
+ export const ${baseName} = (styles) => uncompiledStyle(${JSON.stringify(baseName)})
810
789
  ${baseName}.raw = ${styleFnName}
811
790
  `
812
791
  };
@@ -859,55 +838,12 @@ function generateCreateRecipe(ctx) {
859
838
  name: "create-recipe",
860
839
  dts: "",
861
840
  js: outdent.outdent`
862
- ${ctx.file.import("finalizeConditions, sortConditions", "../css/conditions")}
863
- ${ctx.file.import("assertCompoundVariant, getCompoundVariantCss", "../css/cva")}
864
- ${ctx.file.import("cx", "../css/cx")}
865
- ${ctx.file.import("compact, createCssUncached, getRecipeClassNames, splitProps, toHash, uniq, withoutSpace", "../helpers")}
841
+ ${ctx.file.import(hash.className ? "compact, splitProps, toHash, uniq, uncompiledStyle" : "compact, splitProps, uniq, uncompiledStyle", "../helpers")}
866
842
 
867
- /**
868
- * What \`createCss\` does to a class name: prefix it, and hash it when \`hash.className\`
869
- * is set.
870
- *
871
- * A slot that takes variants gets this for free, because its classes come from
872
- * \`createCss\`. A *scoped* slot's class never goes through it — it is a constant — so it
873
- * has to be formatted here or the runtime hands back a raw name while the stylesheet
874
- * emits the rule under a hashed one, and the slot renders unstyled.
875
- */
876
843
  const withPrefix = ${prefix.className ? `(className) => className ? ${JSON.stringify(prefix.className)} + '-' + className : ${JSON.stringify(prefix.className)}` : `(className) => className`}
877
844
  export const formatRecipeClass = ${hash.className ? `(className) => withPrefix((${utility.toHash})([className], toHash))` : `withPrefix`}
878
845
 
879
- export const createRecipe = (name, defaultVariants, compoundVariants, variantMap) => {
880
- /**
881
- * \`variantMap\` as \`getRecipeClassNames\` wants it — value *keys* rather than a list.
882
- *
883
- * Built once per recipe at module init. The lookup needs \`Object.hasOwn\`, and an array
884
- * answers that for its indices rather than its contents, so a list cannot be passed
885
- * straight through.
886
- */
887
- const variantValues = variantMap
888
- ? Object.fromEntries(
889
- Object.entries(variantMap).map(([variant, values]) => [
890
- variant,
891
- Object.fromEntries(values.map((value) => [value, true])),
892
- ]),
893
- )
894
- : undefined
895
-
896
- /**
897
- * Whether every selected value is a plain scalar, and so nameable without \`createCss\`.
898
- *
899
- * \`typeof value === 'object'\` covers a conditional value like \`{ base: 'sm', md: 'lg' }\`,
900
- * whose classes carry condition prefixes only \`createCss\` can build. It also catches
901
- * \`null\`, which \`compact\` keeps — that goes to the path below and comes out as it did
902
- * before, since \`createCss\` names no class for a null value either.
903
- */
904
- const isScalarSelection = (declared) => {
905
- for (const key in declared) {
906
- if (typeof declared[key] === 'object') return false
907
- }
908
- return true
909
- }
910
-
846
+ export const createRecipe = (name, defaultVariants, _compoundVariants, _variantMap) => {
911
847
  const getVariantProps = (variants) => {
912
848
  return {
913
849
  [name]: '__ignore__',
@@ -916,82 +852,12 @@ function generateCreateRecipe(ctx) {
916
852
  };
917
853
  };
918
854
 
919
- const recipeFn = (variants) => {
920
- const declaredProps = getVariantProps(variants)
921
-
922
- // A scalar selection names its classes by lookup: the recipe's own class plus one per
923
- // selected variant, which is all \`createCss\` was deriving here. Measured at 4.1x the
924
- // \`createCss\` path on a three-variant recipe. The gain is on a \`memo\` miss — the first
925
- // call for each variant combination — since a hit never reaches this at all.
926
- //
927
- // Compound variants stay absent, as they are on the path below: their rule selects on the
928
- // variant classes already named, so it applies without one of its own.
929
- if (variantValues && isScalarSelection(declaredProps)) {
930
- return getRecipeClassNames(name, variantValues, declaredProps, '${utility.separator}', formatRecipeClass)
931
- }
932
-
933
- const transform = (prop, value) => {
934
- assertCompoundVariant(name, compoundVariants, variants, prop)
935
-
936
- if (value === '__ignore__') {
937
- return { className: name }
938
- }
939
-
940
- value = withoutSpace(value)
941
- return { className: \`\${name}--\${prop}${utility.separator}\${value}\` }
942
- }
943
-
944
- // Uncached: this runs *inside* \`recipeFn\`, which is itself memoized, so the cache a
945
- // cached \`createCss\` would build here is constructed fresh per call and used once.
946
- const recipeCss = createCssUncached({
947
- ${hash.className ? "hash: true," : ""}
948
- conditions: {
949
- shift: sortConditions,
950
- finalize: finalizeConditions,
951
- },
952
- utility: {
953
- ${prefix.className ? "prefix: " + JSON.stringify(prefix.className) + "," : ""}
954
- toHash: ${utility.toHash},
955
- transform,
956
- }
957
- })
958
-
959
- // Only what the config declares names a class.
960
- //
961
- // Without this the transform named one for *any* prop it was handed — the build emits
962
- // rules only for declared values, so the element carried a class nothing backed. It also
963
- // disagreed with \`cva\`, which skips an undeclared value, leaving the two recipe kinds
964
- // with different class strings for the same call.
965
- //
966
- // Filtered here rather than in \`getVariantProps\`, which is public and is what compound
967
- // variants are matched against.
968
- const declared = declaredProps
969
- const recipeStyles = variantMap
970
- ? Object.fromEntries(
971
- Object.entries(declared).filter(([prop, value]) => {
972
- if (prop === name) return true
973
- // A conditional or responsive value is an object of leaves, and the leaves are
974
- // what name classes: createCss walks them and calls transform per condition.
975
- // Only a scalar can be judged here.
976
- if (value === null || typeof value === 'object') return true
977
- return Object.hasOwn(variantMap, prop) && variantMap[prop].includes(String(value))
978
- }),
979
- )
980
- : declared
981
-
982
- // No class for the compound variants. Their rule selects on the variant classes
983
- // \`recipeCss\` just named — \`.btn--size_sm.btn--tone_a\` — so it applies on its own,
984
- // and it is in the same layer as the rest of the recipe rather than atomically in
985
- // \`utilities\` above it.
986
- return recipeCss(recipeStyles)
987
- }
855
+ const recipeFn = (_variants) => uncompiledStyle(name)
988
856
 
989
857
  return {
990
858
  recipeFn,
991
859
  getVariantProps,
992
- __getCompoundVariantCss__: (variants) => {
993
- return getCompoundVariantCss(compoundVariants, getVariantProps(variants));
994
- },
860
+ __getCompoundVariantCss__: (_variants) => uncompiledStyle(name),
995
861
  }
996
862
  }
997
863
 
@@ -999,7 +865,7 @@ function generateCreateRecipe(ctx) {
999
865
  if (recipeA && !recipeB) return recipeA
1000
866
  if (!recipeA && recipeB) return recipeB
1001
867
 
1002
- const recipeFn = (...args) => cx(recipeA(...args), recipeB(...args))
868
+ const recipeFn = (..._args) => uncompiledStyle(recipeA.__name__ || 'recipe')
1003
869
  const variantKeys = uniq(Object.keys(recipeA.variantMap), Object.keys(recipeB.variantMap))
1004
870
  const variantMap = variantKeys.reduce((acc, key) => {
1005
871
  acc[key] = uniq(recipeA.variantMap[key], recipeB.variantMap[key])
@@ -1195,7 +1061,7 @@ function generateRecipes(ctx, filters) {
1195
1061
  function generateSvaFn(ctx) {
1196
1062
  return {
1197
1063
  js: outdent.outdent`
1198
- ${ctx.file.import("compact, getRecipeIdentity, getSlotRecipes, memo, splitProps", "../helpers")}
1064
+ ${ctx.file.import("compact, getRecipeIdentity, getSlotRecipes, memo, splitProps, uncompiledStyle", "../helpers")}
1199
1065
  ${ctx.file.import("cva, formatRecipeClass", "./cva")}
1200
1066
  ${ctx.file.import("cx", "./cx")}
1201
1067
 
@@ -1237,12 +1103,8 @@ function generateSvaFn(ctx) {
1237
1103
  // atomic and nothing else carried the name to target it in the DOM. The slot's cva is
1238
1104
  // now named \`name__slot\` and returns that as its base class, so joining it again
1239
1105
  // would just repeat it.
1240
- function svaFn(props) {
1241
- const result = slots.map(([slot, cvaFn]) => [
1242
- slot,
1243
- anchors.length && !anchors.includes(slot) ? formatRecipeClass(cvaFn.config.className) : cvaFn(props),
1244
- ])
1245
- return Object.fromEntries(result)
1106
+ function svaFn(_props) {
1107
+ return uncompiledStyle('sva')
1246
1108
  }
1247
1109
 
1248
1110
  function raw(props) {
@@ -4279,7 +4141,7 @@ var Generator = class extends _bamboocss_core.Context {
4279
4141
  * Get all split CSS artifacts for the stylesheet
4280
4142
  * Used when --splitting flag is enabled
4281
4143
  */
4282
- getSplitCssArtifacts = (sheet) => {
4144
+ getSplitCssArtifacts = (sheet, { includeRecipes = false } = {}) => {
4283
4145
  const layerNames = this.config.layers;
4284
4146
  const decoder = this.decoder.collect(this.encoder);
4285
4147
  const layers = [
@@ -4310,7 +4172,7 @@ var Generator = class extends _bamboocss_core.Context {
4310
4172
  code: l.css
4311
4173
  }));
4312
4174
  const recipes = [];
4313
- for (const recipeName of this.recipes.keys) {
4175
+ if (includeRecipes) for (const recipeName of this.recipes.keys) {
4314
4176
  const recipeSheet = this.createSheet();
4315
4177
  recipeSheet.processDecoderForRecipe(decoder, recipeName);
4316
4178
  const code = recipeSheet.getLayerCss("recipes");
@@ -4334,13 +4196,18 @@ var Generator = class extends _bamboocss_core.Context {
4334
4196
  });
4335
4197
  }
4336
4198
  const recipesIndex = recipes.map((r) => `@import './recipes/${r.file}';`).join("\n");
4337
- const imports = [`@layer ${[
4199
+ const imports = [`@layer ${(includeRecipes ? [
4338
4200
  layerNames.reset,
4339
4201
  layerNames.base,
4340
4202
  layerNames.tokens,
4341
4203
  layerNames.recipes,
4342
4204
  layerNames.utilities
4343
- ].join(", ")};`, ""];
4205
+ ] : [
4206
+ layerNames.reset,
4207
+ layerNames.base,
4208
+ layerNames.tokens,
4209
+ layerNames.utilities
4210
+ ]).join(", ")};`, ""];
4344
4211
  for (const layer of layers) imports.push(`@import './styles/${layer.file}';`);
4345
4212
  if (recipes.length) imports.push(`@import './styles/recipes.css';`);
4346
4213
  return {
package/dist/index.d.cts CHANGED
@@ -208,7 +208,11 @@ declare class Generator extends Context {
208
208
  * Get all split CSS artifacts for the stylesheet
209
209
  * Used when --splitting flag is enabled
210
210
  */
211
- getSplitCssArtifacts: (sheet: Stylesheet) => SplitCssResult;
211
+ getSplitCssArtifacts: (sheet: Stylesheet, {
212
+ includeRecipes
213
+ }?: {
214
+ includeRecipes?: boolean;
215
+ }) => SplitCssResult;
212
216
  getSpec: () => SpecFile[];
213
217
  getSpecOfType: <T extends SpecType>(type: T) => T extends "color-palette" | "themes" ? SpecTypeMap[T] | undefined : SpecTypeMap[T];
214
218
  }
package/dist/index.d.mts CHANGED
@@ -208,7 +208,11 @@ declare class Generator extends Context {
208
208
  * Get all split CSS artifacts for the stylesheet
209
209
  * Used when --splitting flag is enabled
210
210
  */
211
- getSplitCssArtifacts: (sheet: Stylesheet) => SplitCssResult;
211
+ getSplitCssArtifacts: (sheet: Stylesheet, {
212
+ includeRecipes
213
+ }?: {
214
+ includeRecipes?: boolean;
215
+ }) => SplitCssResult;
212
216
  getSpec: () => SpecFile[];
213
217
  getSpecOfType: <T extends SpecType>(type: T) => T extends "color-palette" | "themes" ? SpecTypeMap[T] | undefined : SpecTypeMap[T];
214
218
  }
package/dist/index.mjs CHANGED
@@ -83,8 +83,6 @@ function generateConditions(ctx) {
83
83
  //#endregion
84
84
  //#region src/artifacts/js/css-fn.ts
85
85
  function generateCssFn(ctx) {
86
- const { utility, hash, prefix } = ctx;
87
- const { separator } = utility;
88
86
  return {
89
87
  dts: outdent`
90
88
  ${ctx.file.importType("SystemStyleObject, ViewTransitionFn", "../types/index")}
@@ -135,39 +133,12 @@ function generateCssFn(ctx) {
135
133
 
136
134
  `,
137
135
  js: outdent`
138
- ${ctx.file.import("cloneStyles, createCssUncached, hypenateProperty, memo, viewTransitionClassName, withoutSpace", "../helpers")}
139
- ${ctx.file.import("sortConditions, finalizeConditions", "./conditions")}
140
- ${ctx.file.import("classNameByProp", "./utilities")}
141
- ${ctx.file.import("mergeCss, mergeCssUncached, resolveShorthand", "./merge-css")}
142
-
143
- const context = {
144
- ${hash.className ? "hash: true," : ""}
145
- conditions: {
146
- shift: sortConditions,
147
- finalize: finalizeConditions,
148
- },
149
- utility: {
150
- ${prefix.className ? "prefix: " + JSON.stringify(prefix.className) + "," : ""}
151
- transform: ${utility.hasShorthand ? `(prop, value) => {
152
- const key = resolveShorthand(prop)
153
- const propKey = classNameByProp.get(key) || hypenateProperty(key)
154
- return { className: \`$\{propKey}${separator}$\{withoutSpace(value)}\` }
155
- }` : `(key, value) => ({ className: \`$\{classNameByProp.get(key) || hypenateProperty(key)}${separator}$\{withoutSpace(value)}\` })`},
156
- ${utility.hasShorthand ? "hasShorthand: true," : ""}
157
- toHash: ${utility.toHash},
158
- resolveShorthand: ${utility.hasShorthand ? "resolveShorthand" : "prop => prop"},
159
- }
160
- }
136
+ ${ctx.file.import("cloneStyles, uncompiledStyle", "../helpers")}
137
+ ${ctx.file.import("mergeCss", "./merge-css")}
161
138
 
162
- const cssFn = createCssUncached(context)
163
- // \`createCssUncached\` and \`mergeCssUncached\` rather than their cached forms: this
164
- // callback runs only when the memo above it missed, and a miss means these arguments
165
- // have not been seen — so a second cache keyed on the same arguments, or on the merge
166
- // derived from them, can only miss too, after paying for the lookup.
167
- export const css = /* @__PURE__ */ memo((...styles) => cssFn(mergeCssUncached(...styles)))
168
- // The cached merge here, since \`raw\` is called straight from user code with no memo
169
- // above it. The merged result is cached and shared, so a caller mutating a nested
170
- // condition object would otherwise poison it for everyone after them.
139
+ export const css = (..._styles) => uncompiledStyle('css')
140
+ // \`raw\` is a style object, not a class string. The compiler leaves it; \`css(css.raw(...))\`
141
+ // is what has to fold.
171
142
  css.raw = (...styles) => cloneStyles(mergeCss(...styles))
172
143
 
173
144
  // Sugar for the string form, so the feature has an import to discover, a signature to
@@ -175,10 +146,7 @@ function generateCssFn(ctx) {
175
146
  // value reaching \`css()\` is the same literal either way.
176
147
  export const fallback = (...values) => \`fallback($\{values.join(', ')})\`
177
148
 
178
- // The class is the whole return value — the CSS behind it was emitted at build time
179
- // from the same options, hashed by this same function. A call the extractor never saw
180
- // still returns a class, exactly as \`css()\` does for a value it never saw.
181
- export const viewTransition = (options) => viewTransitionClassName(options, ${JSON.stringify(prefix.className ?? "")})
149
+ export const viewTransition = (_options) => uncompiledStyle('viewTransition')
182
150
 
183
151
  `
184
152
  };
@@ -284,7 +252,7 @@ function generateCvaFn(ctx) {
284
252
  const withPrefix = prefix.className ? `(className) => className ? ${JSON.stringify(prefix.className)} + '-' + className : ${JSON.stringify(prefix.className)}` : `(className) => className`;
285
253
  return {
286
254
  js: outdent`
287
- ${ctx.file.import("cloneStyles, compact, getRecipeClassNames, getRecipeIdentity, mergeProps, memo, splitProps, toHash, uniq", "../helpers")}
255
+ ${ctx.file.import("cloneStyles, compact, getRecipeIdentity, mergeProps, memo, splitProps, toHash, uniq, uncompiledStyle", "../helpers")}
288
256
  ${ctx.file.import("mergeCss", "./merge-css")}
289
257
  ${ctx.file.import("cx", "./cx")}
290
258
 
@@ -354,8 +322,8 @@ function generateCvaFn(ctx) {
354
322
  // Compound variants are absent on purpose. Their rule selects on the variant classes
355
323
  // already in this list — \`.btn--size_sm.btn--tone_a\` — so it applies without anything
356
324
  // being added here, and adding a class for it would name a rule that does not exist.
357
- function cvaFn(props) {
358
- return getRecipeClassNames(name, variants, getVariantProps(props), '${utility.separator}', formatRecipeClass)
325
+ function cvaFn(_props) {
326
+ return uncompiledStyle('cva')
359
327
  }
360
328
 
361
329
  const variantKeys = Object.keys(variants)
@@ -608,6 +576,18 @@ function generateHelpers() {
608
576
  export function __objRest(source, exclude) {
609
577
  return Object.fromEntries(Object.entries(source).filter(([key]) => !exclude.includes(key)))
610
578
  }
579
+
580
+ /**
581
+ * Style-producing calls compile away. Hitting this means \`@bamboocss/vite\` did not fold
582
+ * the call — missing plugin, a file outside \`include\`, or a shape the compiler rejects.
583
+ */
584
+ export function uncompiledStyle(name) {
585
+ throw new Error(
586
+ 'bamboocss: ' +
587
+ name +
588
+ '() was not compiled. Add \`bamboocss()\` from \`@bamboocss/vite\` and import \`virtual:bamboo.css\`. See https://bamboocss.com/docs/installation/vite',
589
+ )
590
+ }
611
591
  ` };
612
592
  }
613
593
  //#endregion
@@ -726,7 +706,7 @@ function generatePattern(ctx, filters) {
726
706
  transform,
727
707
  defaultValues
728
708
  })) ?? "";
729
- const helperImports = ["getPatternStyles, createPatternFns, memo"];
709
+ const helperImports = ["getPatternStyles, createPatternFns"];
730
710
  if (patternConfigFn.includes("__spreadValues")) helperImports.push("__spreadValues");
731
711
  if (patternConfigFn.includes("__objRest")) helperImports.push("__objRest");
732
712
  return {
@@ -759,8 +739,7 @@ function generatePattern(ctx, filters) {
759
739
 
760
740
  `,
761
741
  js: outdent`
762
- ${ctx.file.import(helperImports.join(", "), "../helpers")}
763
- ${ctx.file.import("css", "../css/index")}
742
+ ${ctx.file.import([...helperImports, "uncompiledStyle"].join(", "), "../helpers")}
764
743
  ${ctx.file.import("token", "../tokens/index")}
765
744
 
766
745
  /**
@@ -780,7 +759,7 @@ function generatePattern(ctx, filters) {
780
759
  return ${baseName}Config.transform(_styles, patternHelpers)
781
760
  }
782
761
 
783
- export const ${baseName} = /* @__PURE__ */ memo((styles) => css(${styleFnName}(styles)))
762
+ export const ${baseName} = (styles) => uncompiledStyle(${JSON.stringify(baseName)})
784
763
  ${baseName}.raw = ${styleFnName}
785
764
  `
786
765
  };
@@ -833,55 +812,12 @@ function generateCreateRecipe(ctx) {
833
812
  name: "create-recipe",
834
813
  dts: "",
835
814
  js: outdent`
836
- ${ctx.file.import("finalizeConditions, sortConditions", "../css/conditions")}
837
- ${ctx.file.import("assertCompoundVariant, getCompoundVariantCss", "../css/cva")}
838
- ${ctx.file.import("cx", "../css/cx")}
839
- ${ctx.file.import("compact, createCssUncached, getRecipeClassNames, splitProps, toHash, uniq, withoutSpace", "../helpers")}
815
+ ${ctx.file.import(hash.className ? "compact, splitProps, toHash, uniq, uncompiledStyle" : "compact, splitProps, uniq, uncompiledStyle", "../helpers")}
840
816
 
841
- /**
842
- * What \`createCss\` does to a class name: prefix it, and hash it when \`hash.className\`
843
- * is set.
844
- *
845
- * A slot that takes variants gets this for free, because its classes come from
846
- * \`createCss\`. A *scoped* slot's class never goes through it — it is a constant — so it
847
- * has to be formatted here or the runtime hands back a raw name while the stylesheet
848
- * emits the rule under a hashed one, and the slot renders unstyled.
849
- */
850
817
  const withPrefix = ${prefix.className ? `(className) => className ? ${JSON.stringify(prefix.className)} + '-' + className : ${JSON.stringify(prefix.className)}` : `(className) => className`}
851
818
  export const formatRecipeClass = ${hash.className ? `(className) => withPrefix((${utility.toHash})([className], toHash))` : `withPrefix`}
852
819
 
853
- export const createRecipe = (name, defaultVariants, compoundVariants, variantMap) => {
854
- /**
855
- * \`variantMap\` as \`getRecipeClassNames\` wants it — value *keys* rather than a list.
856
- *
857
- * Built once per recipe at module init. The lookup needs \`Object.hasOwn\`, and an array
858
- * answers that for its indices rather than its contents, so a list cannot be passed
859
- * straight through.
860
- */
861
- const variantValues = variantMap
862
- ? Object.fromEntries(
863
- Object.entries(variantMap).map(([variant, values]) => [
864
- variant,
865
- Object.fromEntries(values.map((value) => [value, true])),
866
- ]),
867
- )
868
- : undefined
869
-
870
- /**
871
- * Whether every selected value is a plain scalar, and so nameable without \`createCss\`.
872
- *
873
- * \`typeof value === 'object'\` covers a conditional value like \`{ base: 'sm', md: 'lg' }\`,
874
- * whose classes carry condition prefixes only \`createCss\` can build. It also catches
875
- * \`null\`, which \`compact\` keeps — that goes to the path below and comes out as it did
876
- * before, since \`createCss\` names no class for a null value either.
877
- */
878
- const isScalarSelection = (declared) => {
879
- for (const key in declared) {
880
- if (typeof declared[key] === 'object') return false
881
- }
882
- return true
883
- }
884
-
820
+ export const createRecipe = (name, defaultVariants, _compoundVariants, _variantMap) => {
885
821
  const getVariantProps = (variants) => {
886
822
  return {
887
823
  [name]: '__ignore__',
@@ -890,82 +826,12 @@ function generateCreateRecipe(ctx) {
890
826
  };
891
827
  };
892
828
 
893
- const recipeFn = (variants) => {
894
- const declaredProps = getVariantProps(variants)
895
-
896
- // A scalar selection names its classes by lookup: the recipe's own class plus one per
897
- // selected variant, which is all \`createCss\` was deriving here. Measured at 4.1x the
898
- // \`createCss\` path on a three-variant recipe. The gain is on a \`memo\` miss — the first
899
- // call for each variant combination — since a hit never reaches this at all.
900
- //
901
- // Compound variants stay absent, as they are on the path below: their rule selects on the
902
- // variant classes already named, so it applies without one of its own.
903
- if (variantValues && isScalarSelection(declaredProps)) {
904
- return getRecipeClassNames(name, variantValues, declaredProps, '${utility.separator}', formatRecipeClass)
905
- }
906
-
907
- const transform = (prop, value) => {
908
- assertCompoundVariant(name, compoundVariants, variants, prop)
909
-
910
- if (value === '__ignore__') {
911
- return { className: name }
912
- }
913
-
914
- value = withoutSpace(value)
915
- return { className: \`\${name}--\${prop}${utility.separator}\${value}\` }
916
- }
917
-
918
- // Uncached: this runs *inside* \`recipeFn\`, which is itself memoized, so the cache a
919
- // cached \`createCss\` would build here is constructed fresh per call and used once.
920
- const recipeCss = createCssUncached({
921
- ${hash.className ? "hash: true," : ""}
922
- conditions: {
923
- shift: sortConditions,
924
- finalize: finalizeConditions,
925
- },
926
- utility: {
927
- ${prefix.className ? "prefix: " + JSON.stringify(prefix.className) + "," : ""}
928
- toHash: ${utility.toHash},
929
- transform,
930
- }
931
- })
932
-
933
- // Only what the config declares names a class.
934
- //
935
- // Without this the transform named one for *any* prop it was handed — the build emits
936
- // rules only for declared values, so the element carried a class nothing backed. It also
937
- // disagreed with \`cva\`, which skips an undeclared value, leaving the two recipe kinds
938
- // with different class strings for the same call.
939
- //
940
- // Filtered here rather than in \`getVariantProps\`, which is public and is what compound
941
- // variants are matched against.
942
- const declared = declaredProps
943
- const recipeStyles = variantMap
944
- ? Object.fromEntries(
945
- Object.entries(declared).filter(([prop, value]) => {
946
- if (prop === name) return true
947
- // A conditional or responsive value is an object of leaves, and the leaves are
948
- // what name classes: createCss walks them and calls transform per condition.
949
- // Only a scalar can be judged here.
950
- if (value === null || typeof value === 'object') return true
951
- return Object.hasOwn(variantMap, prop) && variantMap[prop].includes(String(value))
952
- }),
953
- )
954
- : declared
955
-
956
- // No class for the compound variants. Their rule selects on the variant classes
957
- // \`recipeCss\` just named — \`.btn--size_sm.btn--tone_a\` — so it applies on its own,
958
- // and it is in the same layer as the rest of the recipe rather than atomically in
959
- // \`utilities\` above it.
960
- return recipeCss(recipeStyles)
961
- }
829
+ const recipeFn = (_variants) => uncompiledStyle(name)
962
830
 
963
831
  return {
964
832
  recipeFn,
965
833
  getVariantProps,
966
- __getCompoundVariantCss__: (variants) => {
967
- return getCompoundVariantCss(compoundVariants, getVariantProps(variants));
968
- },
834
+ __getCompoundVariantCss__: (_variants) => uncompiledStyle(name),
969
835
  }
970
836
  }
971
837
 
@@ -973,7 +839,7 @@ function generateCreateRecipe(ctx) {
973
839
  if (recipeA && !recipeB) return recipeA
974
840
  if (!recipeA && recipeB) return recipeB
975
841
 
976
- const recipeFn = (...args) => cx(recipeA(...args), recipeB(...args))
842
+ const recipeFn = (..._args) => uncompiledStyle(recipeA.__name__ || 'recipe')
977
843
  const variantKeys = uniq(Object.keys(recipeA.variantMap), Object.keys(recipeB.variantMap))
978
844
  const variantMap = variantKeys.reduce((acc, key) => {
979
845
  acc[key] = uniq(recipeA.variantMap[key], recipeB.variantMap[key])
@@ -1169,7 +1035,7 @@ function generateRecipes(ctx, filters) {
1169
1035
  function generateSvaFn(ctx) {
1170
1036
  return {
1171
1037
  js: outdent`
1172
- ${ctx.file.import("compact, getRecipeIdentity, getSlotRecipes, memo, splitProps", "../helpers")}
1038
+ ${ctx.file.import("compact, getRecipeIdentity, getSlotRecipes, memo, splitProps, uncompiledStyle", "../helpers")}
1173
1039
  ${ctx.file.import("cva, formatRecipeClass", "./cva")}
1174
1040
  ${ctx.file.import("cx", "./cx")}
1175
1041
 
@@ -1211,12 +1077,8 @@ function generateSvaFn(ctx) {
1211
1077
  // atomic and nothing else carried the name to target it in the DOM. The slot's cva is
1212
1078
  // now named \`name__slot\` and returns that as its base class, so joining it again
1213
1079
  // would just repeat it.
1214
- function svaFn(props) {
1215
- const result = slots.map(([slot, cvaFn]) => [
1216
- slot,
1217
- anchors.length && !anchors.includes(slot) ? formatRecipeClass(cvaFn.config.className) : cvaFn(props),
1218
- ])
1219
- return Object.fromEntries(result)
1080
+ function svaFn(_props) {
1081
+ return uncompiledStyle('sva')
1220
1082
  }
1221
1083
 
1222
1084
  function raw(props) {
@@ -4253,7 +4115,7 @@ var Generator = class extends Context {
4253
4115
  * Get all split CSS artifacts for the stylesheet
4254
4116
  * Used when --splitting flag is enabled
4255
4117
  */
4256
- getSplitCssArtifacts = (sheet) => {
4118
+ getSplitCssArtifacts = (sheet, { includeRecipes = false } = {}) => {
4257
4119
  const layerNames = this.config.layers;
4258
4120
  const decoder = this.decoder.collect(this.encoder);
4259
4121
  const layers = [
@@ -4284,7 +4146,7 @@ var Generator = class extends Context {
4284
4146
  code: l.css
4285
4147
  }));
4286
4148
  const recipes = [];
4287
- for (const recipeName of this.recipes.keys) {
4149
+ if (includeRecipes) for (const recipeName of this.recipes.keys) {
4288
4150
  const recipeSheet = this.createSheet();
4289
4151
  recipeSheet.processDecoderForRecipe(decoder, recipeName);
4290
4152
  const code = recipeSheet.getLayerCss("recipes");
@@ -4308,13 +4170,18 @@ var Generator = class extends Context {
4308
4170
  });
4309
4171
  }
4310
4172
  const recipesIndex = recipes.map((r) => `@import './recipes/${r.file}';`).join("\n");
4311
- const imports = [`@layer ${[
4173
+ const imports = [`@layer ${(includeRecipes ? [
4312
4174
  layerNames.reset,
4313
4175
  layerNames.base,
4314
4176
  layerNames.tokens,
4315
4177
  layerNames.recipes,
4316
4178
  layerNames.utilities
4317
- ].join(", ")};`, ""];
4179
+ ] : [
4180
+ layerNames.reset,
4181
+ layerNames.base,
4182
+ layerNames.tokens,
4183
+ layerNames.utilities
4184
+ ]).join(", ")};`, ""];
4318
4185
  for (const layer of layers) imports.push(`@import './styles/${layer.file}';`);
4319
4186
  if (recipes.length) imports.push(`@import './styles/recipes.css';`);
4320
4187
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bamboocss/generator",
3
- "version": "1.46.3",
3
+ "version": "1.47.0",
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.46.3",
42
- "@bamboocss/is-valid-prop": "^1.46.3",
43
- "@bamboocss/logger": "1.46.3",
44
- "@bamboocss/shared": "1.46.3",
45
- "@bamboocss/token-dictionary": "1.46.3",
46
- "@bamboocss/types": "1.46.3"
41
+ "@bamboocss/core": "1.47.0",
42
+ "@bamboocss/is-valid-prop": "^1.47.0",
43
+ "@bamboocss/logger": "1.47.0",
44
+ "@bamboocss/shared": "1.47.0",
45
+ "@bamboocss/token-dictionary": "1.47.0",
46
+ "@bamboocss/types": "1.47.0"
47
47
  },
48
48
  "devDependencies": {
49
49
  "@types/pluralize": "0.0.33"