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.
@@ -12,7 +12,7 @@ import {
12
12
  makeCloneSlotChild,
13
13
  mergeRefs,
14
14
  render
15
- } from "../chunk-SKAY22CZ.js";
15
+ } from "../chunk-P5ZJBPAR.js";
16
16
 
17
17
  // ../../adapters/react/src/current/slot/composeRefs.ts
18
18
  function getChildRef(element) {
@@ -1,5 +1,5 @@
1
- import { E as ElementType, U as UnknownProps, a as EmptyRecord, V as VariantMap, R as RecipeMap, A as AnyClassPluginFactory, b as ReactFactoryOptions, P as PolymorphicComponent, c as PolymorphicGenerics, d as ExtractPluginProps } from '../react-options-D6rRB2gJ.js';
2
- export { e as AnyFactoryOptions, f as ElementRef, F as FactoryOptions, g as PolymorphicProps, h as PolymorphicWithAsChild, i as PolymorphicWithRender, j as RenderCallbackProps, S as Slottable, k as SlottableProps, l as defineContractComponent, m as mergeRefs } from '../react-options-D6rRB2gJ.js';
1
+ import { E as ElementType, U as UnknownProps, a as EmptyRecord, V as VariantMap, R as RecipeMap, A as AnyClassPluginFactory, b as ReactFactoryOptions, P as PolymorphicComponent, c as PolymorphicGenerics, d as ExtractPluginProps } from '../react-options-AitAOrje.js';
2
+ export { e as AnyFactoryOptions, f as ElementRef, F as FactoryOptions, g as PolymorphicProps, h as PolymorphicWithAsChild, i as PolymorphicWithRender, j as RenderCallbackProps, S as Slottable, k as SlottableProps, l as defineContractComponent, m as mergeRefs } from '../react-options-AitAOrje.js';
3
3
  import * as react from 'react';
4
4
  import 'type-fest';
5
5
  import '../_shared/diagnostics.js';
@@ -13,7 +13,7 @@ import {
13
13
  makeCloneSlotChild,
14
14
  mergeRefs,
15
15
  render
16
- } from "../chunk-SKAY22CZ.js";
16
+ } from "../chunk-P5ZJBPAR.js";
17
17
 
18
18
  // ../../adapters/react/src/legacy/create-contract-component.ts
19
19
  import { forwardRef as forwardRef2 } from "react";
@@ -30,6 +30,26 @@ type MinMax = {
30
30
  };
31
31
  type CardinalityInput = Partial<MinMax>;
32
32
 
33
+ /**
34
+ * Resolved per-instance state available to a dynamic (`dynamic(...)`) child
35
+ * rule field — the same tag/props every adapter already computes before
36
+ * evaluating children, exposed so a rule can vary by them (e.g. cardinality
37
+ * that depends on the resolved `as` tag).
38
+ */
39
+ type ChildRuleContext = {
40
+ readonly tag: unknown;
41
+ readonly props: Readonly<AnyRecord>;
42
+ };
43
+
44
+ declare const RULE_BRAND: unique symbol;
45
+
46
+ type DynamicRule<T, C = unknown> = {
47
+ readonly [RULE_BRAND]: true;
48
+ resolve(context: C): T;
49
+ };
50
+
51
+ type Rule<T, C = unknown> = T | DynamicRule<T, C>;
52
+
33
53
  type ChildRuleMatch<T, U extends T = T> = (child: T) => child is U;
34
54
 
35
55
  type ChildRulePosition = 'first' | 'last' | 'any';
@@ -37,7 +57,13 @@ type ChildRulePosition = 'first' | 'last' | 'any';
37
57
  type ChildRuleInput<T = unknown, U extends T = T> = {
38
58
  name: string;
39
59
  match: ChildRuleMatch<T, U>;
40
- cardinality?: CardinalityInput;
60
+ /**
61
+ * Either a static cardinality, or `dynamic((ctx) => ...)` to derive it from
62
+ * the resolved tag/props (e.g. a different max depending on `as`). `match`
63
+ * stays static-only — it's already a function, so a dynamic wrapper would
64
+ * be indistinguishable from the predicate itself without one.
65
+ */
66
+ cardinality?: Rule<CardinalityInput, ChildRuleContext>;
41
67
  position?: ChildRulePosition;
42
68
  /**
43
69
  * Optional component-type reference for O(1) dispatch index.
@@ -30,6 +30,26 @@ type MinMax = {
30
30
  };
31
31
  type CardinalityInput = Partial<MinMax>;
32
32
 
33
+ /**
34
+ * Resolved per-instance state available to a dynamic (`dynamic(...)`) child
35
+ * rule field — the same tag/props every adapter already computes before
36
+ * evaluating children, exposed so a rule can vary by them (e.g. cardinality
37
+ * that depends on the resolved `as` tag).
38
+ */
39
+ type ChildRuleContext = {
40
+ readonly tag: unknown;
41
+ readonly props: Readonly<AnyRecord>;
42
+ };
43
+
44
+ declare const RULE_BRAND: unique symbol;
45
+
46
+ type DynamicRule<T, C = unknown> = {
47
+ readonly [RULE_BRAND]: true;
48
+ resolve(context: C): T;
49
+ };
50
+
51
+ type Rule<T, C = unknown> = T | DynamicRule<T, C>;
52
+
33
53
  type ChildRuleMatch<T, U extends T = T> = (child: T) => child is U;
34
54
 
35
55
  type ChildRulePosition = 'first' | 'last' | 'any';
@@ -37,7 +57,13 @@ type ChildRulePosition = 'first' | 'last' | 'any';
37
57
  type ChildRuleInput<T = unknown, U extends T = T> = {
38
58
  name: string;
39
59
  match: ChildRuleMatch<T, U>;
40
- cardinality?: CardinalityInput;
60
+ /**
61
+ * Either a static cardinality, or `dynamic((ctx) => ...)` to derive it from
62
+ * the resolved tag/props (e.g. a different max depending on `as`). `match`
63
+ * stays static-only — it's already a function, so a dynamic wrapper would
64
+ * be indistinguishable from the predicate itself without one.
65
+ */
66
+ cardinality?: Rule<CardinalityInput, ChildRuleContext>;
41
67
  position?: ChildRulePosition;
42
68
  /**
43
69
  * Optional component-type reference for O(1) dispatch index.
@@ -445,6 +445,19 @@ function makeResolveTag(defaultTag) {
445
445
  };
446
446
  }
447
447
 
448
+ // ../../lib/primitive/src/rule/rule-brand.ts
449
+ var RULE_BRAND = /* @__PURE__ */ Symbol("praxis-kit/dynamic-rule");
450
+
451
+ // ../../lib/primitive/src/rule/is-dynamic-rule.ts
452
+ function isDynamicRule(rule) {
453
+ return isObject(rule, true) && rule[RULE_BRAND] === true;
454
+ }
455
+
456
+ // ../../lib/primitive/src/rule/resolve-rule.ts
457
+ function resolveRule(rule, context) {
458
+ return isDynamicRule(rule) ? rule.resolve(context) : rule;
459
+ }
460
+
448
461
  // ../../lib/primitive/src/utils/assert-never.ts
449
462
  function assertNever(value) {
450
463
  throw new Error(`Unexpected value: ${String(value)}`);
@@ -1857,10 +1870,22 @@ var RuleValidator = class _RuleValidator extends InvariantBase {
1857
1870
 
1858
1871
  // ../../lib/contract/src/children/children-evaluator.ts
1859
1872
  var isTextLike = (child) => isString(child) || isNumber(child);
1873
+ function checkPositionCardinalityInvariant(rules, context) {
1874
+ iterate.forEach(rules, (rule) => {
1875
+ const { name, position, cardinality } = rule;
1876
+ if ((position === "first" || position === "last") && (cardinality.kind === "unbounded" || cardinality.max > 1)) {
1877
+ throw new RangeError(
1878
+ `ChildrenEvaluator [${context}]: rule "${name}" sets position="${position}" with an unbound or >1 max. position="first|last" implies max=1.`
1879
+ );
1880
+ }
1881
+ });
1882
+ }
1860
1883
  var ChildrenEvaluator = class extends InvariantBase {
1861
1884
  #context;
1862
- #rules;
1863
- #ruleNames;
1885
+ /** Rules with a static cardinality — normalized once, reused on every evaluate() call. */
1886
+ #staticRules;
1887
+ /** Rules whose cardinality is `dynamic(...)` — re-resolved against a ChildRuleContext per call. */
1888
+ #dynamicRuleInputs;
1864
1889
  #matcher;
1865
1890
  #ruleValidator;
1866
1891
  #exclusiveChildren;
@@ -1868,29 +1893,39 @@ var ChildrenEvaluator = class extends InvariantBase {
1868
1893
  constructor(rules, diagnostics, context = "Component", options = {}) {
1869
1894
  super(diagnostics);
1870
1895
  this.#context = context;
1871
- this.#rules = rules.map((r) => normalizeChildRule(r));
1872
- this.#ruleNames = this.#rules.map((r) => r.name);
1873
1896
  this.#exclusiveChildren = options.exclusiveChildren ?? false;
1874
1897
  this.#allowText = options.allowText ?? true;
1875
- iterate.forEach(this.#rules, (rule) => {
1876
- const { name, position, cardinality } = rule;
1877
- if ((position === "first" || position === "last") && (cardinality.kind === "unbounded" || cardinality.max > 1)) {
1878
- throw new RangeError(
1879
- `ChildrenEvaluator [${context}]: rule "${name}" sets position="${position}" with an unbound or >1 max. position="first|last" implies max=1.`
1880
- );
1881
- }
1898
+ const staticRuleInputs = [];
1899
+ const dynamicRuleInputs = [];
1900
+ iterate.forEach(rules, (rule) => {
1901
+ if (isDynamicRule(rule.cardinality)) dynamicRuleInputs.push(rule);
1902
+ else staticRuleInputs.push(rule);
1882
1903
  });
1883
- this.#matcher = new RuleMatcher(this.#rules);
1904
+ this.#dynamicRuleInputs = dynamicRuleInputs;
1905
+ this.#staticRules = staticRuleInputs.map(
1906
+ (r) => normalizeChildRule(r)
1907
+ );
1884
1908
  this.#ruleValidator = new RuleValidator(context, diagnostics);
1909
+ if (this.#dynamicRuleInputs.length === 0) {
1910
+ checkPositionCardinalityInvariant(this.#staticRules, context);
1911
+ this.#matcher = new RuleMatcher(this.#staticRules);
1912
+ } else {
1913
+ this.#matcher = void 0;
1914
+ }
1885
1915
  }
1886
- evaluate(children) {
1916
+ /**
1917
+ * @param context Required when any rule has a `dynamic(...)` cardinality —
1918
+ * supplies the resolved tag/props those rules are evaluated against.
1919
+ */
1920
+ evaluate(children, context) {
1887
1921
  if (!this.active) return;
1922
+ const { rules, matcher } = this.#resolveRules(context);
1888
1923
  const {
1889
1924
  matrix,
1890
1925
  unexpectedIndices: rawUnexpectedIndices,
1891
1926
  ambiguousIndices
1892
- } = this.#matcher.match(children);
1893
- this.#ruleValidator.validate(this.#rules, matrix, children.length);
1927
+ } = matcher.match(children);
1928
+ this.#ruleValidator.validate(rules, matrix, children.length);
1894
1929
  const unexpectedIndices = new Set(
1895
1930
  [...rawUnexpectedIndices].filter(
1896
1931
  (ci) => isTextLike(children[ci]) ? this.#allowText === false : this.#exclusiveChildren
@@ -1904,11 +1939,28 @@ var ChildrenEvaluator = class extends InvariantBase {
1904
1939
  this.violate(ContractDiagnostics.unexpectedChild(typeName, ci, this.#context));
1905
1940
  } else {
1906
1941
  const matches = matrix.childToRules.forward.get(ci);
1907
- const names = [...matches].map((ri) => this.#ruleNames[ri] ?? `#${ri}`);
1942
+ const names = [...matches].map((ri) => rules[ri]?.name ?? `#${ri}`);
1908
1943
  this.violate(ContractDiagnostics.ambiguousChild(typeName, ci, names, this.#context));
1909
1944
  }
1910
1945
  });
1911
1946
  }
1947
+ #resolveRules(context) {
1948
+ if (this.#dynamicRuleInputs.length === 0) {
1949
+ return { rules: this.#staticRules, matcher: this.#matcher };
1950
+ }
1951
+ if (context === void 0) {
1952
+ throw new RangeError(
1953
+ `ChildrenEvaluator [${this.#context}]: rule(s) have a dynamic(...) cardinality \u2014 evaluate() requires a context argument to resolve them.`
1954
+ );
1955
+ }
1956
+ const resolvedDynamicRules = this.#dynamicRuleInputs.map((r) => {
1957
+ const cardinality = resolveRule(r.cardinality, context);
1958
+ return normalizeChildRule({ ...r, cardinality });
1959
+ });
1960
+ checkPositionCardinalityInvariant(resolvedDynamicRules, this.#context);
1961
+ const rules = [...this.#staticRules, ...resolvedDynamicRules];
1962
+ return { rules, matcher: new RuleMatcher(rules) };
1963
+ }
1912
1964
  };
1913
1965
 
1914
1966
  // ../../lib/contract/src/props/get-disabled-props.ts
@@ -2769,7 +2821,10 @@ function render({
2769
2821
  createEffect(() => enforceAllowedAs(tag(), allowedAs, runtime.options.diagnostics, runtime.options.displayName));
2770
2822
  }
2771
2823
  if (process.env.NODE_ENV !== "production" && childrenEvaluator) {
2772
- createEffect(() => childrenEvaluator.evaluate(toChildArray(known.children)));
2824
+ createEffect(() => childrenEvaluator.evaluate(toChildArray(known.children), {
2825
+ tag: tag(),
2826
+ props: normalizedProps()
2827
+ }));
2773
2828
  }
2774
2829
  if (process.env.NODE_ENV !== "production") {
2775
2830
  createEffect(() => runtime.options.htmlChildrenEvaluatorFn?.(tag())?.evaluate(toChildArray(known.children)));
@@ -129,7 +129,7 @@
129
129
  $effect(() => {
130
130
  if (process.env.NODE_ENV === 'production' || !hostEl) return
131
131
  const childArray = Array.from(hostEl.childNodes)
132
- bundle.childrenEvaluator?.evaluate(childArray)
132
+ bundle.childrenEvaluator?.evaluate(childArray, { tag, props: normalizedProps })
133
133
  bundle.runtime.options.htmlChildrenEvaluatorFn?.(tag)?.evaluate(childArray)
134
134
  })
135
135
  }
@@ -36,6 +36,26 @@ type ChildrenEvaluator$1 = {
36
36
  evaluate: (children: unknown[]) => void;
37
37
  };
38
38
 
39
+ /**
40
+ * Resolved per-instance state available to a dynamic (`dynamic(...)`) child
41
+ * rule field — the same tag/props every adapter already computes before
42
+ * evaluating children, exposed so a rule can vary by them (e.g. cardinality
43
+ * that depends on the resolved `as` tag).
44
+ */
45
+ type ChildRuleContext = {
46
+ readonly tag: unknown;
47
+ readonly props: Readonly<AnyRecord>;
48
+ };
49
+
50
+ declare const RULE_BRAND: unique symbol;
51
+
52
+ type DynamicRule<T, C = unknown> = {
53
+ readonly [RULE_BRAND]: true;
54
+ resolve(context: C): T;
55
+ };
56
+
57
+ type Rule<T, C = unknown> = T | DynamicRule<T, C>;
58
+
39
59
  type ChildRuleMatch<T, U extends T = T> = (child: T) => child is U;
40
60
 
41
61
  type ChildRulePosition = 'first' | 'last' | 'any';
@@ -43,7 +63,13 @@ type ChildRulePosition = 'first' | 'last' | 'any';
43
63
  type ChildRuleInput<T = unknown, U extends T = T> = {
44
64
  name: string;
45
65
  match: ChildRuleMatch<T, U>;
46
- cardinality?: CardinalityInput;
66
+ /**
67
+ * Either a static cardinality, or `dynamic((ctx) => ...)` to derive it from
68
+ * the resolved tag/props (e.g. a different max depending on `as`). `match`
69
+ * stays static-only — it's already a function, so a dynamic wrapper would
70
+ * be indistinguishable from the predicate itself without one.
71
+ */
72
+ cardinality?: Rule<CardinalityInput, ChildRuleContext>;
47
73
  position?: ChildRulePosition;
48
74
  /**
49
75
  * Optional component-type reference for O(1) dispatch index.
@@ -336,7 +362,11 @@ type ChildrenEvaluatorOptions = {
336
362
  declare class ChildrenEvaluator extends InvariantBase {
337
363
  #private;
338
364
  constructor(rules: readonly ChildRuleInput[], diagnostics: Diagnostics, context?: string, options?: ChildrenEvaluatorOptions);
339
- evaluate(children: unknown[]): void;
365
+ /**
366
+ * @param context Required when any rule has a `dynamic(...)` cardinality —
367
+ * supplies the resolved tag/props those rules are evaluated against.
368
+ */
369
+ evaluate(children: unknown[], context?: ChildRuleContext): void;
340
370
  }
341
371
 
342
372
  declare function createPolymorphic2<TDefault extends ElementType, Props extends AnyRecord, Variants extends Readonly<VariantMap>, TPreset extends RecipeMap<Variants> = Readonly<EmptyRecord>, TPlugin extends AnyClassPluginFactory = AnyClassPluginFactory>(options?: FactoryOptions<TDefault, Props, Variants, TPreset, TPlugin>): PolymorphicRuntime<TDefault, Props, Variants, Extract<keyof TPreset, string>, TPreset, PluginInstance<TPlugin>>;
@@ -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)}`);
@@ -1761,10 +1774,22 @@ var RuleValidator = class _RuleValidator extends InvariantBase {
1761
1774
 
1762
1775
  // ../../lib/contract/src/children/children-evaluator.ts
1763
1776
  var isTextLike = (child) => isString(child) || isNumber(child);
1777
+ function checkPositionCardinalityInvariant(rules, context) {
1778
+ iterate.forEach(rules, (rule) => {
1779
+ const { name, position, cardinality } = rule;
1780
+ if ((position === "first" || position === "last") && (cardinality.kind === "unbounded" || cardinality.max > 1)) {
1781
+ throw new RangeError(
1782
+ `ChildrenEvaluator [${context}]: rule "${name}" sets position="${position}" with an unbound or >1 max. position="first|last" implies max=1.`
1783
+ );
1784
+ }
1785
+ });
1786
+ }
1764
1787
  var ChildrenEvaluator = class extends InvariantBase {
1765
1788
  #context;
1766
- #rules;
1767
- #ruleNames;
1789
+ /** Rules with a static cardinality — normalized once, reused on every evaluate() call. */
1790
+ #staticRules;
1791
+ /** Rules whose cardinality is `dynamic(...)` — re-resolved against a ChildRuleContext per call. */
1792
+ #dynamicRuleInputs;
1768
1793
  #matcher;
1769
1794
  #ruleValidator;
1770
1795
  #exclusiveChildren;
@@ -1772,29 +1797,39 @@ var ChildrenEvaluator = class extends InvariantBase {
1772
1797
  constructor(rules, diagnostics, context = "Component", options = {}) {
1773
1798
  super(diagnostics);
1774
1799
  this.#context = context;
1775
- this.#rules = rules.map((r) => normalizeChildRule(r));
1776
- this.#ruleNames = this.#rules.map((r) => r.name);
1777
1800
  this.#exclusiveChildren = options.exclusiveChildren ?? false;
1778
1801
  this.#allowText = options.allowText ?? true;
1779
- iterate.forEach(this.#rules, (rule) => {
1780
- const { name, position, cardinality } = rule;
1781
- if ((position === "first" || position === "last") && (cardinality.kind === "unbounded" || cardinality.max > 1)) {
1782
- throw new RangeError(
1783
- `ChildrenEvaluator [${context}]: rule "${name}" sets position="${position}" with an unbound or >1 max. position="first|last" implies max=1.`
1784
- );
1785
- }
1802
+ const staticRuleInputs = [];
1803
+ const dynamicRuleInputs = [];
1804
+ iterate.forEach(rules, (rule) => {
1805
+ if (isDynamicRule(rule.cardinality)) dynamicRuleInputs.push(rule);
1806
+ else staticRuleInputs.push(rule);
1786
1807
  });
1787
- this.#matcher = new RuleMatcher(this.#rules);
1808
+ this.#dynamicRuleInputs = dynamicRuleInputs;
1809
+ this.#staticRules = staticRuleInputs.map(
1810
+ (r) => normalizeChildRule(r)
1811
+ );
1788
1812
  this.#ruleValidator = new RuleValidator(context, diagnostics);
1813
+ if (this.#dynamicRuleInputs.length === 0) {
1814
+ checkPositionCardinalityInvariant(this.#staticRules, context);
1815
+ this.#matcher = new RuleMatcher(this.#staticRules);
1816
+ } else {
1817
+ this.#matcher = void 0;
1818
+ }
1789
1819
  }
1790
- evaluate(children) {
1820
+ /**
1821
+ * @param context Required when any rule has a `dynamic(...)` cardinality —
1822
+ * supplies the resolved tag/props those rules are evaluated against.
1823
+ */
1824
+ evaluate(children, context) {
1791
1825
  if (!this.active) return;
1826
+ const { rules, matcher } = this.#resolveRules(context);
1792
1827
  const {
1793
1828
  matrix,
1794
1829
  unexpectedIndices: rawUnexpectedIndices,
1795
1830
  ambiguousIndices
1796
- } = this.#matcher.match(children);
1797
- this.#ruleValidator.validate(this.#rules, matrix, children.length);
1831
+ } = matcher.match(children);
1832
+ this.#ruleValidator.validate(rules, matrix, children.length);
1798
1833
  const unexpectedIndices = new Set(
1799
1834
  [...rawUnexpectedIndices].filter(
1800
1835
  (ci) => isTextLike(children[ci]) ? this.#allowText === false : this.#exclusiveChildren
@@ -1808,11 +1843,28 @@ var ChildrenEvaluator = class extends InvariantBase {
1808
1843
  this.violate(ContractDiagnostics.unexpectedChild(typeName, ci, this.#context));
1809
1844
  } else {
1810
1845
  const matches = matrix.childToRules.forward.get(ci);
1811
- const names = [...matches].map((ri) => this.#ruleNames[ri] ?? `#${ri}`);
1846
+ const names = [...matches].map((ri) => rules[ri]?.name ?? `#${ri}`);
1812
1847
  this.violate(ContractDiagnostics.ambiguousChild(typeName, ci, names, this.#context));
1813
1848
  }
1814
1849
  });
1815
1850
  }
1851
+ #resolveRules(context) {
1852
+ if (this.#dynamicRuleInputs.length === 0) {
1853
+ return { rules: this.#staticRules, matcher: this.#matcher };
1854
+ }
1855
+ if (context === void 0) {
1856
+ throw new RangeError(
1857
+ `ChildrenEvaluator [${this.#context}]: rule(s) have a dynamic(...) cardinality \u2014 evaluate() requires a context argument to resolve them.`
1858
+ );
1859
+ }
1860
+ const resolvedDynamicRules = this.#dynamicRuleInputs.map((r) => {
1861
+ const cardinality = resolveRule(r.cardinality, context);
1862
+ return normalizeChildRule({ ...r, cardinality });
1863
+ });
1864
+ checkPositionCardinalityInvariant(resolvedDynamicRules, this.#context);
1865
+ const rules = [...this.#staticRules, ...resolvedDynamicRules];
1866
+ return { rules, matcher: new RuleMatcher(rules) };
1867
+ }
1816
1868
  };
1817
1869
 
1818
1870
  // ../../lib/contract/src/props/get-disabled-props.ts
@@ -1,5 +1,21 @@
1
1
  import { Diagnostics } from '../_shared/diagnostics.js';
2
- import { RequireAtLeastOne, Simplify } from 'type-fest';
2
+ import { RequireAtLeastOne, Simplify, ValueOf } from 'type-fest';
3
+
4
+ /**
5
+ * Canonical list of reserved layout prop names.
6
+ *
7
+ * This array is the single source of truth for every supported CSS `display`
8
+ * value exposed as a boolean prop. The `LayoutKey` type is derived directly
9
+ * from this list.
10
+ *
11
+ * To add a new display mode:
12
+ * 1. Add the display value here.
13
+ * 2. Register its layout family in `LAYOUT_FAMILY_MAP`.
14
+ *
15
+ * Prop names intentionally match the corresponding Tailwind/CSS display
16
+ * utilities, so no additional prop-to-class mapping is required.
17
+ */
18
+ declare const layoutKeys: readonly ["flex", "inline-flex", "grid", "inline-grid", "block", "inline-block", "inline", "hidden", "contents", "flow-root", "list-item", "table", "inline-table", "table-caption", "table-cell", "table-column", "table-column-group", "table-footer-group", "table-header-group", "table-row-group", "table-row"];
3
19
 
4
20
  type StringMap<T = unknown> = Record<string, T>;
5
21
  type AnyRecord = StringMap<unknown>;
@@ -94,35 +110,19 @@ type ClassPlugin<TProps extends AnyRecord = EmptyRecord> = Readonly<{
94
110
  readonly _pluginProps?: TProps;
95
111
  }>;
96
112
 
97
- /**
98
- * Canonical list of reserved layout prop names.
99
- *
100
- * This array is the single source of truth for every supported CSS `display`
101
- * value exposed as a boolean prop. The `LayoutKey` type is derived directly
102
- * from this list.
103
- *
104
- * To add a new display mode:
105
- * 1. Add the display value here.
106
- * 2. Register its layout family in `LAYOUT_FAMILY_MAP`.
107
- *
108
- * Prop names intentionally match the corresponding Tailwind/CSS display
109
- * utilities, so no additional prop-to-class mapping is required.
110
- */
111
- declare const layoutKeys: readonly ["flex", "inline-flex", "grid", "inline-grid", "block", "inline-block", "inline", "hidden", "contents", "flow-root", "list-item", "table", "inline-table", "table-caption", "table-cell", "table-column", "table-column-group", "table-footer-group", "table-header-group", "table-row-group", "table-row"];
112
-
113
113
  type TupleValues<T extends readonly unknown[]> = T[number];
114
- type ValueOf<T> = T[keyof T];
115
114
  type LayoutKey<T extends readonly string[]> = TupleValues<T>;
116
115
  type LayoutFamily<M extends StringMap<string>> = ValueOf<M>;
117
- type LayoutMode<T extends readonly string[]> = LayoutKey<T> | 'none';
116
+ type ResolvedLayout<T extends readonly string[]> = LayoutKey<T> | 'none';
118
117
  type ExclusiveTrueProp<K extends PropertyKey> = {
119
118
  [P in K]: Simplify<Record<P, true> & Partial<Record<Exclude<K, P>, never>>>;
120
119
  }[K];
121
120
  /**
122
- * Mutually exclusive display shorthand props.
121
+ * Mutually exclusive layout shorthand props.
123
122
  *
124
- * At most one key may be `true`. Passing multiple is a compile-time error; the
125
- * runtime also warns and lets the first key in declaration order take precedence.
123
+ * Exactly one layout prop may be `true`, or none at all. Multiple `true`
124
+ * props produce a compile-time error. If invalid props reach runtime, the
125
+ * resolver warns and uses the first declared layout.
126
126
  */
127
127
  type LayoutProps<T extends readonly string[]> = ExclusiveTrueProp<LayoutKey<T>> | Partial<Record<LayoutKey<T>, never>>;
128
128
 
@@ -155,23 +155,76 @@ type Token<TKind extends string, TData extends object = EmptyRecord> = {
155
155
  kind: TKind;
156
156
  raw: string;
157
157
  } & TData;
158
- type LayoutToken = Token<'layout', {
159
- value: LayoutKey<typeof layoutKeys>;
160
- }>;
161
- type ConditionalToken = Token<'conditional', {
162
- requires: Exclude<LayoutFamily<typeof LAYOUT_FAMILY_MAP>, 'none'>;
163
- }>;
164
- type GapToken = Token<'gap'>;
165
- type UtilityToken = Token<'utility', {
166
- base: string;
167
- }>;
168
- type ClassifiedToken = Simplify<LayoutToken | ConditionalToken | GapToken | UtilityToken>;
169
-
170
- type VariantSelection = Record<string, string>;
158
+ type TokenData = {
159
+ layout: {
160
+ value: LayoutKey<typeof layoutKeys>;
161
+ };
162
+ conditional: {
163
+ requires: Exclude<LayoutFamily<typeof LAYOUT_FAMILY_MAP>, 'none'>;
164
+ };
165
+ gap: EmptyRecord;
166
+ shared: EmptyRecord;
167
+ utility: {
168
+ base: string;
169
+ };
170
+ };
171
+ type TokenMap = {
172
+ [K in keyof TokenData]: Token<K, TokenData[K]>;
173
+ };
174
+ type LayoutToken = TokenMap['layout'];
175
+ type ConditionalToken = TokenMap['conditional'];
176
+ type GapToken = TokenMap['gap'];
177
+ type SharedToken = TokenMap['shared'];
178
+ type UtilityToken = TokenMap['utility'];
179
+ type ClassifiedToken = Simplify<ValueOf<TokenMap>>;
180
+
181
+ type VariantSelection = StringMap<string>;
171
182
  type CompoundVariant = {
172
183
  class?: unknown;
173
184
  } & AnyRecord;
174
185
 
186
+ /**
187
+ * The resolved display mode for a single render.
188
+ *
189
+ * Mode is owned by the display props; a display class literal in the resolved
190
+ * class string is a reserved-literal authoring mistake. Defaults to `'none'`
191
+ * when no prop is set.
192
+ *
193
+ * `family` is derived from mode: `'flex'` for flex/inline-flex, `'grid'` for
194
+ * grid/inline-grid, `'none'` for all other values (and when no prop is set).
195
+ * The evaluator uses family — not mode — for utility and gap filtering.
196
+ */
197
+ declare class LayoutState {
198
+ #private;
199
+ constructor(mode: ResolvedLayout<typeof layoutKeys>);
200
+ get mode(): ResolvedLayout<typeof layoutKeys>;
201
+ get family(): LayoutFamily<typeof LAYOUT_FAMILY_MAP>;
202
+ }
203
+
204
+ type PipelineLayoutProps = LayoutProps<typeof layoutKeys>;
205
+ type PipelineLayout = ResolvedLayout<typeof layoutKeys>;
206
+ type PipelineProps = PipelineLayoutProps & AnyRecord;
207
+ interface PipelineInputs {
208
+ readonly props: PipelineProps;
209
+ readonly recipe: string | undefined;
210
+ }
211
+ interface PipelineResolution {
212
+ readonly mode: PipelineLayout;
213
+ readonly state: LayoutState;
214
+ }
215
+ interface PipelineTokens {
216
+ readonly filtered: ClassifiedToken[];
217
+ readonly tokens: ClassifiedToken[];
218
+ }
219
+ type TailwindPipelineArgs = [
220
+ tag: unknown,
221
+ props: PipelineInputs['props'],
222
+ className: ClassName | undefined,
223
+ recipe: PipelineInputs['recipe']
224
+ ];
225
+ interface TailwindPipelineContext extends PipelineInputs, PipelineResolution, PipelineTokens {
226
+ }
227
+
175
228
  /**
176
229
  * Layout-aware class pipeline for Tailwind CSS utility class strings.
177
230
  *
@@ -220,28 +273,10 @@ declare class ClassClassifier {
220
273
  type DependencyRules = Record<Exclude<LayoutFamily<typeof LAYOUT_FAMILY_MAP>, 'none'>, readonly RegExp[]>;
221
274
  declare const defaultDependencyRules: DependencyRules;
222
275
 
223
- /**
224
- * The resolved display mode for a single render.
225
- *
226
- * Mode is owned by the display props; a display class literal in the resolved
227
- * class string is a reserved-literal authoring mistake. Defaults to `'none'`
228
- * when no prop is set.
229
- *
230
- * `family` is derived from mode: `'flex'` for flex/inline-flex, `'grid'` for
231
- * grid/inline-grid, `'none'` for all other values (and when no prop is set).
232
- * The evaluator uses family — not mode — for utility and gap filtering.
233
- */
234
- declare class LayoutState {
235
- #private;
236
- constructor(mode: LayoutMode<typeof layoutKeys>);
237
- get mode(): LayoutMode<typeof layoutKeys>;
238
- get family(): LayoutFamily<typeof LAYOUT_FAMILY_MAP>;
239
- }
240
-
241
276
  declare class DependencyEvaluator {
242
277
  private readonly rules;
243
278
  constructor(rules: DependencyRules);
244
279
  evaluate(token: ClassifiedToken, state: LayoutState): boolean;
245
280
  }
246
281
 
247
- export { ClassBuilder, ClassClassifier, type ClassToken, type ClassifiedToken, type CompoundVariant, type ConditionalToken, DependencyEvaluator, type DependencyRules, type GapToken, type LayoutFamily, type LayoutKey, type LayoutMode, type LayoutProps, LayoutState, type LayoutToken, type UtilityToken, type VariantSelection, createTailwindPipeline, defaultDependencyRules, layoutKeys };
282
+ export { ClassBuilder, ClassClassifier, type ClassToken, type ClassifiedToken, type CompoundVariant, type ConditionalToken, DependencyEvaluator, type DependencyRules, type GapToken, type LayoutFamily, type LayoutKey, type LayoutProps, LayoutState, type LayoutToken, type ResolvedLayout, type SharedToken, type TailwindPipelineArgs, type TailwindPipelineContext, type UtilityToken, type VariantSelection, createTailwindPipeline, defaultDependencyRules, layoutKeys };