praxis-kit 1.1.0 → 2.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,4 +1,131 @@
1
- // ../core/dist/chunk-US6MPMDF.js
1
+ // ../../adapters/react/src/shared/merge-refs.ts
2
+ function mergeRefs(...refs) {
3
+ const active = refs.filter((r2) => r2 != null);
4
+ if (active.length === 0) return null;
5
+ if (active.length === 1) return active[0];
6
+ return (value) => {
7
+ for (const ref of active) {
8
+ if (typeof ref === "function") {
9
+ ref(value);
10
+ } else {
11
+ ref.current = value;
12
+ }
13
+ }
14
+ };
15
+ }
16
+
17
+ // ../../adapters/react/src/shared/slot/Slottable.tsx
18
+ import { Fragment } from "react";
19
+ import { jsx } from "react/jsx-runtime";
20
+ function Slottable({ children }) {
21
+ return /* @__PURE__ */ jsx(Fragment, { children });
22
+ }
23
+
24
+ // ../../lib/primitive/src/utils/is-object.ts
25
+ function isNull(value) {
26
+ return value === null;
27
+ }
28
+ function isObject(value) {
29
+ return !isNull(value) && typeof value === "object";
30
+ }
31
+
32
+ // ../../lib/primitive/src/merge/constants.ts
33
+ var EVENT_HANDLER_RE = /^on[A-Z]/;
34
+
35
+ // ../../lib/primitive/src/merge/predicates.ts
36
+ function isFunction(value) {
37
+ return typeof value === "function";
38
+ }
39
+ function isPlainObject(value) {
40
+ if (!isObject(value)) return false;
41
+ const proto = Object.getPrototypeOf(value);
42
+ return proto === Object.prototype || proto === null;
43
+ }
44
+
45
+ // ../shared/src/constants/primitive/slot-name.ts
46
+ var SLOT_NAME = "Slot";
47
+
48
+ // ../../adapters/react/src/shared/slot/clone.ts
49
+ import { cloneElement } from "react";
50
+ function cloneWithProps(child, props, ref) {
51
+ return cloneElement(child, ref !== null ? { ...props, ref } : props);
52
+ }
53
+
54
+ // ../../adapters/react/src/shared/slot/invariant.ts
55
+ function panic(message) {
56
+ throw new Error(message);
57
+ }
58
+ function invariant(condition, message) {
59
+ if (!condition) panic(message);
60
+ }
61
+
62
+ // ../../adapters/react/src/shared/slot/applySlot.ts
63
+ import { isValidElement as isValidElement3 } from "react";
64
+
65
+ // ../../adapters/react/src/shared/slot/extractSlottable.ts
66
+ import { createElement, Fragment as Fragment2, isValidElement as isValidElement2 } from "react";
67
+
68
+ // ../../adapters/react/src/shared/slot/predicates.ts
69
+ import { isValidElement } from "react";
70
+ function isSlottableElement(value) {
71
+ return isValidElement(value) && value.type === Slottable;
72
+ }
73
+
74
+ // ../../adapters/react/src/shared/slot/extractSlottable.ts
75
+ function extractSlottable(children) {
76
+ const childrenArray = Array.isArray(children) ? children : [children];
77
+ const slottables = childrenArray.filter(isSlottableElement);
78
+ invariant(slottables.length <= 1, "Slot: multiple Slottable children are not allowed");
79
+ if (slottables.length === 0) {
80
+ return null;
81
+ }
82
+ const [slottable] = slottables;
83
+ invariant(slottable, "Missing Slottable element");
84
+ const child = slottable.props.children;
85
+ invariant(
86
+ child !== null && child !== void 0,
87
+ "Slottable expects exactly one React element child, received null"
88
+ );
89
+ invariant(
90
+ typeof child !== "string" && typeof child !== "number",
91
+ "Slottable expects exactly one React element child, received text content"
92
+ );
93
+ invariant(isValidElement2(child), "Slottable expects exactly one React element child");
94
+ invariant(child.type !== Fragment2, "Slottable child cannot be a Fragment");
95
+ const index = childrenArray.indexOf(slottable);
96
+ return {
97
+ child,
98
+ // Fragment wrapper: Slot owns no DOM node; ref composition happens only on the merge target.
99
+ rebuild(merged) {
100
+ const out = childrenArray.map((node, i) => i === index ? merged : node);
101
+ return createElement(Fragment2, null, ...out);
102
+ }
103
+ };
104
+ }
105
+
106
+ // ../../adapters/react/src/shared/slot/applySlot.ts
107
+ function applySlot(children, slotProps, ref, cloneSlotChild) {
108
+ const extraction = extractSlottable(children);
109
+ if (extraction) {
110
+ const merged = cloneSlotChild({ child: extraction.child, slotProps, ref });
111
+ return extraction.rebuild(merged);
112
+ }
113
+ invariant(isValidElement3(children), "Slot: child must be a valid React element");
114
+ return cloneSlotChild({ child: children, slotProps, ref });
115
+ }
116
+
117
+ // ../../lib/adapter-utils/src/apply-filter.ts
118
+ function applyFilter(props, filterProps, variantKeys) {
119
+ const out = {};
120
+ for (const k in props) {
121
+ if (!Object.hasOwn(props, k)) continue;
122
+ if (filterProps(k, variantKeys)) continue;
123
+ out[k] = props[k];
124
+ }
125
+ return out;
126
+ }
127
+
128
+ // ../core/dist/chunk-XFCAUPVZ.js
2
129
  function makeResolveTag(defaultTag) {
3
130
  return function tag(as) {
4
131
  return as ?? defaultTag;
@@ -29,11 +156,11 @@ function mergeProps(defaultProps, props) {
29
156
  ...props
30
157
  };
31
158
  }
32
- function isNull(value) {
159
+ function isNull2(value) {
33
160
  return value === null;
34
161
  }
35
- function isObject(value) {
36
- return !isNull(value) && typeof value === "object";
162
+ function isObject2(value) {
163
+ return !isNull2(value) && typeof value === "object";
37
164
  }
38
165
  function isString(value) {
39
166
  return typeof value === "string";
@@ -169,7 +296,7 @@ function validateRenderProps(options, props, presetKey) {
169
296
  }
170
297
  }
171
298
  }
172
- function panic(message) {
299
+ function panic2(message) {
173
300
  throw new Error(message);
174
301
  }
175
302
  function describe(value) {
@@ -179,12 +306,12 @@ function describe(value) {
179
306
  }
180
307
  function assertPluginShape(result) {
181
308
  if (result === null || typeof result !== "object")
182
- panic(
309
+ panic2(
183
310
  `[praxis-kit] Plugin factory must return an object with a 'pipeline' function. Got: ${result === null ? "null" : typeof result}.`
184
311
  );
185
312
  const plugin = result;
186
313
  if (typeof plugin.pipeline !== "function")
187
- panic(
314
+ panic2(
188
315
  `[praxis-kit] Plugin factory return value is missing a 'pipeline' function. Got pipeline: ${typeof plugin.pipeline}.`
189
316
  );
190
317
  }
@@ -193,7 +320,7 @@ function guardPipeline(pipeline) {
193
320
  return function guardedPipeline(tag, props, className, variantKey) {
194
321
  const result = pipeline(tag, props, className, variantKey);
195
322
  if (typeof result !== "string")
196
- panic(`[praxis-kit] Plugin pipeline must return a string. Got: ${describe(result)}.`);
323
+ panic2(`[praxis-kit] Plugin pipeline must return a string. Got: ${describe(result)}.`);
197
324
  return result;
198
325
  };
199
326
  }
@@ -233,7 +360,11 @@ function createRuntimeObject(methods, resolved, pluginResult) {
233
360
  return pluginResult ? { ...methods, options: resolved, hasStyling: true, classPlugin: pluginResult } : { ...methods, options: resolved };
234
361
  }
235
362
  function createPolymorphic(options = {}, capabilities) {
236
- const resolved = resolveFactoryOptions(options);
363
+ const baseResolved = resolveFactoryOptions(options);
364
+ const resolved = capabilities?.htmlPropNormalizersFn !== void 0 ? Object.freeze({
365
+ ...baseResolved,
366
+ htmlPropNormalizersFn: capabilities.htmlPropNormalizersFn
367
+ }) : baseResolved;
237
368
  if (process.env.NODE_ENV !== "production") validateFactoryOptions(resolved);
238
369
  const { pluginResult, classPipeline } = resolveClassPipeline(
239
370
  options,
@@ -241,9 +372,12 @@ function createPolymorphic(options = {}, capabilities) {
241
372
  resolved.strict,
242
373
  capabilities
243
374
  );
375
+ const allAriaRules = [
376
+ .../* @__PURE__ */ new Set([...capabilities?.htmlAriaRules ?? [], ...resolved.ariaRules ?? []])
377
+ ];
244
378
  const engine = options.enforcement !== void 0 && capabilities?.AriaEngine ? new capabilities.AriaEngine(
245
379
  resolved.strict,
246
- resolved.ariaRules?.length ? { rules: resolved.ariaRules } : void 0
380
+ allAriaRules.length ? { rules: allAriaRules } : void 0
247
381
  ) : null;
248
382
  const methods = createRuntimeMethods(resolved, classPipeline, engine);
249
383
  return createRuntimeObject(
@@ -562,17 +696,45 @@ function isKnownAriaRole(value) {
562
696
  return isString(value) && KNOWN_ARIA_ROLES_SET.has(value);
563
697
  }
564
698
 
565
- // ../core/dist/chunk-7YNORQXK.js
699
+ // ../core/dist/chunk-VU44HAB7.js
700
+ var IMPLICIT_ROLE_RECORD2 = {
701
+ article: "article",
702
+ aside: "complementary",
703
+ footer: "contentinfo",
704
+ header: "banner",
705
+ main: "main",
706
+ nav: "navigation",
707
+ button: "button",
708
+ a: "link",
709
+ select: "listbox",
710
+ h1: "heading",
711
+ h2: "heading",
712
+ h3: "heading",
713
+ h4: "heading",
714
+ h5: "heading",
715
+ h6: "heading",
716
+ ul: "list",
717
+ ol: "list",
718
+ li: "listitem",
719
+ table: "table",
720
+ tr: "row",
721
+ td: "cell",
722
+ th: "columnheader"
723
+ };
724
+ function getImplicitRole(tag) {
725
+ if (tag in IMPLICIT_ROLE_RECORD2) return IMPLICIT_ROLE_RECORD2[tag];
726
+ return void 0;
727
+ }
566
728
  var COMPONENT_DEFAULT_TAG = /* @__PURE__ */ Symbol("praxis.component-default-tag");
567
729
  function resolveChildTag(child) {
568
- if (!isObject(child) || !("type" in child)) return void 0;
730
+ if (!isObject2(child) || !("type" in child)) return void 0;
569
731
  const t = child.type;
570
732
  if (isString(t)) return t;
571
- if (isObject(t) && COMPONENT_DEFAULT_TAG in t) {
733
+ if (isObject2(t) && COMPONENT_DEFAULT_TAG in t) {
572
734
  const defaultTag = t[COMPONENT_DEFAULT_TAG];
573
735
  if (!isString(defaultTag)) return void 0;
574
736
  const props = child.props;
575
- const as = isObject(props) && "as" in props ? props.as : void 0;
737
+ const as = isObject2(props) && "as" in props ? props.as : void 0;
576
738
  return isString(as) ? as : defaultTag;
577
739
  }
578
740
  return void 0;
@@ -584,245 +746,61 @@ function isTag(...tags) {
584
746
  return tag !== void 0 && set.has(tag);
585
747
  };
586
748
  }
587
- function isOpenContent(...blockedTags) {
588
- const set = new Set(blockedTags);
589
- return (child) => isObject(child) && "type" in child && (!isString(child.type) || !set.has(child.type));
590
- }
591
- var METADATA_TAGS = ["script", "template"];
592
- var metadataMatch = isTag(...METADATA_TAGS);
593
- function metadata(name = "metadata") {
594
- return { name, match: metadataMatch };
749
+ var pendingAsyncWarns2 = /* @__PURE__ */ new Set();
750
+ var asyncWarnScheduled2 = false;
751
+ function flushAsyncWarns2() {
752
+ asyncWarnScheduled2 = false;
753
+ const messages = [...pendingAsyncWarns2];
754
+ pendingAsyncWarns2.clear();
755
+ for (const msg of messages) {
756
+ console.warn(msg);
757
+ }
595
758
  }
596
- function firstOptional(name, tag) {
597
- return { name, match: isTag(tag), cardinality: { max: 1 }, position: "first" };
759
+ function scheduleAsyncWarn(message) {
760
+ if (pendingAsyncWarns2.has(message)) return;
761
+ pendingAsyncWarns2.add(message);
762
+ if (!asyncWarnScheduled2) {
763
+ asyncWarnScheduled2 = true;
764
+ queueMicrotask(flushAsyncWarns2);
765
+ }
598
766
  }
599
- function contract(children) {
600
- return { strict: "warn", children };
767
+ var StrictBase = class {
768
+ strict;
769
+ constructor(strict) {
770
+ this.strict = strict;
771
+ }
772
+ violate(message) {
773
+ if (this.strict === true || this.strict === "throw") {
774
+ throw new Error(message);
775
+ }
776
+ this.warn(message);
777
+ }
778
+ // Always caps at console.warn — never throws. ARIA 'warning' violations route here
779
+ // so they surface even in strict='throw' mode without aborting a render.
780
+ warn(message) {
781
+ if (!this.strict) return;
782
+ if (this.strict === "async-warn") {
783
+ scheduleAsyncWarn(message);
784
+ return;
785
+ }
786
+ console.warn(message);
787
+ }
788
+ invariant(condition, message) {
789
+ if (!condition) {
790
+ this.violate(message);
791
+ }
792
+ }
793
+ };
794
+ function isNull3(value) {
795
+ return value === null;
601
796
  }
602
- function ariaContract(aria) {
603
- return { strict: "warn", aria };
797
+ var VALID = [{ valid: true }];
798
+ function isIntrinsicTag(tag) {
799
+ return isString(tag);
604
800
  }
605
- function firstChildContract(name, tag) {
606
- return contract([firstOptional(name, tag), { name: "content", match: isOpenContent(tag) }]);
607
- }
608
- var VOID_TAGS = [
609
- "area",
610
- "base",
611
- "br",
612
- "col",
613
- "embed",
614
- "hr",
615
- "img",
616
- "input",
617
- "link",
618
- "meta",
619
- "param",
620
- "source",
621
- "track",
622
- "wbr"
623
- ];
624
- var TEXT_ONLY_TAGS = ["option", "script", "style", "textarea", "title"];
625
- var LANDMARK_TAGS = ["article", "aside", "footer", "header", "main", "nav"];
626
- var listContract = contract([{ name: "list-item", match: isTag("li", ...METADATA_TAGS) }]);
627
- var tableContract = contract([
628
- firstOptional("caption", "caption"),
629
- { name: "colgroup", match: isTag("colgroup") },
630
- { name: "thead", match: isTag("thead"), cardinality: { max: 1 } },
631
- { name: "tbody", match: isTag("tbody") },
632
- { name: "tfoot", match: isTag("tfoot"), cardinality: { max: 1 } },
633
- { name: "table-row", match: isTag("tr", ...METADATA_TAGS) }
634
- ]);
635
- var tableBodyContract = contract([
636
- { name: "table-row", match: isTag("tr", ...METADATA_TAGS) }
637
- ]);
638
- var tableRowContract = contract([
639
- { name: "table-cell", match: isTag("td", "th", ...METADATA_TAGS) }
640
- ]);
641
- var colgroupContract = contract([{ name: "column", match: isTag("col", "template") }]);
642
- var dlContract = contract([
643
- { name: "term", match: isTag("dt") },
644
- { name: "description", match: isTag("dd") },
645
- { name: "group", match: isTag("div") },
646
- metadata()
647
- ]);
648
- var selectContract = contract([
649
- { name: "option", match: isTag("option", "optgroup", "hr", ...METADATA_TAGS) }
650
- ]);
651
- var optgroupContract = contract([
652
- { name: "option", match: isTag("option", ...METADATA_TAGS) }
653
- ]);
654
- var datalistContract = contract([
655
- { name: "option", match: isTag("option", ...METADATA_TAGS) }
656
- ]);
657
- var pictureContract = contract([
658
- { name: "source", match: isTag("source", ...METADATA_TAGS) },
659
- { name: "image", match: isTag("img"), cardinality: { min: 1, max: 1 }, position: "last" }
660
- ]);
661
- var figureContract = contract([
662
- { name: "caption", match: isTag("figcaption"), cardinality: { max: 1 } },
663
- { name: "content", match: isOpenContent("figcaption") }
664
- ]);
665
- var detailsContract = firstChildContract("summary", "summary");
666
- var fieldsetContract = firstChildContract("legend", "legend");
667
- var mediaContract = contract([
668
- { name: "source", match: isTag("source") },
669
- { name: "track", match: isTag("track") },
670
- metadata(),
671
- { name: "content", match: isOpenContent("source", "track", ...METADATA_TAGS) }
672
- ]);
673
- var headContract = contract([
674
- {
675
- name: "metadata",
676
- match: isTag("base", "link", "meta", "noscript", "script", "style", "template", "title")
677
- }
678
- ]);
679
- var htmlContract = contract([
680
- { name: "head", match: isTag("head"), cardinality: { min: 1, max: 1 }, position: "first" },
681
- { name: "body", match: isTag("body"), cardinality: { min: 1, max: 1 } }
682
- ]);
683
- var voidContract = contract([]);
684
- var textOnlyContract = contract([
685
- {
686
- name: "text",
687
- match: (child) => isString(child) || isNumber(child)
688
- }
689
- ]);
690
- var LANDMARK_TAG_SET = new Set(LANDMARK_TAGS);
691
- var removeLandmarkRoleOverride = {
692
- kind: "removeRole",
693
- apply: ({ props }) => {
694
- if (!("role" in props)) return { applied: false, next: props };
695
- const { role: _r, ...rest } = props;
696
- return { applied: true, next: rest, previous: props };
697
- }
698
- };
699
- function landmarkRoleRule({ tag, props, implicitRole }) {
700
- if (!LANDMARK_TAG_SET.has(tag) || !implicitRole) return [];
701
- const role = props.role;
702
- if (!role || role === implicitRole) return [];
703
- return [
704
- {
705
- valid: false,
706
- fixable: true,
707
- severity: "error",
708
- fix: removeLandmarkRoleOverride,
709
- message: `<${tag}> has a fixed landmark role="${implicitRole}". role="${role}" overrides it and confuses assistive technology. The override has been removed.`
710
- }
711
- ];
712
- }
713
- var landmarkContract = ariaContract([landmarkRoleRule]);
714
- var CONTRACT_GROUPS = [
715
- [VOID_TAGS, voidContract],
716
- [TEXT_ONLY_TAGS, textOnlyContract],
717
- [LANDMARK_TAGS, landmarkContract],
718
- [["ul", "ol", "menu"], listContract],
719
- [["audio", "video"], mediaContract],
720
- [["thead", "tbody", "tfoot"], tableBodyContract]
721
- ];
722
- function contractMap(groups) {
723
- return Object.fromEntries(
724
- groups.flatMap(([tags, enforcement]) => tags.map((tag) => [tag, enforcement]))
725
- );
726
- }
727
- var htmlContracts = {
728
- ...contractMap(CONTRACT_GROUPS),
729
- table: tableContract,
730
- tr: tableRowContract,
731
- colgroup: colgroupContract,
732
- dl: dlContract,
733
- select: selectContract,
734
- optgroup: optgroupContract,
735
- datalist: datalistContract,
736
- picture: pictureContract,
737
- figure: figureContract,
738
- details: detailsContract,
739
- fieldset: fieldsetContract,
740
- head: headContract,
741
- html: htmlContract
742
- };
743
- var IMPLICIT_ROLE_RECORD2 = {
744
- article: "article",
745
- aside: "complementary",
746
- footer: "contentinfo",
747
- header: "banner",
748
- main: "main",
749
- nav: "navigation",
750
- button: "button",
751
- a: "link",
752
- select: "listbox",
753
- h1: "heading",
754
- h2: "heading",
755
- h3: "heading",
756
- h4: "heading",
757
- h5: "heading",
758
- h6: "heading",
759
- ul: "list",
760
- ol: "list",
761
- li: "listitem",
762
- table: "table",
763
- tr: "row",
764
- td: "cell",
765
- th: "columnheader"
766
- };
767
- function getImplicitRole(tag) {
768
- if (tag in IMPLICIT_ROLE_RECORD2) return IMPLICIT_ROLE_RECORD2[tag];
769
- return void 0;
770
- }
771
- var pendingAsyncWarns2 = /* @__PURE__ */ new Set();
772
- var asyncWarnScheduled2 = false;
773
- function flushAsyncWarns2() {
774
- asyncWarnScheduled2 = false;
775
- const messages = [...pendingAsyncWarns2];
776
- pendingAsyncWarns2.clear();
777
- for (const msg of messages) {
778
- console.warn(msg);
779
- }
780
- }
781
- function scheduleAsyncWarn(message) {
782
- if (pendingAsyncWarns2.has(message)) return;
783
- pendingAsyncWarns2.add(message);
784
- if (!asyncWarnScheduled2) {
785
- asyncWarnScheduled2 = true;
786
- queueMicrotask(flushAsyncWarns2);
787
- }
788
- }
789
- var StrictBase = class {
790
- strict;
791
- constructor(strict) {
792
- this.strict = strict;
793
- }
794
- violate(message) {
795
- if (this.strict === true || this.strict === "throw") {
796
- throw new Error(message);
797
- }
798
- this.warn(message);
799
- }
800
- // Always caps at console.warn — never throws. ARIA 'warning' violations route here
801
- // so they surface even in strict='throw' mode without aborting a render.
802
- warn(message) {
803
- if (!this.strict) return;
804
- if (this.strict === "async-warn") {
805
- scheduleAsyncWarn(message);
806
- return;
807
- }
808
- console.warn(message);
809
- }
810
- invariant(condition, message) {
811
- if (!condition) {
812
- this.violate(message);
813
- }
814
- }
815
- };
816
- function isNull2(value) {
817
- return value === null;
818
- }
819
- var VALID = [{ valid: true }];
820
- function isIntrinsicTag(tag) {
821
- return isString(tag);
822
- }
823
- function omitProp(obj, key) {
824
- const { [key]: _, ...rest } = obj;
825
- return rest;
801
+ function omitProp(obj, key) {
802
+ const { [key]: _, ...rest } = obj;
803
+ return rest;
826
804
  }
827
805
  var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
828
806
  #extraRules;
@@ -968,7 +946,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
968
946
  }
969
947
  validate(tag, props) {
970
948
  const key = _AriaPolicyEngine.#createPlanKey(tag, props);
971
- if (!isNull2(key)) {
949
+ if (!isNull3(key)) {
972
950
  const cached = this.#planCache.get(key);
973
951
  if (cached !== void 0) {
974
952
  this.#planCache.delete(key);
@@ -982,7 +960,7 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends StrictBase {
982
960
  }
983
961
  const result = this.#extraRules.length ? _AriaPolicyEngine.#evaluateWithRules(tag, props, this.#extraRules) : _AriaPolicyEngine.evaluate(tag, props);
984
962
  if (result.violations.length > 0) this.report(result.violations);
985
- if (!isNull2(key)) {
963
+ if (!isNull3(key)) {
986
964
  const { removals, updates } = _AriaPolicyEngine.#computePlan(
987
965
  props,
988
966
  result.props
@@ -1265,7 +1243,7 @@ function normalizeChildRule(rule) {
1265
1243
  };
1266
1244
  }
1267
1245
  function getChildType(child) {
1268
- if (!isObject(child) || !("type" in child)) return void 0;
1246
+ if (!isObject2(child) || !("type" in child)) return void 0;
1269
1247
  return child.type;
1270
1248
  }
1271
1249
  function buildPartialIndex(rules) {
@@ -1437,6 +1415,21 @@ var ChildrenEvaluator = class extends StrictBase {
1437
1415
  this.invariant(errors.length === 0, this.#matchBuilder.toError(errors).message);
1438
1416
  }
1439
1417
  };
1418
+ var activeProps = ({
1419
+ active,
1420
+ "aria-current": ariaCurrent,
1421
+ "data-active": dataActive
1422
+ }) => {
1423
+ if (!active) return {};
1424
+ return {
1425
+ ...ariaCurrent === void 0 && {
1426
+ "aria-current": "true"
1427
+ },
1428
+ ...dataActive === void 0 && {
1429
+ "data-active": ""
1430
+ }
1431
+ };
1432
+ };
1440
1433
  var disabledProps = ({
1441
1434
  disabled,
1442
1435
  "aria-disabled": ariaDisabled,
@@ -1448,6 +1441,21 @@ var disabledProps = ({
1448
1441
  ...dataDisabled === void 0 && { "data-disabled": "" }
1449
1442
  };
1450
1443
  };
1444
+ var expandedProps = ({
1445
+ expanded,
1446
+ "aria-expanded": ariaExpanded,
1447
+ "data-expanded": dataExpanded
1448
+ }) => {
1449
+ if (!expanded) return {};
1450
+ return {
1451
+ ...ariaExpanded === void 0 && {
1452
+ "aria-expanded": "true"
1453
+ },
1454
+ ...dataExpanded === void 0 && {
1455
+ "data-expanded": ""
1456
+ }
1457
+ };
1458
+ };
1451
1459
  var invalidProps = ({
1452
1460
  invalid,
1453
1461
  "aria-invalid": ariaInvalid,
@@ -1459,6 +1467,247 @@ var invalidProps = ({
1459
1467
  ...dataInvalid === void 0 && { "data-invalid": "" }
1460
1468
  };
1461
1469
  };
1470
+ var loadingProps = ({
1471
+ loading,
1472
+ "aria-busy": ariaBusy,
1473
+ "data-loading": dataLoading
1474
+ }) => {
1475
+ if (!loading) return {};
1476
+ return {
1477
+ ...ariaBusy === void 0 && {
1478
+ "aria-busy": "true"
1479
+ },
1480
+ ...dataLoading === void 0 && {
1481
+ "data-loading": ""
1482
+ }
1483
+ };
1484
+ };
1485
+ var pressedProps = ({
1486
+ pressed,
1487
+ "aria-pressed": ariaPressed,
1488
+ "data-pressed": dataPressed
1489
+ }) => {
1490
+ if (!pressed) return {};
1491
+ return {
1492
+ ...ariaPressed === void 0 && {
1493
+ "aria-pressed": "true"
1494
+ },
1495
+ ...dataPressed === void 0 && {
1496
+ "data-pressed": ""
1497
+ }
1498
+ };
1499
+ };
1500
+ var readonlyProps = ({
1501
+ readOnly,
1502
+ "aria-readonly": ariaReadonly,
1503
+ "data-readonly": dataReadonly
1504
+ }) => {
1505
+ if (!readOnly) return {};
1506
+ return {
1507
+ ...ariaReadonly === void 0 && {
1508
+ "aria-readonly": "true"
1509
+ },
1510
+ ...dataReadonly === void 0 && {
1511
+ "data-readonly": ""
1512
+ }
1513
+ };
1514
+ };
1515
+ var selectedProps = ({
1516
+ selected,
1517
+ "aria-selected": ariaSelected,
1518
+ "data-selected": dataSelected
1519
+ }) => {
1520
+ if (!selected) return {};
1521
+ return {
1522
+ ...ariaSelected === void 0 && {
1523
+ "aria-selected": "true"
1524
+ },
1525
+ ...dataSelected === void 0 && {
1526
+ "data-selected": ""
1527
+ }
1528
+ };
1529
+ };
1530
+ var LANDMARK_TAG_SET = /* @__PURE__ */ new Set(["article", "aside", "footer", "header", "main", "nav"]);
1531
+ var removeLandmarkRoleOverride = {
1532
+ kind: "removeRole",
1533
+ apply: ({ props }) => {
1534
+ if (!("role" in props)) return { applied: false, next: props };
1535
+ const { role: _r, ...rest } = props;
1536
+ return { applied: true, next: rest, previous: props };
1537
+ }
1538
+ };
1539
+ function landmarkRoleRule({ tag, props, implicitRole }) {
1540
+ if (!LANDMARK_TAG_SET.has(tag) || !implicitRole) return [];
1541
+ const role = props.role;
1542
+ if (!role || role === implicitRole) return [];
1543
+ return [
1544
+ {
1545
+ valid: false,
1546
+ fixable: true,
1547
+ severity: "error",
1548
+ fix: removeLandmarkRoleOverride,
1549
+ message: `<${tag}> has a fixed landmark role="${implicitRole}". role="${role}" overrides it and confuses assistive technology. The override has been removed.`
1550
+ }
1551
+ ];
1552
+ }
1553
+ var HTML_ARIA_RULES = [landmarkRoleRule];
1554
+ function isOpenContent(...blockedTags) {
1555
+ const set = new Set(blockedTags);
1556
+ return (child) => isObject2(child) && "type" in child && (!isString(child.type) || !set.has(child.type));
1557
+ }
1558
+ var METADATA_TAGS = ["script", "template"];
1559
+ var metadataMatch = isTag(...METADATA_TAGS);
1560
+ function metadata(name = "metadata") {
1561
+ return { name, match: metadataMatch };
1562
+ }
1563
+ function firstOptional(name, tag) {
1564
+ return { name, match: isTag(tag), cardinality: { max: 1 }, position: "first" };
1565
+ }
1566
+ function contract(children) {
1567
+ return { strict: "warn", children };
1568
+ }
1569
+ function ariaContract(aria) {
1570
+ return { strict: "warn", aria };
1571
+ }
1572
+ function firstChildContract(name, tag) {
1573
+ return contract([firstOptional(name, tag), { name: "content", match: isOpenContent(tag) }]);
1574
+ }
1575
+ var VOID_TAGS = [
1576
+ "area",
1577
+ "base",
1578
+ "br",
1579
+ "col",
1580
+ "embed",
1581
+ "hr",
1582
+ "img",
1583
+ "input",
1584
+ "link",
1585
+ "meta",
1586
+ "param",
1587
+ "source",
1588
+ "track",
1589
+ "wbr"
1590
+ ];
1591
+ var TEXT_ONLY_TAGS = ["option", "script", "style", "textarea", "title"];
1592
+ var LANDMARK_TAGS = ["article", "aside", "footer", "header", "main", "nav"];
1593
+ var listContract = contract([{ name: "list-item", match: isTag("li", ...METADATA_TAGS) }]);
1594
+ var tableContract = contract([
1595
+ firstOptional("caption", "caption"),
1596
+ { name: "colgroup", match: isTag("colgroup") },
1597
+ { name: "thead", match: isTag("thead"), cardinality: { max: 1 } },
1598
+ { name: "tbody", match: isTag("tbody") },
1599
+ { name: "tfoot", match: isTag("tfoot"), cardinality: { max: 1 } },
1600
+ { name: "table-row", match: isTag("tr", ...METADATA_TAGS) }
1601
+ ]);
1602
+ var tableBodyContract = contract([
1603
+ { name: "table-row", match: isTag("tr", ...METADATA_TAGS) }
1604
+ ]);
1605
+ var tableRowContract = contract([
1606
+ { name: "table-cell", match: isTag("td", "th", ...METADATA_TAGS) }
1607
+ ]);
1608
+ var colgroupContract = contract([{ name: "column", match: isTag("col", "template") }]);
1609
+ var dlContract = contract([
1610
+ { name: "term", match: isTag("dt") },
1611
+ { name: "description", match: isTag("dd") },
1612
+ { name: "group", match: isTag("div") },
1613
+ metadata()
1614
+ ]);
1615
+ var selectContract = contract([
1616
+ { name: "option", match: isTag("option", "optgroup", "hr", ...METADATA_TAGS) }
1617
+ ]);
1618
+ var optgroupContract = contract([
1619
+ { name: "option", match: isTag("option", ...METADATA_TAGS) }
1620
+ ]);
1621
+ var datalistContract = contract([
1622
+ { name: "option", match: isTag("option", ...METADATA_TAGS) }
1623
+ ]);
1624
+ var pictureContract = contract([
1625
+ { name: "source", match: isTag("source", ...METADATA_TAGS) },
1626
+ { name: "image", match: isTag("img"), cardinality: { min: 1, max: 1 }, position: "last" }
1627
+ ]);
1628
+ var figureContract = contract([
1629
+ { name: "caption", match: isTag("figcaption"), cardinality: { max: 1 } },
1630
+ { name: "content", match: isOpenContent("figcaption") }
1631
+ ]);
1632
+ var detailsContract = firstChildContract("summary", "summary");
1633
+ var fieldsetContract = firstChildContract("legend", "legend");
1634
+ var mediaContract = contract([
1635
+ { name: "source", match: isTag("source") },
1636
+ { name: "track", match: isTag("track") },
1637
+ metadata(),
1638
+ { name: "content", match: isOpenContent("source", "track", ...METADATA_TAGS) }
1639
+ ]);
1640
+ var headContract = contract([
1641
+ {
1642
+ name: "metadata",
1643
+ match: isTag("base", "link", "meta", "noscript", "script", "style", "template", "title")
1644
+ }
1645
+ ]);
1646
+ var htmlContract = contract([
1647
+ { name: "head", match: isTag("head"), cardinality: { min: 1, max: 1 }, position: "first" },
1648
+ { name: "body", match: isTag("body"), cardinality: { min: 1, max: 1 } }
1649
+ ]);
1650
+ var voidContract = contract([]);
1651
+ var textOnlyContract = contract([
1652
+ {
1653
+ name: "text",
1654
+ match: (child) => isString(child) || isNumber(child)
1655
+ }
1656
+ ]);
1657
+ var landmarkContract = ariaContract([landmarkRoleRule]);
1658
+ var CONTRACT_GROUPS = [
1659
+ [VOID_TAGS, voidContract],
1660
+ [TEXT_ONLY_TAGS, textOnlyContract],
1661
+ [LANDMARK_TAGS, landmarkContract],
1662
+ [["ul", "ol", "menu"], listContract],
1663
+ [["audio", "video"], mediaContract],
1664
+ [["thead", "tbody", "tfoot"], tableBodyContract]
1665
+ ];
1666
+ function contractMap(groups) {
1667
+ return Object.fromEntries(
1668
+ groups.flatMap(([tags, enforcement]) => tags.map((tag) => [tag, enforcement]))
1669
+ );
1670
+ }
1671
+ var htmlContracts = {
1672
+ ...contractMap(CONTRACT_GROUPS),
1673
+ table: tableContract,
1674
+ tr: tableRowContract,
1675
+ colgroup: colgroupContract,
1676
+ dl: dlContract,
1677
+ select: selectContract,
1678
+ optgroup: optgroupContract,
1679
+ datalist: datalistContract,
1680
+ picture: pictureContract,
1681
+ figure: figureContract,
1682
+ details: detailsContract,
1683
+ fieldset: fieldsetContract,
1684
+ head: headContract,
1685
+ html: htmlContract
1686
+ };
1687
+ function buildEvaluatorMap() {
1688
+ const map = /* @__PURE__ */ new Map();
1689
+ for (const [tag, { children }] of Object.entries(htmlContracts)) {
1690
+ if (children?.length) {
1691
+ map.set(tag, new ChildrenEvaluator(children, "warn", `<${tag}>`));
1692
+ }
1693
+ }
1694
+ return map;
1695
+ }
1696
+ var HTML_EVALUATORS = buildEvaluatorMap();
1697
+ function getHtmlChildrenEvaluator(tag) {
1698
+ return typeof tag === "string" ? HTML_EVALUATORS.get(tag) : void 0;
1699
+ }
1700
+ var HTML_FORM_NORMALIZERS = /* @__PURE__ */ new Map([
1701
+ ["button", [disabledProps]],
1702
+ ["input", [disabledProps, readonlyProps, invalidProps]],
1703
+ ["select", [disabledProps]],
1704
+ ["textarea", [disabledProps, readonlyProps]],
1705
+ ["fieldset", [disabledProps]],
1706
+ ["optgroup", [disabledProps]]
1707
+ ]);
1708
+ function getHtmlPropNormalizers(tag) {
1709
+ return typeof tag === "string" ? HTML_FORM_NORMALIZERS.get(tag) : void 0;
1710
+ }
1462
1711
  function enforceAllowedAs(tag, allowedAs, strict, displayName) {
1463
1712
  if (allowedAs.includes(tag)) return;
1464
1713
  const component = displayName ? `<${displayName}>` : "component";
@@ -1472,7 +1721,7 @@ function enforceAllowedAs(tag, allowedAs, strict, displayName) {
1472
1721
  }
1473
1722
  }
1474
1723
 
1475
- // ../core/dist/chunk-RHOMAG5Q.js
1724
+ // ../core/dist/chunk-EHCOMLJ4.js
1476
1725
  var falsyToString = (value) => typeof value === "boolean" ? `${value}` : value === 0 ? "0" : value;
1477
1726
  var cx = clsx;
1478
1727
  var cva = (base, config) => (props) => {
@@ -1638,138 +1887,16 @@ function createClassPipeline(resolved) {
1638
1887
  }
1639
1888
 
1640
1889
  // ../core/dist/index.js
1641
- var FULL_CAPABILITIES = { createClassPipeline, AriaEngine: AriaPolicyEngine };
1890
+ var FULL_CAPABILITIES = {
1891
+ createClassPipeline,
1892
+ AriaEngine: AriaPolicyEngine,
1893
+ htmlAriaRules: HTML_ARIA_RULES,
1894
+ htmlPropNormalizersFn: getHtmlPropNormalizers
1895
+ };
1642
1896
  function createPolymorphic2(options = {}) {
1643
1897
  return createPolymorphic(options, FULL_CAPABILITIES);
1644
1898
  }
1645
1899
 
1646
- // ../../adapters/react/src/shared/merge-refs.ts
1647
- function mergeRefs(...refs) {
1648
- const active = refs.filter((r2) => r2 != null);
1649
- if (active.length === 0) return null;
1650
- if (active.length === 1) return active[0];
1651
- return (value) => {
1652
- for (const ref of active) {
1653
- if (typeof ref === "function") {
1654
- ref(value);
1655
- } else {
1656
- ref.current = value;
1657
- }
1658
- }
1659
- };
1660
- }
1661
-
1662
- // ../../adapters/react/src/shared/slot/Slottable.tsx
1663
- import { Fragment } from "react";
1664
- import { jsx } from "react/jsx-runtime";
1665
- function Slottable({ children }) {
1666
- return /* @__PURE__ */ jsx(Fragment, { children });
1667
- }
1668
-
1669
- // ../../lib/primitive/src/utils/is-object.ts
1670
- function isNull3(value) {
1671
- return value === null;
1672
- }
1673
- function isObject2(value) {
1674
- return !isNull3(value) && typeof value === "object";
1675
- }
1676
-
1677
- // ../../lib/primitive/src/merge/constants.ts
1678
- var EVENT_HANDLER_RE = /^on[A-Z]/;
1679
-
1680
- // ../../lib/primitive/src/merge/predicates.ts
1681
- function isFunction(value) {
1682
- return typeof value === "function";
1683
- }
1684
- function isPlainObject(value) {
1685
- if (!isObject2(value)) return false;
1686
- const proto = Object.getPrototypeOf(value);
1687
- return proto === Object.prototype || proto === null;
1688
- }
1689
-
1690
- // ../shared/src/constants/primitive/slot-name.ts
1691
- var SLOT_NAME = "Slot";
1692
-
1693
- // ../../adapters/react/src/shared/slot/clone.ts
1694
- import { cloneElement } from "react";
1695
- function cloneWithProps(child, props, ref) {
1696
- return cloneElement(child, ref !== null ? { ...props, ref } : props);
1697
- }
1698
-
1699
- // ../../adapters/react/src/shared/slot/invariant.ts
1700
- function panic2(message) {
1701
- throw new Error(message);
1702
- }
1703
- function invariant(condition, message) {
1704
- if (!condition) panic2(message);
1705
- }
1706
-
1707
- // ../../adapters/react/src/shared/slot/applySlot.ts
1708
- import { isValidElement as isValidElement3 } from "react";
1709
-
1710
- // ../../adapters/react/src/shared/slot/extractSlottable.ts
1711
- import { createElement, Fragment as Fragment2, isValidElement as isValidElement2 } from "react";
1712
-
1713
- // ../../adapters/react/src/shared/slot/predicates.ts
1714
- import { isValidElement } from "react";
1715
- function isSlottableElement(value) {
1716
- return isValidElement(value) && value.type === Slottable;
1717
- }
1718
-
1719
- // ../../adapters/react/src/shared/slot/extractSlottable.ts
1720
- function extractSlottable(children) {
1721
- const childrenArray = Array.isArray(children) ? children : [children];
1722
- const slottables = childrenArray.filter(isSlottableElement);
1723
- invariant(slottables.length <= 1, "Slot: multiple Slottable children are not allowed");
1724
- if (slottables.length === 0) {
1725
- return null;
1726
- }
1727
- const [slottable] = slottables;
1728
- invariant(slottable, "Missing Slottable element");
1729
- const child = slottable.props.children;
1730
- invariant(
1731
- child !== null && child !== void 0,
1732
- "Slottable expects exactly one React element child, received null"
1733
- );
1734
- invariant(
1735
- typeof child !== "string" && typeof child !== "number",
1736
- "Slottable expects exactly one React element child, received text content"
1737
- );
1738
- invariant(isValidElement2(child), "Slottable expects exactly one React element child");
1739
- invariant(child.type !== Fragment2, "Slottable child cannot be a Fragment");
1740
- const index = childrenArray.indexOf(slottable);
1741
- return {
1742
- child,
1743
- // Fragment wrapper: Slot owns no DOM node; ref composition happens only on the merge target.
1744
- rebuild(merged) {
1745
- const out = childrenArray.map((node, i) => i === index ? merged : node);
1746
- return createElement(Fragment2, null, ...out);
1747
- }
1748
- };
1749
- }
1750
-
1751
- // ../../adapters/react/src/shared/slot/applySlot.ts
1752
- function applySlot(children, slotProps, ref, cloneSlotChild) {
1753
- const extraction = extractSlottable(children);
1754
- if (extraction) {
1755
- const merged = cloneSlotChild({ child: extraction.child, slotProps, ref });
1756
- return extraction.rebuild(merged);
1757
- }
1758
- invariant(isValidElement3(children), "Slot: child must be a valid React element");
1759
- return cloneSlotChild({ child: children, slotProps, ref });
1760
- }
1761
-
1762
- // ../../lib/adapter-utils/src/apply-filter.ts
1763
- function applyFilter(props, filterProps, variantKeys) {
1764
- const out = {};
1765
- for (const k in props) {
1766
- if (!Object.hasOwn(props, k)) continue;
1767
- if (filterProps(k, variantKeys)) continue;
1768
- out[k] = props[k];
1769
- }
1770
- return out;
1771
- }
1772
-
1773
1900
  // ../../lib/adapter-utils/src/build-core-runtime.ts
1774
1901
  var EMPTY_SET = /* @__PURE__ */ new Set();
1775
1902
  function buildCoreRuntime(normalized) {
@@ -1942,7 +2069,9 @@ function resolveRenderState(runtime, props, filterProps) {
1942
2069
  );
1943
2070
  }
1944
2071
  const mergedProps = runtime.resolveProps(rest);
1945
- const normalizedProps = runtime.options.normalizeFn ? runtime.options.normalizeFn(mergedProps) : mergedProps;
2072
+ const baseProps = runtime.options.normalizeFn ? runtime.options.normalizeFn(mergedProps) : mergedProps;
2073
+ const htmlNormalizers = runtime.options.htmlPropNormalizersFn?.(tag);
2074
+ const normalizedProps = htmlNormalizers?.length ? htmlNormalizers.reduce((acc, fn) => ({ ...acc, ...fn(acc) }), baseProps) : baseProps;
1946
2075
  const resolvedClass = runtime.resolveClasses(tag, normalizedProps, className, variantKey);
1947
2076
  const filteredProps = applyFilter(normalizedProps, filterProps, runtime.options.variantKeys);
1948
2077
  return buildRenderState(tag, buildDirectives(as, asChild), filteredProps, resolvedClass, children);
@@ -2022,7 +2151,10 @@ function render({
2022
2151
  const state = resolveRenderState(runtime, props, filterProps);
2023
2152
  let cached;
2024
2153
  const once = () => cached ??= normalizeChildren(state.children);
2025
- if (process.env.NODE_ENV !== "production") childrenEvaluator?.evaluate(once());
2154
+ if (process.env.NODE_ENV !== "production") {
2155
+ childrenEvaluator?.evaluate(once());
2156
+ getHtmlChildrenEvaluator(state.tag)?.evaluate(once());
2157
+ }
2026
2158
  if (typeof props.render === "function") {
2027
2159
  return props.render({ ...state.props, className: state.className, ref });
2028
2160
  }
@@ -2031,15 +2163,28 @@ function render({
2031
2163
  }
2032
2164
 
2033
2165
  // ../core/dist/contract.js
2034
- var CONTRACTED_CAPABILITIES = { AriaEngine: AriaPolicyEngine };
2166
+ function stateContract(props) {
2167
+ return { props };
2168
+ }
2169
+ var activeContract = stateContract([activeProps]);
2170
+ var disabledContract = stateContract([disabledProps]);
2171
+ var expandedContract = stateContract([expandedProps]);
2172
+ var invalidContract = stateContract([invalidProps]);
2173
+ var loadingContract = stateContract([loadingProps]);
2174
+ var pressedContract = stateContract([pressedProps]);
2175
+ var readonlyContract = stateContract([readonlyProps]);
2176
+ var selectedContract = stateContract([selectedProps]);
2177
+ var CONTRACTED_CAPABILITIES = {
2178
+ AriaEngine: AriaPolicyEngine,
2179
+ htmlAriaRules: HTML_ARIA_RULES,
2180
+ htmlPropNormalizersFn: getHtmlPropNormalizers
2181
+ };
2035
2182
  function createContractedPolymorphic(options = {}) {
2036
2183
  return createPolymorphic(options, CONTRACTED_CAPABILITIES);
2037
2184
  }
2038
2185
 
2039
2186
  export {
2040
2187
  createPolymorphic,
2041
- disabledProps,
2042
- invalidProps,
2043
2188
  createContractedPolymorphic,
2044
2189
  buildEngines,
2045
2190
  composeFilter,