clava 0.4.2 → 0.5.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/CHANGELOG.md CHANGED
@@ -1,5 +1,46 @@
1
1
  # clava
2
2
 
3
+ ## 0.5.0
4
+
5
+ ### Computed default variants
6
+
7
+ **BREAKING** if you're using `setDefaultVariants` in [`cv`](https://clava.style/docs/reference/cv) `refine` callbacks.
8
+
9
+ The `setDefaultVariants` function has been removed from `refine`. Define dependent defaults directly in `defaultVariants` by passing a function for the variant key. The function receives the current `defaultValue` for that key and the resolved `variants` snapshot.
10
+
11
+ Computed default variants run before `refine`, so `refine` callbacks now read computed default values during their first pass. If a variant value itself is a function, return that function from a computed default variant instead of passing it directly as a static default.
12
+
13
+ Before:
14
+
15
+ ```ts
16
+ const button = cv({
17
+ variants: {
18
+ size: { sm: "sm", lg: "lg" },
19
+ intent: { neutral: "neutral", brand: "brand" },
20
+ },
21
+ refine: ({ variants, setDefaultVariants }) => {
22
+ if (variants.size === "lg") {
23
+ setDefaultVariants({ intent: "neutral" });
24
+ }
25
+ },
26
+ });
27
+ ```
28
+
29
+ After:
30
+
31
+ ```ts
32
+ const button = cv({
33
+ variants: {
34
+ size: { sm: "sm", lg: "lg" },
35
+ intent: { neutral: "neutral", brand: "brand" },
36
+ },
37
+ defaultVariants: {
38
+ intent: ({ defaultValue, variants }) =>
39
+ variants.size === "lg" ? "neutral" : defaultValue,
40
+ },
41
+ });
42
+ ```
43
+
3
44
  ## 0.4.2
4
45
 
5
46
  - Improved [`refine`](https://clava.style/docs/reference/refine) iteration warnings to show the latest changing variant values with a shorter component creation stack.
package/README.md CHANGED
@@ -316,7 +316,9 @@ You can extend any component mode, including `baseButton.jsx`, `baseButton.html`
316
316
 
317
317
  ## Refine
318
318
 
319
- Use `refine` for compound conditions, dependent defaults, and final class/style adjustments. It receives the resolved variant values for the component and can return class/style output.
319
+ Use computed `defaultVariants` for dependent defaults. A function entry receives the current default value for that key plus the resolved variants snapshot, and returns the next default value.
320
+
321
+ Use `refine` for final variant overrides and class/style adjustments. It receives the resolved variant values for the component and can return class/style output.
320
322
 
321
323
  ```ts
322
324
  const toolbarButton = cv({
@@ -328,21 +330,15 @@ const toolbarButton = cv({
328
330
  },
329
331
  loading: "toolbar-button-loading",
330
332
  },
331
- refine: ({
332
- variants,
333
- setVariants,
334
- setDefaultVariants,
335
- addClass,
336
- addStyle,
337
- }) => {
333
+ defaultVariants: {
334
+ intent: ({ defaultValue, variants }) =>
335
+ variants.size === "lg" ? "neutral" : defaultValue,
336
+ },
337
+ refine: ({ variants, setVariants, addClass, addStyle }) => {
338
338
  if (variants.loading) {
339
339
  setVariants({ pressed: false });
340
340
  }
341
341
 
342
- if (variants.size === "lg") {
343
- setDefaultVariants({ intent: "neutral" });
344
- }
345
-
346
342
  if (variants.pressed && variants.intent === "brand") {
347
343
  addClass("toolbar-button-brand-pressed");
348
344
  addStyle({ transform: "translateY(1px)" });
@@ -353,9 +349,24 @@ const toolbarButton = cv({
353
349
  });
354
350
  ```
355
351
 
356
- `setVariants()` overrides explicit props. `setDefaultVariants()` overrides static `defaultVariants` and inherited defaults, but it does not override a prop the user explicitly passed unless that prop value is `undefined`. `addClass()` and `addStyle()` append output without changing resolved variant values. `getVariants()` includes values changed by `setVariants()` and `setDefaultVariants()`.
352
+ Computed `defaultVariants` do not override a prop the user explicitly passed unless that prop value is `undefined`. Return `defaultValue` to preserve the inherited or static default value. Return `undefined` to clear the default value. If a variant's value is a function, return that function from a computed default:
353
+
354
+ ```ts
355
+ const transform = (value: string) => value.toUpperCase();
356
+
357
+ const input = cv({
358
+ variants: {
359
+ transform: (fn: (value: string) => string) => fn("example"),
360
+ },
361
+ defaultVariants: {
362
+ transform: () => transform,
363
+ },
364
+ });
365
+ ```
366
+
367
+ `setVariants()` overrides explicit props. `addClass()` and `addStyle()` append output without changing resolved variant values. `getVariants()` includes values changed by computed `defaultVariants` and `setVariants()`.
357
368
 
358
- When a `refine` callback changes variants, Clava re-runs the refine chain so later reads see the latest values. Re-runs are capped at 50 iterations, after which Clava stops and logs a warning in development.
369
+ When a computed default or `refine` callback changes variants, Clava re-runs the refine chain so later reads see the latest values. Re-runs are capped at 50 iterations, after which Clava stops and logs a warning in development.
359
370
 
360
371
  ## Splitting Props
361
372
 
@@ -539,7 +550,7 @@ The package also exports `ClassValue`, `StyleValue`, `StyleClassProps`, `StyleCl
539
550
 
540
551
  `component.style(props?)` returns only the resolved style value for that component mode.
541
552
 
542
- `component.getVariants(props?)` returns resolved variant values after static defaults, inherited defaults, and `refine` updates.
553
+ `component.getVariants(props?)` returns resolved variant values after static defaults, inherited defaults, computed defaults, and `refine` updates.
543
554
 
544
555
  `component.propKeys` lists style props plus variant props for that component mode.
545
556
 
package/dist/index.d.ts CHANGED
@@ -76,7 +76,15 @@ type StringToBoolean<T> = T extends "true" | "false" ? boolean : T;
76
76
  type VariantValue = ClassValue | StyleClassValue;
77
77
  type NonNullKeys<T> = { [K in keyof T]: T[K] extends null ? never : K }[keyof T];
78
78
  type ExtractVariantValue<T> = T extends null ? never : T extends ((value: infer V) => any) ? V : T extends readonly unknown[] ? boolean : T extends Record<string, any> ? StringToBoolean<NonNullKeys<T>> : T extends ClassValue ? boolean : never;
79
- type VariantValues<V> = { [K in keyof V]?: ExtractVariantValue<V[K]> };
79
+ type VariantValues<V> = { [K in keyof V]?: ExtractVariantValue<V[K]> | undefined };
80
+ interface DefaultVariantContext<V, K extends keyof V> {
81
+ defaultValue: ExtractVariantValue<V[K]> | undefined;
82
+ variants: Readonly<VariantValues<V>>;
83
+ }
84
+ type ComputedDefaultVariant<V, K extends keyof V> = (context: DefaultVariantContext<V, K>) => ExtractVariantValue<V[K]> | undefined;
85
+ type NonFunctionVariantValue<T> = Exclude<T, (...args: any[]) => any>;
86
+ type DefaultVariantValue<V, K extends keyof V> = [NonFunctionVariantValue<ExtractVariantValue<V[K]>>] extends [never] ? ComputedDefaultVariant<V, K> : NonFunctionVariantValue<ExtractVariantValue<V[K]>> | ComputedDefaultVariant<V, K>;
87
+ type DefaultVariants<V> = { [K in keyof V]?: DefaultVariantValue<V, K> | undefined };
80
88
  type StyleValue = CSS.Properties & {
81
89
  [key: `--${string}`]: string;
82
90
  };
@@ -87,7 +95,6 @@ interface StyleClassValue {
87
95
  interface RefineContext<V> {
88
96
  variants: VariantValues<V>;
89
97
  setVariants: (variants: VariantValues<V>) => void;
90
- setDefaultVariants: (variants: VariantValues<V>) => void;
91
98
  addClass: (className: ClassValue) => void;
92
99
  addStyle: (style: StyleValue) => void;
93
100
  }
@@ -106,7 +113,7 @@ interface CVConfig<V extends Variants = {}, E extends AnyComponent[] = []> {
106
113
  class?: ClassValue;
107
114
  style?: StyleValue;
108
115
  variants?: ExtendableVariants<V, E>;
109
- defaultVariants?: VariantValues<MergeVariants<V, E>>;
116
+ defaultVariants?: DefaultVariants<MergeVariants<V, E>>;
110
117
  refine?: Refine<MergeVariants<V, E>>;
111
118
  }
112
119
  interface CreateParams {
package/dist/index.js CHANGED
@@ -75,7 +75,7 @@ function warnRefineLimit({ runState, creationFrame, unstableChanges }) {
75
75
  if (process.env.NODE_ENV === "production") return;
76
76
  if (runState.warned) return;
77
77
  runState.warned = true;
78
- let message = "Clava: Maximum refine iterations exceeded. This can happen when a refine callback calls setVariants or setDefaultVariants, but one of the variants changes on every run.";
78
+ let message = "Clava: Maximum refine iterations exceeded. This can happen when a computed default variant or refine callback changes one of the variants on every run.";
79
79
  if (unstableChanges && unstableChanges.size > 0) {
80
80
  message += `\nVariant(s) that did not stabilize: ${Array.from(unstableChanges.keys()).join(", ")}.`;
81
81
  message += `\nLatest variant changes before warning: ${formatVariantChanges(unstableChanges)}.`;
@@ -350,6 +350,23 @@ function mergeVariants(target, source, skipKeys) {
350
350
  }
351
351
  return changed;
352
352
  }
353
+ function mergeProtectedIntoBase(baseResolved, protectedVariants) {
354
+ if (!protectedVariants) return baseResolved;
355
+ let hasProtected = false;
356
+ for (const key in protectedVariants) {
357
+ if (!Object.hasOwn(protectedVariants, key)) continue;
358
+ hasProtected = true;
359
+ break;
360
+ }
361
+ if (!hasProtected) return baseResolved;
362
+ const resolved = {};
363
+ Object.assign(resolved, baseResolved);
364
+ for (const key in protectedVariants) {
365
+ if (!Object.hasOwn(protectedVariants, key)) continue;
366
+ resolved[key] = protectedVariants[key];
367
+ }
368
+ return resolved;
369
+ }
353
370
  function getComponentMeta(component) {
354
371
  return component[META_KEY];
355
372
  }
@@ -419,21 +436,11 @@ function collectVariantKeys(config) {
419
436
  }
420
437
  return Array.from(keys);
421
438
  }
422
- function isVariantDisabled(config, key) {
423
- return config.variants?.[key] === null;
424
- }
425
439
  function getVariantValueKey(value) {
426
440
  if (typeof value === "string") return value;
427
441
  if (typeof value === "number") return String(value);
428
442
  if (typeof value === "boolean") return String(value);
429
443
  }
430
- function isVariantValueDisabled(config, key, value) {
431
- const valueKey = getVariantValueKey(value);
432
- if (valueKey == null) return false;
433
- const variant = config.variants?.[key];
434
- if (!isRecordObject(variant)) return false;
435
- return variant[valueKey] === null;
436
- }
437
444
  function collectDisabledVariantKeys(config) {
438
445
  const keys = /* @__PURE__ */ new Set();
439
446
  if (!config.variants) return keys;
@@ -614,6 +621,9 @@ function create({ transformClass = (className) => className } = {}) {
614
621
  }
615
622
  const variantEntryCount = variantEntryNames.length;
616
623
  const functionVariantCount = functionVariantNames.length;
624
+ const computedDefaultNames = [];
625
+ const computedDefaultFns = [];
626
+ const defaultVariants = config.defaultVariants;
617
627
  const staticDefaults = {};
618
628
  if (extend) for (const ext of extend) {
619
629
  const meta = getComponentMeta(ext);
@@ -625,7 +635,21 @@ function create({ transformClass = (className) => className } = {}) {
625
635
  if (!isRecordObject(variantDef)) continue;
626
636
  if (Object.hasOwn(variantDef, "false") && staticDefaults[name] === void 0) staticDefaults[name] = false;
627
637
  }
628
- if (config.defaultVariants) Object.assign(staticDefaults, config.defaultVariants);
638
+ if (defaultVariants) for (const name in defaultVariants) {
639
+ if (!Object.hasOwn(defaultVariants, name)) continue;
640
+ const value = defaultVariants[name];
641
+ if (typeof value === "function") {
642
+ computedDefaultNames.push(name);
643
+ computedDefaultFns.push(value);
644
+ continue;
645
+ }
646
+ if (value === void 0) {
647
+ Reflect.deleteProperty(staticDefaults, name);
648
+ continue;
649
+ }
650
+ staticDefaults[name] = value;
651
+ }
652
+ const computedDefaultCount = computedDefaultNames.length;
629
653
  if (hasAnyDisabled) for (const key in staticDefaults) {
630
654
  if (!Object.hasOwn(staticDefaults, key)) continue;
631
655
  if (disabledVariantKeys.has(key)) {
@@ -654,14 +678,19 @@ function create({ transformClass = (className) => className } = {}) {
654
678
  } else extBaseClassesArr.push(meta.baseClass);
655
679
  }
656
680
  const extCount = extMetas.length;
681
+ const inheritedComputedDefaultKeys = /* @__PURE__ */ new Set();
682
+ for (let i = 0; i < extCount; i++) {
683
+ const keys = extMetas[i].computedDefaultKeys;
684
+ for (const key of keys) inheritedComputedDefaultKeys.add(key);
685
+ }
657
686
  const extMetasWithRefine = [];
658
687
  for (let i = 0; i < extCount; i++) {
659
688
  const meta = extMetas[i];
660
- if (meta.resolveDefaults) extMetasWithRefine.push(meta);
689
+ if (meta.resolveRefine) extMetasWithRefine.push(meta);
661
690
  }
662
691
  const extMetasWithRefineCount = extMetasWithRefine.length;
663
692
  const shouldCollectChangedVariants = extMetasWithRefineCount > 0;
664
- const creationFrame = !!refine || extMetasWithRefineCount > 0 ? captureCreationFrame(cv) : void 0;
693
+ const creationFrame = !!refine || computedDefaultCount > 0 || extMetasWithRefineCount > 0 ? captureCreationFrame(cv) : void 0;
665
694
  const functionVariantKeys = /* @__PURE__ */ new Set();
666
695
  for (let i = 0; i < extCount; i++) {
667
696
  const fnKeys = extMetas[i].functionVariantKeys;
@@ -672,6 +701,8 @@ function create({ transformClass = (className) => className } = {}) {
672
701
  }
673
702
  for (let i = 0; i < functionVariantCount; i++) functionVariantKeys.add(functionVariantNames[i]);
674
703
  for (let i = 0; i < variantEntryCount; i++) functionVariantKeys.delete(variantEntryNames[i]);
704
+ const computedDefaultKeys = new Set(inheritedComputedDefaultKeys);
705
+ for (let i = 0; i < computedDefaultCount; i++) computedDefaultKeys.add(computedDefaultNames[i]);
675
706
  let staticVariantsOverridingExtFn = null;
676
707
  if (variantEntryCount > 0 && extCount > 0) for (let i = 0; i < variantEntryCount; i++) {
677
708
  const name = variantEntryNames[i];
@@ -705,64 +736,42 @@ function create({ transformClass = (className) => className } = {}) {
705
736
  out[key] = value;
706
737
  }
707
738
  }
708
- const resolveDefaultsFn = refine || extMetasWithRefineCount > 0 ? (childDefaults, userProps = EMPTY_DEFAULTS) => {
709
- const resolvedVariants = {};
710
- Object.assign(resolvedVariants, staticDefaults);
711
- for (const key in childDefaults) {
712
- if (!Object.hasOwn(childDefaults, key)) continue;
713
- const v = childDefaults[key];
714
- if (v === void 0) continue;
715
- resolvedVariants[key] = v;
716
- }
717
- for (const key in userProps) {
718
- if (!Object.hasOwn(userProps, key)) continue;
719
- const v = userProps[key];
720
- if (v === void 0) continue;
721
- resolvedVariants[key] = v;
739
+ const isOwnDisabledValue = (key, value) => {
740
+ if (disabledVariantKeys.has(key)) return true;
741
+ if (hasDisabledVariantValues) {
742
+ const valueKey = getVariantValueKey(value);
743
+ if (valueKey != null && disabledVariantValues[key]?.has(valueKey)) return true;
722
744
  }
723
- const refineDefaults = {};
724
- for (let i = 0; i < extMetasWithRefineCount; i++) {
725
- const extDefaults = extMetasWithRefine[i].resolveDefaults(childDefaults, userProps);
726
- for (const k in extDefaults) {
727
- if (!Object.hasOwn(extDefaults, k)) continue;
728
- refineDefaults[k] = extDefaults[k];
745
+ return false;
746
+ };
747
+ const filterOwnDisabledVariants = (input, fallback) => {
748
+ if (!hasAnyDisabled) return input;
749
+ let hasOwnDisabledValue = false;
750
+ for (const key in input) {
751
+ if (!Object.hasOwn(input, key)) continue;
752
+ const value = input[key];
753
+ if (isOwnDisabledValue(key, value)) {
754
+ hasOwnDisabledValue = true;
755
+ break;
729
756
  }
730
757
  }
731
- if (refine) {
732
- const ownVariants = {};
733
- for (let i = 0; i < variantKeysLength; i++) {
734
- const k = variantKeys[i];
735
- if (Object.hasOwn(resolvedVariants, k)) ownVariants[k] = resolvedVariants[k];
758
+ if (!hasOwnDisabledValue) return input;
759
+ const filtered = {};
760
+ for (const key in input) {
761
+ if (!Object.hasOwn(input, key)) continue;
762
+ const value = input[key];
763
+ if (!isOwnDisabledValue(key, value)) {
764
+ filtered[key] = value;
765
+ continue;
736
766
  }
737
- refine({
738
- variants: ownVariants,
739
- setVariants: noop,
740
- setDefaultVariants: (newDefaults) => {
741
- for (const key in newDefaults) {
742
- if (!Object.hasOwn(newDefaults, key)) continue;
743
- const value = newDefaults[key];
744
- if (userProps[key] !== void 0) continue;
745
- if (isVariantDisabled(config, key)) continue;
746
- if (isVariantValueDisabled(config, key, value)) continue;
747
- refineDefaults[key] = value;
748
- }
749
- },
750
- addClass: noop,
751
- addStyle: noop
752
- });
767
+ const fallbackValue = fallback[key];
768
+ if (fallbackValue !== void 0 && !isOwnDisabledValue(key, fallbackValue)) filtered[key] = fallbackValue;
753
769
  }
754
- return refineDefaults;
755
- } : null;
770
+ return filtered;
771
+ };
756
772
  function resolveVariantsHot(propsVariants) {
757
773
  const defaults = {};
758
774
  Object.assign(defaults, staticDefaults);
759
- for (let i = 0; i < extMetasWithRefineCount; i++) {
760
- const extDefaults = extMetasWithRefine[i].resolveDefaults(defaults, propsVariants);
761
- for (const k in extDefaults) {
762
- if (!Object.hasOwn(extDefaults, k)) continue;
763
- defaults[k] = extDefaults[k];
764
- }
765
- }
766
775
  for (const k in propsVariants) {
767
776
  if (!Object.hasOwn(propsVariants, k)) continue;
768
777
  const v = propsVariants[k];
@@ -774,7 +783,70 @@ function create({ transformClass = (className) => className } = {}) {
774
783
  filterDisabledInto(defaults, result);
775
784
  return result;
776
785
  }
777
- const runRefineContext = (resolved, userVariantProps, filterOwnVariants, collectOutput, protectedVariants, pendingProtectedVariants, protectedVariantKeys) => {
786
+ const runComputedDefaults = (resolved, defaultResolved, userVariantProps, filterOwnVariants, protectedVariantKeys) => {
787
+ if (computedDefaultCount === 0) return {
788
+ workingResolved: resolved,
789
+ changedVariants: null
790
+ };
791
+ let ownVariants = filterOwnVariants ? null : resolved;
792
+ const getOwnVariants = () => {
793
+ if (ownVariants) return ownVariants;
794
+ const filteredVariants = {};
795
+ for (let i = 0; i < variantKeysLength; i++) {
796
+ const key = variantKeys[i];
797
+ if (Object.hasOwn(resolved, key)) filteredVariants[key] = resolved[key];
798
+ }
799
+ ownVariants = filteredVariants;
800
+ return filteredVariants;
801
+ };
802
+ let updatedVariants = null;
803
+ let changedVariants = null;
804
+ const ensureUpdated = () => {
805
+ if (updatedVariants) return updatedVariants;
806
+ const updated = {};
807
+ Object.assign(updated, resolved);
808
+ updatedVariants = updated;
809
+ return updated;
810
+ };
811
+ for (let i = 0; i < computedDefaultCount; i++) {
812
+ const key = computedDefaultNames[i];
813
+ if (Object.hasOwn(userVariantProps, key)) {
814
+ if (userVariantProps[key] !== void 0) continue;
815
+ }
816
+ if (protectedVariantKeys?.has(key)) continue;
817
+ const variantSnapshot = getOwnVariants();
818
+ const defaultValue = inheritedComputedDefaultKeys.has(key) ? variantSnapshot[key] : defaultResolved[key];
819
+ const value = computedDefaultFns[i]({
820
+ defaultValue,
821
+ variants: variantSnapshot
822
+ });
823
+ if (hasAnyDisabled) {
824
+ if (disabledVariantKeys.has(key)) continue;
825
+ const valueKey = getVariantValueKey(value);
826
+ if (valueKey != null && disabledVariantValues[key]?.has(valueKey)) continue;
827
+ }
828
+ if (value === void 0) {
829
+ if (!Object.hasOwn(variantSnapshot, key)) continue;
830
+ if (shouldCollectChangedVariants) {
831
+ changedVariants ??= {};
832
+ changedVariants[key] = value;
833
+ }
834
+ Reflect.deleteProperty(ensureUpdated(), key);
835
+ continue;
836
+ }
837
+ if (Object.is(variantSnapshot[key], value)) continue;
838
+ if (shouldCollectChangedVariants) {
839
+ changedVariants ??= {};
840
+ changedVariants[key] = value;
841
+ }
842
+ ensureUpdated()[key] = value;
843
+ }
844
+ return {
845
+ workingResolved: updatedVariants ?? resolved,
846
+ changedVariants
847
+ };
848
+ };
849
+ const runRefineContext = (resolved, userVariantProps, filterOwnVariants, collectOutput, applyVariantUpdates, protectedVariants, pendingProtectedVariants, protectedVariantKeys) => {
778
850
  let workingResolved = resolved;
779
851
  let cClasses = null;
780
852
  let cStyle = null;
@@ -815,6 +887,7 @@ function create({ transformClass = (className) => className } = {}) {
815
887
  const result = refine({
816
888
  variants: ownVariants,
817
889
  setVariants: (newVariants) => {
890
+ if (!applyVariantUpdates) return;
818
891
  if (!hasAnyDisabled) {
819
892
  for (const key in newVariants) {
820
893
  if (!Object.hasOwn(newVariants, key)) continue;
@@ -838,23 +911,6 @@ function create({ transformClass = (className) => className } = {}) {
838
911
  ensureUpdated()[key] = value;
839
912
  }
840
913
  },
841
- setDefaultVariants: (newDefaults) => {
842
- for (const key in newDefaults) {
843
- if (!Object.hasOwn(newDefaults, key)) continue;
844
- if (userVariantProps[key] !== void 0) continue;
845
- if (protectedVariantKeys?.has(key)) continue;
846
- const value = newDefaults[key];
847
- if (hasAnyDisabled) {
848
- if (disabledVariantKeys.has(key)) continue;
849
- const valueKey = getVariantValueKey(value);
850
- if (valueKey != null && disabledVariantValues[key]?.has(valueKey)) continue;
851
- }
852
- if (Object.is(getCurrentVariantValue(key), value)) continue;
853
- setChangedVariant(key, value);
854
- if (pendingProtectedVariants) pendingProtectedVariants[key] = value;
855
- ensureUpdated()[key] = value;
856
- }
857
- },
858
914
  addClass: (className) => {
859
915
  localCClasses?.push(className);
860
916
  },
@@ -892,18 +948,11 @@ function create({ transformClass = (className) => className } = {}) {
892
948
  style: cStyle
893
949
  };
894
950
  };
895
- const computeOnce = (resolved, userVariantProps, skipKeys, skipValues, classesOut, styleOut, runState, protectedVariants, pendingProtectedVariants, protectedVariantKeys) => {
951
+ const computeOnce = (resolved, userVariantProps, skipKeys, skipValues, classesOut, styleOut, runState, protectedVariants, pendingProtectedVariants, protectedVariantKeys, defaultResolved = resolved, renderOnly = false) => {
896
952
  let workingResolved = resolved;
897
953
  let cClasses = null;
898
954
  let cStyle = null;
899
955
  let changedVariants = null;
900
- if (refine) {
901
- const refineResult = runRefineContext(resolved, userVariantProps, true, true, protectedVariants, pendingProtectedVariants, protectedVariantKeys);
902
- workingResolved = refineResult.workingResolved;
903
- cClasses = refineResult.classes;
904
- cStyle = refineResult.style;
905
- changedVariants = refineResult.changedVariants;
906
- }
907
956
  if (hasExtend) {
908
957
  let extSkipKeys;
909
958
  if (skipKeys === null) extSkipKeys = staticExtSkipKeys;
@@ -931,15 +980,31 @@ function create({ transformClass = (className) => className } = {}) {
931
980
  for (let i = 0; i < extCount; i++) {
932
981
  if (hasIsolatedExt && extIsolated[i]) {
933
982
  const extClasses = [];
934
- workingResolved = extMetas[i].compute(workingResolved, extUserVariantProps, extSkipKeys, extSkipVals, extClasses, styleOut, runState, protectedVariants, pendingProtectedVariants, protectedVariantKeys);
983
+ workingResolved = extMetas[i].compute(workingResolved, extUserVariantProps, extSkipKeys, extSkipVals, extClasses, styleOut, runState, protectedVariants, pendingProtectedVariants, protectedVariantKeys, defaultResolved, renderOnly);
935
984
  if (extClasses.length > 0) {
936
985
  const joined = clsx(extClasses);
937
986
  if (joined.length > 0) classesOut.push(extMetas[i].transformClass(joined));
938
987
  }
939
- } else workingResolved = extMetas[i].compute(workingResolved, extUserVariantProps, extSkipKeys, extSkipVals, classesOut, styleOut, runState, protectedVariants, pendingProtectedVariants, protectedVariantKeys);
988
+ } else workingResolved = extMetas[i].compute(workingResolved, extUserVariantProps, extSkipKeys, extSkipVals, classesOut, styleOut, runState, protectedVariants, pendingProtectedVariants, protectedVariantKeys, defaultResolved, renderOnly);
989
+ workingResolved = filterOwnDisabledVariants(workingResolved, defaultResolved);
940
990
  if (protectedVariants && extMetasWithRefineCount > 0) Object.assign(extUserVariantProps, protectedVariants);
941
991
  }
942
992
  }
993
+ if (!renderOnly && computedDefaultCount > 0) {
994
+ const computedResult = runComputedDefaults(workingResolved, defaultResolved, userVariantProps, true, protectedVariantKeys);
995
+ workingResolved = computedResult.workingResolved;
996
+ changedVariants = computedResult.changedVariants;
997
+ }
998
+ if (refine) {
999
+ const refineResult = runRefineContext(workingResolved, userVariantProps, true, true, !renderOnly, protectedVariants, pendingProtectedVariants, protectedVariantKeys);
1000
+ workingResolved = refineResult.workingResolved;
1001
+ cClasses = refineResult.classes;
1002
+ cStyle = refineResult.style;
1003
+ if (refineResult.changedVariants) {
1004
+ changedVariants ??= {};
1005
+ Object.assign(changedVariants, refineResult.changedVariants);
1006
+ }
1007
+ }
943
1008
  if (hasBaseStyle) Object.assign(styleOut, baseStyle);
944
1009
  const ownSkipKeys = skipKeys;
945
1010
  const ownSkipValues = skipValues;
@@ -982,7 +1047,8 @@ function create({ transformClass = (className) => className } = {}) {
982
1047
  if (cStyle) Object.assign(styleOut, cStyle);
983
1048
  return workingResolved;
984
1049
  };
985
- const compute = !refine && extMetasWithRefineCount === 0 ? computeOnce : (resolved, userVariantProps, skipKeys, skipValues, classesOut, styleOut, runState, protectedVariants, pendingProtectedVariants, protectedVariantKeys) => {
1050
+ const compute = !refine && computedDefaultCount === 0 && extMetasWithRefineCount === 0 ? computeOnce : (resolved, userVariantProps, skipKeys, skipValues, classesOut, styleOut, runState, protectedVariants, pendingProtectedVariants, protectedVariantKeys, incomingDefaultResolved = resolved, renderOnly = false) => {
1051
+ if (renderOnly) return computeOnce(resolved, userVariantProps, skipKeys, skipValues, classesOut, styleOut, runState, protectedVariants, pendingProtectedVariants, protectedVariantKeys, incomingDefaultResolved, true);
986
1052
  runState ??= { remaining: MAX_REFINE_RUNS };
987
1053
  protectedVariants ??= {};
988
1054
  protectedVariantKeys ??= /* @__PURE__ */ new Set();
@@ -1004,12 +1070,19 @@ function create({ transformClass = (className) => className } = {}) {
1004
1070
  const nextPendingProtectedVariants = {};
1005
1071
  const nextClasses = useDirectOutput ? classesOut : [];
1006
1072
  const nextStyle = useDirectOutput ? styleOut : {};
1007
- const nextResolved = computeOnce(workingResolved, userVariantProps, skipKeys, skipValues, nextClasses, nextStyle, runState, protectedVariants, nextPendingProtectedVariants, protectedVariantKeys);
1073
+ const defaultResolved = mergeProtectedIntoBase(incomingDefaultResolved, protectedVariants);
1074
+ const nextResolved = computeOnce(workingResolved, userVariantProps, skipKeys, skipValues, nextClasses, nextStyle, runState, protectedVariants, nextPendingProtectedVariants, protectedVariantKeys, defaultResolved);
1008
1075
  let protectedChanged;
1009
1076
  if (pendingProtectedVariants) protectedChanged = mergeVariants(pendingProtectedVariants, nextPendingProtectedVariants, protectedVariantKeys);
1010
1077
  else protectedChanged = mergeVariants(protectedVariants, nextPendingProtectedVariants, protectedVariantKeys);
1011
1078
  if (!protectedChanged && (nextResolved === workingResolved || areVariantsEqual(workingResolved, nextResolved))) {
1012
- if (!useDirectOutput) {
1079
+ if (nextResolved !== workingResolved) {
1080
+ if (useDirectOutput) {
1081
+ classesOut.length = classCount;
1082
+ for (const key in styleOut) if (Object.hasOwn(styleOut, key)) Reflect.deleteProperty(styleOut, key);
1083
+ }
1084
+ computeOnce(nextResolved, userVariantProps, skipKeys, skipValues, classesOut, styleOut, runState, protectedVariants, null, protectedVariantKeys, defaultResolved, true);
1085
+ } else if (!useDirectOutput) {
1013
1086
  for (let i = 0; i < nextClasses.length; i++) classesOut.push(nextClasses[i]);
1014
1087
  Object.assign(styleOut, nextStyle);
1015
1088
  }
@@ -1046,26 +1119,35 @@ function create({ transformClass = (className) => className } = {}) {
1046
1119
  Object.assign(styleOut, lastStyle);
1047
1120
  return workingResolved;
1048
1121
  };
1049
- const resolveRefineOnce = (resolved, userVariantProps, filterOwnVariants = true, runState, protectedVariants, pendingProtectedVariants, protectedVariantKeys) => {
1122
+ const resolveRefineOnce = (resolved, userVariantProps, filterOwnVariants = true, runState, protectedVariants, pendingProtectedVariants, protectedVariantKeys, defaultResolved = resolved) => {
1050
1123
  let workingResolved = resolved;
1051
1124
  let changedVariants = null;
1052
- if (refine) {
1053
- const refineResult = runRefineContext(resolved, userVariantProps, filterOwnVariants, false, protectedVariants, pendingProtectedVariants, protectedVariantKeys);
1054
- workingResolved = refineResult.workingResolved;
1055
- changedVariants = refineResult.changedVariants;
1056
- }
1057
1125
  if (extMetasWithRefineCount > 0) {
1058
1126
  const extUserVariantProps = getExtUserVariantProps(userVariantProps, protectedVariants ?? null, changedVariants);
1059
1127
  for (let i = 0; i < extMetasWithRefineCount; i++) {
1060
1128
  const resolveRefine = extMetasWithRefine[i].resolveRefine;
1061
1129
  if (!resolveRefine) continue;
1062
- workingResolved = resolveRefine(workingResolved, extUserVariantProps, true, runState, protectedVariants, pendingProtectedVariants, protectedVariantKeys);
1130
+ workingResolved = resolveRefine(workingResolved, extUserVariantProps, true, runState, protectedVariants, pendingProtectedVariants, protectedVariantKeys, defaultResolved);
1131
+ workingResolved = filterOwnDisabledVariants(workingResolved, defaultResolved);
1063
1132
  if (protectedVariants) Object.assign(extUserVariantProps, protectedVariants);
1064
1133
  }
1065
1134
  }
1135
+ if (computedDefaultCount > 0) {
1136
+ const computedResult = runComputedDefaults(workingResolved, defaultResolved, userVariantProps, filterOwnVariants, protectedVariantKeys);
1137
+ workingResolved = computedResult.workingResolved;
1138
+ changedVariants = computedResult.changedVariants;
1139
+ }
1140
+ if (refine) {
1141
+ const refineResult = runRefineContext(workingResolved, userVariantProps, filterOwnVariants, false, true, protectedVariants, pendingProtectedVariants, protectedVariantKeys);
1142
+ workingResolved = refineResult.workingResolved;
1143
+ if (refineResult.changedVariants) {
1144
+ changedVariants ??= {};
1145
+ Object.assign(changedVariants, refineResult.changedVariants);
1146
+ }
1147
+ }
1066
1148
  return workingResolved;
1067
1149
  };
1068
- const resolveRefine = refine || extMetasWithRefineCount > 0 ? (resolved, userVariantProps, filterOwnVariants = true, runState, protectedVariants, pendingProtectedVariants, protectedVariantKeys) => {
1150
+ const resolveRefine = refine || computedDefaultCount > 0 || extMetasWithRefineCount > 0 ? (resolved, userVariantProps, filterOwnVariants = true, runState, protectedVariants, pendingProtectedVariants, protectedVariantKeys, incomingDefaultResolved = resolved) => {
1069
1151
  runState ??= { remaining: MAX_REFINE_RUNS };
1070
1152
  protectedVariants ??= {};
1071
1153
  protectedVariantKeys ??= /* @__PURE__ */ new Set();
@@ -1075,7 +1157,8 @@ function create({ transformClass = (className) => className } = {}) {
1075
1157
  while (runState.remaining > 0) {
1076
1158
  runState.remaining -= 1;
1077
1159
  const nextPendingProtectedVariants = {};
1078
- const nextResolved = resolveRefineOnce(workingResolved, userVariantProps, filterOwnVariants, runState, protectedVariants, nextPendingProtectedVariants, protectedVariantKeys);
1160
+ const defaultResolved = mergeProtectedIntoBase(incomingDefaultResolved, protectedVariants);
1161
+ const nextResolved = resolveRefineOnce(workingResolved, userVariantProps, filterOwnVariants, runState, protectedVariants, nextPendingProtectedVariants, protectedVariantKeys, defaultResolved);
1079
1162
  let protectedChanged;
1080
1163
  if (pendingProtectedVariants) protectedChanged = mergeVariants(pendingProtectedVariants, nextPendingProtectedVariants, protectedVariantKeys);
1081
1164
  else protectedChanged = mergeVariants(protectedVariants, nextPendingProtectedVariants, protectedVariantKeys);
@@ -1102,19 +1185,12 @@ function create({ transformClass = (className) => className } = {}) {
1102
1185
  let resolved = {};
1103
1186
  Object.assign(resolved, staticDefaults);
1104
1187
  let userVariantProps;
1105
- if (extMetasWithRefineCount > 0) {
1188
+ if (refine || computedDefaultCount > 0 || extMetasWithRefineCount > 0) {
1106
1189
  const variantProps = {};
1107
1190
  for (let i = 0; i < variantKeysLength; i++) {
1108
1191
  const key = variantKeys[i];
1109
1192
  if (Object.hasOwn(propsRecord, key)) variantProps[key] = propsRecord[key];
1110
1193
  }
1111
- for (let i = 0; i < extMetasWithRefineCount; i++) {
1112
- const extDefaults = extMetasWithRefine[i].resolveDefaults(resolved, variantProps);
1113
- for (const k in extDefaults) {
1114
- if (!Object.hasOwn(extDefaults, k)) continue;
1115
- resolved[k] = extDefaults[k];
1116
- }
1117
- }
1118
1194
  for (const k in variantProps) {
1119
1195
  if (!Object.hasOwn(variantProps, k)) continue;
1120
1196
  const v = variantProps[k];
@@ -1173,11 +1249,11 @@ function create({ transformClass = (className) => className } = {}) {
1173
1249
  const meta = {
1174
1250
  baseClass: computedBaseClass,
1175
1251
  staticDefaults,
1176
- resolveDefaults: resolveDefaultsFn,
1177
1252
  compute,
1178
1253
  resolveRefine,
1179
1254
  transformClass,
1180
- functionVariantKeys
1255
+ functionVariantKeys,
1256
+ computedDefaultKeys
1181
1257
  };
1182
1258
  const initComponent = (c, propKeys, style) => {
1183
1259
  c.class = classFn;
@@ -1244,7 +1320,6 @@ function create({ transformClass = (className) => className } = {}) {
1244
1320
  cx
1245
1321
  };
1246
1322
  }
1247
- function noop() {}
1248
1323
  const { cv, cx } = create();
1249
1324
  //#endregion
1250
1325
  export { create, cv, cx, splitProps };