clava 0.1.1 → 0.1.2
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 +6 -0
- package/dist/index.d.ts +22 -9
- package/dist/index.js +39 -18
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +74 -46
- package/src/test-react.ts +3 -3
- package/src/test-solid.ts +1 -1
- package/src/test.ts +170 -303
- package/src/types.ts +130 -45
- 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
|
-
Component,
|
|
7
|
-
StyleProps,
|
|
8
4
|
ClassValue,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
Component,
|
|
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,9 +32,6 @@ import {
|
|
|
31
32
|
styleValueToJSXStyle,
|
|
32
33
|
} from "./utils.ts";
|
|
33
34
|
|
|
34
|
-
const MODES = ["jsx", "html", "htmlObj"] as const;
|
|
35
|
-
type Mode = (typeof MODES)[number];
|
|
36
|
-
|
|
37
35
|
export type { ClassValue, StyleValue, StyleClassValue };
|
|
38
36
|
|
|
39
37
|
export type VariantProps<T extends Pick<AnyComponent, "getVariants">> =
|
|
@@ -122,7 +120,7 @@ function collectVariantKeys(
|
|
|
122
120
|
// Collect from extended components
|
|
123
121
|
if (config.extend) {
|
|
124
122
|
for (const ext of config.extend) {
|
|
125
|
-
for (const key of ext.
|
|
123
|
+
for (const key of ext.variantKeys) {
|
|
126
124
|
keys.add(key as string);
|
|
127
125
|
}
|
|
128
126
|
}
|
|
@@ -366,46 +364,67 @@ function processComputed(
|
|
|
366
364
|
return { classes, style, updatedVariants };
|
|
367
365
|
}
|
|
368
366
|
|
|
369
|
-
|
|
370
|
-
* Normalizes a key source (array or component) to an object with keys and defaults.
|
|
371
|
-
*/
|
|
372
|
-
function normalizeKeySource(source: unknown): {
|
|
367
|
+
interface NormalizedSource {
|
|
373
368
|
keys: string[];
|
|
369
|
+
variantKeys: string[];
|
|
374
370
|
defaults: Record<string, unknown>;
|
|
375
|
-
|
|
371
|
+
isComponent: boolean;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Normalizes a key source (array or component) to an object with keys, variantKeys, defaults, and isComponent flag.
|
|
376
|
+
*/
|
|
377
|
+
function normalizeKeySource(source: unknown): NormalizedSource {
|
|
376
378
|
if (Array.isArray(source)) {
|
|
377
|
-
return {
|
|
379
|
+
return {
|
|
380
|
+
keys: source as string[],
|
|
381
|
+
variantKeys: source as string[],
|
|
382
|
+
defaults: {},
|
|
383
|
+
isComponent: false,
|
|
384
|
+
};
|
|
378
385
|
}
|
|
379
|
-
// Components are functions with keys
|
|
386
|
+
// Components are functions with keys and variantKeys properties
|
|
380
387
|
if (
|
|
381
388
|
source &&
|
|
382
389
|
(typeof source === "object" || typeof source === "function") &&
|
|
383
|
-
"keys" in source
|
|
390
|
+
"keys" in source &&
|
|
391
|
+
"variantKeys" in source
|
|
384
392
|
) {
|
|
385
393
|
const keys = [...(source as { keys: string[] }).keys] as string[];
|
|
394
|
+
const variantKeys = [
|
|
395
|
+
...(source as { variantKeys: string[] }).variantKeys,
|
|
396
|
+
] as string[];
|
|
386
397
|
const defaults =
|
|
387
398
|
"getVariants" in source
|
|
388
399
|
? (
|
|
389
400
|
source as { getVariants: () => Record<string, unknown> }
|
|
390
401
|
).getVariants()
|
|
391
402
|
: {};
|
|
392
|
-
return { keys, defaults };
|
|
403
|
+
return { keys, variantKeys, defaults, isComponent: true };
|
|
393
404
|
}
|
|
394
|
-
return { keys: [], defaults: {} };
|
|
405
|
+
return { keys: [], variantKeys: [], defaults: {}, isComponent: false };
|
|
395
406
|
}
|
|
396
407
|
|
|
397
408
|
/**
|
|
398
409
|
* Splits props into multiple groups based on key sources.
|
|
410
|
+
* Only the first component claims styling props (class/className/style).
|
|
411
|
+
* Subsequent components only receive variant props.
|
|
412
|
+
* Arrays always receive their listed keys but don't claim styling props.
|
|
399
413
|
*/
|
|
400
414
|
function splitPropsImpl(
|
|
401
415
|
selfKeys: string[],
|
|
416
|
+
selfVariantKeys: string[],
|
|
402
417
|
selfDefaults: Record<string, unknown>,
|
|
418
|
+
selfIsComponent: boolean,
|
|
403
419
|
props: Record<string, unknown>,
|
|
404
|
-
sources:
|
|
420
|
+
sources: NormalizedSource[],
|
|
405
421
|
): Record<string, unknown>[] {
|
|
406
422
|
const allUsedKeys = new Set<string>(selfKeys);
|
|
407
423
|
const results: Record<string, unknown>[] = [];
|
|
408
424
|
|
|
425
|
+
// Track if styling has been claimed by a component
|
|
426
|
+
let stylingClaimed = selfIsComponent;
|
|
427
|
+
|
|
409
428
|
// Self result with defaults
|
|
410
429
|
const selfResult: Record<string, unknown> = {};
|
|
411
430
|
// First apply defaults
|
|
@@ -425,20 +444,33 @@ function splitPropsImpl(
|
|
|
425
444
|
// Process each source
|
|
426
445
|
for (const source of sources) {
|
|
427
446
|
const sourceResult: Record<string, unknown> = {};
|
|
428
|
-
|
|
447
|
+
|
|
448
|
+
// Determine which keys this source should use
|
|
449
|
+
// Components use variantKeys if styling has already been claimed
|
|
450
|
+
// Arrays always use their listed keys
|
|
451
|
+
const effectiveKeys =
|
|
452
|
+
source.isComponent && stylingClaimed ? source.variantKeys : source.keys;
|
|
453
|
+
|
|
454
|
+
// First apply defaults (only for variant keys if component and styling claimed)
|
|
429
455
|
for (const [key, value] of Object.entries(source.defaults)) {
|
|
430
|
-
if (
|
|
456
|
+
if (effectiveKeys.includes(key)) {
|
|
431
457
|
sourceResult[key] = value;
|
|
432
458
|
}
|
|
433
459
|
}
|
|
460
|
+
|
|
434
461
|
// Then override with props
|
|
435
|
-
for (const key of
|
|
462
|
+
for (const key of effectiveKeys) {
|
|
436
463
|
allUsedKeys.add(key);
|
|
437
464
|
if (key in props) {
|
|
438
465
|
sourceResult[key] = props[key];
|
|
439
466
|
}
|
|
440
467
|
}
|
|
441
468
|
results.push(sourceResult);
|
|
469
|
+
|
|
470
|
+
// If this is a component that hasn't claimed styling yet, mark styling as claimed
|
|
471
|
+
if (source.isComponent && !stylingClaimed) {
|
|
472
|
+
stylingClaimed = true;
|
|
473
|
+
}
|
|
442
474
|
}
|
|
443
475
|
|
|
444
476
|
// Rest - keys not used by anyone
|
|
@@ -456,6 +488,9 @@ function splitPropsImpl(
|
|
|
456
488
|
/**
|
|
457
489
|
* Splits props into multiple groups based on key sources.
|
|
458
490
|
* Each source gets its own result object containing all its matching keys.
|
|
491
|
+
* The first component source claims styling props (class/className/style).
|
|
492
|
+
* Subsequent components only receive variant props.
|
|
493
|
+
* Arrays receive their listed keys but don't claim styling props.
|
|
459
494
|
* The last element is always the "rest" containing keys not claimed by any source.
|
|
460
495
|
*
|
|
461
496
|
* @example
|
|
@@ -463,8 +498,10 @@ function splitPropsImpl(
|
|
|
463
498
|
* const [buttonProps, inputProps, rest] = splitProps(
|
|
464
499
|
* props,
|
|
465
500
|
* buttonComponent,
|
|
466
|
-
* inputComponent
|
|
501
|
+
* inputComponent,
|
|
467
502
|
* );
|
|
503
|
+
* // buttonProps has class/style + button variants
|
|
504
|
+
* // inputProps has only input variants (no class/style)
|
|
468
505
|
* ```
|
|
469
506
|
*/
|
|
470
507
|
export const splitProps: SplitPropsFunction = ((
|
|
@@ -476,7 +513,9 @@ export const splitProps: SplitPropsFunction = ((
|
|
|
476
513
|
const normalizedSources = sources.map(normalizeKeySource);
|
|
477
514
|
return splitPropsImpl(
|
|
478
515
|
normalizedSource1.keys,
|
|
516
|
+
normalizedSource1.variantKeys,
|
|
479
517
|
normalizedSource1.defaults,
|
|
518
|
+
normalizedSource1.isComponent,
|
|
480
519
|
props,
|
|
481
520
|
normalizedSources,
|
|
482
521
|
);
|
|
@@ -501,9 +540,6 @@ export function create<M extends Mode = "jsx">({
|
|
|
501
540
|
config as CVConfig<Variants, ComputedVariants, AnyComponent[]>,
|
|
502
541
|
);
|
|
503
542
|
|
|
504
|
-
const getClassPropertyName = (mode: Mode) =>
|
|
505
|
-
mode === "jsx" ? "className" : "class";
|
|
506
|
-
|
|
507
543
|
const getPropsKeys = (mode: Mode) => [
|
|
508
544
|
getClassPropertyName(mode),
|
|
509
545
|
"style",
|
|
@@ -642,17 +678,9 @@ export function create<M extends Mode = "jsx">({
|
|
|
642
678
|
|
|
643
679
|
component.keys = propsKeys as (keyof MergedVariants | keyof R)[];
|
|
644
680
|
|
|
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>;
|
|
681
|
+
component.variantKeys = variantKeys as (keyof MergedVariants)[];
|
|
682
|
+
|
|
683
|
+
component.propKeys = propsKeys as (keyof MergedVariants | keyof R)[];
|
|
656
684
|
|
|
657
685
|
// Compute base class (without variants) - includes extended base classes
|
|
658
686
|
const extendedBaseClasses: ClassValue[] = [];
|
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" });
|