praxis-kit 3.1.0 → 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,23 +1,18 @@
1
- // ../../adapters/preact/src/create-contract-component.ts
2
- import { forwardRef as forwardRef2 } from "preact/compat";
3
-
4
- // ../../adapters/preact/src/normalize-children.ts
5
- import { isValidElement } from "preact";
6
- function normalizeChildren(children) {
7
- if (isValidElement(children)) return [children];
8
- if (Array.isArray(children)) return children.filter(isValidElement);
9
- return [];
1
+ // ../../lib/adapter-utils/src/apply-display-name.ts
2
+ function applyDisplayName(component, name) {
3
+ Object.assign(component, { displayName: name ?? "PolymorphicComponent" });
10
4
  }
11
5
 
12
- // ../shared/src/guards/children/component-id.ts
13
- var COMPONENT_DEFAULT_TAG = /* @__PURE__ */ Symbol.for("praxis.component-default-tag");
14
-
15
6
  // ../../lib/primitive/src/utils/is-object.ts
16
- function isNull(value) {
17
- return value === null;
7
+ function isObject(value, excludeArrays = false) {
8
+ if (value === null || typeof value !== "object") return false;
9
+ return excludeArrays ? !Array.isArray(value) : true;
18
10
  }
19
- function isObject(value) {
20
- return !isNull(value) && typeof value === "object";
11
+ function isString(value) {
12
+ return typeof value === "string";
13
+ }
14
+ function isNumber(value) {
15
+ return typeof value === "number";
21
16
  }
22
17
 
23
18
  // ../../lib/primitive/src/merge/constants.ts
@@ -33,372 +28,198 @@ function isPlainObject(value) {
33
28
  return proto === Object.prototype || proto === null;
34
29
  }
35
30
 
36
- // ../../adapters/preact/src/apply-display-name.ts
37
- function applyDisplayName(component, name) {
38
- Object.assign(component, { displayName: name ?? "PolymorphicComponent" });
31
+ // ../../lib/primitive/src/utils/assert-never.ts
32
+ function assertNever(value) {
33
+ throw new Error(`Unexpected value: ${String(value)}`);
39
34
  }
40
35
 
41
- // ../../lib/adapter-utils/src/apply-filter.ts
42
- function applyFilter(props, filterProps, variantKeys) {
43
- const out = {};
44
- for (const k in props) {
45
- if (!Object.hasOwn(props, k)) continue;
46
- if (filterProps(k, variantKeys)) continue;
47
- out[k] = props[k];
36
+ // ../../lib/primitive/src/utils/iterate.ts
37
+ function find(iterable, callback) {
38
+ for (const value of iterable) {
39
+ const result = callback(value);
40
+ if (result != null) {
41
+ return result;
42
+ }
48
43
  }
49
- return out;
44
+ return null;
50
45
  }
51
-
52
- // ../../lib/adapter-utils/src/define-component.ts
53
- function defineContractComponent(options) {
54
- return (factory) => factory(options);
46
+ function some(iterable, predicate) {
47
+ for (const value of iterable) {
48
+ if (predicate(value)) return true;
49
+ }
50
+ return false;
55
51
  }
56
-
57
- // ../core/dist/chunk-KKSHJDE7.js
58
- function makeResolveTag(defaultTag) {
59
- return function tag(as) {
60
- return as ?? defaultTag;
61
- };
52
+ function every(iterable, predicate) {
53
+ let index = 0;
54
+ for (const value of iterable) {
55
+ if (!predicate(value, index++)) {
56
+ return false;
57
+ }
58
+ }
59
+ return true;
62
60
  }
63
- function assertNever(value) {
64
- throw new Error(`Unexpected value: ${String(value)}`);
61
+ function* filter(iterable, predicate) {
62
+ let index = 0;
63
+ for (const value of iterable) {
64
+ if (predicate(value, index++)) {
65
+ yield value;
66
+ }
67
+ }
65
68
  }
66
- function r(e) {
67
- var t, f, n = "";
68
- if ("string" == typeof e || "number" == typeof e) n += e;
69
- else if ("object" == typeof e) if (Array.isArray(e)) {
70
- var o = e.length;
71
- for (t = 0; t < o; t++) e[t] && (f = r(e[t])) && (n && (n += " "), n += f);
72
- } else for (f in e) e[f] && (n && (n += " "), n += f);
73
- return n;
69
+ function* map(iterable, callback) {
70
+ let index = 0;
71
+ for (const value of iterable) {
72
+ yield callback(value, index++);
73
+ }
74
74
  }
75
- function clsx() {
76
- for (var e, t, f = 0, n = "", o = arguments.length; f < o; f++) (e = arguments[f]) && (t = r(e)) && (n && (n += " "), n += t);
77
- return n;
75
+ function forEach(iterable, callback) {
76
+ let index = 0;
77
+ for (const value of iterable) {
78
+ callback(value, index++);
79
+ }
78
80
  }
79
- function cn(...inputs) {
80
- return clsx(...inputs);
81
+ function reduce(iterable, initial, callback) {
82
+ let accumulator = initial;
83
+ let index = 0;
84
+ for (const value of iterable) {
85
+ accumulator = callback(accumulator, value, index++);
86
+ }
87
+ return accumulator;
81
88
  }
82
- function mergeProps(defaultProps, props) {
83
- return {
84
- ...defaultProps ?? {},
85
- ...props
86
- };
89
+ function collect(iterable, callback) {
90
+ const result = {};
91
+ let index = 0;
92
+ for (const value of iterable) {
93
+ const entry = callback(value, index++);
94
+ if (entry === null) {
95
+ return null;
96
+ }
97
+ result[entry[0]] = entry[1];
98
+ }
99
+ return result;
87
100
  }
88
- function isNull2(value) {
89
- return value === null;
101
+ function findLast(value, callback) {
102
+ for (let index = value.length - 1; index >= 0; index--) {
103
+ const result = callback(value[index], index);
104
+ if (result != null) {
105
+ return result;
106
+ }
107
+ }
108
+ return null;
109
+ }
110
+ function* items(collection) {
111
+ for (let i = 0; i < collection.length; i++) {
112
+ const item = collection.item(i);
113
+ if (item !== null) {
114
+ yield item;
115
+ }
116
+ }
90
117
  }
91
- function isObject2(value) {
92
- return !isNull2(value) && typeof value === "object";
118
+ function nodeList(list) {
119
+ return {
120
+ *[Symbol.iterator]() {
121
+ for (let i = 0; i < list.length; i++) {
122
+ const node = list.item(i);
123
+ if (node !== null) {
124
+ yield node;
125
+ }
126
+ }
127
+ }
128
+ };
93
129
  }
94
- function isString(value) {
95
- return typeof value === "string";
130
+ function mapEntries(m) {
131
+ return m.entries();
96
132
  }
97
- function isNumber(value) {
98
- return typeof value === "number";
133
+ function set(s) {
134
+ return s.values();
99
135
  }
100
- var EMPTY_VARIANT_KEYS = /* @__PURE__ */ new Set();
101
- function composeNormalizers(normalizers, fn) {
102
- if (!normalizers?.length) return fn;
103
- return ((props) => {
104
- const patched = normalizers.reduce(
105
- (acc, normalizer) => ({ ...acc, ...normalizer(acc) }),
106
- props
107
- );
108
- return fn ? fn(patched) : patched;
109
- });
136
+ function hasOwn(object, key) {
137
+ return Object.hasOwn(object, key);
110
138
  }
111
- function whenDefined(key, value) {
112
- return value === void 0 ? {} : { [key]: value };
113
- }
114
- function resolveFactoryOptions(options = {}) {
115
- const { styling, enforcement } = options;
116
- const composedNormalizeFn = composeNormalizers(enforcement?.props, options.normalize);
117
- const variantKeys = styling?.variants === void 0 ? EMPTY_VARIANT_KEYS : new Set(Object.keys(styling.variants));
118
- return Object.freeze({
119
- defaultTag: options.tag ?? "div",
120
- strict: enforcement?.strict ?? false,
121
- variantKeys,
122
- ...whenDefined("displayName", options.name),
123
- ...whenDefined("defaultProps", options.defaults),
124
- ...whenDefined("baseClassName", styling?.base),
125
- ...whenDefined("tagMap", styling?.tags),
126
- ...whenDefined("recipeMap", styling?.presets),
127
- ...whenDefined("variants", styling?.variants),
128
- ...whenDefined("defaultVariants", styling?.defaults),
129
- ...whenDefined("compoundVariants", styling?.compounds),
130
- ...whenDefined("normalizeFn", composedNormalizeFn),
131
- ...whenDefined("ariaRules", enforcement?.aria),
132
- ...whenDefined("childRules", enforcement?.children),
133
- ...whenDefined("allowedAs", enforcement?.allowedAs),
134
- ...whenDefined("precomputedClasses", styling?.precomputedClasses)
135
- });
139
+ function* entries(object) {
140
+ for (const key in object) {
141
+ if (!hasOwn(object, key)) continue;
142
+ yield [key, object[key]];
143
+ }
136
144
  }
137
- function report(strict, message) {
138
- if (strict === false) return;
139
- const mode = strict === true ? "throw" : strict;
140
- if (mode === "throw") throw new Error(message);
141
- console.warn(message);
142
- }
143
- function validateFactoryOptions(resolved) {
144
- const { strict } = resolved;
145
- if (strict === false) return;
146
- const name = resolved.displayName ?? "Component";
147
- const { variants } = resolved;
148
- const checkSelection = (label2, selection) => {
149
- const record = selection;
150
- for (const dim in record) {
151
- const value = record[dim];
152
- if (value === void 0 || value === null) continue;
153
- if (!variants || !Object.hasOwn(variants, dim)) {
154
- report(strict, `${name}: ${label2} references unknown variant "${dim}".`);
155
- continue;
156
- }
157
- const states = variants[dim];
158
- const stateKey = String(value);
159
- if (!Object.hasOwn(states, stateKey)) {
160
- report(
161
- strict,
162
- `${name}: ${label2} sets "${dim}" to unknown value "${stateKey}" (valid: ${Object.keys(states).join(", ")}).`
163
- );
164
- }
165
- }
166
- };
167
- const { recipeMap } = resolved;
168
- if (recipeMap) {
169
- for (const recipeKey in recipeMap) {
170
- checkSelection(`preset "${recipeKey}"`, recipeMap[recipeKey]);
171
- }
145
+ function* keys(object) {
146
+ for (const [key] of entries(object)) {
147
+ yield key;
172
148
  }
173
- if (resolved.defaultVariants) checkSelection("defaults", resolved.defaultVariants);
174
- }
175
- var warned = /* @__PURE__ */ new Set();
176
- var pendingAsyncWarns = /* @__PURE__ */ new Set();
177
- var asyncWarnScheduled = false;
178
- function flushAsyncWarns() {
179
- asyncWarnScheduled = false;
180
- const messages = [...pendingAsyncWarns];
181
- pendingAsyncWarns.clear();
182
- for (const msg of messages) {
183
- console.warn(msg);
184
- }
185
- }
186
- function report2(strict, message) {
187
- if (!strict) return;
188
- const mode = strict === true ? "throw" : strict;
189
- if (mode === "throw") throw new Error(message);
190
- if (mode === "async-warn") {
191
- if (pendingAsyncWarns.has(message)) return;
192
- pendingAsyncWarns.add(message);
193
- if (!asyncWarnScheduled) {
194
- asyncWarnScheduled = true;
195
- queueMicrotask(flushAsyncWarns);
196
- }
197
- return;
198
- }
199
- if (warned.has(message)) return;
200
- warned.add(message);
201
- console.warn(message);
202
- }
203
- function label(name) {
204
- return name ? `[${name}]` : "[createContractComponent]";
205
- }
206
- function validateRenderProps(options, props, recipeKey) {
207
- const { strict, recipeMap, variants, displayName } = options;
208
- if (!strict) return;
209
- const tag = label(displayName);
210
- if (recipeKey !== void 0 && (!recipeMap || !Object.hasOwn(recipeMap, recipeKey))) {
211
- report2(strict, `${tag} Unknown recipeKey "${recipeKey}" \u2014 no preset with that name exists.`);
212
- }
213
- if (variants) {
214
- for (const key in variants) {
215
- if (!Object.hasOwn(props, key)) continue;
216
- const value = props[key];
217
- if (value === void 0 || value === null) continue;
218
- const dim = variants[key];
219
- if (dim && !Object.hasOwn(dim, String(value))) {
220
- report2(
221
- strict,
222
- `${tag} Variant "${key}=${String(value)}" is not a defined value for the "${key}" dimension.`
223
- );
224
- }
225
- }
149
+ }
150
+ function* values(object) {
151
+ for (const [, value] of entries(object)) {
152
+ yield value;
226
153
  }
227
154
  }
228
- function panic(message) {
229
- throw new Error(message);
155
+ function mapValues(object, callback) {
156
+ const result = {};
157
+ for (const [key, value] of entries(object)) {
158
+ result[key] = callback(value, key);
159
+ }
160
+ return result;
230
161
  }
231
- function describe(value) {
232
- if (value === null) return "null";
233
- if (Array.isArray(value)) return "array";
234
- return typeof value;
162
+ function forEachEntry(object, callback) {
163
+ for (const [key, value] of entries(object)) {
164
+ callback(key, value);
165
+ }
235
166
  }
236
- function assertPluginShape(result) {
237
- if (result === null || typeof result !== "object")
238
- panic(
239
- `[praxis-kit] Plugin factory must return an object with a 'pipeline' function. Got: ${result === null ? "null" : typeof result}.`
240
- );
241
- const plugin = result;
242
- if (typeof plugin.pipeline !== "function")
243
- panic(
244
- `[praxis-kit] Plugin factory return value is missing a 'pipeline' function. Got pipeline: ${typeof plugin.pipeline}.`
245
- );
167
+ function forEachKey(object, callback) {
168
+ for (const key of keys(object)) {
169
+ callback(key);
170
+ }
246
171
  }
247
- function guardPipeline(pipeline) {
248
- if (process.env.NODE_ENV === "production") return pipeline;
249
- return function guardedPipeline(tag, props, className, recipe) {
250
- const result = pipeline(tag, props, className, recipe);
251
- if (typeof result !== "string")
252
- panic(`[praxis-kit] Plugin pipeline must return a string. Got: ${describe(result)}.`);
253
- return result;
254
- };
172
+ function forEachValue(object, callback) {
173
+ for (const value of values(object)) {
174
+ callback(value);
175
+ }
255
176
  }
256
- var NOOP_CLASS_PIPELINE = (_tag, _props, className) => Array.isArray(className) ? className.join(" ") : className ?? "";
257
- function resolveClassPipeline(options, resolved, strict, capabilities) {
258
- const factory = options.styling?.plugin;
259
- if (!factory) {
260
- const createClassPipeline2 = capabilities?.createClassPipeline;
261
- const classPipeline2 = createClassPipeline2 ? createClassPipeline2(resolved) : NOOP_CLASS_PIPELINE;
262
- return { pluginResult: void 0, classPipeline: classPipeline2 };
177
+ function forEachSet(s, callback) {
178
+ for (const value of s) {
179
+ callback(value);
263
180
  }
264
- const pluginResult = factory(resolved, strict);
265
- assertPluginShape(pluginResult);
266
- const classPipeline = guardPipeline(pluginResult.pipeline);
267
- return { pluginResult, classPipeline };
268
181
  }
269
- function createRuntimeMethods(resolved, classPipeline, engine) {
270
- return {
271
- resolveTag: makeResolveTag(resolved.defaultTag),
272
- resolveProps(props) {
273
- return mergeProps(resolved.defaultProps, props);
274
- },
275
- resolveClasses(tag, props, className, recipe) {
276
- if (process.env.NODE_ENV !== "production") {
277
- validateRenderProps(resolved, props, recipe);
182
+ var iterate = Object.freeze({
183
+ entries,
184
+ filter,
185
+ find,
186
+ findLast,
187
+ forEach,
188
+ forEachEntry,
189
+ forEachKey,
190
+ forEachSet,
191
+ forEachValue,
192
+ items,
193
+ keys,
194
+ map,
195
+ mapEntries,
196
+ mapValues,
197
+ nodeList,
198
+ reduce,
199
+ collect,
200
+ set,
201
+ some,
202
+ every,
203
+ values
204
+ });
205
+
206
+ // ../../lib/primitive/src/utils/merge-refs.ts
207
+ function mergeRefsCore(...refs) {
208
+ const active = refs.filter((r) => r != null);
209
+ if (active.length === 0) return null;
210
+ if (active.length === 1) return active[0];
211
+ return (value) => {
212
+ iterate.forEach(active, (ref) => {
213
+ if (typeof ref === "function") {
214
+ ref(value);
215
+ } else {
216
+ ref.current = value;
278
217
  }
279
- return classPipeline(tag, props, className, recipe);
280
- },
281
- resolveAria(tag, props) {
282
- if (!engine) return { props };
283
- const result = engine.validate(tag, props);
284
- return { props: result.props };
285
- }
218
+ });
286
219
  };
287
220
  }
288
- function createRuntimeObject(methods, resolved, pluginResult) {
289
- return pluginResult ? { ...methods, options: resolved, hasStyling: true, classPlugin: pluginResult } : { ...methods, options: resolved };
290
- }
291
- function createPolymorphic(options = {}, capabilities) {
292
- const baseResolved = resolveFactoryOptions(options);
293
- const resolved = capabilities?.htmlPropNormalizersFn !== void 0 ? Object.freeze({
294
- ...baseResolved,
295
- htmlPropNormalizersFn: capabilities.htmlPropNormalizersFn
296
- }) : baseResolved;
297
- if (process.env.NODE_ENV !== "production") validateFactoryOptions(resolved);
298
- const { pluginResult, classPipeline } = resolveClassPipeline(
299
- options,
300
- resolved,
301
- resolved.strict,
302
- capabilities
303
- );
304
- const allAriaRules = [
305
- .../* @__PURE__ */ new Set([...capabilities?.htmlAriaRules ?? [], ...resolved.ariaRules ?? []])
306
- ];
307
- const engine = options.enforcement !== void 0 && capabilities?.AriaEngine ? new capabilities.AriaEngine(
308
- resolved.strict,
309
- allAriaRules.length ? { rules: allAriaRules } : void 0
310
- ) : null;
311
- const methods = createRuntimeMethods(resolved, classPipeline, engine);
312
- return createRuntimeObject(
313
- methods,
314
- resolved,
315
- pluginResult
316
- );
317
- }
318
- var KNOWN_ARIA_ROLES = [
319
- "alert",
320
- "alertdialog",
321
- "application",
322
- "article",
323
- "banner",
324
- "blockquote",
325
- "button",
326
- "caption",
327
- "cell",
328
- "checkbox",
329
- "code",
330
- "columnheader",
331
- "combobox",
332
- "complementary",
333
- "contentinfo",
334
- "definition",
335
- "deletion",
336
- "dialog",
337
- "document",
338
- "emphasis",
339
- "feed",
340
- "figure",
341
- "form",
342
- "generic",
343
- "grid",
344
- "gridcell",
345
- "group",
346
- "heading",
347
- "img",
348
- "insertion",
349
- "link",
350
- "list",
351
- "listbox",
352
- "listitem",
353
- "log",
354
- "main",
355
- "marquee",
356
- "math",
357
- "menu",
358
- "menubar",
359
- "menuitem",
360
- "menuitemcheckbox",
361
- "menuitemradio",
362
- "meter",
363
- "navigation",
364
- "none",
365
- "note",
366
- "option",
367
- "paragraph",
368
- "presentation",
369
- "progressbar",
370
- "radio",
371
- "radiogroup",
372
- "region",
373
- "row",
374
- "rowgroup",
375
- "rowheader",
376
- "scrollbar",
377
- "search",
378
- "searchbox",
379
- "separator",
380
- "slider",
381
- "spinbutton",
382
- "status",
383
- "strong",
384
- "subscript",
385
- "superscript",
386
- "switch",
387
- "tab",
388
- "table",
389
- "tablist",
390
- "tabpanel",
391
- "term",
392
- "textbox",
393
- "time",
394
- "timer",
395
- "toolbar",
396
- "tooltip",
397
- "tree",
398
- "treegrid",
399
- "treeitem"
400
- ];
401
- var KNOWN_ARIA_ROLES_SET = new Set(KNOWN_ARIA_ROLES);
221
+
222
+ // ../../lib/primitive/src/constants/aria/global-aria-attributes.ts
402
223
  var GLOBAL_ARIA_ATTRIBUTES = /* @__PURE__ */ new Set([
403
224
  "aria-atomic",
404
225
  "aria-busy",
@@ -418,29 +239,59 @@ var GLOBAL_ARIA_ATTRIBUTES = /* @__PURE__ */ new Set([
418
239
  "aria-relevant",
419
240
  "aria-roledescription"
420
241
  ]);
242
+
243
+ // ../../lib/primitive/src/constants/aria/implicit-role-record.ts
421
244
  var IMPLICIT_ROLE_RECORD = {
245
+ // Landmarks
422
246
  article: "article",
423
247
  aside: "complementary",
424
248
  footer: "contentinfo",
425
249
  header: "banner",
426
250
  main: "main",
427
251
  nav: "navigation",
428
- button: "button",
252
+ // Interactive
429
253
  a: "link",
254
+ button: "button",
430
255
  select: "listbox",
256
+ textarea: "textbox",
257
+ // Headings
431
258
  h1: "heading",
432
259
  h2: "heading",
433
260
  h3: "heading",
434
261
  h4: "heading",
435
262
  h5: "heading",
436
263
  h6: "heading",
264
+ // Lists
437
265
  ul: "list",
438
266
  ol: "list",
439
267
  li: "listitem",
268
+ // Tables
440
269
  table: "table",
441
270
  tr: "row",
442
271
  td: "cell",
443
- th: "columnheader"
272
+ th: "columnheader",
273
+ // Structural / semantic
274
+ dialog: "dialog",
275
+ fieldset: "group",
276
+ figure: "figure",
277
+ meter: "meter",
278
+ output: "status",
279
+ progress: "progressbar"
280
+ };
281
+ var INPUT_TYPE_ROLE_MAP = {
282
+ checkbox: "checkbox",
283
+ radio: "radio",
284
+ range: "slider",
285
+ number: "spinbutton",
286
+ search: "searchbox",
287
+ text: "textbox",
288
+ email: "textbox",
289
+ tel: "textbox",
290
+ url: "textbox",
291
+ button: "button",
292
+ submit: "button",
293
+ reset: "button",
294
+ image: "button"
444
295
  };
445
296
  var STRONG_ROLES = [
446
297
  "main",
@@ -452,6 +303,8 @@ var STRONG_ROLES = [
452
303
  var STANDALONE_ROLES = ["article"];
453
304
  var STRONG_ROLES_SET = new Set(STRONG_ROLES);
454
305
  var STANDALONE_ROLES_SET = new Set(STANDALONE_ROLES);
306
+
307
+ // ../../lib/primitive/src/constants/aria/role-restricted-attributes.ts
455
308
  var ROLE_RESTRICTED_ATTRIBUTES = /* @__PURE__ */ new Map([
456
309
  [
457
310
  "aria-activedescendant",
@@ -601,9 +454,18 @@ var ROLE_RESTRICTED_ATTRIBUTES = /* @__PURE__ */ new Map([
601
454
  /* @__PURE__ */ new Set(["meter", "progressbar", "scrollbar", "separator", "slider", "spinbutton"])
602
455
  ]
603
456
  ]);
457
+
458
+ // ../../lib/primitive/src/guards/foundational/is-defined.ts
604
459
  function isUndefined(value) {
605
460
  return value === void 0;
606
461
  }
462
+
463
+ // ../../lib/primitive/src/guards/foundational/is-null.ts
464
+ function isNull(value) {
465
+ return value === null;
466
+ }
467
+
468
+ // ../../lib/primitive/src/guards/aria/is-aria-attribute.ts
607
469
  function isGlobalAriaAttribute(attr) {
608
470
  return GLOBAL_ARIA_ATTRIBUTES.has(attr);
609
471
  }
@@ -613,6 +475,8 @@ function isAriaAttributeValidForRole(attr, role) {
613
475
  if (isUndefined(role)) return false;
614
476
  return allowedRoles.has(role);
615
477
  }
478
+
479
+ // ../../lib/primitive/src/guards/aria/is-aria-role.ts
616
480
  function isStrongImplicitRole(tag) {
617
481
  if (!(tag in IMPLICIT_ROLE_RECORD)) return false;
618
482
  return STRONG_ROLES_SET.has(IMPLICIT_ROLE_RECORD[tag]);
@@ -621,53 +485,35 @@ function isStandaloneTag(tag) {
621
485
  if (!(tag in IMPLICIT_ROLE_RECORD)) return false;
622
486
  return STANDALONE_ROLES_SET.has(IMPLICIT_ROLE_RECORD[tag]);
623
487
  }
624
- function isKnownAriaRole(value) {
625
- return isString(value) && KNOWN_ARIA_ROLES_SET.has(value);
488
+ function getInputImplicitRole(type) {
489
+ if (type == null || !(type in INPUT_TYPE_ROLE_MAP)) return void 0;
490
+ return INPUT_TYPE_ROLE_MAP[type];
626
491
  }
627
-
628
- // ../core/dist/chunk-2NJ5XLOA.js
629
- var IMPLICIT_ROLE_RECORD2 = {
630
- article: "article",
631
- aside: "complementary",
632
- footer: "contentinfo",
633
- header: "banner",
634
- main: "main",
635
- nav: "navigation",
636
- button: "button",
637
- a: "link",
638
- select: "listbox",
639
- h1: "heading",
640
- h2: "heading",
641
- h3: "heading",
642
- h4: "heading",
643
- h5: "heading",
644
- h6: "heading",
645
- ul: "list",
646
- ol: "list",
647
- li: "listitem",
648
- table: "table",
649
- tr: "row",
650
- td: "cell",
651
- th: "columnheader"
652
- };
653
- function getImplicitRole(tag) {
654
- if (tag in IMPLICIT_ROLE_RECORD2) return IMPLICIT_ROLE_RECORD2[tag];
492
+ function getConditionalImplicitRole(tag, ariaLabel, ariaLabelledBy) {
493
+ const isNamed = typeof ariaLabel === "string" || typeof ariaLabelledBy === "string";
494
+ if (!isNamed) return void 0;
495
+ if (tag === "section") return "region";
496
+ if (tag === "form") return "form";
655
497
  return void 0;
656
498
  }
657
- var COMPONENT_DEFAULT_TAG2 = /* @__PURE__ */ Symbol.for("praxis.component-default-tag");
499
+
500
+ // ../../lib/primitive/src/guards/children/component-id.ts
501
+ var COMPONENT_DEFAULT_TAG = /* @__PURE__ */ Symbol.for("praxis.component-default-tag");
502
+
503
+ // ../../lib/primitive/src/guards/children/is-tag.ts
658
504
  function getAsProp(child) {
659
- if (!isObject2(child) || !("props" in child)) return void 0;
505
+ if (!isObject(child) || !("props" in child)) return void 0;
660
506
  const props = child.props;
661
- if (!isObject2(props)) return void 0;
507
+ if (!isObject(props)) return void 0;
662
508
  const as = props.as;
663
509
  return isString(as) && as !== "" ? as : void 0;
664
510
  }
665
511
  function getTag(child) {
666
- if (!isObject2(child) || !("type" in child)) return void 0;
512
+ if (!isObject(child) || !("type" in child)) return void 0;
667
513
  const t = child.type;
668
514
  if (isString(t)) return t;
669
- if (typeof t === "function" || isObject2(t)) {
670
- const defaultTag = t[COMPONENT_DEFAULT_TAG2];
515
+ if (typeof t === "function" || isObject(t)) {
516
+ const defaultTag = t[COMPONENT_DEFAULT_TAG];
671
517
  if (!isString(defaultTag)) return void 0;
672
518
  return getAsProp(child) ?? defaultTag;
673
519
  }
@@ -675,65 +521,543 @@ function getTag(child) {
675
521
  }
676
522
  function isTag(...args) {
677
523
  if (isString(args[0])) {
678
- const set2 = new Set(args);
524
+ const set3 = new Set(args);
679
525
  return (child2) => {
680
526
  const tag2 = getTag(child2);
681
- return tag2 !== void 0 && set2.has(tag2);
527
+ return tag2 !== void 0 && set3.has(tag2);
682
528
  };
683
529
  }
684
530
  const [child, ...tags] = args;
685
- const set = new Set(tags);
531
+ const set2 = new Set(tags);
686
532
  const tag = getTag(child);
687
- return tag !== void 0 && set.has(tag);
688
- }
689
- var pendingAsyncWarns2 = /* @__PURE__ */ new Set();
690
- var asyncWarnScheduled2 = false;
691
- function flushAsyncWarns2() {
692
- asyncWarnScheduled2 = false;
693
- const messages = [...pendingAsyncWarns2];
694
- pendingAsyncWarns2.clear();
695
- for (const msg of messages) {
696
- console.warn(msg);
697
- }
698
- }
699
- function scheduleAsyncWarn(message) {
700
- if (pendingAsyncWarns2.has(message)) return;
701
- pendingAsyncWarns2.add(message);
702
- if (!asyncWarnScheduled2) {
703
- asyncWarnScheduled2 = true;
704
- queueMicrotask(flushAsyncWarns2);
705
- }
706
- }
707
- var StrictBase = class {
708
- strict;
709
- constructor(strict) {
710
- this.strict = strict;
711
- }
712
- violate(message) {
713
- if (this.strict === true || this.strict === "throw") {
714
- throw new Error(message);
715
- }
716
- this.warn(message);
533
+ return tag !== void 0 && set2.has(tag);
534
+ }
535
+
536
+ // ../../lib/contract/src/aria/aria-role-policy.ts
537
+ function getImplicitRole(tag, props) {
538
+ if (tag in IMPLICIT_ROLE_RECORD) return IMPLICIT_ROLE_RECORD[tag];
539
+ if (tag === "input") return getInputImplicitRole(props?.type);
540
+ if (tag === "img") return props?.alt === "" ? "none" : "img";
541
+ if (tag === "section" || tag === "form") {
542
+ return getConditionalImplicitRole(tag, props?.["aria-label"], props?.["aria-labelledby"]);
543
+ }
544
+ return void 0;
545
+ }
546
+
547
+ // ../../lib/contract/src/strict/invariant-base.ts
548
+ var InvariantBase = class {
549
+ diagnostics;
550
+ constructor(diagnostics) {
551
+ this.diagnostics = diagnostics;
717
552
  }
718
- // Always caps at console.warn — never throws. ARIA 'warning' violations route here
553
+ get active() {
554
+ return this.diagnostics.active;
555
+ }
556
+ violate(input) {
557
+ this.diagnostics.error(input);
558
+ }
559
+ // Always caps at warn — never throws. ARIA 'warning' violations route here
719
560
  // so they surface even in strict='throw' mode without aborting a render.
720
- warn(message) {
721
- if (!this.strict) return;
722
- if (this.strict === "async-warn") {
723
- scheduleAsyncWarn(message);
724
- return;
725
- }
726
- console.warn(message);
561
+ warn(input) {
562
+ this.diagnostics.warn(input);
727
563
  }
728
- invariant(condition, message) {
729
- if (!condition) {
730
- this.violate(message);
731
- }
564
+ invariant(condition, input) {
565
+ if (!condition) this.violate(input);
732
566
  }
733
567
  };
734
- function isNull3(value) {
735
- return value === null;
568
+
569
+ // ../../lib/diagnostics/src/category.ts
570
+ var DiagnosticCategory = /* @__PURE__ */ ((DiagnosticCategory2) => {
571
+ DiagnosticCategory2[DiagnosticCategory2["Contract"] = 0] = "Contract";
572
+ DiagnosticCategory2[DiagnosticCategory2["HTML"] = 1] = "HTML";
573
+ DiagnosticCategory2[DiagnosticCategory2["ARIA"] = 2] = "ARIA";
574
+ DiagnosticCategory2[DiagnosticCategory2["Composition"] = 3] = "Composition";
575
+ DiagnosticCategory2[DiagnosticCategory2["Rendering"] = 4] = "Rendering";
576
+ DiagnosticCategory2[DiagnosticCategory2["Accessibility"] = 5] = "Accessibility";
577
+ DiagnosticCategory2[DiagnosticCategory2["Performance"] = 6] = "Performance";
578
+ DiagnosticCategory2[DiagnosticCategory2["Internal"] = 7] = "Internal";
579
+ DiagnosticCategory2[DiagnosticCategory2["Deprecation"] = 8] = "Deprecation";
580
+ DiagnosticCategory2[DiagnosticCategory2["Lint"] = 9] = "Lint";
581
+ return DiagnosticCategory2;
582
+ })(DiagnosticCategory || {});
583
+
584
+ // ../../lib/diagnostics/src/error.ts
585
+ var PraxisError = class extends Error {
586
+ diagnostic;
587
+ constructor(diagnostic) {
588
+ super(diagnostic.message);
589
+ this.name = "PraxisError";
590
+ this.diagnostic = diagnostic;
591
+ }
592
+ };
593
+
594
+ // ../../lib/diagnostics/src/severity.ts
595
+ var Severity = /* @__PURE__ */ ((Severity2) => {
596
+ Severity2[Severity2["Debug"] = 0] = "Debug";
597
+ Severity2[Severity2["Info"] = 1] = "Info";
598
+ Severity2[Severity2["Warning"] = 2] = "Warning";
599
+ Severity2[Severity2["Error"] = 3] = "Error";
600
+ Severity2[Severity2["Fatal"] = 4] = "Fatal";
601
+ return Severity2;
602
+ })(Severity || {});
603
+
604
+ // ../../lib/diagnostics/src/policy.ts
605
+ var DefaultPolicy = class {
606
+ reportThreshold;
607
+ throwThreshold;
608
+ constructor({
609
+ reportThreshold = 1 /* Info */,
610
+ throwThreshold = 4 /* Fatal */
611
+ } = {}) {
612
+ this.reportThreshold = reportThreshold;
613
+ this.throwThreshold = throwThreshold;
614
+ }
615
+ resolve(diagnostic) {
616
+ if (diagnostic.severity >= this.throwThreshold) return 2 /* Throw */;
617
+ if (diagnostic.severity >= this.reportThreshold) return 1 /* Report */;
618
+ return 0 /* Ignore */;
619
+ }
620
+ };
621
+
622
+ // ../../lib/diagnostics/src/diagnostics.ts
623
+ var Diagnostics = class {
624
+ reporter;
625
+ policy;
626
+ // Pre-computed at construction time: true if Warning-level diagnostics are not ignored.
627
+ active;
628
+ constructor(reporter, policy = new DefaultPolicy()) {
629
+ this.reporter = reporter;
630
+ this.policy = policy;
631
+ this.active = policy.resolve({ severity: 2 /* Warning */ }) !== 0 /* Ignore */;
632
+ }
633
+ report(diagnostic) {
634
+ const enforcement = this.policy.resolve(diagnostic);
635
+ if (enforcement === 0 /* Ignore */) return diagnostic;
636
+ if (enforcement === 2 /* Throw */) throw new PraxisError(diagnostic);
637
+ this.reporter.report(diagnostic);
638
+ return diagnostic;
639
+ }
640
+ warn(input) {
641
+ return this.report({ ...input, severity: 2 /* Warning */ });
642
+ }
643
+ error(input) {
644
+ return this.report({ ...input, severity: 3 /* Error */ });
645
+ }
646
+ info(input) {
647
+ return this.report({ ...input, severity: 1 /* Info */ });
648
+ }
649
+ };
650
+
651
+ // ../../lib/diagnostics/src/formatter.ts
652
+ function formatDiagnostic(diagnostic) {
653
+ const level = Severity[diagnostic.severity];
654
+ const category = DiagnosticCategory[diagnostic.category];
655
+ const prefix = category !== void 0 ? `[${category}] ` : "";
656
+ return `${level} ${diagnostic.code}: ${prefix}${diagnostic.message}`;
736
657
  }
658
+
659
+ // ../../lib/diagnostics/src/console-reporter.ts
660
+ var ConsoleReporter = class {
661
+ report(diagnostic) {
662
+ const message = formatDiagnostic(diagnostic);
663
+ switch (diagnostic.severity) {
664
+ case 0 /* Debug */:
665
+ console.debug(message);
666
+ break;
667
+ case 1 /* Info */:
668
+ console.info(message);
669
+ break;
670
+ case 2 /* Warning */:
671
+ console.warn(message);
672
+ break;
673
+ case 3 /* Error */:
674
+ case 4 /* Fatal */:
675
+ console.error(message);
676
+ break;
677
+ }
678
+ }
679
+ };
680
+
681
+ // ../../lib/diagnostics/src/null-reporter.ts
682
+ var nullReporter = {
683
+ report() {
684
+ }
685
+ };
686
+
687
+ // ../../lib/diagnostics/src/presets.ts
688
+ var ignoreAllPolicy = {
689
+ resolve(_) {
690
+ return 0 /* Ignore */;
691
+ }
692
+ };
693
+ var warnOnlyReporter = {
694
+ report(diagnostic) {
695
+ console.warn(formatDiagnostic(diagnostic));
696
+ }
697
+ };
698
+ var silentDiagnostics = new Diagnostics(nullReporter, ignoreAllPolicy);
699
+ var warnDiagnostics = new Diagnostics(
700
+ warnOnlyReporter,
701
+ new DefaultPolicy({ reportThreshold: 2 /* Warning */, throwThreshold: 4 /* Fatal */ })
702
+ );
703
+ var throwDiagnostics = new Diagnostics(
704
+ new ConsoleReporter(),
705
+ new DefaultPolicy({ reportThreshold: 2 /* Warning */, throwThreshold: 3 /* Error */ })
706
+ );
707
+
708
+ // ../../lib/contract/src/diagnostics/aria.ts
709
+ var AriaDiagnostics = {
710
+ /** Generic bridge for violations produced by external AriaRule functions. */
711
+ fromViolation(v) {
712
+ return {
713
+ code: "ARIA2002" /* AriaViolation */,
714
+ category: 2 /* ARIA */,
715
+ message: v.message
716
+ };
717
+ },
718
+ attributeInvalid(key, role) {
719
+ return {
720
+ code: "ARIA2003" /* AriaAttributeInvalid */,
721
+ category: 2 /* ARIA */,
722
+ message: `"${key}" is not valid on role="${role}". It will be removed.`,
723
+ rationale: "Invalid ARIA attributes are ignored by assistive technology and may trigger accessibility-tree warnings in browser devtools.",
724
+ suggestions: [
725
+ {
726
+ title: "Remove the attribute",
727
+ description: `"${key}" is not in the allowed attribute set for role="${role}".`
728
+ }
729
+ ]
730
+ };
731
+ },
732
+ missingLiveRegion(role, impliedLive) {
733
+ return {
734
+ code: "ARIA2004" /* AriaMissingLiveRegion */,
735
+ category: 2 /* ARIA */,
736
+ message: `role="${role}" implies aria-live="${impliedLive}" but it is missing. It has been injected.`,
737
+ rationale: "Live-region roles announce dynamic content changes to screen readers. Without aria-live the politeness level is unspecified and announcements may be silent.",
738
+ suggestions: [
739
+ {
740
+ title: `Add aria-live="${impliedLive}"`,
741
+ description: `role="${role}" conventionally implies aria-live="${impliedLive}".`,
742
+ fix: `aria-live="${impliedLive}"`
743
+ }
744
+ ]
745
+ };
746
+ },
747
+ missingAtomic(role) {
748
+ return {
749
+ code: "ARIA2005" /* AriaMissingAtomic */,
750
+ category: 2 /* ARIA */,
751
+ 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.`,
752
+ rationale: "aria-atomic controls whether assistive technology announces the entire live region or only the changed nodes. Omitting it leaves the behaviour browser-defined."
753
+ };
754
+ },
755
+ relevantInvalidTokens(invalid) {
756
+ const quoted = invalid.map((t) => `"${t}"`).join(", ");
757
+ return {
758
+ code: "ARIA2006" /* AriaRelevantInvalidToken */,
759
+ category: 2 /* ARIA */,
760
+ message: `aria-relevant contains invalid token(s): ${quoted}. Valid tokens are: additions, removals, text, all.`,
761
+ rationale: "aria-relevant accepts a space-separated list of change types. Unrecognised tokens are silently ignored by assistive technology, making the attribute ineffective.",
762
+ suggestions: [
763
+ {
764
+ title: "Use only valid tokens",
765
+ description: "Valid values are: additions, removals, text, all (or a space-separated combination)."
766
+ }
767
+ ]
768
+ };
769
+ },
770
+ relevantSuperseded() {
771
+ return {
772
+ code: "ARIA2007" /* AriaRelevantSuperseded */,
773
+ category: 2 /* ARIA */,
774
+ message: 'aria-relevant includes "all" alongside other tokens. "all" supersedes additions, removals, and text \u2014 use aria-relevant="all" alone.',
775
+ rationale: '"all" is equivalent to "additions removals text". Combining it with other tokens is redundant and may confuse readers of the markup.',
776
+ suggestions: [
777
+ {
778
+ title: 'Use aria-relevant="all"',
779
+ fix: 'aria-relevant="all"'
780
+ }
781
+ ]
782
+ };
783
+ },
784
+ missingAccessibleName(tag) {
785
+ return {
786
+ code: "ARIA2009" /* AriaMissingAccessibleName */,
787
+ category: 2 /* ARIA */,
788
+ message: `<${tag}> has no accessible name. Add aria-label or aria-labelledby.`,
789
+ 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.",
790
+ suggestions: [
791
+ {
792
+ title: "Add aria-label",
793
+ description: `Add aria-label="\u2026" directly to the <${tag}> element.`
794
+ },
795
+ {
796
+ title: "Add aria-labelledby",
797
+ description: "Point aria-labelledby at the id of an existing heading or label element."
798
+ }
799
+ ]
800
+ };
801
+ },
802
+ attributeOnPresentational(attr, tag) {
803
+ return {
804
+ code: "ARIA2010" /* AriaAttributeOnPresentational */,
805
+ category: 2 /* ARIA */,
806
+ message: `"${attr}" is not allowed on a presentational <${tag}>. Presentational elements are invisible to assistive technology.`,
807
+ 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.',
808
+ suggestions: [
809
+ {
810
+ title: "Remove the attribute",
811
+ description: `"${attr}" has no effect when the element has role="none" or role="presentation".`
812
+ }
813
+ ]
814
+ };
815
+ },
816
+ ariaHiddenOnFocusable(tag) {
817
+ return {
818
+ code: "ARIA2011" /* AriaHiddenOnFocusable */,
819
+ category: 2 /* ARIA */,
820
+ 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.`,
821
+ 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.',
822
+ suggestions: [
823
+ {
824
+ title: "Remove aria-hidden",
825
+ description: "If the element should be hidden from all users, use the HTML hidden attribute or CSS display:none instead."
826
+ },
827
+ {
828
+ title: "Make the element non-focusable",
829
+ description: 'If the element is intentionally decorative, add tabindex="-1" and disable it so it is not reachable by keyboard.'
830
+ }
831
+ ]
832
+ };
833
+ },
834
+ invalidAttributeValue(attr, value, expected) {
835
+ const got = value === null ? "null" : value === void 0 ? "undefined" : typeof value === "string" ? `"${value}"` : String(value);
836
+ return {
837
+ code: "ARIA2013" /* AriaInvalidAttributeValue */,
838
+ category: 2 /* ARIA */,
839
+ message: `"${attr}" has an invalid value (${got}). Expected: ${expected}.`,
840
+ rationale: "ARIA attributes with invalid values are silently ignored by assistive technology, making the markup semantically inert.",
841
+ suggestions: [
842
+ {
843
+ title: `Use a valid value for ${attr}`,
844
+ description: `Valid values are: ${expected}.`
845
+ }
846
+ ]
847
+ };
848
+ },
849
+ redundantAriaLevel(tag, level) {
850
+ return {
851
+ code: "ARIA2014" /* AriaRedundantLevelAttribute */,
852
+ category: 2 /* ARIA */,
853
+ message: `aria-level="${level}" is redundant on <${tag}>: the element already has an implicit heading level of ${level}. Remove the attribute.`,
854
+ 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>).',
855
+ suggestions: [
856
+ {
857
+ title: "Remove aria-level",
858
+ description: `<${tag}> already implies aria-level="${level}".`
859
+ }
860
+ ]
861
+ };
862
+ },
863
+ requiredProperty(attr, role) {
864
+ return {
865
+ code: "ARIA2012" /* AriaRequiredProperty */,
866
+ category: 2 /* ARIA */,
867
+ message: `"${attr}" is required for role="${role}" but is missing.`,
868
+ 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.`,
869
+ suggestions: [
870
+ {
871
+ title: `Add ${attr}`,
872
+ description: `role="${role}" requires "${attr}" to be present.`
873
+ }
874
+ ]
875
+ };
876
+ },
877
+ invalidRole(role, tag) {
878
+ return {
879
+ code: "ARIA2008" /* AriaInvalidRole */,
880
+ category: 2 /* ARIA */,
881
+ message: `Invalid role "${role ?? ""}" on <${tag}>.`,
882
+ rationale: "An unrecognised or misapplied ARIA role is ignored by assistive technology and may degrade the accessibility of the element."
883
+ };
884
+ }
885
+ };
886
+
887
+ // ../../lib/contract/src/diagnostics/contract.ts
888
+ var ContractDiagnostics = {
889
+ unexpectedChild(typeName, index, context) {
890
+ return {
891
+ code: "COMP1004" /* UnexpectedChild */,
892
+ category: 0 /* Contract */,
893
+ component: context,
894
+ message: `${context}: unexpected child "${typeName}" at index ${index}.`
895
+ };
896
+ },
897
+ ambiguousChild(typeName, index, ruleNames, context) {
898
+ const quoted = ruleNames.map((n) => `"${n}"`).join(" and ");
899
+ return {
900
+ code: "COMP1005" /* AmbiguousChild */,
901
+ category: 0 /* Contract */,
902
+ component: context,
903
+ message: `${context}: child "${typeName}" at index ${index} matches multiple child rules: ${quoted}.`
904
+ };
905
+ },
906
+ cardinalityMin(ruleName, min, context) {
907
+ return {
908
+ code: "COMP1006" /* CardinalityMin */,
909
+ category: 0 /* Contract */,
910
+ component: context,
911
+ message: `${context}: "${ruleName}" requires at least ${min}.`
912
+ };
913
+ },
914
+ cardinalityMax(ruleName, max, context) {
915
+ return {
916
+ code: "COMP1007" /* CardinalityMax */,
917
+ category: 0 /* Contract */,
918
+ component: context,
919
+ message: `${context}: "${ruleName}" allows at most ${max}.`
920
+ };
921
+ },
922
+ positionViolation(ruleName, position, index, context) {
923
+ return {
924
+ code: "COMP1008" /* PositionViolation */,
925
+ category: 0 /* Contract */,
926
+ component: context,
927
+ message: `${context}: "${ruleName}" must be ${position}, got index ${index}`
928
+ };
929
+ },
930
+ unknownVariantDim(component, label, dim) {
931
+ return {
932
+ code: "COMP1010" /* ContractUnknownVariantDim */,
933
+ category: 0 /* Contract */,
934
+ message: `${component}: ${label} references unknown variant "${dim}".`
935
+ };
936
+ },
937
+ unknownVariantValue(component, label, dim, value, valid) {
938
+ return {
939
+ code: "COMP1011" /* ContractUnknownVariantValue */,
940
+ category: 0 /* Contract */,
941
+ message: `${component}: ${label} sets "${dim}" to unknown value "${value}" (valid: ${valid.join(", ")}).`
942
+ };
943
+ },
944
+ unknownRecipeKey(component, key) {
945
+ return {
946
+ code: "COMP1012" /* ContractUnknownRecipeKey */,
947
+ category: 0 /* Contract */,
948
+ message: `${component} Unknown recipeKey "${key}" \u2014 no preset with that name exists.`
949
+ };
950
+ },
951
+ invalidVariantValue(component, key, value) {
952
+ return {
953
+ code: "COMP1013" /* ContractInvalidVariantValue */,
954
+ category: 0 /* Contract */,
955
+ message: `${component} Variant "${key}=${value}" is not a defined value for the "${key}" dimension.`
956
+ };
957
+ },
958
+ allowedAsViolation(tag, allowedAs, component) {
959
+ const allowed = allowedAs.map((t) => `"${String(t)}"`).join(", ");
960
+ return {
961
+ code: "COMP1009" /* AllowedAsViolation */,
962
+ category: 0 /* Contract */,
963
+ component,
964
+ message: `<${component}>: "as" prop received "${tag}" but only [${allowed}] are allowed.`
965
+ };
966
+ }
967
+ };
968
+
969
+ // ../../lib/contract/src/diagnostics/html.ts
970
+ var HtmlDiagnostics = {
971
+ emptyRole(tag) {
972
+ return {
973
+ code: "HTML3002" /* HtmlEmptyRole */,
974
+ category: 1 /* HTML */,
975
+ message: `<${tag}> has an explicit empty role="". Omit the attribute instead.`
976
+ };
977
+ },
978
+ implicitRoleRedundant(tag, implicitRole) {
979
+ return {
980
+ code: "HTML3003" /* HtmlImplicitRoleRedundant */,
981
+ category: 1 /* HTML */,
982
+ message: `<${tag}> already has implicit role="${implicitRole}". Avoid redundant role assignment.`
983
+ };
984
+ },
985
+ implicitRoleOverride(tag, implicitRole, role) {
986
+ return {
987
+ code: "HTML3004" /* HtmlImplicitRoleOverride */,
988
+ category: 1 /* HTML */,
989
+ message: `<${tag}> should not override its implicit role="${implicitRole}" with role="${role}".`
990
+ };
991
+ },
992
+ standaloneRegionOverride(tag, implicitRole) {
993
+ return {
994
+ code: "HTML3005" /* HtmlStandaloneRegionOverride */,
995
+ category: 1 /* HTML */,
996
+ message: `<${tag}> is a self-contained element with implicit role="${implicitRole}". Assigning role="region" has been removed.`
997
+ };
998
+ },
999
+ landmarkRoleOverride(tag, implicitRole, role) {
1000
+ return {
1001
+ code: "HTML3006" /* HtmlLandmarkRoleOverride */,
1002
+ category: 1 /* HTML */,
1003
+ message: `<${tag}> has a fixed landmark role="${implicitRole}". role="${role}" overrides it and confuses assistive technology. The override has been removed.`
1004
+ };
1005
+ },
1006
+ invalidChild(child, parent, allowed) {
1007
+ return {
1008
+ code: "HTML3007" /* HtmlInvalidChild */,
1009
+ category: 1 /* HTML */,
1010
+ message: `<${child}> is not a valid direct child of <${parent}>. Allowed: ${allowed}.`
1011
+ };
1012
+ }
1013
+ };
1014
+
1015
+ // ../../lib/contract/src/diagnostics/slot.ts
1016
+ var SlotDiagnostics = {
1017
+ exclusive(name) {
1018
+ return {
1019
+ code: "SLOT1001" /* SlotExclusive */,
1020
+ category: 0 /* Contract */,
1021
+ component: name,
1022
+ message: `${name}: "as" and "asChild" are mutually exclusive`
1023
+ };
1024
+ },
1025
+ singleChildRequired(name, elementTerm) {
1026
+ return {
1027
+ code: "SLOT1002" /* SlotSingleChild */,
1028
+ category: 0 /* Contract */,
1029
+ component: name,
1030
+ message: `${name}: asChild requires a ${elementTerm} child`
1031
+ };
1032
+ },
1033
+ singleChildExceeded(name, elementTerm, count) {
1034
+ return {
1035
+ code: "SLOT1002" /* SlotSingleChild */,
1036
+ category: 0 /* Contract */,
1037
+ component: name,
1038
+ message: `${name}: asChild requires exactly one ${elementTerm} child, got ${count}`
1039
+ };
1040
+ },
1041
+ discardedChildren(name, elementTerm, count) {
1042
+ const suffix = count === 1 ? "" : "ren";
1043
+ return {
1044
+ code: "SLOT1003" /* SlotDiscardedChildren */,
1045
+ category: 0 /* Contract */,
1046
+ component: name,
1047
+ message: `${name}: asChild discarded ${count} non-element child${suffix} \u2014 only ${elementTerm}s are valid asChild children.`
1048
+ };
1049
+ },
1050
+ renderFnRequired(name, received) {
1051
+ return {
1052
+ code: "SLOT1004" /* SlotRenderFn */,
1053
+ category: 0 /* Contract */,
1054
+ component: name,
1055
+ message: `${name}: asChild requires a render function as children, got ${received}`
1056
+ };
1057
+ }
1058
+ };
1059
+
1060
+ // ../../lib/contract/src/aria/polymorphic-validator.ts
737
1061
  var VALID = [{ valid: true }];
738
1062
  function isIntrinsicTag(tag) {
739
1063
  return isString(tag);
@@ -742,26 +1066,28 @@ function omitProp(obj, key) {
742
1066
  const { [key]: _, ...rest } = obj;
743
1067
  return rest;
744
1068
  }
745
- var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
1069
+ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
746
1070
  #extraRules;
747
1071
  #planCache = /* @__PURE__ */ new Map();
748
1072
  static #MAX_CACHE = 100;
749
1073
  // Memoized AriaFix objects keyed by attribute name — the ARIA attribute set is
750
1074
  // finite so this Map is bounded and avoids recreating closures on every cache miss.
751
1075
  static #removeAttributeFixCache = /* @__PURE__ */ new Map();
752
- constructor(strict = "warn", options) {
753
- super(strict);
1076
+ constructor(diagnostics, options) {
1077
+ super(diagnostics);
754
1078
  this.#extraRules = options?.rules ?? [];
755
1079
  }
756
1080
  static #normalizeEmptyRole(tag, props) {
757
1081
  if (props.role !== "") return { normalized: false };
1082
+ const d = HtmlDiagnostics.emptyRole(tag);
758
1083
  return {
759
1084
  normalized: true,
760
1085
  result: {
761
1086
  props: omitProp(props, "role"),
762
1087
  violations: [
763
1088
  {
764
- message: `<${tag}> has an explicit empty role="". Omit the attribute instead.`,
1089
+ message: d.message,
1090
+ diagnostic: d,
765
1091
  tag,
766
1092
  role: "",
767
1093
  attribute: void 0,
@@ -774,10 +1100,9 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
774
1100
  }
775
1101
  static #deriveContext(tag, props) {
776
1102
  if (!isIntrinsicTag(tag)) return { proceed: false, result: { props, violations: [] } };
777
- const implicitRole = getImplicitRole(tag);
778
- const hasExplicitLiveRole = !implicitRole && _AriaPolicyEngine.#LIVE_REGION_ROLES.has(props.role ?? "");
779
- if (!implicitRole && !hasExplicitLiveRole)
780
- return { proceed: false, result: { props, violations: [] } };
1103
+ const implicitRole = getImplicitRole(tag, props);
1104
+ const hasRole2 = implicitRole != null || isString(props.role) && props.role.length > 0;
1105
+ if (!hasRole2) return { proceed: false, result: { props, violations: [] } };
781
1106
  const normalized = _AriaPolicyEngine.#normalizeEmptyRole(tag, props);
782
1107
  if (normalized.normalized) return { proceed: false, result: normalized.result };
783
1108
  const effectiveRole = props.role ?? implicitRole;
@@ -792,25 +1117,36 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
792
1117
  static #runRules(rules, context) {
793
1118
  const violations = [];
794
1119
  const fixes = [];
795
- for (const rule of rules) {
796
- for (const result of rule(context)) {
797
- if (!result.valid) {
798
- violations.push({
799
- message: result.message ?? `Invalid role "${context.props.role}" on <${context.tag}>`,
800
- tag: context.tag,
801
- role: context.props.role,
802
- attribute: result.attribute,
803
- severity: result.severity,
804
- phase: "evaluate"
805
- });
806
- if (result.fixable) fixes.push(result.fix);
807
- }
808
- }
809
- }
1120
+ iterate.forEach(rules, (rule) => {
1121
+ iterate.forEach(rule(context), (result) => {
1122
+ if (result.valid) return;
1123
+ const {
1124
+ tag,
1125
+ props: { role }
1126
+ } = context;
1127
+ const { message, attribute, severity } = result;
1128
+ const resolvedMessage = message ?? result.diagnostic?.message;
1129
+ const fallbackDiag = resolvedMessage == null ? AriaDiagnostics.invalidRole(role, tag) : void 0;
1130
+ violations.push({
1131
+ message: resolvedMessage ?? fallbackDiag.message,
1132
+ tag,
1133
+ role,
1134
+ attribute,
1135
+ severity,
1136
+ phase: "evaluate",
1137
+ ...result.diagnostic != null && { diagnostic: result.diagnostic },
1138
+ ...fallbackDiag != null && { diagnostic: fallbackDiag }
1139
+ });
1140
+ if (result.fixable) fixes.push(result.fix);
1141
+ });
1142
+ });
810
1143
  return { violations, fixes };
811
1144
  }
812
1145
  static #getRules(context) {
813
- return _AriaPolicyEngine.#hasRole(context.props) ? _AriaPolicyEngine.#pipeline : [_AriaPolicyEngine.#checkInvalidAriaAttributes];
1146
+ if (_AriaPolicyEngine.#hasRole(context.props) || context.effectiveRole != null && _AriaPolicyEngine.#LIVE_REGION_ROLES.has(context.effectiveRole)) {
1147
+ return _AriaPolicyEngine.#pipeline;
1148
+ }
1149
+ return _AriaPolicyEngine.#implicitOnlyRules;
814
1150
  }
815
1151
  static evaluate(tag, props) {
816
1152
  const derived = _AriaPolicyEngine.#deriveContext(tag, props);
@@ -835,10 +1171,11 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
835
1171
  return { props: next, violations };
836
1172
  }
837
1173
  report(violations) {
838
- for (const v of violations) {
839
- if (v.severity === "error") this.violate(v.message);
840
- else this.warn(v.message);
841
- }
1174
+ iterate.forEach(violations, (v) => {
1175
+ const d = v.diagnostic ?? AriaDiagnostics.fromViolation(v);
1176
+ if (v.severity === "error") this.violate(d);
1177
+ else this.warn(d);
1178
+ });
842
1179
  }
843
1180
  // Cache key covers only the aria-relevant subset of props (tag + role + aria-* attrs).
844
1181
  // Non-aria props (className, onClick, etc.) do not affect ARIA decisions and are excluded
@@ -850,27 +1187,26 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
850
1187
  if (!isIntrinsicTag(tag)) return null;
851
1188
  const parts = [tag];
852
1189
  if (typeof props.role === "string") parts.push(`role:${props.role}`);
1190
+ if (tag === "input" && typeof props.type === "string") parts.push(`type:${props.type}`);
1191
+ if (tag === "img") parts.push(`alt:${props.alt === "" ? "empty" : "present"}`);
853
1192
  const ariaEntries = [];
854
- for (const k in props) {
855
- if (!Object.hasOwn(props, k) || !k.startsWith("aria-")) continue;
856
- const v = props[k];
857
- if (!isString(v) && !isNumber(v) && typeof v !== "boolean") continue;
1193
+ iterate.forEachEntry(props, (k, v) => {
1194
+ if (!k.startsWith("aria-")) return;
1195
+ if (!isString(v) && !isNumber(v) && typeof v !== "boolean") return;
858
1196
  ariaEntries.push(`${k}:${String(v)}`);
859
- }
1197
+ });
860
1198
  if (ariaEntries.length > 0) parts.push(...ariaEntries.sort());
861
1199
  return parts.join("|");
862
1200
  }
863
1201
  static #computePlan(inputProps, resultProps) {
864
1202
  const removals = /* @__PURE__ */ new Set();
865
1203
  const updates = {};
866
- for (const key in inputProps) {
867
- if (Object.hasOwn(inputProps, key) && !(key in resultProps)) removals.add(key);
868
- }
869
- for (const key in resultProps) {
870
- if (!Object.hasOwn(resultProps, key)) continue;
871
- const resultVal = resultProps[key];
1204
+ iterate.forEachKey(inputProps, (key) => {
1205
+ if (!(key in resultProps)) removals.add(key);
1206
+ });
1207
+ iterate.forEachEntry(resultProps, (key, resultVal) => {
872
1208
  if (inputProps[key] !== resultVal) updates[key] = resultVal;
873
- }
1209
+ });
874
1210
  return { removals, updates };
875
1211
  }
876
1212
  static #applyPlan(props, removals, updates) {
@@ -878,15 +1214,15 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
878
1214
  const hasUpdates = Object.keys(updates).length > 0;
879
1215
  if (!hasRemovals && !hasUpdates) return props;
880
1216
  const next = {};
881
- for (const k in props) {
882
- if (Object.hasOwn(props, k) && !removals.has(k)) next[k] = props[k];
883
- }
1217
+ iterate.forEachEntry(props, (k, v) => {
1218
+ if (!removals.has(k)) next[k] = v;
1219
+ });
884
1220
  Object.assign(next, updates);
885
1221
  return next;
886
1222
  }
887
1223
  validate(tag, props) {
888
1224
  const key = _AriaPolicyEngine.#createPlanKey(tag, props);
889
- if (!isNull3(key)) {
1225
+ if (!isNull(key)) {
890
1226
  const cached = this.#planCache.get(key);
891
1227
  if (cached !== void 0) {
892
1228
  this.#planCache.delete(key);
@@ -900,7 +1236,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
900
1236
  }
901
1237
  const result = this.#extraRules.length ? _AriaPolicyEngine.#evaluateWithRules(tag, props, this.#extraRules) : _AriaPolicyEngine.evaluate(tag, props);
902
1238
  if (result.violations.length > 0) this.report(result.violations);
903
- if (!isNull3(key)) {
1239
+ if (!isNull(key)) {
904
1240
  const { removals, updates } = _AriaPolicyEngine.#computePlan(
905
1241
  props,
906
1242
  result.props
@@ -921,12 +1257,12 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
921
1257
  if (fixes.length === 0) return props;
922
1258
  const sorted = [...fixes].sort((a, b) => (a.priority ?? Infinity) - (b.priority ?? Infinity));
923
1259
  let next = props;
924
- for (const { apply } of sorted) {
1260
+ iterate.forEach(sorted, ({ apply }) => {
925
1261
  const effectiveRole = next.role ?? implicitRole;
926
1262
  const fixContext = { tag, implicitRole, effectiveRole, props: next };
927
1263
  const fixResult = apply(fixContext);
928
1264
  if (fixResult.applied) next = fixResult.next;
929
- }
1265
+ });
930
1266
  return next;
931
1267
  }
932
1268
  static #removeRole = {
@@ -954,10 +1290,26 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
954
1290
  _AriaPolicyEngine.#checkInvalidRoleOverride,
955
1291
  _AriaPolicyEngine.#checkRedundantRole,
956
1292
  _AriaPolicyEngine.#checkStandaloneRegion,
1293
+ _AriaPolicyEngine.#checkAriaAttributeValues,
957
1294
  _AriaPolicyEngine.#checkInvalidAriaAttributes,
1295
+ _AriaPolicyEngine.#checkRequiredAriaProperties,
1296
+ _AriaPolicyEngine.#checkNameRequiredRoles,
1297
+ _AriaPolicyEngine.#checkRedundantAriaLevel,
958
1298
  _AriaPolicyEngine.#checkMissingLiveRegion,
959
1299
  _AriaPolicyEngine.#checkMissingAtomic,
960
- _AriaPolicyEngine.#checkInvalidAriaRelevant
1300
+ _AriaPolicyEngine.#checkInvalidAriaRelevant,
1301
+ _AriaPolicyEngine.#checkAriaHiddenOnFocusable,
1302
+ _AriaPolicyEngine.#checkPresentationalAriaAttributes
1303
+ ];
1304
+ // Rules for elements with an implicit role but no explicit role (not a live region).
1305
+ static #implicitOnlyRules = [
1306
+ _AriaPolicyEngine.#checkAriaAttributeValues,
1307
+ _AriaPolicyEngine.#checkInvalidAriaAttributes,
1308
+ _AriaPolicyEngine.#checkRequiredAriaProperties,
1309
+ _AriaPolicyEngine.#checkNameRequiredRoles,
1310
+ _AriaPolicyEngine.#checkRedundantAriaLevel,
1311
+ _AriaPolicyEngine.#checkAriaHiddenOnFocusable,
1312
+ _AriaPolicyEngine.#checkPresentationalAriaAttributes
961
1313
  ];
962
1314
  static #checkInvalidRoleOverride({
963
1315
  tag,
@@ -973,7 +1325,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
973
1325
  fixable: true,
974
1326
  severity: "error",
975
1327
  fix: _AriaPolicyEngine.#removeRole,
976
- message: `<${tag}> should not override its implicit role="${implicitRole}" with role="${role}".`
1328
+ diagnostic: HtmlDiagnostics.implicitRoleOverride(tag, implicitRole, role)
977
1329
  }
978
1330
  ];
979
1331
  }
@@ -985,47 +1337,304 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
985
1337
  return [
986
1338
  {
987
1339
  valid: false,
988
- fixable: true,
1340
+ fixable: true,
1341
+ severity: "warning",
1342
+ fix: _AriaPolicyEngine.#removeRole,
1343
+ diagnostic: HtmlDiagnostics.implicitRoleRedundant(tag, implicitRole)
1344
+ }
1345
+ ];
1346
+ }
1347
+ static #checkStandaloneRegion({ tag, props, implicitRole }) {
1348
+ const role = props.role;
1349
+ if (role !== "region") return VALID;
1350
+ if (!isStandaloneTag(tag)) return VALID;
1351
+ return [
1352
+ {
1353
+ valid: false,
1354
+ fixable: true,
1355
+ severity: "error",
1356
+ fix: _AriaPolicyEngine.#removeRole,
1357
+ diagnostic: HtmlDiagnostics.standaloneRegionOverride(tag, implicitRole ?? tag)
1358
+ }
1359
+ ];
1360
+ }
1361
+ static #checkInvalidAriaAttributes({
1362
+ tag,
1363
+ props,
1364
+ effectiveRole
1365
+ }) {
1366
+ if (effectiveRole === "none" || effectiveRole === "presentation") return VALID;
1367
+ const results = [];
1368
+ iterate.forEachEntry(props, (key) => {
1369
+ if (!key.startsWith("aria-")) return;
1370
+ if (isGlobalAriaAttribute(key)) return;
1371
+ if (isAriaAttributeValidForRole(key, effectiveRole)) return;
1372
+ results.push({
1373
+ valid: false,
1374
+ severity: "warning",
1375
+ fixable: true,
1376
+ attribute: key,
1377
+ diagnostic: AriaDiagnostics.attributeInvalid(key, effectiveRole ?? tag),
1378
+ fix: _AriaPolicyEngine.#makeRemoveAttributeFix(key)
1379
+ });
1380
+ });
1381
+ return results;
1382
+ }
1383
+ // ─── ARIA attribute value validation ──────────────────────────────────────
1384
+ // Accepted value shapes for typed ARIA attributes.
1385
+ // Attributes not in this map are unconstrained (arbitrary string values permitted).
1386
+ static #ARIA_VALUE_TYPES = /* @__PURE__ */ new Map([
1387
+ // Boolean (true | false)
1388
+ ["aria-atomic", { kind: "boolean" }],
1389
+ ["aria-busy", { kind: "boolean" }],
1390
+ ["aria-disabled", { kind: "boolean" }],
1391
+ ["aria-expanded", { kind: "boolean" }],
1392
+ ["aria-hidden", { kind: "boolean" }],
1393
+ ["aria-modal", { kind: "boolean" }],
1394
+ ["aria-multiline", { kind: "boolean" }],
1395
+ ["aria-multiselectable", { kind: "boolean" }],
1396
+ ["aria-readonly", { kind: "boolean" }],
1397
+ ["aria-required", { kind: "boolean" }],
1398
+ ["aria-selected", { kind: "boolean" }],
1399
+ // Tristate (true | false | mixed)
1400
+ ["aria-checked", { kind: "tristate" }],
1401
+ ["aria-pressed", { kind: "tristate" }],
1402
+ // Numeric (any finite number)
1403
+ ["aria-valuenow", { kind: "number" }],
1404
+ ["aria-valuemin", { kind: "number" }],
1405
+ ["aria-valuemax", { kind: "number" }],
1406
+ // Integer with optional range
1407
+ ["aria-level", { kind: "integer", min: 1, max: 6 }],
1408
+ ["aria-posinset", { kind: "integer", min: 1 }],
1409
+ ["aria-setsize", { kind: "integer", min: -1 }],
1410
+ ["aria-rowcount", { kind: "integer", min: -1 }],
1411
+ ["aria-colcount", { kind: "integer", min: -1 }],
1412
+ ["aria-rowindex", { kind: "integer", min: 1 }],
1413
+ ["aria-colindex", { kind: "integer", min: 1 }],
1414
+ ["aria-rowspan", { kind: "integer", min: 0 }],
1415
+ ["aria-colspan", { kind: "integer", min: 0 }],
1416
+ // Enum (specific allowed tokens)
1417
+ ["aria-autocomplete", { kind: "enum", values: /* @__PURE__ */ new Set(["inline", "list", "both", "none"]) }],
1418
+ [
1419
+ "aria-current",
1420
+ {
1421
+ kind: "enum",
1422
+ values: /* @__PURE__ */ new Set(["page", "step", "location", "date", "time", "true", "false"])
1423
+ }
1424
+ ],
1425
+ [
1426
+ "aria-haspopup",
1427
+ {
1428
+ kind: "enum",
1429
+ values: /* @__PURE__ */ new Set(["false", "true", "menu", "listbox", "tree", "grid", "dialog"])
1430
+ }
1431
+ ],
1432
+ ["aria-invalid", { kind: "enum", values: /* @__PURE__ */ new Set(["grammar", "false", "spelling", "true"]) }],
1433
+ ["aria-live", { kind: "enum", values: /* @__PURE__ */ new Set(["assertive", "off", "polite"]) }],
1434
+ [
1435
+ "aria-orientation",
1436
+ { kind: "enum", values: /* @__PURE__ */ new Set(["horizontal", "vertical", "undefined"]) }
1437
+ ],
1438
+ ["aria-sort", { kind: "enum", values: /* @__PURE__ */ new Set(["ascending", "descending", "none", "other"]) }]
1439
+ ]);
1440
+ static #isValidAriaValue(value, type) {
1441
+ switch (type.kind) {
1442
+ case "boolean":
1443
+ return value === "true" || value === "false" || value === true || value === false;
1444
+ case "tristate":
1445
+ return value === "true" || value === "false" || value === "mixed" || value === true || value === false;
1446
+ case "number": {
1447
+ if (typeof value === "number") return Number.isFinite(value);
1448
+ if (typeof value !== "string") return false;
1449
+ const n = parseFloat(value);
1450
+ return Number.isFinite(n);
1451
+ }
1452
+ case "integer": {
1453
+ const n = typeof value === "number" ? value : typeof value === "string" ? parseInt(value, 10) : NaN;
1454
+ if (!Number.isFinite(n) || !Number.isInteger(n)) return false;
1455
+ if (type.min !== void 0 && n < type.min) return false;
1456
+ if (type.max !== void 0 && n > type.max) return false;
1457
+ return true;
1458
+ }
1459
+ case "enum":
1460
+ return typeof value === "string" && type.values.has(value);
1461
+ }
1462
+ }
1463
+ static #describeExpected(type) {
1464
+ switch (type.kind) {
1465
+ case "boolean":
1466
+ return '"true" or "false"';
1467
+ case "tristate":
1468
+ return '"true", "false", or "mixed"';
1469
+ case "number":
1470
+ return "a finite number";
1471
+ case "integer": {
1472
+ const parts = ["an integer"];
1473
+ if (type.min !== void 0 && type.max !== void 0)
1474
+ parts.push(`between ${type.min} and ${type.max}`);
1475
+ else if (type.min !== void 0) parts.push(`\u2265 ${type.min}`);
1476
+ else if (type.max !== void 0) parts.push(`\u2264 ${type.max}`);
1477
+ return parts.join(" ");
1478
+ }
1479
+ case "enum":
1480
+ return [...type.values].map((v) => `"${v}"`).join(", ");
1481
+ }
1482
+ }
1483
+ static #checkAriaAttributeValues({ props, effectiveRole }) {
1484
+ if (effectiveRole === "none" || effectiveRole === "presentation") return VALID;
1485
+ const results = [];
1486
+ iterate.forEachEntry(props, (key, value) => {
1487
+ if (!key.startsWith("aria-")) return;
1488
+ const type = _AriaPolicyEngine.#ARIA_VALUE_TYPES.get(key);
1489
+ if (type == null) return;
1490
+ if (_AriaPolicyEngine.#isValidAriaValue(value, type)) return;
1491
+ results.push({
1492
+ valid: false,
1493
+ fixable: true,
1494
+ severity: "warning",
1495
+ attribute: key,
1496
+ diagnostic: AriaDiagnostics.invalidAttributeValue(
1497
+ key,
1498
+ value,
1499
+ _AriaPolicyEngine.#describeExpected(type)
1500
+ ),
1501
+ fix: _AriaPolicyEngine.#makeRemoveAttributeFix(key)
1502
+ });
1503
+ });
1504
+ return results;
1505
+ }
1506
+ // ─── Heading implicit level ────────────────────────────────────────────────
1507
+ static #HEADING_IMPLICIT_LEVELS = /* @__PURE__ */ new Map([
1508
+ ["h1", 1],
1509
+ ["h2", 2],
1510
+ ["h3", 3],
1511
+ ["h4", 4],
1512
+ ["h5", 5],
1513
+ ["h6", 6]
1514
+ ]);
1515
+ static #checkRedundantAriaLevel({
1516
+ tag,
1517
+ props,
1518
+ effectiveRole
1519
+ }) {
1520
+ if (effectiveRole === "none" || effectiveRole === "presentation") return VALID;
1521
+ const implicitLevel = _AriaPolicyEngine.#HEADING_IMPLICIT_LEVELS.get(tag);
1522
+ if (implicitLevel == null) return VALID;
1523
+ const raw = props["aria-level"];
1524
+ if (raw == null) return VALID;
1525
+ const n = typeof raw === "number" ? raw : typeof raw === "string" ? parseInt(raw, 10) : NaN;
1526
+ if (!Number.isFinite(n) || n !== implicitLevel) return VALID;
1527
+ return [
1528
+ {
1529
+ valid: false,
1530
+ fixable: true,
1531
+ severity: "warning",
1532
+ attribute: "aria-level",
1533
+ diagnostic: AriaDiagnostics.redundantAriaLevel(tag, implicitLevel),
1534
+ fix: _AriaPolicyEngine.#makeRemoveAttributeFix("aria-level")
1535
+ }
1536
+ ];
1537
+ }
1538
+ // ─── Name-required roles ───────────────────────────────────────────────────
1539
+ // Roles that always require an accessible name per WAI-ARIA APG.
1540
+ // Dialog and landmark names are enforced via contracts (ariaContract) rather than
1541
+ // the built-in pipeline so consumers can opt in; img is built in because role=img
1542
+ // on any element (including bare <img>) is definitionally useless without a name.
1543
+ static #NAME_REQUIRED_ROLES = /* @__PURE__ */ new Set(["img"]);
1544
+ static #checkNameRequiredRoles({
1545
+ tag,
1546
+ props,
1547
+ effectiveRole
1548
+ }) {
1549
+ if (!effectiveRole || !_AriaPolicyEngine.#NAME_REQUIRED_ROLES.has(effectiveRole)) return VALID;
1550
+ if ("aria-label" in props || "aria-labelledby" in props) return VALID;
1551
+ if (tag === "img" && typeof props.alt === "string" && props.alt.length > 0) return VALID;
1552
+ return [
1553
+ {
1554
+ valid: false,
1555
+ fixable: false,
1556
+ severity: "warning",
1557
+ diagnostic: AriaDiagnostics.missingAccessibleName(tag)
1558
+ }
1559
+ ];
1560
+ }
1561
+ // WAI-ARIA 1.2 required states and properties, keyed by role.
1562
+ // Source: https://www.w3.org/TR/wai-aria-1.2/#requiredState
1563
+ static #REQUIRED_PROPERTIES = /* @__PURE__ */ new Map([
1564
+ ["combobox", ["aria-expanded"]],
1565
+ ["option", ["aria-selected"]],
1566
+ ["slider", ["aria-valuenow"]],
1567
+ ["scrollbar", ["aria-controls", "aria-valuenow"]],
1568
+ ["spinbutton", ["aria-valuenow"]]
1569
+ ]);
1570
+ static #checkRequiredAriaProperties({
1571
+ props,
1572
+ effectiveRole
1573
+ }) {
1574
+ if (!effectiveRole) return VALID;
1575
+ const required = _AriaPolicyEngine.#REQUIRED_PROPERTIES.get(effectiveRole);
1576
+ if (required == null) return VALID;
1577
+ const results = [];
1578
+ iterate.forEach(required, (attr) => {
1579
+ if (attr in props) return;
1580
+ results.push({
1581
+ valid: false,
1582
+ fixable: false,
989
1583
  severity: "warning",
990
- fix: _AriaPolicyEngine.#removeRole,
991
- message: `<${tag}> already has implicit role="${implicitRole}". Avoid redundant role assignment.`
992
- }
993
- ];
1584
+ attribute: attr,
1585
+ diagnostic: AriaDiagnostics.requiredProperty(attr, effectiveRole)
1586
+ });
1587
+ });
1588
+ return results;
994
1589
  }
995
- static #checkStandaloneRegion({ tag, props, implicitRole }) {
996
- const role = props.role;
997
- if (role !== "region") return VALID;
998
- if (!isStandaloneTag(tag)) return VALID;
1590
+ // Natively interactive HTML elements always keyboard-reachable unless explicitly disabled.
1591
+ static #INTERACTIVE_TAGS = /* @__PURE__ */ new Set([
1592
+ "a",
1593
+ "button",
1594
+ "input",
1595
+ "select",
1596
+ "textarea"
1597
+ ]);
1598
+ // WAI-ARIA 1.2 §6.6: aria-hidden="true" must not be placed on focusable elements.
1599
+ static #checkAriaHiddenOnFocusable({ tag, props }) {
1600
+ if (props["aria-hidden"] !== "true" && props["aria-hidden"] !== true) return VALID;
1601
+ const isInteractive = _AriaPolicyEngine.#INTERACTIVE_TAGS.has(tag);
1602
+ if (!isInteractive) {
1603
+ const tabindex = props.tabindex;
1604
+ const n = typeof tabindex === "number" ? tabindex : typeof tabindex === "string" ? parseInt(tabindex, 10) : NaN;
1605
+ if (!Number.isFinite(n) || n < 0) return VALID;
1606
+ }
999
1607
  return [
1000
1608
  {
1001
1609
  valid: false,
1002
- fixable: true,
1610
+ fixable: false,
1003
1611
  severity: "error",
1004
- fix: _AriaPolicyEngine.#removeRole,
1005
- message: `<${tag}> is a self-contained element with implicit role="${implicitRole}". Assigning role="region" has been removed.`
1612
+ attribute: "aria-hidden",
1613
+ diagnostic: AriaDiagnostics.ariaHiddenOnFocusable(tag)
1006
1614
  }
1007
1615
  ];
1008
1616
  }
1009
- static #checkInvalidAriaAttributes({
1617
+ // Presentational elements (role=none/presentation, including <img alt="">) are removed
1618
+ // from the accessibility tree — ARIA attributes on them are meaningless and misleading.
1619
+ static #checkPresentationalAriaAttributes({
1010
1620
  tag,
1011
1621
  props,
1012
1622
  effectiveRole
1013
1623
  }) {
1624
+ if (effectiveRole !== "none" && effectiveRole !== "presentation") return VALID;
1014
1625
  const results = [];
1015
- for (const key in props) {
1016
- if (!Object.hasOwn(props, key)) continue;
1017
- if (!key.startsWith("aria-")) continue;
1018
- if (isGlobalAriaAttribute(key)) continue;
1019
- if (isAriaAttributeValidForRole(key, effectiveRole)) continue;
1626
+ iterate.forEachEntry(props, (key) => {
1627
+ if (!key.startsWith("aria-")) return;
1628
+ if (key === "aria-hidden") return;
1020
1629
  results.push({
1021
1630
  valid: false,
1022
- severity: "warning",
1023
1631
  fixable: true,
1632
+ severity: "warning",
1024
1633
  attribute: key,
1025
- message: `"${key}" is not valid on role="${effectiveRole ?? tag}". It will be removed.`,
1634
+ diagnostic: AriaDiagnostics.attributeOnPresentational(key, tag),
1026
1635
  fix: _AriaPolicyEngine.#makeRemoveAttributeFix(key)
1027
1636
  });
1028
- }
1637
+ });
1029
1638
  return results;
1030
1639
  }
1031
1640
  // WAI-ARIA live region roles and their implied aria-live politeness values.
@@ -1054,7 +1663,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
1054
1663
  fixable: true,
1055
1664
  severity: "warning",
1056
1665
  fix: injectLive,
1057
- message: `role="${effectiveRole}" implies aria-live="${impliedLive}" but it is missing. It has been injected.`
1666
+ diagnostic: AriaDiagnostics.missingLiveRegion(effectiveRole, impliedLive)
1058
1667
  }
1059
1668
  ];
1060
1669
  }
@@ -1066,7 +1675,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
1066
1675
  valid: false,
1067
1676
  fixable: false,
1068
1677
  severity: "warning",
1069
- 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.`
1678
+ diagnostic: AriaDiagnostics.missingAtomic(effectiveRole)
1070
1679
  }
1071
1680
  ];
1072
1681
  }
@@ -1095,7 +1704,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
1095
1704
  fixable: true,
1096
1705
  severity: "warning",
1097
1706
  attribute: "aria-relevant",
1098
- message: `aria-relevant contains invalid token(s): ${invalid.map((t) => `"${t}"`).join(", ")}. Valid tokens are: additions, removals, text, all.`,
1707
+ diagnostic: AriaDiagnostics.relevantInvalidTokens(invalid),
1099
1708
  fix: _AriaPolicyEngine.#makeRemoveAttributeFix("aria-relevant")
1100
1709
  }
1101
1710
  ];
@@ -1107,7 +1716,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
1107
1716
  fixable: true,
1108
1717
  severity: "warning",
1109
1718
  attribute: "aria-relevant",
1110
- message: `aria-relevant includes "all" alongside other tokens. "all" supersedes additions, removals, and text \u2014 use aria-relevant="all" alone.`,
1719
+ diagnostic: AriaDiagnostics.relevantSuperseded(),
1111
1720
  fix: _AriaPolicyEngine.#normalizeRelevantAllFix
1112
1721
  }
1113
1722
  ];
@@ -1115,6 +1724,8 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
1115
1724
  return VALID;
1116
1725
  }
1117
1726
  };
1727
+
1728
+ // ../../lib/contract/src/children/get-type-name.ts
1118
1729
  function getTypeName(value) {
1119
1730
  if (value === null) return "null";
1120
1731
  if (value === void 0) return "undefined";
@@ -1125,39 +1736,8 @@ function getTypeName(value) {
1125
1736
  const name = value.constructor?.name;
1126
1737
  return typeof name === "string" && name !== "Object" ? name : "object";
1127
1738
  }
1128
- var MatchValidationErrorBuilder = class {
1129
- #prefix;
1130
- constructor(ctx = "") {
1131
- this.#prefix = ctx ? `${ctx}:
1132
- ` : "";
1133
- }
1134
- #template(typeName, index, prefix = "", suffix = "") {
1135
- const leadingStr = prefix ? `${prefix} ` : "";
1136
- const followingStr = suffix ? ` ${suffix}` : "";
1137
- return `${leadingStr}child "${typeName}" at index ${index}${followingStr}.`;
1138
- }
1139
- unexpectedChild(typeName, index) {
1140
- return this.#template(typeName, index, "unexpected");
1141
- }
1142
- multipleMatches(typeName, index, ruleNames) {
1143
- const quoted = ruleNames.map((n) => `"${n}"`);
1144
- return this.#template(
1145
- typeName,
1146
- index,
1147
- "",
1148
- `matches multiple child rules: ${quoted.join(" and ")}`
1149
- );
1150
- }
1151
- #format(errors) {
1152
- return this.#prefix + errors.join("\n");
1153
- }
1154
- toError(errors) {
1155
- if (errors.length === 0) {
1156
- return new Error(this.#prefix + "Unknown validation error.");
1157
- }
1158
- return new Error(this.#format(errors));
1159
- }
1160
- };
1739
+
1740
+ // ../../lib/contract/src/children/normalize-child-rule.ts
1161
1741
  function normalizeCardinality(input, impliesSingleton) {
1162
1742
  const min = input?.min ?? 0;
1163
1743
  const max = input?.max ?? (impliesSingleton ? 1 : Infinity);
@@ -1182,16 +1762,18 @@ function normalizeChildRule(rule) {
1182
1762
  cardinality: normalizeCardinality(rule.cardinality, impliesSingleton)
1183
1763
  };
1184
1764
  }
1765
+
1766
+ // ../../lib/contract/src/children/rules-matcher.ts
1185
1767
  function getChildType(child) {
1186
- if (!isObject2(child) || !("type" in child)) return void 0;
1768
+ if (!isObject(child) || !("type" in child)) return void 0;
1187
1769
  return child.type;
1188
1770
  }
1189
1771
  function buildPartialIndex(rules) {
1190
1772
  const typeIndex = /* @__PURE__ */ new Map();
1191
1773
  const duplicateTypes = /* @__PURE__ */ new Set();
1192
1774
  const untypedIndices = [];
1193
- for (let ri = 0; ri < rules.length; ri++) {
1194
- const t = rules[ri].type;
1775
+ iterate.forEach(rules, (rule, ri) => {
1776
+ const t = rule.type;
1195
1777
  if (t === void 0) {
1196
1778
  untypedIndices.push(ri);
1197
1779
  } else if (typeIndex.has(t)) {
@@ -1199,12 +1781,14 @@ function buildPartialIndex(rules) {
1199
1781
  } else {
1200
1782
  typeIndex.set(t, ri);
1201
1783
  }
1202
- }
1784
+ });
1203
1785
  if (duplicateTypes.size > 0) {
1204
- for (const t of duplicateTypes) typeIndex.delete(t);
1205
- for (let ri = 0; ri < rules.length; ri++) {
1206
- if (duplicateTypes.has(rules[ri].type)) untypedIndices.push(ri);
1207
- }
1786
+ iterate.forEachSet(duplicateTypes, (t) => {
1787
+ typeIndex.delete(t);
1788
+ });
1789
+ iterate.forEach(rules, (rule, ri) => {
1790
+ if (duplicateTypes.has(rule.type)) untypedIndices.push(ri);
1791
+ });
1208
1792
  }
1209
1793
  return { typeIndex, untypedIndices };
1210
1794
  }
@@ -1223,10 +1807,10 @@ var RuleMatcher = class {
1223
1807
  const reverse = /* @__PURE__ */ new Map();
1224
1808
  const unexpectedIndices = /* @__PURE__ */ new Set();
1225
1809
  const ambiguousIndices = /* @__PURE__ */ new Set();
1226
- for (let ri = 0; ri < this.#rules.length; ri++) {
1810
+ iterate.forEach(this.#rules, (_, ri) => {
1227
1811
  reverse.set(ri, /* @__PURE__ */ new Set());
1228
- }
1229
- for (const [ci, child] of children.entries()) {
1812
+ });
1813
+ iterate.forEach(children, (child, ci) => {
1230
1814
  const t = getChildType(child);
1231
1815
  if (t !== void 0) {
1232
1816
  const ri = this.#typeIndex.get(t);
@@ -1240,8 +1824,8 @@ var RuleMatcher = class {
1240
1824
  reverse.get(ri).add(ci);
1241
1825
  }
1242
1826
  }
1243
- for (const ri of this.#untypedIndices) {
1244
- if (!this.#rules[ri].match(child)) continue;
1827
+ iterate.forEach(this.#untypedIndices, (ri) => {
1828
+ if (!this.#rules[ri].match(child)) return;
1245
1829
  let childEntry = forward.get(ci);
1246
1830
  if (!childEntry) {
1247
1831
  childEntry = /* @__PURE__ */ new Set();
@@ -1249,33 +1833,35 @@ var RuleMatcher = class {
1249
1833
  }
1250
1834
  childEntry.add(ri);
1251
1835
  reverse.get(ri).add(ci);
1252
- }
1836
+ });
1253
1837
  const entry = forward.get(ci);
1254
1838
  if (!entry) {
1255
1839
  unexpectedIndices.add(ci);
1256
1840
  } else if (entry.size > 1) {
1257
1841
  ambiguousIndices.add(ci);
1258
1842
  }
1259
- }
1843
+ });
1260
1844
  return { matrix: { childToRules: { forward, reverse } }, unexpectedIndices, ambiguousIndices };
1261
1845
  }
1262
1846
  };
1263
- var RuleValidator = class _RuleValidator extends StrictBase {
1847
+
1848
+ // ../../lib/contract/src/children/rule-validator.ts
1849
+ var RuleValidator = class _RuleValidator extends InvariantBase {
1264
1850
  #context;
1265
- constructor(context, strict) {
1266
- super(strict);
1851
+ constructor(context, diagnostics) {
1852
+ super(diagnostics);
1267
1853
  this.#context = context;
1268
1854
  }
1269
1855
  validate(rules, matrix, childCount) {
1270
1856
  const firstIndex = 0;
1271
1857
  const lastIndex = childCount - 1;
1272
- for (const [ri, rule] of rules.entries()) {
1858
+ iterate.forEach(rules, (rule, ri) => {
1273
1859
  const matches = matrix.childToRules.reverse.get(ri);
1274
1860
  const matchCount = matches.size;
1275
1861
  this.#validateCardinality(rule, matchCount);
1276
- if (matchCount === 0) continue;
1862
+ if (matchCount === 0) return;
1277
1863
  this.#validatePositions(rule, matches, firstIndex, lastIndex);
1278
- }
1864
+ });
1279
1865
  }
1280
1866
  #validateCardinality(rule, matchCount) {
1281
1867
  const { cardinality, name } = rule;
@@ -1284,21 +1870,21 @@ var RuleValidator = class _RuleValidator extends StrictBase {
1284
1870
  }
1285
1871
  const { min, max } = cardinality;
1286
1872
  if (matchCount < min) {
1287
- this.violate(`${this.#context}: "${name}" requires at least ${min}.`);
1873
+ this.violate(ContractDiagnostics.cardinalityMin(name, min, this.#context));
1288
1874
  return;
1289
1875
  }
1290
1876
  if (matchCount > max) {
1291
- this.violate(`${this.#context}: "${name}" allows at most ${max}.`);
1877
+ this.violate(ContractDiagnostics.cardinalityMax(name, max, this.#context));
1292
1878
  }
1293
1879
  }
1294
1880
  #validatePositions(rule, matches, firstIndex, lastIndex) {
1295
1881
  const { name, position } = rule;
1296
- for (const index of matches) {
1882
+ iterate.forEachSet(matches, (index) => {
1297
1883
  if (_RuleValidator.#isValidPosition(index, position, firstIndex, lastIndex)) {
1298
- continue;
1884
+ return;
1299
1885
  }
1300
- this.violate(`${this.#context}: "${name}" must be ${position}, got index ${index}`);
1301
- }
1886
+ this.violate(ContractDiagnostics.positionViolation(name, position, index, this.#context));
1887
+ });
1302
1888
  }
1303
1889
  static #isValidPosition(matchIndex, position, firstIndex, lastIndex) {
1304
1890
  switch (position) {
@@ -1313,48 +1899,50 @@ var RuleValidator = class _RuleValidator extends StrictBase {
1313
1899
  }
1314
1900
  }
1315
1901
  };
1316
- var ChildrenEvaluator = class extends StrictBase {
1902
+
1903
+ // ../../lib/contract/src/children/children-evaluator.ts
1904
+ var ChildrenEvaluator = class extends InvariantBase {
1905
+ #context;
1317
1906
  #rules;
1318
1907
  #ruleNames;
1319
1908
  #matcher;
1320
1909
  #ruleValidator;
1321
- #matchBuilder;
1322
- constructor(rules, strict = "warn", context = "Component") {
1323
- super(strict);
1324
- this.#rules = rules.map((r2) => normalizeChildRule(r2));
1325
- this.#ruleNames = this.#rules.map((r2) => r2.name);
1326
- for (const rule of this.#rules) {
1910
+ constructor(rules, diagnostics, context = "Component") {
1911
+ super(diagnostics);
1912
+ this.#context = context;
1913
+ this.#rules = rules.map((r) => normalizeChildRule(r));
1914
+ this.#ruleNames = this.#rules.map((r) => r.name);
1915
+ iterate.forEach(this.#rules, (rule) => {
1327
1916
  const { name, position, cardinality } = rule;
1328
1917
  if ((position === "first" || position === "last") && (cardinality.kind === "unbounded" || cardinality.max > 1)) {
1329
1918
  throw new RangeError(
1330
1919
  `ChildrenEvaluator [${context}]: rule "${name}" sets position="${position}" with an unbound or >1 max. position="first|last" implies max=1.`
1331
1920
  );
1332
1921
  }
1333
- }
1922
+ });
1334
1923
  this.#matcher = new RuleMatcher(this.#rules);
1335
- this.#ruleValidator = new RuleValidator(context, strict);
1336
- this.#matchBuilder = new MatchValidationErrorBuilder(context);
1924
+ this.#ruleValidator = new RuleValidator(context, diagnostics);
1337
1925
  }
1338
1926
  evaluate(children) {
1339
- if (!this.strict) return;
1927
+ if (!this.active) return;
1340
1928
  const { matrix, unexpectedIndices, ambiguousIndices } = this.#matcher.match(children);
1341
1929
  this.#ruleValidator.validate(this.#rules, matrix, children.length);
1342
1930
  if (unexpectedIndices.size === 0 && ambiguousIndices.size === 0) return;
1343
- const errors = [];
1344
1931
  const violating = [...unexpectedIndices, ...ambiguousIndices].sort((a, b) => a - b);
1345
- for (const ci of violating) {
1932
+ iterate.forEach(violating, (ci) => {
1346
1933
  const typeName = getTypeName(children[ci]);
1347
1934
  if (unexpectedIndices.has(ci)) {
1348
- errors.push(this.#matchBuilder.unexpectedChild(typeName, ci));
1935
+ this.violate(ContractDiagnostics.unexpectedChild(typeName, ci, this.#context));
1349
1936
  } else {
1350
1937
  const matches = matrix.childToRules.forward.get(ci);
1351
1938
  const names = [...matches].map((ri) => this.#ruleNames[ri] ?? `#${ri}`);
1352
- errors.push(this.#matchBuilder.multipleMatches(typeName, ci, names));
1939
+ this.violate(ContractDiagnostics.ambiguousChild(typeName, ci, names, this.#context));
1353
1940
  }
1354
- }
1355
- this.invariant(errors.length === 0, this.#matchBuilder.toError(errors).message);
1941
+ });
1356
1942
  }
1357
1943
  };
1944
+
1945
+ // ../../lib/contract/src/props/get-disabled-props.ts
1358
1946
  var disabledProps = ({
1359
1947
  disabled,
1360
1948
  "aria-disabled": ariaDisabled,
@@ -1366,6 +1954,8 @@ var disabledProps = ({
1366
1954
  ...dataDisabled === void 0 && { "data-disabled": "" }
1367
1955
  };
1368
1956
  };
1957
+
1958
+ // ../../lib/contract/src/props/get-invalid-props.ts
1369
1959
  var invalidProps = ({
1370
1960
  invalid,
1371
1961
  "aria-invalid": ariaInvalid,
@@ -1377,6 +1967,8 @@ var invalidProps = ({
1377
1967
  ...dataInvalid === void 0 && { "data-invalid": "" }
1378
1968
  };
1379
1969
  };
1970
+
1971
+ // ../../lib/contract/src/props/get-readonly-props.ts
1380
1972
  var readonlyProps = ({
1381
1973
  readOnly,
1382
1974
  "aria-readonly": ariaReadonly,
@@ -1392,6 +1984,8 @@ var readonlyProps = ({
1392
1984
  }
1393
1985
  };
1394
1986
  };
1987
+
1988
+ // ../core/src/html/aria-rules.ts
1395
1989
  var LANDMARK_TAG_SET = /* @__PURE__ */ new Set(["article", "aside", "footer", "header", "main", "nav"]);
1396
1990
  var removeLandmarkRoleOverride = {
1397
1991
  kind: "removeRole",
@@ -1411,14 +2005,31 @@ function landmarkRoleRule({ tag, props, implicitRole }) {
1411
2005
  fixable: true,
1412
2006
  severity: "error",
1413
2007
  fix: removeLandmarkRoleOverride,
1414
- message: `<${tag}> has a fixed landmark role="${implicitRole}". role="${role}" overrides it and confuses assistive technology. The override has been removed.`
2008
+ diagnostic: HtmlDiagnostics.landmarkRoleOverride(tag, implicitRole, role)
1415
2009
  }
1416
2010
  ];
1417
2011
  }
1418
- var HTML_ARIA_RULES = [landmarkRoleRule];
2012
+ function requireAccessibleName({ tag, props }) {
2013
+ if ("aria-label" in props || "aria-labelledby" in props) return [];
2014
+ return [
2015
+ {
2016
+ valid: false,
2017
+ fixable: false,
2018
+ severity: "warning",
2019
+ diagnostic: AriaDiagnostics.missingAccessibleName(tag)
2020
+ }
2021
+ ];
2022
+ }
2023
+ var NAMED_LANDMARK_TAGS = /* @__PURE__ */ new Set(["nav", "aside"]);
2024
+ function landmarkNameAdvisory(ctx) {
2025
+ if (!ctx.implicitRole || !NAMED_LANDMARK_TAGS.has(ctx.tag)) return [];
2026
+ return requireAccessibleName(ctx);
2027
+ }
2028
+
2029
+ // ../core/src/html/contracts.ts
1419
2030
  function isOpenContent(...blockedTags) {
1420
- const set = new Set(blockedTags);
1421
- return (child) => isObject2(child) && "type" in child && (!isString(child.type) || !set.has(child.type));
2031
+ const set2 = new Set(blockedTags);
2032
+ return (child) => isObject(child) && "type" in child && (!isString(child.type) || !set2.has(child.type));
1422
2033
  }
1423
2034
  var METADATA_TAGS = ["script", "template"];
1424
2035
  var metadataMatch = isTag(...METADATA_TAGS);
@@ -1429,10 +2040,10 @@ function firstOptional(name, tag) {
1429
2040
  return { name, match: isTag(tag), cardinality: { max: 1 }, position: "first" };
1430
2041
  }
1431
2042
  function contract(children) {
1432
- return { strict: "warn", children };
2043
+ return { diagnostics: warnDiagnostics, children };
1433
2044
  }
1434
2045
  function ariaContract(aria) {
1435
- return { strict: "warn", aria };
2046
+ return { diagnostics: warnDiagnostics, aria };
1436
2047
  }
1437
2048
  function firstChildContract(name, tag) {
1438
2049
  return contract([firstOptional(name, tag), { name: "content", match: isOpenContent(tag) }]);
@@ -1519,7 +2130,15 @@ var textOnlyContract = contract([
1519
2130
  match: (child) => isString(child) || isNumber(child)
1520
2131
  }
1521
2132
  ]);
1522
- var landmarkContract = ariaContract([landmarkRoleRule]);
2133
+ var landmarkContract = ariaContract([landmarkRoleRule, landmarkNameAdvisory]);
2134
+ var dialogContract = ariaContract([requireAccessibleName]);
2135
+ var menuContract = ariaContract([requireAccessibleName]);
2136
+ var menubarContract = ariaContract([requireAccessibleName]);
2137
+ var treeContract = ariaContract([requireAccessibleName]);
2138
+ var gridContract = ariaContract([requireAccessibleName]);
2139
+ var listboxContract = ariaContract([requireAccessibleName]);
2140
+ var tablistContract = ariaContract([requireAccessibleName]);
2141
+ var radiogroupContract = ariaContract([requireAccessibleName]);
1523
2142
  var CONTRACT_GROUPS = [
1524
2143
  [VOID_TAGS, voidContract],
1525
2144
  [TEXT_ONLY_TAGS, textOnlyContract],
@@ -1546,19 +2165,28 @@ var htmlContracts = {
1546
2165
  figure: figureContract,
1547
2166
  details: detailsContract,
1548
2167
  fieldset: fieldsetContract,
2168
+ dialog: dialogContract,
1549
2169
  head: headContract,
1550
2170
  html: htmlContract
1551
2171
  };
2172
+
2173
+ // ../core/src/html/evaluators.ts
2174
+ var htmlDiagnostics = warnDiagnostics;
1552
2175
  function buildEvaluatorMap() {
1553
- const map = /* @__PURE__ */ new Map();
1554
- for (const [tag, { children }] of Object.entries(htmlContracts)) {
2176
+ const map2 = /* @__PURE__ */ new Map();
2177
+ iterate.forEachEntry(htmlContracts, (tag, { children }) => {
1555
2178
  if (children?.length) {
1556
- map.set(tag, new ChildrenEvaluator(children, "warn", `<${tag}>`));
2179
+ map2.set(tag, new ChildrenEvaluator(children, htmlDiagnostics, `<${tag}>`));
1557
2180
  }
1558
- }
1559
- return map;
2181
+ });
2182
+ return map2;
1560
2183
  }
1561
2184
  var HTML_EVALUATORS = buildEvaluatorMap();
2185
+ function getHtmlChildrenEvaluator(tag) {
2186
+ return typeof tag === "string" ? HTML_EVALUATORS.get(tag) : void 0;
2187
+ }
2188
+
2189
+ // ../core/src/html/prop-normalizers.ts
1562
2190
  var HTML_FORM_NORMALIZERS = /* @__PURE__ */ new Map([
1563
2191
  ["button", [disabledProps]],
1564
2192
  ["input", [disabledProps, readonlyProps, invalidProps]],
@@ -1571,241 +2199,93 @@ function getHtmlPropNormalizers(tag) {
1571
2199
  return typeof tag === "string" ? HTML_FORM_NORMALIZERS.get(tag) : void 0;
1572
2200
  }
1573
2201
 
1574
- // ../core/dist/chunk-3T4EM5FG.js
1575
- var falsyToString = (value) => typeof value === "boolean" ? `${value}` : value === 0 ? "0" : value;
1576
- var cx = clsx;
1577
- var cva = (base, config) => (props) => {
1578
- var _config_compoundVariants;
1579
- 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
- const { variants, defaultVariants } = config;
1581
- const getVariantClassNames = Object.keys(variants).map((variant) => {
1582
- const variantProp = props === null || props === void 0 ? void 0 : props[variant];
1583
- const defaultVariantProp = defaultVariants === null || defaultVariants === void 0 ? void 0 : defaultVariants[variant];
1584
- if (variantProp === null) return null;
1585
- const variantKey = falsyToString(variantProp) || falsyToString(defaultVariantProp);
1586
- return variants[variant][variantKey];
1587
- });
1588
- const propsWithoutUndefined = props && Object.entries(props).reduce((acc, param) => {
1589
- let [key, value] = param;
1590
- if (value === void 0) {
1591
- return acc;
1592
- }
1593
- acc[key] = value;
1594
- return acc;
1595
- }, {});
1596
- const getCompoundVariantClassNames = config === null || config === void 0 ? void 0 : (_config_compoundVariants = config.compoundVariants) === null || _config_compoundVariants === void 0 ? void 0 : _config_compoundVariants.reduce((acc, param) => {
1597
- let { class: cvClass, className: cvClassName, ...compoundVariantOptions } = param;
1598
- return Object.entries(compoundVariantOptions).every((param2) => {
1599
- let [key, value] = param2;
1600
- return Array.isArray(value) ? value.includes({
1601
- ...defaultVariants,
1602
- ...propsWithoutUndefined
1603
- }[key]) : {
1604
- ...defaultVariants,
1605
- ...propsWithoutUndefined
1606
- }[key] === value;
1607
- }) ? [
1608
- ...acc,
1609
- cvClass,
1610
- cvClassName
1611
- ] : acc;
1612
- }, []);
1613
- return cx(base, getVariantClassNames, getCompoundVariantClassNames, props === null || props === void 0 ? void 0 : props.class, props === null || props === void 0 ? void 0 : props.className);
1614
- };
1615
- function cva2(base, config) {
1616
- const fn = cva(base, config);
1617
- return (props) => cn(fn(props));
1618
- }
1619
- var StaticClassResolver = class {
1620
- #baseClass;
1621
- #cache = /* @__PURE__ */ new Map();
1622
- #resolveTag;
1623
- constructor(baseClass, tagMap) {
1624
- this.#baseClass = Array.isArray(baseClass) ? baseClass.join(" ") : baseClass;
1625
- this.#resolveTag = tagMap ? (tag) => {
1626
- const extra = tagMap[tag];
1627
- if (!extra) return this.#baseClass;
1628
- const extraStr = Array.isArray(extra) ? extra.join(" ") : extra;
1629
- return `${this.#baseClass} ${extraStr}`;
1630
- } : () => this.#baseClass;
1631
- }
1632
- resolve(tag, skipTagMap = false) {
1633
- if (typeof tag !== "string" || skipTagMap) return this.#baseClass;
1634
- const cached = this.#cache.get(tag);
1635
- if (cached !== void 0) {
1636
- this.#cache.delete(tag);
1637
- this.#cache.set(tag, cached);
1638
- return cached;
1639
- }
1640
- const result = this.#resolveTag(tag);
1641
- this.#cache.set(tag, result);
1642
- if (this.#cache.size > 200) {
1643
- const lru = this.#cache.keys().next().value;
1644
- if (lru !== void 0) this.#cache.delete(lru);
1645
- }
1646
- return result;
1647
- }
1648
- };
1649
- var VariantClassResolver = class _VariantClassResolver {
1650
- #cvaFn;
1651
- #recipeMap;
1652
- #variantKeys;
1653
- #precomputedClasses;
1654
- #cache = /* @__PURE__ */ new Map();
1655
- constructor(cvaFn, recipeMap, variantKeys, precomputedClasses) {
1656
- this.#cvaFn = cvaFn ?? null;
1657
- this.#recipeMap = Object.freeze(recipeMap ?? {});
1658
- this.#variantKeys = variantKeys ?? null;
1659
- this.#precomputedClasses = precomputedClasses ?? null;
1660
- }
1661
- resolve({ props, recipe }) {
1662
- const normalizedKey = recipe ?? "__none__";
1663
- const cacheKey = this.#createCacheKey(props, normalizedKey);
1664
- if (this.#precomputedClasses !== null) {
1665
- const precomputed = this.#precomputedClasses[cacheKey];
1666
- if (precomputed !== void 0) return precomputed;
1667
- }
1668
- const cached = this.#cache.get(cacheKey);
1669
- if (cached !== void 0) {
1670
- this.#cache.delete(cacheKey);
1671
- this.#cache.set(cacheKey, cached);
1672
- return cached;
1673
- }
1674
- const result = this.#compute(props, recipe);
1675
- this.#cache.set(cacheKey, result);
1676
- if (this.#cache.size > 1e3) {
1677
- const lru = this.#cache.keys().next().value;
1678
- if (lru !== void 0) this.#cache.delete(lru);
1679
- }
1680
- return result;
1681
- }
1682
- #compute(props, recipe) {
1683
- if (!this.#cvaFn) return "";
1684
- if (!recipe) return this.#cvaFn(props);
1685
- const preset = this.#recipeMap[recipe];
1686
- if (!preset) return this.#cvaFn(props);
1687
- return this.#cvaFn({ ...preset, ...props });
1688
- }
1689
- // When variantKeys is provided, only those keys are included in the cache key — non-variant
1690
- // props (className, id, etc.) produce identical CVA output and must not fragment the cache.
1691
- // Iterating #variantKeys directly (fixed Set insertion order) avoids Object.keys + filter + sort.
1692
- // String is built incrementally to avoid a parts[] array allocation on every render.
1693
- #createCacheKey(props, recipe) {
1694
- if (this.#variantKeys !== null) {
1695
- let key2 = recipe;
1696
- for (const k of this.#variantKeys) {
1697
- if (k in props) key2 += `|${k}:${_VariantClassResolver.#serializeValue(props[k])}`;
1698
- }
1699
- return key2;
1700
- }
1701
- let key = recipe;
1702
- for (const k of Object.keys(props).sort()) {
1703
- key += `|${k}:${_VariantClassResolver.#serializeValue(props[k])}`;
2202
+ // ../../lib/styling/src/variant-pass/compile-variant-lookup.ts
2203
+ function buildPrecomputedKey(props) {
2204
+ return Object.entries(props).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => `${k}:${v}`).join("|");
2205
+ }
2206
+
2207
+ // ../../lib/styling/src/variant-pass/variant-pass.ts
2208
+ function createVariantPass(activeProps, config) {
2209
+ return {
2210
+ name: "variant",
2211
+ execute() {
2212
+ const preset = typeof activeProps["preset"] === "string" ? activeProps["preset"] : void 0;
2213
+ const presetDefaults = preset !== void 0 && config.presets?.[preset] !== void 0 ? config.presets[preset] : {};
2214
+ const resolved = {
2215
+ ...config.defaults,
2216
+ ...presetDefaults,
2217
+ ...activeProps
2218
+ };
2219
+ const classes = [];
2220
+ iterate.forEachEntry(config.variants, (key, valueMap) => {
2221
+ const active = resolved[key];
2222
+ if (typeof active === "string") {
2223
+ const cls = valueMap[active];
2224
+ if (cls !== void 0) classes.push(cls);
2225
+ }
2226
+ });
2227
+ return { context: { classes } };
1704
2228
  }
1705
- return key;
1706
- }
1707
- static #serializeValue(value) {
1708
- if (value === void 0) return "u";
1709
- if (value === null) return "n";
1710
- if (typeof value === "boolean") return `b:${value}`;
1711
- if (typeof value === "string") return `s:${value}`;
1712
- return `x:${String(value)}`;
1713
- }
1714
- };
1715
- function createClassPipeline(resolved) {
1716
- const baseClass = resolved.baseClassName ?? "";
1717
- const cvaFn = resolved.variants ? cva2("", {
1718
- variants: resolved.variants,
1719
- defaultVariants: resolved.defaultVariants,
1720
- compoundVariants: resolved.compoundVariants
1721
- }) : null;
1722
- const variantKeys = resolved.variants ? new Set(Object.keys(resolved.variants)) : void 0;
1723
- const staticResolver = new StaticClassResolver(baseClass, resolved.tagMap);
1724
- const variantResolver = new VariantClassResolver(
1725
- cvaFn,
1726
- resolved.recipeMap,
1727
- variantKeys,
1728
- resolved.precomputedClasses
1729
- );
1730
- return function resolveClasses(tag, props, className, recipe) {
1731
- const staticClasses = staticResolver.resolve(tag, recipe !== void 0);
1732
- const variantClasses = variantResolver.resolve({ props, recipe });
1733
- if (!className)
1734
- return staticClasses && variantClasses ? `${staticClasses} ${variantClasses}` : staticClasses || variantClasses;
1735
- return cn(staticClasses, variantClasses, className);
1736
2229
  };
1737
2230
  }
1738
2231
 
1739
- // ../core/dist/index.js
1740
- var FULL_CAPABILITIES = {
1741
- createClassPipeline,
1742
- AriaEngine: AriaPolicyEngine,
1743
- htmlAriaRules: HTML_ARIA_RULES,
1744
- htmlPropNormalizersFn: getHtmlPropNormalizers
1745
- };
1746
- function createPolymorphic2(options = {}) {
1747
- return createPolymorphic(options, FULL_CAPABILITIES);
2232
+ // ../core/src/resolver/resolver.ts
2233
+ function enforceAllowedAs(tag, allowedAs, diagnostics, displayName) {
2234
+ if (allowedAs.includes(tag)) return;
2235
+ if (!diagnostics) return;
2236
+ const component = displayName ?? String(tag);
2237
+ diagnostics.error(ContractDiagnostics.allowedAsViolation(String(tag), allowedAs, component));
1748
2238
  }
1749
2239
 
1750
- // ../../lib/adapter-utils/src/build-core-runtime.ts
1751
- var EMPTY_SET = /* @__PURE__ */ new Set();
1752
- function buildCoreRuntime(normalized) {
1753
- const runtime = createPolymorphic2(normalized);
1754
- const ownedKeys = "classPlugin" in runtime ? runtime.classPlugin.ownedKeys ?? EMPTY_SET : EMPTY_SET;
1755
- return { runtime, ownedKeys };
2240
+ // ../../lib/adapter-utils/src/apply-prop-normalizers.ts
2241
+ function applyPropNormalizers(tag, props, additional) {
2242
+ const normalizers = [...getHtmlPropNormalizers(tag) ?? [], ...additional ?? []];
2243
+ if (normalizers.length === 0) return props;
2244
+ return normalizers.reduce((acc, fn) => ({ ...acc, ...fn(acc) }), props);
1756
2245
  }
1757
2246
 
1758
- // ../../lib/adapter-utils/src/build-engines.ts
1759
- function buildEngines(strict, childRules, context) {
1760
- return childRules?.length ? { childrenEvaluator: new ChildrenEvaluator(childRules, strict, context) } : {};
2247
+ // ../../lib/adapter-utils/src/define-component.ts
2248
+ function defineContractComponent(options) {
2249
+ return (factory) => factory(options);
1761
2250
  }
1762
2251
 
1763
- // ../../lib/adapter-utils/src/compose-filter.ts
1764
- function composeFilter(ownedKeys, filterProps) {
1765
- const defaultFilter = (key, variantKeys) => variantKeys.has(key) || ownedKeys.has(key);
1766
- if (!filterProps) {
1767
- return defaultFilter;
1768
- }
1769
- return (key, variantKeys) => defaultFilter(key, variantKeys) || filterProps(key, variantKeys);
2252
+ // ../../lib/adapter-utils/src/build-engines.ts
2253
+ function buildEngines(diagnostics, childRules, context) {
2254
+ return childRules?.length ? { childrenEvaluator: new ChildrenEvaluator(childRules, diagnostics, context) } : {};
1770
2255
  }
1771
2256
 
1772
2257
  // ../../lib/adapter-utils/src/resolve-adapter-common-options.ts
1773
- function resolveAdapterCommonOptions(options, defaultName = "PolymorphicComponent", defaultStrict = "throw") {
2258
+ function resolveAdapterCommonOptions(options, defaultName = "PolymorphicComponent", defaultDiagnostics = throwDiagnostics) {
1774
2259
  return {
1775
2260
  name: options.name ?? defaultName,
1776
- strict: options.enforcement?.strict ?? defaultStrict
2261
+ diagnostics: options.enforcement?.diagnostics ?? defaultDiagnostics
1777
2262
  };
1778
2263
  }
1779
2264
 
1780
2265
  // ../../lib/adapter-utils/src/slot-validator.ts
1781
- var SlotValidator = class extends StrictBase {
2266
+ var SlotValidator = class extends InvariantBase {
1782
2267
  #name;
1783
2268
  #elementTerm;
1784
- constructor(name, strict, elementTerm) {
1785
- super(strict);
2269
+ constructor(name, diagnostics, elementTerm) {
2270
+ super(diagnostics);
1786
2271
  this.#name = name;
1787
2272
  this.#elementTerm = elementTerm;
1788
2273
  }
1789
2274
  assertExclusive() {
1790
- this.violate(`${this.#name}: "as" and "asChild" are mutually exclusive`);
2275
+ this.violate(SlotDiagnostics.exclusive(this.#name));
1791
2276
  }
1792
2277
  warnDiscardedChildren(count) {
1793
- const suffix = count === 1 ? "" : "ren";
1794
- this.warn(
1795
- `${this.#name}: asChild discarded ${count} non-element child${suffix} \u2014 only ${this.#elementTerm}s are valid asChild children.`
1796
- );
2278
+ this.warn(SlotDiagnostics.discardedChildren(this.#name, this.#elementTerm, count));
1797
2279
  }
1798
2280
  assertSingleChild(count) {
1799
- const msg = count === 0 ? `${this.#name}: asChild requires a ${this.#elementTerm} child` : `${this.#name}: asChild requires exactly one ${this.#elementTerm} child, got ${count}`;
1800
- this.violate(msg);
2281
+ this.violate(
2282
+ count === 0 ? SlotDiagnostics.singleChildRequired(this.#name, this.#elementTerm) : SlotDiagnostics.singleChildExceeded(this.#name, this.#elementTerm, count)
2283
+ );
1801
2284
  }
1802
2285
  };
1803
2286
 
1804
- // ../shared/src/constants/primitive/slot-name.ts
1805
- var SLOT_NAME = "Slot";
1806
-
1807
2287
  // ../../lib/adapter-utils/src/slot/policies.ts
1808
- import { clsx as clsx2 } from "clsx";
2288
+ import { clsx } from "clsx";
1809
2289
  function chainHandlers(childHandler, slotHandler) {
1810
2290
  return (...args) => {
1811
2291
  childHandler(...args);
@@ -1816,7 +2296,7 @@ function chainHandlers(childHandler, slotHandler) {
1816
2296
  };
1817
2297
  }
1818
2298
  function mergeClassNames(slot, child) {
1819
- return clsx2(slot, child);
2299
+ return clsx(slot, child);
1820
2300
  }
1821
2301
  function mergeStyles(slot, child) {
1822
2302
  if (!isPlainObject(slot) || !isPlainObject(child)) return child;
@@ -1832,10 +2312,10 @@ var policyHandlers = {
1832
2312
  // ../../lib/adapter-utils/src/slot/merge-slot-props.ts
1833
2313
  function mergeSlotProps(slotProps, childProps) {
1834
2314
  const merged = { ...slotProps };
1835
- for (const key in childProps) {
1836
- if (!Object.hasOwn(childProps, key)) continue;
2315
+ iterate.forEachKey(childProps, (key) => {
2316
+ if (!Object.hasOwn(childProps, key)) return;
1837
2317
  merged[key] = applyMergePolicy(key, slotProps[key], childProps[key]);
1838
- }
2318
+ });
1839
2319
  return merged;
1840
2320
  }
1841
2321
  function classifyProp(key, slotVal, childVal) {
@@ -1848,270 +2328,451 @@ function applyMergePolicy(key, slotVal, childVal) {
1848
2328
  return policyHandlers[classifyProp(key, slotVal, childVal)](slotVal, childVal);
1849
2329
  }
1850
2330
 
1851
- // ../../adapters/preact/src/slot/Slot.tsx
1852
- import { forwardRef } from "preact/compat";
1853
-
1854
- // ../../adapters/preact/src/slot/applySlot.ts
1855
- import { isValidElement as isValidElement4 } from "preact";
1856
-
1857
- // ../../adapters/preact/src/slot/invariant.ts
1858
- function panic2(message) {
1859
- throw new Error(message);
1860
- }
1861
- function invariant(condition, message) {
1862
- if (!condition) panic2(message);
2331
+ // ../../lib/adapter-utils/src/build-definition.ts
2332
+ function buildDefinition(name, tag) {
2333
+ return {
2334
+ identity: {
2335
+ id: name,
2336
+ name,
2337
+ tag
2338
+ },
2339
+ capabilities: {},
2340
+ metadata: {},
2341
+ diagnostics: []
2342
+ };
1863
2343
  }
1864
2344
 
1865
- // ../../adapters/preact/src/slot/extractSlottable.ts
1866
- import { h, Fragment as Fragment2, isValidElement as isValidElement3 } from "preact";
1867
-
1868
- // ../../adapters/preact/src/slot/predicates.ts
1869
- import { isValidElement as isValidElement2 } from "preact";
1870
-
1871
- // ../../adapters/preact/src/slot/Slottable.tsx
1872
- import { Fragment } from "preact";
1873
- import { jsx } from "preact/jsx-runtime";
1874
- function Slottable({ children }) {
1875
- return /* @__PURE__ */ jsx(Fragment, { children });
1876
- }
1877
-
1878
- // ../../adapters/preact/src/slot/predicates.ts
1879
- function isSlottableElement(value) {
1880
- return isValidElement2(value) && value.type === Slottable;
1881
- }
1882
-
1883
- // ../../adapters/preact/src/slot/extractSlottable.ts
1884
- function extractSlottable(children) {
1885
- const childrenArray = Array.isArray(children) ? children : [children];
1886
- const slottables = childrenArray.filter(isSlottableElement);
1887
- invariant(slottables.length <= 1, "Slot: multiple Slottable children are not allowed");
1888
- if (slottables.length === 0) return null;
1889
- const [slottable] = slottables;
1890
- invariant(slottable, "Missing Slottable element");
1891
- const child = slottable.props.children;
1892
- invariant(
1893
- child !== null && child !== void 0,
1894
- "Slottable expects exactly one Preact element child, received null"
2345
+ // ../../lib/adapter-utils/src/build-variant-config.ts
2346
+ function flattenClassName(cls) {
2347
+ return Array.isArray(cls) ? cls.join(" ") : cls;
2348
+ }
2349
+ function mapVariantRecord(source, mapper) {
2350
+ return iterate.mapValues(
2351
+ source,
2352
+ (inner) => iterate.mapValues(inner, mapper)
1895
2353
  );
1896
- invariant(
1897
- typeof child !== "string" && typeof child !== "number",
1898
- "Slottable expects exactly one Preact element child, received text content"
1899
- );
1900
- invariant(isValidElement3(child), "Slottable expects exactly one Preact element child");
1901
- invariant(child.type !== Fragment2, "Slottable child cannot be a Fragment");
1902
- const index = childrenArray.indexOf(slottable);
2354
+ }
2355
+ function buildVariantConfig(variants, presets, defaults, compounds) {
1903
2356
  return {
1904
- child,
1905
- rebuild(merged) {
1906
- const out = childrenArray.map((node, i) => i === index ? merged : node);
1907
- return h(Fragment2, null, ...out);
2357
+ variants: mapVariantRecord(variants ?? {}, flattenClassName),
2358
+ ...presets !== void 0 && Object.keys(presets).length > 0 && { presets },
2359
+ ...defaults !== void 0 && Object.keys(defaults).length > 0 && { defaults },
2360
+ ...compounds !== void 0 && compounds.length > 0 && {
2361
+ compounds
1908
2362
  }
1909
2363
  };
1910
2364
  }
1911
2365
 
1912
- // ../../adapters/preact/src/slot/applySlot.ts
1913
- function applySlot(children, slotProps, ref, cloneSlotChild2) {
1914
- const extraction = extractSlottable(children);
1915
- if (extraction) {
1916
- const merged = cloneSlotChild2({ child: extraction.child, slotProps, ref });
1917
- return extraction.rebuild(merged);
2366
+ // ../../runtime/core/src/apply-attributes.ts
2367
+ function applyAttributes(nodeId, incoming, decoration, removedKeys) {
2368
+ const existing = decoration[nodeId] ?? {};
2369
+ const next = { ...existing.attributes };
2370
+ if (removedKeys !== void 0) {
2371
+ iterate.forEachSet(removedKeys, (key) => {
2372
+ delete next[key];
2373
+ });
1918
2374
  }
1919
- invariant(isValidElement4(children), "Slot: child must be a valid Preact element");
1920
- return cloneSlotChild2({ child: children, slotProps, ref });
2375
+ Object.assign(next, incoming);
2376
+ const { attributes: _dropped, ...rest } = existing;
2377
+ const nextDecoration = Object.keys(next).length > 0 ? { ...rest, attributes: next } : rest;
2378
+ return { ...decoration, [nodeId]: nextDecoration };
1921
2379
  }
1922
2380
 
1923
- // ../../adapters/preact/src/slot/cloneSlotChild.ts
1924
- import { cloneElement, Fragment as Fragment3 } from "preact";
2381
+ // ../../runtime/core/src/get-active-props.ts
2382
+ function getActiveProps(nodeId, decoration) {
2383
+ const dec = decoration[nodeId];
2384
+ return { ...dec?.attributes ?? {}, ...dec?.variants ?? {} };
2385
+ }
1925
2386
 
1926
- // ../../adapters/preact/src/slot/composeRefs.ts
1927
- function mergeRefs(...refs) {
1928
- const active = refs.filter((r2) => r2 != null);
1929
- if (active.length === 0) return null;
1930
- if (active.length === 1) return active[0];
1931
- return (value) => {
1932
- for (const ref of active) {
1933
- if (typeof ref === "function") {
1934
- ref(value);
1935
- } else {
1936
- ref.current = value;
1937
- }
1938
- }
1939
- };
2387
+ // ../../runtime/core/src/render-component.ts
2388
+ function renderComponent(definition, tree, render, backend) {
2389
+ return backend.render({ definition, tree, render });
1940
2390
  }
1941
- function getChildRef(child) {
1942
- const ref = child.ref;
1943
- return ref ?? null;
2391
+
2392
+ // ../../runtime/core/src/build-tree-context.ts
2393
+ function buildNode(input, slotAssignments, seenIds, diagnostics) {
2394
+ if (seenIds.has(input.id)) {
2395
+ diagnostics.push({
2396
+ code: "duplicate-node-id",
2397
+ message: `Duplicate node id "${input.id}"`,
2398
+ severity: "error"
2399
+ });
2400
+ } else {
2401
+ seenIds.add(input.id);
2402
+ }
2403
+ if (input.slot !== void 0) {
2404
+ slotAssignments.set(input.id, input.slot);
2405
+ }
2406
+ const children = Object.freeze(
2407
+ (input.children ?? []).map((child) => buildNode(child, slotAssignments, seenIds, diagnostics))
2408
+ );
2409
+ if (input.kind === "native") {
2410
+ return Object.freeze({ kind: "native", id: input.id, tag: input.tag, children });
2411
+ }
2412
+ return Object.freeze({ kind: "component", id: input.id, children });
2413
+ }
2414
+ function buildTreeContext(root) {
2415
+ const slotAssignments = /* @__PURE__ */ new Map();
2416
+ const diagnostics = [];
2417
+ const rootNode = buildNode(root, slotAssignments, /* @__PURE__ */ new Set(), diagnostics);
2418
+ return Object.freeze({ root: rootNode, slotAssignments, diagnostics });
1944
2419
  }
1945
2420
 
1946
- // ../../adapters/preact/src/slot/cloneSlotChild.ts
1947
- function cloneSlotChild({ child, slotProps, ref }) {
1948
- const childProps = child.props;
1949
- const isFragment = child.type === Fragment3;
1950
- const childRef = isFragment ? null : getChildRef(child);
1951
- const mergedRef = isFragment ? null : mergeRefs(ref, childRef);
1952
- const merged = mergeSlotProps(slotProps, childProps);
1953
- return cloneElement(child, mergedRef !== null ? { ...merged, ref: mergedRef } : merged);
2421
+ // ../../runtime/core/src/build-render-context.ts
2422
+ function buildRenderContext(decoration = {}) {
2423
+ return { decoration: new Map(Object.entries(decoration)) };
1954
2424
  }
1955
2425
 
1956
- // ../../adapters/preact/src/slot/Slot.tsx
1957
- var Slot = forwardRef(function Slot2({ children, ...slotProps }, ref) {
1958
- return applySlot(children, slotProps, ref ?? null, cloneSlotChild);
1959
- });
1960
- Object.assign(Slot, { displayName: SLOT_NAME });
2426
+ // ../../lib/adapter-utils/src/resolve-compounds.ts
2427
+ function matchesCompound(active, compound) {
2428
+ const { class: _, ...conditions } = compound;
2429
+ return Object.entries(conditions).every(([key, expected]) => {
2430
+ const actual = active[key];
2431
+ return Array.isArray(expected) ? expected.includes(actual) : actual === expected;
2432
+ });
2433
+ }
2434
+ function resolveCompounds(active, compounds) {
2435
+ if (!compounds?.length) return [];
2436
+ const out = [];
2437
+ iterate.forEach(compounds, (compound) => {
2438
+ if (matchesCompound(active, compound)) {
2439
+ out.push(flattenClassName(compound.class));
2440
+ }
2441
+ });
2442
+ return out;
2443
+ }
1961
2444
 
1962
- // ../../adapters/preact/src/slot/slot-validator.ts
1963
- var SlotValidator2 = class extends SlotValidator {
1964
- constructor(name, strict) {
1965
- super(name, strict, "Preact element");
2445
+ // ../../lib/adapter-utils/src/resolve-classes.ts
2446
+ function resolveClasses(decoration, variantConfig, variantDefaults, recipe, compounds, variantLookup) {
2447
+ const active = getActiveProps("root", decoration);
2448
+ if (variantLookup !== void 0 && recipe === void 0) {
2449
+ const activeVariants = {};
2450
+ iterate.forEachKey(variantConfig.variants, (key) => {
2451
+ const value = active[key];
2452
+ if (typeof value === "string") activeVariants[key] = value;
2453
+ });
2454
+ const lookupKey = buildPrecomputedKey(activeVariants);
2455
+ const precomputedValue = variantLookup[lookupKey];
2456
+ if (precomputedValue !== void 0) {
2457
+ return {
2458
+ variantClasses: precomputedValue !== "" ? [precomputedValue] : [],
2459
+ compoundClasses: []
2460
+ };
2461
+ }
1966
2462
  }
1967
- };
2463
+ const passInput = recipe !== void 0 ? { ...active, preset: recipe } : active;
2464
+ const { context } = createVariantPass(passInput, variantConfig).execute({ classes: [] });
2465
+ const variantClasses = context.classes;
2466
+ const presetOverrides = recipe !== void 0 ? variantConfig.presets?.[recipe] ?? {} : {};
2467
+ const resolvedValues = {
2468
+ ...variantDefaults,
2469
+ ...presetOverrides,
2470
+ ...active
2471
+ };
2472
+ const compoundClasses = resolveCompounds(resolvedValues, compounds);
2473
+ return { variantClasses, compoundClasses };
2474
+ }
1968
2475
 
1969
- // ../../adapters/preact/src/build-runtime.ts
1970
- function normalizeOptions(options) {
2476
+ // ../../lib/adapter-utils/src/build-pipeline.ts
2477
+ function buildStylePipeline(variants, presets, defaults, compounds, variantLookup) {
2478
+ if (variants === void 0 && compounds === void 0 && presets === void 0 && variantLookup === void 0) {
2479
+ return void 0;
2480
+ }
2481
+ const variantConfig = buildVariantConfig(variants, presets, defaults, compounds);
1971
2482
  return {
1972
- ...options,
1973
- slotComponent: options.slotComponent ?? Slot,
1974
- ...resolveAdapterCommonOptions(options)
2483
+ execute(decoration, recipe) {
2484
+ return resolveClasses(decoration, variantConfig, defaults, recipe, compounds, variantLookup);
2485
+ }
1975
2486
  };
1976
2487
  }
1977
- function buildRuntime(options) {
1978
- const normalized = normalizeOptions(options);
1979
- const { runtime, ownedKeys } = buildCoreRuntime(normalized);
1980
- const slotValidator = new SlotValidator2(normalized.name, normalized.strict);
1981
- const { childrenEvaluator } = buildEngines(
1982
- normalized.strict,
1983
- normalized.enforcement?.children,
1984
- normalized.name
1985
- );
1986
- const filterProps = composeFilter(ownedKeys, normalized.filterProps);
2488
+
2489
+ // ../../lib/adapter-utils/src/join-classes.ts
2490
+ function joinClasses(...classes) {
2491
+ return classes.filter(Boolean).join(" ");
2492
+ }
2493
+
2494
+ // ../../lib/adapter-utils/src/decoration-utils.ts
2495
+ function withAttributes(dec, attributes) {
2496
+ const { attributes: _a, ...rest } = dec;
2497
+ return attributes !== void 0 ? { ...rest, attributes } : rest;
2498
+ }
2499
+
2500
+ // ../../lib/adapter-utils/src/apply-aria.ts
2501
+ function applyAria(decoration, tag, ariaEngine) {
2502
+ if (ariaEngine === void 0) return decoration;
2503
+ const dec = decoration["root"];
2504
+ if (dec?.attributes === void 0) return decoration;
2505
+ const result = ariaEngine.validate(tag, dec.attributes);
2506
+ const cleaned = result.props;
1987
2507
  return {
1988
- runtime,
1989
- slotComponent: normalized.slotComponent,
1990
- normalizeChildren,
1991
- slotValidator,
1992
- filterProps,
1993
- ...childrenEvaluator !== void 0 && { childrenEvaluator }
2508
+ ...decoration,
2509
+ root: withAttributes(dec, Object.keys(cleaned).length > 0 ? cleaned : void 0)
1994
2510
  };
1995
2511
  }
1996
2512
 
1997
- // ../../adapters/preact/src/render.ts
1998
- import { h as h2 } from "preact";
1999
- function buildDirectives(as, asChild) {
2513
+ // ../../lib/adapter-utils/src/apply-filter-props.ts
2514
+ function applyFilterProps(decoration, filterFn, variantKeys) {
2515
+ if (filterFn === void 0) return decoration;
2516
+ const dec = decoration["root"];
2517
+ if (dec?.attributes === void 0) return decoration;
2518
+ const kept = Object.fromEntries(
2519
+ Object.entries(dec.attributes).filter(([k]) => !filterFn(k, variantKeys))
2520
+ );
2000
2521
  return {
2001
- ...as !== void 0 && { as },
2002
- ...asChild !== void 0 && { asChild }
2522
+ ...decoration,
2523
+ root: withAttributes(dec, Object.keys(kept).length > 0 ? kept : void 0)
2003
2524
  };
2004
2525
  }
2005
- function buildRenderState(tag, directives, props, className, children) {
2006
- const state = { tag, directives, props, className };
2007
- if (children !== void 0) state.children = children;
2008
- return state;
2009
- }
2010
- function resolveRenderState(runtime, props, filterProps) {
2011
- const { as, asChild, children, className, recipe, ...rest } = props;
2012
- const tag = runtime.resolveTag(as);
2013
- const mergedProps = runtime.resolveProps(rest);
2014
- const baseProps = runtime.options.normalizeFn ? runtime.options.normalizeFn(mergedProps) : mergedProps;
2015
- const htmlNormalizers = runtime.options.htmlPropNormalizersFn?.(tag);
2016
- const normalizedProps = htmlNormalizers?.length ? htmlNormalizers.reduce((acc, fn) => ({ ...acc, ...fn(acc) }), baseProps) : baseProps;
2017
- const resolvedClass = runtime.resolveClasses(tag, normalizedProps, className, recipe);
2018
- const filteredProps = applyFilter(normalizedProps, filterProps, runtime.options.variantKeys);
2019
- return buildRenderState(tag, buildDirectives(as, asChild), filteredProps, resolvedClass, children);
2020
- }
2021
- function warnDiscardedChildren(originalChildren, normalizedChildren, validator) {
2022
- if (!Array.isArray(originalChildren)) return;
2023
- const discarded = originalChildren.length - normalizedChildren.length;
2024
- if (discarded > 0) validator.warnDiscardedChildren(discarded);
2025
- }
2026
- function isSingleElementArray(arr) {
2027
- return arr.length === 1;
2028
- }
2029
- function resolveSlotChildren(children, normalized, validator) {
2030
- warnDiscardedChildren(children, normalized, validator);
2031
- if (isSingleElementArray(normalized)) {
2032
- return normalized[0];
2033
- }
2034
- if (normalized.length > 1 && normalized.some(isSlottableElement)) {
2035
- return normalized;
2036
- }
2037
- validator.assertSingleChild(normalized.length);
2038
- return null;
2526
+
2527
+ // ../../lib/adapter-utils/src/apply-ref.ts
2528
+ function applyRef(decoration, ref) {
2529
+ if (ref == null) return decoration;
2530
+ const existing = decoration["root"] ?? {};
2531
+ return { ...decoration, root: { ...existing, ref } };
2532
+ }
2533
+
2534
+ // ../../adapters/preact/src/create-contract-component.ts
2535
+ import { forwardRef } from "preact/compat";
2536
+
2537
+ // ../../adapters/preact/src/backend/extract-decoration.ts
2538
+ function isStyleValue(v) {
2539
+ return isString(v) || isNumber(v);
2540
+ }
2541
+ function isAttributeValue(v) {
2542
+ return isString(v) || isNumber(v) || typeof v === "boolean";
2543
+ }
2544
+ function assignIfNotEmpty(target, key, value) {
2545
+ if (Object.keys(value).length > 0) {
2546
+ target[key] = value;
2547
+ }
2039
2548
  }
2040
- function validateSlotDirectives(directives, validator) {
2041
- const { as, asChild } = directives;
2042
- if (!asChild) return false;
2043
- if (as !== void 0) {
2044
- validator.assertExclusive();
2549
+ function extractStyles(value, styles) {
2550
+ if (!isObject(value)) return false;
2551
+ iterate.forEachEntry(value, (k, v) => {
2552
+ if (isStyleValue(v)) {
2553
+ styles[k] = v;
2554
+ }
2555
+ });
2556
+ return true;
2557
+ }
2558
+ function extractListener(key, value, listeners) {
2559
+ if (!key.startsWith("on") || !isFunction(value)) {
2045
2560
  return false;
2046
2561
  }
2562
+ listeners[key] = value;
2047
2563
  return true;
2048
2564
  }
2049
- function resolveSlotRender(state, getNormalized, validator) {
2050
- if (!validateSlotDirectives(state.directives, validator)) return null;
2051
- const child = resolveSlotChildren(state.children, getNormalized(), validator);
2052
- if (child === null) return null;
2053
- return { child };
2054
- }
2055
- function renderResolvedSlot(slotComponent, state, resolved, ref) {
2056
- return h2(slotComponent, {
2057
- ...state.props,
2058
- className: state.className,
2059
- ref,
2060
- children: resolved.child
2565
+ function extractAttributeOrVariant(key, value, attributes, variants, variantKeys) {
2566
+ if (variantKeys?.has(key)) {
2567
+ variants[key] = value;
2568
+ } else {
2569
+ attributes[key] = value;
2570
+ }
2571
+ }
2572
+ function extractDecoration(props, variantKeys) {
2573
+ const attributes = {};
2574
+ const styles = {};
2575
+ const listeners = {};
2576
+ const variants = {};
2577
+ const dec = {};
2578
+ iterate.forEachEntry(props, (key, value) => {
2579
+ if (key === "children" || key === "slot" || key === "ref") return;
2580
+ if (key === "style" && extractStyles(value, styles)) return;
2581
+ if (extractListener(key, value, listeners)) return;
2582
+ if (isAttributeValue(value)) {
2583
+ extractAttributeOrVariant(key, value, attributes, variants, variantKeys);
2584
+ }
2061
2585
  });
2586
+ assignIfNotEmpty(dec, "attributes", attributes);
2587
+ assignIfNotEmpty(dec, "styles", styles);
2588
+ assignIfNotEmpty(dec, "listeners", listeners);
2589
+ assignIfNotEmpty(dec, "variants", variants);
2590
+ const ref = props.ref;
2591
+ if (ref !== void 0) {
2592
+ dec.ref = ref;
2593
+ }
2594
+ return dec;
2062
2595
  }
2063
- function tryRenderAsChild(state, ref, slotComponent, getNormalized, validator) {
2064
- const resolved = resolveSlotRender(state, getNormalized, validator);
2065
- if (resolved === null) return null;
2066
- return renderResolvedSlot(slotComponent, state, resolved, ref);
2067
- }
2068
- function buildElementProps(props, className, ref, children) {
2069
- const { role, ...rest } = props;
2596
+
2597
+ // ../../adapters/preact/src/helpers/render-normally.ts
2598
+ import { cloneElement } from "preact";
2599
+
2600
+ // ../../adapters/preact/src/backend/preact-backend.ts
2601
+ import { Fragment, h } from "preact";
2602
+
2603
+ // ../../adapters/preact/src/backend/build-props.ts
2604
+ function buildPropsFromDecoration(id, decoration) {
2070
2605
  return {
2071
- ...rest,
2072
- className,
2073
- ref,
2074
- ...children !== void 0 && { children },
2075
- ...isKnownAriaRole(role) && { role }
2606
+ key: id,
2607
+ ...decoration?.attributes,
2608
+ ...decoration?.styles !== void 0 ? { style: decoration.styles } : {},
2609
+ ...decoration?.listeners,
2610
+ ...decoration?.ref !== void 0 ? { ref: decoration.ref } : {}
2611
+ };
2612
+ }
2613
+
2614
+ // ../../adapters/preact/src/backend/preact-backend.ts
2615
+ function renderNode(node, render) {
2616
+ const children = node.children.map((child) => renderNode(child, render));
2617
+ if (node.kind === "component") {
2618
+ return h(Fragment, { key: node.id }, ...children);
2619
+ }
2620
+ const decoration = render.decoration.get(node.id);
2621
+ const props = buildPropsFromDecoration(node.id, decoration);
2622
+ return h(node.tag, props, ...children);
2623
+ }
2624
+ var preactBackend = {
2625
+ render(context) {
2626
+ return renderNode(context.tree.root, context.render);
2627
+ }
2628
+ };
2629
+
2630
+ // ../../adapters/preact/src/helpers/render-normally.ts
2631
+ function renderNormally(definition, tag, decoration, children) {
2632
+ const treeCtx = buildTreeContext({ kind: "native", tag, id: "root", children: [] });
2633
+ const rendered = renderComponent(
2634
+ definition,
2635
+ treeCtx,
2636
+ buildRenderContext(decoration),
2637
+ preactBackend
2638
+ );
2639
+ return children === void 0 ? rendered : cloneElement(rendered, {}, children);
2640
+ }
2641
+
2642
+ // ../../adapters/preact/src/helpers/make-render-as-child.ts
2643
+ import { isValidElement } from "preact";
2644
+ function makeRenderAsChild(cloneSlotChild2) {
2645
+ return function renderAsChild(children, className, ref) {
2646
+ if (!isValidElement(children)) throw new Error("asChild requires a Preact element child");
2647
+ const slotProps = className ? { className } : {};
2648
+ return cloneSlotChild2({ child: children, slotProps, ref: ref ?? null });
2076
2649
  };
2077
2650
  }
2078
- function renderIntrinsic(state, ref, runtime) {
2079
- const elementProps = buildElementProps(state.props, state.className, ref, state.children);
2080
- const domProps = typeof state.tag === "string" ? runtime.resolveAria(state.tag, elementProps).props : elementProps;
2081
- return h2(state.tag, domProps);
2082
- }
2083
- function render({
2084
- runtime,
2085
- props,
2086
- ref,
2087
- slotComponent,
2088
- normalizeChildren: normalizeChildren2,
2089
- filterProps,
2090
- slotValidator,
2091
- childrenEvaluator
2092
- }) {
2093
- const state = resolveRenderState(runtime, props, filterProps);
2094
- let cached;
2095
- const once = () => cached ??= normalizeChildren2(state.children);
2096
- if (process.env.NODE_ENV !== "production") childrenEvaluator?.evaluate(once());
2097
- const slotResult = tryRenderAsChild(state, ref, slotComponent, once, slotValidator);
2098
- return slotResult ?? renderIntrinsic(state, ref, runtime);
2651
+
2652
+ // ../../adapters/preact/src/normalize-children.ts
2653
+ import { isValidElement as isValidElement2 } from "preact";
2654
+ function normalizeChildren(children) {
2655
+ if (isValidElement2(children)) return [children];
2656
+ if (Array.isArray(children)) return children.filter(isValidElement2);
2657
+ return [];
2658
+ }
2659
+
2660
+ // ../../adapters/preact/src/slot/cloneSlotChild.ts
2661
+ import { cloneElement as cloneElement2, Fragment as Fragment2 } from "preact";
2662
+
2663
+ // ../../adapters/preact/src/slot/composeRefs.ts
2664
+ function mergeRefs(...refs) {
2665
+ return mergeRefsCore(...refs);
2666
+ }
2667
+ function getChildRef(child) {
2668
+ const ref = child.ref;
2669
+ return ref ?? null;
2670
+ }
2671
+
2672
+ // ../../adapters/preact/src/slot/cloneSlotChild.ts
2673
+ function cloneSlotChild({ child, slotProps, ref }) {
2674
+ const childProps = child.props;
2675
+ const isFragment = child.type === Fragment2;
2676
+ const childRef = isFragment ? null : getChildRef(child);
2677
+ const mergedRef = isFragment ? null : mergeRefs(ref, childRef);
2678
+ const merged = mergeSlotProps(slotProps, childProps);
2679
+ return cloneElement2(child, mergedRef !== null ? { ...merged, ref: mergedRef } : merged);
2680
+ }
2681
+
2682
+ // ../../adapters/preact/src/slot/Slottable.tsx
2683
+ import { Fragment as Fragment3 } from "preact";
2684
+ import { jsx } from "preact/jsx-runtime";
2685
+ function Slottable({ children }) {
2686
+ return /* @__PURE__ */ jsx(Fragment3, { children });
2099
2687
  }
2100
2688
 
2101
2689
  // ../../adapters/preact/src/create-contract-component.ts
2690
+ var EMPTY_SET = /* @__PURE__ */ new Set();
2102
2691
  function createContractComponent(options) {
2103
- const bundle = buildRuntime(options);
2104
- const Component = forwardRef2(function Component2(props, ref) {
2105
- return render({
2106
- ...bundle,
2107
- normalizeChildren,
2108
- props,
2109
- ref: ref ?? null
2110
- });
2692
+ const resolved = resolveAdapterCommonOptions(options);
2693
+ const displayName = resolved.name;
2694
+ const defaultTag = options.tag ?? "div";
2695
+ const definition = buildDefinition(displayName, defaultTag);
2696
+ const variantKeys = new Set(Object.keys(options.styling?.variants ?? {}));
2697
+ const domDefaults = options.defaults;
2698
+ const stylePipeline = buildStylePipeline(
2699
+ options.styling?.variants,
2700
+ options.styling?.presets,
2701
+ options.styling?.defaults ?? {},
2702
+ options.styling?.compounds,
2703
+ void 0
2704
+ );
2705
+ const base = options.styling?.base !== void 0 ? flattenClassName(options.styling.base) : void 0;
2706
+ const filterFn = options.filterProps;
2707
+ const allowedAs = options.enforcement?.allowedAs;
2708
+ const normalizeFn = options.normalize;
2709
+ const enforcementNormalizers = options.enforcement?.props;
2710
+ const classPlugin = options.styling?.plugin !== void 0 ? options.styling.plugin(
2711
+ options.styling,
2712
+ resolved.diagnostics
2713
+ ) : void 0;
2714
+ const pluginKeys = classPlugin?.ownedKeys ?? EMPTY_SET;
2715
+ const { childrenEvaluator: explicitEvaluator } = buildEngines(
2716
+ resolved.diagnostics,
2717
+ options.enforcement?.children,
2718
+ displayName
2719
+ );
2720
+ const ariaEngine = options.enforcement !== void 0 ? new AriaPolicyEngine(resolved.diagnostics) : void 0;
2721
+ const slotValidator = new SlotValidator(displayName, resolved.diagnostics, "Preact element");
2722
+ const renderAsChild = makeRenderAsChild(cloneSlotChild);
2723
+ const Component = forwardRef(function Component2(props, ref) {
2724
+ const {
2725
+ as,
2726
+ asChild,
2727
+ children,
2728
+ className: callerClassName,
2729
+ recipe,
2730
+ ...ownProps
2731
+ } = props;
2732
+ const tag = typeof as === "string" ? as : defaultTag;
2733
+ if (allowedAs !== void 0) enforceAllowedAs(tag, allowedAs, resolved.diagnostics, displayName);
2734
+ const rawBaseProps = domDefaults !== void 0 ? { ...domDefaults, ...ownProps } : ownProps;
2735
+ const normalizedProps = applyPropNormalizers(tag, rawBaseProps, enforcementNormalizers);
2736
+ const baseProps = normalizeFn !== void 0 ? normalizeFn(normalizedProps) : normalizedProps;
2737
+ const pluginProps = {};
2738
+ const propsForExtraction = pluginKeys.size > 0 ? Object.fromEntries(
2739
+ Object.entries(baseProps).filter(([k]) => {
2740
+ if (pluginKeys.has(k)) {
2741
+ pluginProps[k] = baseProps[k];
2742
+ return false;
2743
+ }
2744
+ return true;
2745
+ })
2746
+ ) : baseProps;
2747
+ const rootDec = extractDecoration(propsForExtraction, variantKeys);
2748
+ const decoration = applyAria(
2749
+ Object.keys(rootDec).length > 0 ? { root: rootDec } : {},
2750
+ tag,
2751
+ ariaEngine
2752
+ );
2753
+ if (process.env.NODE_ENV !== "production") {
2754
+ const childEval = explicitEvaluator ?? getHtmlChildrenEvaluator(tag);
2755
+ childEval?.evaluate(normalizeChildren(children));
2756
+ }
2757
+ const recipeName = typeof recipe === "string" ? recipe : void 0;
2758
+ const { variantClasses, compoundClasses } = stylePipeline ? stylePipeline.execute(decoration, recipeName) : { variantClasses: [], compoundClasses: [] };
2759
+ const rawClassName = joinClasses(base, ...variantClasses, ...compoundClasses, callerClassName);
2760
+ const className = classPlugin !== void 0 ? classPlugin.pipeline(tag, pluginProps, rawClassName, recipeName) : rawClassName;
2761
+ if (asChild === true) {
2762
+ if (typeof as === "string") {
2763
+ slotValidator.assertExclusive();
2764
+ } else {
2765
+ return renderAsChild(children, className, ref ?? null);
2766
+ }
2767
+ }
2768
+ let finalDecoration = className ? applyAttributes("root", { className }, decoration, variantKeys) : decoration;
2769
+ finalDecoration = applyFilterProps(finalDecoration, filterFn, variantKeys);
2770
+ finalDecoration = applyRef(finalDecoration, ref ?? null);
2771
+ return renderNormally(definition, tag, finalDecoration, children);
2111
2772
  });
2112
2773
  applyDisplayName(Component, options.name);
2113
- if (typeof bundle.runtime.options.defaultTag === "string") {
2114
- Object.assign(Component, { [COMPONENT_DEFAULT_TAG]: bundle.runtime.options.defaultTag });
2774
+ if (typeof defaultTag === "string") {
2775
+ Object.assign(Component, { [COMPONENT_DEFAULT_TAG]: defaultTag });
2115
2776
  }
2116
2777
  return Component;
2117
2778
  }