cva 1.0.0-beta.4 → 1.0.0-beta.6

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.d.ts CHANGED
@@ -4,7 +4,35 @@ export type ClassArray = ClassValue[];
4
4
  type OmitUndefined<T> = T extends undefined ? never : T;
5
5
  type StringToBoolean<T> = T extends "true" | "false" ? boolean : T;
6
6
  type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
7
+ type ComposedTuple<S extends CVAComponentShape | undefined, L extends readonly CVAComponentShape[]> = [S] extends [CVAComponentShape] ? [S] : L;
8
+ type MergedVariants<T extends readonly unknown[]> = UnionToIntersection<{
9
+ [K in keyof T]: T[K] extends {
10
+ config: {
11
+ variants?: infer V extends CVAVariantShape;
12
+ };
13
+ } ? V : never;
14
+ }[number]>;
15
+ type RightMerge<A, B> = {
16
+ [K in keyof A | keyof B]: K extends keyof B ? B[K] : K extends keyof A ? A[K] : never;
17
+ };
18
+ type DefaultsOf<Component> = Component extends {
19
+ config: {
20
+ defaultVariants?: infer D;
21
+ };
22
+ } ? D extends undefined ? {} : D : {};
23
+ type MergedDefaultVariants<T extends readonly unknown[]> = T extends readonly [
24
+ infer Head,
25
+ ...infer Rest
26
+ ] ? RightMerge<DefaultsOf<Head>, MergedDefaultVariants<Rest>> : {};
7
27
  export type VariantProps<Component extends (...args: any) => any> = Omit<OmitUndefined<Parameters<Component>[0]>, "class" | "className">;
28
+ /**
29
+ * @deprecated Use the `composes` property inside `cva` instead.
30
+ * @example
31
+ * // Before
32
+ * const card = compose(box, stack)
33
+ * // After
34
+ * const card = cva({ composes: [box, stack] })
35
+ */
8
36
  export interface Compose {
9
37
  <T extends ReturnType<CVA>[]>(...components: [...T]): (props?: (UnionToIntersection<{
10
38
  [K in keyof T]: VariantProps<T[K]>;
@@ -15,10 +43,14 @@ export interface CX {
15
43
  }
16
44
  export type CXOptions = Parameters<CX>;
17
45
  export type CXReturn = ReturnType<CX>;
18
- type CVAConfigBase = {
46
+ type CVAComponentConfigBase = {
19
47
  base?: ClassValue;
20
48
  };
21
- type CVAVariantShape = Record<string, Record<string, ClassValue>>;
49
+ /**
50
+ * Exported so TypeScript can name this type in your generated declarations
51
+ * (`declaration: true`) — you shouldn't really use it directly.
52
+ */
53
+ export type CVAVariantShape = Record<string, Record<string, ClassValue>>;
22
54
  type CVAVariantSchema<V extends CVAVariantShape> = {
23
55
  [Variant in keyof V]?: StringToBoolean<keyof V[Variant]> | undefined;
24
56
  };
@@ -29,18 +61,42 @@ type CVAClassProp = {
29
61
  class?: never;
30
62
  className?: ClassValue;
31
63
  };
64
+ type InternalOnlyWarning = "cva's generic parameters are restricted to internal use only.";
65
+ type CVAComponentConfig<Config, Variants, ComposedSingle extends CVAComponentShape | undefined = CVAComponentShape | undefined, ComposedList extends readonly CVAComponentShape[] = readonly CVAComponentShape[]> = Config & {
66
+ composes?: ComposedSingle | readonly [...ComposedList];
67
+ } & (Variants extends CVAVariantShape ? CVAComponentConfigBase & {
68
+ variants?: Variants;
69
+ compoundVariants?: (Variants extends CVAVariantShape ? (CVAVariantSchema<Variants> | {
70
+ [Variant in keyof Variants]?: StringToBoolean<keyof Variants[Variant]> | StringToBoolean<keyof Variants[Variant]>[] | undefined;
71
+ }) & CVAClassProp : CVAClassProp)[];
72
+ defaultVariants?: CVAVariantSchema<Variants>;
73
+ } : CVAComponentConfigBase & {
74
+ variants?: never;
75
+ compoundVariants?: never;
76
+ defaultVariants?: never;
77
+ });
78
+ /**
79
+ * Exported so TypeScript can name this type in your generated declarations
80
+ * (`declaration: true`) — you shouldn't really use it directly.
81
+ */
82
+ export interface CVAComponent<Config, Variants> {
83
+ (props?: Variants extends CVAVariantShape ? CVAVariantSchema<Variants> & CVAClassProp : CVAClassProp): string;
84
+ /** @internal */
85
+ config: Config;
86
+ }
87
+ /**
88
+ * Exported so TypeScript can name this type in your generated declarations
89
+ * (`declaration: true`) — you shouldn't really use it directly.
90
+ */
91
+ export type CVAComponentShape = CVAComponent<any, any>;
92
+ type CVADefaultVariants<Config> = Config extends {
93
+ defaultVariants?: infer D;
94
+ } ? D : {};
32
95
  export interface CVA {
33
- <_ extends "cva's generic parameters are restricted to internal use only.", V>(config: V extends CVAVariantShape ? CVAConfigBase & {
34
- variants?: V;
35
- compoundVariants?: (V extends CVAVariantShape ? (CVAVariantSchema<V> | {
36
- [Variant in keyof V]?: StringToBoolean<keyof V[Variant]> | StringToBoolean<keyof V[Variant]>[] | undefined;
37
- }) & CVAClassProp : CVAClassProp)[];
38
- defaultVariants?: CVAVariantSchema<V>;
39
- } : CVAConfigBase & {
40
- variants?: never;
41
- compoundVariants?: never;
42
- defaultVariants?: never;
43
- }): (props?: V extends CVAVariantShape ? CVAVariantSchema<V> & CVAClassProp : CVAClassProp) => string;
96
+ <_ extends InternalOnlyWarning, Config, Variants, ComposedSingle extends CVAComponentShape | undefined = undefined, ComposedList extends readonly CVAComponentShape[] = []>(config: CVAComponentConfig<Config, Variants, ComposedSingle, ComposedList>): CVAComponent<Omit<Config, "defaultVariants"> & {
97
+ variants: Variants & MergedVariants<ComposedTuple<ComposedSingle, ComposedList>>;
98
+ defaultVariants: Omit<MergedDefaultVariants<ComposedTuple<ComposedSingle, ComposedList>>, keyof CVADefaultVariants<Config>> & CVADefaultVariants<Config>;
99
+ }, Variants & MergedVariants<ComposedTuple<ComposedSingle, ComposedList>>>;
44
100
  }
45
101
  export interface DefineConfigOptions {
46
102
  hooks?: {
@@ -56,6 +112,14 @@ export interface DefineConfigOptions {
56
112
  }
57
113
  export interface DefineConfig {
58
114
  (options?: DefineConfigOptions): {
115
+ /**
116
+ * @deprecated Use the `composes` property inside `cva` instead.
117
+ * @example
118
+ * // Before
119
+ * const card = compose(box, stack)
120
+ * // After
121
+ * const card = cva({ composes: [box, stack] })
122
+ */
59
123
  compose: Compose;
60
124
  cx: CX;
61
125
  cva: CVA;
@@ -63,4 +127,23 @@ export interface DefineConfig {
63
127
  }
64
128
  export declare const defineConfig: DefineConfig;
65
129
  export declare const compose: Compose, cva: CVA, cx: CX;
130
+ export interface GetSchema {
131
+ <_ extends InternalOnlyWarning, Component, Config, Variants>(component: Component & (Component extends ReturnType<CVA> ? {
132
+ config: CVAComponentConfig<Config, Variants>;
133
+ } : never)): {
134
+ [Variant in keyof Variants]: Config extends CVAComponentConfig<Config, Variants> ? Variant extends keyof Config["defaultVariants"] ? Config["defaultVariants"][Variant] extends undefined ? never : {
135
+ values: ReadonlyArray<StringToBoolean<keyof Variants[Variant]>>;
136
+ defaultValue: Readonly<StringToBoolean<Config["defaultVariants"][Variant]>>;
137
+ } : {
138
+ values: ReadonlyArray<StringToBoolean<keyof Variants[Variant]>>;
139
+ } : never;
140
+ } extends infer Schema ? {
141
+ [K in keyof Schema as Schema[K] extends {
142
+ values: readonly never[];
143
+ } ? never : K]: Schema[K] extends {
144
+ defaultValue: never;
145
+ } ? never : Schema[K];
146
+ } : never;
147
+ }
148
+ export declare const getSchema: GetSchema;
66
149
  export {};
package/dist/index.js CHANGED
@@ -19,85 +19,137 @@ Object.defineProperty(exports, "__esModule", {
19
19
  function _export(target, all) {
20
20
  for(var name in all)Object.defineProperty(target, name, {
21
21
  enumerable: true,
22
- get: all[name]
22
+ get: Object.getOwnPropertyDescriptor(all, name).get
23
23
  });
24
24
  }
25
25
  _export(exports, {
26
- compose: function() {
26
+ get compose () {
27
27
  return compose;
28
28
  },
29
- cva: function() {
29
+ get cva () {
30
30
  return cva;
31
31
  },
32
- cx: function() {
32
+ get cx () {
33
33
  return cx;
34
34
  },
35
- defineConfig: function() {
35
+ get defineConfig () {
36
36
  return defineConfig;
37
+ },
38
+ get getSchema () {
39
+ return getSchema;
37
40
  }
38
41
  });
39
42
  const _clsx = require("clsx");
40
43
  /* Exports
41
44
  ============================================ */ const falsyToString = (value)=>typeof value === "boolean" ? `${value}` : value === 0 ? "0" : value;
45
+ // Shared across every non-composed call, rather than allocating a fresh `[]`
46
+ // per call — `cx` (clsx) treats an empty array identically to an absent one.
47
+ const emptyClassNames = [];
42
48
  const defineConfig = (options)=>{
43
- const cx = function() {
44
- for(var _len = arguments.length, inputs = new Array(_len), _key = 0; _key < _len; _key++){
45
- inputs[_key] = arguments[_key];
46
- }
47
- var _options_hooks, _options_hooks1;
48
- if (typeof (options === null || options === void 0 ? void 0 : (_options_hooks = options.hooks) === null || _options_hooks === void 0 ? void 0 : _options_hooks["cx:done"]) !== "undefined") return options === null || options === void 0 ? void 0 : options.hooks["cx:done"]((0, _clsx.clsx)(inputs));
49
- if (typeof (options === null || options === void 0 ? void 0 : (_options_hooks1 = options.hooks) === null || _options_hooks1 === void 0 ? void 0 : _options_hooks1.onComplete) !== "undefined") return options === null || options === void 0 ? void 0 : options.hooks.onComplete((0, _clsx.clsx)(inputs));
49
+ const cx = (...inputs)=>{
50
+ if (typeof options?.hooks?.["cx:done"] !== "undefined") return options?.hooks["cx:done"]((0, _clsx.clsx)(inputs));
51
+ if (typeof options?.hooks?.onComplete !== "undefined") return options?.hooks.onComplete((0, _clsx.clsx)(inputs));
50
52
  return (0, _clsx.clsx)(inputs);
51
53
  };
52
- const cva = (config)=>(props)=>{
53
- var _config_compoundVariants;
54
- if ((config === null || config === void 0 ? void 0 : config.variants) == null) return cx(config === null || config === void 0 ? void 0 : config.base, props === null || props === void 0 ? void 0 : props.class, props === null || props === void 0 ? void 0 : props.className);
55
- const { variants, defaultVariants } = config;
54
+ const cva = (config)=>{
55
+ const components = config?.composes == null ? [] : Array.isArray(config.composes) ? config.composes : [
56
+ config.composes
57
+ ];
58
+ // A one-level-deep merge per variant key, so overlapping variants (e.g.
59
+ // multiple composed components declaring `style`) union their values
60
+ // instead of the last component's values silently replacing the rest.
61
+ const mergeVariants = (acc, variants)=>{
62
+ if (!variants) return acc;
63
+ const merged = {
64
+ ...acc
65
+ };
66
+ for (const key of Object.keys(variants)){
67
+ merged[key] = {
68
+ ...merged[key],
69
+ ...variants[key]
70
+ };
71
+ }
72
+ return merged;
73
+ };
74
+ const mergedVariantsFromComposed = components.reduce((acc, component)=>mergeVariants(acc, component.config?.variants), {});
75
+ const mergedVariants = mergeVariants(mergedVariantsFromComposed, config?.variants);
76
+ const mergedDefaultVariantsFromComposed = components.reduce((acc, component)=>({
77
+ ...acc,
78
+ ...component.config?.defaultVariants
79
+ }), {});
80
+ // Local `defaultVariants` win over composed ones here too (last spread).
81
+ const mergedDefaultVariants = {
82
+ ...mergedDefaultVariantsFromComposed,
83
+ ...config?.defaultVariants
84
+ };
85
+ const component = (props)=>{
86
+ // Strip `class`/`className` and explicit `undefined` from props once,
87
+ // reused for both the composed-component calls and compound-variant
88
+ // matching. An explicit `{ variant: undefined }` is dropped so it falls
89
+ // back to the (possibly composed) default, matching variant resolution
90
+ // below. Only built when something consumes it — a plain component with
91
+ // no `composes` and no `variants` skips the work entirely.
92
+ const definedPropsWithoutClass = components.length || config?.variants != null ? Object.fromEntries(Object.entries(props || {}).filter(([key, value])=>key !== "class" && key !== "className" && typeof value !== "undefined")) : {};
93
+ const getComposedClassNames = components.length ? components.map((component)=>component({
94
+ ...mergedDefaultVariants,
95
+ ...definedPropsWithoutClass
96
+ })) : emptyClassNames;
97
+ if (config?.variants == null) {
98
+ return cx(getComposedClassNames, config?.base, props?.class, props?.className);
99
+ }
100
+ const { variants } = config;
101
+ // Resolve against the *merged* defaults (composed + local) so a variant
102
+ // redeclared locally over a composed key uses the same effective default
103
+ // the composed components and `getSchema` see.
56
104
  const getVariantClassNames = Object.keys(variants).map((variant)=>{
57
- const variantProp = props === null || props === void 0 ? void 0 : props[variant];
58
- const defaultVariantProp = defaultVariants === null || defaultVariants === void 0 ? void 0 : defaultVariants[variant];
105
+ const variantProp = props?.[variant];
106
+ const defaultVariantProp = mergedDefaultVariants[variant];
59
107
  const variantKey = falsyToString(variantProp) || falsyToString(defaultVariantProp);
60
108
  return variants[variant][variantKey];
61
109
  });
62
110
  const defaultsAndProps = {
63
- ...defaultVariants,
64
- // remove `undefined` props
65
- ...props && Object.entries(props).reduce((acc, param)=>{
66
- let [key, value] = param;
67
- return typeof value === "undefined" ? acc : {
68
- ...acc,
69
- [key]: value
70
- };
71
- }, {})
111
+ ...mergedDefaultVariants,
112
+ ...definedPropsWithoutClass
72
113
  };
73
- const getCompoundVariantClassNames = config === null || config === void 0 ? void 0 : (_config_compoundVariants = config.compoundVariants) === null || _config_compoundVariants === void 0 ? void 0 : _config_compoundVariants.reduce((acc, param)=>{
74
- let { class: cvClass, className: cvClassName, ...cvConfig } = param;
75
- return Object.entries(cvConfig).every((param)=>{
76
- let [cvKey, cvSelector] = param;
114
+ const getCompoundVariantClassNames = config?.compoundVariants?.reduce((acc, { class: cvClass, className: cvClassName, ...cvConfig })=>Object.entries(cvConfig).every(([cvKey, cvSelector])=>{
77
115
  const selector = defaultsAndProps[cvKey];
78
116
  return Array.isArray(cvSelector) ? cvSelector.includes(selector) : selector === cvSelector;
79
117
  }) ? [
80
118
  ...acc,
81
119
  cvClass,
82
120
  cvClassName
83
- ] : acc;
84
- }, []);
85
- return cx(config === null || config === void 0 ? void 0 : config.base, getVariantClassNames, getCompoundVariantClassNames, props === null || props === void 0 ? void 0 : props.class, props === null || props === void 0 ? void 0 : props.className);
121
+ ] : acc, []);
122
+ return cx(getComposedClassNames, config?.base, getVariantClassNames, getCompoundVariantClassNames, props?.class, props?.className);
86
123
  };
87
- const compose = function() {
88
- for(var _len = arguments.length, components = new Array(_len), _key = 0; _key < _len; _key++){
89
- components[_key] = arguments[_key];
90
- }
91
- return (props)=>{
92
- const propsWithoutClass = Object.fromEntries(Object.entries(props || {}).filter((param)=>{
93
- let [key] = param;
94
- return ![
124
+ component.config = {
125
+ ...config,
126
+ variants: mergedVariants,
127
+ defaultVariants: mergedDefaultVariants
128
+ };
129
+ return component;
130
+ };
131
+ const compose = (...components)=>{
132
+ const config = components.reduce((acc, { config })=>{
133
+ Object.entries(config || {}).forEach(([key, value])=>{
134
+ acc[key] = typeof value === "object" && value !== null && !Array.isArray(value) ? {
135
+ ...acc[key],
136
+ ...value
137
+ } : value;
138
+ });
139
+ return acc;
140
+ }, // A loose accumulator: composed configs carry heterogeneous values
141
+ // (base strings, variant maps, compoundVariant arrays), not just the
142
+ // `CVAVariantShape` the merged `variants` key holds.
143
+ {});
144
+ const component = (props)=>{
145
+ const propsWithoutClass = Object.fromEntries(Object.entries(props || {}).filter(([key])=>![
95
146
  "class",
96
147
  "className"
97
- ].includes(key);
98
- }));
99
- return cx(components.map((component)=>component(propsWithoutClass)), props === null || props === void 0 ? void 0 : props.class, props === null || props === void 0 ? void 0 : props.className);
148
+ ].includes(key)));
149
+ return cx(components.map((component)=>component(propsWithoutClass)), props?.class, props?.className);
100
150
  };
151
+ component.config = config;
152
+ return component;
101
153
  };
102
154
  return {
103
155
  compose,
@@ -106,6 +158,36 @@ const defineConfig = (options)=>{
106
158
  };
107
159
  };
108
160
  const { compose, cva, cx } = defineConfig();
161
+ const getSchema = (component)=>{
162
+ if (!component.config?.variants) return {};
163
+ return Object.entries(component.config.variants).reduce((acc, [key, value])=>{
164
+ const defaultValue = component.config.defaultVariants?.[key];
165
+ const hasDefaultValue = defaultValue !== undefined;
166
+ const values = Object.keys(value).map((v)=>{
167
+ if (v === "true") return true;
168
+ if (v === "false") return false;
169
+ // Normalize numeric-literal keys back to numbers, since that's how
170
+ // they appear in variant prop types (`keyof { 1: ... }` is `1`, not
171
+ // `"1"`) — object keys are always strings/symbols at runtime. The
172
+ // `String(n) === v` round-trip only accepts canonical numeric forms
173
+ // (so `"01"`, `""`, `" 1"` stay strings), covering negatives too.
174
+ const n = Number(v);
175
+ return Number.isFinite(n) && String(n) === v ? n : v;
176
+ });
177
+ const hasValues = values.length > 0;
178
+ return hasValues || hasDefaultValue ? {
179
+ ...acc,
180
+ [key]: {
181
+ ...hasValues ? {
182
+ values
183
+ } : {},
184
+ ...hasDefaultValue ? {
185
+ defaultValue
186
+ } : {}
187
+ }
188
+ } : acc;
189
+ }, {});
190
+ };
109
191
 
110
192
 
111
193
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Copyright 2022 Joe Bell. All rights reserved.\n *\n * This file is licensed to you under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with the\n * License. You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\nimport { clsx } from \"clsx\";\n\n/* Types\n ============================================ */\n\n/* clsx\n ---------------------------------- */\n\n// When compiling with `declaration: true`, many projects experience the dreaded\n// TS2742 error. To combat this, we copy clsx's types manually.\n// Should this project move to JSDoc, this workaround would no longer be needed.\n\nexport type ClassValue =\n | ClassArray\n | ClassDictionary\n | string\n | number\n | bigint\n | null\n | boolean\n | undefined;\nexport type ClassDictionary = Record<string, any>;\nexport type ClassArray = ClassValue[];\n\n/* Utils\n ---------------------------------- */\n\ntype OmitUndefined<T> = T extends undefined ? never : T;\ntype StringToBoolean<T> = T extends \"true\" | \"false\" ? boolean : T;\ntype UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (\n k: infer I,\n) => void\n ? I\n : never;\n\nexport type VariantProps<Component extends (...args: any) => any> = Omit<\n OmitUndefined<Parameters<Component>[0]>,\n \"class\" | \"className\"\n>;\n\n/* compose\n ---------------------------------- */\n\nexport interface Compose {\n <T extends ReturnType<CVA>[]>(\n ...components: [...T]\n ): (\n props?: (\n | UnionToIntersection<\n {\n [K in keyof T]: VariantProps<T[K]>;\n }[number]\n >\n | undefined\n ) &\n CVAClassProp,\n ) => string;\n}\n\n/* cx\n ---------------------------------- */\n\nexport interface CX {\n (...inputs: ClassValue[]): string;\n}\n\nexport type CXOptions = Parameters<CX>;\nexport type CXReturn = ReturnType<CX>;\n\n/* cva\n ============================================ */\n\ntype CVAConfigBase = { base?: ClassValue };\ntype CVAVariantShape = Record<string, Record<string, ClassValue>>;\ntype CVAVariantSchema<V extends CVAVariantShape> = {\n [Variant in keyof V]?: StringToBoolean<keyof V[Variant]> | undefined;\n};\ntype CVAClassProp =\n | {\n class?: ClassValue;\n className?: never;\n }\n | {\n class?: never;\n className?: ClassValue;\n };\n\nexport interface CVA {\n <\n _ extends \"cva's generic parameters are restricted to internal use only.\",\n V,\n >(\n config: V extends CVAVariantShape\n ? CVAConfigBase & {\n variants?: V;\n compoundVariants?: (V extends CVAVariantShape\n ? (\n | CVAVariantSchema<V>\n | {\n [Variant in keyof V]?:\n | StringToBoolean<keyof V[Variant]>\n | StringToBoolean<keyof V[Variant]>[]\n | undefined;\n }\n ) &\n CVAClassProp\n : CVAClassProp)[];\n defaultVariants?: CVAVariantSchema<V>;\n }\n : CVAConfigBase & {\n variants?: never;\n compoundVariants?: never;\n defaultVariants?: never;\n },\n ): (\n props?: V extends CVAVariantShape\n ? CVAVariantSchema<V> & CVAClassProp\n : CVAClassProp,\n ) => string;\n}\n\n/* defineConfig\n ---------------------------------- */\n\nexport interface DefineConfigOptions {\n hooks?: {\n /**\n * @deprecated please use `onComplete`\n */\n \"cx:done\"?: (className: string) => string;\n /**\n * Returns the completed string of concatenated classes/classNames.\n */\n onComplete?: (className: string) => string;\n };\n}\n\nexport interface DefineConfig {\n (options?: DefineConfigOptions): {\n compose: Compose;\n cx: CX;\n cva: CVA;\n };\n}\n\n/* Exports\n ============================================ */\n\nconst falsyToString = <T extends unknown>(value: T) =>\n typeof value === \"boolean\" ? `${value}` : value === 0 ? \"0\" : value;\n\nexport const defineConfig: DefineConfig = (options) => {\n const cx: CX = (...inputs) => {\n if (typeof options?.hooks?.[\"cx:done\"] !== \"undefined\")\n return options?.hooks[\"cx:done\"](clsx(inputs));\n\n if (typeof options?.hooks?.onComplete !== \"undefined\")\n return options?.hooks.onComplete(clsx(inputs));\n\n return clsx(inputs);\n };\n\n const cva: CVA = (config) => (props) => {\n if (config?.variants == null)\n return cx(config?.base, props?.class, props?.className);\n\n const { variants, defaultVariants } = config;\n\n const getVariantClassNames = Object.keys(variants).map(\n (variant: keyof typeof variants) => {\n const variantProp = props?.[variant as keyof typeof props];\n const defaultVariantProp = defaultVariants?.[variant];\n\n const variantKey = (falsyToString(variantProp) ||\n falsyToString(\n defaultVariantProp,\n )) as keyof (typeof variants)[typeof variant];\n\n return variants[variant][variantKey];\n },\n );\n\n const defaultsAndProps = {\n ...defaultVariants,\n // remove `undefined` props\n ...(props &&\n Object.entries(props).reduce<typeof props>(\n (acc, [key, value]) =>\n typeof value === \"undefined\" ? acc : { ...acc, [key]: value },\n {} as typeof props,\n )),\n };\n\n const getCompoundVariantClassNames = config?.compoundVariants?.reduce(\n (acc, { class: cvClass, className: cvClassName, ...cvConfig }) =>\n Object.entries(cvConfig).every(([cvKey, cvSelector]) => {\n const selector =\n defaultsAndProps[cvKey as keyof typeof defaultsAndProps];\n\n return Array.isArray(cvSelector)\n ? cvSelector.includes(selector)\n : selector === cvSelector;\n })\n ? [...acc, cvClass, cvClassName]\n : acc,\n [] as ClassValue[],\n );\n\n return cx(\n config?.base,\n getVariantClassNames,\n getCompoundVariantClassNames,\n props?.class,\n props?.className,\n );\n };\n\n const compose: Compose =\n (...components) =>\n (props) => {\n const propsWithoutClass = Object.fromEntries(\n Object.entries(props || {}).filter(\n ([key]) => ![\"class\", \"className\"].includes(key),\n ),\n );\n\n return cx(\n components.map((component) => component(propsWithoutClass)),\n props?.class,\n props?.className,\n );\n };\n\n return {\n compose,\n cva,\n cx,\n };\n};\n\nexport const { compose, cva, cx } = defineConfig();\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":["compose","cva","cx","defineConfig","getSchema","falsyToString","value","emptyClassNames","options","inputs","hooks","clsx","onComplete","config","components","composes","Array","isArray","mergeVariants","acc","variants","merged","key","Object","keys","mergedVariantsFromComposed","reduce","component","mergedVariants","mergedDefaultVariantsFromComposed","defaultVariants","mergedDefaultVariants","props","definedPropsWithoutClass","length","fromEntries","entries","filter","getComposedClassNames","map","base","class","className","getVariantClassNames","variant","variantProp","defaultVariantProp","variantKey","defaultsAndProps","getCompoundVariantClassNames","compoundVariants","cvClass","cvClassName","cvConfig","every","cvKey","cvSelector","selector","includes","forEach","propsWithoutClass","defaultValue","hasDefaultValue","undefined","values","v","n","Number","isFinite","String","hasValues"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Copyright 2022 Joe Bell. All rights reserved.\n *\n * This file is licensed to you under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with the\n * License. You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\nimport { clsx } from \"clsx\";\n\n/* Types\n ============================================ */\n\n/* clsx\n ---------------------------------- */\n\n// When compiling with `declaration: true`, many projects experience the dreaded\n// TS2742 error. To combat this, we copy clsx's types manually.\n// Should this project move to JSDoc, this workaround would no longer be needed.\n\nexport type ClassValue =\n | ClassArray\n | ClassDictionary\n | string\n | number\n | bigint\n | null\n | boolean\n | undefined;\nexport type ClassDictionary = Record<string, any>;\nexport type ClassArray = ClassValue[];\n\n/* Utils\n ---------------------------------- */\n\ntype OmitUndefined<T> = T extends undefined ? never : T;\ntype StringToBoolean<T> = T extends \"true\" | \"false\" ? boolean : T;\ntype UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (\n k: infer I,\n) => void\n ? I\n : never;\n\n// `composes` accepts either a single component or a list of components. A\n// plain union (`CVAComponentShape | CVAComponentShape[]`) collapses an array\n// literal's element type to a union, silently dropping components whose\n// variants are a structural subtype of another composed component's (e.g.\n// `composes: [a, b]` where `b`'s variants are a superset of `a`'s). Splitting\n// inference across two type parameters preserves the array as a real tuple.\ntype ComposedTuple<\n S extends CVAComponentShape | undefined,\n L extends readonly CVAComponentShape[],\n> = [S] extends [CVAComponentShape] ? [S] : L;\n\ntype MergedVariants<T extends readonly unknown[]> = UnionToIntersection<\n {\n [K in keyof T]: T[K] extends {\n config: { variants?: infer V extends CVAVariantShape };\n }\n ? V\n : never;\n }[number]\n>;\n\n// Right-biased merge (`B`'s keys win on conflicts) implemented as a mapped\n// type rather than `Omit<A, keyof B> & B`: the latter stays an unresolved\n// deferred type when `A`/`B` are themselves generic (as they are here, via\n// `ReturnType<CVA>` with no concrete `Config`), which then breaks downstream\n// `any`-narrowing in unrelated code that consumes `ReturnType<CVA>` (e.g.\n// the deprecated `compose`). A mapped type resolves eagerly instead.\ntype RightMerge<A, B> = {\n [K in keyof A | keyof B]: K extends keyof B\n ? B[K]\n : K extends keyof A\n ? A[K]\n : never;\n};\n\n// `D` infers as `undefined` (not absent) when a component declares no\n// `defaultVariants` at all. `NonNullable<undefined>` would give `never`,\n// and `keyof never` is `string | number | symbol` (not `never`) — poisoning\n// `RightMerge`'s key union with every possible key. Normalize to `{}` instead,\n// matching a component that contributes nothing to the merge.\ntype DefaultsOf<Component> = Component extends {\n config: { defaultVariants?: infer D };\n}\n ? D extends undefined\n ? {}\n : D\n : {};\n\ntype MergedDefaultVariants<T extends readonly unknown[]> = T extends readonly [\n infer Head,\n ...infer Rest,\n]\n ? RightMerge<DefaultsOf<Head>, MergedDefaultVariants<Rest>>\n : {};\n\nexport type VariantProps<Component extends (...args: any) => any> = Omit<\n OmitUndefined<Parameters<Component>[0]>,\n \"class\" | \"className\"\n>;\n\n/* compose\n ---------------------------------- */\n\n/**\n * @deprecated Use the `composes` property inside `cva` instead.\n * @example\n * // Before\n * const card = compose(box, stack)\n * // After\n * const card = cva({ composes: [box, stack] })\n */\nexport interface Compose {\n <T extends ReturnType<CVA>[]>(\n ...components: [...T]\n ): (\n props?: (\n | UnionToIntersection<\n {\n [K in keyof T]: VariantProps<T[K]>;\n }[number]\n >\n | undefined\n ) &\n CVAClassProp,\n ) => string;\n}\n\n/* cx\n ---------------------------------- */\n\nexport interface CX {\n (...inputs: ClassValue[]): string;\n}\n\nexport type CXOptions = Parameters<CX>;\nexport type CXReturn = ReturnType<CX>;\n\n/* cva\n ============================================ */\n\ntype CVAComponentConfigBase = { base?: ClassValue };\n/**\n * Exported so TypeScript can name this type in your generated declarations\n * (`declaration: true`) — you shouldn't really use it directly.\n */\nexport type CVAVariantShape = Record<string, Record<string, ClassValue>>;\ntype CVAVariantSchema<V extends CVAVariantShape> = {\n [Variant in keyof V]?: StringToBoolean<keyof V[Variant]> | undefined;\n};\ntype CVAClassProp =\n | {\n class?: ClassValue;\n className?: never;\n }\n | {\n class?: never;\n className?: ClassValue;\n };\n\ntype InternalOnlyWarning =\n \"cva's generic parameters are restricted to internal use only.\";\n\ntype CVAComponentConfig<\n Config,\n Variants,\n ComposedSingle extends CVAComponentShape | undefined =\n | CVAComponentShape\n | undefined,\n ComposedList extends readonly CVAComponentShape[] =\n readonly CVAComponentShape[],\n> = Config & {\n composes?: ComposedSingle | readonly [...ComposedList];\n} & (Variants extends CVAVariantShape\n ? CVAComponentConfigBase & {\n variants?: Variants;\n compoundVariants?: (Variants extends CVAVariantShape\n ? (\n | CVAVariantSchema<Variants>\n | {\n [Variant in keyof Variants]?:\n | StringToBoolean<keyof Variants[Variant]>\n | StringToBoolean<keyof Variants[Variant]>[]\n | undefined;\n }\n ) &\n CVAClassProp\n : CVAClassProp)[];\n defaultVariants?: CVAVariantSchema<Variants>;\n }\n : CVAComponentConfigBase & {\n variants?: never;\n compoundVariants?: never;\n defaultVariants?: never;\n });\n\n/**\n * Exported so TypeScript can name this type in your generated declarations\n * (`declaration: true`) — you shouldn't really use it directly.\n */\nexport interface CVAComponent<Config, Variants> {\n (\n props?: Variants extends CVAVariantShape\n ? CVAVariantSchema<Variants> & CVAClassProp\n : CVAClassProp,\n ): string;\n /** @internal */\n config: Config;\n}\n\n// The loosest form a composable component can take, constraining `composes`\n// and the composition merge helpers above. Deriving it from `CVAComponent`\n// keeps the two from drifting: instantiated with `any`, the props conditional\n// and `config` both collapse to `any` (mapped types over `any` are `any`),\n// i.e. `{ (props?: any): string; config: any }`. The required `config`\n// property is what rejects plain functions and (deprecated) `compose`\n// results.\n//\n// The `any` arguments are deliberate, not lazy typing — a shaped `config`\n// (e.g. `{ variants?: CVAVariantShape }`) was tried and verifiably breaks:\n// a variant-less `cva({ base })` carries `variants: unknown`, and\n// `ReturnType<CVA>` instantiates this constraint inside the\n// `Compose`/`GetSchema` guards, where the shaped form rejects every real\n// component via props contravariance.\n/**\n * Exported so TypeScript can name this type in your generated declarations\n * (`declaration: true`) — you shouldn't really use it directly.\n */\nexport type CVAComponentShape = CVAComponent<any, any>;\n\ntype CVADefaultVariants<Config> = Config extends { defaultVariants?: infer D }\n ? D\n : {};\n\nexport interface CVA {\n <\n _ extends InternalOnlyWarning,\n Config,\n Variants,\n ComposedSingle extends CVAComponentShape | undefined = undefined,\n ComposedList extends readonly CVAComponentShape[] = [],\n >(\n config: CVAComponentConfig<Config, Variants, ComposedSingle, ComposedList>,\n ): CVAComponent<\n Omit<Config, \"defaultVariants\"> & {\n variants: Variants &\n MergedVariants<ComposedTuple<ComposedSingle, ComposedList>>;\n // Local `defaultVariants` win over composed ones on key conflicts,\n // matching the runtime spread order. A plain intersection would collapse\n // a conflicting key's value to `never` (e.g. `\"sm\" & \"lg\"`), which then\n // silently drops the variant from `getSchema`'s inferred type.\n defaultVariants: Omit<\n MergedDefaultVariants<ComposedTuple<ComposedSingle, ComposedList>>,\n keyof CVADefaultVariants<Config>\n > &\n CVADefaultVariants<Config>;\n },\n Variants & MergedVariants<ComposedTuple<ComposedSingle, ComposedList>>\n >;\n}\n\n/* defineConfig\n ---------------------------------- */\n\nexport interface DefineConfigOptions {\n hooks?: {\n /**\n * @deprecated please use `onComplete`\n */\n \"cx:done\"?: (className: string) => string;\n /**\n * Returns the completed string of concatenated classes/classNames.\n */\n onComplete?: (className: string) => string;\n };\n}\n\nexport interface DefineConfig {\n (options?: DefineConfigOptions): {\n /**\n * @deprecated Use the `composes` property inside `cva` instead.\n * @example\n * // Before\n * const card = compose(box, stack)\n * // After\n * const card = cva({ composes: [box, stack] })\n */\n compose: Compose;\n cx: CX;\n cva: CVA;\n };\n}\n\n/* Exports\n ============================================ */\n\nconst falsyToString = <T extends unknown>(value: T) =>\n typeof value === \"boolean\" ? `${value}` : value === 0 ? \"0\" : value;\n\n// Shared across every non-composed call, rather than allocating a fresh `[]`\n// per call — `cx` (clsx) treats an empty array identically to an absent one.\nconst emptyClassNames: string[] = [];\n\nexport const defineConfig: DefineConfig = (options) => {\n const cx: CX = (...inputs) => {\n if (typeof options?.hooks?.[\"cx:done\"] !== \"undefined\")\n return options?.hooks[\"cx:done\"](clsx(inputs));\n\n if (typeof options?.hooks?.onComplete !== \"undefined\")\n return options?.hooks.onComplete(clsx(inputs));\n\n return clsx(inputs);\n };\n\n const cva = (<\n _ extends InternalOnlyWarning,\n Config,\n Variants,\n ComposedSingle extends CVAComponentShape | undefined = undefined,\n ComposedList extends readonly CVAComponentShape[] = [],\n >(\n config: CVAComponentConfig<Config, Variants, ComposedSingle, ComposedList>,\n ) => {\n const components = (\n config?.composes == null\n ? []\n : Array.isArray(config.composes)\n ? config.composes\n : [config.composes]\n ) as CVAComponentShape[];\n // A one-level-deep merge per variant key, so overlapping variants (e.g.\n // multiple composed components declaring `style`) union their values\n // instead of the last component's values silently replacing the rest.\n const mergeVariants = (\n acc: CVAVariantShape,\n variants: CVAVariantShape | undefined,\n ): CVAVariantShape => {\n if (!variants) return acc;\n const merged: CVAVariantShape = { ...acc };\n for (const key of Object.keys(variants)) {\n merged[key] = { ...merged[key], ...variants[key] };\n }\n return merged;\n };\n const mergedVariantsFromComposed = components.reduce(\n (acc: CVAVariantShape, component: CVAComponentShape) =>\n mergeVariants(acc, component.config?.variants),\n {} as CVAVariantShape,\n );\n const mergedVariants = mergeVariants(\n mergedVariantsFromComposed,\n config?.variants as CVAVariantShape | undefined,\n );\n const mergedDefaultVariantsFromComposed = components.reduce(\n (acc: Record<string, unknown>, component: CVAComponentShape) => ({\n ...acc,\n ...component.config?.defaultVariants,\n }),\n {} as Record<string, unknown>,\n );\n // Local `defaultVariants` win over composed ones here too (last spread).\n const mergedDefaultVariants: Record<string, unknown> = {\n ...mergedDefaultVariantsFromComposed,\n ...config?.defaultVariants,\n };\n\n const component: CVAComponent<typeof config, typeof config.variants> = (\n props,\n ) => {\n // Strip `class`/`className` and explicit `undefined` from props once,\n // reused for both the composed-component calls and compound-variant\n // matching. An explicit `{ variant: undefined }` is dropped so it falls\n // back to the (possibly composed) default, matching variant resolution\n // below. Only built when something consumes it — a plain component with\n // no `composes` and no `variants` skips the work entirely.\n const definedPropsWithoutClass =\n components.length || config?.variants != null\n ? Object.fromEntries(\n Object.entries(props || {}).filter(\n ([key, value]) =>\n key !== \"class\" &&\n key !== \"className\" &&\n typeof value !== \"undefined\",\n ),\n )\n : {};\n\n const getComposedClassNames = components.length\n ? components.map((component: CVAComponentShape) =>\n component({\n ...mergedDefaultVariants,\n ...definedPropsWithoutClass,\n }),\n )\n : emptyClassNames;\n\n if (config?.variants == null) {\n return cx(\n getComposedClassNames,\n config?.base,\n props?.class,\n props?.className,\n );\n }\n\n const { variants } = config;\n\n // Resolve against the *merged* defaults (composed + local) so a variant\n // redeclared locally over a composed key uses the same effective default\n // the composed components and `getSchema` see.\n const getVariantClassNames = Object.keys(variants).map(\n (variant: keyof typeof variants) => {\n const variantProp = props?.[variant as keyof typeof props];\n const defaultVariantProp = mergedDefaultVariants[variant as string];\n\n const variantKey = (falsyToString(variantProp) ||\n falsyToString(\n defaultVariantProp,\n )) as keyof (typeof variants)[typeof variant];\n\n return variants[variant][variantKey];\n },\n );\n\n const defaultsAndProps = {\n ...mergedDefaultVariants,\n ...definedPropsWithoutClass,\n };\n\n const getCompoundVariantClassNames = config?.compoundVariants?.reduce(\n (\n acc: ClassValue[],\n {\n class: cvClass,\n className: cvClassName,\n ...cvConfig\n }: CVAClassProp & Record<string, unknown>,\n ) =>\n Object.entries(cvConfig).every(([cvKey, cvSelector]) => {\n const selector =\n defaultsAndProps[cvKey as keyof typeof defaultsAndProps];\n\n return Array.isArray(cvSelector)\n ? cvSelector.includes(selector)\n : selector === cvSelector;\n })\n ? [...acc, cvClass, cvClassName]\n : acc,\n [] as ClassValue[],\n );\n\n return cx(\n getComposedClassNames,\n config?.base,\n getVariantClassNames,\n getCompoundVariantClassNames,\n props?.class,\n props?.className,\n );\n };\n\n component.config = {\n ...config,\n variants: mergedVariants,\n defaultVariants: mergedDefaultVariants,\n };\n\n return component as ReturnType<CVA>;\n }) as CVA;\n\n const compose: Compose = (...components) => {\n const config = components.reduce(\n (acc, { config }) => {\n Object.entries(config || {}).forEach(([key, value]) => {\n acc[key] =\n typeof value === \"object\" && value !== null && !Array.isArray(value)\n ? {\n ...acc[key],\n ...value,\n }\n : value;\n });\n return acc;\n },\n // A loose accumulator: composed configs carry heterogeneous values\n // (base strings, variant maps, compoundVariant arrays), not just the\n // `CVAVariantShape` the merged `variants` key holds.\n {} as Record<string, any>,\n );\n\n const component: CVAComponent<typeof config, typeof config.variants> = (\n props,\n ) => {\n const propsWithoutClass = Object.fromEntries(\n Object.entries(props || {}).filter(\n ([key]) => ![\"class\", \"className\"].includes(key),\n ),\n );\n\n return cx(\n components.map((component) => component(propsWithoutClass)),\n props?.class,\n props?.className,\n );\n };\n\n component.config = config;\n\n return component;\n };\n\n return {\n compose,\n cva,\n cx,\n };\n};\n\nexport const { compose, cva, cx } = defineConfig();\n\nexport interface GetSchema {\n <_ extends InternalOnlyWarning, Component, Config, Variants>(\n component: Component &\n (Component extends ReturnType<CVA>\n ? { config: CVAComponentConfig<Config, Variants> }\n : never),\n ): {\n [Variant in keyof Variants]: Config extends CVAComponentConfig<\n Config,\n Variants\n >\n ? Variant extends keyof Config[\"defaultVariants\"]\n ? Config[\"defaultVariants\"][Variant] extends undefined\n ? never\n : {\n values: ReadonlyArray<StringToBoolean<keyof Variants[Variant]>>;\n defaultValue: Readonly<\n StringToBoolean<Config[\"defaultVariants\"][Variant]>\n >;\n }\n : {\n values: ReadonlyArray<StringToBoolean<keyof Variants[Variant]>>;\n }\n : never;\n // Iterate over the returned schema and remove any keys that have no values\n } extends infer Schema\n ? {\n [K in keyof Schema as Schema[K] extends {\n values: readonly never[];\n }\n ? never\n : K]: Schema[K] extends { defaultValue: never } ? never : Schema[K];\n }\n : never;\n}\n\nexport const getSchema: GetSchema = (component) => {\n if (!component.config?.variants) return {} as any;\n\n return Object.entries(component.config.variants).reduce(\n (acc, [key, value]) => {\n const defaultValue = component.config.defaultVariants?.[key];\n const hasDefaultValue = defaultValue !== undefined;\n const values = Object.keys(value).map((v) => {\n if (v === \"true\") return true;\n if (v === \"false\") return false;\n // Normalize numeric-literal keys back to numbers, since that's how\n // they appear in variant prop types (`keyof { 1: ... }` is `1`, not\n // `\"1\"`) — object keys are always strings/symbols at runtime. The\n // `String(n) === v` round-trip only accepts canonical numeric forms\n // (so `\"01\"`, `\"\"`, `\" 1\"` stay strings), covering negatives too.\n const n = Number(v);\n return Number.isFinite(n) && String(n) === v ? n : v;\n }) as StringToBoolean<keyof typeof value>[];\n const hasValues = values.length > 0;\n\n return hasValues || hasDefaultValue\n ? {\n ...acc,\n [key]: {\n ...(hasValues ? { values } : {}),\n ...(hasDefaultValue ? { defaultValue } : {}),\n },\n }\n : acc;\n },\n {} as ReturnType<GetSchema>,\n );\n};\n"]}
package/dist/index.mjs CHANGED
@@ -15,65 +15,114 @@
15
15
  */ import { clsx } from "clsx";
16
16
  /* Exports
17
17
  ============================================ */ const falsyToString = (value)=>typeof value === "boolean" ? `${value}` : value === 0 ? "0" : value;
18
+ // Shared across every non-composed call, rather than allocating a fresh `[]`
19
+ // per call — `cx` (clsx) treats an empty array identically to an absent one.
20
+ const emptyClassNames = [];
18
21
  export const defineConfig = (options)=>{
19
- const cx = function() {
20
- for(var _len = arguments.length, inputs = new Array(_len), _key = 0; _key < _len; _key++){
21
- inputs[_key] = arguments[_key];
22
- }
23
- var _options_hooks, _options_hooks1;
24
- if (typeof (options === null || options === void 0 ? void 0 : (_options_hooks = options.hooks) === null || _options_hooks === void 0 ? void 0 : _options_hooks["cx:done"]) !== "undefined") return options === null || options === void 0 ? void 0 : options.hooks["cx:done"](clsx(inputs));
25
- if (typeof (options === null || options === void 0 ? void 0 : (_options_hooks1 = options.hooks) === null || _options_hooks1 === void 0 ? void 0 : _options_hooks1.onComplete) !== "undefined") return options === null || options === void 0 ? void 0 : options.hooks.onComplete(clsx(inputs));
22
+ const cx = (...inputs)=>{
23
+ if (typeof options?.hooks?.["cx:done"] !== "undefined") return options?.hooks["cx:done"](clsx(inputs));
24
+ if (typeof options?.hooks?.onComplete !== "undefined") return options?.hooks.onComplete(clsx(inputs));
26
25
  return clsx(inputs);
27
26
  };
28
- const cva = (config)=>(props)=>{
29
- var _config_compoundVariants;
30
- if ((config === null || config === void 0 ? void 0 : config.variants) == null) return cx(config === null || config === void 0 ? void 0 : config.base, props === null || props === void 0 ? void 0 : props.class, props === null || props === void 0 ? void 0 : props.className);
31
- const { variants, defaultVariants } = config;
27
+ const cva = (config)=>{
28
+ const components = config?.composes == null ? [] : Array.isArray(config.composes) ? config.composes : [
29
+ config.composes
30
+ ];
31
+ // A one-level-deep merge per variant key, so overlapping variants (e.g.
32
+ // multiple composed components declaring `style`) union their values
33
+ // instead of the last component's values silently replacing the rest.
34
+ const mergeVariants = (acc, variants)=>{
35
+ if (!variants) return acc;
36
+ const merged = {
37
+ ...acc
38
+ };
39
+ for (const key of Object.keys(variants)){
40
+ merged[key] = {
41
+ ...merged[key],
42
+ ...variants[key]
43
+ };
44
+ }
45
+ return merged;
46
+ };
47
+ const mergedVariantsFromComposed = components.reduce((acc, component)=>mergeVariants(acc, component.config?.variants), {});
48
+ const mergedVariants = mergeVariants(mergedVariantsFromComposed, config?.variants);
49
+ const mergedDefaultVariantsFromComposed = components.reduce((acc, component)=>({
50
+ ...acc,
51
+ ...component.config?.defaultVariants
52
+ }), {});
53
+ // Local `defaultVariants` win over composed ones here too (last spread).
54
+ const mergedDefaultVariants = {
55
+ ...mergedDefaultVariantsFromComposed,
56
+ ...config?.defaultVariants
57
+ };
58
+ const component = (props)=>{
59
+ // Strip `class`/`className` and explicit `undefined` from props once,
60
+ // reused for both the composed-component calls and compound-variant
61
+ // matching. An explicit `{ variant: undefined }` is dropped so it falls
62
+ // back to the (possibly composed) default, matching variant resolution
63
+ // below. Only built when something consumes it — a plain component with
64
+ // no `composes` and no `variants` skips the work entirely.
65
+ const definedPropsWithoutClass = components.length || config?.variants != null ? Object.fromEntries(Object.entries(props || {}).filter(([key, value])=>key !== "class" && key !== "className" && typeof value !== "undefined")) : {};
66
+ const getComposedClassNames = components.length ? components.map((component)=>component({
67
+ ...mergedDefaultVariants,
68
+ ...definedPropsWithoutClass
69
+ })) : emptyClassNames;
70
+ if (config?.variants == null) {
71
+ return cx(getComposedClassNames, config?.base, props?.class, props?.className);
72
+ }
73
+ const { variants } = config;
74
+ // Resolve against the *merged* defaults (composed + local) so a variant
75
+ // redeclared locally over a composed key uses the same effective default
76
+ // the composed components and `getSchema` see.
32
77
  const getVariantClassNames = Object.keys(variants).map((variant)=>{
33
- const variantProp = props === null || props === void 0 ? void 0 : props[variant];
34
- const defaultVariantProp = defaultVariants === null || defaultVariants === void 0 ? void 0 : defaultVariants[variant];
78
+ const variantProp = props?.[variant];
79
+ const defaultVariantProp = mergedDefaultVariants[variant];
35
80
  const variantKey = falsyToString(variantProp) || falsyToString(defaultVariantProp);
36
81
  return variants[variant][variantKey];
37
82
  });
38
83
  const defaultsAndProps = {
39
- ...defaultVariants,
40
- // remove `undefined` props
41
- ...props && Object.entries(props).reduce((acc, param)=>{
42
- let [key, value] = param;
43
- return typeof value === "undefined" ? acc : {
44
- ...acc,
45
- [key]: value
46
- };
47
- }, {})
84
+ ...mergedDefaultVariants,
85
+ ...definedPropsWithoutClass
48
86
  };
49
- const getCompoundVariantClassNames = config === null || config === void 0 ? void 0 : (_config_compoundVariants = config.compoundVariants) === null || _config_compoundVariants === void 0 ? void 0 : _config_compoundVariants.reduce((acc, param)=>{
50
- let { class: cvClass, className: cvClassName, ...cvConfig } = param;
51
- return Object.entries(cvConfig).every((param)=>{
52
- let [cvKey, cvSelector] = param;
87
+ const getCompoundVariantClassNames = config?.compoundVariants?.reduce((acc, { class: cvClass, className: cvClassName, ...cvConfig })=>Object.entries(cvConfig).every(([cvKey, cvSelector])=>{
53
88
  const selector = defaultsAndProps[cvKey];
54
89
  return Array.isArray(cvSelector) ? cvSelector.includes(selector) : selector === cvSelector;
55
90
  }) ? [
56
91
  ...acc,
57
92
  cvClass,
58
93
  cvClassName
59
- ] : acc;
60
- }, []);
61
- return cx(config === null || config === void 0 ? void 0 : config.base, getVariantClassNames, getCompoundVariantClassNames, props === null || props === void 0 ? void 0 : props.class, props === null || props === void 0 ? void 0 : props.className);
94
+ ] : acc, []);
95
+ return cx(getComposedClassNames, config?.base, getVariantClassNames, getCompoundVariantClassNames, props?.class, props?.className);
96
+ };
97
+ component.config = {
98
+ ...config,
99
+ variants: mergedVariants,
100
+ defaultVariants: mergedDefaultVariants
62
101
  };
63
- const compose = function() {
64
- for(var _len = arguments.length, components = new Array(_len), _key = 0; _key < _len; _key++){
65
- components[_key] = arguments[_key];
66
- }
67
- return (props)=>{
68
- const propsWithoutClass = Object.fromEntries(Object.entries(props || {}).filter((param)=>{
69
- let [key] = param;
70
- return ![
102
+ return component;
103
+ };
104
+ const compose = (...components)=>{
105
+ const config = components.reduce((acc, { config })=>{
106
+ Object.entries(config || {}).forEach(([key, value])=>{
107
+ acc[key] = typeof value === "object" && value !== null && !Array.isArray(value) ? {
108
+ ...acc[key],
109
+ ...value
110
+ } : value;
111
+ });
112
+ return acc;
113
+ }, // A loose accumulator: composed configs carry heterogeneous values
114
+ // (base strings, variant maps, compoundVariant arrays), not just the
115
+ // `CVAVariantShape` the merged `variants` key holds.
116
+ {});
117
+ const component = (props)=>{
118
+ const propsWithoutClass = Object.fromEntries(Object.entries(props || {}).filter(([key])=>![
71
119
  "class",
72
120
  "className"
73
- ].includes(key);
74
- }));
75
- return cx(components.map((component)=>component(propsWithoutClass)), props === null || props === void 0 ? void 0 : props.class, props === null || props === void 0 ? void 0 : props.className);
121
+ ].includes(key)));
122
+ return cx(components.map((component)=>component(propsWithoutClass)), props?.class, props?.className);
76
123
  };
124
+ component.config = config;
125
+ return component;
77
126
  };
78
127
  return {
79
128
  compose,
@@ -82,6 +131,36 @@ export const defineConfig = (options)=>{
82
131
  };
83
132
  };
84
133
  export const { compose, cva, cx } = defineConfig();
134
+ export const getSchema = (component)=>{
135
+ if (!component.config?.variants) return {};
136
+ return Object.entries(component.config.variants).reduce((acc, [key, value])=>{
137
+ const defaultValue = component.config.defaultVariants?.[key];
138
+ const hasDefaultValue = defaultValue !== undefined;
139
+ const values = Object.keys(value).map((v)=>{
140
+ if (v === "true") return true;
141
+ if (v === "false") return false;
142
+ // Normalize numeric-literal keys back to numbers, since that's how
143
+ // they appear in variant prop types (`keyof { 1: ... }` is `1`, not
144
+ // `"1"`) — object keys are always strings/symbols at runtime. The
145
+ // `String(n) === v` round-trip only accepts canonical numeric forms
146
+ // (so `"01"`, `""`, `" 1"` stay strings), covering negatives too.
147
+ const n = Number(v);
148
+ return Number.isFinite(n) && String(n) === v ? n : v;
149
+ });
150
+ const hasValues = values.length > 0;
151
+ return hasValues || hasDefaultValue ? {
152
+ ...acc,
153
+ [key]: {
154
+ ...hasValues ? {
155
+ values
156
+ } : {},
157
+ ...hasDefaultValue ? {
158
+ defaultValue
159
+ } : {}
160
+ }
161
+ } : acc;
162
+ }, {});
163
+ };
85
164
 
86
165
 
87
166
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;CAcC,GACD,SAAS,IAAI,QAAQ,OAAO;AAiJ5B;+CAC+C,GAE/C,MAAM,gBAAgB,CAAoB,QACxC,OAAO,UAAU,YAAY,CAAC,EAAE,MAAM,CAAC,GAAG,UAAU,IAAI,MAAM;AAEhE,OAAO,MAAM,eAA6B,CAAC;IACzC,MAAM,KAAS;yCAAI;YAAA;;YACN,gBAGA;QAHX,IAAI,QAAO,oBAAA,+BAAA,iBAAA,QAAS,KAAK,cAAd,qCAAA,cAAgB,CAAC,UAAU,MAAK,aACzC,OAAO,oBAAA,8BAAA,QAAS,KAAK,CAAC,UAAU,CAAC,KAAK;QAExC,IAAI,QAAO,oBAAA,+BAAA,kBAAA,QAAS,KAAK,cAAd,sCAAA,gBAAgB,UAAU,MAAK,aACxC,OAAO,oBAAA,8BAAA,QAAS,KAAK,CAAC,UAAU,CAAC,KAAK;QAExC,OAAO,KAAK;IACd;IAEA,MAAM,MAAW,CAAC,SAAW,CAAC;gBA+BS;YA9BrC,IAAI,CAAA,mBAAA,6BAAA,OAAQ,QAAQ,KAAI,MACtB,OAAO,GAAG,mBAAA,6BAAA,OAAQ,IAAI,EAAE,kBAAA,4BAAA,MAAO,KAAK,EAAE,kBAAA,4BAAA,MAAO,SAAS;YAExD,MAAM,EAAE,QAAQ,EAAE,eAAe,EAAE,GAAG;YAEtC,MAAM,uBAAuB,OAAO,IAAI,CAAC,UAAU,GAAG,CACpD,CAAC;gBACC,MAAM,cAAc,kBAAA,4BAAA,KAAO,CAAC,QAA8B;gBAC1D,MAAM,qBAAqB,4BAAA,sCAAA,eAAiB,CAAC,QAAQ;gBAErD,MAAM,aAAc,cAAc,gBAChC,cACE;gBAGJ,OAAO,QAAQ,CAAC,QAAQ,CAAC,WAAW;YACtC;YAGF,MAAM,mBAAmB;gBACvB,GAAG,eAAe;gBAClB,2BAA2B;gBAC3B,GAAI,SACF,OAAO,OAAO,CAAC,OAAO,MAAM,CAC1B,CAAC;wBAAK,CAAC,KAAK,MAAM;2BAChB,OAAO,UAAU,cAAc,MAAM;wBAAE,GAAG,GAAG;wBAAE,CAAC,IAAI,EAAE;oBAAM;mBAC9D,CAAC,EACF;YACL;YAEA,MAAM,+BAA+B,mBAAA,8BAAA,2BAAA,OAAQ,gBAAgB,cAAxB,+CAAA,yBAA0B,MAAM,CACnE,CAAC;oBAAK,EAAE,OAAO,OAAO,EAAE,WAAW,WAAW,EAAE,GAAG,UAAU;uBAC3D,OAAO,OAAO,CAAC,UAAU,KAAK,CAAC;wBAAC,CAAC,OAAO,WAAW;oBACjD,MAAM,WACJ,gBAAgB,CAAC,MAAuC;oBAE1D,OAAO,MAAM,OAAO,CAAC,cACjB,WAAW,QAAQ,CAAC,YACpB,aAAa;gBACnB,KACI;uBAAI;oBAAK;oBAAS;iBAAY,GAC9B;eACN,EAAE;YAGJ,OAAO,GACL,mBAAA,6BAAA,OAAQ,IAAI,EACZ,sBACA,8BACA,kBAAA,4BAAA,MAAO,KAAK,EACZ,kBAAA,4BAAA,MAAO,SAAS;QAEpB;IAEA,MAAM,UACJ;yCAAI;YAAA;;eACJ,CAAC;YACC,MAAM,oBAAoB,OAAO,WAAW,CAC1C,OAAO,OAAO,CAAC,SAAS,CAAC,GAAG,MAAM,CAChC;oBAAC,CAAC,IAAI;uBAAK,CAAC;oBAAC;oBAAS;iBAAY,CAAC,QAAQ,CAAC;;YAIhD,OAAO,GACL,WAAW,GAAG,CAAC,CAAC,YAAc,UAAU,qBACxC,kBAAA,4BAAA,MAAO,KAAK,EACZ,kBAAA,4BAAA,MAAO,SAAS;QAEpB;;IAEF,OAAO;QACL;QACA;QACA;IACF;AACF,EAAE;AAEF,OAAO,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,eAAe","file":"index.mjs","sourcesContent":["/**\n * Copyright 2022 Joe Bell. All rights reserved.\n *\n * This file is licensed to you under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with the\n * License. You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\nimport { clsx } from \"clsx\";\n\n/* Types\n ============================================ */\n\n/* clsx\n ---------------------------------- */\n\n// When compiling with `declaration: true`, many projects experience the dreaded\n// TS2742 error. To combat this, we copy clsx's types manually.\n// Should this project move to JSDoc, this workaround would no longer be needed.\n\nexport type ClassValue =\n | ClassArray\n | ClassDictionary\n | string\n | number\n | bigint\n | null\n | boolean\n | undefined;\nexport type ClassDictionary = Record<string, any>;\nexport type ClassArray = ClassValue[];\n\n/* Utils\n ---------------------------------- */\n\ntype OmitUndefined<T> = T extends undefined ? never : T;\ntype StringToBoolean<T> = T extends \"true\" | \"false\" ? boolean : T;\ntype UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (\n k: infer I,\n) => void\n ? I\n : never;\n\nexport type VariantProps<Component extends (...args: any) => any> = Omit<\n OmitUndefined<Parameters<Component>[0]>,\n \"class\" | \"className\"\n>;\n\n/* compose\n ---------------------------------- */\n\nexport interface Compose {\n <T extends ReturnType<CVA>[]>(\n ...components: [...T]\n ): (\n props?: (\n | UnionToIntersection<\n {\n [K in keyof T]: VariantProps<T[K]>;\n }[number]\n >\n | undefined\n ) &\n CVAClassProp,\n ) => string;\n}\n\n/* cx\n ---------------------------------- */\n\nexport interface CX {\n (...inputs: ClassValue[]): string;\n}\n\nexport type CXOptions = Parameters<CX>;\nexport type CXReturn = ReturnType<CX>;\n\n/* cva\n ============================================ */\n\ntype CVAConfigBase = { base?: ClassValue };\ntype CVAVariantShape = Record<string, Record<string, ClassValue>>;\ntype CVAVariantSchema<V extends CVAVariantShape> = {\n [Variant in keyof V]?: StringToBoolean<keyof V[Variant]> | undefined;\n};\ntype CVAClassProp =\n | {\n class?: ClassValue;\n className?: never;\n }\n | {\n class?: never;\n className?: ClassValue;\n };\n\nexport interface CVA {\n <\n _ extends \"cva's generic parameters are restricted to internal use only.\",\n V,\n >(\n config: V extends CVAVariantShape\n ? CVAConfigBase & {\n variants?: V;\n compoundVariants?: (V extends CVAVariantShape\n ? (\n | CVAVariantSchema<V>\n | {\n [Variant in keyof V]?:\n | StringToBoolean<keyof V[Variant]>\n | StringToBoolean<keyof V[Variant]>[]\n | undefined;\n }\n ) &\n CVAClassProp\n : CVAClassProp)[];\n defaultVariants?: CVAVariantSchema<V>;\n }\n : CVAConfigBase & {\n variants?: never;\n compoundVariants?: never;\n defaultVariants?: never;\n },\n ): (\n props?: V extends CVAVariantShape\n ? CVAVariantSchema<V> & CVAClassProp\n : CVAClassProp,\n ) => string;\n}\n\n/* defineConfig\n ---------------------------------- */\n\nexport interface DefineConfigOptions {\n hooks?: {\n /**\n * @deprecated please use `onComplete`\n */\n \"cx:done\"?: (className: string) => string;\n /**\n * Returns the completed string of concatenated classes/classNames.\n */\n onComplete?: (className: string) => string;\n };\n}\n\nexport interface DefineConfig {\n (options?: DefineConfigOptions): {\n compose: Compose;\n cx: CX;\n cva: CVA;\n };\n}\n\n/* Exports\n ============================================ */\n\nconst falsyToString = <T extends unknown>(value: T) =>\n typeof value === \"boolean\" ? `${value}` : value === 0 ? \"0\" : value;\n\nexport const defineConfig: DefineConfig = (options) => {\n const cx: CX = (...inputs) => {\n if (typeof options?.hooks?.[\"cx:done\"] !== \"undefined\")\n return options?.hooks[\"cx:done\"](clsx(inputs));\n\n if (typeof options?.hooks?.onComplete !== \"undefined\")\n return options?.hooks.onComplete(clsx(inputs));\n\n return clsx(inputs);\n };\n\n const cva: CVA = (config) => (props) => {\n if (config?.variants == null)\n return cx(config?.base, props?.class, props?.className);\n\n const { variants, defaultVariants } = config;\n\n const getVariantClassNames = Object.keys(variants).map(\n (variant: keyof typeof variants) => {\n const variantProp = props?.[variant as keyof typeof props];\n const defaultVariantProp = defaultVariants?.[variant];\n\n const variantKey = (falsyToString(variantProp) ||\n falsyToString(\n defaultVariantProp,\n )) as keyof (typeof variants)[typeof variant];\n\n return variants[variant][variantKey];\n },\n );\n\n const defaultsAndProps = {\n ...defaultVariants,\n // remove `undefined` props\n ...(props &&\n Object.entries(props).reduce<typeof props>(\n (acc, [key, value]) =>\n typeof value === \"undefined\" ? acc : { ...acc, [key]: value },\n {} as typeof props,\n )),\n };\n\n const getCompoundVariantClassNames = config?.compoundVariants?.reduce(\n (acc, { class: cvClass, className: cvClassName, ...cvConfig }) =>\n Object.entries(cvConfig).every(([cvKey, cvSelector]) => {\n const selector =\n defaultsAndProps[cvKey as keyof typeof defaultsAndProps];\n\n return Array.isArray(cvSelector)\n ? cvSelector.includes(selector)\n : selector === cvSelector;\n })\n ? [...acc, cvClass, cvClassName]\n : acc,\n [] as ClassValue[],\n );\n\n return cx(\n config?.base,\n getVariantClassNames,\n getCompoundVariantClassNames,\n props?.class,\n props?.className,\n );\n };\n\n const compose: Compose =\n (...components) =>\n (props) => {\n const propsWithoutClass = Object.fromEntries(\n Object.entries(props || {}).filter(\n ([key]) => ![\"class\", \"className\"].includes(key),\n ),\n );\n\n return cx(\n components.map((component) => component(propsWithoutClass)),\n props?.class,\n props?.className,\n );\n };\n\n return {\n compose,\n cva,\n cx,\n };\n};\n\nexport const { compose, cva, cx } = defineConfig();\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":["clsx","falsyToString","value","emptyClassNames","defineConfig","options","cx","inputs","hooks","onComplete","cva","config","components","composes","Array","isArray","mergeVariants","acc","variants","merged","key","Object","keys","mergedVariantsFromComposed","reduce","component","mergedVariants","mergedDefaultVariantsFromComposed","defaultVariants","mergedDefaultVariants","props","definedPropsWithoutClass","length","fromEntries","entries","filter","getComposedClassNames","map","base","class","className","getVariantClassNames","variant","variantProp","defaultVariantProp","variantKey","defaultsAndProps","getCompoundVariantClassNames","compoundVariants","cvClass","cvClassName","cvConfig","every","cvKey","cvSelector","selector","includes","compose","forEach","propsWithoutClass","getSchema","defaultValue","hasDefaultValue","undefined","values","v","n","Number","isFinite","String","hasValues"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Copyright 2022 Joe Bell. All rights reserved.\n *\n * This file is licensed to you under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with the\n * License. You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\nimport { clsx } from \"clsx\";\n\n/* Types\n ============================================ */\n\n/* clsx\n ---------------------------------- */\n\n// When compiling with `declaration: true`, many projects experience the dreaded\n// TS2742 error. To combat this, we copy clsx's types manually.\n// Should this project move to JSDoc, this workaround would no longer be needed.\n\nexport type ClassValue =\n | ClassArray\n | ClassDictionary\n | string\n | number\n | bigint\n | null\n | boolean\n | undefined;\nexport type ClassDictionary = Record<string, any>;\nexport type ClassArray = ClassValue[];\n\n/* Utils\n ---------------------------------- */\n\ntype OmitUndefined<T> = T extends undefined ? never : T;\ntype StringToBoolean<T> = T extends \"true\" | \"false\" ? boolean : T;\ntype UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (\n k: infer I,\n) => void\n ? I\n : never;\n\n// `composes` accepts either a single component or a list of components. A\n// plain union (`CVAComponentShape | CVAComponentShape[]`) collapses an array\n// literal's element type to a union, silently dropping components whose\n// variants are a structural subtype of another composed component's (e.g.\n// `composes: [a, b]` where `b`'s variants are a superset of `a`'s). Splitting\n// inference across two type parameters preserves the array as a real tuple.\ntype ComposedTuple<\n S extends CVAComponentShape | undefined,\n L extends readonly CVAComponentShape[],\n> = [S] extends [CVAComponentShape] ? [S] : L;\n\ntype MergedVariants<T extends readonly unknown[]> = UnionToIntersection<\n {\n [K in keyof T]: T[K] extends {\n config: { variants?: infer V extends CVAVariantShape };\n }\n ? V\n : never;\n }[number]\n>;\n\n// Right-biased merge (`B`'s keys win on conflicts) implemented as a mapped\n// type rather than `Omit<A, keyof B> & B`: the latter stays an unresolved\n// deferred type when `A`/`B` are themselves generic (as they are here, via\n// `ReturnType<CVA>` with no concrete `Config`), which then breaks downstream\n// `any`-narrowing in unrelated code that consumes `ReturnType<CVA>` (e.g.\n// the deprecated `compose`). A mapped type resolves eagerly instead.\ntype RightMerge<A, B> = {\n [K in keyof A | keyof B]: K extends keyof B\n ? B[K]\n : K extends keyof A\n ? A[K]\n : never;\n};\n\n// `D` infers as `undefined` (not absent) when a component declares no\n// `defaultVariants` at all. `NonNullable<undefined>` would give `never`,\n// and `keyof never` is `string | number | symbol` (not `never`) — poisoning\n// `RightMerge`'s key union with every possible key. Normalize to `{}` instead,\n// matching a component that contributes nothing to the merge.\ntype DefaultsOf<Component> = Component extends {\n config: { defaultVariants?: infer D };\n}\n ? D extends undefined\n ? {}\n : D\n : {};\n\ntype MergedDefaultVariants<T extends readonly unknown[]> = T extends readonly [\n infer Head,\n ...infer Rest,\n]\n ? RightMerge<DefaultsOf<Head>, MergedDefaultVariants<Rest>>\n : {};\n\nexport type VariantProps<Component extends (...args: any) => any> = Omit<\n OmitUndefined<Parameters<Component>[0]>,\n \"class\" | \"className\"\n>;\n\n/* compose\n ---------------------------------- */\n\n/**\n * @deprecated Use the `composes` property inside `cva` instead.\n * @example\n * // Before\n * const card = compose(box, stack)\n * // After\n * const card = cva({ composes: [box, stack] })\n */\nexport interface Compose {\n <T extends ReturnType<CVA>[]>(\n ...components: [...T]\n ): (\n props?: (\n | UnionToIntersection<\n {\n [K in keyof T]: VariantProps<T[K]>;\n }[number]\n >\n | undefined\n ) &\n CVAClassProp,\n ) => string;\n}\n\n/* cx\n ---------------------------------- */\n\nexport interface CX {\n (...inputs: ClassValue[]): string;\n}\n\nexport type CXOptions = Parameters<CX>;\nexport type CXReturn = ReturnType<CX>;\n\n/* cva\n ============================================ */\n\ntype CVAComponentConfigBase = { base?: ClassValue };\n/**\n * Exported so TypeScript can name this type in your generated declarations\n * (`declaration: true`) — you shouldn't really use it directly.\n */\nexport type CVAVariantShape = Record<string, Record<string, ClassValue>>;\ntype CVAVariantSchema<V extends CVAVariantShape> = {\n [Variant in keyof V]?: StringToBoolean<keyof V[Variant]> | undefined;\n};\ntype CVAClassProp =\n | {\n class?: ClassValue;\n className?: never;\n }\n | {\n class?: never;\n className?: ClassValue;\n };\n\ntype InternalOnlyWarning =\n \"cva's generic parameters are restricted to internal use only.\";\n\ntype CVAComponentConfig<\n Config,\n Variants,\n ComposedSingle extends CVAComponentShape | undefined =\n | CVAComponentShape\n | undefined,\n ComposedList extends readonly CVAComponentShape[] =\n readonly CVAComponentShape[],\n> = Config & {\n composes?: ComposedSingle | readonly [...ComposedList];\n} & (Variants extends CVAVariantShape\n ? CVAComponentConfigBase & {\n variants?: Variants;\n compoundVariants?: (Variants extends CVAVariantShape\n ? (\n | CVAVariantSchema<Variants>\n | {\n [Variant in keyof Variants]?:\n | StringToBoolean<keyof Variants[Variant]>\n | StringToBoolean<keyof Variants[Variant]>[]\n | undefined;\n }\n ) &\n CVAClassProp\n : CVAClassProp)[];\n defaultVariants?: CVAVariantSchema<Variants>;\n }\n : CVAComponentConfigBase & {\n variants?: never;\n compoundVariants?: never;\n defaultVariants?: never;\n });\n\n/**\n * Exported so TypeScript can name this type in your generated declarations\n * (`declaration: true`) — you shouldn't really use it directly.\n */\nexport interface CVAComponent<Config, Variants> {\n (\n props?: Variants extends CVAVariantShape\n ? CVAVariantSchema<Variants> & CVAClassProp\n : CVAClassProp,\n ): string;\n /** @internal */\n config: Config;\n}\n\n// The loosest form a composable component can take, constraining `composes`\n// and the composition merge helpers above. Deriving it from `CVAComponent`\n// keeps the two from drifting: instantiated with `any`, the props conditional\n// and `config` both collapse to `any` (mapped types over `any` are `any`),\n// i.e. `{ (props?: any): string; config: any }`. The required `config`\n// property is what rejects plain functions and (deprecated) `compose`\n// results.\n//\n// The `any` arguments are deliberate, not lazy typing — a shaped `config`\n// (e.g. `{ variants?: CVAVariantShape }`) was tried and verifiably breaks:\n// a variant-less `cva({ base })` carries `variants: unknown`, and\n// `ReturnType<CVA>` instantiates this constraint inside the\n// `Compose`/`GetSchema` guards, where the shaped form rejects every real\n// component via props contravariance.\n/**\n * Exported so TypeScript can name this type in your generated declarations\n * (`declaration: true`) — you shouldn't really use it directly.\n */\nexport type CVAComponentShape = CVAComponent<any, any>;\n\ntype CVADefaultVariants<Config> = Config extends { defaultVariants?: infer D }\n ? D\n : {};\n\nexport interface CVA {\n <\n _ extends InternalOnlyWarning,\n Config,\n Variants,\n ComposedSingle extends CVAComponentShape | undefined = undefined,\n ComposedList extends readonly CVAComponentShape[] = [],\n >(\n config: CVAComponentConfig<Config, Variants, ComposedSingle, ComposedList>,\n ): CVAComponent<\n Omit<Config, \"defaultVariants\"> & {\n variants: Variants &\n MergedVariants<ComposedTuple<ComposedSingle, ComposedList>>;\n // Local `defaultVariants` win over composed ones on key conflicts,\n // matching the runtime spread order. A plain intersection would collapse\n // a conflicting key's value to `never` (e.g. `\"sm\" & \"lg\"`), which then\n // silently drops the variant from `getSchema`'s inferred type.\n defaultVariants: Omit<\n MergedDefaultVariants<ComposedTuple<ComposedSingle, ComposedList>>,\n keyof CVADefaultVariants<Config>\n > &\n CVADefaultVariants<Config>;\n },\n Variants & MergedVariants<ComposedTuple<ComposedSingle, ComposedList>>\n >;\n}\n\n/* defineConfig\n ---------------------------------- */\n\nexport interface DefineConfigOptions {\n hooks?: {\n /**\n * @deprecated please use `onComplete`\n */\n \"cx:done\"?: (className: string) => string;\n /**\n * Returns the completed string of concatenated classes/classNames.\n */\n onComplete?: (className: string) => string;\n };\n}\n\nexport interface DefineConfig {\n (options?: DefineConfigOptions): {\n /**\n * @deprecated Use the `composes` property inside `cva` instead.\n * @example\n * // Before\n * const card = compose(box, stack)\n * // After\n * const card = cva({ composes: [box, stack] })\n */\n compose: Compose;\n cx: CX;\n cva: CVA;\n };\n}\n\n/* Exports\n ============================================ */\n\nconst falsyToString = <T extends unknown>(value: T) =>\n typeof value === \"boolean\" ? `${value}` : value === 0 ? \"0\" : value;\n\n// Shared across every non-composed call, rather than allocating a fresh `[]`\n// per call — `cx` (clsx) treats an empty array identically to an absent one.\nconst emptyClassNames: string[] = [];\n\nexport const defineConfig: DefineConfig = (options) => {\n const cx: CX = (...inputs) => {\n if (typeof options?.hooks?.[\"cx:done\"] !== \"undefined\")\n return options?.hooks[\"cx:done\"](clsx(inputs));\n\n if (typeof options?.hooks?.onComplete !== \"undefined\")\n return options?.hooks.onComplete(clsx(inputs));\n\n return clsx(inputs);\n };\n\n const cva = (<\n _ extends InternalOnlyWarning,\n Config,\n Variants,\n ComposedSingle extends CVAComponentShape | undefined = undefined,\n ComposedList extends readonly CVAComponentShape[] = [],\n >(\n config: CVAComponentConfig<Config, Variants, ComposedSingle, ComposedList>,\n ) => {\n const components = (\n config?.composes == null\n ? []\n : Array.isArray(config.composes)\n ? config.composes\n : [config.composes]\n ) as CVAComponentShape[];\n // A one-level-deep merge per variant key, so overlapping variants (e.g.\n // multiple composed components declaring `style`) union their values\n // instead of the last component's values silently replacing the rest.\n const mergeVariants = (\n acc: CVAVariantShape,\n variants: CVAVariantShape | undefined,\n ): CVAVariantShape => {\n if (!variants) return acc;\n const merged: CVAVariantShape = { ...acc };\n for (const key of Object.keys(variants)) {\n merged[key] = { ...merged[key], ...variants[key] };\n }\n return merged;\n };\n const mergedVariantsFromComposed = components.reduce(\n (acc: CVAVariantShape, component: CVAComponentShape) =>\n mergeVariants(acc, component.config?.variants),\n {} as CVAVariantShape,\n );\n const mergedVariants = mergeVariants(\n mergedVariantsFromComposed,\n config?.variants as CVAVariantShape | undefined,\n );\n const mergedDefaultVariantsFromComposed = components.reduce(\n (acc: Record<string, unknown>, component: CVAComponentShape) => ({\n ...acc,\n ...component.config?.defaultVariants,\n }),\n {} as Record<string, unknown>,\n );\n // Local `defaultVariants` win over composed ones here too (last spread).\n const mergedDefaultVariants: Record<string, unknown> = {\n ...mergedDefaultVariantsFromComposed,\n ...config?.defaultVariants,\n };\n\n const component: CVAComponent<typeof config, typeof config.variants> = (\n props,\n ) => {\n // Strip `class`/`className` and explicit `undefined` from props once,\n // reused for both the composed-component calls and compound-variant\n // matching. An explicit `{ variant: undefined }` is dropped so it falls\n // back to the (possibly composed) default, matching variant resolution\n // below. Only built when something consumes it — a plain component with\n // no `composes` and no `variants` skips the work entirely.\n const definedPropsWithoutClass =\n components.length || config?.variants != null\n ? Object.fromEntries(\n Object.entries(props || {}).filter(\n ([key, value]) =>\n key !== \"class\" &&\n key !== \"className\" &&\n typeof value !== \"undefined\",\n ),\n )\n : {};\n\n const getComposedClassNames = components.length\n ? components.map((component: CVAComponentShape) =>\n component({\n ...mergedDefaultVariants,\n ...definedPropsWithoutClass,\n }),\n )\n : emptyClassNames;\n\n if (config?.variants == null) {\n return cx(\n getComposedClassNames,\n config?.base,\n props?.class,\n props?.className,\n );\n }\n\n const { variants } = config;\n\n // Resolve against the *merged* defaults (composed + local) so a variant\n // redeclared locally over a composed key uses the same effective default\n // the composed components and `getSchema` see.\n const getVariantClassNames = Object.keys(variants).map(\n (variant: keyof typeof variants) => {\n const variantProp = props?.[variant as keyof typeof props];\n const defaultVariantProp = mergedDefaultVariants[variant as string];\n\n const variantKey = (falsyToString(variantProp) ||\n falsyToString(\n defaultVariantProp,\n )) as keyof (typeof variants)[typeof variant];\n\n return variants[variant][variantKey];\n },\n );\n\n const defaultsAndProps = {\n ...mergedDefaultVariants,\n ...definedPropsWithoutClass,\n };\n\n const getCompoundVariantClassNames = config?.compoundVariants?.reduce(\n (\n acc: ClassValue[],\n {\n class: cvClass,\n className: cvClassName,\n ...cvConfig\n }: CVAClassProp & Record<string, unknown>,\n ) =>\n Object.entries(cvConfig).every(([cvKey, cvSelector]) => {\n const selector =\n defaultsAndProps[cvKey as keyof typeof defaultsAndProps];\n\n return Array.isArray(cvSelector)\n ? cvSelector.includes(selector)\n : selector === cvSelector;\n })\n ? [...acc, cvClass, cvClassName]\n : acc,\n [] as ClassValue[],\n );\n\n return cx(\n getComposedClassNames,\n config?.base,\n getVariantClassNames,\n getCompoundVariantClassNames,\n props?.class,\n props?.className,\n );\n };\n\n component.config = {\n ...config,\n variants: mergedVariants,\n defaultVariants: mergedDefaultVariants,\n };\n\n return component as ReturnType<CVA>;\n }) as CVA;\n\n const compose: Compose = (...components) => {\n const config = components.reduce(\n (acc, { config }) => {\n Object.entries(config || {}).forEach(([key, value]) => {\n acc[key] =\n typeof value === \"object\" && value !== null && !Array.isArray(value)\n ? {\n ...acc[key],\n ...value,\n }\n : value;\n });\n return acc;\n },\n // A loose accumulator: composed configs carry heterogeneous values\n // (base strings, variant maps, compoundVariant arrays), not just the\n // `CVAVariantShape` the merged `variants` key holds.\n {} as Record<string, any>,\n );\n\n const component: CVAComponent<typeof config, typeof config.variants> = (\n props,\n ) => {\n const propsWithoutClass = Object.fromEntries(\n Object.entries(props || {}).filter(\n ([key]) => ![\"class\", \"className\"].includes(key),\n ),\n );\n\n return cx(\n components.map((component) => component(propsWithoutClass)),\n props?.class,\n props?.className,\n );\n };\n\n component.config = config;\n\n return component;\n };\n\n return {\n compose,\n cva,\n cx,\n };\n};\n\nexport const { compose, cva, cx } = defineConfig();\n\nexport interface GetSchema {\n <_ extends InternalOnlyWarning, Component, Config, Variants>(\n component: Component &\n (Component extends ReturnType<CVA>\n ? { config: CVAComponentConfig<Config, Variants> }\n : never),\n ): {\n [Variant in keyof Variants]: Config extends CVAComponentConfig<\n Config,\n Variants\n >\n ? Variant extends keyof Config[\"defaultVariants\"]\n ? Config[\"defaultVariants\"][Variant] extends undefined\n ? never\n : {\n values: ReadonlyArray<StringToBoolean<keyof Variants[Variant]>>;\n defaultValue: Readonly<\n StringToBoolean<Config[\"defaultVariants\"][Variant]>\n >;\n }\n : {\n values: ReadonlyArray<StringToBoolean<keyof Variants[Variant]>>;\n }\n : never;\n // Iterate over the returned schema and remove any keys that have no values\n } extends infer Schema\n ? {\n [K in keyof Schema as Schema[K] extends {\n values: readonly never[];\n }\n ? never\n : K]: Schema[K] extends { defaultValue: never } ? never : Schema[K];\n }\n : never;\n}\n\nexport const getSchema: GetSchema = (component) => {\n if (!component.config?.variants) return {} as any;\n\n return Object.entries(component.config.variants).reduce(\n (acc, [key, value]) => {\n const defaultValue = component.config.defaultVariants?.[key];\n const hasDefaultValue = defaultValue !== undefined;\n const values = Object.keys(value).map((v) => {\n if (v === \"true\") return true;\n if (v === \"false\") return false;\n // Normalize numeric-literal keys back to numbers, since that's how\n // they appear in variant prop types (`keyof { 1: ... }` is `1`, not\n // `\"1\"`) — object keys are always strings/symbols at runtime. The\n // `String(n) === v` round-trip only accepts canonical numeric forms\n // (so `\"01\"`, `\"\"`, `\" 1\"` stay strings), covering negatives too.\n const n = Number(v);\n return Number.isFinite(n) && String(n) === v ? n : v;\n }) as StringToBoolean<keyof typeof value>[];\n const hasValues = values.length > 0;\n\n return hasValues || hasDefaultValue\n ? {\n ...acc,\n [key]: {\n ...(hasValues ? { values } : {}),\n ...(hasDefaultValue ? { defaultValue } : {}),\n },\n }\n : acc;\n },\n {} as ReturnType<GetSchema>,\n );\n};\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "cva",
3
- "version": "1.0.0-beta.4",
4
- "description": "Class Variance Authority 🧬",
3
+ "version": "1.0.0-beta.6",
4
+ "description": "Class Variance Authority",
5
5
  "keywords": [
6
6
  "Class Variance Authority",
7
7
  "class-variance-authority",
@@ -17,9 +17,9 @@
17
17
  "homepage": "https://github.com/joe-bell/cva#readme",
18
18
  "bugs": "https://github.com/joe-bell/cva/issues",
19
19
  "repository": "https://github.com/joe-bell/cva.git",
20
- "funding": "https://polar.sh/cva",
21
20
  "license": "Apache-2.0",
22
- "author": "Joe Bell (https://joebell.co.uk)",
21
+ "author": "Joe Bell (https://joebell.studio)",
22
+ "sideEffects": false,
23
23
  "exports": {
24
24
  "types": "./dist/index.d.ts",
25
25
  "import": "./dist/index.mjs",
@@ -35,17 +35,18 @@
35
35
  "clsx": "^2.1.1"
36
36
  },
37
37
  "devDependencies": {
38
- "@arethetypeswrong/cli": "0.17.3",
39
- "@swc/cli": "0.3.12",
40
- "@swc/core": "1.4.16",
41
- "@types/node": "20.12.7",
42
- "@types/react": "18.2.79",
43
- "@types/react-dom": "18.2.25",
44
- "bundlesize": "0.18.2",
45
- "react": "18.2.0",
46
- "react-dom": "18.2.0",
38
+ "@arethetypeswrong/cli": "0.18.2",
39
+ "@size-limit/preset-small-lib": "^12.1.0",
40
+ "@swc/cli": "0.8.1",
41
+ "@swc/core": "1.15.33",
42
+ "@types/node": "24.13.2",
43
+ "@types/react": "19.2.14",
44
+ "@types/react-dom": "19.2.3",
45
+ "react": "19.2.6",
46
+ "react-dom": "19.2.6",
47
+ "size-limit": "^12.1.0",
47
48
  "ts-node": "10.9.2",
48
- "typescript": "5.7.3"
49
+ "typescript": "6.0.3"
49
50
  },
50
51
  "peerDependencies": {
51
52
  "typescript": ">= 4.5.5"
@@ -55,15 +56,20 @@
55
56
  "optional": true
56
57
  }
57
58
  },
59
+ "size-limit": [
60
+ {
61
+ "path": "dist/index.js",
62
+ "limit": "1.6KB"
63
+ }
64
+ ],
58
65
  "scripts": {
59
66
  "build": "pnpm run '/^build:.*/'",
60
67
  "build:cjs": "swc ./src/index.ts --config-file ./.config/.swcrc -o dist/index.js -C module.type=commonjs",
61
68
  "build:esm": "swc ./src/index.ts --config-file ./.config/.swcrc -o dist/index.mjs -C module.type=es6 ",
62
69
  "build:tsc": "tsc --project .config/tsconfig.build.json",
63
- "bundlesize": "pnpm build && bundlesize -f 'dist/*.js' -s 1.6KB",
70
+ "bundlesize": "pnpm build && size-limit",
64
71
  "check": "pnpm run '/^check:.*/'",
65
72
  "check:exports": "attw --pack .",
66
- "check:tsc": "tsc --project tsconfig.json --noEmit",
67
- "dev": "jest --config .config/jest.config.ts --watch"
73
+ "check:tsc": "tsc --project tsconfig.json --noEmit"
68
74
  }
69
75
  }