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/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
- StyleValue,
10
- StyleClassValue,
11
- VariantValues,
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.onlyVariants.keys) {
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 { keys: source as string[], defaults: {} };
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 property, onlyVariants are objects 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: Array<{ keys: string[]; defaults: Record<string, unknown> }>,
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
- // First apply defaults
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 (source.keys.includes(key)) {
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 source.keys) {
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.onlyVariants,
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.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>;
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 { 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" });