praxis-kit 3.1.1 → 4.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.
@@ -1,1056 +1,174 @@
1
- // ../core/dist/chunk-KKSHJDE7.js
2
- function assertNever(value) {
3
- throw new Error(`Unexpected value: ${String(value)}`);
4
- }
5
- function isNull(value) {
6
- return value === null;
7
- }
8
- function isObject(value) {
9
- return !isNull(value) && typeof value === "object";
10
- }
11
- function isString(value) {
12
- return typeof value === "string";
13
- }
14
- function isNumber(value) {
15
- return typeof value === "number";
16
- }
17
- var KNOWN_ARIA_ROLES = [
18
- "alert",
19
- "alertdialog",
20
- "application",
21
- "article",
22
- "banner",
23
- "blockquote",
24
- "button",
25
- "caption",
26
- "cell",
27
- "checkbox",
28
- "code",
29
- "columnheader",
30
- "combobox",
31
- "complementary",
32
- "contentinfo",
33
- "definition",
34
- "deletion",
35
- "dialog",
36
- "document",
37
- "emphasis",
38
- "feed",
39
- "figure",
40
- "form",
41
- "generic",
42
- "grid",
43
- "gridcell",
44
- "group",
45
- "heading",
46
- "img",
47
- "insertion",
48
- "link",
49
- "list",
50
- "listbox",
51
- "listitem",
52
- "log",
53
- "main",
54
- "marquee",
55
- "math",
56
- "menu",
57
- "menubar",
58
- "menuitem",
59
- "menuitemcheckbox",
60
- "menuitemradio",
61
- "meter",
62
- "navigation",
63
- "none",
64
- "note",
65
- "option",
66
- "paragraph",
67
- "presentation",
68
- "progressbar",
69
- "radio",
70
- "radiogroup",
71
- "region",
72
- "row",
73
- "rowgroup",
74
- "rowheader",
75
- "scrollbar",
76
- "search",
77
- "searchbox",
78
- "separator",
79
- "slider",
80
- "spinbutton",
81
- "status",
82
- "strong",
83
- "subscript",
84
- "superscript",
85
- "switch",
86
- "tab",
87
- "table",
88
- "tablist",
89
- "tabpanel",
90
- "term",
91
- "textbox",
92
- "time",
93
- "timer",
94
- "toolbar",
95
- "tooltip",
96
- "tree",
97
- "treegrid",
98
- "treeitem"
99
- ];
100
- var KNOWN_ARIA_ROLES_SET = new Set(KNOWN_ARIA_ROLES);
101
- var GLOBAL_ARIA_ATTRIBUTES = /* @__PURE__ */ new Set([
102
- "aria-atomic",
103
- "aria-busy",
104
- "aria-controls",
105
- "aria-current",
106
- "aria-describedby",
107
- "aria-details",
108
- "aria-disabled",
109
- "aria-errormessage",
110
- "aria-flowto",
111
- "aria-hidden",
112
- "aria-keyshortcuts",
113
- "aria-label",
114
- "aria-labelledby",
115
- "aria-live",
116
- "aria-owns",
117
- "aria-relevant",
118
- "aria-roledescription"
119
- ]);
120
- var IMPLICIT_ROLE_RECORD = {
121
- article: "article",
122
- aside: "complementary",
123
- footer: "contentinfo",
124
- header: "banner",
125
- main: "main",
126
- nav: "navigation",
127
- button: "button",
128
- a: "link",
129
- select: "listbox",
130
- h1: "heading",
131
- h2: "heading",
132
- h3: "heading",
133
- h4: "heading",
134
- h5: "heading",
135
- h6: "heading",
136
- ul: "list",
137
- ol: "list",
138
- li: "listitem",
139
- table: "table",
140
- tr: "row",
141
- td: "cell",
142
- th: "columnheader"
143
- };
144
- var STRONG_ROLES = [
145
- "main",
146
- "navigation",
147
- "complementary",
148
- "contentinfo",
149
- "banner"
150
- ];
151
- var STANDALONE_ROLES = ["article"];
152
- var STRONG_ROLES_SET = new Set(STRONG_ROLES);
153
- var STANDALONE_ROLES_SET = new Set(STANDALONE_ROLES);
154
- var ROLE_RESTRICTED_ATTRIBUTES = /* @__PURE__ */ new Map([
155
- [
156
- "aria-activedescendant",
157
- /* @__PURE__ */ new Set([
158
- "application",
159
- "combobox",
160
- "grid",
161
- "group",
162
- "listbox",
163
- "menu",
164
- "menubar",
165
- "radiogroup",
166
- "spinbutton",
167
- "tablist",
168
- "toolbar",
169
- "textbox",
170
- "tree",
171
- "treegrid"
172
- ])
173
- ],
174
- ["aria-autocomplete", /* @__PURE__ */ new Set(["combobox", "searchbox", "textbox"])],
175
- [
176
- "aria-checked",
177
- /* @__PURE__ */ new Set(["checkbox", "menuitemcheckbox", "option", "radio", "switch", "treeitem"])
178
- ],
179
- ["aria-colcount", /* @__PURE__ */ new Set(["grid", "table", "treegrid"])],
180
- ["aria-colindex", /* @__PURE__ */ new Set(["cell", "columnheader", "gridcell", "row", "rowheader"])],
181
- ["aria-colspan", /* @__PURE__ */ new Set(["cell", "columnheader", "gridcell", "rowheader"])],
182
- [
183
- "aria-expanded",
184
- /* @__PURE__ */ new Set([
185
- "button",
186
- "combobox",
187
- "gridcell",
188
- "listbox",
189
- "menuitem",
190
- "menuitemcheckbox",
191
- "menuitemradio",
192
- "row",
193
- "rowheader",
194
- "tab",
195
- "treeitem"
196
- ])
197
- ],
198
- [
199
- "aria-haspopup",
200
- /* @__PURE__ */ new Set([
201
- "button",
202
- "combobox",
203
- "gridcell",
204
- "listbox",
205
- "menuitem",
206
- "menuitemcheckbox",
207
- "menuitemradio",
208
- "tab",
209
- "treeitem"
210
- ])
211
- ],
212
- ["aria-level", /* @__PURE__ */ new Set(["heading", "listitem", "row", "treeitem"])],
213
- ["aria-modal", /* @__PURE__ */ new Set(["alertdialog", "dialog"])],
214
- ["aria-multiline", /* @__PURE__ */ new Set(["textbox"])],
215
- ["aria-multiselectable", /* @__PURE__ */ new Set(["grid", "listbox", "tablist", "tree", "treegrid"])],
216
- [
217
- "aria-orientation",
218
- /* @__PURE__ */ new Set(["scrollbar", "select", "separator", "slider", "tablist", "toolbar", "tree"])
219
- ],
220
- ["aria-placeholder", /* @__PURE__ */ new Set(["searchbox", "textbox"])],
221
- [
222
- "aria-posinset",
223
- /* @__PURE__ */ new Set([
224
- "article",
225
- "listitem",
226
- "menuitem",
227
- "menuitemcheckbox",
228
- "menuitemradio",
229
- "option",
230
- "radio",
231
- "row",
232
- "tab"
233
- ])
234
- ],
235
- ["aria-pressed", /* @__PURE__ */ new Set(["button"])],
236
- [
237
- "aria-readonly",
238
- /* @__PURE__ */ new Set([
239
- "combobox",
240
- "grid",
241
- "gridcell",
242
- "listbox",
243
- "radiogroup",
244
- "slider",
245
- "spinbutton",
246
- "textbox",
247
- "tree",
248
- "treegrid"
249
- ])
250
- ],
251
- [
252
- "aria-required",
253
- /* @__PURE__ */ new Set([
254
- "combobox",
255
- "gridcell",
256
- "listbox",
257
- "radiogroup",
258
- "spinbutton",
259
- "textbox",
260
- "tree",
261
- "treegrid"
262
- ])
263
- ],
264
- ["aria-rowcount", /* @__PURE__ */ new Set(["grid", "table", "treegrid"])],
265
- ["aria-rowindex", /* @__PURE__ */ new Set(["cell", "columnheader", "gridcell", "row", "rowheader"])],
266
- ["aria-rowspan", /* @__PURE__ */ new Set(["cell", "columnheader", "gridcell", "rowheader"])],
267
- [
268
- "aria-selected",
269
- /* @__PURE__ */ new Set(["columnheader", "gridcell", "option", "row", "rowheader", "tab", "treeitem"])
270
- ],
271
- [
272
- "aria-setsize",
273
- /* @__PURE__ */ new Set([
274
- "article",
275
- "listitem",
276
- "menuitem",
277
- "menuitemcheckbox",
278
- "menuitemradio",
279
- "option",
280
- "radio",
281
- "row",
282
- "tab"
283
- ])
284
- ],
285
- ["aria-sort", /* @__PURE__ */ new Set(["columnheader", "rowheader"])],
286
- [
287
- "aria-valuemax",
288
- /* @__PURE__ */ new Set(["meter", "progressbar", "scrollbar", "separator", "slider", "spinbutton"])
289
- ],
290
- [
291
- "aria-valuemin",
292
- /* @__PURE__ */ new Set(["meter", "progressbar", "scrollbar", "separator", "slider", "spinbutton"])
293
- ],
294
- [
295
- "aria-valuenow",
296
- /* @__PURE__ */ new Set(["meter", "progressbar", "scrollbar", "separator", "slider", "spinbutton"])
297
- ],
298
- [
299
- "aria-valuetext",
300
- /* @__PURE__ */ new Set(["meter", "progressbar", "scrollbar", "separator", "slider", "spinbutton"])
301
- ]
302
- ]);
303
- function isUndefined(value) {
304
- return value === void 0;
305
- }
306
- function isGlobalAriaAttribute(attr) {
307
- return GLOBAL_ARIA_ATTRIBUTES.has(attr);
308
- }
309
- function isAriaAttributeValidForRole(attr, role) {
310
- const allowedRoles = ROLE_RESTRICTED_ATTRIBUTES.get(attr);
311
- if (isUndefined(allowedRoles)) return true;
312
- if (isUndefined(role)) return false;
313
- return allowedRoles.has(role);
314
- }
315
- function isStrongImplicitRole(tag) {
316
- if (!(tag in IMPLICIT_ROLE_RECORD)) return false;
317
- return STRONG_ROLES_SET.has(IMPLICIT_ROLE_RECORD[tag]);
318
- }
319
- function isStandaloneTag(tag) {
320
- if (!(tag in IMPLICIT_ROLE_RECORD)) return false;
321
- return STANDALONE_ROLES_SET.has(IMPLICIT_ROLE_RECORD[tag]);
322
- }
323
-
324
- // ../core/dist/chunk-2NJ5XLOA.js
325
- var IMPLICIT_ROLE_RECORD2 = {
326
- article: "article",
327
- aside: "complementary",
328
- footer: "contentinfo",
329
- header: "banner",
330
- main: "main",
331
- nav: "navigation",
332
- button: "button",
333
- a: "link",
334
- select: "listbox",
335
- h1: "heading",
336
- h2: "heading",
337
- h3: "heading",
338
- h4: "heading",
339
- h5: "heading",
340
- h6: "heading",
341
- ul: "list",
342
- ol: "list",
343
- li: "listitem",
344
- table: "table",
345
- tr: "row",
346
- td: "cell",
347
- th: "columnheader"
348
- };
349
- function getImplicitRole(tag) {
350
- if (tag in IMPLICIT_ROLE_RECORD2) return IMPLICIT_ROLE_RECORD2[tag];
351
- return void 0;
352
- }
353
- var COMPONENT_DEFAULT_TAG = /* @__PURE__ */ Symbol.for("praxis.component-default-tag");
354
- function getAsProp(child) {
355
- if (!isObject(child) || !("props" in child)) return void 0;
356
- const props = child.props;
357
- if (!isObject(props)) return void 0;
358
- const as = props.as;
359
- return isString(as) && as !== "" ? as : void 0;
360
- }
361
- function getTag(child) {
362
- if (!isObject(child) || !("type" in child)) return void 0;
363
- const t = child.type;
364
- if (isString(t)) return t;
365
- if (typeof t === "function" || isObject(t)) {
366
- const defaultTag = t[COMPONENT_DEFAULT_TAG];
367
- if (!isString(defaultTag)) return void 0;
368
- return getAsProp(child) ?? defaultTag;
369
- }
370
- return void 0;
371
- }
372
- function isTag(...args) {
373
- if (isString(args[0])) {
374
- const set2 = new Set(args);
375
- return (child2) => {
376
- const tag2 = getTag(child2);
377
- return tag2 !== void 0 && set2.has(tag2);
378
- };
379
- }
380
- const [child, ...tags] = args;
381
- const set = new Set(tags);
382
- const tag = getTag(child);
383
- return tag !== void 0 && set.has(tag);
384
- }
385
- var pendingAsyncWarns = /* @__PURE__ */ new Set();
386
- var asyncWarnScheduled = false;
387
- function flushAsyncWarns() {
388
- asyncWarnScheduled = false;
389
- const messages = [...pendingAsyncWarns];
390
- pendingAsyncWarns.clear();
391
- for (const msg of messages) {
392
- console.warn(msg);
1
+ // ../../lib/primitive/src/utils/iterate.ts
2
+ function find(iterable, callback) {
3
+ for (const value of iterable) {
4
+ const result = callback(value);
5
+ if (result != null) {
6
+ return result;
7
+ }
393
8
  }
9
+ return null;
394
10
  }
395
- function scheduleAsyncWarn(message) {
396
- if (pendingAsyncWarns.has(message)) return;
397
- pendingAsyncWarns.add(message);
398
- if (!asyncWarnScheduled) {
399
- asyncWarnScheduled = true;
400
- queueMicrotask(flushAsyncWarns);
11
+ function some(iterable, predicate) {
12
+ for (const value of iterable) {
13
+ if (predicate(value)) return true;
401
14
  }
15
+ return false;
402
16
  }
403
- var StrictBase = class {
404
- strict;
405
- constructor(strict) {
406
- this.strict = strict;
407
- }
408
- violate(message) {
409
- if (this.strict === true || this.strict === "throw") {
410
- throw new Error(message);
17
+ function every(iterable, predicate) {
18
+ let index = 0;
19
+ for (const value of iterable) {
20
+ if (!predicate(value, index++)) {
21
+ return false;
411
22
  }
412
- this.warn(message);
413
23
  }
414
- // Always caps at console.warn — never throws. ARIA 'warning' violations route here
415
- // so they surface even in strict='throw' mode without aborting a render.
416
- warn(message) {
417
- if (!this.strict) return;
418
- if (this.strict === "async-warn") {
419
- scheduleAsyncWarn(message);
420
- return;
421
- }
422
- console.warn(message);
423
- }
424
- invariant(condition, message) {
425
- if (!condition) {
426
- this.violate(message);
427
- }
428
- }
429
- };
430
- function isNull2(value) {
431
- return value === null;
432
- }
433
- var VALID = [{ valid: true }];
434
- function isIntrinsicTag(tag) {
435
- return isString(tag);
436
- }
437
- function omitProp(obj, key) {
438
- const { [key]: _, ...rest } = obj;
439
- return rest;
24
+ return true;
440
25
  }
441
- var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
442
- #extraRules;
443
- #planCache = /* @__PURE__ */ new Map();
444
- static #MAX_CACHE = 100;
445
- // Memoized AriaFix objects keyed by attribute name — the ARIA attribute set is
446
- // finite so this Map is bounded and avoids recreating closures on every cache miss.
447
- static #removeAttributeFixCache = /* @__PURE__ */ new Map();
448
- constructor(strict = "warn", options) {
449
- super(strict);
450
- this.#extraRules = options?.rules ?? [];
451
- }
452
- static #normalizeEmptyRole(tag, props) {
453
- if (props.role !== "") return { normalized: false };
454
- return {
455
- normalized: true,
456
- result: {
457
- props: omitProp(props, "role"),
458
- violations: [
459
- {
460
- message: `<${tag}> has an explicit empty role="". Omit the attribute instead.`,
461
- tag,
462
- role: "",
463
- attribute: void 0,
464
- severity: "warning",
465
- phase: "evaluate"
466
- }
467
- ]
468
- }
469
- };
470
- }
471
- static #deriveContext(tag, props) {
472
- if (!isIntrinsicTag(tag)) return { proceed: false, result: { props, violations: [] } };
473
- const implicitRole = getImplicitRole(tag);
474
- const hasExplicitLiveRole = !implicitRole && _AriaPolicyEngine.#LIVE_REGION_ROLES.has(props.role ?? "");
475
- if (!implicitRole && !hasExplicitLiveRole)
476
- return { proceed: false, result: { props, violations: [] } };
477
- const normalized = _AriaPolicyEngine.#normalizeEmptyRole(tag, props);
478
- if (normalized.normalized) return { proceed: false, result: normalized.result };
479
- const effectiveRole = props.role ?? implicitRole;
480
- return {
481
- proceed: true,
482
- tag,
483
- implicitRole,
484
- effectiveRole,
485
- context: { tag, props, implicitRole, effectiveRole }
486
- };
487
- }
488
- static #runRules(rules, context) {
489
- const violations = [];
490
- const fixes = [];
491
- for (const rule of rules) {
492
- for (const result of rule(context)) {
493
- if (!result.valid) {
494
- violations.push({
495
- message: result.message ?? `Invalid role "${context.props.role}" on <${context.tag}>`,
496
- tag: context.tag,
497
- role: context.props.role,
498
- attribute: result.attribute,
499
- severity: result.severity,
500
- phase: "evaluate"
501
- });
502
- if (result.fixable) fixes.push(result.fix);
503
- }
504
- }
505
- }
506
- return { violations, fixes };
507
- }
508
- static #getRules(context) {
509
- return _AriaPolicyEngine.#hasRole(context.props) ? _AriaPolicyEngine.#pipeline : [_AriaPolicyEngine.#checkInvalidAriaAttributes];
510
- }
511
- static evaluate(tag, props) {
512
- const derived = _AriaPolicyEngine.#deriveContext(tag, props);
513
- if (!derived.proceed) return derived.result;
514
- const { tag: narrowedTag, implicitRole, context } = derived;
515
- const { violations, fixes } = _AriaPolicyEngine.#runRules(
516
- _AriaPolicyEngine.#getRules(context),
517
- context
518
- );
519
- const next = _AriaPolicyEngine.#applyFixes(narrowedTag, implicitRole, props, fixes);
520
- return { props: next, violations };
521
- }
522
- static #evaluateWithRules(tag, props, extraRules) {
523
- const derived = _AriaPolicyEngine.#deriveContext(tag, props);
524
- if (!derived.proceed) return derived.result;
525
- const { tag: narrowedTag, implicitRole, context } = derived;
526
- const { violations, fixes } = _AriaPolicyEngine.#runRules(
527
- [..._AriaPolicyEngine.#getRules(context), ...extraRules],
528
- context
529
- );
530
- const next = _AriaPolicyEngine.#applyFixes(narrowedTag, implicitRole, props, fixes);
531
- return { props: next, violations };
532
- }
533
- report(violations) {
534
- for (const v of violations) {
535
- if (v.severity === "error") this.violate(v.message);
536
- else this.warn(v.message);
26
+ function* filter(iterable, predicate) {
27
+ let index = 0;
28
+ for (const value of iterable) {
29
+ if (predicate(value, index++)) {
30
+ yield value;
537
31
  }
538
32
  }
539
- // Cache key covers only the aria-relevant subset of props (tag + role + aria-* attrs).
540
- // Non-aria props (className, onClick, etc.) do not affect ARIA decisions and are excluded
541
- // so cache hits survive re-renders that only change non-aria props.
542
- // Note: #extraRules are NOT included in the key — each engine instance has its own Map,
543
- // so two engines with different rules never share cache entries. If caching ever becomes
544
- // static/shared, rule identity would need to be folded into the key.
545
- static #createPlanKey(tag, props) {
546
- if (!isIntrinsicTag(tag)) return null;
547
- const parts = [tag];
548
- if (typeof props.role === "string") parts.push(`role:${props.role}`);
549
- const ariaEntries = [];
550
- for (const k in props) {
551
- if (!Object.hasOwn(props, k) || !k.startsWith("aria-")) continue;
552
- const v = props[k];
553
- if (!isString(v) && !isNumber(v) && typeof v !== "boolean") continue;
554
- ariaEntries.push(`${k}:${String(v)}`);
555
- }
556
- if (ariaEntries.length > 0) parts.push(...ariaEntries.sort());
557
- return parts.join("|");
33
+ }
34
+ function* map(iterable, callback) {
35
+ let index = 0;
36
+ for (const value of iterable) {
37
+ yield callback(value, index++);
558
38
  }
559
- static #computePlan(inputProps, resultProps) {
560
- const removals = /* @__PURE__ */ new Set();
561
- const updates = {};
562
- for (const key in inputProps) {
563
- if (Object.hasOwn(inputProps, key) && !(key in resultProps)) removals.add(key);
564
- }
565
- for (const key in resultProps) {
566
- if (!Object.hasOwn(resultProps, key)) continue;
567
- const resultVal = resultProps[key];
568
- if (inputProps[key] !== resultVal) updates[key] = resultVal;
569
- }
570
- return { removals, updates };
39
+ }
40
+ function forEach(iterable, callback) {
41
+ let index = 0;
42
+ for (const value of iterable) {
43
+ callback(value, index++);
571
44
  }
572
- static #applyPlan(props, removals, updates) {
573
- const hasRemovals = removals.size > 0;
574
- const hasUpdates = Object.keys(updates).length > 0;
575
- if (!hasRemovals && !hasUpdates) return props;
576
- const next = {};
577
- for (const k in props) {
578
- if (Object.hasOwn(props, k) && !removals.has(k)) next[k] = props[k];
579
- }
580
- Object.assign(next, updates);
581
- return next;
45
+ }
46
+ function reduce(iterable, initial, callback) {
47
+ let accumulator = initial;
48
+ let index = 0;
49
+ for (const value of iterable) {
50
+ accumulator = callback(accumulator, value, index++);
582
51
  }
583
- validate(tag, props) {
584
- const key = _AriaPolicyEngine.#createPlanKey(tag, props);
585
- if (!isNull2(key)) {
586
- const cached = this.#planCache.get(key);
587
- if (cached !== void 0) {
588
- this.#planCache.delete(key);
589
- this.#planCache.set(key, cached);
590
- if (cached.violations.length > 0) this.report(cached.violations);
591
- return {
592
- props: _AriaPolicyEngine.#applyPlan(props, cached.removals, cached.updates),
593
- violations: cached.violations
594
- };
595
- }
596
- }
597
- const result = this.#extraRules.length ? _AriaPolicyEngine.#evaluateWithRules(tag, props, this.#extraRules) : _AriaPolicyEngine.evaluate(tag, props);
598
- if (result.violations.length > 0) this.report(result.violations);
599
- if (!isNull2(key)) {
600
- const { removals, updates } = _AriaPolicyEngine.#computePlan(
601
- props,
602
- result.props
603
- );
604
- const plan = { removals, updates, violations: result.violations };
605
- this.#planCache.set(key, plan);
606
- if (this.#planCache.size > _AriaPolicyEngine.#MAX_CACHE) {
607
- const lru = this.#planCache.keys().next().value;
608
- if (lru !== void 0) this.#planCache.delete(lru);
609
- }
52
+ return accumulator;
53
+ }
54
+ function collect(iterable, callback) {
55
+ const result = {};
56
+ let index = 0;
57
+ for (const value of iterable) {
58
+ const entry = callback(value, index++);
59
+ if (entry === null) {
60
+ return null;
610
61
  }
611
- return result;
62
+ result[entry[0]] = entry[1];
612
63
  }
613
- static #hasRole(props) {
614
- return isString(props.role) && props.role.length > 0;
615
- }
616
- static #applyFixes(tag, implicitRole, props, fixes) {
617
- if (fixes.length === 0) return props;
618
- const sorted = [...fixes].sort((a, b) => (a.priority ?? Infinity) - (b.priority ?? Infinity));
619
- let next = props;
620
- for (const { apply } of sorted) {
621
- const effectiveRole = next.role ?? implicitRole;
622
- const fixContext = { tag, implicitRole, effectiveRole, props: next };
623
- const fixResult = apply(fixContext);
624
- if (fixResult.applied) next = fixResult.next;
64
+ return result;
65
+ }
66
+ function findLast(value, callback) {
67
+ for (let index = value.length - 1; index >= 0; index--) {
68
+ const result = callback(value[index], index);
69
+ if (result != null) {
70
+ return result;
625
71
  }
626
- return next;
627
72
  }
628
- static #removeRole = {
629
- kind: "removeRole",
630
- apply: ({ props }) => {
631
- if (!("role" in props)) return { applied: false, next: props };
632
- return { applied: true, next: omitProp(props, "role"), previous: props };
73
+ return null;
74
+ }
75
+ function* items(collection) {
76
+ for (let i = 0; i < collection.length; i++) {
77
+ const item = collection.item(i);
78
+ if (item !== null) {
79
+ yield item;
633
80
  }
634
- };
635
- static #makeRemoveAttributeFix(attr) {
636
- const cached = _AriaPolicyEngine.#removeAttributeFixCache.get(attr);
637
- if (cached) return cached;
638
- const fix = {
639
- kind: `removeAttribute:${attr}`,
640
- apply: ({ props }) => {
641
- if (!(attr in props)) return { applied: false, next: props };
642
- return { applied: true, next: omitProp(props, attr), previous: props };
643
- }
644
- };
645
- _AriaPolicyEngine.#removeAttributeFixCache.set(attr, fix);
646
- return fix;
647
81
  }
648
- // Snapshot diagnostic model: all rules evaluate against the same (tag, props, implicitRole) snapshot.
649
- static #pipeline = [
650
- _AriaPolicyEngine.#checkInvalidRoleOverride,
651
- _AriaPolicyEngine.#checkRedundantRole,
652
- _AriaPolicyEngine.#checkStandaloneRegion,
653
- _AriaPolicyEngine.#checkInvalidAriaAttributes,
654
- _AriaPolicyEngine.#checkMissingLiveRegion,
655
- _AriaPolicyEngine.#checkMissingAtomic,
656
- _AriaPolicyEngine.#checkInvalidAriaRelevant
657
- ];
658
- static #checkInvalidRoleOverride({
659
- tag,
660
- props,
661
- implicitRole
662
- }) {
663
- const role = props.role;
664
- if (!implicitRole || !role || role === implicitRole) return VALID;
665
- if (isStrongImplicitRole(tag) && role === "region") {
666
- return [
667
- {
668
- valid: false,
669
- fixable: true,
670
- severity: "error",
671
- fix: _AriaPolicyEngine.#removeRole,
672
- message: `<${tag}> should not override its implicit role="${implicitRole}" with role="${role}".`
82
+ }
83
+ function nodeList(list) {
84
+ return {
85
+ *[Symbol.iterator]() {
86
+ for (let i = 0; i < list.length; i++) {
87
+ const node = list.item(i);
88
+ if (node !== null) {
89
+ yield node;
673
90
  }
674
- ];
675
- }
676
- return VALID;
677
- }
678
- static #checkRedundantRole({ tag, props, implicitRole }) {
679
- const role = props.role;
680
- if (!implicitRole || !role || role !== implicitRole) return VALID;
681
- return [
682
- {
683
- valid: false,
684
- fixable: true,
685
- severity: "warning",
686
- fix: _AriaPolicyEngine.#removeRole,
687
- message: `<${tag}> already has implicit role="${implicitRole}". Avoid redundant role assignment.`
688
- }
689
- ];
690
- }
691
- static #checkStandaloneRegion({ tag, props, implicitRole }) {
692
- const role = props.role;
693
- if (role !== "region") return VALID;
694
- if (!isStandaloneTag(tag)) return VALID;
695
- return [
696
- {
697
- valid: false,
698
- fixable: true,
699
- severity: "error",
700
- fix: _AriaPolicyEngine.#removeRole,
701
- message: `<${tag}> is a self-contained element with implicit role="${implicitRole}". Assigning role="region" has been removed.`
702
91
  }
703
- ];
704
- }
705
- static #checkInvalidAriaAttributes({
706
- tag,
707
- props,
708
- effectiveRole
709
- }) {
710
- const results = [];
711
- for (const key in props) {
712
- if (!Object.hasOwn(props, key)) continue;
713
- if (!key.startsWith("aria-")) continue;
714
- if (isGlobalAriaAttribute(key)) continue;
715
- if (isAriaAttributeValidForRole(key, effectiveRole)) continue;
716
- results.push({
717
- valid: false,
718
- severity: "warning",
719
- fixable: true,
720
- attribute: key,
721
- message: `"${key}" is not valid on role="${effectiveRole ?? tag}". It will be removed.`,
722
- fix: _AriaPolicyEngine.#makeRemoveAttributeFix(key)
723
- });
724
92
  }
725
- return results;
726
- }
727
- // WAI-ARIA live region roles and their implied aria-live politeness values.
728
- static #LIVE_REGION_ROLES = /* @__PURE__ */ new Map([
729
- ["alert", "assertive"],
730
- ["status", "polite"],
731
- ["log", "polite"],
732
- ["timer", "off"]
733
- ]);
734
- static #checkMissingLiveRegion({ effectiveRole, props }) {
735
- if (!effectiveRole) return VALID;
736
- const impliedLive = _AriaPolicyEngine.#LIVE_REGION_ROLES.get(effectiveRole);
737
- if (!impliedLive) return VALID;
738
- if ("aria-live" in props) return VALID;
739
- const injectLive = {
740
- kind: `injectLive:${effectiveRole}`,
741
- apply: (ctx) => ({
742
- applied: true,
743
- next: { ...ctx.props, "aria-live": impliedLive },
744
- previous: ctx.props
745
- })
746
- };
747
- return [
748
- {
749
- valid: false,
750
- fixable: true,
751
- severity: "warning",
752
- fix: injectLive,
753
- message: `role="${effectiveRole}" implies aria-live="${impliedLive}" but it is missing. It has been injected.`
754
- }
755
- ];
756
- }
757
- static #checkMissingAtomic({ effectiveRole, props }) {
758
- if (!effectiveRole || !_AriaPolicyEngine.#LIVE_REGION_ROLES.has(effectiveRole)) return VALID;
759
- if ("aria-atomic" in props) return VALID;
760
- return [
761
- {
762
- valid: false,
763
- fixable: false,
764
- severity: "warning",
765
- message: `role="${effectiveRole}" is a live region. Consider setting aria-atomic="true" if the full region should be announced as a unit, or aria-atomic="false" if only changed nodes should be read.`
766
- }
767
- ];
768
- }
769
- static #VALID_RELEVANT_TOKENS = /* @__PURE__ */ new Set(["additions", "removals", "text", "all"]);
770
- // Custom fix rules passed via `options.rules` must be pure functions of (tag, props) — the cache
771
- // replays stored fixes against new prop objects, so fixes that close over external state will
772
- // produce inconsistent results on cache hits.
773
- static #normalizeRelevantAllFix = {
774
- kind: "normalizeRelevantAll",
775
- apply: ({ props: p }) => ({
776
- applied: true,
777
- next: { ...p, "aria-relevant": "all" },
778
- previous: p
779
- })
780
93
  };
781
- static #checkInvalidAriaRelevant({ props }) {
782
- const relevant = props["aria-relevant"];
783
- if (relevant === void 0) return VALID;
784
- if (typeof relevant !== "string") return VALID;
785
- const tokens = relevant.trim().split(/\s+/);
786
- const invalid = tokens.filter((t) => !_AriaPolicyEngine.#VALID_RELEVANT_TOKENS.has(t));
787
- if (invalid.length > 0) {
788
- return [
789
- {
790
- valid: false,
791
- fixable: true,
792
- severity: "warning",
793
- attribute: "aria-relevant",
794
- message: `aria-relevant contains invalid token(s): ${invalid.map((t) => `"${t}"`).join(", ")}. Valid tokens are: additions, removals, text, all.`,
795
- fix: _AriaPolicyEngine.#makeRemoveAttributeFix("aria-relevant")
796
- }
797
- ];
798
- }
799
- if (tokens.includes("all") && tokens.length > 1) {
800
- return [
801
- {
802
- valid: false,
803
- fixable: true,
804
- severity: "warning",
805
- attribute: "aria-relevant",
806
- message: `aria-relevant includes "all" alongside other tokens. "all" supersedes additions, removals, and text \u2014 use aria-relevant="all" alone.`,
807
- fix: _AriaPolicyEngine.#normalizeRelevantAllFix
808
- }
809
- ];
810
- }
811
- return VALID;
812
- }
813
- };
814
- function getTypeName(value) {
815
- if (value === null) return "null";
816
- if (value === void 0) return "undefined";
817
- const primitive = typeof value;
818
- if (primitive !== "object") {
819
- return primitive;
820
- }
821
- const name = value.constructor?.name;
822
- return typeof name === "string" && name !== "Object" ? name : "object";
823
94
  }
824
- var MatchValidationErrorBuilder = class {
825
- #prefix;
826
- constructor(ctx = "") {
827
- this.#prefix = ctx ? `${ctx}:
828
- ` : "";
829
- }
830
- #template(typeName, index, prefix = "", suffix = "") {
831
- const leadingStr = prefix ? `${prefix} ` : "";
832
- const followingStr = suffix ? ` ${suffix}` : "";
833
- return `${leadingStr}child "${typeName}" at index ${index}${followingStr}.`;
834
- }
835
- unexpectedChild(typeName, index) {
836
- return this.#template(typeName, index, "unexpected");
837
- }
838
- multipleMatches(typeName, index, ruleNames) {
839
- const quoted = ruleNames.map((n) => `"${n}"`);
840
- return this.#template(
841
- typeName,
842
- index,
843
- "",
844
- `matches multiple child rules: ${quoted.join(" and ")}`
845
- );
846
- }
847
- #format(errors) {
848
- return this.#prefix + errors.join("\n");
849
- }
850
- toError(errors) {
851
- if (errors.length === 0) {
852
- return new Error(this.#prefix + "Unknown validation error.");
853
- }
854
- return new Error(this.#format(errors));
855
- }
856
- };
857
- function normalizeCardinality(input, impliesSingleton) {
858
- const min = input?.min ?? 0;
859
- const max = input?.max ?? (impliesSingleton ? 1 : Infinity);
860
- if (min === 0 && max === Infinity) {
861
- return { kind: "unbounded" };
862
- }
863
- if (min > max) {
864
- throw new RangeError(`normalizeChildRule: min (${min}) cannot exceed max (${max})`);
865
- }
866
- return {
867
- kind: "bounded",
868
- min,
869
- max
870
- };
95
+ function mapEntries(m) {
96
+ return m.entries();
871
97
  }
872
- function normalizeChildRule(rule) {
873
- const position = rule.position ?? "any";
874
- const impliesSingleton = position === "first" || position === "last";
875
- return {
876
- ...rule,
877
- position,
878
- cardinality: normalizeCardinality(rule.cardinality, impliesSingleton)
879
- };
98
+ function set(s) {
99
+ return s.values();
880
100
  }
881
- function getChildType(child) {
882
- if (!isObject(child) || !("type" in child)) return void 0;
883
- return child.type;
101
+ function hasOwn(object, key) {
102
+ return Object.hasOwn(object, key);
884
103
  }
885
- function buildPartialIndex(rules) {
886
- const typeIndex = /* @__PURE__ */ new Map();
887
- const duplicateTypes = /* @__PURE__ */ new Set();
888
- const untypedIndices = [];
889
- for (let ri = 0; ri < rules.length; ri++) {
890
- const t = rules[ri].type;
891
- if (t === void 0) {
892
- untypedIndices.push(ri);
893
- } else if (typeIndex.has(t)) {
894
- duplicateTypes.add(t);
895
- } else {
896
- typeIndex.set(t, ri);
897
- }
104
+ function* entries(object) {
105
+ for (const key in object) {
106
+ if (!hasOwn(object, key)) continue;
107
+ yield [key, object[key]];
898
108
  }
899
- if (duplicateTypes.size > 0) {
900
- for (const t of duplicateTypes) typeIndex.delete(t);
901
- for (let ri = 0; ri < rules.length; ri++) {
902
- if (duplicateTypes.has(rules[ri].type)) untypedIndices.push(ri);
903
- }
904
- }
905
- return { typeIndex, untypedIndices };
906
109
  }
907
- var RuleMatcher = class {
908
- #rules;
909
- #typeIndex;
910
- #untypedIndices;
911
- constructor(rules) {
912
- this.#rules = rules;
913
- const { typeIndex, untypedIndices } = buildPartialIndex(rules);
914
- this.#typeIndex = typeIndex;
915
- this.#untypedIndices = untypedIndices;
110
+ function* keys(object) {
111
+ for (const [key] of entries(object)) {
112
+ yield key;
916
113
  }
917
- match(children) {
918
- const forward = /* @__PURE__ */ new Map();
919
- const reverse = /* @__PURE__ */ new Map();
920
- const unexpectedIndices = /* @__PURE__ */ new Set();
921
- const ambiguousIndices = /* @__PURE__ */ new Set();
922
- for (let ri = 0; ri < this.#rules.length; ri++) {
923
- reverse.set(ri, /* @__PURE__ */ new Set());
924
- }
925
- for (const [ci, child] of children.entries()) {
926
- const t = getChildType(child);
927
- if (t !== void 0) {
928
- const ri = this.#typeIndex.get(t);
929
- if (ri !== void 0) {
930
- let childEntry = forward.get(ci);
931
- if (!childEntry) {
932
- childEntry = /* @__PURE__ */ new Set();
933
- forward.set(ci, childEntry);
934
- }
935
- childEntry.add(ri);
936
- reverse.get(ri).add(ci);
937
- }
938
- }
939
- for (const ri of this.#untypedIndices) {
940
- if (!this.#rules[ri].match(child)) continue;
941
- let childEntry = forward.get(ci);
942
- if (!childEntry) {
943
- childEntry = /* @__PURE__ */ new Set();
944
- forward.set(ci, childEntry);
945
- }
946
- childEntry.add(ri);
947
- reverse.get(ri).add(ci);
948
- }
949
- const entry = forward.get(ci);
950
- if (!entry) {
951
- unexpectedIndices.add(ci);
952
- } else if (entry.size > 1) {
953
- ambiguousIndices.add(ci);
954
- }
955
- }
956
- return { matrix: { childToRules: { forward, reverse } }, unexpectedIndices, ambiguousIndices };
957
- }
958
- };
959
- var RuleValidator = class _RuleValidator extends StrictBase {
960
- #context;
961
- constructor(context, strict) {
962
- super(strict);
963
- this.#context = context;
964
- }
965
- validate(rules, matrix, childCount) {
966
- const firstIndex = 0;
967
- const lastIndex = childCount - 1;
968
- for (const [ri, rule] of rules.entries()) {
969
- const matches = matrix.childToRules.reverse.get(ri);
970
- const matchCount = matches.size;
971
- this.#validateCardinality(rule, matchCount);
972
- if (matchCount === 0) continue;
973
- this.#validatePositions(rule, matches, firstIndex, lastIndex);
974
- }
114
+ }
115
+ function* values(object) {
116
+ for (const [, value] of entries(object)) {
117
+ yield value;
975
118
  }
976
- #validateCardinality(rule, matchCount) {
977
- const { cardinality, name } = rule;
978
- if (cardinality.kind !== "bounded") {
979
- return;
980
- }
981
- const { min, max } = cardinality;
982
- if (matchCount < min) {
983
- this.violate(`${this.#context}: "${name}" requires at least ${min}.`);
984
- return;
985
- }
986
- if (matchCount > max) {
987
- this.violate(`${this.#context}: "${name}" allows at most ${max}.`);
988
- }
119
+ }
120
+ function mapValues(object, callback) {
121
+ const result = {};
122
+ for (const [key, value] of entries(object)) {
123
+ result[key] = callback(value, key);
989
124
  }
990
- #validatePositions(rule, matches, firstIndex, lastIndex) {
991
- const { name, position } = rule;
992
- for (const index of matches) {
993
- if (_RuleValidator.#isValidPosition(index, position, firstIndex, lastIndex)) {
994
- continue;
995
- }
996
- this.violate(`${this.#context}: "${name}" must be ${position}, got index ${index}`);
997
- }
125
+ return result;
126
+ }
127
+ function forEachEntry(object, callback) {
128
+ for (const [key, value] of entries(object)) {
129
+ callback(key, value);
998
130
  }
999
- static #isValidPosition(matchIndex, position, firstIndex, lastIndex) {
1000
- switch (position) {
1001
- case "first":
1002
- return matchIndex === firstIndex;
1003
- case "last":
1004
- return matchIndex === lastIndex;
1005
- case "any":
1006
- return true;
1007
- default:
1008
- return assertNever(position);
1009
- }
131
+ }
132
+ function forEachKey(object, callback) {
133
+ for (const key of keys(object)) {
134
+ callback(key);
1010
135
  }
1011
- };
1012
- var ChildrenEvaluator = class extends StrictBase {
1013
- #rules;
1014
- #ruleNames;
1015
- #matcher;
1016
- #ruleValidator;
1017
- #matchBuilder;
1018
- constructor(rules, strict = "warn", context = "Component") {
1019
- super(strict);
1020
- this.#rules = rules.map((r) => normalizeChildRule(r));
1021
- this.#ruleNames = this.#rules.map((r) => r.name);
1022
- for (const rule of this.#rules) {
1023
- const { name, position, cardinality } = rule;
1024
- if ((position === "first" || position === "last") && (cardinality.kind === "unbounded" || cardinality.max > 1)) {
1025
- throw new RangeError(
1026
- `ChildrenEvaluator [${context}]: rule "${name}" sets position="${position}" with an unbound or >1 max. position="first|last" implies max=1.`
1027
- );
1028
- }
1029
- }
1030
- this.#matcher = new RuleMatcher(this.#rules);
1031
- this.#ruleValidator = new RuleValidator(context, strict);
1032
- this.#matchBuilder = new MatchValidationErrorBuilder(context);
136
+ }
137
+ function forEachValue(object, callback) {
138
+ for (const value of values(object)) {
139
+ callback(value);
1033
140
  }
1034
- evaluate(children) {
1035
- if (!this.strict) return;
1036
- const { matrix, unexpectedIndices, ambiguousIndices } = this.#matcher.match(children);
1037
- this.#ruleValidator.validate(this.#rules, matrix, children.length);
1038
- if (unexpectedIndices.size === 0 && ambiguousIndices.size === 0) return;
1039
- const errors = [];
1040
- const violating = [...unexpectedIndices, ...ambiguousIndices].sort((a, b) => a - b);
1041
- for (const ci of violating) {
1042
- const typeName = getTypeName(children[ci]);
1043
- if (unexpectedIndices.has(ci)) {
1044
- errors.push(this.#matchBuilder.unexpectedChild(typeName, ci));
1045
- } else {
1046
- const matches = matrix.childToRules.forward.get(ci);
1047
- const names = [...matches].map((ri) => this.#ruleNames[ri] ?? `#${ri}`);
1048
- errors.push(this.#matchBuilder.multipleMatches(typeName, ci, names));
1049
- }
1050
- }
1051
- this.invariant(errors.length === 0, this.#matchBuilder.toError(errors).message);
141
+ }
142
+ function forEachSet(s, callback) {
143
+ for (const value of s) {
144
+ callback(value);
1052
145
  }
1053
- };
146
+ }
147
+ var iterate = Object.freeze({
148
+ entries,
149
+ filter,
150
+ find,
151
+ findLast,
152
+ forEach,
153
+ forEachEntry,
154
+ forEachKey,
155
+ forEachSet,
156
+ forEachValue,
157
+ items,
158
+ keys,
159
+ map,
160
+ mapEntries,
161
+ mapValues,
162
+ nodeList,
163
+ reduce,
164
+ collect,
165
+ set,
166
+ some,
167
+ every,
168
+ values
169
+ });
170
+
171
+ // ../../lib/contract/src/props/get-active-props.ts
1054
172
  var activeProps = ({
1055
173
  active,
1056
174
  "aria-current": ariaCurrent,
@@ -1066,6 +184,8 @@ var activeProps = ({
1066
184
  }
1067
185
  };
1068
186
  };
187
+
188
+ // ../../lib/contract/src/props/get-disabled-props.ts
1069
189
  var disabledProps = ({
1070
190
  disabled,
1071
191
  "aria-disabled": ariaDisabled,
@@ -1077,6 +197,8 @@ var disabledProps = ({
1077
197
  ...dataDisabled === void 0 && { "data-disabled": "" }
1078
198
  };
1079
199
  };
200
+
201
+ // ../../lib/contract/src/props/get-expanded-props.ts
1080
202
  var expandedProps = ({
1081
203
  expanded,
1082
204
  "aria-expanded": ariaExpanded,
@@ -1092,6 +214,8 @@ var expandedProps = ({
1092
214
  }
1093
215
  };
1094
216
  };
217
+
218
+ // ../../lib/contract/src/props/get-invalid-props.ts
1095
219
  var invalidProps = ({
1096
220
  invalid,
1097
221
  "aria-invalid": ariaInvalid,
@@ -1103,6 +227,8 @@ var invalidProps = ({
1103
227
  ...dataInvalid === void 0 && { "data-invalid": "" }
1104
228
  };
1105
229
  };
230
+
231
+ // ../../lib/contract/src/props/get-loading-props.ts
1106
232
  var loadingProps = ({
1107
233
  loading,
1108
234
  "aria-busy": ariaBusy,
@@ -1118,6 +244,8 @@ var loadingProps = ({
1118
244
  }
1119
245
  };
1120
246
  };
247
+
248
+ // ../../lib/contract/src/props/get-pressed-props.ts
1121
249
  var pressedProps = ({
1122
250
  pressed,
1123
251
  "aria-pressed": ariaPressed,
@@ -1133,6 +261,8 @@ var pressedProps = ({
1133
261
  }
1134
262
  };
1135
263
  };
264
+
265
+ // ../../lib/contract/src/props/get-readonly-props.ts
1136
266
  var readonlyProps = ({
1137
267
  readOnly,
1138
268
  "aria-readonly": ariaReadonly,
@@ -1148,6 +278,8 @@ var readonlyProps = ({
1148
278
  }
1149
279
  };
1150
280
  };
281
+
282
+ // ../../lib/contract/src/props/get-selected-props.ts
1151
283
  var selectedProps = ({
1152
284
  selected,
1153
285
  "aria-selected": ariaSelected,
@@ -1163,174 +295,8 @@ var selectedProps = ({
1163
295
  }
1164
296
  };
1165
297
  };
1166
- var LANDMARK_TAG_SET = /* @__PURE__ */ new Set(["article", "aside", "footer", "header", "main", "nav"]);
1167
- var removeLandmarkRoleOverride = {
1168
- kind: "removeRole",
1169
- apply: ({ props }) => {
1170
- if (!("role" in props)) return { applied: false, next: props };
1171
- const { role: _r, ...rest } = props;
1172
- return { applied: true, next: rest, previous: props };
1173
- }
1174
- };
1175
- function landmarkRoleRule({ tag, props, implicitRole }) {
1176
- if (!LANDMARK_TAG_SET.has(tag) || !implicitRole) return [];
1177
- const role = props.role;
1178
- if (!role || role === implicitRole) return [];
1179
- return [
1180
- {
1181
- valid: false,
1182
- fixable: true,
1183
- severity: "error",
1184
- fix: removeLandmarkRoleOverride,
1185
- message: `<${tag}> has a fixed landmark role="${implicitRole}". role="${role}" overrides it and confuses assistive technology. The override has been removed.`
1186
- }
1187
- ];
1188
- }
1189
- function isOpenContent(...blockedTags) {
1190
- const set = new Set(blockedTags);
1191
- return (child) => isObject(child) && "type" in child && (!isString(child.type) || !set.has(child.type));
1192
- }
1193
- var METADATA_TAGS = ["script", "template"];
1194
- var metadataMatch = isTag(...METADATA_TAGS);
1195
- function metadata(name = "metadata") {
1196
- return { name, match: metadataMatch };
1197
- }
1198
- function firstOptional(name, tag) {
1199
- return { name, match: isTag(tag), cardinality: { max: 1 }, position: "first" };
1200
- }
1201
- function contract(children) {
1202
- return { strict: "warn", children };
1203
- }
1204
- function ariaContract(aria) {
1205
- return { strict: "warn", aria };
1206
- }
1207
- function firstChildContract(name, tag) {
1208
- return contract([firstOptional(name, tag), { name: "content", match: isOpenContent(tag) }]);
1209
- }
1210
- var VOID_TAGS = [
1211
- "area",
1212
- "base",
1213
- "br",
1214
- "col",
1215
- "embed",
1216
- "hr",
1217
- "img",
1218
- "input",
1219
- "link",
1220
- "meta",
1221
- "param",
1222
- "source",
1223
- "track",
1224
- "wbr"
1225
- ];
1226
- var TEXT_ONLY_TAGS = ["option", "script", "style", "textarea", "title"];
1227
- var LANDMARK_TAGS = ["article", "aside", "footer", "header", "main", "nav"];
1228
- var listContract = contract([{ name: "list-item", match: isTag("li", ...METADATA_TAGS) }]);
1229
- var tableContract = contract([
1230
- firstOptional("caption", "caption"),
1231
- { name: "colgroup", match: isTag("colgroup") },
1232
- { name: "thead", match: isTag("thead"), cardinality: { max: 1 } },
1233
- { name: "tbody", match: isTag("tbody") },
1234
- { name: "tfoot", match: isTag("tfoot"), cardinality: { max: 1 } },
1235
- { name: "table-row", match: isTag("tr", ...METADATA_TAGS) }
1236
- ]);
1237
- var tableBodyContract = contract([
1238
- { name: "table-row", match: isTag("tr", ...METADATA_TAGS) }
1239
- ]);
1240
- var tableRowContract = contract([
1241
- { name: "table-cell", match: isTag("td", "th", ...METADATA_TAGS) }
1242
- ]);
1243
- var colgroupContract = contract([{ name: "column", match: isTag("col", "template") }]);
1244
- var dlContract = contract([
1245
- { name: "term", match: isTag("dt") },
1246
- { name: "description", match: isTag("dd") },
1247
- { name: "group", match: isTag("div") },
1248
- metadata()
1249
- ]);
1250
- var selectContract = contract([
1251
- { name: "option", match: isTag("option", "optgroup", "hr", ...METADATA_TAGS) }
1252
- ]);
1253
- var optgroupContract = contract([
1254
- { name: "option", match: isTag("option", ...METADATA_TAGS) }
1255
- ]);
1256
- var datalistContract = contract([
1257
- { name: "option", match: isTag("option", ...METADATA_TAGS) }
1258
- ]);
1259
- var pictureContract = contract([
1260
- { name: "source", match: isTag("source", ...METADATA_TAGS) },
1261
- { name: "image", match: isTag("img"), cardinality: { min: 1, max: 1 }, position: "last" }
1262
- ]);
1263
- var figureContract = contract([
1264
- { name: "caption", match: isTag("figcaption"), cardinality: { max: 1 } },
1265
- { name: "content", match: isOpenContent("figcaption") }
1266
- ]);
1267
- var detailsContract = firstChildContract("summary", "summary");
1268
- var fieldsetContract = firstChildContract("legend", "legend");
1269
- var mediaContract = contract([
1270
- { name: "source", match: isTag("source") },
1271
- { name: "track", match: isTag("track") },
1272
- metadata(),
1273
- { name: "content", match: isOpenContent("source", "track", ...METADATA_TAGS) }
1274
- ]);
1275
- var headContract = contract([
1276
- {
1277
- name: "metadata",
1278
- match: isTag("base", "link", "meta", "noscript", "script", "style", "template", "title")
1279
- }
1280
- ]);
1281
- var htmlContract = contract([
1282
- { name: "head", match: isTag("head"), cardinality: { min: 1, max: 1 }, position: "first" },
1283
- { name: "body", match: isTag("body"), cardinality: { min: 1, max: 1 } }
1284
- ]);
1285
- var voidContract = contract([]);
1286
- var textOnlyContract = contract([
1287
- {
1288
- name: "text",
1289
- match: (child) => isString(child) || isNumber(child)
1290
- }
1291
- ]);
1292
- var landmarkContract = ariaContract([landmarkRoleRule]);
1293
- var CONTRACT_GROUPS = [
1294
- [VOID_TAGS, voidContract],
1295
- [TEXT_ONLY_TAGS, textOnlyContract],
1296
- [LANDMARK_TAGS, landmarkContract],
1297
- [["ul", "ol", "menu"], listContract],
1298
- [["audio", "video"], mediaContract],
1299
- [["thead", "tbody", "tfoot"], tableBodyContract]
1300
- ];
1301
- function contractMap(groups) {
1302
- return Object.fromEntries(
1303
- groups.flatMap(([tags, enforcement]) => tags.map((tag) => [tag, enforcement]))
1304
- );
1305
- }
1306
- var htmlContracts = {
1307
- ...contractMap(CONTRACT_GROUPS),
1308
- table: tableContract,
1309
- tr: tableRowContract,
1310
- colgroup: colgroupContract,
1311
- dl: dlContract,
1312
- select: selectContract,
1313
- optgroup: optgroupContract,
1314
- datalist: datalistContract,
1315
- picture: pictureContract,
1316
- figure: figureContract,
1317
- details: detailsContract,
1318
- fieldset: fieldsetContract,
1319
- head: headContract,
1320
- html: htmlContract
1321
- };
1322
- function buildEvaluatorMap() {
1323
- const map = /* @__PURE__ */ new Map();
1324
- for (const [tag, { children }] of Object.entries(htmlContracts)) {
1325
- if (children?.length) {
1326
- map.set(tag, new ChildrenEvaluator(children, "warn", `<${tag}>`));
1327
- }
1328
- }
1329
- return map;
1330
- }
1331
- var HTML_EVALUATORS = buildEvaluatorMap();
1332
298
 
1333
- // ../core/dist/contract.js
299
+ // ../core/src/state/contracts.ts
1334
300
  function stateContract(props) {
1335
301
  return { props };
1336
302
  }
@@ -1342,21 +308,23 @@ var loadingContract = stateContract([loadingProps]);
1342
308
  var pressedContract = stateContract([pressedProps]);
1343
309
  var readonlyContract = stateContract([readonlyProps]);
1344
310
  var selectedContract = stateContract([selectedProps]);
311
+
312
+ // ../core/src/state/merge-contracts.ts
1345
313
  function mergeContracts(...contracts) {
1346
314
  const props = contracts.flatMap((c) => c.props ?? []);
1347
315
  const aria = contracts.flatMap((c) => c.aria ?? []);
1348
316
  const children = contracts.flatMap((c) => c.children ?? []);
1349
- let strict;
317
+ let diagnostics;
1350
318
  let allowedAs;
1351
- for (const c of contracts) {
1352
- if (c.strict !== void 0) strict = c.strict;
319
+ iterate.forEach(contracts, (c) => {
320
+ if (c.diagnostics !== void 0) diagnostics = c.diagnostics;
1353
321
  if (c.allowedAs !== void 0) allowedAs = c.allowedAs;
1354
- }
322
+ });
1355
323
  return {
1356
324
  ...props.length > 0 && { props },
1357
325
  ...aria.length > 0 && { aria },
1358
326
  ...children.length > 0 && { children },
1359
- ...strict !== void 0 && { strict },
327
+ ...diagnostics !== void 0 && { diagnostics },
1360
328
  ...allowedAs !== void 0 && { allowedAs }
1361
329
  };
1362
330
  }