praxis-kit 4.1.3 → 5.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.
@@ -1856,17 +1856,22 @@ var RuleValidator = class _RuleValidator extends InvariantBase {
1856
1856
  };
1857
1857
 
1858
1858
  // ../../lib/contract/src/children/children-evaluator.ts
1859
+ var isTextLike = (child) => isString(child) || isNumber(child);
1859
1860
  var ChildrenEvaluator = class extends InvariantBase {
1860
1861
  #context;
1861
1862
  #rules;
1862
1863
  #ruleNames;
1863
1864
  #matcher;
1864
1865
  #ruleValidator;
1865
- constructor(rules, diagnostics, context = "Component") {
1866
+ #exclusiveChildren;
1867
+ #allowText;
1868
+ constructor(rules, diagnostics, context = "Component", options = {}) {
1866
1869
  super(diagnostics);
1867
1870
  this.#context = context;
1868
1871
  this.#rules = rules.map((r) => normalizeChildRule(r));
1869
1872
  this.#ruleNames = this.#rules.map((r) => r.name);
1873
+ this.#exclusiveChildren = options.exclusiveChildren ?? false;
1874
+ this.#allowText = options.allowText ?? true;
1870
1875
  iterate.forEach(this.#rules, (rule) => {
1871
1876
  const { name, position, cardinality } = rule;
1872
1877
  if ((position === "first" || position === "last") && (cardinality.kind === "unbounded" || cardinality.max > 1)) {
@@ -1880,8 +1885,17 @@ var ChildrenEvaluator = class extends InvariantBase {
1880
1885
  }
1881
1886
  evaluate(children) {
1882
1887
  if (!this.active) return;
1883
- const { matrix, unexpectedIndices, ambiguousIndices } = this.#matcher.match(children);
1888
+ const {
1889
+ matrix,
1890
+ unexpectedIndices: rawUnexpectedIndices,
1891
+ ambiguousIndices
1892
+ } = this.#matcher.match(children);
1884
1893
  this.#ruleValidator.validate(this.#rules, matrix, children.length);
1894
+ const unexpectedIndices = new Set(
1895
+ [...rawUnexpectedIndices].filter(
1896
+ (ci) => isTextLike(children[ci]) ? this.#allowText === false : this.#exclusiveChildren
1897
+ )
1898
+ );
1885
1899
  if (unexpectedIndices.size === 0 && ambiguousIndices.size === 0) return;
1886
1900
  const violating = [...unexpectedIndices, ...ambiguousIndices].sort((a, b) => a - b);
1887
1901
  iterate.forEach(violating, (ci) => {
@@ -2003,8 +2017,11 @@ function metadata(name = "metadata") {
2003
2017
  function firstOptional(name, tag) {
2004
2018
  return { name, match: isTag(tag), cardinality: { max: 1 }, position: "first" };
2005
2019
  }
2006
- function contract(children) {
2007
- return { diagnostics: warnDiagnostics, children };
2020
+ function contract(children, options) {
2021
+ return { diagnostics: warnDiagnostics, children, ...options };
2022
+ }
2023
+ function closedContract(children) {
2024
+ return contract(children, { exclusiveChildren: true });
2008
2025
  }
2009
2026
  function ariaContract(aria) {
2010
2027
  return { diagnostics: warnDiagnostics, aria };
@@ -2030,8 +2047,10 @@ var VOID_TAGS = [
2030
2047
  ];
2031
2048
  var TEXT_ONLY_TAGS = ["option", "script", "style", "textarea", "title"];
2032
2049
  var LANDMARK_TAGS = ["article", "aside", "footer", "header", "main", "nav"];
2033
- var listContract = contract([{ name: "list-item", match: isTag("li", ...METADATA_TAGS) }]);
2034
- var tableContract = contract([
2050
+ var listContract = closedContract([
2051
+ { name: "list-item", match: isTag("li", ...METADATA_TAGS) }
2052
+ ]);
2053
+ var tableContract = closedContract([
2035
2054
  firstOptional("caption", "caption"),
2036
2055
  { name: "colgroup", match: isTag("colgroup") },
2037
2056
  { name: "thead", match: isTag("thead"), cardinality: { max: 1 } },
@@ -2039,29 +2058,31 @@ var tableContract = contract([
2039
2058
  { name: "tfoot", match: isTag("tfoot"), cardinality: { max: 1 } },
2040
2059
  { name: "table-row", match: isTag("tr", ...METADATA_TAGS) }
2041
2060
  ]);
2042
- var tableBodyContract = contract([
2061
+ var tableBodyContract = closedContract([
2043
2062
  { name: "table-row", match: isTag("tr", ...METADATA_TAGS) }
2044
2063
  ]);
2045
- var tableRowContract = contract([
2064
+ var tableRowContract = closedContract([
2046
2065
  { name: "table-cell", match: isTag("td", "th", ...METADATA_TAGS) }
2047
2066
  ]);
2048
- var colgroupContract = contract([{ name: "column", match: isTag("col", "template") }]);
2049
- var dlContract = contract([
2067
+ var colgroupContract = closedContract([
2068
+ { name: "column", match: isTag("col", "template") }
2069
+ ]);
2070
+ var dlContract = closedContract([
2050
2071
  { name: "term", match: isTag("dt") },
2051
2072
  { name: "description", match: isTag("dd") },
2052
2073
  { name: "group", match: isTag("div") },
2053
2074
  metadata()
2054
2075
  ]);
2055
- var selectContract = contract([
2076
+ var selectContract = closedContract([
2056
2077
  { name: "option", match: isTag("option", "optgroup", "hr", ...METADATA_TAGS) }
2057
2078
  ]);
2058
- var optgroupContract = contract([
2079
+ var optgroupContract = closedContract([
2059
2080
  { name: "option", match: isTag("option", ...METADATA_TAGS) }
2060
2081
  ]);
2061
- var datalistContract = contract([
2082
+ var datalistContract = closedContract([
2062
2083
  { name: "option", match: isTag("option", ...METADATA_TAGS) }
2063
2084
  ]);
2064
- var pictureContract = contract([
2085
+ var pictureContract = closedContract([
2065
2086
  { name: "source", match: isTag("source", ...METADATA_TAGS) },
2066
2087
  { name: "image", match: isTag("img"), cardinality: { min: 1, max: 1 }, position: "last" }
2067
2088
  ]);
@@ -2077,23 +2098,18 @@ var mediaContract = contract([
2077
2098
  metadata(),
2078
2099
  { name: "content", match: isOpenContent("source", "track", ...METADATA_TAGS) }
2079
2100
  ]);
2080
- var headContract = contract([
2101
+ var headContract = closedContract([
2081
2102
  {
2082
2103
  name: "metadata",
2083
2104
  match: isTag("base", "link", "meta", "noscript", "script", "style", "template", "title")
2084
2105
  }
2085
2106
  ]);
2086
- var htmlContract = contract([
2107
+ var htmlContract = closedContract([
2087
2108
  { name: "head", match: isTag("head"), cardinality: { min: 1, max: 1 }, position: "first" },
2088
2109
  { name: "body", match: isTag("body"), cardinality: { min: 1, max: 1 } }
2089
2110
  ]);
2090
- var voidContract = contract([]);
2091
- var textOnlyContract = contract([
2092
- {
2093
- name: "text",
2094
- match: (child) => isString(child) || isNumber(child)
2095
- }
2096
- ]);
2111
+ var voidContract = contract([], { exclusiveChildren: true, allowText: false });
2112
+ var textOnlyContract = contract([], { exclusiveChildren: true });
2097
2113
  var landmarkContract = ariaContract([landmarkRoleRule, landmarkNameAdvisory]);
2098
2114
  var dialogContract = ariaContract([requireAccessibleName]);
2099
2115
  var menuContract = ariaContract([requireAccessibleName]);
@@ -2138,9 +2154,15 @@ var htmlContracts = {
2138
2154
  var htmlDiagnostics = warnDiagnostics2;
2139
2155
  function buildEvaluatorMap() {
2140
2156
  const map2 = /* @__PURE__ */ new Map();
2141
- iterate.forEachEntry(htmlContracts, (tag, { children }) => {
2142
- if (children?.length) {
2143
- map2.set(tag, new ChildrenEvaluator(children, htmlDiagnostics, `<${tag}>`));
2157
+ iterate.forEachEntry(htmlContracts, (tag, { children, exclusiveChildren, allowText }) => {
2158
+ if (children?.length || exclusiveChildren || allowText === false) {
2159
+ map2.set(
2160
+ tag,
2161
+ new ChildrenEvaluator(children ?? [], htmlDiagnostics, `<${tag}>`, {
2162
+ exclusiveChildren,
2163
+ allowText
2164
+ })
2165
+ );
2144
2166
  }
2145
2167
  });
2146
2168
  return map2;
@@ -2351,7 +2373,7 @@ function definePipeline(factory) {
2351
2373
  }
2352
2374
 
2353
2375
  // ../core/src/options/resolve-factory-options.ts
2354
- import { silentDiagnostics } from "../_shared/diagnostics.js";
2376
+ import { resolveDiagnostics, silentDiagnostics } from "../_shared/diagnostics.js";
2355
2377
  var EMPTY_VARIANT_KEYS = /* @__PURE__ */ new Set();
2356
2378
  function composeNormalizers(normalizers, fn) {
2357
2379
  if (!normalizers?.length) return fn;
@@ -2372,7 +2394,7 @@ function resolveFactoryOptions(options = {}) {
2372
2394
  const variantKeys = styling?.variants === void 0 ? EMPTY_VARIANT_KEYS : new Set(Object.keys(styling.variants));
2373
2395
  return Object.freeze({
2374
2396
  defaultTag: options.tag ?? "div",
2375
- diagnostics: enforcement?.diagnostics ?? silentDiagnostics,
2397
+ diagnostics: resolveDiagnostics(enforcement?.diagnostics, silentDiagnostics),
2376
2398
  variantKeys,
2377
2399
  ...whenDefined("displayName", options.name),
2378
2400
  ...whenDefined("defaultProps", options.defaults),
@@ -2385,6 +2407,8 @@ function resolveFactoryOptions(options = {}) {
2385
2407
  ...whenDefined("normalizeFn", composedNormalizeFn),
2386
2408
  ...whenDefined("ariaRules", enforcement?.aria),
2387
2409
  ...whenDefined("childRules", enforcement?.children),
2410
+ ...whenDefined("exclusiveChildren", enforcement?.exclusiveChildren),
2411
+ ...whenDefined("allowText", enforcement?.allowText),
2388
2412
  ...whenDefined("allowedAs", enforcement?.allowedAs),
2389
2413
  ...whenDefined("precomputedClasses", styling?.precomputedClasses)
2390
2414
  });
@@ -2569,16 +2593,22 @@ function buildCoreRuntime(normalized) {
2569
2593
  }
2570
2594
 
2571
2595
  // ../../lib/adapter-utils/src/runtime/build-engines.ts
2572
- function buildEngines(diagnostics, childRules, context) {
2573
- return childRules?.length ? { childrenEvaluator: new ChildrenEvaluator(childRules, diagnostics, context) } : {};
2596
+ function buildEngines(diagnostics, childRules, context, childrenOptions) {
2597
+ const { exclusiveChildren, allowText } = childrenOptions ?? {};
2598
+ return childRules?.length || exclusiveChildren || allowText === false ? {
2599
+ childrenEvaluator: new ChildrenEvaluator(childRules ?? [], diagnostics, context, {
2600
+ exclusiveChildren,
2601
+ allowText
2602
+ })
2603
+ } : {};
2574
2604
  }
2575
2605
 
2576
2606
  // ../../lib/adapter-utils/src/runtime/resolve-adapter-common-options.ts
2577
- import { throwDiagnostics as throwDiagnostics2, silentDiagnostics as silentDiagnostics3 } from "../_shared/diagnostics.js";
2607
+ import { throwDiagnostics as throwDiagnostics2, silentDiagnostics as silentDiagnostics3, resolveDiagnostics as resolveDiagnostics2 } from "../_shared/diagnostics.js";
2578
2608
  function resolveAdapterCommonOptions(options, defaultName = "PolymorphicComponent", defaultDiagnostics = throwDiagnostics2) {
2579
2609
  return {
2580
2610
  name: options.name ?? defaultName,
2581
- diagnostics: options.enforcement?.diagnostics ?? defaultDiagnostics
2611
+ diagnostics: resolveDiagnostics2(options.enforcement?.diagnostics, defaultDiagnostics)
2582
2612
  };
2583
2613
  }
2584
2614
 
@@ -2633,7 +2663,11 @@ function buildRuntime(options) {
2633
2663
  const { childrenEvaluator } = buildEngines(
2634
2664
  normalized.diagnostics,
2635
2665
  normalized.enforcement?.children,
2636
- normalized.name
2666
+ normalized.name,
2667
+ {
2668
+ exclusiveChildren: normalized.enforcement?.exclusiveChildren,
2669
+ allowText: normalized.enforcement?.allowText
2670
+ }
2637
2671
  );
2638
2672
  const filterProps = composeFilter(ownedKeys, normalized.filterProps);
2639
2673
  const slotValidator = new SlotValidator(normalized.name, normalized.diagnostics);
@@ -2646,9 +2680,10 @@ function buildRuntime(options) {
2646
2680
  }
2647
2681
 
2648
2682
  // ../../adapters/solid/src/render.tsx
2683
+ import { createComponent as _$createComponent } from "solid-js/web";
2684
+ import { mergeProps as _$mergeProps } from "solid-js/web";
2649
2685
  import { createEffect, createMemo, splitProps } from "solid-js";
2650
2686
  import { Dynamic } from "solid-js/web";
2651
- import { jsx } from "solid-js/jsx-runtime";
2652
2687
  var SPLIT_KEYS = ["as", "asChild", "children", "class", "recipe", "ref"];
2653
2688
  function toChildArray(children) {
2654
2689
  if (children === void 0 || children === null) return [];
@@ -2656,22 +2691,38 @@ function toChildArray(children) {
2656
2691
  return [children];
2657
2692
  }
2658
2693
  function buildElementProps(props, classStr, ref, children) {
2659
- const { role, ...rest } = props;
2694
+ const {
2695
+ role,
2696
+ ...rest
2697
+ } = props;
2660
2698
  return {
2661
2699
  ...rest,
2662
2700
  class: classStr,
2663
- ...ref !== void 0 && { ref },
2664
- ...children !== void 0 && { children },
2665
- ...isKnownAriaRole(role) && { role }
2701
+ ...ref !== void 0 && {
2702
+ ref
2703
+ },
2704
+ ...children !== void 0 && {
2705
+ children
2706
+ },
2707
+ ...isKnownAriaRole(role) && {
2708
+ role
2709
+ }
2666
2710
  };
2667
2711
  }
2668
2712
  function buildSlotProps(props, classStr, ref) {
2669
- const { role, ...rest } = props;
2713
+ const {
2714
+ role,
2715
+ ...rest
2716
+ } = props;
2670
2717
  return {
2671
2718
  ...rest,
2672
2719
  class: classStr,
2673
- ...ref !== void 0 && { ref },
2674
- ...isKnownAriaRole(role) && { role }
2720
+ ...ref !== void 0 && {
2721
+ ref
2722
+ },
2723
+ ...isKnownAriaRole(role) && {
2724
+ role
2725
+ }
2675
2726
  };
2676
2727
  }
2677
2728
  function resolveTag2(runtime, as) {
@@ -2688,9 +2739,7 @@ function tryRenderAsChild(known, filteredProps, resolvedClass, slotValidator) {
2688
2739
  }
2689
2740
  if (!slotValidator.assertRenderFn(known.children)) return null;
2690
2741
  const renderFn = known.children;
2691
- return createMemo(
2692
- () => renderFn(buildSlotProps(filteredProps(), resolvedClass(), known.ref))
2693
- );
2742
+ return createMemo(() => renderFn(buildSlotProps(filteredProps(), resolvedClass(), known.ref)));
2694
2743
  }
2695
2744
  function render({
2696
2745
  runtime,
@@ -2706,32 +2755,24 @@ function render({
2706
2755
  const normalizedProps = createMemo(() => {
2707
2756
  const base = runtime.options.normalizeFn ? runtime.options.normalizeFn(mergedProps()) : mergedProps();
2708
2757
  const htmlNormalizers = runtime.options.htmlPropNormalizersFn?.(tag());
2709
- return htmlNormalizers?.length ? htmlNormalizers.reduce((acc, fn) => ({ ...acc, ...fn(acc) }), base) : base;
2758
+ return htmlNormalizers?.length ? htmlNormalizers.reduce((acc, fn) => ({
2759
+ ...acc,
2760
+ ...fn(acc)
2761
+ }), base) : base;
2710
2762
  });
2711
- const resolvedClass = createMemo(
2712
- () => runtime.resolveClasses(
2713
- tag(),
2714
- normalizedProps(),
2715
- known.class,
2716
- known.recipe
2717
- )
2718
- );
2719
- const filteredProps = createMemo(
2720
- () => applyFilter(normalizedProps(), filterProps, runtime.options.variantKeys)
2721
- );
2722
- const { allowedAs } = runtime.options;
2763
+ const resolvedClass = createMemo(() => runtime.resolveClasses(tag(), normalizedProps(), known.class, known.recipe));
2764
+ const filteredProps = createMemo(() => applyFilter(normalizedProps(), filterProps, runtime.options.variantKeys));
2765
+ const {
2766
+ allowedAs
2767
+ } = runtime.options;
2723
2768
  if (allowedAs !== void 0) {
2724
- createEffect(
2725
- () => enforceAllowedAs(tag(), allowedAs, runtime.options.diagnostics, runtime.options.displayName)
2726
- );
2769
+ createEffect(() => enforceAllowedAs(tag(), allowedAs, runtime.options.diagnostics, runtime.options.displayName));
2727
2770
  }
2728
2771
  if (process.env.NODE_ENV !== "production" && childrenEvaluator) {
2729
2772
  createEffect(() => childrenEvaluator.evaluate(toChildArray(known.children)));
2730
2773
  }
2731
2774
  if (process.env.NODE_ENV !== "production") {
2732
- createEffect(
2733
- () => runtime.options.htmlChildrenEvaluatorFn?.(tag())?.evaluate(toChildArray(known.children))
2734
- );
2775
+ createEffect(() => runtime.options.htmlChildrenEvaluatorFn?.(tag())?.evaluate(toChildArray(known.children)));
2735
2776
  }
2736
2777
  const slotResult = tryRenderAsChild(known, filteredProps, resolvedClass, slotValidator);
2737
2778
  if (slotResult !== null) return slotResult;
@@ -2739,7 +2780,11 @@ function render({
2739
2780
  const ep = buildElementProps(filteredProps(), resolvedClass(), known.ref, known.children);
2740
2781
  return resolveDomProps(tag(), ep, runtime);
2741
2782
  });
2742
- return /* @__PURE__ */ jsx(Dynamic, { component: tag(), ...domProps() });
2783
+ return _$createComponent(Dynamic, _$mergeProps({
2784
+ get component() {
2785
+ return tag();
2786
+ }
2787
+ }, () => domProps()));
2743
2788
  }
2744
2789
 
2745
2790
  // ../../adapters/solid/src/create-contract-component.ts
@@ -0,0 +1,146 @@
1
+ <script module lang="ts">
2
+ declare const process: { env: { NODE_ENV: string } }
3
+ </script>
4
+
5
+ <script lang="ts">
6
+ import { enforceAllowedAs, isKnownAriaRole } from '@praxis-kit/core'
7
+ import type { ElementType, IntrinsicProps } from '@praxis-kit/core'
8
+ import { isObject, isString } from '@praxis-kit/primitive'
9
+ import { applyFilter } from '@praxis-kit/adapter-utils'
10
+ import type { Snippet } from 'svelte'
11
+ import type {
12
+ PolymorphicComponentProps,
13
+ ResolvedAttributes,
14
+ StyleObject,
15
+ UnknownProps,
16
+ } from './types'
17
+
18
+ let {
19
+ bundle,
20
+ as: asProp,
21
+ asChild,
22
+ class: cls,
23
+ recipe,
24
+ children,
25
+ ...rest
26
+ }: PolymorphicComponentProps = $props()
27
+ let hostEl: Element | undefined = $state()
28
+
29
+ // Svelte 5 event delegation requires lowercase handler names (onclick, onfocus…).
30
+ // Normalize React-style camelCase handlers so spreads on <svelte:element> work.
31
+ const EVENT_RE = /^on[A-Z]/
32
+ function normalizeEventKeys(props: UnknownProps): UnknownProps {
33
+ const out: ResolvedAttributes = {}
34
+ for (const k in props) {
35
+ out[EVENT_RE.test(k) ? k.toLowerCase() : k] = (props as ResolvedAttributes)[k]
36
+ }
37
+ return out as UnknownProps
38
+ }
39
+
40
+ function serializeStyle(style: StyleObject): string {
41
+ let result = ''
42
+ for (const key in style) {
43
+ const value = style[key]
44
+ if (value == null) continue
45
+ if (result) result += ';'
46
+ result += `${key.replace(/([A-Z])/g, '-$1').toLowerCase()}:${value}`
47
+ }
48
+ return result
49
+ }
50
+
51
+ function buildDomProps(
52
+ props: UnknownProps,
53
+ classStr: string,
54
+ tag: ElementType,
55
+ ): ResolvedAttributes {
56
+ const { role, style, ...r } = normalizeEventKeys(props)
57
+ const styleStr = isObject(style, true)
58
+ ? serializeStyle(style as StyleObject)
59
+ : (style as string | undefined)
60
+ const ep: IntrinsicProps = {
61
+ ...(r as IntrinsicProps),
62
+ class: classStr,
63
+ ...(styleStr !== undefined && { style: styleStr }),
64
+ }
65
+ if (isKnownAriaRole(role)) ep.role = role
66
+ if (!isString(tag)) return ep as ResolvedAttributes
67
+ return bundle.runtime.resolveAria(tag, ep).props as ResolvedAttributes
68
+ }
69
+
70
+ function buildSlotProps(props: UnknownProps, classStr: string): UnknownProps {
71
+ const { role, ...r } = props
72
+ return {
73
+ ...r,
74
+ class: classStr,
75
+ ...(isKnownAriaRole(role) && { role }),
76
+ }
77
+ }
78
+
79
+ const tag = $derived(bundle.runtime.resolveTag(asProp as ElementType | undefined))
80
+ const mergedProps = $derived(bundle.runtime.resolveProps(rest as UnknownProps))
81
+ const normalizedProps = $derived.by(() => {
82
+ const { runtime: { options } } = bundle
83
+ // Folded into this derived (rather than a standalone one) so it's guaranteed to run on
84
+ // both SSR and DOM — $derived is lazy in Svelte 5 and only evaluates when read; this one
85
+ // is read downstream by resolvedClass/filteredProps/domProps, which the template renders.
86
+ if (options.allowedAs !== undefined) {
87
+ enforceAllowedAs(
88
+ tag,
89
+ options.allowedAs,
90
+ options.diagnostics,
91
+ options.displayName,
92
+ )
93
+ }
94
+ const base =
95
+ typeof options.normalizeFn === 'function' ? options.normalizeFn(mergedProps) : mergedProps
96
+
97
+ const htmlNormalizers = options.htmlPropNormalizersFn?.(tag)
98
+
99
+ if (!htmlNormalizers?.length) {
100
+ return base
101
+ }
102
+
103
+ return htmlNormalizers.reduce((acc, fn) => ({ ...acc, ...fn(acc) }), base)
104
+ })
105
+ const resolvedClass = $derived(
106
+ bundle.runtime.resolveClasses(tag, normalizedProps, cls as string | undefined, recipe),
107
+ )
108
+ const filteredProps = $derived(
109
+ applyFilter(normalizedProps, bundle.filterProps, bundle.runtime.options.variantKeys),
110
+ )
111
+ const domProps = $derived(buildDomProps(filteredProps, resolvedClass, tag))
112
+
113
+ // Resolves whether to render as child slot; also enforces as+asChild mutual exclusion.
114
+ const useAsChild = $derived.by(() => {
115
+ if (!asChild) return false
116
+ if (asProp !== undefined) {
117
+ bundle.slotValidator.assertExclusive()
118
+ return false
119
+ }
120
+ return true
121
+ })
122
+
123
+ // DOM-only (like Lit skipping htmlChildrenEvaluatorFn for its SSR renderToString). Merely
124
+ // *registering* $effect during svelte/server's render() throws ("effect_orphan") — it's not
125
+ // enough to no-op inside the callback, the rune call itself must never happen during SSR.
126
+ // Reads real child nodes off the mounted host, same approach as Lit's Array.from(this.childNodes).
127
+ // Not reachable in the asChild branch — no host element there.
128
+ if (typeof document !== 'undefined') {
129
+ $effect(() => {
130
+ if (process.env.NODE_ENV === 'production' || !hostEl) return
131
+ const childArray = Array.from(hostEl.childNodes)
132
+ bundle.childrenEvaluator?.evaluate(childArray)
133
+ bundle.runtime.options.htmlChildrenEvaluatorFn?.(tag)?.evaluate(childArray)
134
+ })
135
+ }
136
+ </script>
137
+
138
+ {#if useAsChild}
139
+ {#if children}
140
+ {@render (children as Snippet<[UnknownProps]>)(buildSlotProps(filteredProps, resolvedClass))}
141
+ {/if}
142
+ {:else}
143
+ <svelte:element this={tag as string} bind:this={hostEl} {...domProps}>
144
+ {@render (children as Snippet | undefined)?.()}
145
+ </svelte:element>
146
+ {/if}
@@ -1,5 +1,5 @@
1
1
  import { RequireAtLeastOne, Simplify, ReadonlyDeep } from 'type-fest';
2
- import { Diagnostics, DiagnosticInput } from '../_shared/diagnostics.js';
2
+ import { Diagnostics, DiagnosticInput, DiagnosticsMode } from '../_shared/diagnostics.js';
3
3
 
4
4
  type StringMap<T = unknown> = Record<string, T>;
5
5
  type AnyRecord = StringMap<unknown>;
@@ -217,9 +217,25 @@ type AriaRule<C extends AriaContext = AriaContext> = (context: C) => readonly Ar
217
217
  type PropNormalizer = (props: Readonly<AnyRecord & IntrinsicProps>) => Partial<AnyRecord & IntrinsicProps>;
218
218
 
219
219
  type EnforcementOptions<TAllowed extends ElementType = ElementType> = {
220
- readonly diagnostics?: Diagnostics;
220
+ /**
221
+ * Accepts a preset name (`'warn'`, `'throw'`, `'silent'`) or a full `Diagnostics`
222
+ * instance for custom reporting/policy. The string form needs no import from
223
+ * `@praxis-kit/diagnostics`.
224
+ */
225
+ readonly diagnostics?: Diagnostics | DiagnosticsMode;
221
226
  readonly aria?: readonly AriaRule[];
222
227
  readonly children?: readonly ChildRuleInput[];
228
+ /**
229
+ * When true, only children matching a `children` rule (or text, per `allowText`)
230
+ * are valid — anything else is rejected. Default: false (open — children not
231
+ * matching any rule are allowed).
232
+ */
233
+ readonly exclusiveChildren?: boolean;
234
+ /**
235
+ * When false, text/number child nodes are rejected regardless of exclusiveChildren
236
+ * or any listed rule. Default: true.
237
+ */
238
+ readonly allowText?: boolean;
223
239
  readonly props?: readonly PropNormalizer[];
224
240
  /** Restricts the `as` prop to this set of tags. Violations route through diagnostics. */
225
241
  readonly allowedAs?: readonly TAllowed[];
@@ -265,6 +281,8 @@ type ResolvedFactoryOptions<TDefault extends ElementType = ElementType, Props ex
265
281
  readonly htmlPropNormalizersFn?: (tag: unknown) => readonly PropNormalizer[] | undefined;
266
282
  readonly htmlChildrenEvaluatorFn?: (tag: unknown) => ChildrenEvaluator$1 | undefined;
267
283
  readonly childRules?: readonly ChildRuleInput[];
284
+ readonly exclusiveChildren?: boolean;
285
+ readonly allowText?: boolean;
268
286
  readonly ariaRules?: readonly AriaRule[];
269
287
  readonly allowedAs?: readonly ElementType[];
270
288
  readonly precomputedClasses?: Readonly<Record<string, string>>;
@@ -302,9 +320,22 @@ declare abstract class InvariantBase {
302
320
  protected invariant(condition: unknown, input: DiagnosticInput): void;
303
321
  }
304
322
 
323
+ type ChildrenEvaluatorOptions = {
324
+ /**
325
+ * When true, only children matching a rule (or text, per `allowText`) are
326
+ * valid — anything else is rejected. Default: false (open — children not
327
+ * matching any rule are allowed).
328
+ */
329
+ readonly exclusiveChildren?: boolean | undefined;
330
+ /**
331
+ * When false, text/number child nodes are rejected regardless of
332
+ * exclusiveChildren or any listed rule. Default: true.
333
+ */
334
+ readonly allowText?: boolean | undefined;
335
+ };
305
336
  declare class ChildrenEvaluator extends InvariantBase {
306
337
  #private;
307
- constructor(rules: readonly ChildRuleInput[], diagnostics: Diagnostics, context?: string);
338
+ constructor(rules: readonly ChildRuleInput[], diagnostics: Diagnostics, context?: string, options?: ChildrenEvaluatorOptions);
308
339
  evaluate(children: unknown[]): void;
309
340
  }
310
341