praxis-kit 6.1.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.
@@ -12,8 +12,11 @@ function isUndefined(value) {
12
12
  function isNull(value) {
13
13
  return value === null;
14
14
  }
15
+ function isNonNull(value) {
16
+ return value != null;
17
+ }
15
18
 
16
- // ../../lib/primitive/src/utils/is-object.ts
19
+ // ../../lib/primitive/src/utils/type-guards.ts
17
20
  function isObject(value, excludeArrays = false) {
18
21
  if (value === null || typeof value !== "object") return false;
19
22
  return excludeArrays ? !Array.isArray(value) : true;
@@ -969,7 +972,7 @@ var InvariantBase = class {
969
972
  };
970
973
 
971
974
  // ../../lib/contract/src/aria/polymorphic-validator.ts
972
- var VALID = [{ valid: true }];
975
+ var NO_VIOLATIONS = [{ valid: true }];
973
976
  function isIntrinsicTag(tag) {
974
977
  return isString(tag);
975
978
  }
@@ -1011,17 +1014,20 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1011
1014
  static #deriveContext(tag, props) {
1012
1015
  if (!isIntrinsicTag(tag)) return { proceed: false, result: { props, violations: [] } };
1013
1016
  const implicitRole = getImplicitRole(tag, props);
1014
- const hasRole = implicitRole != null || isString(props.role) && props.role.length > 0;
1017
+ const hasRole = isNonNull(implicitRole) || isString(props.role) && props.role.length > 0;
1015
1018
  if (!hasRole) return { proceed: false, result: { props, violations: [] } };
1016
1019
  const normalized = _AriaPolicyEngine.#normalizeEmptyRole(tag, props);
1017
- if (normalized.normalized) return { proceed: false, result: normalized.result };
1018
- const effectiveRole = props.role ?? implicitRole;
1020
+ const workingProps = normalized.normalized ? normalized.result.props : props;
1021
+ const preExistingViolations = normalized.normalized ? normalized.result.violations : [];
1022
+ const effectiveRole = workingProps.role ?? implicitRole;
1019
1023
  return {
1020
1024
  proceed: true,
1021
1025
  tag,
1022
1026
  implicitRole,
1023
1027
  effectiveRole,
1024
- context: { tag, props, implicitRole, effectiveRole }
1028
+ props: workingProps,
1029
+ preExistingViolations,
1030
+ context: { tag, props: workingProps, implicitRole, effectiveRole }
1025
1031
  };
1026
1032
  }
1027
1033
  static #runRules(rules, context) {
@@ -1036,7 +1042,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1036
1042
  } = context;
1037
1043
  const { message, attribute, severity } = result;
1038
1044
  const resolvedMessage = message ?? result.diagnostic?.message;
1039
- const fallbackDiag = resolvedMessage == null ? AriaDiagnostics.invalidRole(role, tag) : void 0;
1045
+ const fallbackDiag = isNonNull(resolvedMessage) ? void 0 : AriaDiagnostics.invalidRole(role, tag);
1040
1046
  violations.push({
1041
1047
  message: resolvedMessage ?? fallbackDiag.message,
1042
1048
  tag,
@@ -1044,8 +1050,8 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1044
1050
  attribute,
1045
1051
  severity,
1046
1052
  phase: "evaluate",
1047
- ...result.diagnostic != null && { diagnostic: result.diagnostic },
1048
- ...fallbackDiag != null && { diagnostic: fallbackDiag }
1053
+ ...isNonNull(result.diagnostic) && { diagnostic: result.diagnostic },
1054
+ ...isNonNull(fallbackDiag) && { diagnostic: fallbackDiag }
1049
1055
  });
1050
1056
  if (result.fixable) fixes.push(result.fix);
1051
1057
  });
@@ -1053,7 +1059,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1053
1059
  return { violations, fixes };
1054
1060
  }
1055
1061
  static #getRules(context) {
1056
- if (_AriaPolicyEngine.#hasRole(context.props) || context.effectiveRole != null && _AriaPolicyEngine.#LIVE_REGION_ROLES.has(context.effectiveRole)) {
1062
+ if (_AriaPolicyEngine.#hasRole(context.props) || isNonNull(context.effectiveRole) && _AriaPolicyEngine.#LIVE_REGION_ROLES.has(context.effectiveRole)) {
1057
1063
  return _AriaPolicyEngine.#pipeline;
1058
1064
  }
1059
1065
  return _AriaPolicyEngine.#implicitOnlyRules;
@@ -1061,24 +1067,36 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1061
1067
  static evaluate(tag, props) {
1062
1068
  const derived = _AriaPolicyEngine.#deriveContext(tag, props);
1063
1069
  if (!derived.proceed) return derived.result;
1064
- const { tag: narrowedTag, implicitRole, context } = derived;
1070
+ const {
1071
+ tag: narrowedTag,
1072
+ implicitRole,
1073
+ context,
1074
+ props: workingProps,
1075
+ preExistingViolations
1076
+ } = derived;
1065
1077
  const { violations, fixes } = _AriaPolicyEngine.#runRules(
1066
1078
  _AriaPolicyEngine.#getRules(context),
1067
1079
  context
1068
1080
  );
1069
- const next = _AriaPolicyEngine.#applyFixes(narrowedTag, implicitRole, props, fixes);
1070
- return { props: next, violations };
1081
+ const next = _AriaPolicyEngine.#applyFixes(narrowedTag, implicitRole, workingProps, fixes);
1082
+ return { props: next, violations: [...preExistingViolations, ...violations] };
1071
1083
  }
1072
1084
  static #evaluateWithRules(tag, props, extraRules) {
1073
1085
  const derived = _AriaPolicyEngine.#deriveContext(tag, props);
1074
1086
  if (!derived.proceed) return derived.result;
1075
- const { tag: narrowedTag, implicitRole, context } = derived;
1087
+ const {
1088
+ tag: narrowedTag,
1089
+ implicitRole,
1090
+ context,
1091
+ props: workingProps,
1092
+ preExistingViolations
1093
+ } = derived;
1076
1094
  const { violations, fixes } = _AriaPolicyEngine.#runRules(
1077
1095
  [..._AriaPolicyEngine.#getRules(context), ...extraRules],
1078
1096
  context
1079
1097
  );
1080
- const next = _AriaPolicyEngine.#applyFixes(narrowedTag, implicitRole, props, fixes);
1081
- return { props: next, violations };
1098
+ const next = _AriaPolicyEngine.#applyFixes(narrowedTag, implicitRole, workingProps, fixes);
1099
+ return { props: next, violations: [...preExistingViolations, ...violations] };
1082
1100
  }
1083
1101
  report(violations) {
1084
1102
  iterate.forEach(violations, (v) => {
@@ -1087,12 +1105,12 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1087
1105
  else this.warn(d);
1088
1106
  });
1089
1107
  }
1090
- // Cache key covers only the aria-relevant subset of props (tag + role + aria-* attrs).
1091
- // Non-aria props (className, onClick, etc.) do not affect ARIA decisions and are excluded
1092
- // so cache hits survive re-renders that only change non-aria props.
1093
- // Note: #extraRules are NOT included in the key each engine instance has its own Map,
1094
- // so two engines with different rules never share cache entries. If caching ever becomes
1095
- // static/shared, rule identity would need to be folded into the key.
1108
+ // Cache key covers only the aria-relevant subset of props (tag + role + aria-* attrs)
1109
+ // exactly what the built-in pipeline reads. Non-aria props (className, onClick, etc.) do
1110
+ // not affect built-in ARIA decisions and are excluded so cache hits survive re-renders
1111
+ // that only change non-aria props. This key alone is unsound for #extraRules, which may
1112
+ // read arbitrary props outside this set validate() extends it with #extraRulesKeySuffix,
1113
+ // or bypasses the cache, to account for that.
1096
1114
  static #createPlanKey(tag, props) {
1097
1115
  if (!isIntrinsicTag(tag)) return null;
1098
1116
  const parts = [tag];
@@ -1108,6 +1126,23 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1108
1126
  if (ariaEntries.length > 0) parts.push(...ariaEntries.sort());
1109
1127
  return parts.join("|");
1110
1128
  }
1129
+ // Extends the base cache key with the props each extra rule declares it reads (`readsProps`).
1130
+ // Returns null — meaning "don't cache" — if any extra rule omits `readsProps` (it may read
1131
+ // arbitrary props the key can't account for) or if a declared prop's value isn't a primitive
1132
+ // (object/array identity isn't stably representable in a string key).
1133
+ static #extraRulesKeySuffix(extraRules, props) {
1134
+ const parts = [];
1135
+ for (const rule of extraRules) {
1136
+ const readsProps = rule.readsProps;
1137
+ if (!isNonNull(readsProps)) return null;
1138
+ for (const propKey of readsProps) {
1139
+ const v = props[propKey];
1140
+ if (v !== void 0 && !isString(v) && !isNumber(v) && typeof v !== "boolean") return null;
1141
+ parts.push(`x:${propKey}:${String(v)}`);
1142
+ }
1143
+ }
1144
+ return parts.sort().join("|");
1145
+ }
1111
1146
  static #computePlan(inputProps, resultProps) {
1112
1147
  const removals = /* @__PURE__ */ new Set();
1113
1148
  const updates = {};
@@ -1131,7 +1166,12 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1131
1166
  return next;
1132
1167
  }
1133
1168
  validate(tag, props) {
1134
- const key = _AriaPolicyEngine.#createPlanKey(tag, props);
1169
+ const baseKey = _AriaPolicyEngine.#createPlanKey(tag, props);
1170
+ let key = baseKey;
1171
+ if (this.#extraRules.length > 0) {
1172
+ const suffix = _AriaPolicyEngine.#extraRulesKeySuffix(this.#extraRules, props);
1173
+ key = isNonNull(baseKey) && isNonNull(suffix) ? `${baseKey}|${suffix}` : null;
1174
+ }
1135
1175
  if (!isNull(key)) {
1136
1176
  const cached = this.#planCache.get(key);
1137
1177
  if (cached !== void 0) {
@@ -1221,7 +1261,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1221
1261
  implicitRole
1222
1262
  }) {
1223
1263
  const role = props.role;
1224
- if (!implicitRole || !role || role === implicitRole) return VALID;
1264
+ if (!implicitRole || !role || role === implicitRole) return NO_VIOLATIONS;
1225
1265
  if (isStrongImplicitRole(tag) && role === "region") {
1226
1266
  return [
1227
1267
  {
@@ -1233,11 +1273,11 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1233
1273
  }
1234
1274
  ];
1235
1275
  }
1236
- return VALID;
1276
+ return NO_VIOLATIONS;
1237
1277
  }
1238
1278
  static #checkRedundantRole({ tag, props, implicitRole }) {
1239
1279
  const role = props.role;
1240
- if (!implicitRole || !role || role !== implicitRole) return VALID;
1280
+ if (!implicitRole || !role || role !== implicitRole) return NO_VIOLATIONS;
1241
1281
  return [
1242
1282
  {
1243
1283
  valid: false,
@@ -1250,8 +1290,8 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1250
1290
  }
1251
1291
  static #checkStandaloneRegion({ tag, props, implicitRole }) {
1252
1292
  const role = props.role;
1253
- if (role !== "region") return VALID;
1254
- if (!isStandaloneTag(tag)) return VALID;
1293
+ if (role !== "region") return NO_VIOLATIONS;
1294
+ if (!isStandaloneTag(tag)) return NO_VIOLATIONS;
1255
1295
  return [
1256
1296
  {
1257
1297
  valid: false,
@@ -1267,7 +1307,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1267
1307
  props,
1268
1308
  effectiveRole
1269
1309
  }) {
1270
- if (effectiveRole === "none" || effectiveRole === "presentation") return VALID;
1310
+ if (effectiveRole === "none" || effectiveRole === "presentation") return NO_VIOLATIONS;
1271
1311
  const results = [];
1272
1312
  iterate.forEachEntry(props, (key) => {
1273
1313
  if (!key.startsWith("aria-")) return;
@@ -1385,12 +1425,12 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1385
1425
  }
1386
1426
  }
1387
1427
  static #checkAriaAttributeValues({ props, effectiveRole }) {
1388
- if (effectiveRole === "none" || effectiveRole === "presentation") return VALID;
1428
+ if (effectiveRole === "none" || effectiveRole === "presentation") return NO_VIOLATIONS;
1389
1429
  const results = [];
1390
1430
  iterate.forEachEntry(props, (key, value) => {
1391
1431
  if (!key.startsWith("aria-")) return;
1392
1432
  const type = _AriaPolicyEngine.#ARIA_VALUE_TYPES.get(key);
1393
- if (type == null) return;
1433
+ if (!isNonNull(type)) return;
1394
1434
  if (_AriaPolicyEngine.#isValidAriaValue(value, type)) return;
1395
1435
  results.push({
1396
1436
  valid: false,
@@ -1421,13 +1461,13 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1421
1461
  props,
1422
1462
  effectiveRole
1423
1463
  }) {
1424
- if (effectiveRole === "none" || effectiveRole === "presentation") return VALID;
1464
+ if (effectiveRole === "none" || effectiveRole === "presentation") return NO_VIOLATIONS;
1425
1465
  const implicitLevel = _AriaPolicyEngine.#HEADING_IMPLICIT_LEVELS.get(tag);
1426
- if (implicitLevel == null) return VALID;
1466
+ if (!isNonNull(implicitLevel)) return NO_VIOLATIONS;
1427
1467
  const raw = props["aria-level"];
1428
- if (raw == null) return VALID;
1468
+ if (!isNonNull(raw)) return NO_VIOLATIONS;
1429
1469
  const n = typeof raw === "number" ? raw : typeof raw === "string" ? parseInt(raw, 10) : NaN;
1430
- if (!Number.isFinite(n) || n !== implicitLevel) return VALID;
1470
+ if (!Number.isFinite(n) || n !== implicitLevel) return NO_VIOLATIONS;
1431
1471
  return [
1432
1472
  {
1433
1473
  valid: false,
@@ -1450,9 +1490,10 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1450
1490
  props,
1451
1491
  effectiveRole
1452
1492
  }) {
1453
- if (!effectiveRole || !_AriaPolicyEngine.#NAME_REQUIRED_ROLES.has(effectiveRole)) return VALID;
1454
- if ("aria-label" in props || "aria-labelledby" in props) return VALID;
1455
- if (tag === "img" && typeof props.alt === "string" && props.alt.length > 0) return VALID;
1493
+ if (!effectiveRole || !_AriaPolicyEngine.#NAME_REQUIRED_ROLES.has(effectiveRole))
1494
+ return NO_VIOLATIONS;
1495
+ if ("aria-label" in props || "aria-labelledby" in props) return NO_VIOLATIONS;
1496
+ if (tag === "img" && typeof props.alt === "string" && props.alt.length > 0) return NO_VIOLATIONS;
1456
1497
  return [
1457
1498
  {
1458
1499
  valid: false,
@@ -1475,9 +1516,9 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1475
1516
  props,
1476
1517
  effectiveRole
1477
1518
  }) {
1478
- if (!effectiveRole) return VALID;
1519
+ if (!effectiveRole) return NO_VIOLATIONS;
1479
1520
  const required = _AriaPolicyEngine.#REQUIRED_PROPERTIES.get(effectiveRole);
1480
- if (required == null) return VALID;
1521
+ if (!isNonNull(required)) return NO_VIOLATIONS;
1481
1522
  const results = [];
1482
1523
  iterate.forEach(required, (attr) => {
1483
1524
  if (attr in props) return;
@@ -1501,12 +1542,12 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1501
1542
  ]);
1502
1543
  // WAI-ARIA 1.2 §6.6: aria-hidden="true" must not be placed on focusable elements.
1503
1544
  static #checkAriaHiddenOnFocusable({ tag, props }) {
1504
- if (props["aria-hidden"] !== "true" && props["aria-hidden"] !== true) return VALID;
1545
+ if (props["aria-hidden"] !== "true" && props["aria-hidden"] !== true) return NO_VIOLATIONS;
1505
1546
  const isInteractive = _AriaPolicyEngine.#INTERACTIVE_TAGS.has(tag);
1506
1547
  if (!isInteractive) {
1507
1548
  const tabindex = props.tabindex;
1508
1549
  const n = typeof tabindex === "number" ? tabindex : typeof tabindex === "string" ? parseInt(tabindex, 10) : NaN;
1509
- if (!Number.isFinite(n) || n < 0) return VALID;
1550
+ if (!Number.isFinite(n) || n < 0) return NO_VIOLATIONS;
1510
1551
  }
1511
1552
  return [
1512
1553
  {
@@ -1525,7 +1566,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1525
1566
  props,
1526
1567
  effectiveRole
1527
1568
  }) {
1528
- if (effectiveRole !== "none" && effectiveRole !== "presentation") return VALID;
1569
+ if (effectiveRole !== "none" && effectiveRole !== "presentation") return NO_VIOLATIONS;
1529
1570
  const results = [];
1530
1571
  iterate.forEachEntry(props, (key) => {
1531
1572
  if (!key.startsWith("aria-")) return;
@@ -1549,10 +1590,10 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1549
1590
  ["timer", "off"]
1550
1591
  ]);
1551
1592
  static #checkMissingLiveRegion({ effectiveRole, props }) {
1552
- if (!effectiveRole) return VALID;
1593
+ if (!effectiveRole) return NO_VIOLATIONS;
1553
1594
  const impliedLive = _AriaPolicyEngine.#LIVE_REGION_ROLES.get(effectiveRole);
1554
- if (!impliedLive) return VALID;
1555
- if ("aria-live" in props) return VALID;
1595
+ if (!impliedLive) return NO_VIOLATIONS;
1596
+ if ("aria-live" in props) return NO_VIOLATIONS;
1556
1597
  const injectLive = {
1557
1598
  kind: `injectLive:${effectiveRole}`,
1558
1599
  apply: (ctx) => ({
@@ -1572,8 +1613,9 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1572
1613
  ];
1573
1614
  }
1574
1615
  static #checkMissingAtomic({ effectiveRole, props }) {
1575
- if (!effectiveRole || !_AriaPolicyEngine.#LIVE_REGION_ROLES.has(effectiveRole)) return VALID;
1576
- if ("aria-atomic" in props) return VALID;
1616
+ if (!effectiveRole || !_AriaPolicyEngine.#LIVE_REGION_ROLES.has(effectiveRole))
1617
+ return NO_VIOLATIONS;
1618
+ if ("aria-atomic" in props) return NO_VIOLATIONS;
1577
1619
  return [
1578
1620
  {
1579
1621
  valid: false,
@@ -1597,8 +1639,8 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1597
1639
  };
1598
1640
  static #checkInvalidAriaRelevant({ props }) {
1599
1641
  const relevant = props["aria-relevant"];
1600
- if (relevant === void 0) return VALID;
1601
- if (typeof relevant !== "string") return VALID;
1642
+ if (relevant === void 0) return NO_VIOLATIONS;
1643
+ if (typeof relevant !== "string") return NO_VIOLATIONS;
1602
1644
  const tokens = relevant.trim().split(/\s+/);
1603
1645
  const invalid = tokens.filter((t) => !_AriaPolicyEngine.#VALID_RELEVANT_TOKENS.has(t));
1604
1646
  if (invalid.length > 0) {
@@ -1625,7 +1667,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1625
1667
  }
1626
1668
  ];
1627
1669
  }
1628
- return VALID;
1670
+ return NO_VIOLATIONS;
1629
1671
  }
1630
1672
  };
1631
1673
 
@@ -2326,7 +2368,7 @@ function createClassPipeline(resolved) {
2326
2368
  const staticClasses = staticResolver.resolve(tag, recipe !== void 0);
2327
2369
  const variantClasses = variantResolver.resolve({ props, recipe });
2328
2370
  if (!className)
2329
- return staticClasses && variantClasses ? `${staticClasses} ${variantClasses}` : staticClasses || variantClasses;
2371
+ return (staticClasses && variantClasses ? `${staticClasses} ${variantClasses}` : staticClasses || variantClasses) || void 0;
2330
2372
  return cn(staticClasses, variantClasses, className);
2331
2373
  };
2332
2374
  }
@@ -2537,7 +2579,7 @@ function createPolymorphic2(options = {}) {
2537
2579
  if (process.env.NODE_ENV !== "production") {
2538
2580
  validateRenderProps(resolved.diagnostics, resolved, props, recipe);
2539
2581
  }
2540
- return classPipeline(tag, props, className, recipe);
2582
+ return classPipeline(tag, props, className, recipe) || void 0;
2541
2583
  },
2542
2584
  resolveAria(tag, props) {
2543
2585
  return resolveAriaFn(tag, props);
@@ -84,7 +84,7 @@ interface BaseClassOptions {
84
84
  baseClassName?: ClassName;
85
85
  }
86
86
 
87
- type ClassPipelineFn = (tag: unknown, props: AnyRecord, className?: ClassName, recipe?: string) => string;
87
+ type ClassPipelineFn = (tag: unknown, props: AnyRecord, className?: ClassName, recipe?: string) => string | undefined;
88
88
 
89
89
  interface RecipeOptions<TVariants extends VariantMap = VariantMap> {
90
90
  recipeMap?: Record<string, RecipeTarget<TVariants>>;
@@ -1,4 +1,4 @@
1
- // ../../lib/primitive/src/utils/is-object.ts
1
+ // ../../lib/primitive/src/utils/type-guards.ts
2
2
  function isString(value) {
3
3
  return typeof value === "string";
4
4
  }
@@ -376,7 +376,7 @@ function createClassPipeline(resolved) {
376
376
  const staticClasses = staticResolver.resolve(tag, recipe !== void 0);
377
377
  const variantClasses = variantResolver.resolve({ props, recipe });
378
378
  if (!className)
379
- return staticClasses && variantClasses ? `${staticClasses} ${variantClasses}` : staticClasses || variantClasses;
379
+ return (staticClasses && variantClasses ? `${staticClasses} ${variantClasses}` : staticClasses || variantClasses) || void 0;
380
380
  return cn(staticClasses, variantClasses, className);
381
381
  };
382
382
  }
@@ -701,7 +701,7 @@ function createTailwindPipeline(options, diagnostics) {
701
701
  const compoundDims = compoundDimensions(getCompoundVariants(options));
702
702
  const resolveLayoutContext = (tag, props, className, recipe) => {
703
703
  const mode = resolveLayout(devDiagnostics, props);
704
- const resolvedClasses = innerPipeline(tag, props, className, recipe);
704
+ const resolvedClasses = innerPipeline(tag, props, className, recipe) ?? "";
705
705
  const tokens = classifyTokens(resolvedClasses);
706
706
  const state = new LayoutState(mode);
707
707
  const filtered = tokens.filter((token) => evaluator.evaluate(token, state));
@@ -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