praxis-kit 5.0.0 → 6.1.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.
@@ -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)}`);
@@ -626,6 +639,45 @@ var iterate = Object.freeze({
626
639
  values
627
640
  });
628
641
 
642
+ // ../../lib/primitive/src/utils/lru-cache.ts
643
+ var LRUCache = class {
644
+ #maxSize;
645
+ #store = /* @__PURE__ */ new Map();
646
+ constructor(maxSize) {
647
+ if (!Number.isInteger(maxSize) || maxSize < 1) {
648
+ throw new RangeError("LRUCache maxSize must be a positive integer.");
649
+ }
650
+ this.#maxSize = maxSize;
651
+ }
652
+ get(key) {
653
+ if (!this.#store.has(key)) return void 0;
654
+ const value = this.#store.get(key);
655
+ this.#store.delete(key);
656
+ this.#store.set(key, value);
657
+ return value;
658
+ }
659
+ set(key, value) {
660
+ this.#store.delete(key);
661
+ this.#store.set(key, value);
662
+ if (this.#store.size > this.#maxSize) {
663
+ const lru = this.#store.keys().next().value;
664
+ if (lru !== void 0) this.#store.delete(lru);
665
+ }
666
+ }
667
+ has(key) {
668
+ return this.#store.has(key);
669
+ }
670
+ delete(key) {
671
+ return this.#store.delete(key);
672
+ }
673
+ get size() {
674
+ return this.#store.size;
675
+ }
676
+ clear() {
677
+ this.#store.clear();
678
+ }
679
+ };
680
+
629
681
  // ../../lib/primitive/src/utils/merge-props.ts
630
682
  function mergeProps(defaultProps, props) {
631
683
  return {
@@ -634,28 +686,6 @@ function mergeProps(defaultProps, props) {
634
686
  };
635
687
  }
636
688
 
637
- // ../../lib/contract/src/strict/invariant-base.ts
638
- var InvariantBase = class {
639
- diagnostics;
640
- constructor(diagnostics) {
641
- this.diagnostics = diagnostics;
642
- }
643
- get active() {
644
- return this.diagnostics.active;
645
- }
646
- violate(input) {
647
- this.diagnostics.error(input);
648
- }
649
- // Always caps at warn — never throws. ARIA 'warning' violations route here
650
- // so they surface even in strict='throw' mode without aborting a render.
651
- warn(input) {
652
- this.diagnostics.warn(input);
653
- }
654
- invariant(condition, input) {
655
- if (!condition) this.violate(input);
656
- }
657
- };
658
-
659
689
  // ../../lib/contract/src/diagnostics/aria.ts
660
690
  import { DiagnosticCategory, DiagnosticCode } from "../_shared/diagnostics.js";
661
691
  var AriaDiagnostics = {
@@ -1012,6 +1042,28 @@ var SlotDiagnostics = {
1012
1042
  }
1013
1043
  };
1014
1044
 
1045
+ // ../../lib/contract/src/strict/invariant-base.ts
1046
+ var InvariantBase = class {
1047
+ diagnostics;
1048
+ constructor(diagnostics) {
1049
+ this.diagnostics = diagnostics;
1050
+ }
1051
+ get active() {
1052
+ return this.diagnostics.active;
1053
+ }
1054
+ violate(input) {
1055
+ this.diagnostics.error(input);
1056
+ }
1057
+ // Always caps at warn — never throws. ARIA 'warning' violations route here
1058
+ // so they surface even in strict='throw' mode without aborting a render.
1059
+ warn(input) {
1060
+ this.diagnostics.warn(input);
1061
+ }
1062
+ invariant(condition, input) {
1063
+ if (!condition) this.violate(input);
1064
+ }
1065
+ };
1066
+
1015
1067
  // ../../lib/contract/src/aria/polymorphic-validator.ts
1016
1068
  var VALID = [{ valid: true }];
1017
1069
  function isIntrinsicTag(tag) {
@@ -1023,8 +1075,7 @@ function omitProp(obj, key) {
1023
1075
  }
1024
1076
  var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1025
1077
  #extraRules;
1026
- #planCache = /* @__PURE__ */ new Map();
1027
- static #MAX_CACHE = 100;
1078
+ #planCache = new LRUCache(100);
1028
1079
  // Memoized AriaFix objects keyed by attribute name — the ARIA attribute set is
1029
1080
  // finite so this Map is bounded and avoids recreating closures on every cache miss.
1030
1081
  static #removeAttributeFixCache = /* @__PURE__ */ new Map();
@@ -1180,8 +1231,6 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1180
1231
  if (!isNull(key)) {
1181
1232
  const cached = this.#planCache.get(key);
1182
1233
  if (cached !== void 0) {
1183
- this.#planCache.delete(key);
1184
- this.#planCache.set(key, cached);
1185
1234
  if (cached.violations.length > 0) this.report(cached.violations);
1186
1235
  return {
1187
1236
  props: _AriaPolicyEngine.#applyPlan(props, cached.removals, cached.updates),
@@ -1198,10 +1247,6 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1198
1247
  );
1199
1248
  const plan = { removals, updates, violations: result.violations };
1200
1249
  this.#planCache.set(key, plan);
1201
- if (this.#planCache.size > _AriaPolicyEngine.#MAX_CACHE) {
1202
- const lru = this.#planCache.keys().next().value;
1203
- if (lru !== void 0) this.#planCache.delete(lru);
1204
- }
1205
1250
  }
1206
1251
  return result;
1207
1252
  }
@@ -1857,10 +1902,22 @@ var RuleValidator = class _RuleValidator extends InvariantBase {
1857
1902
 
1858
1903
  // ../../lib/contract/src/children/children-evaluator.ts
1859
1904
  var isTextLike = (child) => isString(child) || isNumber(child);
1905
+ function checkPositionCardinalityInvariant(rules, context) {
1906
+ iterate.forEach(rules, (rule) => {
1907
+ const { name, position, cardinality } = rule;
1908
+ if ((position === "first" || position === "last") && (cardinality.kind === "unbounded" || cardinality.max > 1)) {
1909
+ throw new RangeError(
1910
+ `ChildrenEvaluator [${context}]: rule "${name}" sets position="${position}" with an unbound or >1 max. position="first|last" implies max=1.`
1911
+ );
1912
+ }
1913
+ });
1914
+ }
1860
1915
  var ChildrenEvaluator = class extends InvariantBase {
1861
1916
  #context;
1862
- #rules;
1863
- #ruleNames;
1917
+ /** Rules with a static cardinality — normalized once, reused on every evaluate() call. */
1918
+ #staticRules;
1919
+ /** Rules whose cardinality is `dynamic(...)` — re-resolved against a ChildRuleContext per call. */
1920
+ #dynamicRuleInputs;
1864
1921
  #matcher;
1865
1922
  #ruleValidator;
1866
1923
  #exclusiveChildren;
@@ -1868,29 +1925,39 @@ var ChildrenEvaluator = class extends InvariantBase {
1868
1925
  constructor(rules, diagnostics, context = "Component", options = {}) {
1869
1926
  super(diagnostics);
1870
1927
  this.#context = context;
1871
- this.#rules = rules.map((r) => normalizeChildRule(r));
1872
- this.#ruleNames = this.#rules.map((r) => r.name);
1873
1928
  this.#exclusiveChildren = options.exclusiveChildren ?? false;
1874
1929
  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
- }
1930
+ const staticRuleInputs = [];
1931
+ const dynamicRuleInputs = [];
1932
+ iterate.forEach(rules, (rule) => {
1933
+ if (isDynamicRule(rule.cardinality)) dynamicRuleInputs.push(rule);
1934
+ else staticRuleInputs.push(rule);
1882
1935
  });
1883
- this.#matcher = new RuleMatcher(this.#rules);
1936
+ this.#dynamicRuleInputs = dynamicRuleInputs;
1937
+ this.#staticRules = staticRuleInputs.map(
1938
+ (r) => normalizeChildRule(r)
1939
+ );
1884
1940
  this.#ruleValidator = new RuleValidator(context, diagnostics);
1941
+ if (this.#dynamicRuleInputs.length === 0) {
1942
+ checkPositionCardinalityInvariant(this.#staticRules, context);
1943
+ this.#matcher = new RuleMatcher(this.#staticRules);
1944
+ } else {
1945
+ this.#matcher = void 0;
1946
+ }
1885
1947
  }
1886
- evaluate(children) {
1948
+ /**
1949
+ * @param context Required when any rule has a `dynamic(...)` cardinality —
1950
+ * supplies the resolved tag/props those rules are evaluated against.
1951
+ */
1952
+ evaluate(children, context) {
1887
1953
  if (!this.active) return;
1954
+ const { rules, matcher } = this.#resolveRules(context);
1888
1955
  const {
1889
1956
  matrix,
1890
1957
  unexpectedIndices: rawUnexpectedIndices,
1891
1958
  ambiguousIndices
1892
- } = this.#matcher.match(children);
1893
- this.#ruleValidator.validate(this.#rules, matrix, children.length);
1959
+ } = matcher.match(children);
1960
+ this.#ruleValidator.validate(rules, matrix, children.length);
1894
1961
  const unexpectedIndices = new Set(
1895
1962
  [...rawUnexpectedIndices].filter(
1896
1963
  (ci) => isTextLike(children[ci]) ? this.#allowText === false : this.#exclusiveChildren
@@ -1904,11 +1971,28 @@ var ChildrenEvaluator = class extends InvariantBase {
1904
1971
  this.violate(ContractDiagnostics.unexpectedChild(typeName, ci, this.#context));
1905
1972
  } else {
1906
1973
  const matches = matrix.childToRules.forward.get(ci);
1907
- const names = [...matches].map((ri) => this.#ruleNames[ri] ?? `#${ri}`);
1974
+ const names = [...matches].map((ri) => rules[ri]?.name ?? `#${ri}`);
1908
1975
  this.violate(ContractDiagnostics.ambiguousChild(typeName, ci, names, this.#context));
1909
1976
  }
1910
1977
  });
1911
1978
  }
1979
+ #resolveRules(context) {
1980
+ if (this.#dynamicRuleInputs.length === 0) {
1981
+ return { rules: this.#staticRules, matcher: this.#matcher };
1982
+ }
1983
+ if (context === void 0) {
1984
+ throw new RangeError(
1985
+ `ChildrenEvaluator [${this.#context}]: rule(s) have a dynamic(...) cardinality \u2014 evaluate() requires a context argument to resolve them.`
1986
+ );
1987
+ }
1988
+ const resolvedDynamicRules = this.#dynamicRuleInputs.map((r) => {
1989
+ const cardinality = resolveRule(r.cardinality, context);
1990
+ return normalizeChildRule({ ...r, cardinality });
1991
+ });
1992
+ checkPositionCardinalityInvariant(resolvedDynamicRules, this.#context);
1993
+ const rules = [...this.#staticRules, ...resolvedDynamicRules];
1994
+ return { rules, matcher: new RuleMatcher(rules) };
1995
+ }
1912
1996
  };
1913
1997
 
1914
1998
  // ../../lib/contract/src/props/get-disabled-props.ts
@@ -2237,7 +2321,7 @@ function cva2(base, config) {
2237
2321
  // ../../lib/styling/src/static-class-resolver.ts
2238
2322
  var StaticClassResolver = class {
2239
2323
  #baseClass;
2240
- #cache = /* @__PURE__ */ new Map();
2324
+ #cache = new LRUCache(200);
2241
2325
  #resolveTag;
2242
2326
  constructor(baseClass, tagMap) {
2243
2327
  this.#baseClass = Array.isArray(baseClass) ? baseClass.join(" ") : baseClass;
@@ -2251,17 +2335,9 @@ var StaticClassResolver = class {
2251
2335
  resolve(tag, skipTagMap = false) {
2252
2336
  if (typeof tag !== "string" || skipTagMap) return this.#baseClass;
2253
2337
  const cached = this.#cache.get(tag);
2254
- if (cached !== void 0) {
2255
- this.#cache.delete(tag);
2256
- this.#cache.set(tag, cached);
2257
- return cached;
2258
- }
2338
+ if (cached !== void 0) return cached;
2259
2339
  const result = this.#resolveTag(tag);
2260
2340
  this.#cache.set(tag, result);
2261
- if (this.#cache.size > 200) {
2262
- const lru = this.#cache.keys().next().value;
2263
- if (lru !== void 0) this.#cache.delete(lru);
2264
- }
2265
2341
  return result;
2266
2342
  }
2267
2343
  };
@@ -2272,7 +2348,7 @@ var VariantClassResolver = class _VariantClassResolver {
2272
2348
  #recipeMap;
2273
2349
  #variantKeys;
2274
2350
  #precomputedClasses;
2275
- #cache = /* @__PURE__ */ new Map();
2351
+ #cache = new LRUCache(1e3);
2276
2352
  constructor(cvaFn, recipeMap, variantKeys, precomputedClasses) {
2277
2353
  this.#cvaFn = cvaFn ?? null;
2278
2354
  this.#recipeMap = Object.freeze(recipeMap ?? {});
@@ -2287,17 +2363,9 @@ var VariantClassResolver = class _VariantClassResolver {
2287
2363
  if (precomputed !== void 0) return precomputed;
2288
2364
  }
2289
2365
  const cached = this.#cache.get(cacheKey);
2290
- if (cached !== void 0) {
2291
- this.#cache.delete(cacheKey);
2292
- this.#cache.set(cacheKey, cached);
2293
- return cached;
2294
- }
2366
+ if (cached !== void 0) return cached;
2295
2367
  const result = this.#compute(props, recipe);
2296
2368
  this.#cache.set(cacheKey, result);
2297
- if (this.#cache.size > 1e3) {
2298
- const lru = this.#cache.keys().next().value;
2299
- if (lru !== void 0) this.#cache.delete(lru);
2300
- }
2301
2369
  return result;
2302
2370
  }
2303
2371
  #compute(props, recipe) {
@@ -2769,7 +2837,10 @@ function render({
2769
2837
  createEffect(() => enforceAllowedAs(tag(), allowedAs, runtime.options.diagnostics, runtime.options.displayName));
2770
2838
  }
2771
2839
  if (process.env.NODE_ENV !== "production" && childrenEvaluator) {
2772
- createEffect(() => childrenEvaluator.evaluate(toChildArray(known.children)));
2840
+ createEffect(() => childrenEvaluator.evaluate(toChildArray(known.children), {
2841
+ tag: tag(),
2842
+ props: normalizedProps()
2843
+ }));
2773
2844
  }
2774
2845
  if (process.env.NODE_ENV !== "production") {
2775
2846
  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>>;