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.
package/dist/lit/index.js CHANGED
@@ -1714,17 +1714,22 @@ var RuleValidator = class _RuleValidator extends InvariantBase {
1714
1714
  };
1715
1715
 
1716
1716
  // ../../lib/contract/src/children/children-evaluator.ts
1717
+ var isTextLike = (child) => isString(child) || isNumber(child);
1717
1718
  var ChildrenEvaluator = class extends InvariantBase {
1718
1719
  #context;
1719
1720
  #rules;
1720
1721
  #ruleNames;
1721
1722
  #matcher;
1722
1723
  #ruleValidator;
1723
- constructor(rules, diagnostics, context = "Component") {
1724
+ #exclusiveChildren;
1725
+ #allowText;
1726
+ constructor(rules, diagnostics, context = "Component", options = {}) {
1724
1727
  super(diagnostics);
1725
1728
  this.#context = context;
1726
1729
  this.#rules = rules.map((r) => normalizeChildRule(r));
1727
1730
  this.#ruleNames = this.#rules.map((r) => r.name);
1731
+ this.#exclusiveChildren = options.exclusiveChildren ?? false;
1732
+ this.#allowText = options.allowText ?? true;
1728
1733
  iterate.forEach(this.#rules, (rule) => {
1729
1734
  const { name, position, cardinality } = rule;
1730
1735
  if ((position === "first" || position === "last") && (cardinality.kind === "unbounded" || cardinality.max > 1)) {
@@ -1738,8 +1743,17 @@ var ChildrenEvaluator = class extends InvariantBase {
1738
1743
  }
1739
1744
  evaluate(children) {
1740
1745
  if (!this.active) return;
1741
- const { matrix, unexpectedIndices, ambiguousIndices } = this.#matcher.match(children);
1746
+ const {
1747
+ matrix,
1748
+ unexpectedIndices: rawUnexpectedIndices,
1749
+ ambiguousIndices
1750
+ } = this.#matcher.match(children);
1742
1751
  this.#ruleValidator.validate(this.#rules, matrix, children.length);
1752
+ const unexpectedIndices = new Set(
1753
+ [...rawUnexpectedIndices].filter(
1754
+ (ci) => isTextLike(children[ci]) ? this.#allowText === false : this.#exclusiveChildren
1755
+ )
1756
+ );
1743
1757
  if (unexpectedIndices.size === 0 && ambiguousIndices.size === 0) return;
1744
1758
  const violating = [...unexpectedIndices, ...ambiguousIndices].sort((a, b) => a - b);
1745
1759
  iterate.forEach(violating, (ci) => {
@@ -1861,8 +1875,11 @@ function metadata(name = "metadata") {
1861
1875
  function firstOptional(name, tag) {
1862
1876
  return { name, match: isTag(tag), cardinality: { max: 1 }, position: "first" };
1863
1877
  }
1864
- function contract(children) {
1865
- return { diagnostics: warnDiagnostics, children };
1878
+ function contract(children, options) {
1879
+ return { diagnostics: warnDiagnostics, children, ...options };
1880
+ }
1881
+ function closedContract(children) {
1882
+ return contract(children, { exclusiveChildren: true });
1866
1883
  }
1867
1884
  function ariaContract(aria) {
1868
1885
  return { diagnostics: warnDiagnostics, aria };
@@ -1888,8 +1905,10 @@ var VOID_TAGS = [
1888
1905
  ];
1889
1906
  var TEXT_ONLY_TAGS = ["option", "script", "style", "textarea", "title"];
1890
1907
  var LANDMARK_TAGS = ["article", "aside", "footer", "header", "main", "nav"];
1891
- var listContract = contract([{ name: "list-item", match: isTag("li", ...METADATA_TAGS) }]);
1892
- var tableContract = contract([
1908
+ var listContract = closedContract([
1909
+ { name: "list-item", match: isTag("li", ...METADATA_TAGS) }
1910
+ ]);
1911
+ var tableContract = closedContract([
1893
1912
  firstOptional("caption", "caption"),
1894
1913
  { name: "colgroup", match: isTag("colgroup") },
1895
1914
  { name: "thead", match: isTag("thead"), cardinality: { max: 1 } },
@@ -1897,29 +1916,31 @@ var tableContract = contract([
1897
1916
  { name: "tfoot", match: isTag("tfoot"), cardinality: { max: 1 } },
1898
1917
  { name: "table-row", match: isTag("tr", ...METADATA_TAGS) }
1899
1918
  ]);
1900
- var tableBodyContract = contract([
1919
+ var tableBodyContract = closedContract([
1901
1920
  { name: "table-row", match: isTag("tr", ...METADATA_TAGS) }
1902
1921
  ]);
1903
- var tableRowContract = contract([
1922
+ var tableRowContract = closedContract([
1904
1923
  { name: "table-cell", match: isTag("td", "th", ...METADATA_TAGS) }
1905
1924
  ]);
1906
- var colgroupContract = contract([{ name: "column", match: isTag("col", "template") }]);
1907
- var dlContract = contract([
1925
+ var colgroupContract = closedContract([
1926
+ { name: "column", match: isTag("col", "template") }
1927
+ ]);
1928
+ var dlContract = closedContract([
1908
1929
  { name: "term", match: isTag("dt") },
1909
1930
  { name: "description", match: isTag("dd") },
1910
1931
  { name: "group", match: isTag("div") },
1911
1932
  metadata()
1912
1933
  ]);
1913
- var selectContract = contract([
1934
+ var selectContract = closedContract([
1914
1935
  { name: "option", match: isTag("option", "optgroup", "hr", ...METADATA_TAGS) }
1915
1936
  ]);
1916
- var optgroupContract = contract([
1937
+ var optgroupContract = closedContract([
1917
1938
  { name: "option", match: isTag("option", ...METADATA_TAGS) }
1918
1939
  ]);
1919
- var datalistContract = contract([
1940
+ var datalistContract = closedContract([
1920
1941
  { name: "option", match: isTag("option", ...METADATA_TAGS) }
1921
1942
  ]);
1922
- var pictureContract = contract([
1943
+ var pictureContract = closedContract([
1923
1944
  { name: "source", match: isTag("source", ...METADATA_TAGS) },
1924
1945
  { name: "image", match: isTag("img"), cardinality: { min: 1, max: 1 }, position: "last" }
1925
1946
  ]);
@@ -1935,23 +1956,18 @@ var mediaContract = contract([
1935
1956
  metadata(),
1936
1957
  { name: "content", match: isOpenContent("source", "track", ...METADATA_TAGS) }
1937
1958
  ]);
1938
- var headContract = contract([
1959
+ var headContract = closedContract([
1939
1960
  {
1940
1961
  name: "metadata",
1941
1962
  match: isTag("base", "link", "meta", "noscript", "script", "style", "template", "title")
1942
1963
  }
1943
1964
  ]);
1944
- var htmlContract = contract([
1965
+ var htmlContract = closedContract([
1945
1966
  { name: "head", match: isTag("head"), cardinality: { min: 1, max: 1 }, position: "first" },
1946
1967
  { name: "body", match: isTag("body"), cardinality: { min: 1, max: 1 } }
1947
1968
  ]);
1948
- var voidContract = contract([]);
1949
- var textOnlyContract = contract([
1950
- {
1951
- name: "text",
1952
- match: (child) => isString(child) || isNumber(child)
1953
- }
1954
- ]);
1969
+ var voidContract = contract([], { exclusiveChildren: true, allowText: false });
1970
+ var textOnlyContract = contract([], { exclusiveChildren: true });
1955
1971
  var landmarkContract = ariaContract([landmarkRoleRule, landmarkNameAdvisory]);
1956
1972
  var dialogContract = ariaContract([requireAccessibleName]);
1957
1973
  var menuContract = ariaContract([requireAccessibleName]);
@@ -1996,9 +2012,15 @@ var htmlContracts = {
1996
2012
  var htmlDiagnostics = warnDiagnostics2;
1997
2013
  function buildEvaluatorMap() {
1998
2014
  const map2 = /* @__PURE__ */ new Map();
1999
- iterate.forEachEntry(htmlContracts, (tag, { children }) => {
2000
- if (children?.length) {
2001
- map2.set(tag, new ChildrenEvaluator(children, htmlDiagnostics, `<${tag}>`));
2015
+ iterate.forEachEntry(htmlContracts, (tag, { children, exclusiveChildren, allowText }) => {
2016
+ if (children?.length || exclusiveChildren || allowText === false) {
2017
+ map2.set(
2018
+ tag,
2019
+ new ChildrenEvaluator(children ?? [], htmlDiagnostics, `<${tag}>`, {
2020
+ exclusiveChildren,
2021
+ allowText
2022
+ })
2023
+ );
2002
2024
  }
2003
2025
  });
2004
2026
  return map2;
@@ -2209,7 +2231,7 @@ function definePipeline(factory) {
2209
2231
  }
2210
2232
 
2211
2233
  // ../core/src/options/resolve-factory-options.ts
2212
- import { silentDiagnostics } from "../_shared/diagnostics.js";
2234
+ import { resolveDiagnostics, silentDiagnostics } from "../_shared/diagnostics.js";
2213
2235
  var EMPTY_VARIANT_KEYS = /* @__PURE__ */ new Set();
2214
2236
  function composeNormalizers(normalizers, fn) {
2215
2237
  if (!normalizers?.length) return fn;
@@ -2230,7 +2252,7 @@ function resolveFactoryOptions(options = {}) {
2230
2252
  const variantKeys = styling?.variants === void 0 ? EMPTY_VARIANT_KEYS : new Set(Object.keys(styling.variants));
2231
2253
  return Object.freeze({
2232
2254
  defaultTag: options.tag ?? "div",
2233
- diagnostics: enforcement?.diagnostics ?? silentDiagnostics,
2255
+ diagnostics: resolveDiagnostics(enforcement?.diagnostics, silentDiagnostics),
2234
2256
  variantKeys,
2235
2257
  ...whenDefined("displayName", options.name),
2236
2258
  ...whenDefined("defaultProps", options.defaults),
@@ -2243,6 +2265,8 @@ function resolveFactoryOptions(options = {}) {
2243
2265
  ...whenDefined("normalizeFn", composedNormalizeFn),
2244
2266
  ...whenDefined("ariaRules", enforcement?.aria),
2245
2267
  ...whenDefined("childRules", enforcement?.children),
2268
+ ...whenDefined("exclusiveChildren", enforcement?.exclusiveChildren),
2269
+ ...whenDefined("allowText", enforcement?.allowText),
2246
2270
  ...whenDefined("allowedAs", enforcement?.allowedAs),
2247
2271
  ...whenDefined("precomputedClasses", styling?.precomputedClasses)
2248
2272
  });
@@ -2427,16 +2451,22 @@ function buildCoreRuntime(normalized) {
2427
2451
  }
2428
2452
 
2429
2453
  // ../../lib/adapter-utils/src/runtime/build-engines.ts
2430
- function buildEngines(diagnostics, childRules, context) {
2431
- return childRules?.length ? { childrenEvaluator: new ChildrenEvaluator(childRules, diagnostics, context) } : {};
2454
+ function buildEngines(diagnostics, childRules, context, childrenOptions) {
2455
+ const { exclusiveChildren, allowText } = childrenOptions ?? {};
2456
+ return childRules?.length || exclusiveChildren || allowText === false ? {
2457
+ childrenEvaluator: new ChildrenEvaluator(childRules ?? [], diagnostics, context, {
2458
+ exclusiveChildren,
2459
+ allowText
2460
+ })
2461
+ } : {};
2432
2462
  }
2433
2463
 
2434
2464
  // ../../lib/adapter-utils/src/runtime/resolve-adapter-common-options.ts
2435
- import { throwDiagnostics as throwDiagnostics2, silentDiagnostics as silentDiagnostics3 } from "../_shared/diagnostics.js";
2465
+ import { throwDiagnostics as throwDiagnostics2, silentDiagnostics as silentDiagnostics3, resolveDiagnostics as resolveDiagnostics2 } from "../_shared/diagnostics.js";
2436
2466
  function resolveAdapterCommonOptions(options, defaultName = "PolymorphicComponent", defaultDiagnostics = throwDiagnostics2) {
2437
2467
  return {
2438
2468
  name: options.name ?? defaultName,
2439
- diagnostics: options.enforcement?.diagnostics ?? defaultDiagnostics
2469
+ diagnostics: resolveDiagnostics2(options.enforcement?.diagnostics, defaultDiagnostics)
2440
2470
  };
2441
2471
  }
2442
2472
 
@@ -2600,7 +2630,8 @@ function buildRuntime(options) {
2600
2630
  const { childrenEvaluator } = buildEngines(
2601
2631
  normalized.diagnostics,
2602
2632
  enforcement?.children,
2603
- normalized.name
2633
+ normalized.name,
2634
+ { exclusiveChildren: enforcement?.exclusiveChildren, allowText: enforcement?.allowText }
2604
2635
  );
2605
2636
  const filterProps = composeFilter(ownedKeys, customFilter);
2606
2637
  return {
@@ -1,5 +1,5 @@
1
1
  import { RequireAtLeastOne, Simplify, ReadonlyDeep, OmitIndexSignature } from 'type-fest';
2
- import { Diagnostics, DiagnosticInput } from '../_shared/diagnostics.js';
2
+ import { Diagnostics, DiagnosticInput, DiagnosticsMode } from '../_shared/diagnostics.js';
3
3
  import { ComponentChildren, VNode, ComponentType, JSX, Ref } from 'preact';
4
4
 
5
5
  type StringMap<T = unknown> = Record<string, T>;
@@ -213,9 +213,25 @@ type AriaRule<C extends AriaContext = AriaContext> = (context: C) => readonly Ar
213
213
  type PropNormalizer = (props: Readonly<AnyRecord & IntrinsicProps>) => Partial<AnyRecord & IntrinsicProps>;
214
214
 
215
215
  type EnforcementOptions<TAllowed extends ElementType = ElementType> = {
216
- readonly diagnostics?: Diagnostics;
216
+ /**
217
+ * Accepts a preset name (`'warn'`, `'throw'`, `'silent'`) or a full `Diagnostics`
218
+ * instance for custom reporting/policy. The string form needs no import from
219
+ * `@praxis-kit/diagnostics`.
220
+ */
221
+ readonly diagnostics?: Diagnostics | DiagnosticsMode;
217
222
  readonly aria?: readonly AriaRule[];
218
223
  readonly children?: readonly ChildRuleInput[];
224
+ /**
225
+ * When true, only children matching a `children` rule (or text, per `allowText`)
226
+ * are valid — anything else is rejected. Default: false (open — children not
227
+ * matching any rule are allowed).
228
+ */
229
+ readonly exclusiveChildren?: boolean;
230
+ /**
231
+ * When false, text/number child nodes are rejected regardless of exclusiveChildren
232
+ * or any listed rule. Default: true.
233
+ */
234
+ readonly allowText?: boolean;
219
235
  readonly props?: readonly PropNormalizer[];
220
236
  /** Restricts the `as` prop to this set of tags. Violations route through diagnostics. */
221
237
  readonly allowedAs?: readonly TAllowed[];
@@ -1899,17 +1899,22 @@ var RuleValidator = class _RuleValidator extends InvariantBase {
1899
1899
  };
1900
1900
 
1901
1901
  // ../../lib/contract/src/children/children-evaluator.ts
1902
+ var isTextLike = (child) => isString(child) || isNumber(child);
1902
1903
  var ChildrenEvaluator = class extends InvariantBase {
1903
1904
  #context;
1904
1905
  #rules;
1905
1906
  #ruleNames;
1906
1907
  #matcher;
1907
1908
  #ruleValidator;
1908
- constructor(rules, diagnostics, context = "Component") {
1909
+ #exclusiveChildren;
1910
+ #allowText;
1911
+ constructor(rules, diagnostics, context = "Component", options = {}) {
1909
1912
  super(diagnostics);
1910
1913
  this.#context = context;
1911
1914
  this.#rules = rules.map((r) => normalizeChildRule(r));
1912
1915
  this.#ruleNames = this.#rules.map((r) => r.name);
1916
+ this.#exclusiveChildren = options.exclusiveChildren ?? false;
1917
+ this.#allowText = options.allowText ?? true;
1913
1918
  iterate.forEach(this.#rules, (rule) => {
1914
1919
  const { name, position, cardinality } = rule;
1915
1920
  if ((position === "first" || position === "last") && (cardinality.kind === "unbounded" || cardinality.max > 1)) {
@@ -1923,8 +1928,17 @@ var ChildrenEvaluator = class extends InvariantBase {
1923
1928
  }
1924
1929
  evaluate(children) {
1925
1930
  if (!this.active) return;
1926
- const { matrix, unexpectedIndices, ambiguousIndices } = this.#matcher.match(children);
1931
+ const {
1932
+ matrix,
1933
+ unexpectedIndices: rawUnexpectedIndices,
1934
+ ambiguousIndices
1935
+ } = this.#matcher.match(children);
1927
1936
  this.#ruleValidator.validate(this.#rules, matrix, children.length);
1937
+ const unexpectedIndices = new Set(
1938
+ [...rawUnexpectedIndices].filter(
1939
+ (ci) => isTextLike(children[ci]) ? this.#allowText === false : this.#exclusiveChildren
1940
+ )
1941
+ );
1928
1942
  if (unexpectedIndices.size === 0 && ambiguousIndices.size === 0) return;
1929
1943
  const violating = [...unexpectedIndices, ...ambiguousIndices].sort((a, b) => a - b);
1930
1944
  iterate.forEach(violating, (ci) => {
@@ -2046,8 +2060,11 @@ function metadata(name = "metadata") {
2046
2060
  function firstOptional(name, tag) {
2047
2061
  return { name, match: isTag(tag), cardinality: { max: 1 }, position: "first" };
2048
2062
  }
2049
- function contract(children) {
2050
- return { diagnostics: warnDiagnostics, children };
2063
+ function contract(children, options) {
2064
+ return { diagnostics: warnDiagnostics, children, ...options };
2065
+ }
2066
+ function closedContract(children) {
2067
+ return contract(children, { exclusiveChildren: true });
2051
2068
  }
2052
2069
  function ariaContract(aria) {
2053
2070
  return { diagnostics: warnDiagnostics, aria };
@@ -2073,8 +2090,10 @@ var VOID_TAGS = [
2073
2090
  ];
2074
2091
  var TEXT_ONLY_TAGS = ["option", "script", "style", "textarea", "title"];
2075
2092
  var LANDMARK_TAGS = ["article", "aside", "footer", "header", "main", "nav"];
2076
- var listContract = contract([{ name: "list-item", match: isTag("li", ...METADATA_TAGS) }]);
2077
- var tableContract = contract([
2093
+ var listContract = closedContract([
2094
+ { name: "list-item", match: isTag("li", ...METADATA_TAGS) }
2095
+ ]);
2096
+ var tableContract = closedContract([
2078
2097
  firstOptional("caption", "caption"),
2079
2098
  { name: "colgroup", match: isTag("colgroup") },
2080
2099
  { name: "thead", match: isTag("thead"), cardinality: { max: 1 } },
@@ -2082,29 +2101,31 @@ var tableContract = contract([
2082
2101
  { name: "tfoot", match: isTag("tfoot"), cardinality: { max: 1 } },
2083
2102
  { name: "table-row", match: isTag("tr", ...METADATA_TAGS) }
2084
2103
  ]);
2085
- var tableBodyContract = contract([
2104
+ var tableBodyContract = closedContract([
2086
2105
  { name: "table-row", match: isTag("tr", ...METADATA_TAGS) }
2087
2106
  ]);
2088
- var tableRowContract = contract([
2107
+ var tableRowContract = closedContract([
2089
2108
  { name: "table-cell", match: isTag("td", "th", ...METADATA_TAGS) }
2090
2109
  ]);
2091
- var colgroupContract = contract([{ name: "column", match: isTag("col", "template") }]);
2092
- var dlContract = contract([
2110
+ var colgroupContract = closedContract([
2111
+ { name: "column", match: isTag("col", "template") }
2112
+ ]);
2113
+ var dlContract = closedContract([
2093
2114
  { name: "term", match: isTag("dt") },
2094
2115
  { name: "description", match: isTag("dd") },
2095
2116
  { name: "group", match: isTag("div") },
2096
2117
  metadata()
2097
2118
  ]);
2098
- var selectContract = contract([
2119
+ var selectContract = closedContract([
2099
2120
  { name: "option", match: isTag("option", "optgroup", "hr", ...METADATA_TAGS) }
2100
2121
  ]);
2101
- var optgroupContract = contract([
2122
+ var optgroupContract = closedContract([
2102
2123
  { name: "option", match: isTag("option", ...METADATA_TAGS) }
2103
2124
  ]);
2104
- var datalistContract = contract([
2125
+ var datalistContract = closedContract([
2105
2126
  { name: "option", match: isTag("option", ...METADATA_TAGS) }
2106
2127
  ]);
2107
- var pictureContract = contract([
2128
+ var pictureContract = closedContract([
2108
2129
  { name: "source", match: isTag("source", ...METADATA_TAGS) },
2109
2130
  { name: "image", match: isTag("img"), cardinality: { min: 1, max: 1 }, position: "last" }
2110
2131
  ]);
@@ -2120,23 +2141,18 @@ var mediaContract = contract([
2120
2141
  metadata(),
2121
2142
  { name: "content", match: isOpenContent("source", "track", ...METADATA_TAGS) }
2122
2143
  ]);
2123
- var headContract = contract([
2144
+ var headContract = closedContract([
2124
2145
  {
2125
2146
  name: "metadata",
2126
2147
  match: isTag("base", "link", "meta", "noscript", "script", "style", "template", "title")
2127
2148
  }
2128
2149
  ]);
2129
- var htmlContract = contract([
2150
+ var htmlContract = closedContract([
2130
2151
  { name: "head", match: isTag("head"), cardinality: { min: 1, max: 1 }, position: "first" },
2131
2152
  { name: "body", match: isTag("body"), cardinality: { min: 1, max: 1 } }
2132
2153
  ]);
2133
- var voidContract = contract([]);
2134
- var textOnlyContract = contract([
2135
- {
2136
- name: "text",
2137
- match: (child) => isString(child) || isNumber(child)
2138
- }
2139
- ]);
2154
+ var voidContract = contract([], { exclusiveChildren: true, allowText: false });
2155
+ var textOnlyContract = contract([], { exclusiveChildren: true });
2140
2156
  var landmarkContract = ariaContract([landmarkRoleRule, landmarkNameAdvisory]);
2141
2157
  var dialogContract = ariaContract([requireAccessibleName]);
2142
2158
  var menuContract = ariaContract([requireAccessibleName]);
@@ -2181,9 +2197,15 @@ var htmlContracts = {
2181
2197
  var htmlDiagnostics = warnDiagnostics2;
2182
2198
  function buildEvaluatorMap() {
2183
2199
  const map2 = /* @__PURE__ */ new Map();
2184
- iterate.forEachEntry(htmlContracts, (tag, { children }) => {
2185
- if (children?.length) {
2186
- map2.set(tag, new ChildrenEvaluator(children, htmlDiagnostics, `<${tag}>`));
2200
+ iterate.forEachEntry(htmlContracts, (tag, { children, exclusiveChildren, allowText }) => {
2201
+ if (children?.length || exclusiveChildren || allowText === false) {
2202
+ map2.set(
2203
+ tag,
2204
+ new ChildrenEvaluator(children ?? [], htmlDiagnostics, `<${tag}>`, {
2205
+ exclusiveChildren,
2206
+ allowText
2207
+ })
2208
+ );
2187
2209
  }
2188
2210
  });
2189
2211
  return map2;
@@ -2394,7 +2416,7 @@ function definePipeline(factory) {
2394
2416
  }
2395
2417
 
2396
2418
  // ../core/src/options/resolve-factory-options.ts
2397
- import { silentDiagnostics } from "../_shared/diagnostics.js";
2419
+ import { resolveDiagnostics, silentDiagnostics } from "../_shared/diagnostics.js";
2398
2420
  var EMPTY_VARIANT_KEYS = /* @__PURE__ */ new Set();
2399
2421
  function composeNormalizers(normalizers, fn) {
2400
2422
  if (!normalizers?.length) return fn;
@@ -2415,7 +2437,7 @@ function resolveFactoryOptions(options = {}) {
2415
2437
  const variantKeys = styling?.variants === void 0 ? EMPTY_VARIANT_KEYS : new Set(Object.keys(styling.variants));
2416
2438
  return Object.freeze({
2417
2439
  defaultTag: options.tag ?? "div",
2418
- diagnostics: enforcement?.diagnostics ?? silentDiagnostics,
2440
+ diagnostics: resolveDiagnostics(enforcement?.diagnostics, silentDiagnostics),
2419
2441
  variantKeys,
2420
2442
  ...whenDefined("displayName", options.name),
2421
2443
  ...whenDefined("defaultProps", options.defaults),
@@ -2428,6 +2450,8 @@ function resolveFactoryOptions(options = {}) {
2428
2450
  ...whenDefined("normalizeFn", composedNormalizeFn),
2429
2451
  ...whenDefined("ariaRules", enforcement?.aria),
2430
2452
  ...whenDefined("childRules", enforcement?.children),
2453
+ ...whenDefined("exclusiveChildren", enforcement?.exclusiveChildren),
2454
+ ...whenDefined("allowText", enforcement?.allowText),
2431
2455
  ...whenDefined("allowedAs", enforcement?.allowedAs),
2432
2456
  ...whenDefined("precomputedClasses", styling?.precomputedClasses)
2433
2457
  });
@@ -2612,16 +2636,22 @@ function buildCoreRuntime(normalized) {
2612
2636
  }
2613
2637
 
2614
2638
  // ../../lib/adapter-utils/src/runtime/build-engines.ts
2615
- function buildEngines(diagnostics, childRules, context) {
2616
- return childRules?.length ? { childrenEvaluator: new ChildrenEvaluator(childRules, diagnostics, context) } : {};
2639
+ function buildEngines(diagnostics, childRules, context, childrenOptions) {
2640
+ const { exclusiveChildren, allowText } = childrenOptions ?? {};
2641
+ return childRules?.length || exclusiveChildren || allowText === false ? {
2642
+ childrenEvaluator: new ChildrenEvaluator(childRules ?? [], diagnostics, context, {
2643
+ exclusiveChildren,
2644
+ allowText
2645
+ })
2646
+ } : {};
2617
2647
  }
2618
2648
 
2619
2649
  // ../../lib/adapter-utils/src/runtime/resolve-adapter-common-options.ts
2620
- import { throwDiagnostics as throwDiagnostics2, silentDiagnostics as silentDiagnostics3 } from "../_shared/diagnostics.js";
2650
+ import { throwDiagnostics as throwDiagnostics2, silentDiagnostics as silentDiagnostics3, resolveDiagnostics as resolveDiagnostics2 } from "../_shared/diagnostics.js";
2621
2651
  function resolveAdapterCommonOptions(options, defaultName = "PolymorphicComponent", defaultDiagnostics = throwDiagnostics2) {
2622
2652
  return {
2623
2653
  name: options.name ?? defaultName,
2624
- diagnostics: options.enforcement?.diagnostics ?? defaultDiagnostics
2654
+ diagnostics: resolveDiagnostics2(options.enforcement?.diagnostics, defaultDiagnostics)
2625
2655
  };
2626
2656
  }
2627
2657
 
@@ -2944,7 +2974,10 @@ function buildRuntime(options) {
2944
2974
  const normalized = normalizeOptions(options);
2945
2975
  const { runtime, ownedKeys } = buildCoreRuntime(normalized);
2946
2976
  const { diagnostics, enforcement, filterProps: userFilter, name, slotComponent } = normalized;
2947
- const { childrenEvaluator } = buildEngines(diagnostics, enforcement?.children, name);
2977
+ const { childrenEvaluator } = buildEngines(diagnostics, enforcement?.children, name, {
2978
+ exclusiveChildren: enforcement?.exclusiveChildren,
2979
+ allowText: enforcement?.allowText
2980
+ });
2948
2981
  const filterProps = composeFilter(ownedKeys, userFilter);
2949
2982
  const slotValidator = new SlotValidator(name, diagnostics, "Preact element");
2950
2983
  const built = {
@@ -1,5 +1,5 @@
1
- import { U as UnknownProps, E as ElementType, a as EmptyRecord, V as VariantMap, R as RecipeMap, A as AnyClassPluginFactory, b as ReactFactoryOptions, P as PolymorphicComponent, c as PolymorphicGenerics, d as ExtractPluginProps } from '../react-options-XrRof248.js';
2
- export { e as AnyFactoryOptions, f as ElementRef, F as FactoryOptions, g as PolymorphicProps, h as PolymorphicWithAsChild, i as PolymorphicWithRender, j as RenderCallbackProps, S as Slottable, k as SlottableProps, m as composeRefs, l as defineContractComponent, m as mergeRefs } from '../react-options-XrRof248.js';
1
+ import { U as UnknownProps, E as ElementType, a as EmptyRecord, V as VariantMap, R as RecipeMap, A as AnyClassPluginFactory, b as ReactFactoryOptions, P as PolymorphicComponent, c as PolymorphicGenerics, d as ExtractPluginProps } from '../react-options-D6rRB2gJ.js';
2
+ export { e as AnyFactoryOptions, f as ElementRef, F as FactoryOptions, g as PolymorphicProps, h as PolymorphicWithAsChild, i as PolymorphicWithRender, j as RenderCallbackProps, S as Slottable, k as SlottableProps, m as composeRefs, l as defineContractComponent, m as mergeRefs } from '../react-options-D6rRB2gJ.js';
3
3
  import * as react from 'react';
4
4
  import { ReactElement, Ref } from 'react';
5
5
  import 'type-fest';
@@ -12,7 +12,7 @@ import {
12
12
  makeCloneSlotChild,
13
13
  mergeRefs,
14
14
  render
15
- } from "../chunk-R2RKHZNX.js";
15
+ } from "../chunk-SKAY22CZ.js";
16
16
 
17
17
  // ../../adapters/react/src/current/slot/composeRefs.ts
18
18
  function getChildRef(element) {
@@ -1,5 +1,5 @@
1
- import { E as ElementType, U as UnknownProps, a as EmptyRecord, V as VariantMap, R as RecipeMap, A as AnyClassPluginFactory, b as ReactFactoryOptions, P as PolymorphicComponent, c as PolymorphicGenerics, d as ExtractPluginProps } from '../react-options-XrRof248.js';
2
- export { e as AnyFactoryOptions, f as ElementRef, F as FactoryOptions, g as PolymorphicProps, h as PolymorphicWithAsChild, i as PolymorphicWithRender, j as RenderCallbackProps, S as Slottable, k as SlottableProps, l as defineContractComponent, m as mergeRefs } from '../react-options-XrRof248.js';
1
+ import { E as ElementType, U as UnknownProps, a as EmptyRecord, V as VariantMap, R as RecipeMap, A as AnyClassPluginFactory, b as ReactFactoryOptions, P as PolymorphicComponent, c as PolymorphicGenerics, d as ExtractPluginProps } from '../react-options-D6rRB2gJ.js';
2
+ export { e as AnyFactoryOptions, f as ElementRef, F as FactoryOptions, g as PolymorphicProps, h as PolymorphicWithAsChild, i as PolymorphicWithRender, j as RenderCallbackProps, S as Slottable, k as SlottableProps, l as defineContractComponent, m as mergeRefs } from '../react-options-D6rRB2gJ.js';
3
3
  import * as react from 'react';
4
4
  import 'type-fest';
5
5
  import '../_shared/diagnostics.js';
@@ -13,7 +13,7 @@ import {
13
13
  makeCloneSlotChild,
14
14
  mergeRefs,
15
15
  render
16
- } from "../chunk-R2RKHZNX.js";
16
+ } from "../chunk-SKAY22CZ.js";
17
17
 
18
18
  // ../../adapters/react/src/legacy/create-contract-component.ts
19
19
  import { forwardRef as forwardRef2 } from "react";
@@ -1,6 +1,6 @@
1
1
  import { Ref, PropsWithChildren, ReactElement, ComponentType, JSX, ReactNode } from 'react';
2
2
  import { RequireAtLeastOne, Simplify, ReadonlyDeep, NonEmptyTuple } from 'type-fest';
3
- import { Diagnostics, DiagnosticInput } from './_shared/diagnostics.js';
3
+ import { Diagnostics, DiagnosticInput, DiagnosticsMode } from './_shared/diagnostics.js';
4
4
 
5
5
  type StringMap<T = unknown> = Record<string, T>;
6
6
  type AnyRecord = StringMap<unknown>;
@@ -214,9 +214,25 @@ type AriaRule<C extends AriaContext = AriaContext> = (context: C) => readonly Ar
214
214
  type PropNormalizer = (props: Readonly<AnyRecord & IntrinsicProps>) => Partial<AnyRecord & IntrinsicProps>;
215
215
 
216
216
  type EnforcementOptions<TAllowed extends ElementType = ElementType> = {
217
- readonly diagnostics?: Diagnostics;
217
+ /**
218
+ * Accepts a preset name (`'warn'`, `'throw'`, `'silent'`) or a full `Diagnostics`
219
+ * instance for custom reporting/policy. The string form needs no import from
220
+ * `@praxis-kit/diagnostics`.
221
+ */
222
+ readonly diagnostics?: Diagnostics | DiagnosticsMode;
218
223
  readonly aria?: readonly AriaRule[];
219
224
  readonly children?: readonly ChildRuleInput[];
225
+ /**
226
+ * When true, only children matching a `children` rule (or text, per `allowText`)
227
+ * are valid — anything else is rejected. Default: false (open — children not
228
+ * matching any rule are allowed).
229
+ */
230
+ readonly exclusiveChildren?: boolean;
231
+ /**
232
+ * When false, text/number child nodes are rejected regardless of exclusiveChildren
233
+ * or any listed rule. Default: true.
234
+ */
235
+ readonly allowText?: boolean;
220
236
  readonly props?: readonly PropNormalizer[];
221
237
  /** Restricts the `as` prop to this set of tags. Violations route through diagnostics. */
222
238
  readonly allowedAs?: readonly TAllowed[];
@@ -1,5 +1,5 @@
1
1
  import { RequireAtLeastOne, Simplify, ReadonlyDeep, OmitIndexSignature } from 'type-fest';
2
- import { Diagnostics, DiagnosticInput } from '../_shared/diagnostics.js';
2
+ import { Diagnostics, DiagnosticInput, DiagnosticsMode } from '../_shared/diagnostics.js';
3
3
  import { JSX } from 'solid-js';
4
4
 
5
5
  type StringMap<T = unknown> = Record<string, T>;
@@ -213,9 +213,25 @@ type AriaRule<C extends AriaContext = AriaContext> = (context: C) => readonly Ar
213
213
  type PropNormalizer = (props: Readonly<AnyRecord & IntrinsicProps>) => Partial<AnyRecord & IntrinsicProps>;
214
214
 
215
215
  type EnforcementOptions<TAllowed extends ElementType = ElementType> = {
216
- readonly diagnostics?: Diagnostics;
216
+ /**
217
+ * Accepts a preset name (`'warn'`, `'throw'`, `'silent'`) or a full `Diagnostics`
218
+ * instance for custom reporting/policy. The string form needs no import from
219
+ * `@praxis-kit/diagnostics`.
220
+ */
221
+ readonly diagnostics?: Diagnostics | DiagnosticsMode;
217
222
  readonly aria?: readonly AriaRule[];
218
223
  readonly children?: readonly ChildRuleInput[];
224
+ /**
225
+ * When true, only children matching a `children` rule (or text, per `allowText`)
226
+ * are valid — anything else is rejected. Default: false (open — children not
227
+ * matching any rule are allowed).
228
+ */
229
+ readonly exclusiveChildren?: boolean;
230
+ /**
231
+ * When false, text/number child nodes are rejected regardless of exclusiveChildren
232
+ * or any listed rule. Default: true.
233
+ */
234
+ readonly allowText?: boolean;
219
235
  readonly props?: readonly PropNormalizer[];
220
236
  /** Restricts the `as` prop to this set of tags. Violations route through diagnostics. */
221
237
  readonly allowedAs?: readonly TAllowed[];