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/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,
4
+ CVComponent,
8
5
  ClassValue,
9
- StyleValue,
10
- StyleClassValue,
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
- const MODES = ["jsx", "html", "htmlObj"] as const;
35
- type Mode = (typeof MODES)[number];
36
-
37
- export type { ClassValue, StyleValue, StyleClassValue };
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.onlyVariants.keys) {
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 { keys: source as string[], defaults: {} };
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 property, onlyVariants are objects 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: Array<{ keys: string[]; defaults: Record<string, unknown> }>,
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
- // First apply defaults
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 (source.keys.includes(key)) {
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 source.keys) {
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.onlyVariants,
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
- ): Component<V, CV, E, StyleProps[M]> => {
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.onlyVariants = {
646
- getVariants: (
647
- variants?: VariantValues<MergedVariants>,
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 Component<V, CV, E, StyleProps[M]>;
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 { ComponentProps, CSSProperties } from "react";
1
+ import type { CSSProperties, ComponentProps } from "react";
2
2
  import { expect, expectTypeOf, test } from "vitest";
3
- import { cv, splitProps, type VariantProps } from "./index.ts";
4
- import { JSXProps } from "./types.ts";
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, type VariantProps } from "./index.ts";
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" });