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,288 +1,315 @@
1
- // ../shared/src/guards/children/component-id.ts
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
- // ../../adapters/solid/src/apply-display-name.ts
5
- function applyDisplayName(component, name) {
6
- Object.assign(component, { displayName: name ?? "PolymorphicComponent" });
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";
7
14
  }
8
15
 
9
- // ../../lib/adapter-utils/src/apply-filter.ts
10
- function applyFilter(props, filterProps, variantKeys) {
11
- const out = {};
12
- for (const k in props) {
13
- if (!Object.hasOwn(props, k)) continue;
14
- if (filterProps(k, variantKeys)) continue;
15
- out[k] = props[k];
16
- }
17
- return out;
16
+ // ../../lib/primitive/src/guards/foundational/is-defined.ts
17
+ function isUndefined(value) {
18
+ return value === void 0;
18
19
  }
19
20
 
20
- // ../../lib/adapter-utils/src/define-component.ts
21
- function defineContractComponent(options) {
22
- return (factory) => factory(options);
21
+ // ../../lib/primitive/src/guards/foundational/is-null.ts
22
+ function isNull(value) {
23
+ return value === null;
23
24
  }
24
25
 
25
- // ../core/dist/chunk-KKSHJDE7.js
26
+ // ../../lib/adapter-utils/src/apply-display-name.ts
27
+ function applyDisplayName(component, name) {
28
+ Object.assign(component, { displayName: name ?? "PolymorphicComponent" });
29
+ }
30
+
31
+ // ../../lib/primitive/src/tag/resolve-tag.ts
26
32
  function makeResolveTag(defaultTag) {
27
33
  return function tag(as) {
28
34
  return as ?? defaultTag;
29
35
  };
30
36
  }
37
+
38
+ // ../../lib/primitive/src/utils/assert-never.ts
31
39
  function assertNever(value) {
32
40
  throw new Error(`Unexpected value: ${String(value)}`);
33
41
  }
34
- function r(e) {
35
- var t, f, n = "";
36
- if ("string" == typeof e || "number" == typeof e) n += e;
37
- else if ("object" == typeof e) if (Array.isArray(e)) {
38
- var o = e.length;
39
- for (t = 0; t < o; t++) e[t] && (f = r(e[t])) && (n && (n += " "), n += f);
40
- } else for (f in e) e[f] && (n && (n += " "), n += f);
41
- return n;
42
- }
43
- function clsx() {
44
- for (var e, t, f = 0, n = "", o = arguments.length; f < o; f++) (e = arguments[f]) && (t = r(e)) && (n && (n += " "), n += t);
45
- return n;
46
- }
42
+
43
+ // ../../lib/primitive/src/utils/cn.ts
44
+ import { clsx } from "clsx";
47
45
  function cn(...inputs) {
48
46
  return clsx(...inputs);
49
47
  }
50
- function mergeProps(defaultProps, props) {
51
- return {
52
- ...defaultProps ?? {},
53
- ...props
54
- };
55
- }
56
- function isNull(value) {
57
- return value === null;
58
- }
59
- function isObject(value) {
60
- return !isNull(value) && typeof value === "object";
48
+
49
+ // ../../lib/primitive/src/utils/iterate.ts
50
+ function find(iterable, callback) {
51
+ for (const value of iterable) {
52
+ const result = callback(value);
53
+ if (result != null) {
54
+ return result;
55
+ }
56
+ }
57
+ return null;
61
58
  }
62
- function isString(value) {
63
- return typeof value === "string";
59
+ function some(iterable, predicate) {
60
+ for (const value of iterable) {
61
+ if (predicate(value)) return true;
62
+ }
63
+ return false;
64
64
  }
65
- function isNumber(value) {
66
- return typeof value === "number";
65
+ function every(iterable, predicate) {
66
+ let index = 0;
67
+ for (const value of iterable) {
68
+ if (!predicate(value, index++)) {
69
+ return false;
70
+ }
71
+ }
72
+ return true;
67
73
  }
68
- var EMPTY_VARIANT_KEYS = /* @__PURE__ */ new Set();
69
- function composeNormalizers(normalizers, fn) {
70
- if (!normalizers?.length) return fn;
71
- return ((props) => {
72
- const patched = normalizers.reduce(
73
- (acc, normalizer) => ({ ...acc, ...normalizer(acc) }),
74
- props
75
- );
76
- return fn ? fn(patched) : patched;
77
- });
74
+ function* filter(iterable, predicate) {
75
+ let index = 0;
76
+ for (const value of iterable) {
77
+ if (predicate(value, index++)) {
78
+ yield value;
79
+ }
80
+ }
78
81
  }
79
- function whenDefined(key, value) {
80
- return value === void 0 ? {} : { [key]: value };
82
+ function* map(iterable, callback) {
83
+ let index = 0;
84
+ for (const value of iterable) {
85
+ yield callback(value, index++);
86
+ }
81
87
  }
82
- function resolveFactoryOptions(options = {}) {
83
- const { styling, enforcement } = options;
84
- const composedNormalizeFn = composeNormalizers(enforcement?.props, options.normalize);
85
- const variantKeys = styling?.variants === void 0 ? EMPTY_VARIANT_KEYS : new Set(Object.keys(styling.variants));
86
- return Object.freeze({
87
- defaultTag: options.tag ?? "div",
88
- strict: enforcement?.strict ?? false,
89
- variantKeys,
90
- ...whenDefined("displayName", options.name),
91
- ...whenDefined("defaultProps", options.defaults),
92
- ...whenDefined("baseClassName", styling?.base),
93
- ...whenDefined("tagMap", styling?.tags),
94
- ...whenDefined("recipeMap", styling?.presets),
95
- ...whenDefined("variants", styling?.variants),
96
- ...whenDefined("defaultVariants", styling?.defaults),
97
- ...whenDefined("compoundVariants", styling?.compounds),
98
- ...whenDefined("normalizeFn", composedNormalizeFn),
99
- ...whenDefined("ariaRules", enforcement?.aria),
100
- ...whenDefined("childRules", enforcement?.children),
101
- ...whenDefined("allowedAs", enforcement?.allowedAs),
102
- ...whenDefined("precomputedClasses", styling?.precomputedClasses)
103
- });
88
+ function forEach(iterable, callback) {
89
+ let index = 0;
90
+ for (const value of iterable) {
91
+ callback(value, index++);
92
+ }
104
93
  }
105
- function report(strict, message) {
106
- if (strict === false) return;
107
- const mode = strict === true ? "throw" : strict;
108
- if (mode === "throw") throw new Error(message);
109
- console.warn(message);
94
+ function reduce(iterable, initial, callback) {
95
+ let accumulator = initial;
96
+ let index = 0;
97
+ for (const value of iterable) {
98
+ accumulator = callback(accumulator, value, index++);
99
+ }
100
+ return accumulator;
110
101
  }
111
- function validateFactoryOptions(resolved) {
112
- const { strict } = resolved;
113
- if (strict === false) return;
114
- const name = resolved.displayName ?? "Component";
115
- const { variants } = resolved;
116
- const checkSelection = (label2, selection) => {
117
- const record = selection;
118
- for (const dim in record) {
119
- const value = record[dim];
120
- if (value === void 0 || value === null) continue;
121
- if (!variants || !Object.hasOwn(variants, dim)) {
122
- report(strict, `${name}: ${label2} references unknown variant "${dim}".`);
123
- continue;
124
- }
125
- const states = variants[dim];
126
- const stateKey = String(value);
127
- if (!Object.hasOwn(states, stateKey)) {
128
- report(
129
- strict,
130
- `${name}: ${label2} sets "${dim}" to unknown value "${stateKey}" (valid: ${Object.keys(states).join(", ")}).`
131
- );
132
- }
133
- }
134
- };
135
- const { recipeMap } = resolved;
136
- if (recipeMap) {
137
- for (const recipeKey in recipeMap) {
138
- checkSelection(`preset "${recipeKey}"`, recipeMap[recipeKey]);
102
+ function collect(iterable, callback) {
103
+ const result = {};
104
+ let index = 0;
105
+ for (const value of iterable) {
106
+ const entry = callback(value, index++);
107
+ if (entry === null) {
108
+ return null;
139
109
  }
110
+ result[entry[0]] = entry[1];
140
111
  }
141
- if (resolved.defaultVariants) checkSelection("defaults", resolved.defaultVariants);
112
+ return result;
142
113
  }
143
- var warned = /* @__PURE__ */ new Set();
144
- var pendingAsyncWarns = /* @__PURE__ */ new Set();
145
- var asyncWarnScheduled = false;
146
- function flushAsyncWarns() {
147
- asyncWarnScheduled = false;
148
- const messages = [...pendingAsyncWarns];
149
- pendingAsyncWarns.clear();
150
- for (const msg of messages) {
151
- console.warn(msg);
152
- }
153
- }
154
- function report2(strict, message) {
155
- if (!strict) return;
156
- const mode = strict === true ? "throw" : strict;
157
- if (mode === "throw") throw new Error(message);
158
- if (mode === "async-warn") {
159
- if (pendingAsyncWarns.has(message)) return;
160
- pendingAsyncWarns.add(message);
161
- if (!asyncWarnScheduled) {
162
- asyncWarnScheduled = true;
163
- queueMicrotask(flushAsyncWarns);
114
+ function findLast(value, callback) {
115
+ for (let index = value.length - 1; index >= 0; index--) {
116
+ const result = callback(value[index], index);
117
+ if (result != null) {
118
+ return result;
164
119
  }
165
- return;
166
120
  }
167
- if (warned.has(message)) return;
168
- warned.add(message);
169
- console.warn(message);
121
+ return null;
170
122
  }
171
- function label(name) {
172
- return name ? `[${name}]` : "[createContractComponent]";
173
- }
174
- function validateRenderProps(options, props, recipeKey) {
175
- const { strict, recipeMap, variants, displayName } = options;
176
- if (!strict) return;
177
- const tag = label(displayName);
178
- if (recipeKey !== void 0 && (!recipeMap || !Object.hasOwn(recipeMap, recipeKey))) {
179
- report2(strict, `${tag} Unknown recipeKey "${recipeKey}" \u2014 no preset with that name exists.`);
123
+ function* items(collection) {
124
+ for (let i = 0; i < collection.length; i++) {
125
+ const item = collection.item(i);
126
+ if (item !== null) {
127
+ yield item;
128
+ }
180
129
  }
181
- if (variants) {
182
- for (const key in variants) {
183
- if (!Object.hasOwn(props, key)) continue;
184
- const value = props[key];
185
- if (value === void 0 || value === null) continue;
186
- const dim = variants[key];
187
- if (dim && !Object.hasOwn(dim, String(value))) {
188
- report2(
189
- strict,
190
- `${tag} Variant "${key}=${String(value)}" is not a defined value for the "${key}" dimension.`
191
- );
130
+ }
131
+ function nodeList(list) {
132
+ return {
133
+ *[Symbol.iterator]() {
134
+ for (let i = 0; i < list.length; i++) {
135
+ const node = list.item(i);
136
+ if (node !== null) {
137
+ yield node;
138
+ }
192
139
  }
193
140
  }
141
+ };
142
+ }
143
+ function mapEntries(m) {
144
+ return m.entries();
145
+ }
146
+ function set(s) {
147
+ return s.values();
148
+ }
149
+ function hasOwn(object, key) {
150
+ return Object.hasOwn(object, key);
151
+ }
152
+ function* entries(object) {
153
+ for (const key in object) {
154
+ if (!hasOwn(object, key)) continue;
155
+ yield [key, object[key]];
194
156
  }
195
157
  }
196
- function panic(message) {
197
- throw new Error(message);
158
+ function* keys(object) {
159
+ for (const [key] of entries(object)) {
160
+ yield key;
161
+ }
198
162
  }
199
- function describe(value) {
200
- if (value === null) return "null";
201
- if (Array.isArray(value)) return "array";
202
- return typeof value;
163
+ function* values(object) {
164
+ for (const [, value] of entries(object)) {
165
+ yield value;
166
+ }
203
167
  }
204
- function assertPluginShape(result) {
205
- if (result === null || typeof result !== "object")
206
- panic(
207
- `[praxis-kit] Plugin factory must return an object with a 'pipeline' function. Got: ${result === null ? "null" : typeof result}.`
208
- );
209
- const plugin = result;
210
- if (typeof plugin.pipeline !== "function")
211
- panic(
212
- `[praxis-kit] Plugin factory return value is missing a 'pipeline' function. Got pipeline: ${typeof plugin.pipeline}.`
213
- );
168
+ function mapValues(object, callback) {
169
+ const result = {};
170
+ for (const [key, value] of entries(object)) {
171
+ result[key] = callback(value, key);
172
+ }
173
+ return result;
214
174
  }
215
- function guardPipeline(pipeline) {
216
- if (process.env.NODE_ENV === "production") return pipeline;
217
- return function guardedPipeline(tag, props, className, recipe) {
218
- const result = pipeline(tag, props, className, recipe);
219
- if (typeof result !== "string")
220
- panic(`[praxis-kit] Plugin pipeline must return a string. Got: ${describe(result)}.`);
221
- return result;
222
- };
175
+ function forEachEntry(object, callback) {
176
+ for (const [key, value] of entries(object)) {
177
+ callback(key, value);
178
+ }
223
179
  }
224
- var NOOP_CLASS_PIPELINE = (_tag, _props, className) => Array.isArray(className) ? className.join(" ") : className ?? "";
225
- function resolveClassPipeline(options, resolved, strict, capabilities) {
226
- const factory = options.styling?.plugin;
227
- if (!factory) {
228
- const createClassPipeline2 = capabilities?.createClassPipeline;
229
- const classPipeline2 = createClassPipeline2 ? createClassPipeline2(resolved) : NOOP_CLASS_PIPELINE;
230
- return { pluginResult: void 0, classPipeline: classPipeline2 };
180
+ function forEachKey(object, callback) {
181
+ for (const key of keys(object)) {
182
+ callback(key);
231
183
  }
232
- const pluginResult = factory(resolved, strict);
233
- assertPluginShape(pluginResult);
234
- const classPipeline = guardPipeline(pluginResult.pipeline);
235
- return { pluginResult, classPipeline };
236
184
  }
237
- function createRuntimeMethods(resolved, classPipeline, engine) {
238
- return {
239
- resolveTag: makeResolveTag(resolved.defaultTag),
240
- resolveProps(props) {
241
- return mergeProps(resolved.defaultProps, props);
242
- },
243
- resolveClasses(tag, props, className, recipe) {
244
- if (process.env.NODE_ENV !== "production") {
245
- validateRenderProps(resolved, props, recipe);
246
- }
247
- return classPipeline(tag, props, className, recipe);
248
- },
249
- resolveAria(tag, props) {
250
- if (!engine) return { props };
251
- const result = engine.validate(tag, props);
252
- return { props: result.props };
253
- }
254
- };
185
+ function forEachValue(object, callback) {
186
+ for (const value of values(object)) {
187
+ callback(value);
188
+ }
255
189
  }
256
- function createRuntimeObject(methods, resolved, pluginResult) {
257
- return pluginResult ? { ...methods, options: resolved, hasStyling: true, classPlugin: pluginResult } : { ...methods, options: resolved };
190
+ function forEachSet(s, callback) {
191
+ for (const value of s) {
192
+ callback(value);
193
+ }
258
194
  }
259
- function createPolymorphic(options = {}, capabilities) {
260
- const baseResolved = resolveFactoryOptions(options);
261
- const resolved = capabilities?.htmlPropNormalizersFn !== void 0 ? Object.freeze({
262
- ...baseResolved,
263
- htmlPropNormalizersFn: capabilities.htmlPropNormalizersFn
264
- }) : baseResolved;
265
- if (process.env.NODE_ENV !== "production") validateFactoryOptions(resolved);
266
- const { pluginResult, classPipeline } = resolveClassPipeline(
267
- options,
268
- resolved,
269
- resolved.strict,
270
- capabilities
271
- );
272
- const allAriaRules = [
273
- .../* @__PURE__ */ new Set([...capabilities?.htmlAriaRules ?? [], ...resolved.ariaRules ?? []])
274
- ];
275
- const engine = options.enforcement !== void 0 && capabilities?.AriaEngine ? new capabilities.AriaEngine(
276
- resolved.strict,
277
- allAriaRules.length ? { rules: allAriaRules } : void 0
278
- ) : null;
279
- const methods = createRuntimeMethods(resolved, classPipeline, engine);
280
- return createRuntimeObject(
281
- methods,
282
- resolved,
283
- pluginResult
284
- );
195
+ var iterate = Object.freeze({
196
+ entries,
197
+ filter,
198
+ find,
199
+ findLast,
200
+ forEach,
201
+ forEachEntry,
202
+ forEachKey,
203
+ forEachSet,
204
+ forEachValue,
205
+ items,
206
+ keys,
207
+ map,
208
+ mapEntries,
209
+ mapValues,
210
+ nodeList,
211
+ reduce,
212
+ collect,
213
+ set,
214
+ some,
215
+ every,
216
+ values
217
+ });
218
+
219
+ // ../../lib/primitive/src/utils/merge-props.ts
220
+ function mergeProps(defaultProps, props) {
221
+ return {
222
+ ...defaultProps ?? {},
223
+ ...props
224
+ };
285
225
  }
226
+
227
+ // ../../lib/primitive/src/constants/aria/global-aria-attributes.ts
228
+ var GLOBAL_ARIA_ATTRIBUTES = /* @__PURE__ */ new Set([
229
+ "aria-atomic",
230
+ "aria-busy",
231
+ "aria-controls",
232
+ "aria-current",
233
+ "aria-describedby",
234
+ "aria-details",
235
+ "aria-disabled",
236
+ "aria-errormessage",
237
+ "aria-flowto",
238
+ "aria-hidden",
239
+ "aria-keyshortcuts",
240
+ "aria-label",
241
+ "aria-labelledby",
242
+ "aria-live",
243
+ "aria-owns",
244
+ "aria-relevant",
245
+ "aria-roledescription"
246
+ ]);
247
+
248
+ // ../../lib/primitive/src/constants/aria/implicit-role-record.ts
249
+ var IMPLICIT_ROLE_RECORD = {
250
+ // Landmarks
251
+ article: "article",
252
+ aside: "complementary",
253
+ footer: "contentinfo",
254
+ header: "banner",
255
+ main: "main",
256
+ nav: "navigation",
257
+ // Interactive
258
+ a: "link",
259
+ button: "button",
260
+ select: "listbox",
261
+ textarea: "textbox",
262
+ // Headings
263
+ h1: "heading",
264
+ h2: "heading",
265
+ h3: "heading",
266
+ h4: "heading",
267
+ h5: "heading",
268
+ h6: "heading",
269
+ // Lists
270
+ ul: "list",
271
+ ol: "list",
272
+ li: "listitem",
273
+ // Tables
274
+ table: "table",
275
+ tr: "row",
276
+ td: "cell",
277
+ th: "columnheader",
278
+ // Structural / semantic
279
+ dialog: "dialog",
280
+ fieldset: "group",
281
+ figure: "figure",
282
+ meter: "meter",
283
+ output: "status",
284
+ progress: "progressbar"
285
+ };
286
+ var INPUT_TYPE_ROLE_MAP = {
287
+ checkbox: "checkbox",
288
+ radio: "radio",
289
+ range: "slider",
290
+ number: "spinbutton",
291
+ search: "searchbox",
292
+ text: "textbox",
293
+ email: "textbox",
294
+ tel: "textbox",
295
+ url: "textbox",
296
+ button: "button",
297
+ submit: "button",
298
+ reset: "button",
299
+ image: "button"
300
+ };
301
+ var STRONG_ROLES = [
302
+ "main",
303
+ "navigation",
304
+ "complementary",
305
+ "contentinfo",
306
+ "banner"
307
+ ];
308
+ var STANDALONE_ROLES = ["article"];
309
+ var STRONG_ROLES_SET = new Set(STRONG_ROLES);
310
+ var STANDALONE_ROLES_SET = new Set(STANDALONE_ROLES);
311
+
312
+ // ../../lib/primitive/src/constants/aria/known-aria-roles.ts
286
313
  var KNOWN_ARIA_ROLES = [
287
314
  "alert",
288
315
  "alertdialog",
@@ -367,59 +394,8 @@ var KNOWN_ARIA_ROLES = [
367
394
  "treeitem"
368
395
  ];
369
396
  var KNOWN_ARIA_ROLES_SET = new Set(KNOWN_ARIA_ROLES);
370
- var GLOBAL_ARIA_ATTRIBUTES = /* @__PURE__ */ new Set([
371
- "aria-atomic",
372
- "aria-busy",
373
- "aria-controls",
374
- "aria-current",
375
- "aria-describedby",
376
- "aria-details",
377
- "aria-disabled",
378
- "aria-errormessage",
379
- "aria-flowto",
380
- "aria-hidden",
381
- "aria-keyshortcuts",
382
- "aria-label",
383
- "aria-labelledby",
384
- "aria-live",
385
- "aria-owns",
386
- "aria-relevant",
387
- "aria-roledescription"
388
- ]);
389
- var IMPLICIT_ROLE_RECORD = {
390
- article: "article",
391
- aside: "complementary",
392
- footer: "contentinfo",
393
- header: "banner",
394
- main: "main",
395
- nav: "navigation",
396
- button: "button",
397
- a: "link",
398
- select: "listbox",
399
- h1: "heading",
400
- h2: "heading",
401
- h3: "heading",
402
- h4: "heading",
403
- h5: "heading",
404
- h6: "heading",
405
- ul: "list",
406
- ol: "list",
407
- li: "listitem",
408
- table: "table",
409
- tr: "row",
410
- td: "cell",
411
- th: "columnheader"
412
- };
413
- var STRONG_ROLES = [
414
- "main",
415
- "navigation",
416
- "complementary",
417
- "contentinfo",
418
- "banner"
419
- ];
420
- var STANDALONE_ROLES = ["article"];
421
- var STRONG_ROLES_SET = new Set(STRONG_ROLES);
422
- var STANDALONE_ROLES_SET = new Set(STANDALONE_ROLES);
397
+
398
+ // ../../lib/primitive/src/constants/aria/role-restricted-attributes.ts
423
399
  var ROLE_RESTRICTED_ATTRIBUTES = /* @__PURE__ */ new Map([
424
400
  [
425
401
  "aria-activedescendant",
@@ -569,9 +545,8 @@ var ROLE_RESTRICTED_ATTRIBUTES = /* @__PURE__ */ new Map([
569
545
  /* @__PURE__ */ new Set(["meter", "progressbar", "scrollbar", "separator", "slider", "spinbutton"])
570
546
  ]
571
547
  ]);
572
- function isUndefined(value) {
573
- return value === void 0;
574
- }
548
+
549
+ // ../../lib/primitive/src/guards/aria/is-aria-attribute.ts
575
550
  function isGlobalAriaAttribute(attr) {
576
551
  return GLOBAL_ARIA_ATTRIBUTES.has(attr);
577
552
  }
@@ -581,6 +556,8 @@ function isAriaAttributeValidForRole(attr, role) {
581
556
  if (isUndefined(role)) return false;
582
557
  return allowedRoles.has(role);
583
558
  }
559
+
560
+ // ../../lib/primitive/src/guards/aria/is-aria-role.ts
584
561
  function isStrongImplicitRole(tag) {
585
562
  if (!(tag in IMPLICIT_ROLE_RECORD)) return false;
586
563
  return STRONG_ROLES_SET.has(IMPLICIT_ROLE_RECORD[tag]);
@@ -589,119 +566,559 @@ function isStandaloneTag(tag) {
589
566
  if (!(tag in IMPLICIT_ROLE_RECORD)) return false;
590
567
  return STANDALONE_ROLES_SET.has(IMPLICIT_ROLE_RECORD[tag]);
591
568
  }
569
+ function getInputImplicitRole(type) {
570
+ if (type == null || !(type in INPUT_TYPE_ROLE_MAP)) return void 0;
571
+ return INPUT_TYPE_ROLE_MAP[type];
572
+ }
573
+ function getConditionalImplicitRole(tag, ariaLabel, ariaLabelledBy) {
574
+ const isNamed = typeof ariaLabel === "string" || typeof ariaLabelledBy === "string";
575
+ if (!isNamed) return void 0;
576
+ if (tag === "section") return "region";
577
+ if (tag === "form") return "form";
578
+ return void 0;
579
+ }
580
+
581
+ // ../../lib/primitive/src/guards/aria/is-known-aria-role.ts
592
582
  function isKnownAriaRole(value) {
593
583
  return isString(value) && KNOWN_ARIA_ROLES_SET.has(value);
594
584
  }
595
585
 
596
- // ../core/dist/chunk-2NJ5XLOA.js
597
- var IMPLICIT_ROLE_RECORD2 = {
598
- article: "article",
599
- aside: "complementary",
600
- footer: "contentinfo",
601
- header: "banner",
602
- main: "main",
603
- nav: "navigation",
604
- button: "button",
605
- a: "link",
606
- select: "listbox",
607
- h1: "heading",
608
- h2: "heading",
609
- h3: "heading",
610
- h4: "heading",
611
- h5: "heading",
612
- h6: "heading",
613
- ul: "list",
614
- ol: "list",
615
- li: "listitem",
616
- table: "table",
617
- tr: "row",
618
- td: "cell",
619
- th: "columnheader"
620
- };
621
- function getImplicitRole(tag) {
622
- if (tag in IMPLICIT_ROLE_RECORD2) return IMPLICIT_ROLE_RECORD2[tag];
623
- return void 0;
624
- }
625
- var COMPONENT_DEFAULT_TAG2 = /* @__PURE__ */ Symbol.for("praxis.component-default-tag");
626
- function getAsProp(child) {
627
- if (!isObject(child) || !("props" in child)) return void 0;
628
- const props = child.props;
629
- if (!isObject(props)) return void 0;
630
- const as = props.as;
631
- return isString(as) && as !== "" ? as : void 0;
586
+ // ../../lib/adapter-utils/src/apply-filter.ts
587
+ function applyFilter(props, filterProps, variantKeys) {
588
+ const out = {};
589
+ iterate.forEachEntry(props, (k) => {
590
+ if (!Object.hasOwn(props, k)) return;
591
+ if (filterProps(k, variantKeys)) return;
592
+ out[k] = props[k];
593
+ });
594
+ return out;
632
595
  }
633
- function getTag(child) {
634
- if (!isObject(child) || !("type" in child)) return void 0;
635
- const t = child.type;
636
- if (isString(t)) return t;
637
- if (typeof t === "function" || isObject(t)) {
638
- const defaultTag = t[COMPONENT_DEFAULT_TAG2];
639
- if (!isString(defaultTag)) return void 0;
640
- return getAsProp(child) ?? defaultTag;
596
+
597
+ // ../../lib/contract/src/aria/aria-role-policy.ts
598
+ function getImplicitRole(tag, props) {
599
+ if (tag in IMPLICIT_ROLE_RECORD) return IMPLICIT_ROLE_RECORD[tag];
600
+ if (tag === "input") return getInputImplicitRole(props?.type);
601
+ if (tag === "img") return props?.alt === "" ? "none" : "img";
602
+ if (tag === "section" || tag === "form") {
603
+ return getConditionalImplicitRole(tag, props?.["aria-label"], props?.["aria-labelledby"]);
641
604
  }
642
605
  return void 0;
643
606
  }
644
- function isTag(...args) {
645
- if (isString(args[0])) {
646
- const set2 = new Set(args);
647
- return (child2) => {
648
- const tag2 = getTag(child2);
649
- return tag2 !== void 0 && set2.has(tag2);
650
- };
607
+
608
+ // ../../lib/contract/src/strict/invariant-base.ts
609
+ var InvariantBase = class {
610
+ diagnostics;
611
+ constructor(diagnostics) {
612
+ this.diagnostics = diagnostics;
651
613
  }
652
- const [child, ...tags] = args;
653
- const set = new Set(tags);
654
- const tag = getTag(child);
655
- return tag !== void 0 && set.has(tag);
656
- }
657
- var pendingAsyncWarns2 = /* @__PURE__ */ new Set();
658
- var asyncWarnScheduled2 = false;
659
- function flushAsyncWarns2() {
660
- asyncWarnScheduled2 = false;
661
- const messages = [...pendingAsyncWarns2];
662
- pendingAsyncWarns2.clear();
663
- for (const msg of messages) {
664
- console.warn(msg);
665
- }
666
- }
667
- function scheduleAsyncWarn(message) {
668
- if (pendingAsyncWarns2.has(message)) return;
669
- pendingAsyncWarns2.add(message);
670
- if (!asyncWarnScheduled2) {
671
- asyncWarnScheduled2 = true;
672
- queueMicrotask(flushAsyncWarns2);
673
- }
674
- }
675
- var StrictBase = class {
676
- strict;
677
- constructor(strict) {
678
- this.strict = strict;
679
- }
680
- violate(message) {
681
- if (this.strict === true || this.strict === "throw") {
682
- throw new Error(message);
683
- }
684
- this.warn(message);
614
+ get active() {
615
+ return this.diagnostics.active;
685
616
  }
686
- // Always caps at console.warn — never throws. ARIA 'warning' violations route here
617
+ violate(input) {
618
+ this.diagnostics.error(input);
619
+ }
620
+ // Always caps at warn — never throws. ARIA 'warning' violations route here
687
621
  // so they surface even in strict='throw' mode without aborting a render.
688
- warn(message) {
689
- if (!this.strict) return;
690
- if (this.strict === "async-warn") {
691
- scheduleAsyncWarn(message);
692
- return;
693
- }
694
- console.warn(message);
622
+ warn(input) {
623
+ this.diagnostics.warn(input);
695
624
  }
696
- invariant(condition, message) {
697
- if (!condition) {
698
- this.violate(message);
699
- }
625
+ invariant(condition, input) {
626
+ if (!condition) this.violate(input);
700
627
  }
701
628
  };
702
- function isNull2(value) {
703
- return value === null;
629
+
630
+ // ../../lib/diagnostics/src/category.ts
631
+ var DiagnosticCategory = /* @__PURE__ */ ((DiagnosticCategory2) => {
632
+ DiagnosticCategory2[DiagnosticCategory2["Contract"] = 0] = "Contract";
633
+ DiagnosticCategory2[DiagnosticCategory2["HTML"] = 1] = "HTML";
634
+ DiagnosticCategory2[DiagnosticCategory2["ARIA"] = 2] = "ARIA";
635
+ DiagnosticCategory2[DiagnosticCategory2["Composition"] = 3] = "Composition";
636
+ DiagnosticCategory2[DiagnosticCategory2["Rendering"] = 4] = "Rendering";
637
+ DiagnosticCategory2[DiagnosticCategory2["Accessibility"] = 5] = "Accessibility";
638
+ DiagnosticCategory2[DiagnosticCategory2["Performance"] = 6] = "Performance";
639
+ DiagnosticCategory2[DiagnosticCategory2["Internal"] = 7] = "Internal";
640
+ DiagnosticCategory2[DiagnosticCategory2["Deprecation"] = 8] = "Deprecation";
641
+ DiagnosticCategory2[DiagnosticCategory2["Lint"] = 9] = "Lint";
642
+ return DiagnosticCategory2;
643
+ })(DiagnosticCategory || {});
644
+
645
+ // ../../lib/diagnostics/src/error.ts
646
+ var PraxisError = class extends Error {
647
+ diagnostic;
648
+ constructor(diagnostic) {
649
+ super(diagnostic.message);
650
+ this.name = "PraxisError";
651
+ this.diagnostic = diagnostic;
652
+ }
653
+ };
654
+
655
+ // ../../lib/diagnostics/src/severity.ts
656
+ var Severity = /* @__PURE__ */ ((Severity2) => {
657
+ Severity2[Severity2["Debug"] = 0] = "Debug";
658
+ Severity2[Severity2["Info"] = 1] = "Info";
659
+ Severity2[Severity2["Warning"] = 2] = "Warning";
660
+ Severity2[Severity2["Error"] = 3] = "Error";
661
+ Severity2[Severity2["Fatal"] = 4] = "Fatal";
662
+ return Severity2;
663
+ })(Severity || {});
664
+
665
+ // ../../lib/diagnostics/src/policy.ts
666
+ var DefaultPolicy = class {
667
+ reportThreshold;
668
+ throwThreshold;
669
+ constructor({
670
+ reportThreshold = 1 /* Info */,
671
+ throwThreshold = 4 /* Fatal */
672
+ } = {}) {
673
+ this.reportThreshold = reportThreshold;
674
+ this.throwThreshold = throwThreshold;
675
+ }
676
+ resolve(diagnostic) {
677
+ if (diagnostic.severity >= this.throwThreshold) return 2 /* Throw */;
678
+ if (diagnostic.severity >= this.reportThreshold) return 1 /* Report */;
679
+ return 0 /* Ignore */;
680
+ }
681
+ };
682
+
683
+ // ../../lib/diagnostics/src/diagnostics.ts
684
+ var Diagnostics = class {
685
+ reporter;
686
+ policy;
687
+ // Pre-computed at construction time: true if Warning-level diagnostics are not ignored.
688
+ active;
689
+ constructor(reporter, policy = new DefaultPolicy()) {
690
+ this.reporter = reporter;
691
+ this.policy = policy;
692
+ this.active = policy.resolve({ severity: 2 /* Warning */ }) !== 0 /* Ignore */;
693
+ }
694
+ report(diagnostic) {
695
+ const enforcement = this.policy.resolve(diagnostic);
696
+ if (enforcement === 0 /* Ignore */) return diagnostic;
697
+ if (enforcement === 2 /* Throw */) throw new PraxisError(diagnostic);
698
+ this.reporter.report(diagnostic);
699
+ return diagnostic;
700
+ }
701
+ warn(input) {
702
+ return this.report({ ...input, severity: 2 /* Warning */ });
703
+ }
704
+ error(input) {
705
+ return this.report({ ...input, severity: 3 /* Error */ });
706
+ }
707
+ info(input) {
708
+ return this.report({ ...input, severity: 1 /* Info */ });
709
+ }
710
+ };
711
+
712
+ // ../../lib/diagnostics/src/formatter.ts
713
+ function formatDiagnostic(diagnostic) {
714
+ const level = Severity[diagnostic.severity];
715
+ const category = DiagnosticCategory[diagnostic.category];
716
+ const prefix = category !== void 0 ? `[${category}] ` : "";
717
+ return `${level} ${diagnostic.code}: ${prefix}${diagnostic.message}`;
704
718
  }
719
+
720
+ // ../../lib/diagnostics/src/console-reporter.ts
721
+ var ConsoleReporter = class {
722
+ report(diagnostic) {
723
+ const message = formatDiagnostic(diagnostic);
724
+ switch (diagnostic.severity) {
725
+ case 0 /* Debug */:
726
+ console.debug(message);
727
+ break;
728
+ case 1 /* Info */:
729
+ console.info(message);
730
+ break;
731
+ case 2 /* Warning */:
732
+ console.warn(message);
733
+ break;
734
+ case 3 /* Error */:
735
+ case 4 /* Fatal */:
736
+ console.error(message);
737
+ break;
738
+ }
739
+ }
740
+ };
741
+
742
+ // ../../lib/diagnostics/src/null-reporter.ts
743
+ var nullReporter = {
744
+ report() {
745
+ }
746
+ };
747
+
748
+ // ../../lib/diagnostics/src/presets.ts
749
+ var ignoreAllPolicy = {
750
+ resolve(_) {
751
+ return 0 /* Ignore */;
752
+ }
753
+ };
754
+ var warnOnlyReporter = {
755
+ report(diagnostic) {
756
+ console.warn(formatDiagnostic(diagnostic));
757
+ }
758
+ };
759
+ var silentDiagnostics = new Diagnostics(nullReporter, ignoreAllPolicy);
760
+ var warnDiagnostics = new Diagnostics(
761
+ warnOnlyReporter,
762
+ new DefaultPolicy({ reportThreshold: 2 /* Warning */, throwThreshold: 4 /* Fatal */ })
763
+ );
764
+ var throwDiagnostics = new Diagnostics(
765
+ new ConsoleReporter(),
766
+ new DefaultPolicy({ reportThreshold: 2 /* Warning */, throwThreshold: 3 /* Error */ })
767
+ );
768
+
769
+ // ../../lib/contract/src/diagnostics/aria.ts
770
+ var AriaDiagnostics = {
771
+ /** Generic bridge for violations produced by external AriaRule functions. */
772
+ fromViolation(v) {
773
+ return {
774
+ code: "ARIA2002" /* AriaViolation */,
775
+ category: 2 /* ARIA */,
776
+ message: v.message
777
+ };
778
+ },
779
+ attributeInvalid(key, role) {
780
+ return {
781
+ code: "ARIA2003" /* AriaAttributeInvalid */,
782
+ category: 2 /* ARIA */,
783
+ message: `"${key}" is not valid on role="${role}". It will be removed.`,
784
+ rationale: "Invalid ARIA attributes are ignored by assistive technology and may trigger accessibility-tree warnings in browser devtools.",
785
+ suggestions: [
786
+ {
787
+ title: "Remove the attribute",
788
+ description: `"${key}" is not in the allowed attribute set for role="${role}".`
789
+ }
790
+ ]
791
+ };
792
+ },
793
+ missingLiveRegion(role, impliedLive) {
794
+ return {
795
+ code: "ARIA2004" /* AriaMissingLiveRegion */,
796
+ category: 2 /* ARIA */,
797
+ message: `role="${role}" implies aria-live="${impliedLive}" but it is missing. It has been injected.`,
798
+ rationale: "Live-region roles announce dynamic content changes to screen readers. Without aria-live the politeness level is unspecified and announcements may be silent.",
799
+ suggestions: [
800
+ {
801
+ title: `Add aria-live="${impliedLive}"`,
802
+ description: `role="${role}" conventionally implies aria-live="${impliedLive}".`,
803
+ fix: `aria-live="${impliedLive}"`
804
+ }
805
+ ]
806
+ };
807
+ },
808
+ missingAtomic(role) {
809
+ return {
810
+ code: "ARIA2005" /* AriaMissingAtomic */,
811
+ category: 2 /* ARIA */,
812
+ message: `role="${role}" 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.`,
813
+ rationale: "aria-atomic controls whether assistive technology announces the entire live region or only the changed nodes. Omitting it leaves the behaviour browser-defined."
814
+ };
815
+ },
816
+ relevantInvalidTokens(invalid) {
817
+ const quoted = invalid.map((t) => `"${t}"`).join(", ");
818
+ return {
819
+ code: "ARIA2006" /* AriaRelevantInvalidToken */,
820
+ category: 2 /* ARIA */,
821
+ message: `aria-relevant contains invalid token(s): ${quoted}. Valid tokens are: additions, removals, text, all.`,
822
+ rationale: "aria-relevant accepts a space-separated list of change types. Unrecognised tokens are silently ignored by assistive technology, making the attribute ineffective.",
823
+ suggestions: [
824
+ {
825
+ title: "Use only valid tokens",
826
+ description: "Valid values are: additions, removals, text, all (or a space-separated combination)."
827
+ }
828
+ ]
829
+ };
830
+ },
831
+ relevantSuperseded() {
832
+ return {
833
+ code: "ARIA2007" /* AriaRelevantSuperseded */,
834
+ category: 2 /* ARIA */,
835
+ message: 'aria-relevant includes "all" alongside other tokens. "all" supersedes additions, removals, and text \u2014 use aria-relevant="all" alone.',
836
+ rationale: '"all" is equivalent to "additions removals text". Combining it with other tokens is redundant and may confuse readers of the markup.',
837
+ suggestions: [
838
+ {
839
+ title: 'Use aria-relevant="all"',
840
+ fix: 'aria-relevant="all"'
841
+ }
842
+ ]
843
+ };
844
+ },
845
+ missingAccessibleName(tag) {
846
+ return {
847
+ code: "ARIA2009" /* AriaMissingAccessibleName */,
848
+ category: 2 /* ARIA */,
849
+ message: `<${tag}> has no accessible name. Add aria-label or aria-labelledby.`,
850
+ rationale: "Elements with a landmark or interactive role must have an accessible name so that assistive technology can identify them when presenting the page outline.",
851
+ suggestions: [
852
+ {
853
+ title: "Add aria-label",
854
+ description: `Add aria-label="\u2026" directly to the <${tag}> element.`
855
+ },
856
+ {
857
+ title: "Add aria-labelledby",
858
+ description: "Point aria-labelledby at the id of an existing heading or label element."
859
+ }
860
+ ]
861
+ };
862
+ },
863
+ attributeOnPresentational(attr, tag) {
864
+ return {
865
+ code: "ARIA2010" /* AriaAttributeOnPresentational */,
866
+ category: 2 /* ARIA */,
867
+ message: `"${attr}" is not allowed on a presentational <${tag}>. Presentational elements are invisible to assistive technology.`,
868
+ rationale: 'role="none" and role="presentation" (including <img alt="">) remove an element from the accessibility tree. ARIA attributes on such elements are ignored by assistive technology.',
869
+ suggestions: [
870
+ {
871
+ title: "Remove the attribute",
872
+ description: `"${attr}" has no effect when the element has role="none" or role="presentation".`
873
+ }
874
+ ]
875
+ };
876
+ },
877
+ ariaHiddenOnFocusable(tag) {
878
+ return {
879
+ code: "ARIA2011" /* AriaHiddenOnFocusable */,
880
+ category: 2 /* ARIA */,
881
+ message: `aria-hidden="true" must not be used on focusable <${tag}> elements. Screen reader users who navigate by keyboard will encounter the element but receive no information about it.`,
882
+ rationale: 'aria-hidden removes an element from the accessibility tree while leaving it keyboard-reachable. This creates a "ghost" \u2014 a focusable element assistive technology cannot describe.',
883
+ suggestions: [
884
+ {
885
+ title: "Remove aria-hidden",
886
+ description: "If the element should be hidden from all users, use the HTML hidden attribute or CSS display:none instead."
887
+ },
888
+ {
889
+ title: "Make the element non-focusable",
890
+ description: 'If the element is intentionally decorative, add tabindex="-1" and disable it so it is not reachable by keyboard.'
891
+ }
892
+ ]
893
+ };
894
+ },
895
+ invalidAttributeValue(attr, value, expected) {
896
+ const got = value === null ? "null" : value === void 0 ? "undefined" : typeof value === "string" ? `"${value}"` : String(value);
897
+ return {
898
+ code: "ARIA2013" /* AriaInvalidAttributeValue */,
899
+ category: 2 /* ARIA */,
900
+ message: `"${attr}" has an invalid value (${got}). Expected: ${expected}.`,
901
+ rationale: "ARIA attributes with invalid values are silently ignored by assistive technology, making the markup semantically inert.",
902
+ suggestions: [
903
+ {
904
+ title: `Use a valid value for ${attr}`,
905
+ description: `Valid values are: ${expected}.`
906
+ }
907
+ ]
908
+ };
909
+ },
910
+ redundantAriaLevel(tag, level) {
911
+ return {
912
+ code: "ARIA2014" /* AriaRedundantLevelAttribute */,
913
+ category: 2 /* ARIA */,
914
+ message: `aria-level="${level}" is redundant on <${tag}>: the element already has an implicit heading level of ${level}. Remove the attribute.`,
915
+ rationale: 'Restating the implicit aria-level adds noise without semantic value. Use aria-level only to override the native heading level (e.g. aria-level="3" on <h2>).',
916
+ suggestions: [
917
+ {
918
+ title: "Remove aria-level",
919
+ description: `<${tag}> already implies aria-level="${level}".`
920
+ }
921
+ ]
922
+ };
923
+ },
924
+ requiredProperty(attr, role) {
925
+ return {
926
+ code: "ARIA2012" /* AriaRequiredProperty */,
927
+ category: 2 /* ARIA */,
928
+ message: `"${attr}" is required for role="${role}" but is missing.`,
929
+ rationale: `WAI-ARIA 1.2 specifies required states and properties for certain roles. Without "${attr}", assistive technology cannot correctly communicate the element's state to users.`,
930
+ suggestions: [
931
+ {
932
+ title: `Add ${attr}`,
933
+ description: `role="${role}" requires "${attr}" to be present.`
934
+ }
935
+ ]
936
+ };
937
+ },
938
+ invalidRole(role, tag) {
939
+ return {
940
+ code: "ARIA2008" /* AriaInvalidRole */,
941
+ category: 2 /* ARIA */,
942
+ message: `Invalid role "${role ?? ""}" on <${tag}>.`,
943
+ rationale: "An unrecognised or misapplied ARIA role is ignored by assistive technology and may degrade the accessibility of the element."
944
+ };
945
+ }
946
+ };
947
+
948
+ // ../../lib/contract/src/diagnostics/contract.ts
949
+ var ContractDiagnostics = {
950
+ unexpectedChild(typeName, index, context) {
951
+ return {
952
+ code: "COMP1004" /* UnexpectedChild */,
953
+ category: 0 /* Contract */,
954
+ component: context,
955
+ message: `${context}: unexpected child "${typeName}" at index ${index}.`
956
+ };
957
+ },
958
+ ambiguousChild(typeName, index, ruleNames, context) {
959
+ const quoted = ruleNames.map((n) => `"${n}"`).join(" and ");
960
+ return {
961
+ code: "COMP1005" /* AmbiguousChild */,
962
+ category: 0 /* Contract */,
963
+ component: context,
964
+ message: `${context}: child "${typeName}" at index ${index} matches multiple child rules: ${quoted}.`
965
+ };
966
+ },
967
+ cardinalityMin(ruleName, min, context) {
968
+ return {
969
+ code: "COMP1006" /* CardinalityMin */,
970
+ category: 0 /* Contract */,
971
+ component: context,
972
+ message: `${context}: "${ruleName}" requires at least ${min}.`
973
+ };
974
+ },
975
+ cardinalityMax(ruleName, max, context) {
976
+ return {
977
+ code: "COMP1007" /* CardinalityMax */,
978
+ category: 0 /* Contract */,
979
+ component: context,
980
+ message: `${context}: "${ruleName}" allows at most ${max}.`
981
+ };
982
+ },
983
+ positionViolation(ruleName, position, index, context) {
984
+ return {
985
+ code: "COMP1008" /* PositionViolation */,
986
+ category: 0 /* Contract */,
987
+ component: context,
988
+ message: `${context}: "${ruleName}" must be ${position}, got index ${index}`
989
+ };
990
+ },
991
+ unknownVariantDim(component, label2, dim) {
992
+ return {
993
+ code: "COMP1010" /* ContractUnknownVariantDim */,
994
+ category: 0 /* Contract */,
995
+ message: `${component}: ${label2} references unknown variant "${dim}".`
996
+ };
997
+ },
998
+ unknownVariantValue(component, label2, dim, value, valid) {
999
+ return {
1000
+ code: "COMP1011" /* ContractUnknownVariantValue */,
1001
+ category: 0 /* Contract */,
1002
+ message: `${component}: ${label2} sets "${dim}" to unknown value "${value}" (valid: ${valid.join(", ")}).`
1003
+ };
1004
+ },
1005
+ unknownRecipeKey(component, key) {
1006
+ return {
1007
+ code: "COMP1012" /* ContractUnknownRecipeKey */,
1008
+ category: 0 /* Contract */,
1009
+ message: `${component} Unknown recipeKey "${key}" \u2014 no preset with that name exists.`
1010
+ };
1011
+ },
1012
+ invalidVariantValue(component, key, value) {
1013
+ return {
1014
+ code: "COMP1013" /* ContractInvalidVariantValue */,
1015
+ category: 0 /* Contract */,
1016
+ message: `${component} Variant "${key}=${value}" is not a defined value for the "${key}" dimension.`
1017
+ };
1018
+ },
1019
+ allowedAsViolation(tag, allowedAs, component) {
1020
+ const allowed = allowedAs.map((t) => `"${String(t)}"`).join(", ");
1021
+ return {
1022
+ code: "COMP1009" /* AllowedAsViolation */,
1023
+ category: 0 /* Contract */,
1024
+ component,
1025
+ message: `<${component}>: "as" prop received "${tag}" but only [${allowed}] are allowed.`
1026
+ };
1027
+ }
1028
+ };
1029
+
1030
+ // ../../lib/contract/src/diagnostics/html.ts
1031
+ var HtmlDiagnostics = {
1032
+ emptyRole(tag) {
1033
+ return {
1034
+ code: "HTML3002" /* HtmlEmptyRole */,
1035
+ category: 1 /* HTML */,
1036
+ message: `<${tag}> has an explicit empty role="". Omit the attribute instead.`
1037
+ };
1038
+ },
1039
+ implicitRoleRedundant(tag, implicitRole) {
1040
+ return {
1041
+ code: "HTML3003" /* HtmlImplicitRoleRedundant */,
1042
+ category: 1 /* HTML */,
1043
+ message: `<${tag}> already has implicit role="${implicitRole}". Avoid redundant role assignment.`
1044
+ };
1045
+ },
1046
+ implicitRoleOverride(tag, implicitRole, role) {
1047
+ return {
1048
+ code: "HTML3004" /* HtmlImplicitRoleOverride */,
1049
+ category: 1 /* HTML */,
1050
+ message: `<${tag}> should not override its implicit role="${implicitRole}" with role="${role}".`
1051
+ };
1052
+ },
1053
+ standaloneRegionOverride(tag, implicitRole) {
1054
+ return {
1055
+ code: "HTML3005" /* HtmlStandaloneRegionOverride */,
1056
+ category: 1 /* HTML */,
1057
+ message: `<${tag}> is a self-contained element with implicit role="${implicitRole}". Assigning role="region" has been removed.`
1058
+ };
1059
+ },
1060
+ landmarkRoleOverride(tag, implicitRole, role) {
1061
+ return {
1062
+ code: "HTML3006" /* HtmlLandmarkRoleOverride */,
1063
+ category: 1 /* HTML */,
1064
+ message: `<${tag}> has a fixed landmark role="${implicitRole}". role="${role}" overrides it and confuses assistive technology. The override has been removed.`
1065
+ };
1066
+ },
1067
+ invalidChild(child, parent, allowed) {
1068
+ return {
1069
+ code: "HTML3007" /* HtmlInvalidChild */,
1070
+ category: 1 /* HTML */,
1071
+ message: `<${child}> is not a valid direct child of <${parent}>. Allowed: ${allowed}.`
1072
+ };
1073
+ }
1074
+ };
1075
+
1076
+ // ../../lib/contract/src/diagnostics/slot.ts
1077
+ var SlotDiagnostics = {
1078
+ exclusive(name) {
1079
+ return {
1080
+ code: "SLOT1001" /* SlotExclusive */,
1081
+ category: 0 /* Contract */,
1082
+ component: name,
1083
+ message: `${name}: "as" and "asChild" are mutually exclusive`
1084
+ };
1085
+ },
1086
+ singleChildRequired(name, elementTerm) {
1087
+ return {
1088
+ code: "SLOT1002" /* SlotSingleChild */,
1089
+ category: 0 /* Contract */,
1090
+ component: name,
1091
+ message: `${name}: asChild requires a ${elementTerm} child`
1092
+ };
1093
+ },
1094
+ singleChildExceeded(name, elementTerm, count) {
1095
+ return {
1096
+ code: "SLOT1002" /* SlotSingleChild */,
1097
+ category: 0 /* Contract */,
1098
+ component: name,
1099
+ message: `${name}: asChild requires exactly one ${elementTerm} child, got ${count}`
1100
+ };
1101
+ },
1102
+ discardedChildren(name, elementTerm, count) {
1103
+ const suffix = count === 1 ? "" : "ren";
1104
+ return {
1105
+ code: "SLOT1003" /* SlotDiscardedChildren */,
1106
+ category: 0 /* Contract */,
1107
+ component: name,
1108
+ message: `${name}: asChild discarded ${count} non-element child${suffix} \u2014 only ${elementTerm}s are valid asChild children.`
1109
+ };
1110
+ },
1111
+ renderFnRequired(name, received) {
1112
+ return {
1113
+ code: "SLOT1004" /* SlotRenderFn */,
1114
+ category: 0 /* Contract */,
1115
+ component: name,
1116
+ message: `${name}: asChild requires a render function as children, got ${received}`
1117
+ };
1118
+ }
1119
+ };
1120
+
1121
+ // ../../lib/contract/src/aria/polymorphic-validator.ts
705
1122
  var VALID = [{ valid: true }];
706
1123
  function isIntrinsicTag(tag) {
707
1124
  return isString(tag);
@@ -710,26 +1127,28 @@ function omitProp(obj, key) {
710
1127
  const { [key]: _, ...rest } = obj;
711
1128
  return rest;
712
1129
  }
713
- var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
1130
+ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
714
1131
  #extraRules;
715
1132
  #planCache = /* @__PURE__ */ new Map();
716
1133
  static #MAX_CACHE = 100;
717
1134
  // Memoized AriaFix objects keyed by attribute name — the ARIA attribute set is
718
1135
  // finite so this Map is bounded and avoids recreating closures on every cache miss.
719
1136
  static #removeAttributeFixCache = /* @__PURE__ */ new Map();
720
- constructor(strict = "warn", options) {
721
- super(strict);
1137
+ constructor(diagnostics, options) {
1138
+ super(diagnostics);
722
1139
  this.#extraRules = options?.rules ?? [];
723
1140
  }
724
1141
  static #normalizeEmptyRole(tag, props) {
725
1142
  if (props.role !== "") return { normalized: false };
1143
+ const d = HtmlDiagnostics.emptyRole(tag);
726
1144
  return {
727
1145
  normalized: true,
728
1146
  result: {
729
1147
  props: omitProp(props, "role"),
730
1148
  violations: [
731
1149
  {
732
- message: `<${tag}> has an explicit empty role="". Omit the attribute instead.`,
1150
+ message: d.message,
1151
+ diagnostic: d,
733
1152
  tag,
734
1153
  role: "",
735
1154
  attribute: void 0,
@@ -742,10 +1161,9 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
742
1161
  }
743
1162
  static #deriveContext(tag, props) {
744
1163
  if (!isIntrinsicTag(tag)) return { proceed: false, result: { props, violations: [] } };
745
- const implicitRole = getImplicitRole(tag);
746
- const hasExplicitLiveRole = !implicitRole && _AriaPolicyEngine.#LIVE_REGION_ROLES.has(props.role ?? "");
747
- if (!implicitRole && !hasExplicitLiveRole)
748
- return { proceed: false, result: { props, violations: [] } };
1164
+ const implicitRole = getImplicitRole(tag, props);
1165
+ const hasRole2 = implicitRole != null || isString(props.role) && props.role.length > 0;
1166
+ if (!hasRole2) return { proceed: false, result: { props, violations: [] } };
749
1167
  const normalized = _AriaPolicyEngine.#normalizeEmptyRole(tag, props);
750
1168
  if (normalized.normalized) return { proceed: false, result: normalized.result };
751
1169
  const effectiveRole = props.role ?? implicitRole;
@@ -760,25 +1178,36 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
760
1178
  static #runRules(rules, context) {
761
1179
  const violations = [];
762
1180
  const fixes = [];
763
- for (const rule of rules) {
764
- for (const result of rule(context)) {
765
- if (!result.valid) {
766
- violations.push({
767
- message: result.message ?? `Invalid role "${context.props.role}" on <${context.tag}>`,
768
- tag: context.tag,
769
- role: context.props.role,
770
- attribute: result.attribute,
771
- severity: result.severity,
772
- phase: "evaluate"
773
- });
774
- if (result.fixable) fixes.push(result.fix);
775
- }
776
- }
777
- }
1181
+ iterate.forEach(rules, (rule) => {
1182
+ iterate.forEach(rule(context), (result) => {
1183
+ if (result.valid) return;
1184
+ const {
1185
+ tag,
1186
+ props: { role }
1187
+ } = context;
1188
+ const { message, attribute, severity } = result;
1189
+ const resolvedMessage = message ?? result.diagnostic?.message;
1190
+ const fallbackDiag = resolvedMessage == null ? AriaDiagnostics.invalidRole(role, tag) : void 0;
1191
+ violations.push({
1192
+ message: resolvedMessage ?? fallbackDiag.message,
1193
+ tag,
1194
+ role,
1195
+ attribute,
1196
+ severity,
1197
+ phase: "evaluate",
1198
+ ...result.diagnostic != null && { diagnostic: result.diagnostic },
1199
+ ...fallbackDiag != null && { diagnostic: fallbackDiag }
1200
+ });
1201
+ if (result.fixable) fixes.push(result.fix);
1202
+ });
1203
+ });
778
1204
  return { violations, fixes };
779
1205
  }
780
1206
  static #getRules(context) {
781
- return _AriaPolicyEngine.#hasRole(context.props) ? _AriaPolicyEngine.#pipeline : [_AriaPolicyEngine.#checkInvalidAriaAttributes];
1207
+ if (_AriaPolicyEngine.#hasRole(context.props) || context.effectiveRole != null && _AriaPolicyEngine.#LIVE_REGION_ROLES.has(context.effectiveRole)) {
1208
+ return _AriaPolicyEngine.#pipeline;
1209
+ }
1210
+ return _AriaPolicyEngine.#implicitOnlyRules;
782
1211
  }
783
1212
  static evaluate(tag, props) {
784
1213
  const derived = _AriaPolicyEngine.#deriveContext(tag, props);
@@ -803,10 +1232,11 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
803
1232
  return { props: next, violations };
804
1233
  }
805
1234
  report(violations) {
806
- for (const v of violations) {
807
- if (v.severity === "error") this.violate(v.message);
808
- else this.warn(v.message);
809
- }
1235
+ iterate.forEach(violations, (v) => {
1236
+ const d = v.diagnostic ?? AriaDiagnostics.fromViolation(v);
1237
+ if (v.severity === "error") this.violate(d);
1238
+ else this.warn(d);
1239
+ });
810
1240
  }
811
1241
  // Cache key covers only the aria-relevant subset of props (tag + role + aria-* attrs).
812
1242
  // Non-aria props (className, onClick, etc.) do not affect ARIA decisions and are excluded
@@ -818,27 +1248,26 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
818
1248
  if (!isIntrinsicTag(tag)) return null;
819
1249
  const parts = [tag];
820
1250
  if (typeof props.role === "string") parts.push(`role:${props.role}`);
1251
+ if (tag === "input" && typeof props.type === "string") parts.push(`type:${props.type}`);
1252
+ if (tag === "img") parts.push(`alt:${props.alt === "" ? "empty" : "present"}`);
821
1253
  const ariaEntries = [];
822
- for (const k in props) {
823
- if (!Object.hasOwn(props, k) || !k.startsWith("aria-")) continue;
824
- const v = props[k];
825
- if (!isString(v) && !isNumber(v) && typeof v !== "boolean") continue;
1254
+ iterate.forEachEntry(props, (k, v) => {
1255
+ if (!k.startsWith("aria-")) return;
1256
+ if (!isString(v) && !isNumber(v) && typeof v !== "boolean") return;
826
1257
  ariaEntries.push(`${k}:${String(v)}`);
827
- }
1258
+ });
828
1259
  if (ariaEntries.length > 0) parts.push(...ariaEntries.sort());
829
1260
  return parts.join("|");
830
1261
  }
831
1262
  static #computePlan(inputProps, resultProps) {
832
1263
  const removals = /* @__PURE__ */ new Set();
833
1264
  const updates = {};
834
- for (const key in inputProps) {
835
- if (Object.hasOwn(inputProps, key) && !(key in resultProps)) removals.add(key);
836
- }
837
- for (const key in resultProps) {
838
- if (!Object.hasOwn(resultProps, key)) continue;
839
- const resultVal = resultProps[key];
1265
+ iterate.forEachKey(inputProps, (key) => {
1266
+ if (!(key in resultProps)) removals.add(key);
1267
+ });
1268
+ iterate.forEachEntry(resultProps, (key, resultVal) => {
840
1269
  if (inputProps[key] !== resultVal) updates[key] = resultVal;
841
- }
1270
+ });
842
1271
  return { removals, updates };
843
1272
  }
844
1273
  static #applyPlan(props, removals, updates) {
@@ -846,15 +1275,15 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
846
1275
  const hasUpdates = Object.keys(updates).length > 0;
847
1276
  if (!hasRemovals && !hasUpdates) return props;
848
1277
  const next = {};
849
- for (const k in props) {
850
- if (Object.hasOwn(props, k) && !removals.has(k)) next[k] = props[k];
851
- }
1278
+ iterate.forEachEntry(props, (k, v) => {
1279
+ if (!removals.has(k)) next[k] = v;
1280
+ });
852
1281
  Object.assign(next, updates);
853
1282
  return next;
854
1283
  }
855
1284
  validate(tag, props) {
856
1285
  const key = _AriaPolicyEngine.#createPlanKey(tag, props);
857
- if (!isNull2(key)) {
1286
+ if (!isNull(key)) {
858
1287
  const cached = this.#planCache.get(key);
859
1288
  if (cached !== void 0) {
860
1289
  this.#planCache.delete(key);
@@ -868,7 +1297,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
868
1297
  }
869
1298
  const result = this.#extraRules.length ? _AriaPolicyEngine.#evaluateWithRules(tag, props, this.#extraRules) : _AriaPolicyEngine.evaluate(tag, props);
870
1299
  if (result.violations.length > 0) this.report(result.violations);
871
- if (!isNull2(key)) {
1300
+ if (!isNull(key)) {
872
1301
  const { removals, updates } = _AriaPolicyEngine.#computePlan(
873
1302
  props,
874
1303
  result.props
@@ -889,12 +1318,12 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
889
1318
  if (fixes.length === 0) return props;
890
1319
  const sorted = [...fixes].sort((a, b) => (a.priority ?? Infinity) - (b.priority ?? Infinity));
891
1320
  let next = props;
892
- for (const { apply } of sorted) {
1321
+ iterate.forEach(sorted, ({ apply }) => {
893
1322
  const effectiveRole = next.role ?? implicitRole;
894
1323
  const fixContext = { tag, implicitRole, effectiveRole, props: next };
895
1324
  const fixResult = apply(fixContext);
896
1325
  if (fixResult.applied) next = fixResult.next;
897
- }
1326
+ });
898
1327
  return next;
899
1328
  }
900
1329
  static #removeRole = {
@@ -922,10 +1351,26 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
922
1351
  _AriaPolicyEngine.#checkInvalidRoleOverride,
923
1352
  _AriaPolicyEngine.#checkRedundantRole,
924
1353
  _AriaPolicyEngine.#checkStandaloneRegion,
1354
+ _AriaPolicyEngine.#checkAriaAttributeValues,
925
1355
  _AriaPolicyEngine.#checkInvalidAriaAttributes,
1356
+ _AriaPolicyEngine.#checkRequiredAriaProperties,
1357
+ _AriaPolicyEngine.#checkNameRequiredRoles,
1358
+ _AriaPolicyEngine.#checkRedundantAriaLevel,
926
1359
  _AriaPolicyEngine.#checkMissingLiveRegion,
927
1360
  _AriaPolicyEngine.#checkMissingAtomic,
928
- _AriaPolicyEngine.#checkInvalidAriaRelevant
1361
+ _AriaPolicyEngine.#checkInvalidAriaRelevant,
1362
+ _AriaPolicyEngine.#checkAriaHiddenOnFocusable,
1363
+ _AriaPolicyEngine.#checkPresentationalAriaAttributes
1364
+ ];
1365
+ // Rules for elements with an implicit role but no explicit role (not a live region).
1366
+ static #implicitOnlyRules = [
1367
+ _AriaPolicyEngine.#checkAriaAttributeValues,
1368
+ _AriaPolicyEngine.#checkInvalidAriaAttributes,
1369
+ _AriaPolicyEngine.#checkRequiredAriaProperties,
1370
+ _AriaPolicyEngine.#checkNameRequiredRoles,
1371
+ _AriaPolicyEngine.#checkRedundantAriaLevel,
1372
+ _AriaPolicyEngine.#checkAriaHiddenOnFocusable,
1373
+ _AriaPolicyEngine.#checkPresentationalAriaAttributes
929
1374
  ];
930
1375
  static #checkInvalidRoleOverride({
931
1376
  tag,
@@ -941,7 +1386,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
941
1386
  fixable: true,
942
1387
  severity: "error",
943
1388
  fix: _AriaPolicyEngine.#removeRole,
944
- message: `<${tag}> should not override its implicit role="${implicitRole}" with role="${role}".`
1389
+ diagnostic: HtmlDiagnostics.implicitRoleOverride(tag, implicitRole, role)
945
1390
  }
946
1391
  ];
947
1392
  }
@@ -953,47 +1398,304 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
953
1398
  return [
954
1399
  {
955
1400
  valid: false,
956
- fixable: true,
1401
+ fixable: true,
1402
+ severity: "warning",
1403
+ fix: _AriaPolicyEngine.#removeRole,
1404
+ diagnostic: HtmlDiagnostics.implicitRoleRedundant(tag, implicitRole)
1405
+ }
1406
+ ];
1407
+ }
1408
+ static #checkStandaloneRegion({ tag, props, implicitRole }) {
1409
+ const role = props.role;
1410
+ if (role !== "region") return VALID;
1411
+ if (!isStandaloneTag(tag)) return VALID;
1412
+ return [
1413
+ {
1414
+ valid: false,
1415
+ fixable: true,
1416
+ severity: "error",
1417
+ fix: _AriaPolicyEngine.#removeRole,
1418
+ diagnostic: HtmlDiagnostics.standaloneRegionOverride(tag, implicitRole ?? tag)
1419
+ }
1420
+ ];
1421
+ }
1422
+ static #checkInvalidAriaAttributes({
1423
+ tag,
1424
+ props,
1425
+ effectiveRole
1426
+ }) {
1427
+ if (effectiveRole === "none" || effectiveRole === "presentation") return VALID;
1428
+ const results = [];
1429
+ iterate.forEachEntry(props, (key) => {
1430
+ if (!key.startsWith("aria-")) return;
1431
+ if (isGlobalAriaAttribute(key)) return;
1432
+ if (isAriaAttributeValidForRole(key, effectiveRole)) return;
1433
+ results.push({
1434
+ valid: false,
1435
+ severity: "warning",
1436
+ fixable: true,
1437
+ attribute: key,
1438
+ diagnostic: AriaDiagnostics.attributeInvalid(key, effectiveRole ?? tag),
1439
+ fix: _AriaPolicyEngine.#makeRemoveAttributeFix(key)
1440
+ });
1441
+ });
1442
+ return results;
1443
+ }
1444
+ // ─── ARIA attribute value validation ──────────────────────────────────────
1445
+ // Accepted value shapes for typed ARIA attributes.
1446
+ // Attributes not in this map are unconstrained (arbitrary string values permitted).
1447
+ static #ARIA_VALUE_TYPES = /* @__PURE__ */ new Map([
1448
+ // Boolean (true | false)
1449
+ ["aria-atomic", { kind: "boolean" }],
1450
+ ["aria-busy", { kind: "boolean" }],
1451
+ ["aria-disabled", { kind: "boolean" }],
1452
+ ["aria-expanded", { kind: "boolean" }],
1453
+ ["aria-hidden", { kind: "boolean" }],
1454
+ ["aria-modal", { kind: "boolean" }],
1455
+ ["aria-multiline", { kind: "boolean" }],
1456
+ ["aria-multiselectable", { kind: "boolean" }],
1457
+ ["aria-readonly", { kind: "boolean" }],
1458
+ ["aria-required", { kind: "boolean" }],
1459
+ ["aria-selected", { kind: "boolean" }],
1460
+ // Tristate (true | false | mixed)
1461
+ ["aria-checked", { kind: "tristate" }],
1462
+ ["aria-pressed", { kind: "tristate" }],
1463
+ // Numeric (any finite number)
1464
+ ["aria-valuenow", { kind: "number" }],
1465
+ ["aria-valuemin", { kind: "number" }],
1466
+ ["aria-valuemax", { kind: "number" }],
1467
+ // Integer with optional range
1468
+ ["aria-level", { kind: "integer", min: 1, max: 6 }],
1469
+ ["aria-posinset", { kind: "integer", min: 1 }],
1470
+ ["aria-setsize", { kind: "integer", min: -1 }],
1471
+ ["aria-rowcount", { kind: "integer", min: -1 }],
1472
+ ["aria-colcount", { kind: "integer", min: -1 }],
1473
+ ["aria-rowindex", { kind: "integer", min: 1 }],
1474
+ ["aria-colindex", { kind: "integer", min: 1 }],
1475
+ ["aria-rowspan", { kind: "integer", min: 0 }],
1476
+ ["aria-colspan", { kind: "integer", min: 0 }],
1477
+ // Enum (specific allowed tokens)
1478
+ ["aria-autocomplete", { kind: "enum", values: /* @__PURE__ */ new Set(["inline", "list", "both", "none"]) }],
1479
+ [
1480
+ "aria-current",
1481
+ {
1482
+ kind: "enum",
1483
+ values: /* @__PURE__ */ new Set(["page", "step", "location", "date", "time", "true", "false"])
1484
+ }
1485
+ ],
1486
+ [
1487
+ "aria-haspopup",
1488
+ {
1489
+ kind: "enum",
1490
+ values: /* @__PURE__ */ new Set(["false", "true", "menu", "listbox", "tree", "grid", "dialog"])
1491
+ }
1492
+ ],
1493
+ ["aria-invalid", { kind: "enum", values: /* @__PURE__ */ new Set(["grammar", "false", "spelling", "true"]) }],
1494
+ ["aria-live", { kind: "enum", values: /* @__PURE__ */ new Set(["assertive", "off", "polite"]) }],
1495
+ [
1496
+ "aria-orientation",
1497
+ { kind: "enum", values: /* @__PURE__ */ new Set(["horizontal", "vertical", "undefined"]) }
1498
+ ],
1499
+ ["aria-sort", { kind: "enum", values: /* @__PURE__ */ new Set(["ascending", "descending", "none", "other"]) }]
1500
+ ]);
1501
+ static #isValidAriaValue(value, type) {
1502
+ switch (type.kind) {
1503
+ case "boolean":
1504
+ return value === "true" || value === "false" || value === true || value === false;
1505
+ case "tristate":
1506
+ return value === "true" || value === "false" || value === "mixed" || value === true || value === false;
1507
+ case "number": {
1508
+ if (typeof value === "number") return Number.isFinite(value);
1509
+ if (typeof value !== "string") return false;
1510
+ const n = parseFloat(value);
1511
+ return Number.isFinite(n);
1512
+ }
1513
+ case "integer": {
1514
+ const n = typeof value === "number" ? value : typeof value === "string" ? parseInt(value, 10) : NaN;
1515
+ if (!Number.isFinite(n) || !Number.isInteger(n)) return false;
1516
+ if (type.min !== void 0 && n < type.min) return false;
1517
+ if (type.max !== void 0 && n > type.max) return false;
1518
+ return true;
1519
+ }
1520
+ case "enum":
1521
+ return typeof value === "string" && type.values.has(value);
1522
+ }
1523
+ }
1524
+ static #describeExpected(type) {
1525
+ switch (type.kind) {
1526
+ case "boolean":
1527
+ return '"true" or "false"';
1528
+ case "tristate":
1529
+ return '"true", "false", or "mixed"';
1530
+ case "number":
1531
+ return "a finite number";
1532
+ case "integer": {
1533
+ const parts = ["an integer"];
1534
+ if (type.min !== void 0 && type.max !== void 0)
1535
+ parts.push(`between ${type.min} and ${type.max}`);
1536
+ else if (type.min !== void 0) parts.push(`\u2265 ${type.min}`);
1537
+ else if (type.max !== void 0) parts.push(`\u2264 ${type.max}`);
1538
+ return parts.join(" ");
1539
+ }
1540
+ case "enum":
1541
+ return [...type.values].map((v) => `"${v}"`).join(", ");
1542
+ }
1543
+ }
1544
+ static #checkAriaAttributeValues({ props, effectiveRole }) {
1545
+ if (effectiveRole === "none" || effectiveRole === "presentation") return VALID;
1546
+ const results = [];
1547
+ iterate.forEachEntry(props, (key, value) => {
1548
+ if (!key.startsWith("aria-")) return;
1549
+ const type = _AriaPolicyEngine.#ARIA_VALUE_TYPES.get(key);
1550
+ if (type == null) return;
1551
+ if (_AriaPolicyEngine.#isValidAriaValue(value, type)) return;
1552
+ results.push({
1553
+ valid: false,
1554
+ fixable: true,
1555
+ severity: "warning",
1556
+ attribute: key,
1557
+ diagnostic: AriaDiagnostics.invalidAttributeValue(
1558
+ key,
1559
+ value,
1560
+ _AriaPolicyEngine.#describeExpected(type)
1561
+ ),
1562
+ fix: _AriaPolicyEngine.#makeRemoveAttributeFix(key)
1563
+ });
1564
+ });
1565
+ return results;
1566
+ }
1567
+ // ─── Heading implicit level ────────────────────────────────────────────────
1568
+ static #HEADING_IMPLICIT_LEVELS = /* @__PURE__ */ new Map([
1569
+ ["h1", 1],
1570
+ ["h2", 2],
1571
+ ["h3", 3],
1572
+ ["h4", 4],
1573
+ ["h5", 5],
1574
+ ["h6", 6]
1575
+ ]);
1576
+ static #checkRedundantAriaLevel({
1577
+ tag,
1578
+ props,
1579
+ effectiveRole
1580
+ }) {
1581
+ if (effectiveRole === "none" || effectiveRole === "presentation") return VALID;
1582
+ const implicitLevel = _AriaPolicyEngine.#HEADING_IMPLICIT_LEVELS.get(tag);
1583
+ if (implicitLevel == null) return VALID;
1584
+ const raw = props["aria-level"];
1585
+ if (raw == null) return VALID;
1586
+ const n = typeof raw === "number" ? raw : typeof raw === "string" ? parseInt(raw, 10) : NaN;
1587
+ if (!Number.isFinite(n) || n !== implicitLevel) return VALID;
1588
+ return [
1589
+ {
1590
+ valid: false,
1591
+ fixable: true,
1592
+ severity: "warning",
1593
+ attribute: "aria-level",
1594
+ diagnostic: AriaDiagnostics.redundantAriaLevel(tag, implicitLevel),
1595
+ fix: _AriaPolicyEngine.#makeRemoveAttributeFix("aria-level")
1596
+ }
1597
+ ];
1598
+ }
1599
+ // ─── Name-required roles ───────────────────────────────────────────────────
1600
+ // Roles that always require an accessible name per WAI-ARIA APG.
1601
+ // Dialog and landmark names are enforced via contracts (ariaContract) rather than
1602
+ // the built-in pipeline so consumers can opt in; img is built in because role=img
1603
+ // on any element (including bare <img>) is definitionally useless without a name.
1604
+ static #NAME_REQUIRED_ROLES = /* @__PURE__ */ new Set(["img"]);
1605
+ static #checkNameRequiredRoles({
1606
+ tag,
1607
+ props,
1608
+ effectiveRole
1609
+ }) {
1610
+ if (!effectiveRole || !_AriaPolicyEngine.#NAME_REQUIRED_ROLES.has(effectiveRole)) return VALID;
1611
+ if ("aria-label" in props || "aria-labelledby" in props) return VALID;
1612
+ if (tag === "img" && typeof props.alt === "string" && props.alt.length > 0) return VALID;
1613
+ return [
1614
+ {
1615
+ valid: false,
1616
+ fixable: false,
1617
+ severity: "warning",
1618
+ diagnostic: AriaDiagnostics.missingAccessibleName(tag)
1619
+ }
1620
+ ];
1621
+ }
1622
+ // WAI-ARIA 1.2 required states and properties, keyed by role.
1623
+ // Source: https://www.w3.org/TR/wai-aria-1.2/#requiredState
1624
+ static #REQUIRED_PROPERTIES = /* @__PURE__ */ new Map([
1625
+ ["combobox", ["aria-expanded"]],
1626
+ ["option", ["aria-selected"]],
1627
+ ["slider", ["aria-valuenow"]],
1628
+ ["scrollbar", ["aria-controls", "aria-valuenow"]],
1629
+ ["spinbutton", ["aria-valuenow"]]
1630
+ ]);
1631
+ static #checkRequiredAriaProperties({
1632
+ props,
1633
+ effectiveRole
1634
+ }) {
1635
+ if (!effectiveRole) return VALID;
1636
+ const required = _AriaPolicyEngine.#REQUIRED_PROPERTIES.get(effectiveRole);
1637
+ if (required == null) return VALID;
1638
+ const results = [];
1639
+ iterate.forEach(required, (attr) => {
1640
+ if (attr in props) return;
1641
+ results.push({
1642
+ valid: false,
1643
+ fixable: false,
957
1644
  severity: "warning",
958
- fix: _AriaPolicyEngine.#removeRole,
959
- message: `<${tag}> already has implicit role="${implicitRole}". Avoid redundant role assignment.`
960
- }
961
- ];
1645
+ attribute: attr,
1646
+ diagnostic: AriaDiagnostics.requiredProperty(attr, effectiveRole)
1647
+ });
1648
+ });
1649
+ return results;
962
1650
  }
963
- static #checkStandaloneRegion({ tag, props, implicitRole }) {
964
- const role = props.role;
965
- if (role !== "region") return VALID;
966
- if (!isStandaloneTag(tag)) return VALID;
1651
+ // Natively interactive HTML elements always keyboard-reachable unless explicitly disabled.
1652
+ static #INTERACTIVE_TAGS = /* @__PURE__ */ new Set([
1653
+ "a",
1654
+ "button",
1655
+ "input",
1656
+ "select",
1657
+ "textarea"
1658
+ ]);
1659
+ // WAI-ARIA 1.2 §6.6: aria-hidden="true" must not be placed on focusable elements.
1660
+ static #checkAriaHiddenOnFocusable({ tag, props }) {
1661
+ if (props["aria-hidden"] !== "true" && props["aria-hidden"] !== true) return VALID;
1662
+ const isInteractive = _AriaPolicyEngine.#INTERACTIVE_TAGS.has(tag);
1663
+ if (!isInteractive) {
1664
+ const tabindex = props.tabindex;
1665
+ const n = typeof tabindex === "number" ? tabindex : typeof tabindex === "string" ? parseInt(tabindex, 10) : NaN;
1666
+ if (!Number.isFinite(n) || n < 0) return VALID;
1667
+ }
967
1668
  return [
968
1669
  {
969
1670
  valid: false,
970
- fixable: true,
1671
+ fixable: false,
971
1672
  severity: "error",
972
- fix: _AriaPolicyEngine.#removeRole,
973
- message: `<${tag}> is a self-contained element with implicit role="${implicitRole}". Assigning role="region" has been removed.`
1673
+ attribute: "aria-hidden",
1674
+ diagnostic: AriaDiagnostics.ariaHiddenOnFocusable(tag)
974
1675
  }
975
1676
  ];
976
1677
  }
977
- static #checkInvalidAriaAttributes({
1678
+ // Presentational elements (role=none/presentation, including <img alt="">) are removed
1679
+ // from the accessibility tree — ARIA attributes on them are meaningless and misleading.
1680
+ static #checkPresentationalAriaAttributes({
978
1681
  tag,
979
1682
  props,
980
1683
  effectiveRole
981
1684
  }) {
1685
+ if (effectiveRole !== "none" && effectiveRole !== "presentation") return VALID;
982
1686
  const results = [];
983
- for (const key in props) {
984
- if (!Object.hasOwn(props, key)) continue;
985
- if (!key.startsWith("aria-")) continue;
986
- if (isGlobalAriaAttribute(key)) continue;
987
- if (isAriaAttributeValidForRole(key, effectiveRole)) continue;
1687
+ iterate.forEachEntry(props, (key) => {
1688
+ if (!key.startsWith("aria-")) return;
1689
+ if (key === "aria-hidden") return;
988
1690
  results.push({
989
1691
  valid: false,
990
- severity: "warning",
991
1692
  fixable: true,
1693
+ severity: "warning",
992
1694
  attribute: key,
993
- message: `"${key}" is not valid on role="${effectiveRole ?? tag}". It will be removed.`,
1695
+ diagnostic: AriaDiagnostics.attributeOnPresentational(key, tag),
994
1696
  fix: _AriaPolicyEngine.#makeRemoveAttributeFix(key)
995
1697
  });
996
- }
1698
+ });
997
1699
  return results;
998
1700
  }
999
1701
  // WAI-ARIA live region roles and their implied aria-live politeness values.
@@ -1022,7 +1724,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
1022
1724
  fixable: true,
1023
1725
  severity: "warning",
1024
1726
  fix: injectLive,
1025
- message: `role="${effectiveRole}" implies aria-live="${impliedLive}" but it is missing. It has been injected.`
1727
+ diagnostic: AriaDiagnostics.missingLiveRegion(effectiveRole, impliedLive)
1026
1728
  }
1027
1729
  ];
1028
1730
  }
@@ -1034,7 +1736,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
1034
1736
  valid: false,
1035
1737
  fixable: false,
1036
1738
  severity: "warning",
1037
- 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.`
1739
+ diagnostic: AriaDiagnostics.missingAtomic(effectiveRole)
1038
1740
  }
1039
1741
  ];
1040
1742
  }
@@ -1063,7 +1765,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
1063
1765
  fixable: true,
1064
1766
  severity: "warning",
1065
1767
  attribute: "aria-relevant",
1066
- message: `aria-relevant contains invalid token(s): ${invalid.map((t) => `"${t}"`).join(", ")}. Valid tokens are: additions, removals, text, all.`,
1768
+ diagnostic: AriaDiagnostics.relevantInvalidTokens(invalid),
1067
1769
  fix: _AriaPolicyEngine.#makeRemoveAttributeFix("aria-relevant")
1068
1770
  }
1069
1771
  ];
@@ -1075,7 +1777,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
1075
1777
  fixable: true,
1076
1778
  severity: "warning",
1077
1779
  attribute: "aria-relevant",
1078
- message: `aria-relevant includes "all" alongside other tokens. "all" supersedes additions, removals, and text \u2014 use aria-relevant="all" alone.`,
1780
+ diagnostic: AriaDiagnostics.relevantSuperseded(),
1079
1781
  fix: _AriaPolicyEngine.#normalizeRelevantAllFix
1080
1782
  }
1081
1783
  ];
@@ -1083,6 +1785,8 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
1083
1785
  return VALID;
1084
1786
  }
1085
1787
  };
1788
+
1789
+ // ../../lib/contract/src/children/get-type-name.ts
1086
1790
  function getTypeName(value) {
1087
1791
  if (value === null) return "null";
1088
1792
  if (value === void 0) return "undefined";
@@ -1093,39 +1797,8 @@ function getTypeName(value) {
1093
1797
  const name = value.constructor?.name;
1094
1798
  return typeof name === "string" && name !== "Object" ? name : "object";
1095
1799
  }
1096
- var MatchValidationErrorBuilder = class {
1097
- #prefix;
1098
- constructor(ctx = "") {
1099
- this.#prefix = ctx ? `${ctx}:
1100
- ` : "";
1101
- }
1102
- #template(typeName, index, prefix = "", suffix = "") {
1103
- const leadingStr = prefix ? `${prefix} ` : "";
1104
- const followingStr = suffix ? ` ${suffix}` : "";
1105
- return `${leadingStr}child "${typeName}" at index ${index}${followingStr}.`;
1106
- }
1107
- unexpectedChild(typeName, index) {
1108
- return this.#template(typeName, index, "unexpected");
1109
- }
1110
- multipleMatches(typeName, index, ruleNames) {
1111
- const quoted = ruleNames.map((n) => `"${n}"`);
1112
- return this.#template(
1113
- typeName,
1114
- index,
1115
- "",
1116
- `matches multiple child rules: ${quoted.join(" and ")}`
1117
- );
1118
- }
1119
- #format(errors) {
1120
- return this.#prefix + errors.join("\n");
1121
- }
1122
- toError(errors) {
1123
- if (errors.length === 0) {
1124
- return new Error(this.#prefix + "Unknown validation error.");
1125
- }
1126
- return new Error(this.#format(errors));
1127
- }
1128
- };
1800
+
1801
+ // ../../lib/contract/src/children/normalize-child-rule.ts
1129
1802
  function normalizeCardinality(input, impliesSingleton) {
1130
1803
  const min = input?.min ?? 0;
1131
1804
  const max = input?.max ?? (impliesSingleton ? 1 : Infinity);
@@ -1150,6 +1823,8 @@ function normalizeChildRule(rule) {
1150
1823
  cardinality: normalizeCardinality(rule.cardinality, impliesSingleton)
1151
1824
  };
1152
1825
  }
1826
+
1827
+ // ../../lib/contract/src/children/rules-matcher.ts
1153
1828
  function getChildType(child) {
1154
1829
  if (!isObject(child) || !("type" in child)) return void 0;
1155
1830
  return child.type;
@@ -1158,8 +1833,8 @@ function buildPartialIndex(rules) {
1158
1833
  const typeIndex = /* @__PURE__ */ new Map();
1159
1834
  const duplicateTypes = /* @__PURE__ */ new Set();
1160
1835
  const untypedIndices = [];
1161
- for (let ri = 0; ri < rules.length; ri++) {
1162
- const t = rules[ri].type;
1836
+ iterate.forEach(rules, (rule, ri) => {
1837
+ const t = rule.type;
1163
1838
  if (t === void 0) {
1164
1839
  untypedIndices.push(ri);
1165
1840
  } else if (typeIndex.has(t)) {
@@ -1167,12 +1842,14 @@ function buildPartialIndex(rules) {
1167
1842
  } else {
1168
1843
  typeIndex.set(t, ri);
1169
1844
  }
1170
- }
1845
+ });
1171
1846
  if (duplicateTypes.size > 0) {
1172
- for (const t of duplicateTypes) typeIndex.delete(t);
1173
- for (let ri = 0; ri < rules.length; ri++) {
1174
- if (duplicateTypes.has(rules[ri].type)) untypedIndices.push(ri);
1175
- }
1847
+ iterate.forEachSet(duplicateTypes, (t) => {
1848
+ typeIndex.delete(t);
1849
+ });
1850
+ iterate.forEach(rules, (rule, ri) => {
1851
+ if (duplicateTypes.has(rule.type)) untypedIndices.push(ri);
1852
+ });
1176
1853
  }
1177
1854
  return { typeIndex, untypedIndices };
1178
1855
  }
@@ -1191,10 +1868,10 @@ var RuleMatcher = class {
1191
1868
  const reverse = /* @__PURE__ */ new Map();
1192
1869
  const unexpectedIndices = /* @__PURE__ */ new Set();
1193
1870
  const ambiguousIndices = /* @__PURE__ */ new Set();
1194
- for (let ri = 0; ri < this.#rules.length; ri++) {
1871
+ iterate.forEach(this.#rules, (_, ri) => {
1195
1872
  reverse.set(ri, /* @__PURE__ */ new Set());
1196
- }
1197
- for (const [ci, child] of children.entries()) {
1873
+ });
1874
+ iterate.forEach(children, (child, ci) => {
1198
1875
  const t = getChildType(child);
1199
1876
  if (t !== void 0) {
1200
1877
  const ri = this.#typeIndex.get(t);
@@ -1208,8 +1885,8 @@ var RuleMatcher = class {
1208
1885
  reverse.get(ri).add(ci);
1209
1886
  }
1210
1887
  }
1211
- for (const ri of this.#untypedIndices) {
1212
- if (!this.#rules[ri].match(child)) continue;
1888
+ iterate.forEach(this.#untypedIndices, (ri) => {
1889
+ if (!this.#rules[ri].match(child)) return;
1213
1890
  let childEntry = forward.get(ci);
1214
1891
  if (!childEntry) {
1215
1892
  childEntry = /* @__PURE__ */ new Set();
@@ -1217,33 +1894,35 @@ var RuleMatcher = class {
1217
1894
  }
1218
1895
  childEntry.add(ri);
1219
1896
  reverse.get(ri).add(ci);
1220
- }
1897
+ });
1221
1898
  const entry = forward.get(ci);
1222
1899
  if (!entry) {
1223
1900
  unexpectedIndices.add(ci);
1224
1901
  } else if (entry.size > 1) {
1225
1902
  ambiguousIndices.add(ci);
1226
1903
  }
1227
- }
1904
+ });
1228
1905
  return { matrix: { childToRules: { forward, reverse } }, unexpectedIndices, ambiguousIndices };
1229
1906
  }
1230
1907
  };
1231
- var RuleValidator = class _RuleValidator extends StrictBase {
1908
+
1909
+ // ../../lib/contract/src/children/rule-validator.ts
1910
+ var RuleValidator = class _RuleValidator extends InvariantBase {
1232
1911
  #context;
1233
- constructor(context, strict) {
1234
- super(strict);
1912
+ constructor(context, diagnostics) {
1913
+ super(diagnostics);
1235
1914
  this.#context = context;
1236
1915
  }
1237
1916
  validate(rules, matrix, childCount) {
1238
1917
  const firstIndex = 0;
1239
1918
  const lastIndex = childCount - 1;
1240
- for (const [ri, rule] of rules.entries()) {
1919
+ iterate.forEach(rules, (rule, ri) => {
1241
1920
  const matches = matrix.childToRules.reverse.get(ri);
1242
1921
  const matchCount = matches.size;
1243
1922
  this.#validateCardinality(rule, matchCount);
1244
- if (matchCount === 0) continue;
1923
+ if (matchCount === 0) return;
1245
1924
  this.#validatePositions(rule, matches, firstIndex, lastIndex);
1246
- }
1925
+ });
1247
1926
  }
1248
1927
  #validateCardinality(rule, matchCount) {
1249
1928
  const { cardinality, name } = rule;
@@ -1252,21 +1931,21 @@ var RuleValidator = class _RuleValidator extends StrictBase {
1252
1931
  }
1253
1932
  const { min, max } = cardinality;
1254
1933
  if (matchCount < min) {
1255
- this.violate(`${this.#context}: "${name}" requires at least ${min}.`);
1934
+ this.violate(ContractDiagnostics.cardinalityMin(name, min, this.#context));
1256
1935
  return;
1257
1936
  }
1258
1937
  if (matchCount > max) {
1259
- this.violate(`${this.#context}: "${name}" allows at most ${max}.`);
1938
+ this.violate(ContractDiagnostics.cardinalityMax(name, max, this.#context));
1260
1939
  }
1261
1940
  }
1262
1941
  #validatePositions(rule, matches, firstIndex, lastIndex) {
1263
1942
  const { name, position } = rule;
1264
- for (const index of matches) {
1943
+ iterate.forEachSet(matches, (index) => {
1265
1944
  if (_RuleValidator.#isValidPosition(index, position, firstIndex, lastIndex)) {
1266
- continue;
1945
+ return;
1267
1946
  }
1268
- this.violate(`${this.#context}: "${name}" must be ${position}, got index ${index}`);
1269
- }
1947
+ this.violate(ContractDiagnostics.positionViolation(name, position, index, this.#context));
1948
+ });
1270
1949
  }
1271
1950
  static #isValidPosition(matchIndex, position, firstIndex, lastIndex) {
1272
1951
  switch (position) {
@@ -1281,48 +1960,50 @@ var RuleValidator = class _RuleValidator extends StrictBase {
1281
1960
  }
1282
1961
  }
1283
1962
  };
1284
- var ChildrenEvaluator = class extends StrictBase {
1963
+
1964
+ // ../../lib/contract/src/children/children-evaluator.ts
1965
+ var ChildrenEvaluator = class extends InvariantBase {
1966
+ #context;
1285
1967
  #rules;
1286
1968
  #ruleNames;
1287
1969
  #matcher;
1288
1970
  #ruleValidator;
1289
- #matchBuilder;
1290
- constructor(rules, strict = "warn", context = "Component") {
1291
- super(strict);
1292
- this.#rules = rules.map((r2) => normalizeChildRule(r2));
1293
- this.#ruleNames = this.#rules.map((r2) => r2.name);
1294
- for (const rule of this.#rules) {
1971
+ constructor(rules, diagnostics, context = "Component") {
1972
+ super(diagnostics);
1973
+ this.#context = context;
1974
+ this.#rules = rules.map((r) => normalizeChildRule(r));
1975
+ this.#ruleNames = this.#rules.map((r) => r.name);
1976
+ iterate.forEach(this.#rules, (rule) => {
1295
1977
  const { name, position, cardinality } = rule;
1296
1978
  if ((position === "first" || position === "last") && (cardinality.kind === "unbounded" || cardinality.max > 1)) {
1297
1979
  throw new RangeError(
1298
1980
  `ChildrenEvaluator [${context}]: rule "${name}" sets position="${position}" with an unbound or >1 max. position="first|last" implies max=1.`
1299
1981
  );
1300
1982
  }
1301
- }
1983
+ });
1302
1984
  this.#matcher = new RuleMatcher(this.#rules);
1303
- this.#ruleValidator = new RuleValidator(context, strict);
1304
- this.#matchBuilder = new MatchValidationErrorBuilder(context);
1985
+ this.#ruleValidator = new RuleValidator(context, diagnostics);
1305
1986
  }
1306
1987
  evaluate(children) {
1307
- if (!this.strict) return;
1988
+ if (!this.active) return;
1308
1989
  const { matrix, unexpectedIndices, ambiguousIndices } = this.#matcher.match(children);
1309
1990
  this.#ruleValidator.validate(this.#rules, matrix, children.length);
1310
1991
  if (unexpectedIndices.size === 0 && ambiguousIndices.size === 0) return;
1311
- const errors = [];
1312
1992
  const violating = [...unexpectedIndices, ...ambiguousIndices].sort((a, b) => a - b);
1313
- for (const ci of violating) {
1993
+ iterate.forEach(violating, (ci) => {
1314
1994
  const typeName = getTypeName(children[ci]);
1315
1995
  if (unexpectedIndices.has(ci)) {
1316
- errors.push(this.#matchBuilder.unexpectedChild(typeName, ci));
1996
+ this.violate(ContractDiagnostics.unexpectedChild(typeName, ci, this.#context));
1317
1997
  } else {
1318
1998
  const matches = matrix.childToRules.forward.get(ci);
1319
1999
  const names = [...matches].map((ri) => this.#ruleNames[ri] ?? `#${ri}`);
1320
- errors.push(this.#matchBuilder.multipleMatches(typeName, ci, names));
2000
+ this.violate(ContractDiagnostics.ambiguousChild(typeName, ci, names, this.#context));
1321
2001
  }
1322
- }
1323
- this.invariant(errors.length === 0, this.#matchBuilder.toError(errors).message);
2002
+ });
1324
2003
  }
1325
2004
  };
2005
+
2006
+ // ../../lib/contract/src/props/get-disabled-props.ts
1326
2007
  var disabledProps = ({
1327
2008
  disabled,
1328
2009
  "aria-disabled": ariaDisabled,
@@ -1334,6 +2015,8 @@ var disabledProps = ({
1334
2015
  ...dataDisabled === void 0 && { "data-disabled": "" }
1335
2016
  };
1336
2017
  };
2018
+
2019
+ // ../../lib/contract/src/props/get-invalid-props.ts
1337
2020
  var invalidProps = ({
1338
2021
  invalid,
1339
2022
  "aria-invalid": ariaInvalid,
@@ -1345,6 +2028,8 @@ var invalidProps = ({
1345
2028
  ...dataInvalid === void 0 && { "data-invalid": "" }
1346
2029
  };
1347
2030
  };
2031
+
2032
+ // ../../lib/contract/src/props/get-readonly-props.ts
1348
2033
  var readonlyProps = ({
1349
2034
  readOnly,
1350
2035
  "aria-readonly": ariaReadonly,
@@ -1360,6 +2045,8 @@ var readonlyProps = ({
1360
2045
  }
1361
2046
  };
1362
2047
  };
2048
+
2049
+ // ../core/src/html/aria-rules.ts
1363
2050
  var LANDMARK_TAG_SET = /* @__PURE__ */ new Set(["article", "aside", "footer", "header", "main", "nav"]);
1364
2051
  var removeLandmarkRoleOverride = {
1365
2052
  kind: "removeRole",
@@ -1379,154 +2066,29 @@ function landmarkRoleRule({ tag, props, implicitRole }) {
1379
2066
  fixable: true,
1380
2067
  severity: "error",
1381
2068
  fix: removeLandmarkRoleOverride,
1382
- message: `<${tag}> has a fixed landmark role="${implicitRole}". role="${role}" overrides it and confuses assistive technology. The override has been removed.`
2069
+ diagnostic: HtmlDiagnostics.landmarkRoleOverride(tag, implicitRole, role)
1383
2070
  }
1384
2071
  ];
1385
2072
  }
1386
- var HTML_ARIA_RULES = [landmarkRoleRule];
1387
- function isOpenContent(...blockedTags) {
1388
- const set = new Set(blockedTags);
1389
- return (child) => isObject(child) && "type" in child && (!isString(child.type) || !set.has(child.type));
1390
- }
1391
- var METADATA_TAGS = ["script", "template"];
1392
- var metadataMatch = isTag(...METADATA_TAGS);
1393
- function metadata(name = "metadata") {
1394
- return { name, match: metadataMatch };
1395
- }
1396
- function firstOptional(name, tag) {
1397
- return { name, match: isTag(tag), cardinality: { max: 1 }, position: "first" };
1398
- }
1399
- function contract(children) {
1400
- return { strict: "warn", children };
1401
- }
1402
- function ariaContract(aria) {
1403
- return { strict: "warn", aria };
1404
- }
1405
- function firstChildContract(name, tag) {
1406
- return contract([firstOptional(name, tag), { name: "content", match: isOpenContent(tag) }]);
1407
- }
1408
- var VOID_TAGS = [
1409
- "area",
1410
- "base",
1411
- "br",
1412
- "col",
1413
- "embed",
1414
- "hr",
1415
- "img",
1416
- "input",
1417
- "link",
1418
- "meta",
1419
- "param",
1420
- "source",
1421
- "track",
1422
- "wbr"
1423
- ];
1424
- var TEXT_ONLY_TAGS = ["option", "script", "style", "textarea", "title"];
1425
- var LANDMARK_TAGS = ["article", "aside", "footer", "header", "main", "nav"];
1426
- var listContract = contract([{ name: "list-item", match: isTag("li", ...METADATA_TAGS) }]);
1427
- var tableContract = contract([
1428
- firstOptional("caption", "caption"),
1429
- { name: "colgroup", match: isTag("colgroup") },
1430
- { name: "thead", match: isTag("thead"), cardinality: { max: 1 } },
1431
- { name: "tbody", match: isTag("tbody") },
1432
- { name: "tfoot", match: isTag("tfoot"), cardinality: { max: 1 } },
1433
- { name: "table-row", match: isTag("tr", ...METADATA_TAGS) }
1434
- ]);
1435
- var tableBodyContract = contract([
1436
- { name: "table-row", match: isTag("tr", ...METADATA_TAGS) }
1437
- ]);
1438
- var tableRowContract = contract([
1439
- { name: "table-cell", match: isTag("td", "th", ...METADATA_TAGS) }
1440
- ]);
1441
- var colgroupContract = contract([{ name: "column", match: isTag("col", "template") }]);
1442
- var dlContract = contract([
1443
- { name: "term", match: isTag("dt") },
1444
- { name: "description", match: isTag("dd") },
1445
- { name: "group", match: isTag("div") },
1446
- metadata()
1447
- ]);
1448
- var selectContract = contract([
1449
- { name: "option", match: isTag("option", "optgroup", "hr", ...METADATA_TAGS) }
1450
- ]);
1451
- var optgroupContract = contract([
1452
- { name: "option", match: isTag("option", ...METADATA_TAGS) }
1453
- ]);
1454
- var datalistContract = contract([
1455
- { name: "option", match: isTag("option", ...METADATA_TAGS) }
1456
- ]);
1457
- var pictureContract = contract([
1458
- { name: "source", match: isTag("source", ...METADATA_TAGS) },
1459
- { name: "image", match: isTag("img"), cardinality: { min: 1, max: 1 }, position: "last" }
1460
- ]);
1461
- var figureContract = contract([
1462
- { name: "caption", match: isTag("figcaption"), cardinality: { max: 1 } },
1463
- { name: "content", match: isOpenContent("figcaption") }
1464
- ]);
1465
- var detailsContract = firstChildContract("summary", "summary");
1466
- var fieldsetContract = firstChildContract("legend", "legend");
1467
- var mediaContract = contract([
1468
- { name: "source", match: isTag("source") },
1469
- { name: "track", match: isTag("track") },
1470
- metadata(),
1471
- { name: "content", match: isOpenContent("source", "track", ...METADATA_TAGS) }
1472
- ]);
1473
- var headContract = contract([
1474
- {
1475
- name: "metadata",
1476
- match: isTag("base", "link", "meta", "noscript", "script", "style", "template", "title")
1477
- }
1478
- ]);
1479
- var htmlContract = contract([
1480
- { name: "head", match: isTag("head"), cardinality: { min: 1, max: 1 }, position: "first" },
1481
- { name: "body", match: isTag("body"), cardinality: { min: 1, max: 1 } }
1482
- ]);
1483
- var voidContract = contract([]);
1484
- var textOnlyContract = contract([
1485
- {
1486
- name: "text",
1487
- match: (child) => isString(child) || isNumber(child)
1488
- }
1489
- ]);
1490
- var landmarkContract = ariaContract([landmarkRoleRule]);
1491
- var CONTRACT_GROUPS = [
1492
- [VOID_TAGS, voidContract],
1493
- [TEXT_ONLY_TAGS, textOnlyContract],
1494
- [LANDMARK_TAGS, landmarkContract],
1495
- [["ul", "ol", "menu"], listContract],
1496
- [["audio", "video"], mediaContract],
1497
- [["thead", "tbody", "tfoot"], tableBodyContract]
1498
- ];
1499
- function contractMap(groups) {
1500
- return Object.fromEntries(
1501
- groups.flatMap(([tags, enforcement]) => tags.map((tag) => [tag, enforcement]))
1502
- );
1503
- }
1504
- var htmlContracts = {
1505
- ...contractMap(CONTRACT_GROUPS),
1506
- table: tableContract,
1507
- tr: tableRowContract,
1508
- colgroup: colgroupContract,
1509
- dl: dlContract,
1510
- select: selectContract,
1511
- optgroup: optgroupContract,
1512
- datalist: datalistContract,
1513
- picture: pictureContract,
1514
- figure: figureContract,
1515
- details: detailsContract,
1516
- fieldset: fieldsetContract,
1517
- head: headContract,
1518
- html: htmlContract
1519
- };
1520
- function buildEvaluatorMap() {
1521
- const map = /* @__PURE__ */ new Map();
1522
- for (const [tag, { children }] of Object.entries(htmlContracts)) {
1523
- if (children?.length) {
1524
- map.set(tag, new ChildrenEvaluator(children, "warn", `<${tag}>`));
2073
+ function requireAccessibleName({ tag, props }) {
2074
+ if ("aria-label" in props || "aria-labelledby" in props) return [];
2075
+ return [
2076
+ {
2077
+ valid: false,
2078
+ fixable: false,
2079
+ severity: "warning",
2080
+ diagnostic: AriaDiagnostics.missingAccessibleName(tag)
1525
2081
  }
1526
- }
1527
- return map;
2082
+ ];
1528
2083
  }
1529
- var HTML_EVALUATORS = buildEvaluatorMap();
2084
+ var NAMED_LANDMARK_TAGS = /* @__PURE__ */ new Set(["nav", "aside"]);
2085
+ function landmarkNameAdvisory(ctx) {
2086
+ if (!ctx.implicitRole || !NAMED_LANDMARK_TAGS.has(ctx.tag)) return [];
2087
+ return requireAccessibleName(ctx);
2088
+ }
2089
+ var HTML_ARIA_RULES = [landmarkRoleRule, landmarkNameAdvisory];
2090
+
2091
+ // ../core/src/html/prop-normalizers.ts
1530
2092
  var HTML_FORM_NORMALIZERS = /* @__PURE__ */ new Map([
1531
2093
  ["button", [disabledProps]],
1532
2094
  ["input", [disabledProps, readonlyProps, invalidProps]],
@@ -1539,9 +2101,10 @@ function getHtmlPropNormalizers(tag) {
1539
2101
  return typeof tag === "string" ? HTML_FORM_NORMALIZERS.get(tag) : void 0;
1540
2102
  }
1541
2103
 
1542
- // ../core/dist/chunk-3T4EM5FG.js
2104
+ // ../../node_modules/.pnpm/class-variance-authority@0.7.1/node_modules/class-variance-authority/dist/index.mjs
2105
+ import { clsx as clsx2 } from "clsx";
1543
2106
  var falsyToString = (value) => typeof value === "boolean" ? `${value}` : value === 0 ? "0" : value;
1544
- var cx = clsx;
2107
+ var cx = clsx2;
1545
2108
  var cva = (base, config) => (props) => {
1546
2109
  var _config_compoundVariants;
1547
2110
  if ((config === null || config === void 0 ? void 0 : config.variants) == null) return cx(base, props === null || props === void 0 ? void 0 : props.class, props === null || props === void 0 ? void 0 : props.className);
@@ -1580,10 +2143,14 @@ var cva = (base, config) => (props) => {
1580
2143
  }, []);
1581
2144
  return cx(base, getVariantClassNames, getCompoundVariantClassNames, props === null || props === void 0 ? void 0 : props.class, props === null || props === void 0 ? void 0 : props.className);
1582
2145
  };
2146
+
2147
+ // ../../lib/styling/src/cva.ts
1583
2148
  function cva2(base, config) {
1584
2149
  const fn = cva(base, config);
1585
2150
  return (props) => cn(fn(props));
1586
2151
  }
2152
+
2153
+ // ../../lib/styling/src/static-class-resolver.ts
1587
2154
  var StaticClassResolver = class {
1588
2155
  #baseClass;
1589
2156
  #cache = /* @__PURE__ */ new Map();
@@ -1614,6 +2181,8 @@ var StaticClassResolver = class {
1614
2181
  return result;
1615
2182
  }
1616
2183
  };
2184
+
2185
+ // ../../lib/styling/src/variant-class-resolver.ts
1617
2186
  var VariantClassResolver = class _VariantClassResolver {
1618
2187
  #cvaFn;
1619
2188
  #recipeMap;
@@ -1661,15 +2230,15 @@ var VariantClassResolver = class _VariantClassResolver {
1661
2230
  #createCacheKey(props, recipe) {
1662
2231
  if (this.#variantKeys !== null) {
1663
2232
  let key2 = recipe;
1664
- for (const k of this.#variantKeys) {
2233
+ iterate.forEachSet(this.#variantKeys, (k) => {
1665
2234
  if (k in props) key2 += `|${k}:${_VariantClassResolver.#serializeValue(props[k])}`;
1666
- }
2235
+ });
1667
2236
  return key2;
1668
2237
  }
1669
2238
  let key = recipe;
1670
- for (const k of Object.keys(props).sort()) {
2239
+ iterate.forEach(Object.keys(props).sort(), (k) => {
1671
2240
  key += `|${k}:${_VariantClassResolver.#serializeValue(props[k])}`;
1672
- }
2241
+ });
1673
2242
  return key;
1674
2243
  }
1675
2244
  static #serializeValue(value) {
@@ -1680,6 +2249,8 @@ var VariantClassResolver = class _VariantClassResolver {
1680
2249
  return `x:${String(value)}`;
1681
2250
  }
1682
2251
  };
2252
+
2253
+ // ../../lib/styling/src/create-class-pipeline.ts
1683
2254
  function createClassPipeline(resolved) {
1684
2255
  const baseClass = resolved.baseClassName ?? "";
1685
2256
  const cvaFn = resolved.variants ? cva2("", {
@@ -1704,7 +2275,203 @@ function createClassPipeline(resolved) {
1704
2275
  };
1705
2276
  }
1706
2277
 
1707
- // ../core/dist/index.js
2278
+ // ../core/src/options/resolve-factory-options.ts
2279
+ var EMPTY_VARIANT_KEYS = /* @__PURE__ */ new Set();
2280
+ function composeNormalizers(normalizers, fn) {
2281
+ if (!normalizers?.length) return fn;
2282
+ return ((props) => {
2283
+ const patched = normalizers.reduce(
2284
+ (acc, normalizer) => ({ ...acc, ...normalizer(acc) }),
2285
+ props
2286
+ );
2287
+ return fn ? fn(patched) : patched;
2288
+ });
2289
+ }
2290
+ function whenDefined(key, value) {
2291
+ return value === void 0 ? {} : { [key]: value };
2292
+ }
2293
+ function resolveFactoryOptions(options = {}) {
2294
+ const { styling, enforcement } = options;
2295
+ const composedNormalizeFn = composeNormalizers(enforcement?.props, options.normalize);
2296
+ const variantKeys = styling?.variants === void 0 ? EMPTY_VARIANT_KEYS : new Set(Object.keys(styling.variants));
2297
+ return Object.freeze({
2298
+ defaultTag: options.tag ?? "div",
2299
+ diagnostics: enforcement?.diagnostics ?? silentDiagnostics,
2300
+ variantKeys,
2301
+ ...whenDefined("displayName", options.name),
2302
+ ...whenDefined("defaultProps", options.defaults),
2303
+ ...whenDefined("baseClassName", styling?.base),
2304
+ ...whenDefined("tagMap", styling?.tags),
2305
+ ...whenDefined("recipeMap", styling?.presets),
2306
+ ...whenDefined("variants", styling?.variants),
2307
+ ...whenDefined("defaultVariants", styling?.defaults),
2308
+ ...whenDefined("compoundVariants", styling?.compounds),
2309
+ ...whenDefined("normalizeFn", composedNormalizeFn),
2310
+ ...whenDefined("ariaRules", enforcement?.aria),
2311
+ ...whenDefined("childRules", enforcement?.children),
2312
+ ...whenDefined("allowedAs", enforcement?.allowedAs),
2313
+ ...whenDefined("precomputedClasses", styling?.precomputedClasses)
2314
+ });
2315
+ }
2316
+
2317
+ // ../core/src/options/validate-factory-options.ts
2318
+ function validateFactoryOptions(resolved, diagnostics) {
2319
+ if (!diagnostics.active) return;
2320
+ const name = resolved.displayName ?? "Component";
2321
+ const { variants } = resolved;
2322
+ const checkSelection = (label2, selection) => {
2323
+ iterate.forEachEntry(selection, (dim, value) => {
2324
+ if (value === void 0 || value === null) return;
2325
+ if (!variants || !Object.hasOwn(variants, dim)) {
2326
+ diagnostics.error(ContractDiagnostics.unknownVariantDim(name, label2, dim));
2327
+ return;
2328
+ }
2329
+ const states = variants[dim];
2330
+ const stateKey = String(value);
2331
+ if (!Object.hasOwn(states, stateKey)) {
2332
+ diagnostics.error(
2333
+ ContractDiagnostics.unknownVariantValue(name, label2, dim, stateKey, Object.keys(states))
2334
+ );
2335
+ }
2336
+ });
2337
+ };
2338
+ const { recipeMap } = resolved;
2339
+ if (recipeMap) {
2340
+ iterate.forEachEntry(recipeMap, (recipeKey, selection) => {
2341
+ checkSelection(`preset "${recipeKey}"`, selection);
2342
+ });
2343
+ }
2344
+ if (resolved.defaultVariants) checkSelection("defaults", resolved.defaultVariants);
2345
+ }
2346
+
2347
+ // ../core/src/options/validate-render-props.ts
2348
+ function label(name) {
2349
+ return name ? `[${name}]` : "[createContractComponent]";
2350
+ }
2351
+ function validateRenderProps(diagnostics, options, props, recipeKey) {
2352
+ const { recipeMap, variants, displayName } = options;
2353
+ const tag = label(displayName);
2354
+ if (recipeKey !== void 0 && (!recipeMap || !Object.hasOwn(recipeMap, recipeKey))) {
2355
+ diagnostics.error(ContractDiagnostics.unknownRecipeKey(tag, recipeKey));
2356
+ }
2357
+ if (variants) {
2358
+ iterate.forEachKey(variants, (key) => {
2359
+ if (!Object.hasOwn(props, key)) return;
2360
+ const value = props[key];
2361
+ if (value === void 0 || value === null) return;
2362
+ const dim = variants[key];
2363
+ if (dim && !Object.hasOwn(dim, String(value))) {
2364
+ diagnostics.error(ContractDiagnostics.invalidVariantValue(tag, key, String(value)));
2365
+ }
2366
+ });
2367
+ }
2368
+ }
2369
+
2370
+ // ../core/src/factory/plugin-diagnostics.ts
2371
+ var PluginDiagnostics = {
2372
+ invalidShape(received) {
2373
+ const got = received === null ? "null" : typeof received;
2374
+ return {
2375
+ code: "PLUGIN7001" /* PluginInvalidShape */,
2376
+ category: 7 /* Internal */,
2377
+ message: `[praxis-kit] Plugin factory must return an object with a 'pipeline' function. Got: ${got}.`
2378
+ };
2379
+ },
2380
+ pipelineReturnType(received) {
2381
+ const got = received === null ? "null" : Array.isArray(received) ? "array" : typeof received;
2382
+ return {
2383
+ code: "PLUGIN7002" /* PluginPipelineReturnType */,
2384
+ category: 7 /* Internal */,
2385
+ message: `[praxis-kit] Plugin pipeline must return a string. Got: ${got}.`
2386
+ };
2387
+ }
2388
+ };
2389
+
2390
+ // ../core/src/factory/plugin-invariants.ts
2391
+ function assertPluginShape(result) {
2392
+ if (result === null || typeof result !== "object")
2393
+ throwDiagnostics.error(PluginDiagnostics.invalidShape(result));
2394
+ const plugin = result;
2395
+ if (typeof plugin.pipeline !== "function")
2396
+ throwDiagnostics.error(PluginDiagnostics.invalidShape(result));
2397
+ }
2398
+ function guardPipeline(pipeline) {
2399
+ if (process.env.NODE_ENV === "production") return pipeline;
2400
+ return function guardedPipeline(tag, props, className, recipe) {
2401
+ const result = pipeline(tag, props, className, recipe);
2402
+ if (typeof result !== "string")
2403
+ throwDiagnostics.error(PluginDiagnostics.pipelineReturnType(result));
2404
+ return result;
2405
+ };
2406
+ }
2407
+
2408
+ // ../core/src/factory/create-polymorphic.ts
2409
+ var NOOP_CLASS_PIPELINE = (_tag, _props, className) => Array.isArray(className) ? className.join(" ") : className ?? "";
2410
+ function resolveClassPipeline(options, resolved, diagnostics, capabilities) {
2411
+ const factory = options.styling?.plugin;
2412
+ if (!factory) {
2413
+ const createClassPipeline2 = capabilities?.createClassPipeline;
2414
+ const classPipeline2 = createClassPipeline2 ? createClassPipeline2(resolved) : NOOP_CLASS_PIPELINE;
2415
+ return { pluginResult: void 0, classPipeline: classPipeline2 };
2416
+ }
2417
+ const pluginResult = factory(resolved, diagnostics);
2418
+ assertPluginShape(pluginResult);
2419
+ const classPipeline = guardPipeline(pluginResult.pipeline);
2420
+ return { pluginResult, classPipeline };
2421
+ }
2422
+ function createRuntimeMethods(resolved, classPipeline, engine, renderDiagnostics) {
2423
+ return {
2424
+ resolveTag: makeResolveTag(resolved.defaultTag),
2425
+ resolveProps(props) {
2426
+ return mergeProps(resolved.defaultProps, props);
2427
+ },
2428
+ resolveClasses(tag, props, className, recipe) {
2429
+ if (process.env.NODE_ENV !== "production") {
2430
+ validateRenderProps(renderDiagnostics, resolved, props, recipe);
2431
+ }
2432
+ return classPipeline(tag, props, className, recipe);
2433
+ },
2434
+ resolveAria(tag, props) {
2435
+ if (!engine) return { props };
2436
+ const result = engine.validate(tag, props);
2437
+ return { props: result.props };
2438
+ }
2439
+ };
2440
+ }
2441
+ function createRuntimeObject(methods, resolved, pluginResult) {
2442
+ return pluginResult ? { ...methods, options: resolved, hasStyling: true, classPlugin: pluginResult } : { ...methods, options: resolved };
2443
+ }
2444
+ function createPolymorphic(options = {}, capabilities) {
2445
+ const baseResolved = resolveFactoryOptions(options);
2446
+ const resolved = capabilities?.htmlPropNormalizersFn !== void 0 ? Object.freeze({
2447
+ ...baseResolved,
2448
+ htmlPropNormalizersFn: capabilities.htmlPropNormalizersFn
2449
+ }) : baseResolved;
2450
+ if (process.env.NODE_ENV !== "production") {
2451
+ validateFactoryOptions(resolved, resolved.diagnostics);
2452
+ }
2453
+ const { pluginResult, classPipeline } = resolveClassPipeline(
2454
+ options,
2455
+ resolved,
2456
+ resolved.diagnostics,
2457
+ capabilities
2458
+ );
2459
+ const allAriaRules = [
2460
+ .../* @__PURE__ */ new Set([...capabilities?.htmlAriaRules ?? [], ...resolved.ariaRules ?? []])
2461
+ ];
2462
+ const engine = options.enforcement !== void 0 && capabilities?.AriaEngine ? new capabilities.AriaEngine(
2463
+ resolved.diagnostics,
2464
+ allAriaRules.length ? { rules: allAriaRules } : void 0
2465
+ ) : null;
2466
+ const methods = createRuntimeMethods(resolved, classPipeline, engine, resolved.diagnostics);
2467
+ return createRuntimeObject(
2468
+ methods,
2469
+ resolved,
2470
+ pluginResult
2471
+ );
2472
+ }
2473
+
2474
+ // ../core/src/factory/create-polymorphic-full.ts
1708
2475
  var FULL_CAPABILITIES = {
1709
2476
  createClassPipeline,
1710
2477
  AriaEngine: AriaPolicyEngine,
@@ -1715,6 +2482,11 @@ function createPolymorphic2(options = {}) {
1715
2482
  return createPolymorphic(options, FULL_CAPABILITIES);
1716
2483
  }
1717
2484
 
2485
+ // ../../lib/adapter-utils/src/define-component.ts
2486
+ function defineContractComponent(options) {
2487
+ return (factory) => factory(options);
2488
+ }
2489
+
1718
2490
  // ../../lib/adapter-utils/src/build-core-runtime.ts
1719
2491
  var EMPTY_SET = /* @__PURE__ */ new Set();
1720
2492
  function buildCoreRuntime(normalized) {
@@ -1724,8 +2496,8 @@ function buildCoreRuntime(normalized) {
1724
2496
  }
1725
2497
 
1726
2498
  // ../../lib/adapter-utils/src/build-engines.ts
1727
- function buildEngines(strict, childRules, context) {
1728
- return childRules?.length ? { childrenEvaluator: new ChildrenEvaluator(childRules, strict, context) } : {};
2499
+ function buildEngines(diagnostics, childRules, context) {
2500
+ return childRules?.length ? { childrenEvaluator: new ChildrenEvaluator(childRules, diagnostics, context) } : {};
1729
2501
  }
1730
2502
 
1731
2503
  // ../../lib/adapter-utils/src/compose-filter.ts
@@ -1738,30 +2510,28 @@ function composeFilter(ownedKeys, filterProps) {
1738
2510
  }
1739
2511
 
1740
2512
  // ../../lib/adapter-utils/src/resolve-adapter-common-options.ts
1741
- function resolveAdapterCommonOptions(options, defaultName = "PolymorphicComponent", defaultStrict = "throw") {
2513
+ function resolveAdapterCommonOptions(options, defaultName = "PolymorphicComponent", defaultDiagnostics = throwDiagnostics) {
1742
2514
  return {
1743
2515
  name: options.name ?? defaultName,
1744
- strict: options.enforcement?.strict ?? defaultStrict
2516
+ diagnostics: options.enforcement?.diagnostics ?? defaultDiagnostics
1745
2517
  };
1746
2518
  }
1747
2519
 
1748
2520
  // ../../adapters/solid/src/slot/slot-validator.ts
1749
- var SlotValidator = class extends StrictBase {
2521
+ var SlotValidator = class extends InvariantBase {
1750
2522
  #name;
1751
- constructor(name, strict) {
1752
- super(strict);
2523
+ constructor(name, diagnostics) {
2524
+ super(diagnostics);
1753
2525
  this.#name = name;
1754
2526
  }
1755
2527
  assertExclusive() {
1756
- this.violate(`${this.#name}: "as" and "asChild" are mutually exclusive`);
2528
+ this.violate(SlotDiagnostics.exclusive(this.#name));
1757
2529
  }
1758
2530
  // Returns false (instead of throwing) when strict mode caps at warn, so callers can
1759
2531
  // fall through to a safe no-op render rather than calling an undefined render function.
1760
2532
  assertRenderFn(children) {
1761
2533
  if (typeof children !== "function") {
1762
- this.violate(
1763
- `${this.#name}: asChild requires a render function as children, got ${typeof children}`
1764
- );
2534
+ this.violate(SlotDiagnostics.renderFnRequired(this.#name, typeof children));
1765
2535
  return false;
1766
2536
  }
1767
2537
  return true;
@@ -1776,12 +2546,12 @@ function buildRuntime(options) {
1776
2546
  const normalized = normalizeOptions(options);
1777
2547
  const { runtime, ownedKeys } = buildCoreRuntime(normalized);
1778
2548
  const { childrenEvaluator } = buildEngines(
1779
- normalized.strict,
2549
+ normalized.diagnostics,
1780
2550
  normalized.enforcement?.children,
1781
2551
  normalized.name
1782
2552
  );
1783
2553
  const filterProps = composeFilter(ownedKeys, normalized.filterProps);
1784
- const slotValidator = new SlotValidator(normalized.name, normalized.strict);
2554
+ const slotValidator = new SlotValidator(normalized.name, normalized.diagnostics);
1785
2555
  return {
1786
2556
  runtime,
1787
2557
  filterProps,