praxis-kit 5.0.0 → 6.0.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.
@@ -358,6 +358,14 @@ function createClassPipeline(resolved) {
358
358
  };
359
359
  }
360
360
 
361
+ // ../../lib/pipeline-kit/src/core/compose-pipelines.ts
362
+ function composePipelines(first, second) {
363
+ return (...args) => second(first(...args));
364
+ }
365
+
366
+ // ../../lib/tailwind/src/create-tailwind-pipeline.ts
367
+ import { ConsoleReporter, DefaultPolicy, Diagnostics, Severity } from "../_shared/diagnostics.js";
368
+
361
369
  // ../../lib/tailwind/src/class-builder.ts
362
370
  var ClassBuilder = class {
363
371
  build(tokens) {
@@ -371,6 +379,7 @@ var ClassBuilder = class {
371
379
  }
372
380
  case "utility":
373
381
  case "gap":
382
+ case "shared":
374
383
  case "conditional": {
375
384
  normal.push(token.raw);
376
385
  break;
@@ -444,6 +453,16 @@ var CONDITIONALS = {
444
453
  "[&.flex": "flex",
445
454
  "[&.grid": "grid"
446
455
  };
456
+ var SHARED_PREFIXES = [
457
+ /^order/,
458
+ /^justify-(?!items-|self-)/,
459
+ /^content-/,
460
+ /^items-/,
461
+ /^self-/,
462
+ /^place-content-/,
463
+ /^place-items-/,
464
+ /^place-self-/
465
+ ];
447
466
  var ClassClassifier = class _ClassClassifier {
448
467
  static #getBaseUtility(token) {
449
468
  let depth = 0;
@@ -476,23 +495,16 @@ var ClassClassifier = class _ClassClassifier {
476
495
  }
477
496
  );
478
497
  if (conditional !== null) return conditional;
479
- return base === "gap" || base.startsWith("gap-") ? {
480
- kind: "gap",
481
- raw: token
482
- } : {
483
- kind: "utility",
484
- base,
485
- raw: token
486
- };
498
+ if (base === "gap" || base.startsWith("gap-")) {
499
+ return { kind: "gap", raw: token };
500
+ }
501
+ if (SHARED_PREFIXES.some((rule) => rule.test(base))) {
502
+ return { kind: "shared", raw: token };
503
+ }
504
+ return { kind: "utility", base, raw: token };
487
505
  }
488
506
  };
489
507
 
490
- // ../../lib/tailwind/src/dependency-rules.ts
491
- var defaultDependencyRules = {
492
- flex: [/^flex-/, /^grow/, /^shrink/, /^basis-/],
493
- grid: [/^grid-/, /^col-/, /^row-/, /^auto-cols-/, /^auto-rows-/]
494
- };
495
-
496
508
  // ../../lib/tailwind/src/dependency-evaluator.ts
497
509
  var DependencyEvaluator = class {
498
510
  constructor(rules) {
@@ -513,7 +525,8 @@ var DependencyEvaluator = class {
513
525
  (layout) => this.rules[layout].some((rule) => rule.test(token.base)) ? state.family === layout : null
514
526
  ) ?? true;
515
527
  }
516
- case "gap": {
528
+ case "gap":
529
+ case "shared": {
517
530
  return state.family !== "none";
518
531
  }
519
532
  default:
@@ -522,26 +535,22 @@ var DependencyEvaluator = class {
522
535
  }
523
536
  };
524
537
 
525
- // ../../lib/tailwind/src/layout-state.ts
526
- var LayoutState = class {
527
- #mode;
528
- #family;
529
- constructor(mode) {
530
- this.#mode = mode;
531
- this.#family = mode === "none" ? "none" : LAYOUT_FAMILY_MAP[mode];
532
- Object.freeze(this);
533
- }
534
- get mode() {
535
- return this.#mode;
536
- }
537
- get family() {
538
- return this.#family;
539
- }
538
+ // ../../lib/tailwind/src/dependency-rules.ts
539
+ var defaultDependencyRules = {
540
+ flex: [/^flex-/, /^grow/, /^shrink/, /^basis-/],
541
+ grid: [
542
+ /^grid-/,
543
+ /^col-/,
544
+ /^row-/,
545
+ /^auto-cols-/,
546
+ /^auto-rows-/,
547
+ // justify-items/-self are no-ops on flex containers per the CSS box
548
+ // alignment spec (flex items ignore them), so treat as grid-only.
549
+ /^justify-items-/,
550
+ /^justify-self-/
551
+ ]
540
552
  };
541
553
 
542
- // ../../lib/tailwind/src/create-tailwind-pipeline.ts
543
- import { ConsoleReporter, Diagnostics, DefaultPolicy, Severity } from "../_shared/diagnostics.js";
544
-
545
554
  // ../../lib/tailwind/src/diagnostics.ts
546
555
  import { DiagnosticCategory, DiagnosticCode } from "../_shared/diagnostics.js";
547
556
  var TailwindDiagnostics = {
@@ -568,6 +577,23 @@ var TailwindDiagnostics = {
568
577
  }
569
578
  };
570
579
 
580
+ // ../../lib/tailwind/src/layout-state.ts
581
+ var LayoutState = class {
582
+ #mode;
583
+ #family;
584
+ constructor(mode) {
585
+ this.#mode = mode;
586
+ this.#family = mode === "none" ? "none" : LAYOUT_FAMILY_MAP[mode];
587
+ Object.freeze(this);
588
+ }
589
+ get mode() {
590
+ return this.#mode;
591
+ }
592
+ get family() {
593
+ return this.#family;
594
+ }
595
+ };
596
+
571
597
  // ../../lib/tailwind/src/create-tailwind-pipeline.ts
572
598
  var DEV = process.env.NODE_ENV !== "production";
573
599
  var devDiagnostics = new Diagnostics(
@@ -648,23 +674,36 @@ function warnDeadVariants(diagnostics, options, compoundDims, props, recipe, sta
648
674
  });
649
675
  }
650
676
  function createTailwindPipeline(options, diagnostics) {
651
- const pipeline = createClassPipeline(options);
677
+ const innerPipeline = createClassPipeline(options);
652
678
  const compoundDims = compoundDimensions(getCompoundVariants(options));
679
+ const resolveLayoutContext = (tag, props, className, recipe) => {
680
+ const mode = resolveLayout(devDiagnostics, props);
681
+ const resolvedClasses = innerPipeline(tag, props, className, recipe);
682
+ const tokens = classifyTokens(resolvedClasses);
683
+ const state = new LayoutState(mode);
684
+ const filtered = tokens.filter((token) => evaluator.evaluate(token, state));
685
+ return { mode, state, filtered, tokens, props, recipe };
686
+ };
687
+ const buildClassString = (ctx) => {
688
+ const built = builder.build(ctx.filtered);
689
+ if (ctx.mode === "none") return built;
690
+ return ctx.filtered.some((t) => t.kind === "layout" && t.value === ctx.mode) ? built : cn(ctx.mode, built);
691
+ };
692
+ const emitDiagnosticsFromContext = (ctx) => {
693
+ if (!DEV) return;
694
+ warnReservedLayoutLiterals(diagnostics, ctx.tokens);
695
+ warnDeadVariants(diagnostics, options, compoundDims, ctx.props, ctx.recipe, ctx.state);
696
+ };
697
+ const combined = (ctx) => {
698
+ const built = buildClassString(ctx);
699
+ emitDiagnosticsFromContext(ctx);
700
+ return built;
701
+ };
702
+ const mainPipeline = composePipelines(resolveLayoutContext, combined);
653
703
  return {
654
704
  ownedKeys: LAYOUT_OWNED_KEYS,
655
705
  pipeline(tag, props, className, recipe) {
656
- const mode = resolveLayout(devDiagnostics, props);
657
- const raw = pipeline(tag, props, className, recipe);
658
- const tokens = classifyTokens(raw);
659
- const state = new LayoutState(mode);
660
- if (DEV) {
661
- warnReservedLayoutLiterals(diagnostics, tokens);
662
- warnDeadVariants(diagnostics, options, compoundDims, props, recipe, state);
663
- }
664
- const filtered = tokens.filter((token) => evaluator.evaluate(token, state));
665
- const built = builder.build(filtered);
666
- if (mode === "none") return built;
667
- return filtered.some((t) => t.kind === "layout" && t.value === mode) ? built : cn(mode, built);
706
+ return mainPipeline(tag, props, className, recipe);
668
707
  }
669
708
  };
670
709
  }
@@ -31,6 +31,26 @@ type MinMax = {
31
31
  };
32
32
  type CardinalityInput = Partial<MinMax>;
33
33
 
34
+ /**
35
+ * Resolved per-instance state available to a dynamic (`dynamic(...)`) child
36
+ * rule field — the same tag/props every adapter already computes before
37
+ * evaluating children, exposed so a rule can vary by them (e.g. cardinality
38
+ * that depends on the resolved `as` tag).
39
+ */
40
+ type ChildRuleContext = {
41
+ readonly tag: unknown;
42
+ readonly props: Readonly<AnyRecord>;
43
+ };
44
+
45
+ declare const RULE_BRAND: unique symbol;
46
+
47
+ type DynamicRule<T, C = unknown> = {
48
+ readonly [RULE_BRAND]: true;
49
+ resolve(context: C): T;
50
+ };
51
+
52
+ type Rule<T, C = unknown> = T | DynamicRule<T, C>;
53
+
34
54
  type ChildRuleMatch<T, U extends T = T> = (child: T) => child is U;
35
55
 
36
56
  type ChildRulePosition = 'first' | 'last' | 'any';
@@ -38,7 +58,13 @@ type ChildRulePosition = 'first' | 'last' | 'any';
38
58
  type ChildRuleInput<T = unknown, U extends T = T> = {
39
59
  name: string;
40
60
  match: ChildRuleMatch<T, U>;
41
- cardinality?: CardinalityInput;
61
+ /**
62
+ * Either a static cardinality, or `dynamic((ctx) => ...)` to derive it from
63
+ * the resolved tag/props (e.g. a different max depending on `as`). `match`
64
+ * stays static-only — it's already a function, so a dynamic wrapper would
65
+ * be indistinguishable from the predicate itself without one.
66
+ */
67
+ cardinality?: Rule<CardinalityInput, ChildRuleContext>;
42
68
  position?: ChildRulePosition;
43
69
  /**
44
70
  * Optional component-type reference for O(1) dispatch index.
package/dist/vue/index.js CHANGED
@@ -456,6 +456,19 @@ function makeResolveTag(defaultTag) {
456
456
  };
457
457
  }
458
458
 
459
+ // ../../lib/primitive/src/rule/rule-brand.ts
460
+ var RULE_BRAND = /* @__PURE__ */ Symbol("praxis-kit/dynamic-rule");
461
+
462
+ // ../../lib/primitive/src/rule/is-dynamic-rule.ts
463
+ function isDynamicRule(rule) {
464
+ return isObject(rule, true) && rule[RULE_BRAND] === true;
465
+ }
466
+
467
+ // ../../lib/primitive/src/rule/resolve-rule.ts
468
+ function resolveRule(rule, context) {
469
+ return isDynamicRule(rule) ? rule.resolve(context) : rule;
470
+ }
471
+
459
472
  // ../../lib/primitive/src/utils/assert-never.ts
460
473
  function assertNever(value) {
461
474
  throw new Error(`Unexpected value: ${String(value)}`);
@@ -1868,10 +1881,22 @@ var RuleValidator = class _RuleValidator extends InvariantBase {
1868
1881
 
1869
1882
  // ../../lib/contract/src/children/children-evaluator.ts
1870
1883
  var isTextLike = (child) => isString(child) || isNumber(child);
1884
+ function checkPositionCardinalityInvariant(rules, context) {
1885
+ iterate.forEach(rules, (rule) => {
1886
+ const { name, position, cardinality } = rule;
1887
+ if ((position === "first" || position === "last") && (cardinality.kind === "unbounded" || cardinality.max > 1)) {
1888
+ throw new RangeError(
1889
+ `ChildrenEvaluator [${context}]: rule "${name}" sets position="${position}" with an unbound or >1 max. position="first|last" implies max=1.`
1890
+ );
1891
+ }
1892
+ });
1893
+ }
1871
1894
  var ChildrenEvaluator = class extends InvariantBase {
1872
1895
  #context;
1873
- #rules;
1874
- #ruleNames;
1896
+ /** Rules with a static cardinality — normalized once, reused on every evaluate() call. */
1897
+ #staticRules;
1898
+ /** Rules whose cardinality is `dynamic(...)` — re-resolved against a ChildRuleContext per call. */
1899
+ #dynamicRuleInputs;
1875
1900
  #matcher;
1876
1901
  #ruleValidator;
1877
1902
  #exclusiveChildren;
@@ -1879,29 +1904,39 @@ var ChildrenEvaluator = class extends InvariantBase {
1879
1904
  constructor(rules, diagnostics, context = "Component", options = {}) {
1880
1905
  super(diagnostics);
1881
1906
  this.#context = context;
1882
- this.#rules = rules.map((r) => normalizeChildRule(r));
1883
- this.#ruleNames = this.#rules.map((r) => r.name);
1884
1907
  this.#exclusiveChildren = options.exclusiveChildren ?? false;
1885
1908
  this.#allowText = options.allowText ?? true;
1886
- iterate.forEach(this.#rules, (rule) => {
1887
- const { name, position, cardinality } = rule;
1888
- if ((position === "first" || position === "last") && (cardinality.kind === "unbounded" || cardinality.max > 1)) {
1889
- throw new RangeError(
1890
- `ChildrenEvaluator [${context}]: rule "${name}" sets position="${position}" with an unbound or >1 max. position="first|last" implies max=1.`
1891
- );
1892
- }
1909
+ const staticRuleInputs = [];
1910
+ const dynamicRuleInputs = [];
1911
+ iterate.forEach(rules, (rule) => {
1912
+ if (isDynamicRule(rule.cardinality)) dynamicRuleInputs.push(rule);
1913
+ else staticRuleInputs.push(rule);
1893
1914
  });
1894
- this.#matcher = new RuleMatcher(this.#rules);
1915
+ this.#dynamicRuleInputs = dynamicRuleInputs;
1916
+ this.#staticRules = staticRuleInputs.map(
1917
+ (r) => normalizeChildRule(r)
1918
+ );
1895
1919
  this.#ruleValidator = new RuleValidator(context, diagnostics);
1920
+ if (this.#dynamicRuleInputs.length === 0) {
1921
+ checkPositionCardinalityInvariant(this.#staticRules, context);
1922
+ this.#matcher = new RuleMatcher(this.#staticRules);
1923
+ } else {
1924
+ this.#matcher = void 0;
1925
+ }
1896
1926
  }
1897
- evaluate(children) {
1927
+ /**
1928
+ * @param context Required when any rule has a `dynamic(...)` cardinality —
1929
+ * supplies the resolved tag/props those rules are evaluated against.
1930
+ */
1931
+ evaluate(children, context) {
1898
1932
  if (!this.active) return;
1933
+ const { rules, matcher } = this.#resolveRules(context);
1899
1934
  const {
1900
1935
  matrix,
1901
1936
  unexpectedIndices: rawUnexpectedIndices,
1902
1937
  ambiguousIndices
1903
- } = this.#matcher.match(children);
1904
- this.#ruleValidator.validate(this.#rules, matrix, children.length);
1938
+ } = matcher.match(children);
1939
+ this.#ruleValidator.validate(rules, matrix, children.length);
1905
1940
  const unexpectedIndices = new Set(
1906
1941
  [...rawUnexpectedIndices].filter(
1907
1942
  (ci) => isTextLike(children[ci]) ? this.#allowText === false : this.#exclusiveChildren
@@ -1915,11 +1950,28 @@ var ChildrenEvaluator = class extends InvariantBase {
1915
1950
  this.violate(ContractDiagnostics.unexpectedChild(typeName, ci, this.#context));
1916
1951
  } else {
1917
1952
  const matches = matrix.childToRules.forward.get(ci);
1918
- const names = [...matches].map((ri) => this.#ruleNames[ri] ?? `#${ri}`);
1953
+ const names = [...matches].map((ri) => rules[ri]?.name ?? `#${ri}`);
1919
1954
  this.violate(ContractDiagnostics.ambiguousChild(typeName, ci, names, this.#context));
1920
1955
  }
1921
1956
  });
1922
1957
  }
1958
+ #resolveRules(context) {
1959
+ if (this.#dynamicRuleInputs.length === 0) {
1960
+ return { rules: this.#staticRules, matcher: this.#matcher };
1961
+ }
1962
+ if (context === void 0) {
1963
+ throw new RangeError(
1964
+ `ChildrenEvaluator [${this.#context}]: rule(s) have a dynamic(...) cardinality \u2014 evaluate() requires a context argument to resolve them.`
1965
+ );
1966
+ }
1967
+ const resolvedDynamicRules = this.#dynamicRuleInputs.map((r) => {
1968
+ const cardinality = resolveRule(r.cardinality, context);
1969
+ return normalizeChildRule({ ...r, cardinality });
1970
+ });
1971
+ checkPositionCardinalityInvariant(resolvedDynamicRules, this.#context);
1972
+ const rules = [...this.#staticRules, ...resolvedDynamicRules];
1973
+ return { rules, matcher: new RuleMatcher(rules) };
1974
+ }
1923
1975
  };
1924
1976
 
1925
1977
  // ../../lib/contract/src/props/get-disabled-props.ts
@@ -2785,6 +2837,7 @@ function prepareRenderState(runtime, attrs, filterProps) {
2785
2837
  ...asChild !== void 0 && { asChild }
2786
2838
  },
2787
2839
  props: filteredProps,
2840
+ normalizedProps,
2788
2841
  className
2789
2842
  };
2790
2843
  }
@@ -2831,7 +2884,7 @@ function render({
2831
2884
  }) {
2832
2885
  const { vnodes: children, discarded } = normalizeChildren(slots);
2833
2886
  if (process.env.NODE_ENV !== "production") {
2834
- childrenEvaluator?.evaluate(children);
2887
+ childrenEvaluator?.evaluate(children, { tag: state.tag, props: state.normalizedProps });
2835
2888
  runtime.options.htmlChildrenEvaluatorFn?.(state.tag)?.evaluate(children);
2836
2889
  }
2837
2890
  const slotResult = tryRenderAsChild(state, children, discarded, slotValidator);
@@ -29,6 +29,26 @@ type MinMax = {
29
29
  };
30
30
  type CardinalityInput = Partial<MinMax>;
31
31
 
32
+ /**
33
+ * Resolved per-instance state available to a dynamic (`dynamic(...)`) child
34
+ * rule field — the same tag/props every adapter already computes before
35
+ * evaluating children, exposed so a rule can vary by them (e.g. cardinality
36
+ * that depends on the resolved `as` tag).
37
+ */
38
+ type ChildRuleContext = {
39
+ readonly tag: unknown;
40
+ readonly props: Readonly<AnyRecord>;
41
+ };
42
+
43
+ declare const RULE_BRAND: unique symbol;
44
+
45
+ type DynamicRule<T, C = unknown> = {
46
+ readonly [RULE_BRAND]: true;
47
+ resolve(context: C): T;
48
+ };
49
+
50
+ type Rule<T, C = unknown> = T | DynamicRule<T, C>;
51
+
32
52
  type ChildRuleMatch<T, U extends T = T> = (child: T) => child is U;
33
53
 
34
54
  type ChildRulePosition = 'first' | 'last' | 'any';
@@ -36,7 +56,13 @@ type ChildRulePosition = 'first' | 'last' | 'any';
36
56
  type ChildRuleInput<T = unknown, U extends T = T> = {
37
57
  name: string;
38
58
  match: ChildRuleMatch<T, U>;
39
- cardinality?: CardinalityInput;
59
+ /**
60
+ * Either a static cardinality, or `dynamic((ctx) => ...)` to derive it from
61
+ * the resolved tag/props (e.g. a different max depending on `as`). `match`
62
+ * stays static-only — it's already a function, so a dynamic wrapper would
63
+ * be indistinguishable from the predicate itself without one.
64
+ */
65
+ cardinality?: Rule<CardinalityInput, ChildRuleContext>;
40
66
  position?: ChildRulePosition;
41
67
  /**
42
68
  * Optional component-type reference for O(1) dispatch index.
package/dist/web/index.js CHANGED
@@ -313,6 +313,19 @@ function makeResolveTag(defaultTag) {
313
313
  };
314
314
  }
315
315
 
316
+ // ../../lib/primitive/src/rule/rule-brand.ts
317
+ var RULE_BRAND = /* @__PURE__ */ Symbol("praxis-kit/dynamic-rule");
318
+
319
+ // ../../lib/primitive/src/rule/is-dynamic-rule.ts
320
+ function isDynamicRule(rule) {
321
+ return isObject(rule, true) && rule[RULE_BRAND] === true;
322
+ }
323
+
324
+ // ../../lib/primitive/src/rule/resolve-rule.ts
325
+ function resolveRule(rule, context) {
326
+ return isDynamicRule(rule) ? rule.resolve(context) : rule;
327
+ }
328
+
316
329
  // ../../lib/primitive/src/utils/assert-never.ts
317
330
  function assertNever(value) {
318
331
  throw new Error(`Unexpected value: ${String(value)}`);
@@ -1715,10 +1728,22 @@ var RuleValidator = class _RuleValidator extends InvariantBase {
1715
1728
 
1716
1729
  // ../../lib/contract/src/children/children-evaluator.ts
1717
1730
  var isTextLike = (child) => isString(child) || isNumber(child);
1731
+ function checkPositionCardinalityInvariant(rules, context) {
1732
+ iterate.forEach(rules, (rule) => {
1733
+ const { name, position, cardinality } = rule;
1734
+ if ((position === "first" || position === "last") && (cardinality.kind === "unbounded" || cardinality.max > 1)) {
1735
+ throw new RangeError(
1736
+ `ChildrenEvaluator [${context}]: rule "${name}" sets position="${position}" with an unbound or >1 max. position="first|last" implies max=1.`
1737
+ );
1738
+ }
1739
+ });
1740
+ }
1718
1741
  var ChildrenEvaluator = class extends InvariantBase {
1719
1742
  #context;
1720
- #rules;
1721
- #ruleNames;
1743
+ /** Rules with a static cardinality — normalized once, reused on every evaluate() call. */
1744
+ #staticRules;
1745
+ /** Rules whose cardinality is `dynamic(...)` — re-resolved against a ChildRuleContext per call. */
1746
+ #dynamicRuleInputs;
1722
1747
  #matcher;
1723
1748
  #ruleValidator;
1724
1749
  #exclusiveChildren;
@@ -1726,29 +1751,39 @@ var ChildrenEvaluator = class extends InvariantBase {
1726
1751
  constructor(rules, diagnostics, context = "Component", options = {}) {
1727
1752
  super(diagnostics);
1728
1753
  this.#context = context;
1729
- this.#rules = rules.map((r) => normalizeChildRule(r));
1730
- this.#ruleNames = this.#rules.map((r) => r.name);
1731
1754
  this.#exclusiveChildren = options.exclusiveChildren ?? false;
1732
1755
  this.#allowText = options.allowText ?? true;
1733
- iterate.forEach(this.#rules, (rule) => {
1734
- const { name, position, cardinality } = rule;
1735
- if ((position === "first" || position === "last") && (cardinality.kind === "unbounded" || cardinality.max > 1)) {
1736
- throw new RangeError(
1737
- `ChildrenEvaluator [${context}]: rule "${name}" sets position="${position}" with an unbound or >1 max. position="first|last" implies max=1.`
1738
- );
1739
- }
1756
+ const staticRuleInputs = [];
1757
+ const dynamicRuleInputs = [];
1758
+ iterate.forEach(rules, (rule) => {
1759
+ if (isDynamicRule(rule.cardinality)) dynamicRuleInputs.push(rule);
1760
+ else staticRuleInputs.push(rule);
1740
1761
  });
1741
- this.#matcher = new RuleMatcher(this.#rules);
1762
+ this.#dynamicRuleInputs = dynamicRuleInputs;
1763
+ this.#staticRules = staticRuleInputs.map(
1764
+ (r) => normalizeChildRule(r)
1765
+ );
1742
1766
  this.#ruleValidator = new RuleValidator(context, diagnostics);
1767
+ if (this.#dynamicRuleInputs.length === 0) {
1768
+ checkPositionCardinalityInvariant(this.#staticRules, context);
1769
+ this.#matcher = new RuleMatcher(this.#staticRules);
1770
+ } else {
1771
+ this.#matcher = void 0;
1772
+ }
1743
1773
  }
1744
- evaluate(children) {
1774
+ /**
1775
+ * @param context Required when any rule has a `dynamic(...)` cardinality —
1776
+ * supplies the resolved tag/props those rules are evaluated against.
1777
+ */
1778
+ evaluate(children, context) {
1745
1779
  if (!this.active) return;
1780
+ const { rules, matcher } = this.#resolveRules(context);
1746
1781
  const {
1747
1782
  matrix,
1748
1783
  unexpectedIndices: rawUnexpectedIndices,
1749
1784
  ambiguousIndices
1750
- } = this.#matcher.match(children);
1751
- this.#ruleValidator.validate(this.#rules, matrix, children.length);
1785
+ } = matcher.match(children);
1786
+ this.#ruleValidator.validate(rules, matrix, children.length);
1752
1787
  const unexpectedIndices = new Set(
1753
1788
  [...rawUnexpectedIndices].filter(
1754
1789
  (ci) => isTextLike(children[ci]) ? this.#allowText === false : this.#exclusiveChildren
@@ -1762,11 +1797,28 @@ var ChildrenEvaluator = class extends InvariantBase {
1762
1797
  this.violate(ContractDiagnostics.unexpectedChild(typeName, ci, this.#context));
1763
1798
  } else {
1764
1799
  const matches = matrix.childToRules.forward.get(ci);
1765
- const names = [...matches].map((ri) => this.#ruleNames[ri] ?? `#${ri}`);
1800
+ const names = [...matches].map((ri) => rules[ri]?.name ?? `#${ri}`);
1766
1801
  this.violate(ContractDiagnostics.ambiguousChild(typeName, ci, names, this.#context));
1767
1802
  }
1768
1803
  });
1769
1804
  }
1805
+ #resolveRules(context) {
1806
+ if (this.#dynamicRuleInputs.length === 0) {
1807
+ return { rules: this.#staticRules, matcher: this.#matcher };
1808
+ }
1809
+ if (context === void 0) {
1810
+ throw new RangeError(
1811
+ `ChildrenEvaluator [${this.#context}]: rule(s) have a dynamic(...) cardinality \u2014 evaluate() requires a context argument to resolve them.`
1812
+ );
1813
+ }
1814
+ const resolvedDynamicRules = this.#dynamicRuleInputs.map((r) => {
1815
+ const cardinality = resolveRule(r.cardinality, context);
1816
+ return normalizeChildRule({ ...r, cardinality });
1817
+ });
1818
+ checkPositionCardinalityInvariant(resolvedDynamicRules, this.#context);
1819
+ const rules = [...this.#staticRules, ...resolvedDynamicRules];
1820
+ return { rules, matcher: new RuleMatcher(rules) };
1821
+ }
1770
1822
  };
1771
1823
 
1772
1824
  // ../../lib/contract/src/props/get-disabled-props.ts
@@ -2558,13 +2610,10 @@ function toLooseBundle(bundle) {
2558
2610
  }
2559
2611
  return bundle;
2560
2612
  }
2561
- function resolveHostState(bundle, props) {
2562
- const { as, className, recipe, ...rest } = props;
2563
- const { options, resolveAria, resolveClasses, resolveProps, resolveTag: resolveTag2 } = bundle.runtime;
2613
+ function resolveTagAndNormalizedProps(bundle, props) {
2614
+ const { as, className: _className, recipe: _recipe, ...rest } = props;
2615
+ const { options, resolveProps, resolveTag: resolveTag2 } = bundle.runtime;
2564
2616
  const tag = resolveTag2(as);
2565
- if (options.allowedAs !== void 0) {
2566
- enforceAllowedAs(tag, options.allowedAs, options.diagnostics, options.displayName);
2567
- }
2568
2617
  const mergedProps = resolveProps(rest);
2569
2618
  const normalizedProps = typeof options.normalizeFn === "function" ? options.normalizeFn(mergedProps) : mergedProps;
2570
2619
  const htmlNormalizers = options.htmlPropNormalizersFn?.(tag);
@@ -2574,6 +2623,15 @@ function resolveHostState(bundle, props) {
2574
2623
  Object.assign(finalProps, normalize(finalProps));
2575
2624
  }
2576
2625
  }
2626
+ return { tag, normalizedProps: finalProps };
2627
+ }
2628
+ function resolveHostState(bundle, props) {
2629
+ const { className, recipe } = props;
2630
+ const { options, resolveAria, resolveClasses } = bundle.runtime;
2631
+ const { tag, normalizedProps: finalProps } = resolveTagAndNormalizedProps(bundle, props);
2632
+ if (options.allowedAs !== void 0) {
2633
+ enforceAllowedAs(tag, options.allowedAs, options.diagnostics, options.displayName);
2634
+ }
2577
2635
  const resolvedClass = resolveClasses(
2578
2636
  tag,
2579
2637
  finalProps,
@@ -2582,7 +2640,7 @@ function resolveHostState(bundle, props) {
2582
2640
  );
2583
2641
  const ariaResult = resolveAria(tag, finalProps);
2584
2642
  const attributes = applyFilter(ariaResult.props, bundle.filterProps, options.variantKeys);
2585
- return { className: resolvedClass, attributes };
2643
+ return { className: resolvedClass, attributes, tag, normalizedProps: finalProps };
2586
2644
  }
2587
2645
  function diffAndApplyAttributes(host, state, prevPipelineAttrs, incomingProps) {
2588
2646
  const hasOwn2 = Object.hasOwn;
@@ -2689,14 +2747,8 @@ function createContractComponent(options) {
2689
2747
  const self = this._self;
2690
2748
  const {
2691
2749
  childrenEvaluator,
2692
- runtime: { options: options2, resolveTag: resolveTag2 }
2750
+ runtime: { options: options2 }
2693
2751
  } = bundle;
2694
- const tag = resolveTag2(self.as);
2695
- const children = Array.from(this.childNodes);
2696
- if (childrenEvaluator) {
2697
- childrenEvaluator.evaluate(children);
2698
- }
2699
- options2.htmlChildrenEvaluatorFn?.(tag)?.evaluate(children);
2700
2752
  const observedSet = new Set(
2701
2753
  this.constructor.observedAttributes ?? []
2702
2754
  );
@@ -2712,7 +2764,16 @@ function createContractComponent(options) {
2712
2764
  const val = self[key] ?? this.getAttribute(key);
2713
2765
  if (val != null) props[key] = val;
2714
2766
  }
2715
- diffAndApplyAttributes(this, resolveHostState(looseBundle, props), this._pipelineAttrs, props);
2767
+ const hostState = resolveHostState(looseBundle, props);
2768
+ const children = Array.from(this.childNodes);
2769
+ if (childrenEvaluator) {
2770
+ childrenEvaluator.evaluate(children, {
2771
+ tag: hostState.tag,
2772
+ props: hostState.normalizedProps
2773
+ });
2774
+ }
2775
+ options2.htmlChildrenEvaluatorFn?.(hostState.tag)?.evaluate(children);
2776
+ diffAndApplyAttributes(this, hostState, this._pipelineAttrs, props);
2716
2777
  }
2717
2778
  }
2718
2779
  if (options.name) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "praxis-kit",
3
- "version": "5.0.0",
3
+ "version": "6.0.0",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./react": {
@@ -184,10 +184,10 @@
184
184
  "vue": "^3.5.38",
185
185
  "@praxis-kit/core": "0.0.0",
186
186
  "@praxis-kit/adapter-utils": "0.0.0",
187
- "@praxis-kit/pipeline": "0.0.0",
188
- "@praxis-kit/primitive": "0.0.0",
189
187
  "@praxis-kit/diagnostics": "0.0.0",
190
- "@praxis-kit/vite-plugin": "0.0.0"
188
+ "@praxis-kit/pipeline": "0.0.0",
189
+ "@praxis-kit/vite-plugin": "0.0.0",
190
+ "@praxis-kit/primitive": "0.0.0"
191
191
  },
192
192
  "publishConfig": {
193
193
  "access": "public"