clava 0.3.0 → 0.4.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/src/types.ts CHANGED
@@ -179,46 +179,46 @@ export interface ModalComponent<V, R extends ComponentResult> {
179
179
 
180
180
  export interface CVComponent<
181
181
  V extends Variants = {},
182
- CV extends ComputedVariants = {},
183
182
  E extends AnyComponent[] = [],
184
183
  R extends ComponentResult = StyleClassProps,
185
- > extends ModalComponent<MergeVariants<V, CV, E>, R> {
186
- jsx: ModalComponent<MergeVariants<V, CV, E>, JSXProps>;
187
- html: ModalComponent<MergeVariants<V, CV, E>, HTMLProps>;
188
- htmlObj: ModalComponent<MergeVariants<V, CV, E>, HTMLObjProps>;
184
+ > extends ModalComponent<MergeVariants<V, E>, R> {
185
+ jsx: ModalComponent<MergeVariants<V, E>, JSXProps>;
186
+ html: ModalComponent<MergeVariants<V, E>, HTMLProps>;
187
+ htmlObj: ModalComponent<MergeVariants<V, E>, HTMLObjProps>;
189
188
  }
190
189
 
191
190
  export type AnyComponent =
192
- | CVComponent<any, any, any, any>
191
+ | CVComponent<any, any, any>
193
192
  | ModalComponent<any, any>;
194
193
 
195
194
  type MergeExtendedVariants<T> = T extends readonly [infer First, ...infer Rest]
196
195
  ? ExtractVariants<First> & MergeExtendedVariants<Rest>
197
196
  : {};
198
197
 
199
- type MergeExtendedComputedVariants<T> = T extends readonly [
200
- infer First,
201
- ...infer Rest,
202
- ]
203
- ? ExtractComputedVariants<First> & MergeExtendedComputedVariants<Rest>
204
- : {};
205
-
198
+ // Returns a component's effective variants — merged with its own extends
199
+ // so that a later intermediate component's static variant correctly hides a
200
+ // grandparent's function variant from further descendants. Using a raw
201
+ // intersection here would re-expose the grandparent function through the
202
+ // type chain even after the middle layer replaced it.
206
203
  type ExtractVariants<T> =
207
- T extends CVComponent<infer V, any, infer E, any>
208
- ? V & MergeExtendedVariants<E>
209
- : {};
210
-
211
- type ExtractComputedVariants<T> =
212
- T extends CVComponent<any, infer CV, infer E, any>
213
- ? CV & Omit<MergeExtendedComputedVariants<E>, keyof CV>
204
+ T extends CVComponent<infer V, infer E, any>
205
+ ? MergeVariantMaps<V, MergeExtendedVariants<E>>
214
206
  : {};
215
207
 
216
- type MergeVariantDefinition<Child, Parent> =
217
- Child extends Record<string, any>
218
- ? Parent extends Record<string, any>
219
- ? Omit<Parent, keyof Child> & Child
220
- : Child
221
- : Child;
208
+ // A function value in `variants` (a function variant) replaces any inherited
209
+ // variant for the same key. An object value merges value-by-value with an
210
+ // inherited object, but replaces an inherited function.
211
+ type MergeVariantDefinition<Child, Parent> = Child extends (
212
+ ...args: any[]
213
+ ) => any
214
+ ? Child
215
+ : Parent extends (...args: any[]) => any
216
+ ? Child
217
+ : Child extends Record<string, any>
218
+ ? Parent extends Record<string, any>
219
+ ? Omit<Parent, keyof Child> & Child
220
+ : Child
221
+ : Child;
222
222
 
223
223
  type MergeVariantMaps<Child, Parent> = Omit<Parent, keyof Child> &
224
224
  Child & {
@@ -228,17 +228,11 @@ type MergeVariantMaps<Child, Parent> = Omit<Parent, keyof Child> &
228
228
  >;
229
229
  };
230
230
 
231
- type MergeExtendedAllVariants<E extends AnyComponent[]> =
232
- MergeExtendedVariants<E> & MergeExtendedComputedVariants<E>;
233
-
234
- type MergeBaseVariants<V, E extends AnyComponent[]> = MergeVariantMaps<
231
+ export type MergeVariants<V, E extends AnyComponent[]> = MergeVariantMaps<
235
232
  NoInfer<V>,
236
- MergeExtendedAllVariants<E>
233
+ MergeExtendedVariants<E>
237
234
  >;
238
235
 
239
- export type MergeVariants<V, CV, E extends AnyComponent[]> = NoInfer<CV> &
240
- Omit<MergeBaseVariants<V, E>, keyof CV>;
241
-
242
236
  type StringToBoolean<T> = T extends "true" | "false" ? boolean : T;
243
237
 
244
238
  type VariantValue = ClassValue | StyleClassValue;
@@ -272,7 +266,7 @@ export interface StyleClassValue {
272
266
  class?: ClassValue;
273
267
  }
274
268
 
275
- export interface ComputedContext<V> {
269
+ export interface RefineContext<V> {
276
270
  variants: VariantValues<V>;
277
271
  setVariants: (variants: VariantValues<V>) => void;
278
272
  setDefaultVariants: (variants: VariantValues<V>) => void;
@@ -280,16 +274,14 @@ export interface ComputedContext<V> {
280
274
  addStyle: (style: StyleValue) => void;
281
275
  }
282
276
 
283
- export type Computed<V> = (context: ComputedContext<V>) => VariantValue;
277
+ export type Refine<V> = (context: RefineContext<V>) => VariantValue;
284
278
 
285
- export type ComputedVariant = (value: any) => VariantValue;
286
- export type ComputedVariants = Record<string, ComputedVariant>;
287
- export type Variant = ClassValue | Record<string, VariantValue>;
279
+ export type Variant =
280
+ | ClassValue
281
+ | Record<string, VariantValue>
282
+ | ((value: any) => VariantValue);
288
283
  export type Variants = Record<string, Variant>;
289
284
 
290
- type ExtendedVariants<E extends AnyComponent[]> = MergeExtendedVariants<E> &
291
- MergeExtendedComputedVariants<E>;
292
-
293
285
  type NullablePartial<T> =
294
286
  T extends Record<string, any> ? { [K in keyof T]?: T[K] | null } : T | null;
295
287
 
@@ -297,7 +289,7 @@ export type ExtendableVariants<
297
289
  V extends Variants,
298
290
  E extends AnyComponent[],
299
291
  > = V & {
300
- [K in keyof ExtendedVariants<E>]?:
301
- | NullablePartial<ExtendedVariants<E>[K]>
292
+ [K in keyof MergeExtendedVariants<E>]?:
293
+ | NullablePartial<MergeExtendedVariants<E>[K]>
302
294
  | Variant;
303
295
  };
package/tests/_utils.ts CHANGED
@@ -4,7 +4,6 @@ import type {
4
4
  AnyComponent,
5
5
  CVComponent,
6
6
  ComponentResult,
7
- ComputedVariants,
8
7
  HTMLObjProps,
9
8
  HTMLProps,
10
9
  JSXProps,
@@ -86,9 +85,8 @@ export function createCVFromConfig(
86
85
  export function getModeComponent<
87
86
  M extends Mode,
88
87
  V extends Variants = {},
89
- CV extends ComputedVariants = {},
90
88
  const E extends AnyComponent[] = [],
91
- >(mode: M, component: CVComponent<V, CV, E>) {
89
+ >(mode: M, component: CVComponent<V, E>) {
92
90
  if (!mode) return component;
93
91
  return component[mode];
94
92
  }
@@ -59,7 +59,7 @@ for (const config of Object.values(CONFIGS)) {
59
59
  expect(variants).toEqual({ size: "sm" });
60
60
  });
61
61
 
62
- test("getVariants returns variants set by computed setVariants", () => {
62
+ test("getVariants returns variants set by refine setVariants", () => {
63
63
  const component = getModeComponent(
64
64
  mode,
65
65
  cv({
@@ -67,7 +67,7 @@ for (const config of Object.values(CONFIGS)) {
67
67
  size: { sm: "sm", lg: "lg" },
68
68
  color: { red: "red", blue: "blue" },
69
69
  },
70
- computed: ({ variants, setVariants }) => {
70
+ refine: ({ variants, setVariants }) => {
71
71
  if (variants.size === "lg") {
72
72
  setVariants({ color: "red" });
73
73
  }
@@ -78,7 +78,7 @@ for (const config of Object.values(CONFIGS)) {
78
78
  expect(variants).toEqual({ size: "lg", color: "red" });
79
79
  });
80
80
 
81
- test("getVariants re-runs when computed changes variants", () => {
81
+ test("getVariants re-runs when refine changes variants", () => {
82
82
  const component = getModeComponent(
83
83
  mode,
84
84
  cv({
@@ -86,7 +86,7 @@ for (const config of Object.values(CONFIGS)) {
86
86
  size: { sm: "sm", lg: "lg" },
87
87
  color: { red: "red", blue: "blue" },
88
88
  },
89
- computed: ({ variants, setVariants }) => {
89
+ refine: ({ variants, setVariants }) => {
90
90
  if (variants.size === "lg") {
91
91
  setVariants({ color: "red" });
92
92
  }
@@ -108,7 +108,7 @@ for (const config of Object.values(CONFIGS)) {
108
108
  size: { sm: "sm", lg: "lg" },
109
109
  color: { red: "red", blue: "blue" },
110
110
  },
111
- computed: ({ variants, setDefaultVariants }) => {
111
+ refine: ({ variants, setDefaultVariants }) => {
112
112
  setDefaultVariants({ color: "red" });
113
113
  if (variants.color === "red") {
114
114
  setDefaultVariants({ size: "lg" });
@@ -120,7 +120,7 @@ for (const config of Object.values(CONFIGS)) {
120
120
  expect(variants).toEqual({ size: "lg", color: "red" });
121
121
  });
122
122
 
123
- test("getVariants returns variants set by computed setDefaultVariants", () => {
123
+ test("getVariants returns variants set by refine setDefaultVariants", () => {
124
124
  const component = getModeComponent(
125
125
  mode,
126
126
  cv({
@@ -128,7 +128,7 @@ for (const config of Object.values(CONFIGS)) {
128
128
  size: { sm: "sm", lg: "lg" },
129
129
  color: { red: "red", blue: "blue" },
130
130
  },
131
- computed: ({ variants, setDefaultVariants }) => {
131
+ refine: ({ variants, setDefaultVariants }) => {
132
132
  if (variants.size === "lg") {
133
133
  setDefaultVariants({ color: "blue" });
134
134
  }
@@ -147,7 +147,7 @@ for (const config of Object.values(CONFIGS)) {
147
147
  size: { sm: "sm", lg: "lg" },
148
148
  color: { red: "red", blue: "blue" },
149
149
  },
150
- computed: ({ setDefaultVariants }) => {
150
+ refine: ({ setDefaultVariants }) => {
151
151
  setDefaultVariants({ color: "blue" });
152
152
  },
153
153
  }),
@@ -164,7 +164,7 @@ for (const config of Object.values(CONFIGS)) {
164
164
  size: { sm: "sm", lg: "lg" },
165
165
  color: { red: "red", blue: "blue" },
166
166
  },
167
- computed: ({ setVariants }) => {
167
+ refine: ({ setVariants }) => {
168
168
  setVariants({ color: "blue" });
169
169
  },
170
170
  }),
@@ -176,7 +176,7 @@ for (const config of Object.values(CONFIGS)) {
176
176
  test("getVariants picks up setDefaultVariants from extended component", () => {
177
177
  const base = cv({
178
178
  variants: { size: { sm: "sm", lg: "lg" } },
179
- computed: ({ setDefaultVariants }) => {
179
+ refine: ({ setDefaultVariants }) => {
180
180
  setDefaultVariants({ size: "lg" });
181
181
  },
182
182
  });
@@ -195,7 +195,7 @@ for (const config of Object.values(CONFIGS)) {
195
195
  test("getVariants picks up setDefaultVariants from grandparent component", () => {
196
196
  const grandparent = cv({
197
197
  variants: { size: { sm: "sm", lg: "lg" } },
198
- computed: ({ setDefaultVariants }) => {
198
+ refine: ({ setDefaultVariants }) => {
199
199
  setDefaultVariants({ size: "lg" });
200
200
  },
201
201
  });
@@ -212,11 +212,11 @@ for (const config of Object.values(CONFIGS)) {
212
212
  expect(variants).toEqual({ size: "lg", color: "red" });
213
213
  });
214
214
 
215
- test("getVariants re-runs when base component computed changes variants", () => {
215
+ test("getVariants re-runs when base component refine changes variants", () => {
216
216
  const base = cv({
217
217
  variants: { size: { sm: "sm", lg: "lg" }, active: "" },
218
218
  defaultVariants: { size: "sm" },
219
- computed: ({ variants, setVariants }) => {
219
+ refine: ({ variants, setVariants }) => {
220
220
  if (variants.active) {
221
221
  setVariants({ size: "lg" });
222
222
  }
@@ -227,7 +227,7 @@ for (const config of Object.values(CONFIGS)) {
227
227
  cv({
228
228
  extend: [base],
229
229
  variants: { color: { red: "red", blue: "blue" } },
230
- computed: ({ variants, setVariants }) => {
230
+ refine: ({ variants, setVariants }) => {
231
231
  if (variants.size === "lg") {
232
232
  setVariants({ color: "red" });
233
233
  }
@@ -246,7 +246,7 @@ for (const config of Object.values(CONFIGS)) {
246
246
  mode: { on: "on" },
247
247
  },
248
248
  defaultVariants: { size: "sm" },
249
- computed: ({ variants, setVariants, setDefaultVariants }) => {
249
+ refine: ({ variants, setVariants, setDefaultVariants }) => {
250
250
  if (variants.active) {
251
251
  setVariants({ mode: "on" });
252
252
  }
@@ -266,7 +266,7 @@ for (const config of Object.values(CONFIGS)) {
266
266
  cv({
267
267
  variants: { size: { sm: "sm", lg: "lg" } },
268
268
  defaultVariants: { size: "sm" },
269
- computed: ({ setVariants }) => {
269
+ refine: ({ setVariants }) => {
270
270
  setVariants({ size: "lg" });
271
271
  setVariants({ size: "sm" });
272
272
  },
@@ -279,7 +279,7 @@ for (const config of Object.values(CONFIGS)) {
279
279
  test("getVariants child setVariants keeps overriding base setDefaultVariants across re-runs", () => {
280
280
  const base = cv({
281
281
  variants: { color: { red: "red", blue: "blue" } },
282
- computed: ({ setDefaultVariants }) => {
282
+ refine: ({ setDefaultVariants }) => {
283
283
  setDefaultVariants({ color: "blue" });
284
284
  },
285
285
  });
@@ -289,7 +289,7 @@ for (const config of Object.values(CONFIGS)) {
289
289
  extend: [base],
290
290
  variants: { size: { sm: "sm", lg: "lg" } },
291
291
  defaultVariants: { size: "sm" },
292
- computed: ({ variants, setVariants }) => {
292
+ refine: ({ variants, setVariants }) => {
293
293
  if (variants.size === "sm") {
294
294
  setVariants({ color: "red" });
295
295
  }
@@ -303,7 +303,7 @@ for (const config of Object.values(CONFIGS)) {
303
303
  test("getVariants setVariants sticks across re-runs", () => {
304
304
  const base = cv({
305
305
  variants: { color: { red: "red", blue: "blue" } },
306
- computed: ({ setDefaultVariants }) => {
306
+ refine: ({ setDefaultVariants }) => {
307
307
  setDefaultVariants({ color: "blue" });
308
308
  },
309
309
  });
@@ -312,7 +312,7 @@ for (const config of Object.values(CONFIGS)) {
312
312
  cv({
313
313
  extend: [base],
314
314
  variants: { color: { red: "red", blue: "blue" }, done: "" },
315
- computed: ({ variants, setVariants }) => {
315
+ refine: ({ variants, setVariants }) => {
316
316
  if (!variants.done) {
317
317
  setVariants({ color: "red", done: true });
318
318
  }
@@ -330,7 +330,7 @@ for (const config of Object.values(CONFIGS)) {
330
330
  active: "",
331
331
  mode: { on: "on" },
332
332
  },
333
- computed: ({ variants, setVariants, setDefaultVariants }) => {
333
+ refine: ({ variants, setVariants, setDefaultVariants }) => {
334
334
  if (variants.active) {
335
335
  setVariants({ mode: "on" });
336
336
  }
@@ -350,13 +350,13 @@ for (const config of Object.values(CONFIGS)) {
350
350
  test("getVariants setVariants from earlier extends overrides setDefaultVariants from later extends", () => {
351
351
  const first = cv({
352
352
  variants: { color: { red: "first-red", blue: "first-blue" } },
353
- computed: ({ setVariants }) => {
353
+ refine: ({ setVariants }) => {
354
354
  setVariants({ color: "red" });
355
355
  },
356
356
  });
357
357
  const second = cv({
358
358
  variants: { color: { red: "second-red", blue: "second-blue" } },
359
- computed: ({ setDefaultVariants }) => {
359
+ refine: ({ setDefaultVariants }) => {
360
360
  setDefaultVariants({ color: "blue" });
361
361
  },
362
362
  });
@@ -368,13 +368,13 @@ for (const config of Object.values(CONFIGS)) {
368
368
  test("getVariants setDefaultVariants from later extends overrides setDefaultVariants from earlier extends", () => {
369
369
  const first = cv({
370
370
  variants: { color: { red: "first-red", blue: "first-blue" } },
371
- computed: ({ setDefaultVariants }) => {
371
+ refine: ({ setDefaultVariants }) => {
372
372
  setDefaultVariants({ color: "red" });
373
373
  },
374
374
  });
375
375
  const second = cv({
376
376
  variants: { color: { red: "second-red", blue: "second-blue" } },
377
- computed: ({ setDefaultVariants }) => {
377
+ refine: ({ setDefaultVariants }) => {
378
378
  setDefaultVariants({ color: "blue" });
379
379
  },
380
380
  });
@@ -386,7 +386,7 @@ for (const config of Object.values(CONFIGS)) {
386
386
  test("getVariants setDefaultVariants does not override stable setVariants on later passes", () => {
387
387
  const base = cv({
388
388
  variants: { color: { red: "base-red", blue: "base-blue" } },
389
- computed: ({ setVariants }) => {
389
+ refine: ({ setVariants }) => {
390
390
  setVariants({ color: "red" });
391
391
  },
392
392
  });
@@ -395,7 +395,7 @@ for (const config of Object.values(CONFIGS)) {
395
395
  cv({
396
396
  extend: [base],
397
397
  variants: { color: { red: "child-red", blue: "child-blue" } },
398
- computed: ({ variants, setDefaultVariants }) => {
398
+ refine: ({ variants, setDefaultVariants }) => {
399
399
  if (variants.color === "red") {
400
400
  setDefaultVariants({ color: "blue" });
401
401
  }
@@ -414,7 +414,7 @@ for (const config of Object.values(CONFIGS)) {
414
414
  color: { red: "red", blue: "blue" },
415
415
  done: "",
416
416
  },
417
- computed: ({ variants, setVariants, setDefaultVariants }) => {
417
+ refine: ({ variants, setVariants, setDefaultVariants }) => {
418
418
  if (!variants.done) {
419
419
  setVariants({ color: "red", done: true });
420
420
  }
@@ -144,7 +144,7 @@ for (const config of Object.values(CONFIGS)) {
144
144
  });
145
145
  });
146
146
 
147
- test("extend disabled variant value with computed setDefaultVariants", () => {
147
+ test("extend disabled variant value with refine setDefaultVariants", () => {
148
148
  const base = cv({
149
149
  variants: {
150
150
  size: {
@@ -158,7 +158,7 @@ for (const config of Object.values(CONFIGS)) {
158
158
  cv({
159
159
  extend: [base],
160
160
  variants: { size: { sm: null } },
161
- computed: ({ setDefaultVariants }) => {
161
+ refine: ({ setDefaultVariants }) => {
162
162
  setDefaultVariants({ size: "lg" });
163
163
  },
164
164
  }),
@@ -173,7 +173,7 @@ for (const config of Object.values(CONFIGS)) {
173
173
  cv({
174
174
  extend: [base],
175
175
  variants: { size: { sm: null } },
176
- computed: ({ setDefaultVariants }) => {
176
+ refine: ({ setDefaultVariants }) => {
177
177
  setDefaultVariants({
178
178
  // @ts-expect-error disabled variant value cannot be set
179
179
  size:
@@ -186,7 +186,7 @@ for (const config of Object.values(CONFIGS)) {
186
186
  expect(getStyleClass(invalidComponent())).toEqual({ class: "" });
187
187
  });
188
188
 
189
- test("extend disabled variant value with computed setVariants", () => {
189
+ test("extend disabled variant value with refine setVariants", () => {
190
190
  const base = cv({
191
191
  variants: {
192
192
  size: {
@@ -200,7 +200,7 @@ for (const config of Object.values(CONFIGS)) {
200
200
  cv({
201
201
  extend: [base],
202
202
  variants: { size: { sm: null } },
203
- computed: ({ setVariants }) => {
203
+ refine: ({ setVariants }) => {
204
204
  setVariants({ size: "lg" });
205
205
  },
206
206
  }),
@@ -215,7 +215,7 @@ for (const config of Object.values(CONFIGS)) {
215
215
  cv({
216
216
  extend: [base],
217
217
  variants: { size: { sm: null } },
218
- computed: ({ setVariants }) => {
218
+ refine: ({ setVariants }) => {
219
219
  setVariants({
220
220
  // @ts-expect-error disabled variant value cannot be set
221
221
  size: