praxis-kit 4.0.1 → 4.1.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.
package/dist/web/index.js CHANGED
@@ -1,8 +1,16 @@
1
- // ../../lib/primitive/src/tag/resolve-tag.ts
2
- function makeResolveTag(defaultTag) {
3
- return function tag(as) {
4
- return as ?? defaultTag;
5
- };
1
+ // ../../lib/adapter-utils/src/runtime/define-component.ts
2
+ function defineContractComponent(options) {
3
+ return (factory) => factory(options);
4
+ }
5
+
6
+ // ../../lib/primitive/src/guards/foundational/is-defined.ts
7
+ function isUndefined(value) {
8
+ return value === void 0;
9
+ }
10
+
11
+ // ../../lib/primitive/src/guards/foundational/is-null.ts
12
+ function isNull(value) {
13
+ return value === null;
6
14
  }
7
15
 
8
16
  // ../../lib/primitive/src/utils/is-object.ts
@@ -17,195 +25,6 @@ function isNumber(value) {
17
25
  return typeof value === "number";
18
26
  }
19
27
 
20
- // ../../lib/primitive/src/utils/assert-never.ts
21
- function assertNever(value) {
22
- throw new Error(`Unexpected value: ${String(value)}`);
23
- }
24
-
25
- // ../../lib/primitive/src/utils/cn.ts
26
- import { clsx } from "clsx";
27
- function cn(...inputs) {
28
- return clsx(...inputs);
29
- }
30
-
31
- // ../../lib/primitive/src/utils/iterate.ts
32
- function find(iterable, callback) {
33
- for (const value of iterable) {
34
- const result = callback(value);
35
- if (result != null) {
36
- return result;
37
- }
38
- }
39
- return null;
40
- }
41
- function some(iterable, predicate) {
42
- for (const value of iterable) {
43
- if (predicate(value)) return true;
44
- }
45
- return false;
46
- }
47
- function every(iterable, predicate) {
48
- let index = 0;
49
- for (const value of iterable) {
50
- if (!predicate(value, index++)) {
51
- return false;
52
- }
53
- }
54
- return true;
55
- }
56
- function* filter(iterable, predicate) {
57
- let index = 0;
58
- for (const value of iterable) {
59
- if (predicate(value, index++)) {
60
- yield value;
61
- }
62
- }
63
- }
64
- function* map(iterable, callback) {
65
- let index = 0;
66
- for (const value of iterable) {
67
- yield callback(value, index++);
68
- }
69
- }
70
- function forEach(iterable, callback) {
71
- let index = 0;
72
- for (const value of iterable) {
73
- callback(value, index++);
74
- }
75
- }
76
- function reduce(iterable, initial, callback) {
77
- let accumulator = initial;
78
- let index = 0;
79
- for (const value of iterable) {
80
- accumulator = callback(accumulator, value, index++);
81
- }
82
- return accumulator;
83
- }
84
- function collect(iterable, callback) {
85
- const result = {};
86
- let index = 0;
87
- for (const value of iterable) {
88
- const entry = callback(value, index++);
89
- if (entry === null) {
90
- return null;
91
- }
92
- result[entry[0]] = entry[1];
93
- }
94
- return result;
95
- }
96
- function findLast(value, callback) {
97
- for (let index = value.length - 1; index >= 0; index--) {
98
- const result = callback(value[index], index);
99
- if (result != null) {
100
- return result;
101
- }
102
- }
103
- return null;
104
- }
105
- function* items(collection) {
106
- for (let i = 0; i < collection.length; i++) {
107
- const item = collection.item(i);
108
- if (item !== null) {
109
- yield item;
110
- }
111
- }
112
- }
113
- function nodeList(list) {
114
- return {
115
- *[Symbol.iterator]() {
116
- for (let i = 0; i < list.length; i++) {
117
- const node = list.item(i);
118
- if (node !== null) {
119
- yield node;
120
- }
121
- }
122
- }
123
- };
124
- }
125
- function mapEntries(m) {
126
- return m.entries();
127
- }
128
- function set(s) {
129
- return s.values();
130
- }
131
- function hasOwn(object, key) {
132
- return Object.hasOwn(object, key);
133
- }
134
- function* entries(object) {
135
- for (const key in object) {
136
- if (!hasOwn(object, key)) continue;
137
- yield [key, object[key]];
138
- }
139
- }
140
- function* keys(object) {
141
- for (const [key] of entries(object)) {
142
- yield key;
143
- }
144
- }
145
- function* values(object) {
146
- for (const [, value] of entries(object)) {
147
- yield value;
148
- }
149
- }
150
- function mapValues(object, callback) {
151
- const result = {};
152
- for (const [key, value] of entries(object)) {
153
- result[key] = callback(value, key);
154
- }
155
- return result;
156
- }
157
- function forEachEntry(object, callback) {
158
- for (const [key, value] of entries(object)) {
159
- callback(key, value);
160
- }
161
- }
162
- function forEachKey(object, callback) {
163
- for (const key of keys(object)) {
164
- callback(key);
165
- }
166
- }
167
- function forEachValue(object, callback) {
168
- for (const value of values(object)) {
169
- callback(value);
170
- }
171
- }
172
- function forEachSet(s, callback) {
173
- for (const value of s) {
174
- callback(value);
175
- }
176
- }
177
- var iterate = Object.freeze({
178
- entries,
179
- filter,
180
- find,
181
- findLast,
182
- forEach,
183
- forEachEntry,
184
- forEachKey,
185
- forEachSet,
186
- forEachValue,
187
- items,
188
- keys,
189
- map,
190
- mapEntries,
191
- mapValues,
192
- nodeList,
193
- reduce,
194
- collect,
195
- set,
196
- some,
197
- every,
198
- values
199
- });
200
-
201
- // ../../lib/primitive/src/utils/merge-props.ts
202
- function mergeProps(defaultProps, props) {
203
- return {
204
- ...defaultProps ?? {},
205
- ...props
206
- };
207
- }
208
-
209
28
  // ../../lib/primitive/src/constants/aria/global-aria-attributes.ts
210
29
  var GLOBAL_ARIA_ATTRIBUTES = /* @__PURE__ */ new Set([
211
30
  "aria-atomic",
@@ -228,7 +47,7 @@ var GLOBAL_ARIA_ATTRIBUTES = /* @__PURE__ */ new Set([
228
47
  ]);
229
48
 
230
49
  // ../../lib/primitive/src/constants/aria/implicit-role-record.ts
231
- var IMPLICIT_ROLE_RECORD = {
50
+ var IMPLICIT_ROLE_RECORD = Object.freeze({
232
51
  // Landmarks
233
52
  article: "article",
234
53
  aside: "complementary",
@@ -264,8 +83,8 @@ var IMPLICIT_ROLE_RECORD = {
264
83
  meter: "meter",
265
84
  output: "status",
266
85
  progress: "progressbar"
267
- };
268
- var INPUT_TYPE_ROLE_MAP = {
86
+ });
87
+ var INPUT_TYPE_ROLE_MAP = Object.freeze({
269
88
  checkbox: "checkbox",
270
89
  radio: "radio",
271
90
  range: "slider",
@@ -279,15 +98,17 @@ var INPUT_TYPE_ROLE_MAP = {
279
98
  submit: "button",
280
99
  reset: "button",
281
100
  image: "button"
282
- };
283
- var STRONG_ROLES = [
101
+ });
102
+ var STRONG_ROLES = Object.freeze([
284
103
  "main",
285
104
  "navigation",
286
105
  "complementary",
287
106
  "contentinfo",
288
107
  "banner"
289
- ];
290
- var STANDALONE_ROLES = ["article"];
108
+ ]);
109
+ var STANDALONE_ROLES = Object.freeze([
110
+ "article"
111
+ ]);
291
112
  var STRONG_ROLES_SET = new Set(STRONG_ROLES);
292
113
  var STANDALONE_ROLES_SET = new Set(STANDALONE_ROLES);
293
114
 
@@ -442,16 +263,6 @@ var ROLE_RESTRICTED_ATTRIBUTES = /* @__PURE__ */ new Map([
442
263
  ]
443
264
  ]);
444
265
 
445
- // ../../lib/primitive/src/guards/foundational/is-defined.ts
446
- function isUndefined(value) {
447
- return value === void 0;
448
- }
449
-
450
- // ../../lib/primitive/src/guards/foundational/is-null.ts
451
- function isNull(value) {
452
- return value === null;
453
- }
454
-
455
266
  // ../../lib/primitive/src/guards/aria/is-aria-attribute.ts
456
267
  function isGlobalAriaAttribute(attr) {
457
268
  return GLOBAL_ARIA_ATTRIBUTES.has(attr);
@@ -472,39 +283,260 @@ function isStandaloneTag(tag) {
472
283
  if (!(tag in IMPLICIT_ROLE_RECORD)) return false;
473
284
  return STANDALONE_ROLES_SET.has(IMPLICIT_ROLE_RECORD[tag]);
474
285
  }
475
- function getInputImplicitRole(type) {
476
- if (type == null || !(type in INPUT_TYPE_ROLE_MAP)) return void 0;
477
- return INPUT_TYPE_ROLE_MAP[type];
286
+ function getInputImplicitRole(type) {
287
+ if (!isString(type) || !(type in INPUT_TYPE_ROLE_MAP)) return void 0;
288
+ return INPUT_TYPE_ROLE_MAP[type];
289
+ }
290
+ function getConditionalImplicitRole(tag, ariaLabel, ariaLabelledBy) {
291
+ const isNamed = isString(ariaLabel) || isString(ariaLabelledBy);
292
+ if (!isNamed) return void 0;
293
+ if (tag === "section") return "region";
294
+ if (tag === "form") return "form";
295
+ return void 0;
296
+ }
297
+
298
+ // ../../lib/contract/src/aria/aria-role-policy.ts
299
+ function getImplicitRole(tag, props) {
300
+ if (tag in IMPLICIT_ROLE_RECORD) return IMPLICIT_ROLE_RECORD[tag];
301
+ if (tag === "input") return getInputImplicitRole(props?.type);
302
+ if (tag === "img") return props?.alt === "" ? "none" : "img";
303
+ if (tag === "section" || tag === "form") {
304
+ return getConditionalImplicitRole(tag, props?.["aria-label"], props?.["aria-labelledby"]);
305
+ }
306
+ return void 0;
307
+ }
308
+
309
+ // ../../lib/primitive/src/tag/resolve-tag.ts
310
+ function makeResolveTag(defaultTag) {
311
+ return function tag(as) {
312
+ return as ?? defaultTag;
313
+ };
314
+ }
315
+
316
+ // ../../lib/primitive/src/utils/assert-never.ts
317
+ function assertNever(value) {
318
+ throw new Error(`Unexpected value: ${String(value)}`);
319
+ }
320
+
321
+ // ../../lib/primitive/src/utils/cn.ts
322
+ import { clsx } from "clsx";
323
+ function cn(...inputs) {
324
+ return clsx(...inputs);
325
+ }
326
+
327
+ // ../../lib/primitive/src/utils/iterate.ts
328
+ function find(iterable, callback) {
329
+ for (const value of iterable) {
330
+ const result = callback(value);
331
+ if (result != null) {
332
+ return result;
333
+ }
334
+ }
335
+ return null;
336
+ }
337
+ function some(iterable, predicate) {
338
+ for (const value of iterable) {
339
+ if (predicate(value)) return true;
340
+ }
341
+ return false;
342
+ }
343
+ function every(iterable, predicate) {
344
+ let index = 0;
345
+ for (const value of iterable) {
346
+ if (!predicate(value, index++)) {
347
+ return false;
348
+ }
349
+ }
350
+ return true;
351
+ }
352
+ function* filter(iterable, predicate) {
353
+ let index = 0;
354
+ for (const value of iterable) {
355
+ if (predicate(value, index++)) {
356
+ yield value;
357
+ }
358
+ }
359
+ }
360
+ function* map(iterable, callback) {
361
+ let index = 0;
362
+ for (const value of iterable) {
363
+ yield callback(value, index++);
364
+ }
365
+ }
366
+ function forEach(iterable, callback) {
367
+ let index = 0;
368
+ for (const value of iterable) {
369
+ callback(value, index++);
370
+ }
371
+ }
372
+ function reduce(iterable, initial, callback) {
373
+ let accumulator = initial;
374
+ let index = 0;
375
+ for (const value of iterable) {
376
+ accumulator = callback(accumulator, value, index++);
377
+ }
378
+ return accumulator;
379
+ }
380
+ function collect(iterable, callback) {
381
+ const result = {};
382
+ let index = 0;
383
+ for (const value of iterable) {
384
+ const entry = callback(value, index++);
385
+ if (entry === null) {
386
+ return null;
387
+ }
388
+ result[entry[0]] = entry[1];
389
+ }
390
+ return result;
391
+ }
392
+ function findLast(value, callback) {
393
+ for (let index = value.length - 1; index >= 0; index--) {
394
+ const result = callback(value[index], index);
395
+ if (result != null) {
396
+ return result;
397
+ }
398
+ }
399
+ return null;
400
+ }
401
+ function* items(collection) {
402
+ for (let i = 0; i < collection.length; i++) {
403
+ const item = collection.item(i);
404
+ if (item !== null) {
405
+ yield item;
406
+ }
407
+ }
408
+ }
409
+ function nodeList(list) {
410
+ return {
411
+ *[Symbol.iterator]() {
412
+ for (let i = 0; i < list.length; i++) {
413
+ const node = list.item(i);
414
+ if (node !== null) {
415
+ yield node;
416
+ }
417
+ }
418
+ }
419
+ };
420
+ }
421
+ function mapEntries(m) {
422
+ return m.entries();
423
+ }
424
+ function set(s) {
425
+ return s.values();
426
+ }
427
+ function hasOwn(object, key) {
428
+ return Object.hasOwn(object, key);
429
+ }
430
+ function* entries(object) {
431
+ for (const key in object) {
432
+ if (!hasOwn(object, key)) continue;
433
+ yield [key, object[key]];
434
+ }
435
+ }
436
+ function* keys(object) {
437
+ for (const [key] of entries(object)) {
438
+ yield key;
439
+ }
440
+ }
441
+ function* values(object) {
442
+ for (const [, value] of entries(object)) {
443
+ yield value;
444
+ }
445
+ }
446
+ function mapValues(object, callback) {
447
+ const result = {};
448
+ for (const [key, value] of entries(object)) {
449
+ result[key] = callback(value, key);
450
+ }
451
+ return result;
452
+ }
453
+ function forEachEntry(object, callback) {
454
+ for (const [key, value] of entries(object)) {
455
+ callback(key, value);
456
+ }
457
+ }
458
+ function forEachKey(object, callback) {
459
+ for (const key of keys(object)) {
460
+ callback(key);
461
+ }
462
+ }
463
+ function forEachValue(object, callback) {
464
+ for (const value of values(object)) {
465
+ callback(value);
466
+ }
478
467
  }
479
- function getConditionalImplicitRole(tag, ariaLabel, ariaLabelledBy) {
480
- const isNamed = typeof ariaLabel === "string" || typeof ariaLabelledBy === "string";
481
- if (!isNamed) return void 0;
482
- if (tag === "section") return "region";
483
- if (tag === "form") return "form";
484
- return void 0;
468
+ function forEachSet(s, callback) {
469
+ for (const value of s) {
470
+ callback(value);
471
+ }
485
472
  }
473
+ var iterate = Object.freeze({
474
+ entries,
475
+ filter,
476
+ find,
477
+ findLast,
478
+ forEach,
479
+ forEachEntry,
480
+ forEachKey,
481
+ forEachSet,
482
+ forEachValue,
483
+ items,
484
+ keys,
485
+ map,
486
+ mapEntries,
487
+ mapValues,
488
+ nodeList,
489
+ reduce,
490
+ collect,
491
+ set,
492
+ some,
493
+ every,
494
+ values
495
+ });
486
496
 
487
- // ../../lib/adapter-utils/src/apply-filter.ts
488
- function applyFilter(props, filterProps, variantKeys) {
489
- const out = {};
490
- iterate.forEachEntry(props, (k) => {
491
- if (!Object.hasOwn(props, k)) return;
492
- if (filterProps(k, variantKeys)) return;
493
- out[k] = props[k];
494
- });
495
- return out;
497
+ // ../../lib/primitive/src/utils/merge-props.ts
498
+ function mergeProps(defaultProps, props) {
499
+ return {
500
+ ...defaultProps ?? {},
501
+ ...props
502
+ };
496
503
  }
497
504
 
498
- // ../../lib/contract/src/aria/aria-role-policy.ts
499
- function getImplicitRole(tag, props) {
500
- if (tag in IMPLICIT_ROLE_RECORD) return IMPLICIT_ROLE_RECORD[tag];
501
- if (tag === "input") return getInputImplicitRole(props?.type);
502
- if (tag === "img") return props?.alt === "" ? "none" : "img";
503
- if (tag === "section" || tag === "form") {
504
- return getConditionalImplicitRole(tag, props?.["aria-label"], props?.["aria-labelledby"]);
505
+ // ../../lib/primitive/src/guards/children/component-id.ts
506
+ var COMPONENT_DEFAULT_TAG = /* @__PURE__ */ Symbol.for("praxis.component-default-tag");
507
+
508
+ // ../../lib/primitive/src/guards/children/is-tag.ts
509
+ function getAsProp(child) {
510
+ if (!isObject(child) || !("props" in child)) return void 0;
511
+ const props = child.props;
512
+ if (!isObject(props)) return void 0;
513
+ const as = props.as;
514
+ return isString(as) && as !== "" ? as : void 0;
515
+ }
516
+ function getTag(child) {
517
+ if (!isObject(child) || !("type" in child)) return void 0;
518
+ const t = child.type;
519
+ if (isString(t)) return t;
520
+ if (typeof t === "function" || isObject(t)) {
521
+ const defaultTag = t[COMPONENT_DEFAULT_TAG];
522
+ if (!isString(defaultTag)) return void 0;
523
+ return getAsProp(child) ?? defaultTag;
505
524
  }
506
525
  return void 0;
507
526
  }
527
+ function isTag(...args) {
528
+ if (isString(args[0])) {
529
+ const set3 = new Set(args);
530
+ return (child2) => {
531
+ const tag2 = getTag(child2);
532
+ return tag2 !== void 0 && set3.has(tag2);
533
+ };
534
+ }
535
+ const [child, ...tags] = args;
536
+ const set2 = new Set(tags);
537
+ const tag = getTag(child);
538
+ return tag !== void 0 && set2.has(tag);
539
+ }
508
540
 
509
541
  // ../../lib/contract/src/strict/invariant-base.ts
510
542
  var InvariantBase = class {
@@ -528,159 +560,21 @@ var InvariantBase = class {
528
560
  }
529
561
  };
530
562
 
531
- // ../../lib/diagnostics/src/category.ts
532
- var DiagnosticCategory = /* @__PURE__ */ ((DiagnosticCategory2) => {
533
- DiagnosticCategory2[DiagnosticCategory2["Contract"] = 0] = "Contract";
534
- DiagnosticCategory2[DiagnosticCategory2["HTML"] = 1] = "HTML";
535
- DiagnosticCategory2[DiagnosticCategory2["ARIA"] = 2] = "ARIA";
536
- DiagnosticCategory2[DiagnosticCategory2["Composition"] = 3] = "Composition";
537
- DiagnosticCategory2[DiagnosticCategory2["Rendering"] = 4] = "Rendering";
538
- DiagnosticCategory2[DiagnosticCategory2["Accessibility"] = 5] = "Accessibility";
539
- DiagnosticCategory2[DiagnosticCategory2["Performance"] = 6] = "Performance";
540
- DiagnosticCategory2[DiagnosticCategory2["Internal"] = 7] = "Internal";
541
- DiagnosticCategory2[DiagnosticCategory2["Deprecation"] = 8] = "Deprecation";
542
- DiagnosticCategory2[DiagnosticCategory2["Lint"] = 9] = "Lint";
543
- return DiagnosticCategory2;
544
- })(DiagnosticCategory || {});
545
-
546
- // ../../lib/diagnostics/src/error.ts
547
- var PraxisError = class extends Error {
548
- diagnostic;
549
- constructor(diagnostic) {
550
- super(diagnostic.message);
551
- this.name = "PraxisError";
552
- this.diagnostic = diagnostic;
553
- }
554
- };
555
-
556
- // ../../lib/diagnostics/src/severity.ts
557
- var Severity = /* @__PURE__ */ ((Severity2) => {
558
- Severity2[Severity2["Debug"] = 0] = "Debug";
559
- Severity2[Severity2["Info"] = 1] = "Info";
560
- Severity2[Severity2["Warning"] = 2] = "Warning";
561
- Severity2[Severity2["Error"] = 3] = "Error";
562
- Severity2[Severity2["Fatal"] = 4] = "Fatal";
563
- return Severity2;
564
- })(Severity || {});
565
-
566
- // ../../lib/diagnostics/src/policy.ts
567
- var DefaultPolicy = class {
568
- reportThreshold;
569
- throwThreshold;
570
- constructor({
571
- reportThreshold = 1 /* Info */,
572
- throwThreshold = 4 /* Fatal */
573
- } = {}) {
574
- this.reportThreshold = reportThreshold;
575
- this.throwThreshold = throwThreshold;
576
- }
577
- resolve(diagnostic) {
578
- if (diagnostic.severity >= this.throwThreshold) return 2 /* Throw */;
579
- if (diagnostic.severity >= this.reportThreshold) return 1 /* Report */;
580
- return 0 /* Ignore */;
581
- }
582
- };
583
-
584
- // ../../lib/diagnostics/src/diagnostics.ts
585
- var Diagnostics = class {
586
- reporter;
587
- policy;
588
- // Pre-computed at construction time: true if Warning-level diagnostics are not ignored.
589
- active;
590
- constructor(reporter, policy = new DefaultPolicy()) {
591
- this.reporter = reporter;
592
- this.policy = policy;
593
- this.active = policy.resolve({ severity: 2 /* Warning */ }) !== 0 /* Ignore */;
594
- }
595
- report(diagnostic) {
596
- const enforcement = this.policy.resolve(diagnostic);
597
- if (enforcement === 0 /* Ignore */) return diagnostic;
598
- if (enforcement === 2 /* Throw */) throw new PraxisError(diagnostic);
599
- this.reporter.report(diagnostic);
600
- return diagnostic;
601
- }
602
- warn(input) {
603
- return this.report({ ...input, severity: 2 /* Warning */ });
604
- }
605
- error(input) {
606
- return this.report({ ...input, severity: 3 /* Error */ });
607
- }
608
- info(input) {
609
- return this.report({ ...input, severity: 1 /* Info */ });
610
- }
611
- };
612
-
613
- // ../../lib/diagnostics/src/formatter.ts
614
- function formatDiagnostic(diagnostic) {
615
- const level = Severity[diagnostic.severity];
616
- const category = DiagnosticCategory[diagnostic.category];
617
- const prefix = category !== void 0 ? `[${category}] ` : "";
618
- return `${level} ${diagnostic.code}: ${prefix}${diagnostic.message}`;
619
- }
620
-
621
- // ../../lib/diagnostics/src/console-reporter.ts
622
- var ConsoleReporter = class {
623
- report(diagnostic) {
624
- const message = formatDiagnostic(diagnostic);
625
- switch (diagnostic.severity) {
626
- case 0 /* Debug */:
627
- console.debug(message);
628
- break;
629
- case 1 /* Info */:
630
- console.info(message);
631
- break;
632
- case 2 /* Warning */:
633
- console.warn(message);
634
- break;
635
- case 3 /* Error */:
636
- case 4 /* Fatal */:
637
- console.error(message);
638
- break;
639
- }
640
- }
641
- };
642
-
643
- // ../../lib/diagnostics/src/null-reporter.ts
644
- var nullReporter = {
645
- report() {
646
- }
647
- };
648
-
649
- // ../../lib/diagnostics/src/presets.ts
650
- var ignoreAllPolicy = {
651
- resolve(_) {
652
- return 0 /* Ignore */;
653
- }
654
- };
655
- var warnOnlyReporter = {
656
- report(diagnostic) {
657
- console.warn(formatDiagnostic(diagnostic));
658
- }
659
- };
660
- var silentDiagnostics = new Diagnostics(nullReporter, ignoreAllPolicy);
661
- var warnDiagnostics = new Diagnostics(
662
- warnOnlyReporter,
663
- new DefaultPolicy({ reportThreshold: 2 /* Warning */, throwThreshold: 4 /* Fatal */ })
664
- );
665
- var throwDiagnostics = new Diagnostics(
666
- new ConsoleReporter(),
667
- new DefaultPolicy({ reportThreshold: 2 /* Warning */, throwThreshold: 3 /* Error */ })
668
- );
669
-
670
563
  // ../../lib/contract/src/diagnostics/aria.ts
564
+ import { DiagnosticCategory, DiagnosticCode } from "../_shared/diagnostics.js";
671
565
  var AriaDiagnostics = {
672
566
  /** Generic bridge for violations produced by external AriaRule functions. */
673
567
  fromViolation(v) {
674
568
  return {
675
- code: "ARIA2002" /* AriaViolation */,
676
- category: 2 /* ARIA */,
569
+ code: DiagnosticCode.AriaViolation,
570
+ category: DiagnosticCategory.ARIA,
677
571
  message: v.message
678
572
  };
679
573
  },
680
574
  attributeInvalid(key, role) {
681
575
  return {
682
- code: "ARIA2003" /* AriaAttributeInvalid */,
683
- category: 2 /* ARIA */,
576
+ code: DiagnosticCode.AriaAttributeInvalid,
577
+ category: DiagnosticCategory.ARIA,
684
578
  message: `"${key}" is not valid on role="${role}". It will be removed.`,
685
579
  rationale: "Invalid ARIA attributes are ignored by assistive technology and may trigger accessibility-tree warnings in browser devtools.",
686
580
  suggestions: [
@@ -693,8 +587,8 @@ var AriaDiagnostics = {
693
587
  },
694
588
  missingLiveRegion(role, impliedLive) {
695
589
  return {
696
- code: "ARIA2004" /* AriaMissingLiveRegion */,
697
- category: 2 /* ARIA */,
590
+ code: DiagnosticCode.AriaMissingLiveRegion,
591
+ category: DiagnosticCategory.ARIA,
698
592
  message: `role="${role}" implies aria-live="${impliedLive}" but it is missing. It has been injected.`,
699
593
  rationale: "Live-region roles announce dynamic content changes to screen readers. Without aria-live the politeness level is unspecified and announcements may be silent.",
700
594
  suggestions: [
@@ -708,8 +602,8 @@ var AriaDiagnostics = {
708
602
  },
709
603
  missingAtomic(role) {
710
604
  return {
711
- code: "ARIA2005" /* AriaMissingAtomic */,
712
- category: 2 /* ARIA */,
605
+ code: DiagnosticCode.AriaMissingAtomic,
606
+ category: DiagnosticCategory.ARIA,
713
607
  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.`,
714
608
  rationale: "aria-atomic controls whether assistive technology announces the entire live region or only the changed nodes. Omitting it leaves the behaviour browser-defined."
715
609
  };
@@ -717,8 +611,8 @@ var AriaDiagnostics = {
717
611
  relevantInvalidTokens(invalid) {
718
612
  const quoted = invalid.map((t) => `"${t}"`).join(", ");
719
613
  return {
720
- code: "ARIA2006" /* AriaRelevantInvalidToken */,
721
- category: 2 /* ARIA */,
614
+ code: DiagnosticCode.AriaRelevantInvalidToken,
615
+ category: DiagnosticCategory.ARIA,
722
616
  message: `aria-relevant contains invalid token(s): ${quoted}. Valid tokens are: additions, removals, text, all.`,
723
617
  rationale: "aria-relevant accepts a space-separated list of change types. Unrecognised tokens are silently ignored by assistive technology, making the attribute ineffective.",
724
618
  suggestions: [
@@ -731,8 +625,8 @@ var AriaDiagnostics = {
731
625
  },
732
626
  relevantSuperseded() {
733
627
  return {
734
- code: "ARIA2007" /* AriaRelevantSuperseded */,
735
- category: 2 /* ARIA */,
628
+ code: DiagnosticCode.AriaRelevantSuperseded,
629
+ category: DiagnosticCategory.ARIA,
736
630
  message: 'aria-relevant includes "all" alongside other tokens. "all" supersedes additions, removals, and text \u2014 use aria-relevant="all" alone.',
737
631
  rationale: '"all" is equivalent to "additions removals text". Combining it with other tokens is redundant and may confuse readers of the markup.',
738
632
  suggestions: [
@@ -745,8 +639,8 @@ var AriaDiagnostics = {
745
639
  },
746
640
  missingAccessibleName(tag) {
747
641
  return {
748
- code: "ARIA2009" /* AriaMissingAccessibleName */,
749
- category: 2 /* ARIA */,
642
+ code: DiagnosticCode.AriaMissingAccessibleName,
643
+ category: DiagnosticCategory.ARIA,
750
644
  message: `<${tag}> has no accessible name. Add aria-label or aria-labelledby.`,
751
645
  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.",
752
646
  suggestions: [
@@ -763,8 +657,8 @@ var AriaDiagnostics = {
763
657
  },
764
658
  attributeOnPresentational(attr, tag) {
765
659
  return {
766
- code: "ARIA2010" /* AriaAttributeOnPresentational */,
767
- category: 2 /* ARIA */,
660
+ code: DiagnosticCode.AriaAttributeOnPresentational,
661
+ category: DiagnosticCategory.ARIA,
768
662
  message: `"${attr}" is not allowed on a presentational <${tag}>. Presentational elements are invisible to assistive technology.`,
769
663
  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.',
770
664
  suggestions: [
@@ -777,8 +671,8 @@ var AriaDiagnostics = {
777
671
  },
778
672
  ariaHiddenOnFocusable(tag) {
779
673
  return {
780
- code: "ARIA2011" /* AriaHiddenOnFocusable */,
781
- category: 2 /* ARIA */,
674
+ code: DiagnosticCode.AriaHiddenOnFocusable,
675
+ category: DiagnosticCategory.ARIA,
782
676
  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.`,
783
677
  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.',
784
678
  suggestions: [
@@ -796,8 +690,8 @@ var AriaDiagnostics = {
796
690
  invalidAttributeValue(attr, value, expected) {
797
691
  const got = value === null ? "null" : value === void 0 ? "undefined" : typeof value === "string" ? `"${value}"` : String(value);
798
692
  return {
799
- code: "ARIA2013" /* AriaInvalidAttributeValue */,
800
- category: 2 /* ARIA */,
693
+ code: DiagnosticCode.AriaInvalidAttributeValue,
694
+ category: DiagnosticCategory.ARIA,
801
695
  message: `"${attr}" has an invalid value (${got}). Expected: ${expected}.`,
802
696
  rationale: "ARIA attributes with invalid values are silently ignored by assistive technology, making the markup semantically inert.",
803
697
  suggestions: [
@@ -810,8 +704,8 @@ var AriaDiagnostics = {
810
704
  },
811
705
  redundantAriaLevel(tag, level) {
812
706
  return {
813
- code: "ARIA2014" /* AriaRedundantLevelAttribute */,
814
- category: 2 /* ARIA */,
707
+ code: DiagnosticCode.AriaRedundantLevelAttribute,
708
+ category: DiagnosticCategory.ARIA,
815
709
  message: `aria-level="${level}" is redundant on <${tag}>: the element already has an implicit heading level of ${level}. Remove the attribute.`,
816
710
  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>).',
817
711
  suggestions: [
@@ -824,8 +718,8 @@ var AriaDiagnostics = {
824
718
  },
825
719
  requiredProperty(attr, role) {
826
720
  return {
827
- code: "ARIA2012" /* AriaRequiredProperty */,
828
- category: 2 /* ARIA */,
721
+ code: DiagnosticCode.AriaRequiredProperty,
722
+ category: DiagnosticCategory.ARIA,
829
723
  message: `"${attr}" is required for role="${role}" but is missing.`,
830
724
  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.`,
831
725
  suggestions: [
@@ -838,8 +732,8 @@ var AriaDiagnostics = {
838
732
  },
839
733
  invalidRole(role, tag) {
840
734
  return {
841
- code: "ARIA2008" /* AriaInvalidRole */,
842
- category: 2 /* ARIA */,
735
+ code: DiagnosticCode.AriaInvalidRole,
736
+ category: DiagnosticCategory.ARIA,
843
737
  message: `Invalid role "${role ?? ""}" on <${tag}>.`,
844
738
  rationale: "An unrecognised or misapplied ARIA role is ignored by assistive technology and may degrade the accessibility of the element."
845
739
  };
@@ -847,11 +741,12 @@ var AriaDiagnostics = {
847
741
  };
848
742
 
849
743
  // ../../lib/contract/src/diagnostics/contract.ts
744
+ import { DiagnosticCategory as DiagnosticCategory2, DiagnosticCode as DiagnosticCode2 } from "../_shared/diagnostics.js";
850
745
  var ContractDiagnostics = {
851
746
  unexpectedChild(typeName, index, context) {
852
747
  return {
853
- code: "COMP1004" /* UnexpectedChild */,
854
- category: 0 /* Contract */,
748
+ code: DiagnosticCode2.UnexpectedChild,
749
+ category: DiagnosticCategory2.Contract,
855
750
  component: context,
856
751
  message: `${context}: unexpected child "${typeName}" at index ${index}.`
857
752
  };
@@ -859,69 +754,69 @@ var ContractDiagnostics = {
859
754
  ambiguousChild(typeName, index, ruleNames, context) {
860
755
  const quoted = ruleNames.map((n) => `"${n}"`).join(" and ");
861
756
  return {
862
- code: "COMP1005" /* AmbiguousChild */,
863
- category: 0 /* Contract */,
757
+ code: DiagnosticCode2.AmbiguousChild,
758
+ category: DiagnosticCategory2.Contract,
864
759
  component: context,
865
760
  message: `${context}: child "${typeName}" at index ${index} matches multiple child rules: ${quoted}.`
866
761
  };
867
762
  },
868
763
  cardinalityMin(ruleName, min, context) {
869
764
  return {
870
- code: "COMP1006" /* CardinalityMin */,
871
- category: 0 /* Contract */,
765
+ code: DiagnosticCode2.CardinalityMin,
766
+ category: DiagnosticCategory2.Contract,
872
767
  component: context,
873
768
  message: `${context}: "${ruleName}" requires at least ${min}.`
874
769
  };
875
770
  },
876
771
  cardinalityMax(ruleName, max, context) {
877
772
  return {
878
- code: "COMP1007" /* CardinalityMax */,
879
- category: 0 /* Contract */,
773
+ code: DiagnosticCode2.CardinalityMax,
774
+ category: DiagnosticCategory2.Contract,
880
775
  component: context,
881
776
  message: `${context}: "${ruleName}" allows at most ${max}.`
882
777
  };
883
778
  },
884
779
  positionViolation(ruleName, position, index, context) {
885
780
  return {
886
- code: "COMP1008" /* PositionViolation */,
887
- category: 0 /* Contract */,
781
+ code: DiagnosticCode2.PositionViolation,
782
+ category: DiagnosticCategory2.Contract,
888
783
  component: context,
889
784
  message: `${context}: "${ruleName}" must be ${position}, got index ${index}`
890
785
  };
891
786
  },
892
787
  unknownVariantDim(component, label2, dim) {
893
788
  return {
894
- code: "COMP1010" /* ContractUnknownVariantDim */,
895
- category: 0 /* Contract */,
789
+ code: DiagnosticCode2.ContractUnknownVariantDim,
790
+ category: DiagnosticCategory2.Contract,
896
791
  message: `${component}: ${label2} references unknown variant "${dim}".`
897
792
  };
898
793
  },
899
794
  unknownVariantValue(component, label2, dim, value, valid) {
900
795
  return {
901
- code: "COMP1011" /* ContractUnknownVariantValue */,
902
- category: 0 /* Contract */,
796
+ code: DiagnosticCode2.ContractUnknownVariantValue,
797
+ category: DiagnosticCategory2.Contract,
903
798
  message: `${component}: ${label2} sets "${dim}" to unknown value "${value}" (valid: ${valid.join(", ")}).`
904
799
  };
905
800
  },
906
801
  unknownRecipeKey(component, key) {
907
802
  return {
908
- code: "COMP1012" /* ContractUnknownRecipeKey */,
909
- category: 0 /* Contract */,
803
+ code: DiagnosticCode2.ContractUnknownRecipeKey,
804
+ category: DiagnosticCategory2.Contract,
910
805
  message: `${component} Unknown recipeKey "${key}" \u2014 no preset with that name exists.`
911
806
  };
912
807
  },
913
808
  invalidVariantValue(component, key, value) {
914
809
  return {
915
- code: "COMP1013" /* ContractInvalidVariantValue */,
916
- category: 0 /* Contract */,
810
+ code: DiagnosticCode2.ContractInvalidVariantValue,
811
+ category: DiagnosticCategory2.Contract,
917
812
  message: `${component} Variant "${key}=${value}" is not a defined value for the "${key}" dimension.`
918
813
  };
919
814
  },
920
815
  allowedAsViolation(tag, allowedAs, component) {
921
816
  const allowed = allowedAs.map((t) => `"${String(t)}"`).join(", ");
922
817
  return {
923
- code: "COMP1009" /* AllowedAsViolation */,
924
- category: 0 /* Contract */,
818
+ code: DiagnosticCode2.AllowedAsViolation,
819
+ category: DiagnosticCategory2.Contract,
925
820
  component,
926
821
  message: `<${component}>: "as" prop received "${tag}" but only [${allowed}] are allowed.`
927
822
  };
@@ -929,46 +824,47 @@ var ContractDiagnostics = {
929
824
  };
930
825
 
931
826
  // ../../lib/contract/src/diagnostics/html.ts
827
+ import { DiagnosticCategory as DiagnosticCategory3, DiagnosticCode as DiagnosticCode3 } from "../_shared/diagnostics.js";
932
828
  var HtmlDiagnostics = {
933
829
  emptyRole(tag) {
934
830
  return {
935
- code: "HTML3002" /* HtmlEmptyRole */,
936
- category: 1 /* HTML */,
831
+ code: DiagnosticCode3.HtmlEmptyRole,
832
+ category: DiagnosticCategory3.HTML,
937
833
  message: `<${tag}> has an explicit empty role="". Omit the attribute instead.`
938
834
  };
939
835
  },
940
836
  implicitRoleRedundant(tag, implicitRole) {
941
837
  return {
942
- code: "HTML3003" /* HtmlImplicitRoleRedundant */,
943
- category: 1 /* HTML */,
838
+ code: DiagnosticCode3.HtmlImplicitRoleRedundant,
839
+ category: DiagnosticCategory3.HTML,
944
840
  message: `<${tag}> already has implicit role="${implicitRole}". Avoid redundant role assignment.`
945
841
  };
946
842
  },
947
843
  implicitRoleOverride(tag, implicitRole, role) {
948
844
  return {
949
- code: "HTML3004" /* HtmlImplicitRoleOverride */,
950
- category: 1 /* HTML */,
845
+ code: DiagnosticCode3.HtmlImplicitRoleOverride,
846
+ category: DiagnosticCategory3.HTML,
951
847
  message: `<${tag}> should not override its implicit role="${implicitRole}" with role="${role}".`
952
848
  };
953
849
  },
954
850
  standaloneRegionOverride(tag, implicitRole) {
955
851
  return {
956
- code: "HTML3005" /* HtmlStandaloneRegionOverride */,
957
- category: 1 /* HTML */,
852
+ code: DiagnosticCode3.HtmlStandaloneRegionOverride,
853
+ category: DiagnosticCategory3.HTML,
958
854
  message: `<${tag}> is a self-contained element with implicit role="${implicitRole}". Assigning role="region" has been removed.`
959
855
  };
960
856
  },
961
857
  landmarkRoleOverride(tag, implicitRole, role) {
962
858
  return {
963
- code: "HTML3006" /* HtmlLandmarkRoleOverride */,
964
- category: 1 /* HTML */,
859
+ code: DiagnosticCode3.HtmlLandmarkRoleOverride,
860
+ category: DiagnosticCategory3.HTML,
965
861
  message: `<${tag}> has a fixed landmark role="${implicitRole}". role="${role}" overrides it and confuses assistive technology. The override has been removed.`
966
862
  };
967
863
  },
968
864
  invalidChild(child, parent, allowed) {
969
865
  return {
970
- code: "HTML3007" /* HtmlInvalidChild */,
971
- category: 1 /* HTML */,
866
+ code: DiagnosticCode3.HtmlInvalidChild,
867
+ category: DiagnosticCategory3.HTML,
972
868
  message: `<${child}> is not a valid direct child of <${parent}>. Allowed: ${allowed}.`
973
869
  };
974
870
  }
@@ -1651,7 +1547,7 @@ function getTypeName(value) {
1651
1547
  return primitive;
1652
1548
  }
1653
1549
  const name = value.constructor?.name;
1654
- return typeof name === "string" && name !== "Object" ? name : "object";
1550
+ return isString(name) && name !== "Object" ? name : "object";
1655
1551
  }
1656
1552
 
1657
1553
  // ../../lib/contract/src/children/normalize-child-rule.ts
@@ -1902,6 +1798,9 @@ var readonlyProps = ({
1902
1798
  };
1903
1799
  };
1904
1800
 
1801
+ // ../core/src/html/evaluators.ts
1802
+ import { warnDiagnostics as warnDiagnostics2 } from "../_shared/diagnostics.js";
1803
+
1905
1804
  // ../core/src/html/aria-rules.ts
1906
1805
  var LANDMARK_TAG_SET = /* @__PURE__ */ new Set(["article", "aside", "footer", "header", "main", "nav"]);
1907
1806
  var removeLandmarkRoleOverride = {
@@ -1944,6 +1843,167 @@ function landmarkNameAdvisory(ctx) {
1944
1843
  }
1945
1844
  var HTML_ARIA_RULES = [landmarkRoleRule, landmarkNameAdvisory];
1946
1845
 
1846
+ // ../core/src/html/contracts.ts
1847
+ import { warnDiagnostics } from "../_shared/diagnostics.js";
1848
+ function isOpenContent(...blockedTags) {
1849
+ const set2 = new Set(blockedTags);
1850
+ return (child) => isObject(child) && "type" in child && (!isString(child.type) || !set2.has(child.type));
1851
+ }
1852
+ var METADATA_TAGS = ["script", "template"];
1853
+ var metadataMatch = isTag(...METADATA_TAGS);
1854
+ function metadata(name = "metadata") {
1855
+ return { name, match: metadataMatch };
1856
+ }
1857
+ function firstOptional(name, tag) {
1858
+ return { name, match: isTag(tag), cardinality: { max: 1 }, position: "first" };
1859
+ }
1860
+ function contract(children) {
1861
+ return { diagnostics: warnDiagnostics, children };
1862
+ }
1863
+ function ariaContract(aria) {
1864
+ return { diagnostics: warnDiagnostics, aria };
1865
+ }
1866
+ function firstChildContract(name, tag) {
1867
+ return contract([firstOptional(name, tag), { name: "content", match: isOpenContent(tag) }]);
1868
+ }
1869
+ var VOID_TAGS = [
1870
+ "area",
1871
+ "base",
1872
+ "br",
1873
+ "col",
1874
+ "embed",
1875
+ "hr",
1876
+ "img",
1877
+ "input",
1878
+ "link",
1879
+ "meta",
1880
+ "param",
1881
+ "source",
1882
+ "track",
1883
+ "wbr"
1884
+ ];
1885
+ var TEXT_ONLY_TAGS = ["option", "script", "style", "textarea", "title"];
1886
+ var LANDMARK_TAGS = ["article", "aside", "footer", "header", "main", "nav"];
1887
+ var listContract = contract([{ name: "list-item", match: isTag("li", ...METADATA_TAGS) }]);
1888
+ var tableContract = contract([
1889
+ firstOptional("caption", "caption"),
1890
+ { name: "colgroup", match: isTag("colgroup") },
1891
+ { name: "thead", match: isTag("thead"), cardinality: { max: 1 } },
1892
+ { name: "tbody", match: isTag("tbody") },
1893
+ { name: "tfoot", match: isTag("tfoot"), cardinality: { max: 1 } },
1894
+ { name: "table-row", match: isTag("tr", ...METADATA_TAGS) }
1895
+ ]);
1896
+ var tableBodyContract = contract([
1897
+ { name: "table-row", match: isTag("tr", ...METADATA_TAGS) }
1898
+ ]);
1899
+ var tableRowContract = contract([
1900
+ { name: "table-cell", match: isTag("td", "th", ...METADATA_TAGS) }
1901
+ ]);
1902
+ var colgroupContract = contract([{ name: "column", match: isTag("col", "template") }]);
1903
+ var dlContract = contract([
1904
+ { name: "term", match: isTag("dt") },
1905
+ { name: "description", match: isTag("dd") },
1906
+ { name: "group", match: isTag("div") },
1907
+ metadata()
1908
+ ]);
1909
+ var selectContract = contract([
1910
+ { name: "option", match: isTag("option", "optgroup", "hr", ...METADATA_TAGS) }
1911
+ ]);
1912
+ var optgroupContract = contract([
1913
+ { name: "option", match: isTag("option", ...METADATA_TAGS) }
1914
+ ]);
1915
+ var datalistContract = contract([
1916
+ { name: "option", match: isTag("option", ...METADATA_TAGS) }
1917
+ ]);
1918
+ var pictureContract = contract([
1919
+ { name: "source", match: isTag("source", ...METADATA_TAGS) },
1920
+ { name: "image", match: isTag("img"), cardinality: { min: 1, max: 1 }, position: "last" }
1921
+ ]);
1922
+ var figureContract = contract([
1923
+ { name: "caption", match: isTag("figcaption"), cardinality: { max: 1 } },
1924
+ { name: "content", match: isOpenContent("figcaption") }
1925
+ ]);
1926
+ var detailsContract = firstChildContract("summary", "summary");
1927
+ var fieldsetContract = firstChildContract("legend", "legend");
1928
+ var mediaContract = contract([
1929
+ { name: "source", match: isTag("source") },
1930
+ { name: "track", match: isTag("track") },
1931
+ metadata(),
1932
+ { name: "content", match: isOpenContent("source", "track", ...METADATA_TAGS) }
1933
+ ]);
1934
+ var headContract = contract([
1935
+ {
1936
+ name: "metadata",
1937
+ match: isTag("base", "link", "meta", "noscript", "script", "style", "template", "title")
1938
+ }
1939
+ ]);
1940
+ var htmlContract = contract([
1941
+ { name: "head", match: isTag("head"), cardinality: { min: 1, max: 1 }, position: "first" },
1942
+ { name: "body", match: isTag("body"), cardinality: { min: 1, max: 1 } }
1943
+ ]);
1944
+ var voidContract = contract([]);
1945
+ var textOnlyContract = contract([
1946
+ {
1947
+ name: "text",
1948
+ match: (child) => isString(child) || isNumber(child)
1949
+ }
1950
+ ]);
1951
+ var landmarkContract = ariaContract([landmarkRoleRule, landmarkNameAdvisory]);
1952
+ var dialogContract = ariaContract([requireAccessibleName]);
1953
+ var menuContract = ariaContract([requireAccessibleName]);
1954
+ var menubarContract = ariaContract([requireAccessibleName]);
1955
+ var treeContract = ariaContract([requireAccessibleName]);
1956
+ var gridContract = ariaContract([requireAccessibleName]);
1957
+ var listboxContract = ariaContract([requireAccessibleName]);
1958
+ var tablistContract = ariaContract([requireAccessibleName]);
1959
+ var radiogroupContract = ariaContract([requireAccessibleName]);
1960
+ var CONTRACT_GROUPS = [
1961
+ [VOID_TAGS, voidContract],
1962
+ [TEXT_ONLY_TAGS, textOnlyContract],
1963
+ [LANDMARK_TAGS, landmarkContract],
1964
+ [["ul", "ol", "menu"], listContract],
1965
+ [["audio", "video"], mediaContract],
1966
+ [["thead", "tbody", "tfoot"], tableBodyContract]
1967
+ ];
1968
+ function contractMap(groups) {
1969
+ return Object.fromEntries(
1970
+ groups.flatMap(([tags, enforcement]) => tags.map((tag) => [tag, enforcement]))
1971
+ );
1972
+ }
1973
+ var htmlContracts = {
1974
+ ...contractMap(CONTRACT_GROUPS),
1975
+ table: tableContract,
1976
+ tr: tableRowContract,
1977
+ colgroup: colgroupContract,
1978
+ dl: dlContract,
1979
+ select: selectContract,
1980
+ optgroup: optgroupContract,
1981
+ datalist: datalistContract,
1982
+ picture: pictureContract,
1983
+ figure: figureContract,
1984
+ details: detailsContract,
1985
+ fieldset: fieldsetContract,
1986
+ dialog: dialogContract,
1987
+ head: headContract,
1988
+ html: htmlContract
1989
+ };
1990
+
1991
+ // ../core/src/html/evaluators.ts
1992
+ var htmlDiagnostics = warnDiagnostics2;
1993
+ function buildEvaluatorMap() {
1994
+ const map2 = /* @__PURE__ */ new Map();
1995
+ iterate.forEachEntry(htmlContracts, (tag, { children }) => {
1996
+ if (children?.length) {
1997
+ map2.set(tag, new ChildrenEvaluator(children, htmlDiagnostics, `<${tag}>`));
1998
+ }
1999
+ });
2000
+ return map2;
2001
+ }
2002
+ var HTML_EVALUATORS = buildEvaluatorMap();
2003
+ function getHtmlChildrenEvaluator(tag) {
2004
+ return typeof tag === "string" ? HTML_EVALUATORS.get(tag) : void 0;
2005
+ }
2006
+
1947
2007
  // ../core/src/html/prop-normalizers.ts
1948
2008
  var HTML_FORM_NORMALIZERS = /* @__PURE__ */ new Map([
1949
2009
  ["button", [disabledProps]],
@@ -2131,7 +2191,21 @@ function createClassPipeline(resolved) {
2131
2191
  };
2132
2192
  }
2133
2193
 
2194
+ // ../../lib/pipeline-kit/src/factory/define-pipeline.ts
2195
+ function definePipeline(factory) {
2196
+ const cache = /* @__PURE__ */ new WeakMap();
2197
+ return (resolved) => {
2198
+ let pipeline = cache.get(resolved);
2199
+ if (!pipeline) {
2200
+ pipeline = factory(resolved);
2201
+ cache.set(resolved, pipeline);
2202
+ }
2203
+ return pipeline;
2204
+ };
2205
+ }
2206
+
2134
2207
  // ../core/src/options/resolve-factory-options.ts
2208
+ import { silentDiagnostics } from "../_shared/diagnostics.js";
2135
2209
  var EMPTY_VARIANT_KEYS = /* @__PURE__ */ new Set();
2136
2210
  function composeNormalizers(normalizers, fn) {
2137
2211
  if (!normalizers?.length) return fn;
@@ -2223,21 +2297,25 @@ function validateRenderProps(diagnostics, options, props, recipeKey) {
2223
2297
  }
2224
2298
  }
2225
2299
 
2300
+ // ../core/src/factory/plugin-invariants.ts
2301
+ import { throwDiagnostics } from "../_shared/diagnostics.js";
2302
+
2226
2303
  // ../core/src/factory/plugin-diagnostics.ts
2304
+ import { DiagnosticCategory as DiagnosticCategory4, DiagnosticCode as DiagnosticCode4 } from "../_shared/diagnostics.js";
2227
2305
  var PluginDiagnostics = {
2228
2306
  invalidShape(received) {
2229
2307
  const got = received === null ? "null" : typeof received;
2230
2308
  return {
2231
- code: "PLUGIN7001" /* PluginInvalidShape */,
2232
- category: 7 /* Internal */,
2309
+ code: DiagnosticCode4.PluginInvalidShape,
2310
+ category: DiagnosticCategory4.Internal,
2233
2311
  message: `[praxis-kit] Plugin factory must return an object with a 'pipeline' function. Got: ${got}.`
2234
2312
  };
2235
2313
  },
2236
2314
  pipelineReturnType(received) {
2237
2315
  const got = received === null ? "null" : Array.isArray(received) ? "array" : typeof received;
2238
2316
  return {
2239
- code: "PLUGIN7002" /* PluginPipelineReturnType */,
2240
- category: 7 /* Internal */,
2317
+ code: DiagnosticCode4.PluginPipelineReturnType,
2318
+ category: DiagnosticCategory4.Internal,
2241
2319
  message: `[praxis-kit] Plugin pipeline must return a string. Got: ${got}.`
2242
2320
  };
2243
2321
  }
@@ -2261,89 +2339,82 @@ function guardPipeline(pipeline) {
2261
2339
  };
2262
2340
  }
2263
2341
 
2264
- // ../core/src/factory/create-polymorphic.ts
2265
- var NOOP_CLASS_PIPELINE = (_tag, _props, className) => Array.isArray(className) ? className.join(" ") : className ?? "";
2266
- function resolveClassPipeline(options, resolved, diagnostics, capabilities) {
2267
- const factory = options.styling?.plugin;
2268
- if (!factory) {
2269
- const createClassPipeline2 = capabilities?.createClassPipeline;
2270
- const classPipeline2 = createClassPipeline2 ? createClassPipeline2(resolved) : NOOP_CLASS_PIPELINE;
2271
- return { pluginResult: void 0, classPipeline: classPipeline2 };
2272
- }
2342
+ // ../core/src/factory/create-polymorphic2.ts
2343
+ var createTagPipeline = (resolved) => makeResolveTag(resolved.defaultTag);
2344
+ var createPropsPipeline = (resolved) => (props) => mergeProps(resolved.defaultProps, props);
2345
+ var createHtmlPropNormalizersPipeline = () => getHtmlPropNormalizers;
2346
+ var createHtmlChildrenEvaluatorPipeline = () => getHtmlChildrenEvaluator;
2347
+ var createStylingClassPipeline = (resolved) => createClassPipeline(resolved);
2348
+ function resolveAriaRules(resolved) {
2349
+ return [.../* @__PURE__ */ new Set([...HTML_ARIA_RULES, ...resolved.ariaRules ?? []])];
2350
+ }
2351
+ var createAriaPipeline = (resolved) => {
2352
+ const rules = resolveAriaRules(resolved);
2353
+ const engine = new AriaPolicyEngine(resolved.diagnostics, rules.length ? { rules } : void 0);
2354
+ return (tag, props) => engine.validate(tag, props);
2355
+ };
2356
+ var memoizedTagPipeline = definePipeline(createTagPipeline);
2357
+ var memoizedPropsPipeline = definePipeline(createPropsPipeline);
2358
+ var memoizedHtmlPropNormalizersPipeline = definePipeline(createHtmlPropNormalizersPipeline);
2359
+ var memoizedHtmlChildrenEvaluatorPipeline = definePipeline(createHtmlChildrenEvaluatorPipeline);
2360
+ var memoizedClassPipeline = definePipeline(createStylingClassPipeline);
2361
+ var memoizedAriaPipeline = definePipeline(createAriaPipeline);
2362
+ function resolveAriaPassthrough(_tag, props) {
2363
+ return { props };
2364
+ }
2365
+ function resolveClassPlugin(factory, resolved, diagnostics) {
2366
+ if (!factory) return { pluginResult: void 0, classPipeline: memoizedClassPipeline(resolved) };
2273
2367
  const pluginResult = factory(resolved, diagnostics);
2274
2368
  assertPluginShape(pluginResult);
2275
- const classPipeline = guardPipeline(pluginResult.pipeline);
2276
- return { pluginResult, classPipeline };
2369
+ return { pluginResult, classPipeline: guardPipeline(pluginResult.pipeline) };
2277
2370
  }
2278
- function createRuntimeMethods(resolved, classPipeline, engine, renderDiagnostics) {
2279
- return {
2280
- resolveTag: makeResolveTag(resolved.defaultTag),
2281
- resolveProps(props) {
2282
- return mergeProps(resolved.defaultProps, props);
2283
- },
2371
+ function createPolymorphic2(options = {}) {
2372
+ const baseResolved = resolveFactoryOptions(options);
2373
+ const anyBaseResolved = baseResolved;
2374
+ const resolved = Object.freeze({
2375
+ ...baseResolved,
2376
+ htmlPropNormalizersFn: memoizedHtmlPropNormalizersPipeline(anyBaseResolved),
2377
+ htmlChildrenEvaluatorFn: memoizedHtmlChildrenEvaluatorPipeline(anyBaseResolved)
2378
+ });
2379
+ const anyResolved = resolved;
2380
+ if (process.env.NODE_ENV !== "production") {
2381
+ validateFactoryOptions(resolved, resolved.diagnostics);
2382
+ }
2383
+ const { pluginResult, classPipeline } = resolveClassPlugin(
2384
+ options.styling?.plugin,
2385
+ anyResolved,
2386
+ resolved.diagnostics
2387
+ );
2388
+ const resolveTag2 = memoizedTagPipeline(anyResolved);
2389
+ const resolveProps = memoizedPropsPipeline(anyResolved);
2390
+ const resolveAriaFn = options.enforcement !== void 0 ? memoizedAriaPipeline(anyResolved) : resolveAriaPassthrough;
2391
+ const methods = {
2392
+ resolveTag: resolveTag2,
2393
+ resolveProps,
2284
2394
  resolveClasses(tag, props, className, recipe) {
2285
2395
  if (process.env.NODE_ENV !== "production") {
2286
- validateRenderProps(renderDiagnostics, resolved, props, recipe);
2396
+ validateRenderProps(resolved.diagnostics, resolved, props, recipe);
2287
2397
  }
2288
2398
  return classPipeline(tag, props, className, recipe);
2289
2399
  },
2290
2400
  resolveAria(tag, props) {
2291
- if (!engine) return { props };
2292
- const result = engine.validate(tag, props);
2293
- return { props: result.props };
2401
+ return resolveAriaFn(tag, props);
2294
2402
  }
2295
2403
  };
2296
- }
2297
- function createRuntimeObject(methods, resolved, pluginResult) {
2298
- return pluginResult ? { ...methods, options: resolved, hasStyling: true, classPlugin: pluginResult } : { ...methods, options: resolved };
2299
- }
2300
- function createPolymorphic(options = {}, capabilities) {
2301
- const baseResolved = resolveFactoryOptions(options);
2302
- const resolved = capabilities?.htmlPropNormalizersFn !== void 0 ? Object.freeze({
2303
- ...baseResolved,
2304
- htmlPropNormalizersFn: capabilities.htmlPropNormalizersFn
2305
- }) : baseResolved;
2306
- if (process.env.NODE_ENV !== "production") {
2307
- validateFactoryOptions(resolved, resolved.diagnostics);
2308
- }
2309
- const { pluginResult, classPipeline } = resolveClassPipeline(
2310
- options,
2311
- resolved,
2312
- resolved.diagnostics,
2313
- capabilities
2314
- );
2315
- const allAriaRules = [
2316
- .../* @__PURE__ */ new Set([...capabilities?.htmlAriaRules ?? [], ...resolved.ariaRules ?? []])
2317
- ];
2318
- const engine = options.enforcement !== void 0 && capabilities?.AriaEngine ? new capabilities.AriaEngine(
2319
- resolved.diagnostics,
2320
- allAriaRules.length ? { rules: allAriaRules } : void 0
2321
- ) : null;
2322
- const methods = createRuntimeMethods(resolved, classPipeline, engine, resolved.diagnostics);
2323
- return createRuntimeObject(
2324
- methods,
2325
- resolved,
2326
- pluginResult
2327
- );
2328
- }
2329
-
2330
- // ../core/src/factory/create-polymorphic-full.ts
2331
- var FULL_CAPABILITIES = {
2332
- createClassPipeline,
2333
- AriaEngine: AriaPolicyEngine,
2334
- htmlAriaRules: HTML_ARIA_RULES,
2335
- htmlPropNormalizersFn: getHtmlPropNormalizers
2336
- };
2337
- function createPolymorphic2(options = {}) {
2338
- return createPolymorphic(options, FULL_CAPABILITIES);
2404
+ const runtimeObject = pluginResult ? { ...methods, options: resolved, hasStyling: true, classPlugin: pluginResult } : { ...methods, options: resolved };
2405
+ return runtimeObject;
2339
2406
  }
2340
2407
 
2341
- // ../../lib/adapter-utils/src/define-component.ts
2342
- function defineContractComponent(options) {
2343
- return (factory) => factory(options);
2408
+ // ../core/src/resolver/resolver.ts
2409
+ import { silentDiagnostics as silentDiagnostics2 } from "../_shared/diagnostics.js";
2410
+ function enforceAllowedAs(tag, allowedAs, diagnostics, displayName) {
2411
+ if (allowedAs.includes(tag)) return;
2412
+ if (!diagnostics) return;
2413
+ const component = displayName ?? String(tag);
2414
+ diagnostics.error(ContractDiagnostics.allowedAsViolation(String(tag), allowedAs, component));
2344
2415
  }
2345
2416
 
2346
- // ../../lib/adapter-utils/src/build-core-runtime.ts
2417
+ // ../../lib/adapter-utils/src/runtime/build-core-runtime.ts
2347
2418
  var EMPTY_SET = /* @__PURE__ */ new Set();
2348
2419
  function buildCoreRuntime(normalized) {
2349
2420
  const runtime = createPolymorphic2(normalized);
@@ -2351,55 +2422,41 @@ function buildCoreRuntime(normalized) {
2351
2422
  return { runtime, ownedKeys };
2352
2423
  }
2353
2424
 
2354
- // ../../lib/adapter-utils/src/build-engines.ts
2425
+ // ../../lib/adapter-utils/src/runtime/build-engines.ts
2355
2426
  function buildEngines(diagnostics, childRules, context) {
2356
2427
  return childRules?.length ? { childrenEvaluator: new ChildrenEvaluator(childRules, diagnostics, context) } : {};
2357
2428
  }
2358
2429
 
2359
- // ../../lib/adapter-utils/src/compose-filter.ts
2360
- function composeFilter(ownedKeys, filterProps) {
2361
- const defaultFilter = (key, variantKeys) => variantKeys.has(key) || ownedKeys.has(key);
2362
- if (!filterProps) {
2363
- return defaultFilter;
2364
- }
2365
- return (key, variantKeys) => defaultFilter(key, variantKeys) || filterProps(key, variantKeys);
2366
- }
2367
-
2368
- // ../../lib/adapter-utils/src/resolve-adapter-common-options.ts
2369
- function resolveAdapterCommonOptions(options, defaultName = "PolymorphicComponent", defaultDiagnostics = throwDiagnostics) {
2430
+ // ../../lib/adapter-utils/src/runtime/resolve-adapter-common-options.ts
2431
+ import { throwDiagnostics as throwDiagnostics2, silentDiagnostics as silentDiagnostics3 } from "../_shared/diagnostics.js";
2432
+ function resolveAdapterCommonOptions(options, defaultName = "PolymorphicComponent", defaultDiagnostics = throwDiagnostics2) {
2370
2433
  return {
2371
2434
  name: options.name ?? defaultName,
2372
2435
  diagnostics: options.enforcement?.diagnostics ?? defaultDiagnostics
2373
2436
  };
2374
2437
  }
2375
2438
 
2376
- // ../../adapters/web/src/build-runtime.ts
2377
- function buildRuntime(options) {
2378
- const normalized = {
2379
- ...options,
2380
- ...resolveAdapterCommonOptions(options, "PolymorphicElement", silentDiagnostics)
2381
- };
2382
- const { filterProps: customFilter, enforcement } = normalized;
2383
- const { runtime, ownedKeys } = buildCoreRuntime(normalized);
2384
- const { childrenEvaluator } = buildEngines(
2385
- normalized.diagnostics,
2386
- enforcement?.children,
2387
- normalized.name
2388
- );
2389
- const filterProps = composeFilter(ownedKeys, customFilter);
2390
- return {
2391
- runtime,
2392
- filterProps,
2393
- diagnostics: normalized.diagnostics,
2394
- ...childrenEvaluator !== void 0 && { childrenEvaluator }
2395
- };
2439
+ // ../../lib/adapter-utils/src/props/apply-filter.ts
2440
+ function applyFilter(props, filterProps, variantKeys) {
2441
+ const out = {};
2442
+ iterate.forEachEntry(props, (k) => {
2443
+ if (!Object.hasOwn(props, k)) return;
2444
+ if (filterProps(k, variantKeys)) return;
2445
+ out[k] = props[k];
2446
+ });
2447
+ return out;
2396
2448
  }
2397
2449
 
2398
- // ../../adapters/web/src/render-to-string.ts
2399
- var ssrRegistry = /* @__PURE__ */ new WeakMap();
2400
- function registerForSsr(cls, bundle) {
2401
- ssrRegistry.set(cls, { bundle });
2450
+ // ../../lib/adapter-utils/src/props/compose-filter.ts
2451
+ function composeFilter(ownedKeys, filterProps) {
2452
+ const defaultFilter = (key, variantKeys) => variantKeys.has(key) || ownedKeys.has(key);
2453
+ if (!filterProps) {
2454
+ return defaultFilter;
2455
+ }
2456
+ return (key, variantKeys) => defaultFilter(key, variantKeys) || filterProps(key, variantKeys);
2402
2457
  }
2458
+
2459
+ // ../../lib/adapter-utils/src/render/render-to-string.ts
2403
2460
  function escapeAttr(value) {
2404
2461
  return value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;");
2405
2462
  }
@@ -2413,50 +2470,51 @@ function buildAttrString(attributes) {
2413
2470
  parts.push(`${key}="${escapeAttr(String(value))}"`);
2414
2471
  }
2415
2472
  });
2416
- return parts.length > 0 ? " " + parts.join(" ") : "";
2473
+ return parts.length > 0 ? ` ${parts.join(" ")}` : "";
2417
2474
  }
2418
- function renderToString(component, props = {}, innerHTML = "") {
2419
- const entry = ssrRegistry.get(component);
2420
- if (!entry) {
2421
- const name = component.name ?? "AnonymousComponent";
2422
- throw new Error(
2423
- `[renderToString] ${name} was not registered for SSR. Ensure it was created with createContractComponent from @praxis-kit/web.`
2424
- );
2425
- }
2426
- const { bundle } = entry;
2475
+ function renderBundleToString(bundle, props = {}, innerHTML = "") {
2476
+ const {
2477
+ filterProps,
2478
+ runtime: { options, resolveAria, resolveClasses, resolveProps, resolveTag: resolveTag2 }
2479
+ } = bundle;
2427
2480
  const { as, className, recipe, class: classAttr, ...rest } = props;
2428
- const tag = bundle.runtime.resolveTag(as);
2429
- const mergedProps = bundle.runtime.resolveProps(rest);
2430
- const resolvedClass = bundle.runtime.resolveClasses(
2481
+ const tag = resolveTag2(as);
2482
+ if (options.allowedAs !== void 0) {
2483
+ enforceAllowedAs(tag, options.allowedAs, options.diagnostics, options.displayName);
2484
+ }
2485
+ const mergedProps = resolveProps(rest);
2486
+ const normalizedProps = typeof options.normalizeFn === "function" ? options.normalizeFn(mergedProps) : mergedProps;
2487
+ const htmlNormalizers = options.htmlPropNormalizersFn?.(tag);
2488
+ const finalProps = { ...normalizedProps };
2489
+ if (htmlNormalizers) {
2490
+ for (const normalize of htmlNormalizers) {
2491
+ Object.assign(finalProps, normalize(finalProps));
2492
+ }
2493
+ }
2494
+ const resolvedClass = resolveClasses(
2431
2495
  tag,
2432
- mergedProps,
2496
+ finalProps,
2497
+ // Accept both React-style className and HTML-native class
2433
2498
  className ?? classAttr,
2434
2499
  recipe
2435
2500
  );
2436
- const ariaResult = bundle.runtime.resolveAria(tag, mergedProps);
2437
- const filtered = applyFilter(
2438
- ariaResult.props,
2439
- bundle.filterProps,
2440
- bundle.runtime.options.variantKeys
2441
- );
2501
+ const ariaResult = resolveAria(tag, finalProps);
2502
+ const filtered = applyFilter(ariaResult.props, filterProps, options.variantKeys);
2442
2503
  const attrs = { ...filtered, class: resolvedClass || void 0 };
2443
2504
  const attrStr = buildAttrString(attrs);
2444
2505
  return `<${tag}${attrStr}>${innerHTML}</${tag}>`;
2445
2506
  }
2446
2507
 
2447
- // ../../adapters/web/src/create-contract-component.ts
2448
- function isObject2(value) {
2449
- return typeof value === "object" && value !== null;
2450
- }
2508
+ // ../../lib/adapter-utils/src/render/host-state.ts
2451
2509
  function isLooseBundle(arg) {
2452
- if (!isObject2(arg)) return false;
2510
+ if (!isObject(arg)) return false;
2453
2511
  const { runtime, filterProps, childrenEvaluator } = arg;
2454
- if (!isObject2(runtime)) return false;
2455
- if (!isObject2(runtime["options"])) return false;
2512
+ if (!isObject(runtime)) return false;
2513
+ if (!isObject(runtime["options"])) return false;
2456
2514
  if (typeof runtime["resolveTag"] !== "function" || typeof runtime["resolveProps"] !== "function" || typeof runtime["resolveClasses"] !== "function" || typeof runtime["resolveAria"] !== "function")
2457
2515
  return false;
2458
2516
  if (typeof filterProps !== "function") return false;
2459
- if (childrenEvaluator !== void 0 && (!isObject2(childrenEvaluator) || typeof childrenEvaluator["evaluate"] !== "function"))
2517
+ if (childrenEvaluator !== void 0 && (!isObject(childrenEvaluator) || typeof childrenEvaluator["evaluate"] !== "function"))
2460
2518
  return false;
2461
2519
  return true;
2462
2520
  }
@@ -2468,39 +2526,46 @@ function toLooseBundle(bundle) {
2468
2526
  }
2469
2527
  function resolveHostState(bundle, props) {
2470
2528
  const { as, className, recipe, ...rest } = props;
2471
- const tag = bundle.runtime.resolveTag(as);
2472
- const mergedProps = bundle.runtime.resolveProps(rest);
2473
- const baseProps = bundle.runtime.options.normalizeFn ? bundle.runtime.options.normalizeFn(mergedProps) : mergedProps;
2474
- const htmlNormalizers = bundle.runtime.options.htmlPropNormalizersFn?.(tag);
2475
- const normalizedProps = htmlNormalizers?.length ? htmlNormalizers.reduce((acc, fn) => ({ ...acc, ...fn(acc) }), baseProps) : baseProps;
2476
- const resolvedClass = bundle.runtime.resolveClasses(
2529
+ const { options, resolveAria, resolveClasses, resolveProps, resolveTag: resolveTag2 } = bundle.runtime;
2530
+ const tag = resolveTag2(as);
2531
+ if (options.allowedAs !== void 0) {
2532
+ enforceAllowedAs(tag, options.allowedAs, options.diagnostics, options.displayName);
2533
+ }
2534
+ const mergedProps = resolveProps(rest);
2535
+ const normalizedProps = typeof options.normalizeFn === "function" ? options.normalizeFn(mergedProps) : mergedProps;
2536
+ const htmlNormalizers = options.htmlPropNormalizersFn?.(tag);
2537
+ const finalProps = { ...normalizedProps };
2538
+ if (htmlNormalizers) {
2539
+ for (const normalize of htmlNormalizers) {
2540
+ Object.assign(finalProps, normalize(finalProps));
2541
+ }
2542
+ }
2543
+ const resolvedClass = resolveClasses(
2477
2544
  tag,
2478
- normalizedProps,
2545
+ finalProps,
2479
2546
  className,
2480
2547
  recipe
2481
2548
  );
2482
- const ariaResult = bundle.runtime.resolveAria(tag, normalizedProps);
2483
- const attributes = applyFilter(
2484
- ariaResult.props,
2485
- bundle.filterProps,
2486
- bundle.runtime.options.variantKeys
2487
- );
2549
+ const ariaResult = resolveAria(tag, finalProps);
2550
+ const attributes = applyFilter(ariaResult.props, bundle.filterProps, options.variantKeys);
2488
2551
  return { className: resolvedClass, attributes };
2489
2552
  }
2490
- function applyHostState(host, state, prevPipelineAttrs, incomingProps) {
2553
+ function diffAndApplyAttributes(host, state, prevPipelineAttrs, incomingProps) {
2554
+ const hasOwn2 = Object.hasOwn;
2555
+ const attrs = state.attributes;
2491
2556
  host.className = state.className;
2492
2557
  for (const key of prevPipelineAttrs) {
2493
- if (!Object.hasOwn(state.attributes, key)) host.removeAttribute(key);
2558
+ if (!hasOwn2(attrs, key)) host.removeAttribute(key);
2494
2559
  }
2495
2560
  prevPipelineAttrs.clear();
2496
2561
  for (const key in incomingProps) {
2497
- if (!Object.hasOwn(incomingProps, key)) continue;
2562
+ if (!hasOwn2(incomingProps, key)) continue;
2498
2563
  if (!key.startsWith("aria-") && key !== "role") continue;
2499
- if (!Object.hasOwn(state.attributes, key)) host.removeAttribute(key);
2564
+ if (!hasOwn2(attrs, key)) host.removeAttribute(key);
2500
2565
  }
2501
- for (const key in state.attributes) {
2502
- if (!Object.hasOwn(state.attributes, key)) continue;
2503
- const value = state.attributes[key];
2566
+ for (const key in attrs) {
2567
+ if (!hasOwn2(attrs, key)) continue;
2568
+ const value = attrs[key];
2504
2569
  if (value === void 0 || value === null || value === false) {
2505
2570
  host.removeAttribute(key);
2506
2571
  } else if (value === true) {
@@ -2512,6 +2577,47 @@ function applyHostState(host, state, prevPipelineAttrs, incomingProps) {
2512
2577
  }
2513
2578
  }
2514
2579
  }
2580
+
2581
+ // ../../adapters/web/src/build-runtime.ts
2582
+ import { silentDiagnostics as silentDiagnostics4 } from "../_shared/diagnostics.js";
2583
+ function buildRuntime(options) {
2584
+ const normalized = {
2585
+ ...options,
2586
+ ...resolveAdapterCommonOptions(options, "PolymorphicElement", silentDiagnostics4)
2587
+ };
2588
+ const { filterProps: customFilter, enforcement } = normalized;
2589
+ const { runtime, ownedKeys } = buildCoreRuntime(normalized);
2590
+ const { childrenEvaluator } = buildEngines(
2591
+ normalized.diagnostics,
2592
+ enforcement?.children,
2593
+ normalized.name
2594
+ );
2595
+ const filterProps = composeFilter(ownedKeys, customFilter);
2596
+ return {
2597
+ runtime,
2598
+ filterProps,
2599
+ diagnostics: normalized.diagnostics,
2600
+ ...childrenEvaluator !== void 0 && { childrenEvaluator }
2601
+ };
2602
+ }
2603
+
2604
+ // ../../adapters/web/src/render-to-string.ts
2605
+ var ssrRegistry = /* @__PURE__ */ new WeakMap();
2606
+ function registerForSsr(cls, bundle) {
2607
+ ssrRegistry.set(cls, { bundle });
2608
+ }
2609
+ function renderToString(component, props = {}, innerHTML = "") {
2610
+ const entry = ssrRegistry.get(component);
2611
+ if (!entry) {
2612
+ const name = component.name ?? "AnonymousComponent";
2613
+ throw new Error(
2614
+ `[renderToString] ${name} was not registered for SSR. Ensure it was created with createContractComponent from @praxis-kit/web.`
2615
+ );
2616
+ }
2617
+ return renderBundleToString(entry.bundle, props, innerHTML);
2618
+ }
2619
+
2620
+ // ../../adapters/web/src/create-contract-component.ts
2515
2621
  function createContractComponent(options) {
2516
2622
  const bundle = buildRuntime(options);
2517
2623
  const looseBundle = toLooseBundle(bundle);
@@ -2546,16 +2652,23 @@ function createContractComponent(options) {
2546
2652
  }
2547
2653
  _applyPraxis() {
2548
2654
  const self = this._self;
2549
- if (bundle.childrenEvaluator) {
2550
- bundle.childrenEvaluator.evaluate(Array.from(this.childNodes));
2655
+ const {
2656
+ childrenEvaluator,
2657
+ runtime: { options: options2, resolveTag: resolveTag2 }
2658
+ } = bundle;
2659
+ const tag = resolveTag2(self.as);
2660
+ const children = Array.from(this.childNodes);
2661
+ if (childrenEvaluator) {
2662
+ childrenEvaluator.evaluate(children);
2551
2663
  }
2664
+ options2.htmlChildrenEvaluatorFn?.(tag)?.evaluate(children);
2552
2665
  const observedSet = new Set(
2553
2666
  this.constructor.observedAttributes ?? []
2554
2667
  );
2555
2668
  const props = {};
2556
2669
  for (const attr of Array.from(this.attributes)) {
2557
2670
  if (attr.name === "class" || observedSet.has(attr.name)) continue;
2558
- props[attr.name] = attr.value;
2671
+ props[attr.name] = attr.name === "disabled" ? true : attr.value;
2559
2672
  }
2560
2673
  props["as"] = self.as ?? this.getAttribute("as") ?? void 0;
2561
2674
  props["recipe"] = self.recipe ?? this.getAttribute("variant-key") ?? void 0;
@@ -2564,7 +2677,7 @@ function createContractComponent(options) {
2564
2677
  const val = self[key] ?? this.getAttribute(key);
2565
2678
  if (val != null) props[key] = val;
2566
2679
  }
2567
- applyHostState(this, resolveHostState(looseBundle, props), this._pipelineAttrs, props);
2680
+ diffAndApplyAttributes(this, resolveHostState(looseBundle, props), this._pipelineAttrs, props);
2568
2681
  }
2569
2682
  }
2570
2683
  if (options.name) {