praxis-kit 6.6.0 → 7.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.
@@ -13,6 +13,11 @@ function makeResolveTag(defaultTag) {
13
13
  // ../../lib/primitive/src/rule/rule-brand.ts
14
14
  var RULE_BRAND = /* @__PURE__ */ Symbol("praxis-kit/dynamic-rule");
15
15
 
16
+ // ../../lib/primitive/src/rule/dynamic.ts
17
+ function dynamic(resolve) {
18
+ return { [RULE_BRAND]: true, resolve };
19
+ }
20
+
16
21
  // ../../lib/primitive/src/guards/foundational/is-defined.ts
17
22
  function isUndefined(value) {
18
23
  return value === void 0;
@@ -26,7 +31,7 @@ function isNonNull(value) {
26
31
  return value != null;
27
32
  }
28
33
  function isNullish(value) {
29
- return isNull(value) || value === void 0;
34
+ return isNull(value) || isUndefined(value);
30
35
  }
31
36
 
32
37
  // ../../lib/primitive/src/utils/type-guards.ts
@@ -517,6 +522,24 @@ var ROLE_RESTRICTED_ATTRIBUTES = /* @__PURE__ */ new Map([
517
522
  ]
518
523
  ]);
519
524
 
525
+ // ../../lib/primitive/src/constants/html/void-tags.ts
526
+ var VOID_TAGS = [
527
+ "area",
528
+ "base",
529
+ "br",
530
+ "col",
531
+ "embed",
532
+ "hr",
533
+ "img",
534
+ "input",
535
+ "link",
536
+ "meta",
537
+ "param",
538
+ "source",
539
+ "track",
540
+ "wbr"
541
+ ];
542
+
520
543
  // ../../lib/primitive/src/guards/aria/is-aria-attribute.ts
521
544
  function isGlobalAriaAttribute(attr) {
522
545
  return GLOBAL_ARIA_ATTRIBUTES.has(attr);
@@ -1492,7 +1515,8 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1492
1515
  const cached = _AriaPolicyEngine.#removeAttributeFixCache.get(attr);
1493
1516
  if (cached) return cached;
1494
1517
  const fix = {
1495
- kind: `removeAttribute:${attr}`,
1518
+ kind: "removeAttribute",
1519
+ attribute: attr,
1496
1520
  apply: ({ props }) => {
1497
1521
  if (!(attr in props)) return { applied: false, next: props };
1498
1522
  return { applied: true, next: omitProp(props, attr), previous: props };
@@ -1763,7 +1787,8 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1763
1787
  if (!impliedLive) return NO_VIOLATIONS2;
1764
1788
  if ("aria-live" in props) return NO_VIOLATIONS2;
1765
1789
  const injectLive = {
1766
- kind: `injectLive:${effectiveRole}`,
1790
+ kind: "injectLive",
1791
+ attribute: "aria-live",
1767
1792
  apply: (ctx) => ({
1768
1793
  applied: true,
1769
1794
  next: { ...ctx.props, "aria-live": impliedLive },
@@ -1832,6 +1857,23 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1832
1857
  }
1833
1858
  };
1834
1859
 
1860
+ // ../../lib/contract/src/aria/factories.ts
1861
+ function removeProp(props, key) {
1862
+ const next = { ...props };
1863
+ delete next[key];
1864
+ return next;
1865
+ }
1866
+ function removeAttributeFix(attribute) {
1867
+ return Object.freeze({
1868
+ kind: "removeAttribute",
1869
+ attribute,
1870
+ apply: ({ props }) => {
1871
+ if (!(attribute in props)) return { applied: false, next: props };
1872
+ return { applied: true, next: removeProp(props, attribute), previous: props };
1873
+ }
1874
+ });
1875
+ }
1876
+
1835
1877
  // ../../lib/contract/src/children/get-type-name.ts
1836
1878
  function getTypeName(value) {
1837
1879
  if (value === null) return "null";
@@ -2148,6 +2190,77 @@ var readonlyProps = ({
2148
2190
  // ../core/src/html/evaluators.ts
2149
2191
  import { warnDiagnostics as warnDiagnostics2 } from "../_shared/diagnostics.js";
2150
2192
 
2193
+ // ../core/src/html/contracts/categories.ts
2194
+ var METADATA_TAGS = ["script", "template"];
2195
+ var TEXT_ONLY_TAGS = [
2196
+ "option",
2197
+ "script",
2198
+ "style",
2199
+ "textarea",
2200
+ "title"
2201
+ ];
2202
+ var LANDMARK_TAGS = [
2203
+ "article",
2204
+ "aside",
2205
+ "footer",
2206
+ "header",
2207
+ "main",
2208
+ "nav"
2209
+ ];
2210
+ var INTERACTIVE_CONTENT_TAGS = [
2211
+ "a",
2212
+ "button",
2213
+ "input",
2214
+ "select",
2215
+ "textarea",
2216
+ "label"
2217
+ ];
2218
+ var LABELABLE_TAGS = [
2219
+ "button",
2220
+ "input",
2221
+ "meter",
2222
+ "output",
2223
+ "progress",
2224
+ "select",
2225
+ "textarea"
2226
+ ];
2227
+ var OTHER_INTERACTIVE_TAGS = [
2228
+ "a",
2229
+ "details",
2230
+ "embed",
2231
+ "iframe"
2232
+ ];
2233
+ var P_BLOCKED_TAGS = [
2234
+ "address",
2235
+ "article",
2236
+ "aside",
2237
+ "blockquote",
2238
+ "details",
2239
+ "dialog",
2240
+ "div",
2241
+ "dl",
2242
+ "fieldset",
2243
+ "figure",
2244
+ "footer",
2245
+ "form",
2246
+ "h1",
2247
+ "h2",
2248
+ "h3",
2249
+ "h4",
2250
+ "h5",
2251
+ "h6",
2252
+ "header",
2253
+ "hr",
2254
+ "main",
2255
+ "nav",
2256
+ "ol",
2257
+ "p",
2258
+ "pre",
2259
+ "section",
2260
+ "table",
2261
+ "ul"
2262
+ ];
2263
+
2151
2264
  // ../core/src/html/spec/vocabulary/input.ts
2152
2265
  var TEXT_INPUT_TYPES = ["text", "search", "url", "tel", "email", "password"];
2153
2266
  var NUMERIC_INPUT_TYPES = [
@@ -2202,20 +2315,6 @@ var INPUT_MUTUALLY_EXCLUSIVE_POLICIES = [
2202
2315
 
2203
2316
  // ../core/src/html/spec/validators/attribute-type-validator.ts
2204
2317
  var DEFAULT_INPUT_TYPE = "text";
2205
- function omit(props, key) {
2206
- const next = { ...props };
2207
- delete next[key];
2208
- return next;
2209
- }
2210
- function removeAttributeFix(attribute) {
2211
- return {
2212
- kind: `removeAttribute:${attribute}`,
2213
- apply: ({ props }) => {
2214
- if (!(attribute in props)) return { applied: false, next: props };
2215
- return { applied: true, next: omit(props, attribute), previous: props };
2216
- }
2217
- };
2218
- }
2219
2318
  function createInputAttributeTypeRule({
2220
2319
  attribute,
2221
2320
  allowedTypes
@@ -2527,7 +2626,11 @@ var ALLOWED_ROLES = {
2527
2626
  "treeitem"
2528
2627
  ],
2529
2628
  dialog: ["alertdialog"],
2530
- fieldset: ["none", "presentation", "radiogroup"]
2629
+ fieldset: ["none", "presentation", "radiogroup"],
2630
+ // `<label>` has no implicit role and no documented alternates — its native labeling
2631
+ // semantics (control association, accessible-name contribution) aren't reproducible via
2632
+ // ARIA, so any explicit `role` should be avoided rather than substituted.
2633
+ label: []
2531
2634
  };
2532
2635
  var ELEMENT_SPECS = {
2533
2636
  input: inputElementSpec,
@@ -2568,7 +2671,10 @@ var roleNotPermittedRule = Object.assign(
2568
2671
  );
2569
2672
 
2570
2673
  // ../core/src/html/aria-rules.ts
2571
- var LANDMARK_TAG_SET = /* @__PURE__ */ new Set(["article", "aside", "footer", "header", "main", "nav"]);
2674
+ function defineAriaRule(tags, rule) {
2675
+ return Object.assign(rule, { tags });
2676
+ }
2677
+ var LANDMARK_TAG_SET = new Set(LANDMARK_TAGS);
2572
2678
  var removeLandmarkRoleOverride = {
2573
2679
  kind: "removeRole",
2574
2680
  apply: ({ props }) => {
@@ -2577,10 +2683,11 @@ var removeLandmarkRoleOverride = {
2577
2683
  return { applied: true, next: rest, previous: props };
2578
2684
  }
2579
2685
  };
2580
- var landmarkRoleRule = Object.assign(
2686
+ var landmarkRoleRule = defineAriaRule(
2687
+ LANDMARK_TAGS,
2581
2688
  ({ tag, props, implicitRole }) => {
2582
2689
  if (!LANDMARK_TAG_SET.has(tag) || !implicitRole) return [];
2583
- const role = props.role;
2690
+ const { role } = props;
2584
2691
  if (!role || role === implicitRole) return [];
2585
2692
  const diagnostic = HtmlDiagnostics.landmarkRoleOverride(tag, implicitRole, role);
2586
2693
  return [
@@ -2592,8 +2699,7 @@ var landmarkRoleRule = Object.assign(
2592
2699
  diagnostic
2593
2700
  }
2594
2701
  ];
2595
- },
2596
- { tags: [...LANDMARK_TAG_SET] }
2702
+ }
2597
2703
  );
2598
2704
  function requireAccessibleName({ tag, props }) {
2599
2705
  if ("aria-label" in props || "aria-labelledby" in props) return [];
@@ -2606,38 +2712,44 @@ function requireAccessibleName({ tag, props }) {
2606
2712
  }
2607
2713
  ];
2608
2714
  }
2609
- var NAMED_LANDMARK_TAGS = /* @__PURE__ */ new Set(["nav", "aside"]);
2610
- var landmarkNameAdvisory = Object.assign(
2715
+ var NAMED_LANDMARK_TAGS = ["nav", "aside"];
2716
+ var NAMED_LANDMARK_TAG_SET = new Set(NAMED_LANDMARK_TAGS);
2717
+ var landmarkAccessibleNameRule = defineAriaRule(
2718
+ NAMED_LANDMARK_TAGS,
2611
2719
  (ctx) => {
2612
- if (!ctx.implicitRole || !NAMED_LANDMARK_TAGS.has(ctx.tag)) return [];
2720
+ if (!ctx.implicitRole || !NAMED_LANDMARK_TAG_SET.has(ctx.tag)) return [];
2613
2721
  return requireAccessibleName(ctx);
2614
- },
2615
- { tags: [...NAMED_LANDMARK_TAGS] }
2722
+ }
2616
2723
  );
2617
2724
  var HTML_ARIA_RULES = [
2618
2725
  landmarkRoleRule,
2619
- landmarkNameAdvisory,
2726
+ landmarkAccessibleNameRule,
2620
2727
  roleNotPermittedRule,
2621
2728
  ...INPUT_RULES
2622
2729
  ];
2623
2730
 
2624
- // ../core/src/html/contracts.ts
2731
+ // ../core/src/html/contracts/helpers.ts
2625
2732
  import { warnDiagnostics } from "../_shared/diagnostics.js";
2733
+ function isVNodeLike(child) {
2734
+ return isObject(child) && "type" in child;
2735
+ }
2626
2736
  function isOpenContent(...blockedTags) {
2627
2737
  const set2 = new Set(blockedTags);
2628
2738
  return (child) => {
2629
- if (!isObject(child) || !("type" in child)) return false;
2739
+ if (!isVNodeLike(child)) return false;
2630
2740
  const tag = getTag(child);
2631
2741
  return tag === void 0 || !set2.has(tag);
2632
2742
  };
2633
2743
  }
2634
- var METADATA_TAGS = ["script", "template"];
2635
2744
  var metadataMatch = isTag(...METADATA_TAGS);
2636
2745
  function metadata(name = "metadata") {
2637
2746
  return { name, match: metadataMatch };
2638
2747
  }
2748
+ function optional(name, tag) {
2749
+ return { name, match: isTag(tag), cardinality: { max: 1 } };
2750
+ }
2639
2751
  function firstOptional(name, tag) {
2640
- return { name, match: isTag(tag), cardinality: { max: 1 }, position: "first" };
2752
+ return { ...optional(name, tag), position: "first" };
2641
2753
  }
2642
2754
  function contract(children, options) {
2643
2755
  return { diagnostics: warnDiagnostics, children, ...options };
@@ -2651,50 +2763,41 @@ function ariaContract(aria) {
2651
2763
  function firstChildContract(name, tag) {
2652
2764
  return contract([firstOptional(name, tag), { name: "content", match: isOpenContent(tag) }]);
2653
2765
  }
2654
- var VOID_TAGS = [
2655
- "area",
2656
- "base",
2657
- "br",
2658
- "col",
2659
- "embed",
2660
- "hr",
2661
- "img",
2662
- "input",
2663
- "link",
2664
- "meta",
2665
- "param",
2666
- "source",
2667
- "track",
2668
- "wbr"
2669
- ];
2670
- var TEXT_ONLY_TAGS = ["option", "script", "style", "textarea", "title"];
2671
- var LANDMARK_TAGS = ["article", "aside", "footer", "header", "main", "nav"];
2672
- var listContract = closedContract([
2673
- { name: "list-item", match: isTag("li", ...METADATA_TAGS) }
2674
- ]);
2675
- var tableContract = closedContract([
2676
- firstOptional("caption", "caption"),
2677
- { name: "colgroup", match: isTag("colgroup") },
2678
- { name: "thead", match: isTag("thead"), cardinality: { max: 1 } },
2679
- { name: "tbody", match: isTag("tbody") },
2680
- { name: "tfoot", match: isTag("tfoot"), cardinality: { max: 1 } },
2681
- { name: "table-row", match: isTag("tr", ...METADATA_TAGS) }
2682
- ]);
2683
- var tableBodyContract = closedContract([
2684
- { name: "table-row", match: isTag("tr", ...METADATA_TAGS) }
2685
- ]);
2686
- var tableRowContract = closedContract([
2687
- { name: "table-cell", match: isTag("td", "th", ...METADATA_TAGS) }
2688
- ]);
2689
- var colgroupContract = closedContract([
2690
- { name: "column", match: isTag("col", "template") }
2766
+ function getChildProp(child, key) {
2767
+ if (!isVNodeLike(child)) return void 0;
2768
+ const { props } = child;
2769
+ if (!isObject(props)) return void 0;
2770
+ return props[key];
2771
+ }
2772
+
2773
+ // ../core/src/html/contracts/aria/landmarks.ts
2774
+ var landmarkContract = ariaContract([landmarkRoleRule, landmarkAccessibleNameRule]);
2775
+
2776
+ // ../core/src/html/contracts/aria/widgets.ts
2777
+ var dialogContract = ariaContract([requireAccessibleName]);
2778
+ var menuContract = ariaContract([requireAccessibleName]);
2779
+ var menubarContract = ariaContract([requireAccessibleName]);
2780
+ var treeContract = ariaContract([requireAccessibleName]);
2781
+ var gridContract = ariaContract([requireAccessibleName]);
2782
+ var listboxContract = ariaContract([requireAccessibleName]);
2783
+ var tablistContract = ariaContract([requireAccessibleName]);
2784
+ var radiogroupContract = ariaContract([requireAccessibleName]);
2785
+
2786
+ // ../core/src/html/contracts/html/document.ts
2787
+ var headContract = closedContract([
2788
+ {
2789
+ name: "metadata",
2790
+ match: isTag("base", "link", "meta", "noscript", "script", "style", "template", "title")
2791
+ }
2691
2792
  ]);
2692
- var dlContract = closedContract([
2693
- { name: "term", match: isTag("dt") },
2694
- { name: "description", match: isTag("dd") },
2695
- { name: "group", match: isTag("div") },
2696
- metadata()
2793
+ var htmlContract = closedContract([
2794
+ { name: "head", match: isTag("head"), cardinality: { min: 1, max: 1 }, position: "first" },
2795
+ { name: "body", match: isTag("body"), cardinality: { min: 1, max: 1 } }
2697
2796
  ]);
2797
+ var voidContract = contract([], { exclusiveChildren: true, allowText: false });
2798
+ var textOnlyContract = contract([], { exclusiveChildren: true });
2799
+
2800
+ // ../core/src/html/contracts/html/forms.ts
2698
2801
  var selectContract = closedContract([
2699
2802
  { name: "option", match: isTag("option", "optgroup", "hr", ...METADATA_TAGS) }
2700
2803
  ]);
@@ -2704,6 +2807,59 @@ var optgroupContract = closedContract([
2704
2807
  var datalistContract = closedContract([
2705
2808
  { name: "option", match: isTag("option", ...METADATA_TAGS) }
2706
2809
  ]);
2810
+ var buttonContract = closedContract([
2811
+ { name: "content", match: isOpenContent(...INTERACTIVE_CONTENT_TAGS) }
2812
+ ]);
2813
+ var anchorContract = closedContract([
2814
+ { name: "content", match: isOpenContent(...INTERACTIVE_CONTENT_TAGS) }
2815
+ ]);
2816
+ var labelableTagMatch = isTag(...LABELABLE_TAGS);
2817
+ function isLabelableControl(child) {
2818
+ if (!labelableTagMatch(child)) return false;
2819
+ if (getTag(child) !== "input") return true;
2820
+ const type = getChildProp(child, "type");
2821
+ return !isString(type) || type !== "hidden";
2822
+ }
2823
+ function hasAccessibleNameProp(props) {
2824
+ return "aria-label" in props || "aria-labelledby" in props;
2825
+ }
2826
+ function isNonEmptyTextChild(child) {
2827
+ if (isNumber(child)) return true;
2828
+ return isString(child) && child.trim().length > 0;
2829
+ }
2830
+ var labelContract = contract([
2831
+ { name: "control", match: isLabelableControl, cardinality: { max: 1 } },
2832
+ { name: "nested-label", match: isTag("label"), cardinality: { max: 0 } },
2833
+ {
2834
+ name: "other-interactive-content",
2835
+ match: isTag(...OTHER_INTERACTIVE_TAGS),
2836
+ cardinality: { max: 0 }
2837
+ },
2838
+ {
2839
+ name: "accessible-name",
2840
+ match: isNonEmptyTextChild,
2841
+ cardinality: dynamic(
2842
+ (ctx) => hasAccessibleNameProp(ctx.props) ? { min: 0 } : { min: 1 }
2843
+ )
2844
+ }
2845
+ ]);
2846
+
2847
+ // ../core/src/html/contracts/html/grouping.ts
2848
+ var detailsContract = firstChildContract("summary", "summary");
2849
+ var fieldsetContract = firstChildContract("legend", "legend");
2850
+
2851
+ // ../core/src/html/contracts/html/lists.ts
2852
+ var listContract = closedContract([
2853
+ { name: "list-item", match: isTag("li", ...METADATA_TAGS) }
2854
+ ]);
2855
+ var dlContract = closedContract([
2856
+ { name: "term", match: isTag("dt") },
2857
+ { name: "description", match: isTag("dd") },
2858
+ { name: "group", match: isTag("div") },
2859
+ metadata()
2860
+ ]);
2861
+
2862
+ // ../core/src/html/contracts/html/media.ts
2707
2863
  var pictureContract = closedContract([
2708
2864
  { name: "source", match: isTag("source", ...METADATA_TAGS) },
2709
2865
  { name: "image", match: isTag("img"), cardinality: { min: 1, max: 1 }, position: "last" }
@@ -2712,91 +2868,49 @@ var figureContract = contract([
2712
2868
  { name: "caption", match: isTag("figcaption"), cardinality: { max: 1 } },
2713
2869
  { name: "content", match: isOpenContent("figcaption") }
2714
2870
  ]);
2715
- var detailsContract = firstChildContract("summary", "summary");
2716
- var fieldsetContract = firstChildContract("legend", "legend");
2717
2871
  var objectContract = contract([
2718
2872
  { name: "param", match: isTag("param") },
2719
2873
  { name: "content", match: isOpenContent("param") }
2720
2874
  ]);
2721
- var INTERACTIVE_CONTENT_TAGS = ["a", "button", "input", "select", "textarea", "label"];
2722
- var buttonContract = closedContract([
2723
- { name: "content", match: isOpenContent(...INTERACTIVE_CONTENT_TAGS) }
2724
- ]);
2725
- var anchorContract = closedContract([
2726
- { name: "content", match: isOpenContent(...INTERACTIVE_CONTENT_TAGS) }
2727
- ]);
2728
- var LABELABLE_TAGS = [
2729
- "button",
2730
- "input",
2731
- "meter",
2732
- "output",
2733
- "progress",
2734
- "select",
2735
- "textarea"
2736
- ];
2737
- var labelContract = contract([
2738
- { name: "control", match: isTag(...LABELABLE_TAGS), cardinality: { max: 1 } }
2739
- ]);
2740
- var P_BLOCKED_TAGS = [
2741
- "address",
2742
- "article",
2743
- "aside",
2744
- "blockquote",
2745
- "details",
2746
- "dialog",
2747
- "div",
2748
- "dl",
2749
- "fieldset",
2750
- "figure",
2751
- "footer",
2752
- "form",
2753
- "h1",
2754
- "h2",
2755
- "h3",
2756
- "h4",
2757
- "h5",
2758
- "h6",
2759
- "header",
2760
- "hr",
2761
- "main",
2762
- "nav",
2763
- "ol",
2764
- "p",
2765
- "pre",
2766
- "section",
2767
- "table",
2768
- "ul"
2769
- ];
2770
- var pContract = closedContract([
2771
- { name: "content", match: isOpenContent(...P_BLOCKED_TAGS) }
2772
- ]);
2773
2875
  var mediaContract = contract([
2774
2876
  { name: "source", match: isTag("source") },
2775
2877
  { name: "track", match: isTag("track") },
2776
2878
  metadata(),
2777
2879
  { name: "content", match: isOpenContent("source", "track", ...METADATA_TAGS) }
2778
2880
  ]);
2779
- var headContract = closedContract([
2780
- {
2781
- name: "metadata",
2782
- match: isTag("base", "link", "meta", "noscript", "script", "style", "template", "title")
2783
- }
2881
+
2882
+ // ../core/src/html/contracts/html/tables.ts
2883
+ var tableContract = closedContract([
2884
+ firstOptional("caption", "caption"),
2885
+ { name: "colgroup", match: isTag("colgroup") },
2886
+ { name: "thead", match: isTag("thead"), cardinality: { max: 1 } },
2887
+ { name: "tbody", match: isTag("tbody") },
2888
+ { name: "tfoot", match: isTag("tfoot"), cardinality: { max: 1 } },
2889
+ { name: "table-row", match: isTag("tr", ...METADATA_TAGS) }
2784
2890
  ]);
2785
- var htmlContract = closedContract([
2786
- { name: "head", match: isTag("head"), cardinality: { min: 1, max: 1 }, position: "first" },
2787
- { name: "body", match: isTag("body"), cardinality: { min: 1, max: 1 } }
2891
+ var tableBodyContract = closedContract([
2892
+ { name: "table-row", match: isTag("tr", ...METADATA_TAGS) }
2788
2893
  ]);
2789
- var voidContract = contract([], { exclusiveChildren: true, allowText: false });
2790
- var textOnlyContract = contract([], { exclusiveChildren: true });
2791
- var landmarkContract = ariaContract([landmarkRoleRule, landmarkNameAdvisory]);
2792
- var dialogContract = ariaContract([requireAccessibleName]);
2793
- var menuContract = ariaContract([requireAccessibleName]);
2794
- var menubarContract = ariaContract([requireAccessibleName]);
2795
- var treeContract = ariaContract([requireAccessibleName]);
2796
- var gridContract = ariaContract([requireAccessibleName]);
2797
- var listboxContract = ariaContract([requireAccessibleName]);
2798
- var tablistContract = ariaContract([requireAccessibleName]);
2799
- var radiogroupContract = ariaContract([requireAccessibleName]);
2894
+ var tableRowContract = closedContract([
2895
+ { name: "table-cell", match: isTag("td", "th", ...METADATA_TAGS) }
2896
+ ]);
2897
+ var colgroupContract = closedContract([
2898
+ { name: "column", match: isTag("col", "template") }
2899
+ ]);
2900
+
2901
+ // ../core/src/html/contracts/html/text.ts
2902
+ var pContract = closedContract([
2903
+ { name: "content", match: isOpenContent(...P_BLOCKED_TAGS) }
2904
+ ]);
2905
+
2906
+ // ../core/src/html/contracts/build-map.ts
2907
+ function buildMap(groups) {
2908
+ return Object.fromEntries(
2909
+ groups.flatMap(([keys2, value]) => keys2.map((key) => [key, value]))
2910
+ );
2911
+ }
2912
+
2913
+ // ../core/src/html/contracts/maps.ts
2800
2914
  var CONTRACT_GROUPS = [
2801
2915
  [VOID_TAGS, voidContract],
2802
2916
  [TEXT_ONLY_TAGS, textOnlyContract],
@@ -2805,13 +2919,8 @@ var CONTRACT_GROUPS = [
2805
2919
  [["audio", "video"], mediaContract],
2806
2920
  [["thead", "tbody", "tfoot"], tableBodyContract]
2807
2921
  ];
2808
- function contractMap(groups) {
2809
- return Object.fromEntries(
2810
- groups.flatMap(([tags, enforcement]) => tags.map((tag) => [tag, enforcement]))
2811
- );
2812
- }
2813
2922
  var htmlContracts = {
2814
- ...contractMap(CONTRACT_GROUPS),
2923
+ ...buildMap(CONTRACT_GROUPS),
2815
2924
  table: tableContract,
2816
2925
  tr: tableRowContract,
2817
2926
  colgroup: colgroupContract,
@@ -223,6 +223,24 @@ var LRUCache = class {
223
223
  }
224
224
  };
225
225
 
226
+ // ../../lib/primitive/src/constants/html/void-tags.ts
227
+ var VOID_TAGS = [
228
+ "area",
229
+ "base",
230
+ "br",
231
+ "col",
232
+ "embed",
233
+ "hr",
234
+ "img",
235
+ "input",
236
+ "link",
237
+ "meta",
238
+ "param",
239
+ "source",
240
+ "track",
241
+ "wbr"
242
+ ];
243
+
226
244
  // ../../node_modules/.pnpm/class-variance-authority@0.7.1/node_modules/class-variance-authority/dist/index.mjs
227
245
  import { clsx as clsx2 } from "clsx";
228
246
  var falsyToString = (value) => typeof value === "boolean" ? `${value}` : value === 0 ? "0" : value;
@@ -597,6 +615,13 @@ var TailwindDiagnostics = {
597
615
  category: DiagnosticCategory.Contract,
598
616
  message: `[createTailwindPipeline] Variant "${dim}=${value}" contributes only classes stripped under layout mode "${mode}" ("${classStr}") \u2014 it produces nothing in this mode.`
599
617
  };
618
+ },
619
+ layoutOnVoidTag(tag, mode) {
620
+ return {
621
+ code: DiagnosticCode.TailwindLayoutOnVoidTag,
622
+ category: DiagnosticCategory.Contract,
623
+ message: `[createTailwindPipeline] "${mode}" sets <${tag}>'s inner display, but <${tag}> is a void element and can never have children \u2014 there is nothing for a flex/grid formatting context to apply to, so "${mode}" (and any gap-* utility) has no effect here.`
624
+ };
600
625
  }
601
626
  };
602
627
 
@@ -626,6 +651,7 @@ var devDiagnostics = new Diagnostics(
626
651
  var classifier = new ClassClassifier();
627
652
  var evaluator = new DependencyEvaluator(defaultDependencyRules);
628
653
  var builder = new ClassBuilder();
654
+ var VOID_TAG_SET = new Set(VOID_TAGS);
629
655
  function normalizeVariantValue(value) {
630
656
  if (isString(value)) return value;
631
657
  return value.join(" ");
@@ -640,6 +666,10 @@ function resolveLayout(diagnostics, props) {
640
666
  }
641
667
  return active[0] ?? "none";
642
668
  }
669
+ function warnLayoutOnVoidTag(diagnostics, tag, state) {
670
+ if (state.family === "none" || !isString(tag) || !VOID_TAG_SET.has(tag)) return;
671
+ diagnostics.warn(TailwindDiagnostics.layoutOnVoidTag(tag, state.mode));
672
+ }
643
673
  function warnReservedLayoutLiterals(diagnostics, tokens) {
644
674
  const reserved = [];
645
675
  iterate.forEach(tokens, (token) => {
@@ -705,6 +735,7 @@ function createTailwindPipeline(options, diagnostics) {
705
735
  const tokens = classifyTokens(resolvedClasses);
706
736
  const state = new LayoutState(mode);
707
737
  const filtered = tokens.filter((token) => evaluator.evaluate(token, state));
738
+ if (DEV) warnLayoutOnVoidTag(devDiagnostics, tag, state);
708
739
  return { mode, state, filtered, tokens, props, recipe };
709
740
  };
710
741
  const buildClassString = (ctx) => {
@@ -97,6 +97,7 @@ declare enum DiagnosticCode {
97
97
  TailwindMultipleDisplayProps = "CSS6001",
98
98
  TailwindReservedLayoutLiteral = "CSS6002",
99
99
  TailwindDeadVariantClass = "CSS6003",
100
+ TailwindLayoutOnVoidTag = "CSS6004",
100
101
  PluginInvalidShape = "PLUGIN7001",
101
102
  PluginPipelineReturnType = "PLUGIN7002",
102
103
  InternalError = "INTERNAL9000"
@@ -197,8 +197,8 @@ type AriaContext = {
197
197
  readonly props: ReadonlyDeep<IntrinsicProps>;
198
198
  };
199
199
 
200
- type RemoveAttributeFixKind = `removeAttribute:${string}`;
201
- type InjectLiveFixKind = `injectLive:${string}`;
200
+ type RemoveAttributeFixKind = 'removeAttribute';
201
+ type InjectLiveFixKind = 'injectLive';
202
202
  type FixKind = 'removeRole' | 'setRole' | 'normalizeRelevantAll' | RemoveAttributeFixKind | InjectLiveFixKind;
203
203
 
204
204
  type AriaFixResult = {
@@ -211,6 +211,9 @@ type AriaFixResult = {
211
211
  };
212
212
  type AriaFix = {
213
213
  readonly kind: FixKind;
214
+ /** The attribute a `'removeAttribute'`/`'injectLive'` fix targets — always set for those
215
+ * kinds, absent for kinds with no single-attribute target (`'removeRole'`, etc.). */
216
+ readonly attribute?: string;
214
217
  readonly priority?: number;
215
218
  readonly source?: string;
216
219
  readonly apply: (context: AriaContext) => AriaFixResult;