praxis-kit 6.0.0 → 6.1.1

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.
@@ -1,18 +1,6 @@
1
1
  // ../../lib/primitive/src/guards/children/component-id.ts
2
2
  var COMPONENT_DEFAULT_TAG = /* @__PURE__ */ Symbol.for("praxis.component-default-tag");
3
3
 
4
- // ../../lib/primitive/src/utils/is-object.ts
5
- function isObject(value, excludeArrays = false) {
6
- if (value === null || typeof value !== "object") return false;
7
- return excludeArrays ? !Array.isArray(value) : true;
8
- }
9
- function isString(value) {
10
- return typeof value === "string";
11
- }
12
- function isNumber(value) {
13
- return typeof value === "number";
14
- }
15
-
16
4
  // ../../lib/primitive/src/guards/foundational/is-defined.ts
17
5
  function isUndefined(value) {
18
6
  return value === void 0;
@@ -22,16 +10,26 @@ function isUndefined(value) {
22
10
  function isNull(value) {
23
11
  return value === null;
24
12
  }
13
+ function isNonNull(value) {
14
+ return value != null;
15
+ }
25
16
 
26
- // ../../lib/primitive/src/merge/constants.ts
27
- var EVENT_HANDLER_RE = /^on[A-Z]/;
28
-
29
- // ../../lib/primitive/src/merge/predicates.ts
17
+ // ../../lib/primitive/src/utils/type-guards.ts
18
+ function isObject(value, excludeArrays = false) {
19
+ if (value === null || typeof value !== "object") return false;
20
+ return excludeArrays ? !Array.isArray(value) : true;
21
+ }
22
+ function isString(value) {
23
+ return typeof value === "string";
24
+ }
25
+ function isNumber(value) {
26
+ return typeof value === "number";
27
+ }
30
28
  function isFunction(value) {
31
29
  return typeof value === "function";
32
30
  }
33
31
  function isPlainObject(value) {
34
- if (!isObject(value)) return false;
32
+ if (!isObject(value, true)) return false;
35
33
  const proto = Object.getPrototypeOf(value);
36
34
  return proto === Object.prototype || proto === null;
37
35
  }
@@ -472,6 +470,9 @@ function makeResolveTag(defaultTag) {
472
470
  };
473
471
  }
474
472
 
473
+ // ../../lib/primitive/src/merge/constants.ts
474
+ var EVENT_HANDLER_RE = /^on[A-Z]/;
475
+
475
476
  // ../../lib/primitive/src/rule/rule-brand.ts
476
477
  var RULE_BRAND = /* @__PURE__ */ Symbol("praxis-kit/dynamic-rule");
477
478
 
@@ -666,14 +667,53 @@ var iterate = Object.freeze({
666
667
  values
667
668
  });
668
669
 
670
+ // ../../lib/primitive/src/utils/lru-cache.ts
671
+ var LRUCache = class {
672
+ #maxSize;
673
+ #store = /* @__PURE__ */ new Map();
674
+ constructor(maxSize) {
675
+ if (!Number.isInteger(maxSize) || maxSize < 1) {
676
+ throw new RangeError("LRUCache maxSize must be a positive integer.");
677
+ }
678
+ this.#maxSize = maxSize;
679
+ }
680
+ get(key) {
681
+ if (!this.#store.has(key)) return void 0;
682
+ const value = this.#store.get(key);
683
+ this.#store.delete(key);
684
+ this.#store.set(key, value);
685
+ return value;
686
+ }
687
+ set(key, value) {
688
+ this.#store.delete(key);
689
+ this.#store.set(key, value);
690
+ if (this.#store.size > this.#maxSize) {
691
+ const lru = this.#store.keys().next().value;
692
+ if (lru !== void 0) this.#store.delete(lru);
693
+ }
694
+ }
695
+ has(key) {
696
+ return this.#store.has(key);
697
+ }
698
+ delete(key) {
699
+ return this.#store.delete(key);
700
+ }
701
+ get size() {
702
+ return this.#store.size;
703
+ }
704
+ clear() {
705
+ this.#store.clear();
706
+ }
707
+ };
708
+
669
709
  // ../../lib/primitive/src/utils/merge-refs.ts
670
710
  function mergeRefsCore(...refs) {
671
- const active = refs.filter((r) => r != null);
672
- if (active.length === 0) return null;
673
- if (active.length === 1) return active[0];
711
+ const resolvedRefs = refs.filter((r) => r != null);
712
+ if (resolvedRefs.length === 0) return null;
713
+ if (resolvedRefs.length === 1) return resolvedRefs[0] ?? null;
674
714
  return (value) => {
675
- iterate.forEach(active, (ref) => {
676
- if (typeof ref === "function") {
715
+ iterate.forEach(resolvedRefs, (ref) => {
716
+ if (isFunction(ref)) {
677
717
  ref(value);
678
718
  } else {
679
719
  ref.current = value;
@@ -690,28 +730,6 @@ function mergeProps(defaultProps, props) {
690
730
  };
691
731
  }
692
732
 
693
- // ../../lib/contract/src/strict/invariant-base.ts
694
- var InvariantBase = class {
695
- diagnostics;
696
- constructor(diagnostics) {
697
- this.diagnostics = diagnostics;
698
- }
699
- get active() {
700
- return this.diagnostics.active;
701
- }
702
- violate(input) {
703
- this.diagnostics.error(input);
704
- }
705
- // Always caps at warn — never throws. ARIA 'warning' violations route here
706
- // so they surface even in strict='throw' mode without aborting a render.
707
- warn(input) {
708
- this.diagnostics.warn(input);
709
- }
710
- invariant(condition, input) {
711
- if (!condition) this.violate(input);
712
- }
713
- };
714
-
715
733
  // ../../lib/contract/src/diagnostics/aria.ts
716
734
  import { DiagnosticCategory, DiagnosticCode } from "../_shared/diagnostics.js";
717
735
  var AriaDiagnostics = {
@@ -1068,8 +1086,30 @@ var SlotDiagnostics = {
1068
1086
  }
1069
1087
  };
1070
1088
 
1089
+ // ../../lib/contract/src/strict/invariant-base.ts
1090
+ var InvariantBase = class {
1091
+ diagnostics;
1092
+ constructor(diagnostics) {
1093
+ this.diagnostics = diagnostics;
1094
+ }
1095
+ get active() {
1096
+ return this.diagnostics.active;
1097
+ }
1098
+ violate(input) {
1099
+ this.diagnostics.error(input);
1100
+ }
1101
+ // Always caps at warn — never throws. ARIA 'warning' violations route here
1102
+ // so they surface even in strict='throw' mode without aborting a render.
1103
+ warn(input) {
1104
+ this.diagnostics.warn(input);
1105
+ }
1106
+ invariant(condition, input) {
1107
+ if (!condition) this.violate(input);
1108
+ }
1109
+ };
1110
+
1071
1111
  // ../../lib/contract/src/aria/polymorphic-validator.ts
1072
- var VALID = [{ valid: true }];
1112
+ var NO_VIOLATIONS = [{ valid: true }];
1073
1113
  function isIntrinsicTag(tag) {
1074
1114
  return isString(tag);
1075
1115
  }
@@ -1079,8 +1119,7 @@ function omitProp(obj, key) {
1079
1119
  }
1080
1120
  var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1081
1121
  #extraRules;
1082
- #planCache = /* @__PURE__ */ new Map();
1083
- static #MAX_CACHE = 100;
1122
+ #planCache = new LRUCache(100);
1084
1123
  // Memoized AriaFix objects keyed by attribute name — the ARIA attribute set is
1085
1124
  // finite so this Map is bounded and avoids recreating closures on every cache miss.
1086
1125
  static #removeAttributeFixCache = /* @__PURE__ */ new Map();
@@ -1112,17 +1151,20 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1112
1151
  static #deriveContext(tag, props) {
1113
1152
  if (!isIntrinsicTag(tag)) return { proceed: false, result: { props, violations: [] } };
1114
1153
  const implicitRole = getImplicitRole(tag, props);
1115
- const hasRole2 = implicitRole != null || isString(props.role) && props.role.length > 0;
1154
+ const hasRole2 = isNonNull(implicitRole) || isString(props.role) && props.role.length > 0;
1116
1155
  if (!hasRole2) return { proceed: false, result: { props, violations: [] } };
1117
1156
  const normalized = _AriaPolicyEngine.#normalizeEmptyRole(tag, props);
1118
- if (normalized.normalized) return { proceed: false, result: normalized.result };
1119
- const effectiveRole = props.role ?? implicitRole;
1157
+ const workingProps = normalized.normalized ? normalized.result.props : props;
1158
+ const preExistingViolations = normalized.normalized ? normalized.result.violations : [];
1159
+ const effectiveRole = workingProps.role ?? implicitRole;
1120
1160
  return {
1121
1161
  proceed: true,
1122
1162
  tag,
1123
1163
  implicitRole,
1124
1164
  effectiveRole,
1125
- context: { tag, props, implicitRole, effectiveRole }
1165
+ props: workingProps,
1166
+ preExistingViolations,
1167
+ context: { tag, props: workingProps, implicitRole, effectiveRole }
1126
1168
  };
1127
1169
  }
1128
1170
  static #runRules(rules, context) {
@@ -1137,7 +1179,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1137
1179
  } = context;
1138
1180
  const { message, attribute, severity } = result;
1139
1181
  const resolvedMessage = message ?? result.diagnostic?.message;
1140
- const fallbackDiag = resolvedMessage == null ? AriaDiagnostics.invalidRole(role, tag) : void 0;
1182
+ const fallbackDiag = isNonNull(resolvedMessage) ? void 0 : AriaDiagnostics.invalidRole(role, tag);
1141
1183
  violations.push({
1142
1184
  message: resolvedMessage ?? fallbackDiag.message,
1143
1185
  tag,
@@ -1145,8 +1187,8 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1145
1187
  attribute,
1146
1188
  severity,
1147
1189
  phase: "evaluate",
1148
- ...result.diagnostic != null && { diagnostic: result.diagnostic },
1149
- ...fallbackDiag != null && { diagnostic: fallbackDiag }
1190
+ ...isNonNull(result.diagnostic) && { diagnostic: result.diagnostic },
1191
+ ...isNonNull(fallbackDiag) && { diagnostic: fallbackDiag }
1150
1192
  });
1151
1193
  if (result.fixable) fixes.push(result.fix);
1152
1194
  });
@@ -1154,7 +1196,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1154
1196
  return { violations, fixes };
1155
1197
  }
1156
1198
  static #getRules(context) {
1157
- if (_AriaPolicyEngine.#hasRole(context.props) || context.effectiveRole != null && _AriaPolicyEngine.#LIVE_REGION_ROLES.has(context.effectiveRole)) {
1199
+ if (_AriaPolicyEngine.#hasRole(context.props) || isNonNull(context.effectiveRole) && _AriaPolicyEngine.#LIVE_REGION_ROLES.has(context.effectiveRole)) {
1158
1200
  return _AriaPolicyEngine.#pipeline;
1159
1201
  }
1160
1202
  return _AriaPolicyEngine.#implicitOnlyRules;
@@ -1162,24 +1204,36 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1162
1204
  static evaluate(tag, props) {
1163
1205
  const derived = _AriaPolicyEngine.#deriveContext(tag, props);
1164
1206
  if (!derived.proceed) return derived.result;
1165
- const { tag: narrowedTag, implicitRole, context } = derived;
1207
+ const {
1208
+ tag: narrowedTag,
1209
+ implicitRole,
1210
+ context,
1211
+ props: workingProps,
1212
+ preExistingViolations
1213
+ } = derived;
1166
1214
  const { violations, fixes } = _AriaPolicyEngine.#runRules(
1167
1215
  _AriaPolicyEngine.#getRules(context),
1168
1216
  context
1169
1217
  );
1170
- const next = _AriaPolicyEngine.#applyFixes(narrowedTag, implicitRole, props, fixes);
1171
- return { props: next, violations };
1218
+ const next = _AriaPolicyEngine.#applyFixes(narrowedTag, implicitRole, workingProps, fixes);
1219
+ return { props: next, violations: [...preExistingViolations, ...violations] };
1172
1220
  }
1173
1221
  static #evaluateWithRules(tag, props, extraRules) {
1174
1222
  const derived = _AriaPolicyEngine.#deriveContext(tag, props);
1175
1223
  if (!derived.proceed) return derived.result;
1176
- const { tag: narrowedTag, implicitRole, context } = derived;
1224
+ const {
1225
+ tag: narrowedTag,
1226
+ implicitRole,
1227
+ context,
1228
+ props: workingProps,
1229
+ preExistingViolations
1230
+ } = derived;
1177
1231
  const { violations, fixes } = _AriaPolicyEngine.#runRules(
1178
1232
  [..._AriaPolicyEngine.#getRules(context), ...extraRules],
1179
1233
  context
1180
1234
  );
1181
- const next = _AriaPolicyEngine.#applyFixes(narrowedTag, implicitRole, props, fixes);
1182
- return { props: next, violations };
1235
+ const next = _AriaPolicyEngine.#applyFixes(narrowedTag, implicitRole, workingProps, fixes);
1236
+ return { props: next, violations: [...preExistingViolations, ...violations] };
1183
1237
  }
1184
1238
  report(violations) {
1185
1239
  iterate.forEach(violations, (v) => {
@@ -1188,12 +1242,12 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1188
1242
  else this.warn(d);
1189
1243
  });
1190
1244
  }
1191
- // Cache key covers only the aria-relevant subset of props (tag + role + aria-* attrs).
1192
- // Non-aria props (className, onClick, etc.) do not affect ARIA decisions and are excluded
1193
- // so cache hits survive re-renders that only change non-aria props.
1194
- // Note: #extraRules are NOT included in the key each engine instance has its own Map,
1195
- // so two engines with different rules never share cache entries. If caching ever becomes
1196
- // static/shared, rule identity would need to be folded into the key.
1245
+ // Cache key covers only the aria-relevant subset of props (tag + role + aria-* attrs)
1246
+ // exactly what the built-in pipeline reads. Non-aria props (className, onClick, etc.) do
1247
+ // not affect built-in ARIA decisions and are excluded so cache hits survive re-renders
1248
+ // that only change non-aria props. This key alone is unsound for #extraRules, which may
1249
+ // read arbitrary props outside this set validate() extends it with #extraRulesKeySuffix,
1250
+ // or bypasses the cache, to account for that.
1197
1251
  static #createPlanKey(tag, props) {
1198
1252
  if (!isIntrinsicTag(tag)) return null;
1199
1253
  const parts = [tag];
@@ -1209,6 +1263,23 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1209
1263
  if (ariaEntries.length > 0) parts.push(...ariaEntries.sort());
1210
1264
  return parts.join("|");
1211
1265
  }
1266
+ // Extends the base cache key with the props each extra rule declares it reads (`readsProps`).
1267
+ // Returns null — meaning "don't cache" — if any extra rule omits `readsProps` (it may read
1268
+ // arbitrary props the key can't account for) or if a declared prop's value isn't a primitive
1269
+ // (object/array identity isn't stably representable in a string key).
1270
+ static #extraRulesKeySuffix(extraRules, props) {
1271
+ const parts = [];
1272
+ for (const rule of extraRules) {
1273
+ const readsProps = rule.readsProps;
1274
+ if (!isNonNull(readsProps)) return null;
1275
+ for (const propKey of readsProps) {
1276
+ const v = props[propKey];
1277
+ if (v !== void 0 && !isString(v) && !isNumber(v) && typeof v !== "boolean") return null;
1278
+ parts.push(`x:${propKey}:${String(v)}`);
1279
+ }
1280
+ }
1281
+ return parts.sort().join("|");
1282
+ }
1212
1283
  static #computePlan(inputProps, resultProps) {
1213
1284
  const removals = /* @__PURE__ */ new Set();
1214
1285
  const updates = {};
@@ -1232,12 +1303,15 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1232
1303
  return next;
1233
1304
  }
1234
1305
  validate(tag, props) {
1235
- const key = _AriaPolicyEngine.#createPlanKey(tag, props);
1306
+ const baseKey = _AriaPolicyEngine.#createPlanKey(tag, props);
1307
+ let key = baseKey;
1308
+ if (this.#extraRules.length > 0) {
1309
+ const suffix = _AriaPolicyEngine.#extraRulesKeySuffix(this.#extraRules, props);
1310
+ key = isNonNull(baseKey) && isNonNull(suffix) ? `${baseKey}|${suffix}` : null;
1311
+ }
1236
1312
  if (!isNull(key)) {
1237
1313
  const cached = this.#planCache.get(key);
1238
1314
  if (cached !== void 0) {
1239
- this.#planCache.delete(key);
1240
- this.#planCache.set(key, cached);
1241
1315
  if (cached.violations.length > 0) this.report(cached.violations);
1242
1316
  return {
1243
1317
  props: _AriaPolicyEngine.#applyPlan(props, cached.removals, cached.updates),
@@ -1254,10 +1328,6 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1254
1328
  );
1255
1329
  const plan = { removals, updates, violations: result.violations };
1256
1330
  this.#planCache.set(key, plan);
1257
- if (this.#planCache.size > _AriaPolicyEngine.#MAX_CACHE) {
1258
- const lru = this.#planCache.keys().next().value;
1259
- if (lru !== void 0) this.#planCache.delete(lru);
1260
- }
1261
1331
  }
1262
1332
  return result;
1263
1333
  }
@@ -1328,7 +1398,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1328
1398
  implicitRole
1329
1399
  }) {
1330
1400
  const role = props.role;
1331
- if (!implicitRole || !role || role === implicitRole) return VALID;
1401
+ if (!implicitRole || !role || role === implicitRole) return NO_VIOLATIONS;
1332
1402
  if (isStrongImplicitRole(tag) && role === "region") {
1333
1403
  return [
1334
1404
  {
@@ -1340,11 +1410,11 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1340
1410
  }
1341
1411
  ];
1342
1412
  }
1343
- return VALID;
1413
+ return NO_VIOLATIONS;
1344
1414
  }
1345
1415
  static #checkRedundantRole({ tag, props, implicitRole }) {
1346
1416
  const role = props.role;
1347
- if (!implicitRole || !role || role !== implicitRole) return VALID;
1417
+ if (!implicitRole || !role || role !== implicitRole) return NO_VIOLATIONS;
1348
1418
  return [
1349
1419
  {
1350
1420
  valid: false,
@@ -1357,8 +1427,8 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1357
1427
  }
1358
1428
  static #checkStandaloneRegion({ tag, props, implicitRole }) {
1359
1429
  const role = props.role;
1360
- if (role !== "region") return VALID;
1361
- if (!isStandaloneTag(tag)) return VALID;
1430
+ if (role !== "region") return NO_VIOLATIONS;
1431
+ if (!isStandaloneTag(tag)) return NO_VIOLATIONS;
1362
1432
  return [
1363
1433
  {
1364
1434
  valid: false,
@@ -1374,7 +1444,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1374
1444
  props,
1375
1445
  effectiveRole
1376
1446
  }) {
1377
- if (effectiveRole === "none" || effectiveRole === "presentation") return VALID;
1447
+ if (effectiveRole === "none" || effectiveRole === "presentation") return NO_VIOLATIONS;
1378
1448
  const results = [];
1379
1449
  iterate.forEachEntry(props, (key) => {
1380
1450
  if (!key.startsWith("aria-")) return;
@@ -1492,12 +1562,12 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1492
1562
  }
1493
1563
  }
1494
1564
  static #checkAriaAttributeValues({ props, effectiveRole }) {
1495
- if (effectiveRole === "none" || effectiveRole === "presentation") return VALID;
1565
+ if (effectiveRole === "none" || effectiveRole === "presentation") return NO_VIOLATIONS;
1496
1566
  const results = [];
1497
1567
  iterate.forEachEntry(props, (key, value) => {
1498
1568
  if (!key.startsWith("aria-")) return;
1499
1569
  const type = _AriaPolicyEngine.#ARIA_VALUE_TYPES.get(key);
1500
- if (type == null) return;
1570
+ if (!isNonNull(type)) return;
1501
1571
  if (_AriaPolicyEngine.#isValidAriaValue(value, type)) return;
1502
1572
  results.push({
1503
1573
  valid: false,
@@ -1528,13 +1598,13 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1528
1598
  props,
1529
1599
  effectiveRole
1530
1600
  }) {
1531
- if (effectiveRole === "none" || effectiveRole === "presentation") return VALID;
1601
+ if (effectiveRole === "none" || effectiveRole === "presentation") return NO_VIOLATIONS;
1532
1602
  const implicitLevel = _AriaPolicyEngine.#HEADING_IMPLICIT_LEVELS.get(tag);
1533
- if (implicitLevel == null) return VALID;
1603
+ if (!isNonNull(implicitLevel)) return NO_VIOLATIONS;
1534
1604
  const raw = props["aria-level"];
1535
- if (raw == null) return VALID;
1605
+ if (!isNonNull(raw)) return NO_VIOLATIONS;
1536
1606
  const n = typeof raw === "number" ? raw : typeof raw === "string" ? parseInt(raw, 10) : NaN;
1537
- if (!Number.isFinite(n) || n !== implicitLevel) return VALID;
1607
+ if (!Number.isFinite(n) || n !== implicitLevel) return NO_VIOLATIONS;
1538
1608
  return [
1539
1609
  {
1540
1610
  valid: false,
@@ -1557,9 +1627,10 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1557
1627
  props,
1558
1628
  effectiveRole
1559
1629
  }) {
1560
- if (!effectiveRole || !_AriaPolicyEngine.#NAME_REQUIRED_ROLES.has(effectiveRole)) return VALID;
1561
- if ("aria-label" in props || "aria-labelledby" in props) return VALID;
1562
- if (tag === "img" && typeof props.alt === "string" && props.alt.length > 0) return VALID;
1630
+ if (!effectiveRole || !_AriaPolicyEngine.#NAME_REQUIRED_ROLES.has(effectiveRole))
1631
+ return NO_VIOLATIONS;
1632
+ if ("aria-label" in props || "aria-labelledby" in props) return NO_VIOLATIONS;
1633
+ if (tag === "img" && typeof props.alt === "string" && props.alt.length > 0) return NO_VIOLATIONS;
1563
1634
  return [
1564
1635
  {
1565
1636
  valid: false,
@@ -1582,9 +1653,9 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1582
1653
  props,
1583
1654
  effectiveRole
1584
1655
  }) {
1585
- if (!effectiveRole) return VALID;
1656
+ if (!effectiveRole) return NO_VIOLATIONS;
1586
1657
  const required = _AriaPolicyEngine.#REQUIRED_PROPERTIES.get(effectiveRole);
1587
- if (required == null) return VALID;
1658
+ if (!isNonNull(required)) return NO_VIOLATIONS;
1588
1659
  const results = [];
1589
1660
  iterate.forEach(required, (attr) => {
1590
1661
  if (attr in props) return;
@@ -1608,12 +1679,12 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1608
1679
  ]);
1609
1680
  // WAI-ARIA 1.2 §6.6: aria-hidden="true" must not be placed on focusable elements.
1610
1681
  static #checkAriaHiddenOnFocusable({ tag, props }) {
1611
- if (props["aria-hidden"] !== "true" && props["aria-hidden"] !== true) return VALID;
1682
+ if (props["aria-hidden"] !== "true" && props["aria-hidden"] !== true) return NO_VIOLATIONS;
1612
1683
  const isInteractive = _AriaPolicyEngine.#INTERACTIVE_TAGS.has(tag);
1613
1684
  if (!isInteractive) {
1614
1685
  const tabindex = props.tabindex;
1615
1686
  const n = typeof tabindex === "number" ? tabindex : typeof tabindex === "string" ? parseInt(tabindex, 10) : NaN;
1616
- if (!Number.isFinite(n) || n < 0) return VALID;
1687
+ if (!Number.isFinite(n) || n < 0) return NO_VIOLATIONS;
1617
1688
  }
1618
1689
  return [
1619
1690
  {
@@ -1632,7 +1703,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1632
1703
  props,
1633
1704
  effectiveRole
1634
1705
  }) {
1635
- if (effectiveRole !== "none" && effectiveRole !== "presentation") return VALID;
1706
+ if (effectiveRole !== "none" && effectiveRole !== "presentation") return NO_VIOLATIONS;
1636
1707
  const results = [];
1637
1708
  iterate.forEachEntry(props, (key) => {
1638
1709
  if (!key.startsWith("aria-")) return;
@@ -1656,10 +1727,10 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1656
1727
  ["timer", "off"]
1657
1728
  ]);
1658
1729
  static #checkMissingLiveRegion({ effectiveRole, props }) {
1659
- if (!effectiveRole) return VALID;
1730
+ if (!effectiveRole) return NO_VIOLATIONS;
1660
1731
  const impliedLive = _AriaPolicyEngine.#LIVE_REGION_ROLES.get(effectiveRole);
1661
- if (!impliedLive) return VALID;
1662
- if ("aria-live" in props) return VALID;
1732
+ if (!impliedLive) return NO_VIOLATIONS;
1733
+ if ("aria-live" in props) return NO_VIOLATIONS;
1663
1734
  const injectLive = {
1664
1735
  kind: `injectLive:${effectiveRole}`,
1665
1736
  apply: (ctx) => ({
@@ -1679,8 +1750,9 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1679
1750
  ];
1680
1751
  }
1681
1752
  static #checkMissingAtomic({ effectiveRole, props }) {
1682
- if (!effectiveRole || !_AriaPolicyEngine.#LIVE_REGION_ROLES.has(effectiveRole)) return VALID;
1683
- if ("aria-atomic" in props) return VALID;
1753
+ if (!effectiveRole || !_AriaPolicyEngine.#LIVE_REGION_ROLES.has(effectiveRole))
1754
+ return NO_VIOLATIONS;
1755
+ if ("aria-atomic" in props) return NO_VIOLATIONS;
1684
1756
  return [
1685
1757
  {
1686
1758
  valid: false,
@@ -1704,8 +1776,8 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1704
1776
  };
1705
1777
  static #checkInvalidAriaRelevant({ props }) {
1706
1778
  const relevant = props["aria-relevant"];
1707
- if (relevant === void 0) return VALID;
1708
- if (typeof relevant !== "string") return VALID;
1779
+ if (relevant === void 0) return NO_VIOLATIONS;
1780
+ if (typeof relevant !== "string") return NO_VIOLATIONS;
1709
1781
  const tokens = relevant.trim().split(/\s+/);
1710
1782
  const invalid = tokens.filter((t) => !_AriaPolicyEngine.#VALID_RELEVANT_TOKENS.has(t));
1711
1783
  if (invalid.length > 0) {
@@ -1732,7 +1804,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1732
1804
  }
1733
1805
  ];
1734
1806
  }
1735
- return VALID;
1807
+ return NO_VIOLATIONS;
1736
1808
  }
1737
1809
  };
1738
1810
 
@@ -2332,7 +2404,7 @@ function cva2(base, config) {
2332
2404
  // ../../lib/styling/src/static-class-resolver.ts
2333
2405
  var StaticClassResolver = class {
2334
2406
  #baseClass;
2335
- #cache = /* @__PURE__ */ new Map();
2407
+ #cache = new LRUCache(200);
2336
2408
  #resolveTag;
2337
2409
  constructor(baseClass, tagMap) {
2338
2410
  this.#baseClass = Array.isArray(baseClass) ? baseClass.join(" ") : baseClass;
@@ -2346,17 +2418,9 @@ var StaticClassResolver = class {
2346
2418
  resolve(tag, skipTagMap = false) {
2347
2419
  if (typeof tag !== "string" || skipTagMap) return this.#baseClass;
2348
2420
  const cached = this.#cache.get(tag);
2349
- if (cached !== void 0) {
2350
- this.#cache.delete(tag);
2351
- this.#cache.set(tag, cached);
2352
- return cached;
2353
- }
2421
+ if (cached !== void 0) return cached;
2354
2422
  const result = this.#resolveTag(tag);
2355
2423
  this.#cache.set(tag, result);
2356
- if (this.#cache.size > 200) {
2357
- const lru = this.#cache.keys().next().value;
2358
- if (lru !== void 0) this.#cache.delete(lru);
2359
- }
2360
2424
  return result;
2361
2425
  }
2362
2426
  };
@@ -2367,7 +2431,7 @@ var VariantClassResolver = class _VariantClassResolver {
2367
2431
  #recipeMap;
2368
2432
  #variantKeys;
2369
2433
  #precomputedClasses;
2370
- #cache = /* @__PURE__ */ new Map();
2434
+ #cache = new LRUCache(1e3);
2371
2435
  constructor(cvaFn, recipeMap, variantKeys, precomputedClasses) {
2372
2436
  this.#cvaFn = cvaFn ?? null;
2373
2437
  this.#recipeMap = Object.freeze(recipeMap ?? {});
@@ -2382,17 +2446,9 @@ var VariantClassResolver = class _VariantClassResolver {
2382
2446
  if (precomputed !== void 0) return precomputed;
2383
2447
  }
2384
2448
  const cached = this.#cache.get(cacheKey);
2385
- if (cached !== void 0) {
2386
- this.#cache.delete(cacheKey);
2387
- this.#cache.set(cacheKey, cached);
2388
- return cached;
2389
- }
2449
+ if (cached !== void 0) return cached;
2390
2450
  const result = this.#compute(props, recipe);
2391
2451
  this.#cache.set(cacheKey, result);
2392
- if (this.#cache.size > 1e3) {
2393
- const lru = this.#cache.keys().next().value;
2394
- if (lru !== void 0) this.#cache.delete(lru);
2395
- }
2396
2452
  return result;
2397
2453
  }
2398
2454
  #compute(props, recipe) {
@@ -2449,7 +2505,7 @@ function createClassPipeline(resolved) {
2449
2505
  const staticClasses = staticResolver.resolve(tag, recipe !== void 0);
2450
2506
  const variantClasses = variantResolver.resolve({ props, recipe });
2451
2507
  if (!className)
2452
- return staticClasses && variantClasses ? `${staticClasses} ${variantClasses}` : staticClasses || variantClasses;
2508
+ return (staticClasses && variantClasses ? `${staticClasses} ${variantClasses}` : staticClasses || variantClasses) || void 0;
2453
2509
  return cn(staticClasses, variantClasses, className);
2454
2510
  };
2455
2511
  }
@@ -2660,7 +2716,7 @@ function createPolymorphic2(options = {}) {
2660
2716
  if (process.env.NODE_ENV !== "production") {
2661
2717
  validateRenderProps(resolved.diagnostics, resolved, props, recipe);
2662
2718
  }
2663
- return classPipeline(tag, props, className, recipe);
2719
+ return classPipeline(tag, props, className, recipe) || void 0;
2664
2720
  },
2665
2721
  resolveAria(tag, props) {
2666
2722
  return resolveAriaFn(tag, props);
@@ -1,5 +1,5 @@
1
- import { U as UnknownProps, E as ElementType, 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, m as composeRefs, l as defineContractComponent, m as mergeRefs } from '../react-options-AitAOrje.js';
1
+ import { U as UnknownProps, E as ElementType, 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-CjiWrT4q.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, m as composeRefs, l as defineContractComponent, m as mergeRefs } from '../react-options-CjiWrT4q.js';
3
3
  import * as react from 'react';
4
4
  import { ReactElement, Ref } from 'react';
5
5
  import 'type-fest';
@@ -12,7 +12,7 @@ import {
12
12
  makeCloneSlotChild,
13
13
  mergeRefs,
14
14
  render
15
- } from "../chunk-P5ZJBPAR.js";
15
+ } from "../chunk-OGQ7QKKP.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-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';
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-CjiWrT4q.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-CjiWrT4q.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-P5ZJBPAR.js";
16
+ } from "../chunk-OGQ7QKKP.js";
17
17
 
18
18
  // ../../adapters/react/src/legacy/create-contract-component.ts
19
19
  import { forwardRef as forwardRef2 } from "react";
@@ -157,7 +157,7 @@ interface BaseClassOptions {
157
157
  baseClassName?: ClassName;
158
158
  }
159
159
 
160
- type ClassPipelineFn = (tag: unknown, props: AnyRecord, className?: ClassName, recipe?: string) => string;
160
+ type ClassPipelineFn = (tag: unknown, props: AnyRecord, className?: ClassName, recipe?: string) => string | undefined;
161
161
 
162
162
  interface RecipeOptions<TVariants extends VariantMap = VariantMap> {
163
163
  recipeMap?: Record<string, RecipeTarget<TVariants>>;
@@ -235,7 +235,9 @@ type AriaInvalidWithoutFix<M extends string = string> = AriaInvalidBase<M> & {
235
235
  type AriaInvalidResult<M extends string = string> = AriaInvalidWithFix<M> | AriaInvalidWithoutFix<M>;
236
236
  type AriaResult = ValidResult | AriaInvalidResult;
237
237
 
238
- type AriaRule<C extends AriaContext = AriaContext> = (context: C) => readonly AriaResult[];
238
+ type AriaRule<C extends AriaContext = AriaContext> = ((context: C) => readonly AriaResult[]) & {
239
+ readonly readsProps?: readonly string[];
240
+ };
239
241
 
240
242
  type PropNormalizer = (props: Readonly<AnyRecord & IntrinsicProps>) => Partial<AnyRecord & IntrinsicProps>;
241
243