praxis-kit 7.0.0 → 7.4.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.
@@ -98,7 +98,13 @@ declare enum DiagnosticCode {
98
98
  InternalError = "INTERNAL9000"
99
99
  }
100
100
 
101
+ /**
102
+ * A string-keyed object whose values are of type `T`.
103
+ */
101
104
  type StringMap<T = unknown> = Record<string, T>;
105
+ /**
106
+ * A string-keyed object with values of unknown type.
107
+ */
102
108
  type AnyRecord = StringMap<unknown>;
103
109
 
104
110
  declare enum Severity {
@@ -3,6 +3,12 @@ function defineContractComponent(options) {
3
3
  return (factory) => factory(options);
4
4
  }
5
5
 
6
+ // ../../lib/adapter-utils/src/runtime/assemble-compound-component.ts
7
+ function assembleCompoundComponent(root, subComponents) {
8
+ if (!subComponents) return root;
9
+ return Object.assign(root, subComponents);
10
+ }
11
+
6
12
  // ../../lib/primitive/src/tag/resolve-tag.ts
7
13
  function makeResolveTag(defaultTag) {
8
14
  return function tag(as) {
@@ -59,7 +65,7 @@ function isPlainObject(value) {
59
65
 
60
66
  // ../../lib/primitive/src/rule/is-dynamic-rule.ts
61
67
  function isDynamicRule(rule) {
62
- return isObject(rule, true) && rule[RULE_BRAND] === true;
68
+ return isObject(rule, true) && Reflect.get(rule, RULE_BRAND) === true;
63
69
  }
64
70
 
65
71
  // ../../lib/primitive/src/rule/resolve-rule.ts
@@ -722,17 +728,17 @@ var COMPONENT_DEFAULT_TAG = /* @__PURE__ */ Symbol.for("praxis.component-default
722
728
  // ../../lib/primitive/src/guards/children/is-tag.ts
723
729
  function getAsProp(child) {
724
730
  if (!isObject(child) || !("props" in child)) return void 0;
725
- const props = child.props;
731
+ const { props } = child;
726
732
  if (!isObject(props)) return void 0;
727
- const as = props.as;
733
+ const as = Reflect.get(props, "as");
728
734
  return isString(as) && as !== "" ? as : void 0;
729
735
  }
730
736
  function getTag(child) {
731
737
  if (!isObject(child) || !("type" in child)) return void 0;
732
- const t = child.type;
738
+ const { type: t } = child;
733
739
  if (isString(t)) return t;
734
740
  if (typeof t === "function" || isObject(t)) {
735
- const defaultTag = t[COMPONENT_DEFAULT_TAG];
741
+ const defaultTag = Reflect.get(t, COMPONENT_DEFAULT_TAG);
736
742
  if (!isString(defaultTag)) return void 0;
737
743
  return getAsProp(child) ?? defaultTag;
738
744
  }
@@ -752,6 +758,36 @@ function isTag(...args) {
752
758
  return tag !== void 0 && set2.has(tag);
753
759
  }
754
760
 
761
+ // ../../lib/adapter-utils/src/runtime/finalize-component.ts
762
+ function finalizeComponent(component, defaultTag, subComponents) {
763
+ if (typeof defaultTag === "string") {
764
+ Object.assign(component, { [COMPONENT_DEFAULT_TAG]: defaultTag });
765
+ }
766
+ return assembleCompoundComponent(component, subComponents);
767
+ }
768
+
769
+ // ../../lib/adapter-utils/src/runtime/is-factory-options-like.ts
770
+ var FACTORY_OPTIONS_FIELD_VALIDATORS = {
771
+ tag: (v) => v === void 0 || isString(v),
772
+ name: (v) => v === void 0 || isString(v),
773
+ defaults: (v) => v === void 0 || isObject(v),
774
+ normalize: (v) => v === void 0 || isFunction(v),
775
+ styling: (v) => v === void 0 || isObject(v),
776
+ enforcement: (v) => v === void 0 || isObject(v),
777
+ diagnostics: (v) => v === void 0 || isObject(v),
778
+ subComponents: (v) => v === void 0 || isObject(v),
779
+ onElement: (v) => v === void 0 || isFunction(v)
780
+ };
781
+ function isFactoryOptionsLike(options, extraFieldValidators) {
782
+ if (!isObject(options)) return false;
783
+ const validators = { ...FACTORY_OPTIONS_FIELD_VALIDATORS, ...extraFieldValidators };
784
+ for (const [key, value] of Object.entries(options)) {
785
+ const validate = validators[key];
786
+ if (!validate || !validate(value)) return false;
787
+ }
788
+ return true;
789
+ }
790
+
755
791
  // ../../lib/contract/src/aria/aria-role-policy.ts
756
792
  function getImplicitRole(tag, props) {
757
793
  if (tag in IMPLICIT_ROLE_RECORD) return IMPLICIT_ROLE_RECORD[tag];
@@ -2902,7 +2938,7 @@ function getChildProp(child, key) {
2902
2938
  if (!isVNodeLike(child)) return void 0;
2903
2939
  const { props } = child;
2904
2940
  if (!isObject(props)) return void 0;
2905
- return props[key];
2941
+ return Reflect.get(props, key);
2906
2942
  }
2907
2943
 
2908
2944
  // ../core/src/html/contracts/aria/landmarks.ts
@@ -3725,6 +3761,23 @@ function applySlot(children, slotProps, ref, cloneSlotChild) {
3725
3761
  return cloneSlotChild({ child: children, slotProps, ref });
3726
3762
  }
3727
3763
 
3764
+ // ../../adapters/react/src/shared/to-react-factory-options.ts
3765
+ var REACT_FIELD_VALIDATORS = {
3766
+ slotComponent: (v) => v === void 0 || isFunction(v) || isObject(v),
3767
+ filterProps: (v) => v === void 0 || isFunction(v),
3768
+ artifact: (v) => v === void 0 || isObject(v)
3769
+ };
3770
+ function isReactFactoryOptions(options) {
3771
+ return isFactoryOptionsLike(options, REACT_FIELD_VALIDATORS);
3772
+ }
3773
+
3774
+ // ../../adapters/react/src/shared/is-polymorphic-component.ts
3775
+ function isPolymorphicComponent(value) {
3776
+ if (!isFunction(value)) return false;
3777
+ if (!("displayName" in value)) return true;
3778
+ return value.displayName === void 0 || isString(value.displayName);
3779
+ }
3780
+
3728
3781
  // ../../adapters/react/src/shared/apply-display-name.ts
3729
3782
  function applyDisplayName(component, name) {
3730
3783
  const displayName = name ?? "PolymorphicComponent";
@@ -3901,10 +3954,14 @@ function buildRuntime(options, defaultSlotComponent, normalizeChildren) {
3901
3954
  }
3902
3955
 
3903
3956
  export {
3957
+ invariant,
3904
3958
  defineContractComponent,
3905
3959
  isString,
3906
3960
  SLOT_NAME,
3907
3961
  COMPONENT_DEFAULT_TAG,
3962
+ finalizeComponent,
3963
+ isReactFactoryOptions,
3964
+ isPolymorphicComponent,
3908
3965
  mergeRefs,
3909
3966
  applyDisplayName,
3910
3967
  Slottable,
@@ -211608,12 +211608,12 @@ var require_commonjs = __commonJS({
211608
211608
  }
211609
211609
  });
211610
211610
 
211611
- // ../../node_modules/.pnpm/brace-expansion@5.0.7/node_modules/brace-expansion/dist/commonjs/index.js
211611
+ // ../../node_modules/.pnpm/brace-expansion@5.0.9/node_modules/brace-expansion/dist/commonjs/index.js
211612
211612
  var require_commonjs2 = __commonJS({
211613
- "../../node_modules/.pnpm/brace-expansion@5.0.7/node_modules/brace-expansion/dist/commonjs/index.js"(exports) {
211613
+ "../../node_modules/.pnpm/brace-expansion@5.0.9/node_modules/brace-expansion/dist/commonjs/index.js"(exports) {
211614
211614
  "use strict";
211615
211615
  Object.defineProperty(exports, "__esModule", { value: true });
211616
- exports.EXPANSION_MAX = void 0;
211616
+ exports.EXPANSION_MAX_LENGTH = exports.EXPANSION_MAX = void 0;
211617
211617
  exports.expand = expand;
211618
211618
  var balanced_match_1 = require_commonjs();
211619
211619
  var escSlash = "\0SLASH" + Math.random() + "\0";
@@ -211632,6 +211632,7 @@ var require_commonjs2 = __commonJS({
211632
211632
  var commaPattern = /\\,/g;
211633
211633
  var periodPattern = /\\\./g;
211634
211634
  exports.EXPANSION_MAX = 1e5;
211635
+ exports.EXPANSION_MAX_LENGTH = 4e6;
211635
211636
  function numeric(str) {
211636
211637
  return !isNaN(str) ? parseInt(str, 10) : str.charCodeAt(0);
211637
211638
  }
@@ -211666,11 +211667,11 @@ var require_commonjs2 = __commonJS({
211666
211667
  if (!str) {
211667
211668
  return [];
211668
211669
  }
211669
- const { max = exports.EXPANSION_MAX } = options;
211670
+ const { max = exports.EXPANSION_MAX, maxLength = exports.EXPANSION_MAX_LENGTH } = options;
211670
211671
  if (str.slice(0, 2) === "{}") {
211671
211672
  str = "\\{\\}" + str.slice(2);
211672
211673
  }
211673
- return expand_(escapeBraces(str), max, true).map(unescapeBraces);
211674
+ return expand_(escapeBraces(str), max, maxLength, true).map(unescapeBraces);
211674
211675
  }
211675
211676
  function embrace(str) {
211676
211677
  return "{" + str + "}";
@@ -211684,20 +211685,87 @@ var require_commonjs2 = __commonJS({
211684
211685
  function gte(i, y) {
211685
211686
  return i >= y;
211686
211687
  }
211687
- function expand_(str, max, isTop) {
211688
- const expansions = [];
211688
+ function combine(acc, pre, values, max, maxLength, dropEmpties) {
211689
+ const out = [];
211690
+ let length = 0;
211691
+ for (let a = 0; a < acc.length; a++) {
211692
+ for (let v = 0; v < values.length; v++) {
211693
+ if (out.length >= max)
211694
+ return out;
211695
+ const expansion = acc[a] + pre + values[v];
211696
+ if (dropEmpties && !expansion)
211697
+ continue;
211698
+ if (length + expansion.length > maxLength)
211699
+ return out;
211700
+ out.push(expansion);
211701
+ length += expansion.length;
211702
+ }
211703
+ }
211704
+ return out;
211705
+ }
211706
+ function expandSequence(body, isAlphaSequence, max, maxLength) {
211707
+ const n = body.split(/\.\./);
211708
+ const N = [];
211709
+ if (n[0] === void 0 || n[1] === void 0) {
211710
+ return N;
211711
+ }
211712
+ const x = numeric(n[0]);
211713
+ const y = numeric(n[1]);
211714
+ const width = Math.max(n[0].length, n[1].length);
211715
+ let incr = n.length === 3 && n[2] !== void 0 ? Math.max(Math.abs(numeric(n[2])), 1) : 1;
211716
+ let test = lte;
211717
+ const reverse = y < x;
211718
+ if (reverse) {
211719
+ incr *= -1;
211720
+ test = gte;
211721
+ }
211722
+ const pad = n.some(isPadded);
211723
+ let length = 0;
211724
+ for (let i = x; test(i, y) && N.length < max; i += incr) {
211725
+ let c;
211726
+ if (isAlphaSequence) {
211727
+ c = String.fromCharCode(i);
211728
+ if (c === "\\") {
211729
+ c = "";
211730
+ }
211731
+ } else {
211732
+ c = String(i);
211733
+ if (pad) {
211734
+ const need = width - c.length;
211735
+ if (need > 0) {
211736
+ const z = new Array(need + 1).join("0");
211737
+ if (i < 0) {
211738
+ c = "-" + z + c.slice(1);
211739
+ } else {
211740
+ c = z + c;
211741
+ }
211742
+ }
211743
+ }
211744
+ }
211745
+ if (length + c.length > maxLength)
211746
+ break;
211747
+ N.push(c);
211748
+ length += c.length;
211749
+ }
211750
+ return N;
211751
+ }
211752
+ function expand_(str, max, maxLength, isTop) {
211753
+ let acc = [""];
211754
+ let dropEmpties = false;
211755
+ let firstGroup = true;
211689
211756
  for (; ; ) {
211690
211757
  const m = (0, balanced_match_1.balanced)("{", "}", str);
211691
- if (!m)
211692
- return [str];
211758
+ if (!m) {
211759
+ return combine(acc, str, [""], max, maxLength, dropEmpties);
211760
+ }
211693
211761
  const pre = m.pre;
211694
- if (/\$$/.test(m.pre)) {
211695
- const post2 = m.post.length ? expand_(m.post, max, false) : [""];
211696
- for (let k = 0; k < post2.length && k < max; k++) {
211697
- const expansion = pre + "{" + m.body + "}" + post2[k];
211698
- expansions.push(expansion);
211699
- }
211700
- return expansions;
211762
+ if (/\$$/.test(pre)) {
211763
+ acc = combine(acc, pre + "{" + m.body + "}", [""], max, maxLength, dropEmpties && !m.post.length);
211764
+ firstGroup = false;
211765
+ if (!m.post.length)
211766
+ break;
211767
+ str = m.post;
211768
+ continue;
211701
211769
  }
211702
211770
  const isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body);
211703
211771
  const isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body);
@@ -211709,74 +211777,55 @@ var require_commonjs2 = __commonJS({
211709
211777
  isTop = true;
211710
211778
  continue;
211711
211779
  }
211712
- return [str];
211780
+ return combine(acc, pre + "{" + m.body + "}" + m.post, [""], max, maxLength, dropEmpties);
211713
211781
  }
211714
- const post = m.post.length ? expand_(m.post, max, false) : [""];
211715
- let n;
211782
+ if (firstGroup) {
211783
+ dropEmpties = isTop && !isSequence;
211784
+ firstGroup = false;
211785
+ }
211786
+ let values;
211716
211787
  if (isSequence) {
211717
- n = m.body.split(/\.\./);
211788
+ values = expandSequence(m.body, isAlphaSequence, max, maxLength);
211718
211789
  } else {
211719
- n = parseCommaParts(m.body);
211790
+ let n = parseCommaParts(m.body);
211720
211791
  if (n.length === 1 && n[0] !== void 0) {
211721
- n = expand_(n[0], max, false).map(embrace);
211792
+ n = expand_(n[0], max, maxLength, false).map(embrace);
211722
211793
  if (n.length === 1) {
211723
- return post.map((p) => m.pre + n[0] + p);
211724
- }
211725
- }
211726
- }
211727
- let N;
211728
- if (isSequence && n[0] !== void 0 && n[1] !== void 0) {
211729
- const x = numeric(n[0]);
211730
- const y = numeric(n[1]);
211731
- const width = Math.max(n[0].length, n[1].length);
211732
- let incr = n.length === 3 && n[2] !== void 0 ? Math.max(Math.abs(numeric(n[2])), 1) : 1;
211733
- let test = lte;
211734
- const reverse = y < x;
211735
- if (reverse) {
211736
- incr *= -1;
211737
- test = gte;
211738
- }
211739
- const pad = n.some(isPadded);
211740
- N = [];
211741
- for (let i = x; test(i, y) && N.length < max; i += incr) {
211742
- let c;
211743
- if (isAlphaSequence) {
211744
- c = String.fromCharCode(i);
211745
- if (c === "\\") {
211746
- c = "";
211747
- }
211748
- } else {
211749
- c = String(i);
211750
- if (pad) {
211751
- const need = width - c.length;
211752
- if (need > 0) {
211753
- const z = new Array(need + 1).join("0");
211754
- if (i < 0) {
211755
- c = "-" + z + c.slice(1);
211756
- } else {
211757
- c = z + c;
211758
- }
211759
- }
211760
- }
211794
+ acc = combine(acc, pre + n[0], [""], max, maxLength, dropEmpties && !m.post.length);
211795
+ if (!m.post.length)
211796
+ break;
211797
+ str = m.post;
211798
+ continue;
211761
211799
  }
211762
- N.push(c);
211763
211800
  }
211764
- } else {
211765
- N = [];
211766
- for (let j = 0; j < n.length; j++) {
211767
- N.push.apply(N, expand_(n[j], max, false));
211801
+ let dropsEmpties = dropEmpties && !m.post.length && !pre;
211802
+ for (let d = 0; dropsEmpties && d < acc.length; d++) {
211803
+ if (acc[d]) {
211804
+ dropsEmpties = false;
211805
+ }
211768
211806
  }
211769
- }
211770
- for (let j = 0; j < N.length; j++) {
211771
- for (let k = 0; k < post.length && expansions.length < max; k++) {
211772
- const expansion = pre + N[j] + post[k];
211773
- if (!isTop || isSequence || expansion) {
211774
- expansions.push(expansion);
211807
+ values = [];
211808
+ let valuesLength = 0;
211809
+ outer: for (let j = 0; j < n.length; j++) {
211810
+ const expanded = expand_(n[j], max, maxLength, false);
211811
+ for (let k = 0; k < expanded.length; k++) {
211812
+ const v = expanded[k];
211813
+ if (dropsEmpties && !v)
211814
+ continue;
211815
+ if (values.length >= max || valuesLength + v.length > maxLength) {
211816
+ break outer;
211817
+ }
211818
+ values.push(v);
211819
+ valuesLength += v.length;
211775
211820
  }
211776
211821
  }
211777
211822
  }
211778
- return expansions;
211823
+ acc = combine(acc, pre, values, max, maxLength, dropEmpties && !m.post.length);
211824
+ if (!m.post.length)
211825
+ break;
211826
+ str = m.post;
211779
211827
  }
211828
+ return acc;
211780
211829
  }
211781
211830
  }
211782
211831
  });
@@ -1,9 +1,26 @@
1
1
  import { Diagnostics as Diagnostics$1, DiagnosticInput, DiagnosticsMode } from '../_shared/diagnostics.js';
2
2
  import { RequireAtLeastOne, Simplify, ReadonlyDeep } from 'type-fest';
3
3
 
4
+ /**
5
+ * A string-keyed object whose values are of type `T`.
6
+ */
4
7
  type StringMap<T = unknown> = Record<string, T>;
8
+ /**
9
+ * A string-keyed object with values of unknown type.
10
+ */
5
11
  type AnyRecord = StringMap<unknown>;
12
+ /**
13
+ * An object type with no named properties.
14
+ *
15
+ * Unlike `{}`, this excludes arbitrary properties during type operations while
16
+ * still satisfying `extends object`.
17
+ */
6
18
  type EmptyRecord = Record<never, never>;
19
+ /**
20
+ * A compound component's named sub-components, for example
21
+ * `{ Header, Content, Footer }`.
22
+ */
23
+ type SubComponentMap = Readonly<AnyRecord>;
7
24
 
8
25
  type IntrinsicTag = keyof HTMLElementTagNameMap;
9
26
 
@@ -233,6 +250,12 @@ type EnforcementOptions<TAllowed extends ElementType = ElementType> = {
233
250
  * `@praxis-kit/diagnostics`.
234
251
  */
235
252
  readonly diagnostics?: Diagnostics$1 | DiagnosticsMode;
253
+ /**
254
+ * ARIA/accessibility rules evaluated against the resolved tag and props on every render.
255
+ * Each rule is a function receiving the current context and returning zero or more
256
+ * violations, some of which can carry an auto-applicable fix (see `createRemoveAttributeRule`
257
+ * and friends in `praxis-kit/contract`).
258
+ */
236
259
  readonly aria?: readonly AriaRule[];
237
260
  /**
238
261
  * Rules that need `AriaPolicyEngine`'s fix-application/caching machinery
@@ -244,6 +267,11 @@ type EnforcementOptions<TAllowed extends ElementType = ElementType> = {
244
267
  * misleading `aria` name to get the machinery it needs.
245
268
  */
246
269
  readonly rules?: readonly AriaRule[];
270
+ /**
271
+ * Declares which children are valid, by name, match predicate, and cardinality (e.g. "at
272
+ * least 1, at most 4 `Button` children"). Open by default — children matching no rule are
273
+ * still allowed unless `exclusiveChildren` is set.
274
+ */
247
275
  readonly children?: readonly ChildRuleInput[];
248
276
  /**
249
277
  * When true, only children matching a `children` rule (or text, per `allowText`)
@@ -256,19 +284,49 @@ type EnforcementOptions<TAllowed extends ElementType = ElementType> = {
256
284
  * or any listed rule. Default: true.
257
285
  */
258
286
  readonly allowText?: boolean;
287
+ /**
288
+ * Prop transforms composed with the component's own `normalize` (from `FactoryOptions`) and
289
+ * run before it. Unlike `normalize`, these live in the enforcement bucket because they
290
+ * typically encode a built-in HTML/ARIA fact rather than component-specific behavior.
291
+ */
259
292
  readonly props?: readonly PropNormalizer[];
260
293
  /** Restricts the `as` prop to this set of tags. Violations route through diagnostics. */
261
294
  readonly allowedAs?: readonly TAllowed[];
262
295
  };
263
296
 
264
297
  type StylingOptions<V extends Readonly<VariantMap> = Readonly<EmptyRecord>, TPreset extends RecipeMap<V> = Readonly<EmptyRecord>, TPlugin extends AnyClassPluginFactory = AnyClassPluginFactory> = {
298
+ /** Class applied to every instance regardless of variant selection. */
265
299
  readonly base?: ClassName;
300
+ /**
301
+ * Named variant groups (e.g. `intent`, `size`), each mapping its possible values to a
302
+ * class string. A consumer selects a value per group as a prop (`<Button intent="primary">`).
303
+ */
266
304
  readonly variants?: V;
305
+ /** Value used for a variant group when the consumer doesn't pass one explicitly. */
267
306
  readonly defaults?: Partial<DefaultVariants<V>>;
307
+ /**
308
+ * Applies an extra class only when a specific *combination* of variant selections matches —
309
+ * for cases `variants` alone can't express (e.g. `intent: 'primary'` + `size: 'lg'` together
310
+ * need a class neither variant would add on its own).
311
+ */
268
312
  readonly compounds?: readonly CompoundVariant<V>[];
313
+ /**
314
+ * Named bundles of variant values, selectable as a single unit via the `recipe` prop (e.g.
315
+ * `<Button recipe="cta">` instead of setting `intent`/`size` individually).
316
+ */
269
317
  readonly presets?: TPreset;
318
+ /** Maps a resolved tag directly to a raw class string, independent of the variant system. */
270
319
  readonly tags?: Readonly<TagMap>;
320
+ /**
321
+ * A `ClassPluginFactory` (e.g. the Tailwind layout pipeline) that extends class resolution
322
+ * with its own owned props, layered on top of `variants`/`presets`/`tags`.
323
+ */
271
324
  readonly plugin?: TPlugin;
325
+ /**
326
+ * A cache-key → resolved-class-string lookup for every statically-known variant
327
+ * combination, skipping runtime class computation entirely when a match is found. Normally
328
+ * generated by a build-time class-extraction plugin rather than hand-authored.
329
+ */
272
330
  readonly precomputedClasses?: Readonly<Record<string, string>>;
273
331
  };
274
332
 
@@ -277,17 +335,51 @@ type NormalizeFn<Props extends AnyRecord = AnyRecord> = {
277
335
  }['normalize'];
278
336
  type AnyFactoryOptions = FactoryOptions<ElementType, AnyRecord, VariantMap, RecipeMap<VariantMap>, AnyClassPluginFactory>;
279
337
  type FactoryOptions<TDefault extends ElementType = ElementType, Props extends AnyRecord = EmptyRecord, V extends Readonly<VariantMap> = Readonly<EmptyRecord>, TPreset extends RecipeMap<V> = Readonly<EmptyRecord>, TPlugin extends AnyClassPluginFactory = AnyClassPluginFactory, TAllowed extends ElementType = ElementType> = {
338
+ /** The intrinsic tag the component renders by default. Overridable per instance via `as`. */
280
339
  readonly tag?: TDefault;
340
+ /** Display name used in diagnostics, dev tools, and generated component naming. */
281
341
  readonly name?: string;
342
+ /** Values used for the component's own (non-variant) props when the consumer omits them. */
282
343
  readonly defaults?: Partial<NoInfer<Props>>;
344
+ /**
345
+ * A pure `(props) => props` transform run on every render, after `enforcement.props`'s
346
+ * normalizers see the same input. Use this for component-specific prop shaping — anything
347
+ * that depends on live instance state or the real DOM element belongs in `onElement` instead.
348
+ */
283
349
  readonly normalize?: NormalizeFn<NoInfer<Props>>;
350
+ /** Variant groups, base classes, presets, and the optional class-resolution plugin. */
284
351
  readonly styling?: StylingOptions<V, TPreset, TPlugin>;
352
+ /** ARIA rules, child-content contracts, and other runtime validation for this component. */
285
353
  readonly enforcement?: EnforcementOptions<TAllowed>;
286
354
  /**
287
355
  * Adapter-resolved diagnostics default, spread in by `resolveAdapterCommonOptions`. Not meant to
288
356
  * be set directly by component authors — use `enforcement.diagnostics` to override per component.
289
357
  */
290
358
  readonly diagnostics?: Diagnostics$1;
359
+ /**
360
+ * Sub-components to attach to the generated root component, producing a
361
+ * compound component API (for example, `Card.Header`, `Card.Content`,
362
+ * and `Card.Footer`). Purely additive — has no effect on
363
+ * `enforcement.children`; author child rules explicitly if the component
364
+ * needs to validate its children.
365
+ */
366
+ readonly subComponents?: SubComponentMap;
367
+ /**
368
+ * Called once per instance, when the real underlying DOM element first
369
+ * exists, in every adapter — via that adapter's own native mount
370
+ * lifecycle, never through the props/attribute pipeline. Use this for
371
+ * wiring that needs the actual element (native imperative methods like
372
+ * `dialogEl.showModal()`, native events like `close`/`cancel` that have
373
+ * no prop-based equivalent), not for anything expressible as a plain
374
+ * prop.
375
+ *
376
+ * `getProps` returns the instance's *current* resolved props at call
377
+ * time — read it from inside a listener registered once at mount, rather
378
+ * than re-subscribing on every prop change.
379
+ *
380
+ * Return a cleanup function to run when the instance unmounts.
381
+ */
382
+ readonly onElement?: (element: Element, getProps: () => Readonly<Props>) => void | (() => void);
291
383
  };
292
384
 
293
385
  /** Shared input shape for `invalidWithFix`/`invalidWithoutFix`. */
@@ -1,4 +1,10 @@
1
+ /**
2
+ * A string-keyed object whose values are of type `T`.
3
+ */
1
4
  type StringMap<T = unknown> = Record<string, T>;
5
+ /**
6
+ * A string-keyed object with values of unknown type.
7
+ */
2
8
  type AnyRecord = StringMap<unknown>;
3
9
 
4
10
  /**
@@ -41,17 +41,17 @@ function getComponentDefaultTag(component) {
41
41
  // ../../lib/primitive/src/guards/children/is-tag.ts
42
42
  function getAsProp(child) {
43
43
  if (!isObject(child) || !("props" in child)) return void 0;
44
- const props = child.props;
44
+ const { props } = child;
45
45
  if (!isObject(props)) return void 0;
46
- const as = props.as;
46
+ const as = Reflect.get(props, "as");
47
47
  return isString(as) && as !== "" ? as : void 0;
48
48
  }
49
49
  function getTag(child) {
50
50
  if (!isObject(child) || !("type" in child)) return void 0;
51
- const t = child.type;
51
+ const { type: t } = child;
52
52
  if (isString(t)) return t;
53
53
  if (typeof t === "function" || isObject(t)) {
54
- const defaultTag = t[COMPONENT_DEFAULT_TAG];
54
+ const defaultTag = Reflect.get(t, COMPONENT_DEFAULT_TAG);
55
55
  if (!isString(defaultTag)) return void 0;
56
56
  return getAsProp(child) ?? defaultTag;
57
57
  }
@@ -1,7 +1,13 @@
1
1
  import { ReadonlyDeep } from 'type-fest';
2
2
  import { DiagnosticInput } from '../_shared/diagnostics.js';
3
3
 
4
+ /**
5
+ * A string-keyed object whose values are of type `T`.
6
+ */
4
7
  type StringMap<T = unknown> = Record<string, T>;
8
+ /**
9
+ * A string-keyed object with values of unknown type.
10
+ */
5
11
  type AnyRecord = StringMap<unknown>;
6
12
 
7
13
  type IntrinsicTag = keyof HTMLElementTagNameMap;