praxis-kit 6.6.1 → 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";
@@ -2150,22 +2192,6 @@ import { warnDiagnostics as warnDiagnostics2 } from "../_shared/diagnostics.js";
2150
2192
 
2151
2193
  // ../core/src/html/contracts/categories.ts
2152
2194
  var METADATA_TAGS = ["script", "template"];
2153
- var VOID_TAGS = [
2154
- "area",
2155
- "base",
2156
- "br",
2157
- "col",
2158
- "embed",
2159
- "hr",
2160
- "img",
2161
- "input",
2162
- "link",
2163
- "meta",
2164
- "param",
2165
- "source",
2166
- "track",
2167
- "wbr"
2168
- ];
2169
2195
  var TEXT_ONLY_TAGS = [
2170
2196
  "option",
2171
2197
  "script",
@@ -2289,20 +2315,6 @@ var INPUT_MUTUALLY_EXCLUSIVE_POLICIES = [
2289
2315
 
2290
2316
  // ../core/src/html/spec/validators/attribute-type-validator.ts
2291
2317
  var DEFAULT_INPUT_TYPE = "text";
2292
- function omit(props, key) {
2293
- const next = { ...props };
2294
- delete next[key];
2295
- return next;
2296
- }
2297
- function removeAttributeFix(attribute) {
2298
- return {
2299
- kind: `removeAttribute:${attribute}`,
2300
- apply: ({ props }) => {
2301
- if (!(attribute in props)) return { applied: false, next: props };
2302
- return { applied: true, next: omit(props, attribute), previous: props };
2303
- }
2304
- };
2305
- }
2306
2318
  function createInputAttributeTypeRule({
2307
2319
  attribute,
2308
2320
  allowedTypes
@@ -2808,6 +2820,13 @@ function isLabelableControl(child) {
2808
2820
  const type = getChildProp(child, "type");
2809
2821
  return !isString(type) || type !== "hidden";
2810
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
+ }
2811
2830
  var labelContract = contract([
2812
2831
  { name: "control", match: isLabelableControl, cardinality: { max: 1 } },
2813
2832
  { name: "nested-label", match: isTag("label"), cardinality: { max: 0 } },
@@ -2815,6 +2834,13 @@ var labelContract = contract([
2815
2834
  name: "other-interactive-content",
2816
2835
  match: isTag(...OTHER_INTERACTIVE_TAGS),
2817
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
+ )
2818
2844
  }
2819
2845
  ]);
2820
2846
 
@@ -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;
package/dist/vue/index.js CHANGED
@@ -11,6 +11,11 @@ function makeResolveTag(defaultTag) {
11
11
  // ../../lib/primitive/src/rule/rule-brand.ts
12
12
  var RULE_BRAND = /* @__PURE__ */ Symbol("praxis-kit/dynamic-rule");
13
13
 
14
+ // ../../lib/primitive/src/rule/dynamic.ts
15
+ function dynamic(resolve) {
16
+ return { [RULE_BRAND]: true, resolve };
17
+ }
18
+
14
19
  // ../../lib/primitive/src/guards/foundational/is-defined.ts
15
20
  function isUndefined(value) {
16
21
  return value === void 0;
@@ -24,7 +29,7 @@ function isNonNull(value) {
24
29
  return value != null;
25
30
  }
26
31
  function isNullish(value) {
27
- return isNull(value) || value === void 0;
32
+ return isNull(value) || isUndefined(value);
28
33
  }
29
34
 
30
35
  // ../../lib/primitive/src/utils/type-guards.ts
@@ -601,6 +606,24 @@ var ROLE_RESTRICTED_ATTRIBUTES = /* @__PURE__ */ new Map([
601
606
  ]
602
607
  ]);
603
608
 
609
+ // ../../lib/primitive/src/constants/html/void-tags.ts
610
+ var VOID_TAGS = [
611
+ "area",
612
+ "base",
613
+ "br",
614
+ "col",
615
+ "embed",
616
+ "hr",
617
+ "img",
618
+ "input",
619
+ "link",
620
+ "meta",
621
+ "param",
622
+ "source",
623
+ "track",
624
+ "wbr"
625
+ ];
626
+
604
627
  // ../../lib/primitive/src/guards/aria/is-aria-attribute.ts
605
628
  function isGlobalAriaAttribute(attr) {
606
629
  return GLOBAL_ARIA_ATTRIBUTES.has(attr);
@@ -1599,7 +1622,8 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1599
1622
  const cached = _AriaPolicyEngine.#removeAttributeFixCache.get(attr);
1600
1623
  if (cached) return cached;
1601
1624
  const fix = {
1602
- kind: `removeAttribute:${attr}`,
1625
+ kind: "removeAttribute",
1626
+ attribute: attr,
1603
1627
  apply: ({ props }) => {
1604
1628
  if (!(attr in props)) return { applied: false, next: props };
1605
1629
  return { applied: true, next: omitProp(props, attr), previous: props };
@@ -1870,7 +1894,8 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1870
1894
  if (!impliedLive) return NO_VIOLATIONS2;
1871
1895
  if ("aria-live" in props) return NO_VIOLATIONS2;
1872
1896
  const injectLive = {
1873
- kind: `injectLive:${effectiveRole}`,
1897
+ kind: "injectLive",
1898
+ attribute: "aria-live",
1874
1899
  apply: (ctx) => ({
1875
1900
  applied: true,
1876
1901
  next: { ...ctx.props, "aria-live": impliedLive },
@@ -1939,6 +1964,23 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1939
1964
  }
1940
1965
  };
1941
1966
 
1967
+ // ../../lib/contract/src/aria/factories.ts
1968
+ function removeProp(props, key) {
1969
+ const next = { ...props };
1970
+ delete next[key];
1971
+ return next;
1972
+ }
1973
+ function removeAttributeFix(attribute) {
1974
+ return Object.freeze({
1975
+ kind: "removeAttribute",
1976
+ attribute,
1977
+ apply: ({ props }) => {
1978
+ if (!(attribute in props)) return { applied: false, next: props };
1979
+ return { applied: true, next: removeProp(props, attribute), previous: props };
1980
+ }
1981
+ });
1982
+ }
1983
+
1942
1984
  // ../../lib/contract/src/children/get-type-name.ts
1943
1985
  function getTypeName(value) {
1944
1986
  if (value === null) return "null";
@@ -2257,22 +2299,6 @@ import { warnDiagnostics as warnDiagnostics2 } from "../_shared/diagnostics.js";
2257
2299
 
2258
2300
  // ../core/src/html/contracts/categories.ts
2259
2301
  var METADATA_TAGS = ["script", "template"];
2260
- var VOID_TAGS = [
2261
- "area",
2262
- "base",
2263
- "br",
2264
- "col",
2265
- "embed",
2266
- "hr",
2267
- "img",
2268
- "input",
2269
- "link",
2270
- "meta",
2271
- "param",
2272
- "source",
2273
- "track",
2274
- "wbr"
2275
- ];
2276
2302
  var TEXT_ONLY_TAGS = [
2277
2303
  "option",
2278
2304
  "script",
@@ -2396,20 +2422,6 @@ var INPUT_MUTUALLY_EXCLUSIVE_POLICIES = [
2396
2422
 
2397
2423
  // ../core/src/html/spec/validators/attribute-type-validator.ts
2398
2424
  var DEFAULT_INPUT_TYPE = "text";
2399
- function omit(props, key) {
2400
- const next = { ...props };
2401
- delete next[key];
2402
- return next;
2403
- }
2404
- function removeAttributeFix(attribute) {
2405
- return {
2406
- kind: `removeAttribute:${attribute}`,
2407
- apply: ({ props }) => {
2408
- if (!(attribute in props)) return { applied: false, next: props };
2409
- return { applied: true, next: omit(props, attribute), previous: props };
2410
- }
2411
- };
2412
- }
2413
2425
  function createInputAttributeTypeRule({
2414
2426
  attribute,
2415
2427
  allowedTypes
@@ -2915,6 +2927,13 @@ function isLabelableControl(child) {
2915
2927
  const type = getChildProp(child, "type");
2916
2928
  return !isString(type) || type !== "hidden";
2917
2929
  }
2930
+ function hasAccessibleNameProp(props) {
2931
+ return "aria-label" in props || "aria-labelledby" in props;
2932
+ }
2933
+ function isNonEmptyTextChild(child) {
2934
+ if (isNumber(child)) return true;
2935
+ return isString(child) && child.trim().length > 0;
2936
+ }
2918
2937
  var labelContract = contract([
2919
2938
  { name: "control", match: isLabelableControl, cardinality: { max: 1 } },
2920
2939
  { name: "nested-label", match: isTag("label"), cardinality: { max: 0 } },
@@ -2922,6 +2941,13 @@ var labelContract = contract([
2922
2941
  name: "other-interactive-content",
2923
2942
  match: isTag(...OTHER_INTERACTIVE_TAGS),
2924
2943
  cardinality: { max: 0 }
2944
+ },
2945
+ {
2946
+ name: "accessible-name",
2947
+ match: isNonEmptyTextChild,
2948
+ cardinality: dynamic(
2949
+ (ctx) => hasAccessibleNameProp(ctx.props) ? { min: 0 } : { min: 1 }
2950
+ )
2925
2951
  }
2926
2952
  ]);
2927
2953
 
@@ -3693,7 +3719,7 @@ function render({
3693
3719
  const { vnodes: children, discarded } = normalizeChildren(slots);
3694
3720
  if (process.env.NODE_ENV !== "production") {
3695
3721
  childrenEvaluator?.evaluate(children, { tag: state.tag, props: state.normalizedProps });
3696
- runtime.options.htmlChildrenEvaluatorFn?.(state.tag)?.evaluate(children);
3722
+ runtime.options.htmlChildrenEvaluatorFn?.(state.tag)?.evaluate(children, { tag: state.tag, props: state.normalizedProps });
3697
3723
  }
3698
3724
  const slotResult = tryRenderAsChild(state, children, discarded, slotValidator);
3699
3725
  return slotResult ?? renderIntrinsic(state, runtime, slots);
@@ -178,8 +178,8 @@ type AriaContext = {
178
178
  readonly props: ReadonlyDeep<IntrinsicProps>;
179
179
  };
180
180
 
181
- type RemoveAttributeFixKind = `removeAttribute:${string}`;
182
- type InjectLiveFixKind = `injectLive:${string}`;
181
+ type RemoveAttributeFixKind = 'removeAttribute';
182
+ type InjectLiveFixKind = 'injectLive';
183
183
  type FixKind = 'removeRole' | 'setRole' | 'normalizeRelevantAll' | RemoveAttributeFixKind | InjectLiveFixKind;
184
184
 
185
185
  type AriaFixResult = {
@@ -192,6 +192,9 @@ type AriaFixResult = {
192
192
  };
193
193
  type AriaFix = {
194
194
  readonly kind: FixKind;
195
+ /** The attribute a `'removeAttribute'`/`'injectLive'` fix targets — always set for those
196
+ * kinds, absent for kinds with no single-attribute target (`'removeRole'`, etc.). */
197
+ readonly attribute?: string;
195
198
  readonly priority?: number;
196
199
  readonly source?: string;
197
200
  readonly apply: (context: AriaContext) => AriaFixResult;
package/dist/web/index.js CHANGED
@@ -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);
@@ -1446,7 +1469,8 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1446
1469
  const cached = _AriaPolicyEngine.#removeAttributeFixCache.get(attr);
1447
1470
  if (cached) return cached;
1448
1471
  const fix = {
1449
- kind: `removeAttribute:${attr}`,
1472
+ kind: "removeAttribute",
1473
+ attribute: attr,
1450
1474
  apply: ({ props }) => {
1451
1475
  if (!(attr in props)) return { applied: false, next: props };
1452
1476
  return { applied: true, next: omitProp(props, attr), previous: props };
@@ -1717,7 +1741,8 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1717
1741
  if (!impliedLive) return NO_VIOLATIONS2;
1718
1742
  if ("aria-live" in props) return NO_VIOLATIONS2;
1719
1743
  const injectLive = {
1720
- kind: `injectLive:${effectiveRole}`,
1744
+ kind: "injectLive",
1745
+ attribute: "aria-live",
1721
1746
  apply: (ctx) => ({
1722
1747
  applied: true,
1723
1748
  next: { ...ctx.props, "aria-live": impliedLive },
@@ -1786,6 +1811,23 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1786
1811
  }
1787
1812
  };
1788
1813
 
1814
+ // ../../lib/contract/src/aria/factories.ts
1815
+ function removeProp(props, key) {
1816
+ const next = { ...props };
1817
+ delete next[key];
1818
+ return next;
1819
+ }
1820
+ function removeAttributeFix(attribute) {
1821
+ return Object.freeze({
1822
+ kind: "removeAttribute",
1823
+ attribute,
1824
+ apply: ({ props }) => {
1825
+ if (!(attribute in props)) return { applied: false, next: props };
1826
+ return { applied: true, next: removeProp(props, attribute), previous: props };
1827
+ }
1828
+ });
1829
+ }
1830
+
1789
1831
  // ../../lib/contract/src/children/get-type-name.ts
1790
1832
  function getTypeName(value) {
1791
1833
  if (value === null) return "null";
@@ -2104,22 +2146,6 @@ import { warnDiagnostics as warnDiagnostics2 } from "../_shared/diagnostics.js";
2104
2146
 
2105
2147
  // ../core/src/html/contracts/categories.ts
2106
2148
  var METADATA_TAGS = ["script", "template"];
2107
- var VOID_TAGS = [
2108
- "area",
2109
- "base",
2110
- "br",
2111
- "col",
2112
- "embed",
2113
- "hr",
2114
- "img",
2115
- "input",
2116
- "link",
2117
- "meta",
2118
- "param",
2119
- "source",
2120
- "track",
2121
- "wbr"
2122
- ];
2123
2149
  var TEXT_ONLY_TAGS = [
2124
2150
  "option",
2125
2151
  "script",
@@ -2243,20 +2269,6 @@ var INPUT_MUTUALLY_EXCLUSIVE_POLICIES = [
2243
2269
 
2244
2270
  // ../core/src/html/spec/validators/attribute-type-validator.ts
2245
2271
  var DEFAULT_INPUT_TYPE = "text";
2246
- function omit(props, key) {
2247
- const next = { ...props };
2248
- delete next[key];
2249
- return next;
2250
- }
2251
- function removeAttributeFix(attribute) {
2252
- return {
2253
- kind: `removeAttribute:${attribute}`,
2254
- apply: ({ props }) => {
2255
- if (!(attribute in props)) return { applied: false, next: props };
2256
- return { applied: true, next: omit(props, attribute), previous: props };
2257
- }
2258
- };
2259
- }
2260
2272
  function createInputAttributeTypeRule({
2261
2273
  attribute,
2262
2274
  allowedTypes
@@ -2762,6 +2774,13 @@ function isLabelableControl(child) {
2762
2774
  const type = getChildProp(child, "type");
2763
2775
  return !isString(type) || type !== "hidden";
2764
2776
  }
2777
+ function hasAccessibleNameProp(props) {
2778
+ return "aria-label" in props || "aria-labelledby" in props;
2779
+ }
2780
+ function isNonEmptyTextChild(child) {
2781
+ if (isNumber(child)) return true;
2782
+ return isString(child) && child.trim().length > 0;
2783
+ }
2765
2784
  var labelContract = contract([
2766
2785
  { name: "control", match: isLabelableControl, cardinality: { max: 1 } },
2767
2786
  { name: "nested-label", match: isTag("label"), cardinality: { max: 0 } },
@@ -2769,6 +2788,13 @@ var labelContract = contract([
2769
2788
  name: "other-interactive-content",
2770
2789
  match: isTag(...OTHER_INTERACTIVE_TAGS),
2771
2790
  cardinality: { max: 0 }
2791
+ },
2792
+ {
2793
+ name: "accessible-name",
2794
+ match: isNonEmptyTextChild,
2795
+ cardinality: dynamic(
2796
+ (ctx) => hasAccessibleNameProp(ctx.props) ? { min: 0 } : { min: 1 }
2797
+ )
2772
2798
  }
2773
2799
  ]);
2774
2800
 
@@ -3578,7 +3604,7 @@ function createContractComponent(options) {
3578
3604
  props: hostState.normalizedProps
3579
3605
  });
3580
3606
  }
3581
- options2.htmlChildrenEvaluatorFn?.(hostState.tag)?.evaluate(children);
3607
+ options2.htmlChildrenEvaluatorFn?.(hostState.tag)?.evaluate(children, { tag: hostState.tag, props: hostState.normalizedProps });
3582
3608
  diffAndApplyAttributes(this, hostState, this._pipelineAttrs, props);
3583
3609
  }
3584
3610
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "praxis-kit",
3
- "version": "6.6.1",
3
+ "version": "7.0.0",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./react": {
@@ -190,23 +190,23 @@
190
190
  "@types/node": "^26.1.1",
191
191
  "@types/react": "^19.2.17",
192
192
  "@types/react-dom": "^19.0.0",
193
- "@typescript-eslint/utils": "8.63.0",
193
+ "@typescript-eslint/utils": "8.65.0",
194
194
  "lit": "^3.0.0",
195
195
  "preact": "^10.25.0",
196
- "react": "^19.2.7",
197
- "react-dom": "^19.2.7",
196
+ "react": "^19.2.8",
197
+ "react-dom": "^19.2.8",
198
198
  "solid-js": "^1.9.0",
199
199
  "svelte": "^5.56.3",
200
200
  "ts-morph": "^28.0.0",
201
201
  "tsup": "^8.5.1",
202
- "tsx": "^4.22.5",
202
+ "tsx": "^4.23.1",
203
203
  "typescript": "^6.0.3",
204
204
  "vite": "^8.1.5",
205
- "vue": "^3.5.38",
205
+ "vue": "^3.5.40",
206
206
  "@praxis-kit/adapter-utils": "0.0.0",
207
207
  "@praxis-kit/diagnostics": "0.0.0",
208
- "@praxis-kit/pipeline": "0.0.0",
209
208
  "@praxis-kit/core": "0.0.0",
209
+ "@praxis-kit/pipeline": "0.0.0",
210
210
  "@praxis-kit/primitive": "0.0.0",
211
211
  "@praxis-kit/vite-plugin": "0.0.0"
212
212
  },