clava 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/index.d.ts +29 -16
- package/dist/index.js +39 -18
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +85 -49
- package/src/test-react.ts +3 -3
- package/src/test-solid.ts +1 -1
- package/src/test.ts +171 -304
- package/src/types.ts +134 -49
- package/src/utils.ts +15 -2
package/src/index.ts
CHANGED
|
@@ -1,27 +1,28 @@
|
|
|
1
1
|
import clsx, { type ClassValue as ClsxClassValue } from "clsx";
|
|
2
2
|
import type {
|
|
3
|
-
Variants,
|
|
4
|
-
ComputedVariants,
|
|
5
3
|
AnyComponent,
|
|
6
|
-
|
|
7
|
-
StyleProps,
|
|
4
|
+
CVComponent,
|
|
8
5
|
ClassValue,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
VariantValues,
|
|
6
|
+
ComponentProps,
|
|
7
|
+
ComponentResult,
|
|
12
8
|
Computed,
|
|
9
|
+
ComputedVariants,
|
|
13
10
|
ExtendableVariants,
|
|
11
|
+
HTMLObjProps,
|
|
12
|
+
HTMLProps,
|
|
13
|
+
JSXProps,
|
|
14
14
|
MergeVariants,
|
|
15
15
|
ModalComponent,
|
|
16
|
-
ComponentResult,
|
|
17
|
-
JSXProps,
|
|
18
|
-
HTMLProps,
|
|
19
|
-
HTMLObjProps,
|
|
20
|
-
OnlyVariantsComponent,
|
|
21
|
-
ComponentProps,
|
|
22
16
|
SplitPropsFunction,
|
|
17
|
+
StyleClassValue,
|
|
18
|
+
StyleProps,
|
|
19
|
+
StyleValue,
|
|
20
|
+
VariantValues,
|
|
21
|
+
Variants,
|
|
23
22
|
} from "./types.ts";
|
|
24
23
|
import {
|
|
24
|
+
type Mode,
|
|
25
|
+
getClassPropertyName,
|
|
25
26
|
htmlObjStyleToStyleValue,
|
|
26
27
|
htmlStyleToStyleValue,
|
|
27
28
|
isHTMLObjStyle,
|
|
@@ -31,10 +32,15 @@ import {
|
|
|
31
32
|
styleValueToJSXStyle,
|
|
32
33
|
} from "./utils.ts";
|
|
33
34
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
export type {
|
|
36
|
+
ClassValue,
|
|
37
|
+
StyleValue,
|
|
38
|
+
StyleClassValue,
|
|
39
|
+
JSXProps,
|
|
40
|
+
HTMLProps,
|
|
41
|
+
HTMLObjProps,
|
|
42
|
+
CVComponent,
|
|
43
|
+
};
|
|
38
44
|
|
|
39
45
|
export type VariantProps<T extends Pick<AnyComponent, "getVariants">> =
|
|
40
46
|
ReturnType<T["getVariants"]>;
|
|
@@ -122,7 +128,7 @@ function collectVariantKeys(
|
|
|
122
128
|
// Collect from extended components
|
|
123
129
|
if (config.extend) {
|
|
124
130
|
for (const ext of config.extend) {
|
|
125
|
-
for (const key of ext.
|
|
131
|
+
for (const key of ext.variantKeys) {
|
|
126
132
|
keys.add(key as string);
|
|
127
133
|
}
|
|
128
134
|
}
|
|
@@ -366,46 +372,67 @@ function processComputed(
|
|
|
366
372
|
return { classes, style, updatedVariants };
|
|
367
373
|
}
|
|
368
374
|
|
|
369
|
-
|
|
370
|
-
* Normalizes a key source (array or component) to an object with keys and defaults.
|
|
371
|
-
*/
|
|
372
|
-
function normalizeKeySource(source: unknown): {
|
|
375
|
+
interface NormalizedSource {
|
|
373
376
|
keys: string[];
|
|
377
|
+
variantKeys: string[];
|
|
374
378
|
defaults: Record<string, unknown>;
|
|
375
|
-
|
|
379
|
+
isComponent: boolean;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Normalizes a key source (array or component) to an object with keys, variantKeys, defaults, and isComponent flag.
|
|
384
|
+
*/
|
|
385
|
+
function normalizeKeySource(source: unknown): NormalizedSource {
|
|
376
386
|
if (Array.isArray(source)) {
|
|
377
|
-
return {
|
|
387
|
+
return {
|
|
388
|
+
keys: source as string[],
|
|
389
|
+
variantKeys: source as string[],
|
|
390
|
+
defaults: {},
|
|
391
|
+
isComponent: false,
|
|
392
|
+
};
|
|
378
393
|
}
|
|
379
|
-
// Components are functions with keys
|
|
394
|
+
// Components are functions with keys and variantKeys properties
|
|
380
395
|
if (
|
|
381
396
|
source &&
|
|
382
397
|
(typeof source === "object" || typeof source === "function") &&
|
|
383
|
-
"keys" in source
|
|
398
|
+
"keys" in source &&
|
|
399
|
+
"variantKeys" in source
|
|
384
400
|
) {
|
|
385
401
|
const keys = [...(source as { keys: string[] }).keys] as string[];
|
|
402
|
+
const variantKeys = [
|
|
403
|
+
...(source as { variantKeys: string[] }).variantKeys,
|
|
404
|
+
] as string[];
|
|
386
405
|
const defaults =
|
|
387
406
|
"getVariants" in source
|
|
388
407
|
? (
|
|
389
408
|
source as { getVariants: () => Record<string, unknown> }
|
|
390
409
|
).getVariants()
|
|
391
410
|
: {};
|
|
392
|
-
return { keys, defaults };
|
|
411
|
+
return { keys, variantKeys, defaults, isComponent: true };
|
|
393
412
|
}
|
|
394
|
-
return { keys: [], defaults: {} };
|
|
413
|
+
return { keys: [], variantKeys: [], defaults: {}, isComponent: false };
|
|
395
414
|
}
|
|
396
415
|
|
|
397
416
|
/**
|
|
398
417
|
* Splits props into multiple groups based on key sources.
|
|
418
|
+
* Only the first component claims styling props (class/className/style).
|
|
419
|
+
* Subsequent components only receive variant props.
|
|
420
|
+
* Arrays always receive their listed keys but don't claim styling props.
|
|
399
421
|
*/
|
|
400
422
|
function splitPropsImpl(
|
|
401
423
|
selfKeys: string[],
|
|
424
|
+
selfVariantKeys: string[],
|
|
402
425
|
selfDefaults: Record<string, unknown>,
|
|
426
|
+
selfIsComponent: boolean,
|
|
403
427
|
props: Record<string, unknown>,
|
|
404
|
-
sources:
|
|
428
|
+
sources: NormalizedSource[],
|
|
405
429
|
): Record<string, unknown>[] {
|
|
406
430
|
const allUsedKeys = new Set<string>(selfKeys);
|
|
407
431
|
const results: Record<string, unknown>[] = [];
|
|
408
432
|
|
|
433
|
+
// Track if styling has been claimed by a component
|
|
434
|
+
let stylingClaimed = selfIsComponent;
|
|
435
|
+
|
|
409
436
|
// Self result with defaults
|
|
410
437
|
const selfResult: Record<string, unknown> = {};
|
|
411
438
|
// First apply defaults
|
|
@@ -425,20 +452,33 @@ function splitPropsImpl(
|
|
|
425
452
|
// Process each source
|
|
426
453
|
for (const source of sources) {
|
|
427
454
|
const sourceResult: Record<string, unknown> = {};
|
|
428
|
-
|
|
455
|
+
|
|
456
|
+
// Determine which keys this source should use
|
|
457
|
+
// Components use variantKeys if styling has already been claimed
|
|
458
|
+
// Arrays always use their listed keys
|
|
459
|
+
const effectiveKeys =
|
|
460
|
+
source.isComponent && stylingClaimed ? source.variantKeys : source.keys;
|
|
461
|
+
|
|
462
|
+
// First apply defaults (only for variant keys if component and styling claimed)
|
|
429
463
|
for (const [key, value] of Object.entries(source.defaults)) {
|
|
430
|
-
if (
|
|
464
|
+
if (effectiveKeys.includes(key)) {
|
|
431
465
|
sourceResult[key] = value;
|
|
432
466
|
}
|
|
433
467
|
}
|
|
468
|
+
|
|
434
469
|
// Then override with props
|
|
435
|
-
for (const key of
|
|
470
|
+
for (const key of effectiveKeys) {
|
|
436
471
|
allUsedKeys.add(key);
|
|
437
472
|
if (key in props) {
|
|
438
473
|
sourceResult[key] = props[key];
|
|
439
474
|
}
|
|
440
475
|
}
|
|
441
476
|
results.push(sourceResult);
|
|
477
|
+
|
|
478
|
+
// If this is a component that hasn't claimed styling yet, mark styling as claimed
|
|
479
|
+
if (source.isComponent && !stylingClaimed) {
|
|
480
|
+
stylingClaimed = true;
|
|
481
|
+
}
|
|
442
482
|
}
|
|
443
483
|
|
|
444
484
|
// Rest - keys not used by anyone
|
|
@@ -456,6 +496,9 @@ function splitPropsImpl(
|
|
|
456
496
|
/**
|
|
457
497
|
* Splits props into multiple groups based on key sources.
|
|
458
498
|
* Each source gets its own result object containing all its matching keys.
|
|
499
|
+
* The first component source claims styling props (class/className/style).
|
|
500
|
+
* Subsequent components only receive variant props.
|
|
501
|
+
* Arrays receive their listed keys but don't claim styling props.
|
|
459
502
|
* The last element is always the "rest" containing keys not claimed by any source.
|
|
460
503
|
*
|
|
461
504
|
* @example
|
|
@@ -463,8 +506,10 @@ function splitPropsImpl(
|
|
|
463
506
|
* const [buttonProps, inputProps, rest] = splitProps(
|
|
464
507
|
* props,
|
|
465
508
|
* buttonComponent,
|
|
466
|
-
* inputComponent
|
|
509
|
+
* inputComponent,
|
|
467
510
|
* );
|
|
511
|
+
* // buttonProps has class/style + button variants
|
|
512
|
+
* // inputProps has only input variants (no class/style)
|
|
468
513
|
* ```
|
|
469
514
|
*/
|
|
470
515
|
export const splitProps: SplitPropsFunction = ((
|
|
@@ -476,7 +521,9 @@ export const splitProps: SplitPropsFunction = ((
|
|
|
476
521
|
const normalizedSources = sources.map(normalizeKeySource);
|
|
477
522
|
return splitPropsImpl(
|
|
478
523
|
normalizedSource1.keys,
|
|
524
|
+
normalizedSource1.variantKeys,
|
|
479
525
|
normalizedSource1.defaults,
|
|
526
|
+
normalizedSource1.isComponent,
|
|
480
527
|
props,
|
|
481
528
|
normalizedSources,
|
|
482
529
|
);
|
|
@@ -494,16 +541,13 @@ export function create<M extends Mode = "jsx">({
|
|
|
494
541
|
const E extends AnyComponent[] = [],
|
|
495
542
|
>(
|
|
496
543
|
config: CVConfig<V, CV, E> = {},
|
|
497
|
-
):
|
|
544
|
+
): CVComponent<V, CV, E, StyleProps[M]> => {
|
|
498
545
|
type MergedVariants = MergeVariants<V, CV, E>;
|
|
499
546
|
|
|
500
547
|
const variantKeys = collectVariantKeys(
|
|
501
548
|
config as CVConfig<Variants, ComputedVariants, AnyComponent[]>,
|
|
502
549
|
);
|
|
503
550
|
|
|
504
|
-
const getClassPropertyName = (mode: Mode) =>
|
|
505
|
-
mode === "jsx" ? "className" : "class";
|
|
506
|
-
|
|
507
551
|
const getPropsKeys = (mode: Mode) => [
|
|
508
552
|
getClassPropertyName(mode),
|
|
509
553
|
"style",
|
|
@@ -642,17 +686,9 @@ export function create<M extends Mode = "jsx">({
|
|
|
642
686
|
|
|
643
687
|
component.keys = propsKeys as (keyof MergedVariants | keyof R)[];
|
|
644
688
|
|
|
645
|
-
component.
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
): VariantValues<MergedVariants> => {
|
|
649
|
-
return resolveVariants(
|
|
650
|
-
config as CVConfig<Variants, ComputedVariants, AnyComponent[]>,
|
|
651
|
-
variants as VariantValues<Record<string, unknown>>,
|
|
652
|
-
) as VariantValues<MergedVariants>;
|
|
653
|
-
},
|
|
654
|
-
keys: variantKeys as (keyof MergedVariants)[],
|
|
655
|
-
} as OnlyVariantsComponent<MergedVariants>;
|
|
689
|
+
component.variantKeys = variantKeys as (keyof MergedVariants)[];
|
|
690
|
+
|
|
691
|
+
component.propKeys = propsKeys as (keyof MergedVariants | keyof R)[];
|
|
656
692
|
|
|
657
693
|
// Compute base class (without variants) - includes extended base classes
|
|
658
694
|
const extendedBaseClasses: ClassValue[] = [];
|
|
@@ -678,7 +714,7 @@ export function create<M extends Mode = "jsx">({
|
|
|
678
714
|
const htmlObjComponent = createModalComponent<HTMLObjProps>("htmlObj");
|
|
679
715
|
|
|
680
716
|
// Build the final component
|
|
681
|
-
const component = defaultComponent as
|
|
717
|
+
const component = defaultComponent as CVComponent<V, CV, E, StyleProps[M]>;
|
|
682
718
|
component.jsx = jsxComponent;
|
|
683
719
|
component.html = htmlComponent;
|
|
684
720
|
component.htmlObj = htmlObjComponent;
|
package/src/test-react.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { CSSProperties, ComponentProps } from "react";
|
|
2
2
|
import { expect, expectTypeOf, test } from "vitest";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import type { JSXProps } from "./types.ts";
|
|
4
|
+
import { type VariantProps, cv, splitProps } from "./index.ts";
|
|
5
5
|
|
|
6
6
|
test("splitProps", () => {
|
|
7
7
|
const component = cv({ variants: { size: { sm: "sm", md: "md" } } });
|
package/src/test-solid.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ComponentProps, JSX } from "solid-js";
|
|
2
2
|
import { expect, expectTypeOf, test } from "vitest";
|
|
3
|
-
import { create, splitProps
|
|
3
|
+
import { type VariantProps, create, splitProps } from "./index.ts";
|
|
4
4
|
import { type HTMLObjProps } from "./types.ts";
|
|
5
5
|
|
|
6
6
|
const { cv } = create({ defaultMode: "htmlObj" });
|