praxis-kit 6.6.1 → 7.3.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/vue/index.js CHANGED
@@ -1,6 +1,30 @@
1
1
  // ../../adapters/vue/src/create-contract-component.ts
2
2
  import { computed, defineComponent as defineComponent2 } from "vue";
3
3
 
4
+ // ../../lib/adapter-utils/src/invariant.ts
5
+ function panic(message) {
6
+ throw new Error(message);
7
+ }
8
+ function invariant(condition, message) {
9
+ if (!condition) panic(message);
10
+ }
11
+
12
+ // ../../lib/adapter-utils/src/runtime/apply-display-name.ts
13
+ function applyDisplayName(component, name) {
14
+ Object.assign(component, { displayName: name ?? "PolymorphicComponent" });
15
+ }
16
+
17
+ // ../../lib/adapter-utils/src/runtime/define-component.ts
18
+ function defineContractComponent(options) {
19
+ return (factory) => factory(options);
20
+ }
21
+
22
+ // ../../lib/adapter-utils/src/runtime/assemble-compound-component.ts
23
+ function assembleCompoundComponent(root, subComponents) {
24
+ if (!subComponents) return root;
25
+ return Object.assign(root, subComponents);
26
+ }
27
+
4
28
  // ../../lib/primitive/src/tag/resolve-tag.ts
5
29
  function makeResolveTag(defaultTag) {
6
30
  return function tag(as) {
@@ -11,6 +35,11 @@ function makeResolveTag(defaultTag) {
11
35
  // ../../lib/primitive/src/rule/rule-brand.ts
12
36
  var RULE_BRAND = /* @__PURE__ */ Symbol("praxis-kit/dynamic-rule");
13
37
 
38
+ // ../../lib/primitive/src/rule/dynamic.ts
39
+ function dynamic(resolve) {
40
+ return { [RULE_BRAND]: true, resolve };
41
+ }
42
+
14
43
  // ../../lib/primitive/src/guards/foundational/is-defined.ts
15
44
  function isUndefined(value) {
16
45
  return value === void 0;
@@ -24,7 +53,7 @@ function isNonNull(value) {
24
53
  return value != null;
25
54
  }
26
55
  function isNullish(value) {
27
- return isNull(value) || value === void 0;
56
+ return isNull(value) || isUndefined(value);
28
57
  }
29
58
 
30
59
  // ../../lib/primitive/src/utils/type-guards.ts
@@ -38,10 +67,13 @@ function isString(value) {
38
67
  function isNumber(value) {
39
68
  return typeof value === "number";
40
69
  }
70
+ function isFunction(value) {
71
+ return typeof value === "function";
72
+ }
41
73
 
42
74
  // ../../lib/primitive/src/rule/is-dynamic-rule.ts
43
75
  function isDynamicRule(rule) {
44
- return isObject(rule, true) && rule[RULE_BRAND] === true;
76
+ return isObject(rule, true) && Reflect.get(rule, RULE_BRAND) === true;
45
77
  }
46
78
 
47
79
  // ../../lib/primitive/src/rule/resolve-rule.ts
@@ -601,6 +633,24 @@ var ROLE_RESTRICTED_ATTRIBUTES = /* @__PURE__ */ new Map([
601
633
  ]
602
634
  ]);
603
635
 
636
+ // ../../lib/primitive/src/constants/html/void-tags.ts
637
+ var VOID_TAGS = [
638
+ "area",
639
+ "base",
640
+ "br",
641
+ "col",
642
+ "embed",
643
+ "hr",
644
+ "img",
645
+ "input",
646
+ "link",
647
+ "meta",
648
+ "param",
649
+ "source",
650
+ "track",
651
+ "wbr"
652
+ ];
653
+
604
654
  // ../../lib/primitive/src/guards/aria/is-aria-attribute.ts
605
655
  function isGlobalAriaAttribute(attr) {
606
656
  return GLOBAL_ARIA_ATTRIBUTES.has(attr);
@@ -653,17 +703,17 @@ var COMPONENT_DEFAULT_TAG = /* @__PURE__ */ Symbol.for("praxis.component-default
653
703
  // ../../lib/primitive/src/guards/children/is-tag.ts
654
704
  function getAsProp(child) {
655
705
  if (!isObject(child) || !("props" in child)) return void 0;
656
- const props = child.props;
706
+ const { props } = child;
657
707
  if (!isObject(props)) return void 0;
658
- const as = props.as;
708
+ const as = Reflect.get(props, "as");
659
709
  return isString(as) && as !== "" ? as : void 0;
660
710
  }
661
711
  function getTag(child) {
662
712
  if (!isObject(child) || !("type" in child)) return void 0;
663
- const t = child.type;
713
+ const { type: t } = child;
664
714
  if (isString(t)) return t;
665
715
  if (typeof t === "function" || isObject(t)) {
666
- const defaultTag = t[COMPONENT_DEFAULT_TAG];
716
+ const defaultTag = Reflect.get(t, COMPONENT_DEFAULT_TAG);
667
717
  if (!isString(defaultTag)) return void 0;
668
718
  return getAsProp(child) ?? defaultTag;
669
719
  }
@@ -683,22 +733,34 @@ function isTag(...args) {
683
733
  return tag !== void 0 && set2.has(tag);
684
734
  }
685
735
 
686
- // ../../lib/adapter-utils/src/invariant.ts
687
- function panic(message) {
688
- throw new Error(message);
689
- }
690
- function invariant(condition, message) {
691
- if (!condition) panic(message);
692
- }
693
-
694
- // ../../lib/adapter-utils/src/runtime/apply-display-name.ts
695
- function applyDisplayName(component, name) {
696
- Object.assign(component, { displayName: name ?? "PolymorphicComponent" });
697
- }
698
-
699
- // ../../lib/adapter-utils/src/runtime/define-component.ts
700
- function defineContractComponent(options) {
701
- return (factory) => factory(options);
736
+ // ../../lib/adapter-utils/src/runtime/finalize-component.ts
737
+ function finalizeComponent(component, defaultTag, subComponents) {
738
+ if (typeof defaultTag === "string") {
739
+ Object.assign(component, { [COMPONENT_DEFAULT_TAG]: defaultTag });
740
+ }
741
+ return assembleCompoundComponent(component, subComponents);
742
+ }
743
+
744
+ // ../../lib/adapter-utils/src/runtime/is-factory-options-like.ts
745
+ var FACTORY_OPTIONS_FIELD_VALIDATORS = {
746
+ tag: (v) => v === void 0 || isString(v),
747
+ name: (v) => v === void 0 || isString(v),
748
+ defaults: (v) => v === void 0 || isObject(v),
749
+ normalize: (v) => v === void 0 || isFunction(v),
750
+ styling: (v) => v === void 0 || isObject(v),
751
+ enforcement: (v) => v === void 0 || isObject(v),
752
+ diagnostics: (v) => v === void 0 || isObject(v),
753
+ subComponents: (v) => v === void 0 || isObject(v),
754
+ onElement: (v) => v === void 0 || isFunction(v)
755
+ };
756
+ function isFactoryOptionsLike(options, extraFieldValidators) {
757
+ if (!isObject(options)) return false;
758
+ const validators = { ...FACTORY_OPTIONS_FIELD_VALIDATORS, ...extraFieldValidators };
759
+ for (const [key, value] of Object.entries(options)) {
760
+ const validate = validators[key];
761
+ if (!validate || !validate(value)) return false;
762
+ }
763
+ return true;
702
764
  }
703
765
 
704
766
  // ../../lib/contract/src/aria/aria-role-policy.ts
@@ -1599,7 +1661,8 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1599
1661
  const cached = _AriaPolicyEngine.#removeAttributeFixCache.get(attr);
1600
1662
  if (cached) return cached;
1601
1663
  const fix = {
1602
- kind: `removeAttribute:${attr}`,
1664
+ kind: "removeAttribute",
1665
+ attribute: attr,
1603
1666
  apply: ({ props }) => {
1604
1667
  if (!(attr in props)) return { applied: false, next: props };
1605
1668
  return { applied: true, next: omitProp(props, attr), previous: props };
@@ -1870,7 +1933,8 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1870
1933
  if (!impliedLive) return NO_VIOLATIONS2;
1871
1934
  if ("aria-live" in props) return NO_VIOLATIONS2;
1872
1935
  const injectLive = {
1873
- kind: `injectLive:${effectiveRole}`,
1936
+ kind: "injectLive",
1937
+ attribute: "aria-live",
1874
1938
  apply: (ctx) => ({
1875
1939
  applied: true,
1876
1940
  next: { ...ctx.props, "aria-live": impliedLive },
@@ -1939,6 +2003,23 @@ var AriaPolicyEngine = class _AriaPolicyEngine extends InvariantBase {
1939
2003
  }
1940
2004
  };
1941
2005
 
2006
+ // ../../lib/contract/src/aria/factories.ts
2007
+ function removeProp(props, key) {
2008
+ const next = { ...props };
2009
+ delete next[key];
2010
+ return next;
2011
+ }
2012
+ function removeAttributeFix(attribute) {
2013
+ return Object.freeze({
2014
+ kind: "removeAttribute",
2015
+ attribute,
2016
+ apply: ({ props }) => {
2017
+ if (!(attribute in props)) return { applied: false, next: props };
2018
+ return { applied: true, next: removeProp(props, attribute), previous: props };
2019
+ }
2020
+ });
2021
+ }
2022
+
1942
2023
  // ../../lib/contract/src/children/get-type-name.ts
1943
2024
  function getTypeName(value) {
1944
2025
  if (value === null) return "null";
@@ -2257,22 +2338,6 @@ import { warnDiagnostics as warnDiagnostics2 } from "../_shared/diagnostics.js";
2257
2338
 
2258
2339
  // ../core/src/html/contracts/categories.ts
2259
2340
  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
2341
  var TEXT_ONLY_TAGS = [
2277
2342
  "option",
2278
2343
  "script",
@@ -2396,20 +2461,6 @@ var INPUT_MUTUALLY_EXCLUSIVE_POLICIES = [
2396
2461
 
2397
2462
  // ../core/src/html/spec/validators/attribute-type-validator.ts
2398
2463
  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
2464
  function createInputAttributeTypeRule({
2414
2465
  attribute,
2415
2466
  allowedTypes
@@ -2862,7 +2913,7 @@ function getChildProp(child, key) {
2862
2913
  if (!isVNodeLike(child)) return void 0;
2863
2914
  const { props } = child;
2864
2915
  if (!isObject(props)) return void 0;
2865
- return props[key];
2916
+ return Reflect.get(props, key);
2866
2917
  }
2867
2918
 
2868
2919
  // ../core/src/html/contracts/aria/landmarks.ts
@@ -2915,6 +2966,13 @@ function isLabelableControl(child) {
2915
2966
  const type = getChildProp(child, "type");
2916
2967
  return !isString(type) || type !== "hidden";
2917
2968
  }
2969
+ function hasAccessibleNameProp(props) {
2970
+ return "aria-label" in props || "aria-labelledby" in props;
2971
+ }
2972
+ function isNonEmptyTextChild(child) {
2973
+ if (isNumber(child)) return true;
2974
+ return isString(child) && child.trim().length > 0;
2975
+ }
2918
2976
  var labelContract = contract([
2919
2977
  { name: "control", match: isLabelableControl, cardinality: { max: 1 } },
2920
2978
  { name: "nested-label", match: isTag("label"), cardinality: { max: 0 } },
@@ -2922,6 +2980,13 @@ var labelContract = contract([
2922
2980
  name: "other-interactive-content",
2923
2981
  match: isTag(...OTHER_INTERACTIVE_TAGS),
2924
2982
  cardinality: { max: 0 }
2983
+ },
2984
+ {
2985
+ name: "accessible-name",
2986
+ match: isNonEmptyTextChild,
2987
+ cardinality: dynamic(
2988
+ (ctx) => hasAccessibleNameProp(ctx.props) ? { min: 0 } : { min: 1 }
2989
+ )
2925
2990
  }
2926
2991
  ]);
2927
2992
 
@@ -3545,6 +3610,13 @@ function buildRuntime(options) {
3545
3610
  return built;
3546
3611
  }
3547
3612
 
3613
+ // ../../adapters/vue/src/is-polymorphic-component.ts
3614
+ function isPolymorphicComponent(value) {
3615
+ if (!isObject(value)) return false;
3616
+ if (!("displayName" in value)) return true;
3617
+ return value.displayName === void 0 || isString(value.displayName);
3618
+ }
3619
+
3548
3620
  // ../../adapters/vue/src/render.ts
3549
3621
  import { cloneVNode, h as h3 } from "vue";
3550
3622
 
@@ -3643,7 +3715,7 @@ function prepareRenderState(runtime, attrs, filterProps) {
3643
3715
  className
3644
3716
  };
3645
3717
  }
3646
- function buildElementProps(props, className) {
3718
+ function buildElementProps(props, className, elementRef) {
3647
3719
  const { role, ...rest } = props;
3648
3720
  return {
3649
3721
  ...normalizeListenerKeys(rest),
@@ -3651,11 +3723,17 @@ function buildElementProps(props, className) {
3651
3723
  // normalizeClass turns it into '' and still emits class="", while the client patcher
3652
3724
  // removes the attribute outright. Omitting the key entirely keeps both paths consistent.
3653
3725
  ...className !== void 0 && { class: className },
3654
- ...isKnownAriaRole(role) && { role }
3726
+ ...isKnownAriaRole(role) && { role },
3727
+ // Vue calls a function-ref with the element on mount and with null on unmount, same
3728
+ // contract as React/Preact's callback refs — a natural fit for FactoryOptions.onElement.
3729
+ // Cast: Vue's own VNodeRef type also accepts a resolved *component* instance, since refs
3730
+ // can target components as well as elements — irrelevant here, this is only ever attached
3731
+ // to an intrinsic host tag, which always resolves to a real Element.
3732
+ ...elementRef !== void 0 && { ref: elementRef }
3655
3733
  };
3656
3734
  }
3657
- function renderIntrinsic(state, runtime, slots) {
3658
- const elementProps = buildElementProps(state.props, state.className);
3735
+ function renderIntrinsic(state, runtime, slots, elementRef) {
3736
+ const elementProps = buildElementProps(state.props, state.className, elementRef);
3659
3737
  const domProps = runtime.resolveAria(state.tag, elementProps).props;
3660
3738
  return h3(state.tag, domProps, slots.default ? { default: slots.default } : void 0);
3661
3739
  }
@@ -3668,12 +3746,13 @@ function validateSlotDirectives(directives, validator) {
3668
3746
  }
3669
3747
  return true;
3670
3748
  }
3671
- function tryRenderAsChild(state, children, discarded, validator) {
3749
+ function tryRenderAsChild(state, children, discarded, validator, elementRef) {
3672
3750
  if (!validateSlotDirectives(state.directives, validator)) return null;
3673
3751
  if (discarded > 0) validator.warnDiscardedChildren(discarded);
3674
3752
  const attrs = {
3675
3753
  ...pickAttributes(state.props),
3676
- ...state.className !== void 0 && { class: state.className }
3754
+ ...state.className !== void 0 && { class: state.className },
3755
+ ...elementRef !== void 0 && { ref: elementRef }
3677
3756
  };
3678
3757
  const slottable = extractSlottable(children);
3679
3758
  if (slottable) return slottable.rebuild(cloneVNode(slottable.child, attrs));
@@ -3688,20 +3767,31 @@ function render({
3688
3767
  state,
3689
3768
  slots,
3690
3769
  slotValidator,
3691
- childrenEvaluator
3770
+ childrenEvaluator,
3771
+ elementRef
3692
3772
  }) {
3693
3773
  const { vnodes: children, discarded } = normalizeChildren(slots);
3694
3774
  if (process.env.NODE_ENV !== "production") {
3695
3775
  childrenEvaluator?.evaluate(children, { tag: state.tag, props: state.normalizedProps });
3696
- runtime.options.htmlChildrenEvaluatorFn?.(state.tag)?.evaluate(children);
3776
+ runtime.options.htmlChildrenEvaluatorFn?.(state.tag)?.evaluate(children, { tag: state.tag, props: state.normalizedProps });
3697
3777
  }
3698
- const slotResult = tryRenderAsChild(state, children, discarded, slotValidator);
3699
- return slotResult ?? renderIntrinsic(state, runtime, slots);
3778
+ const slotResult = tryRenderAsChild(state, children, discarded, slotValidator, elementRef);
3779
+ return slotResult ?? renderIntrinsic(state, runtime, slots, elementRef);
3780
+ }
3781
+
3782
+ // ../../adapters/vue/src/to-vue-factory-options.ts
3783
+ var VUE_FIELD_VALIDATORS = {
3784
+ filterProps: (v) => v === void 0 || isFunction(v)
3785
+ };
3786
+ function isVueFactoryOptions(options) {
3787
+ return isFactoryOptionsLike(options, VUE_FIELD_VALIDATORS);
3700
3788
  }
3701
3789
 
3702
3790
  // ../../adapters/vue/src/create-contract-component.ts
3703
3791
  function createContractComponent(options) {
3792
+ invariant(isVueFactoryOptions(options), "options is not a valid VueFactoryOptions object");
3704
3793
  const bundle = buildRuntime(options);
3794
+ const { onElement } = options;
3705
3795
  const Component = defineComponent2({
3706
3796
  // normalizeOptions always supplies `name`, so displayName is always defined here —
3707
3797
  // the fallback only satisfies the type, which allows it to be absent in general.
@@ -3711,15 +3801,33 @@ function createContractComponent(options) {
3711
3801
  const state = computed(
3712
3802
  () => prepareRenderState(bundle.runtime, attrs, bundle.filterProps)
3713
3803
  );
3714
- return () => render({ ...bundle, state: state.value, slots });
3804
+ let cleanup;
3805
+ let boundElement = null;
3806
+ const onElementRef = onElement ? (element) => {
3807
+ if (element === boundElement) return;
3808
+ if (boundElement) {
3809
+ cleanup?.();
3810
+ cleanup = void 0;
3811
+ }
3812
+ boundElement = element;
3813
+ if (element) {
3814
+ cleanup = onElement(element, () => attrs) ?? void 0;
3815
+ }
3816
+ } : void 0;
3817
+ return () => render({ ...bundle, state: state.value, slots, elementRef: onElementRef });
3715
3818
  }
3716
3819
  });
3717
3820
  applyDisplayName(Component, options.name);
3718
- const defaultTag = bundle.runtime.options.defaultTag;
3719
- if (typeof defaultTag === "string") {
3720
- Object.assign(Component, { [COMPONENT_DEFAULT_TAG]: defaultTag });
3721
- }
3722
- return Component;
3821
+ const assembled = finalizeComponent(
3822
+ Component,
3823
+ bundle.runtime.options.defaultTag,
3824
+ options.subComponents
3825
+ );
3826
+ invariant(
3827
+ isPolymorphicComponent(assembled),
3828
+ "Generated component failed to satisfy the PolymorphicComponent shape"
3829
+ );
3830
+ return assembled;
3723
3831
  }
3724
3832
  export {
3725
3833
  Slottable,
@@ -4,6 +4,8 @@ import { Diagnostics, DiagnosticInput, DiagnosticsMode } from '../_shared/diagno
4
4
  type StringMap<T = unknown> = Record<string, T>;
5
5
  type AnyRecord = StringMap<unknown>;
6
6
  type EmptyRecord = Record<never, never>;
7
+ /** A compound component's named sub-components, e.g. `{ Header, Content, Footer }`. */
8
+ type SubComponentMap = Readonly<AnyRecord>;
7
9
 
8
10
  type IntrinsicTag = keyof HTMLElementTagNameMap;
9
11
 
@@ -178,8 +180,8 @@ type AriaContext = {
178
180
  readonly props: ReadonlyDeep<IntrinsicProps>;
179
181
  };
180
182
 
181
- type RemoveAttributeFixKind = `removeAttribute:${string}`;
182
- type InjectLiveFixKind = `injectLive:${string}`;
183
+ type RemoveAttributeFixKind = 'removeAttribute';
184
+ type InjectLiveFixKind = 'injectLive';
183
185
  type FixKind = 'removeRole' | 'setRole' | 'normalizeRelevantAll' | RemoveAttributeFixKind | InjectLiveFixKind;
184
186
 
185
187
  type AriaFixResult = {
@@ -192,6 +194,9 @@ type AriaFixResult = {
192
194
  };
193
195
  type AriaFix = {
194
196
  readonly kind: FixKind;
197
+ /** The attribute a `'removeAttribute'`/`'injectLive'` fix targets — always set for those
198
+ * kinds, absent for kinds with no single-attribute target (`'removeRole'`, etc.). */
199
+ readonly attribute?: string;
195
200
  readonly priority?: number;
196
201
  readonly source?: string;
197
202
  readonly apply: (context: AriaContext) => AriaFixResult;
@@ -285,6 +290,30 @@ type FactoryOptions<TDefault extends ElementType = ElementType, Props extends An
285
290
  * be set directly by component authors — use `enforcement.diagnostics` to override per component.
286
291
  */
287
292
  readonly diagnostics?: Diagnostics;
293
+ /**
294
+ * Sub-components to attach to the generated root component, producing a
295
+ * compound component API (for example, `Card.Header`, `Card.Content`,
296
+ * and `Card.Footer`). Purely additive — has no effect on
297
+ * `enforcement.children`; author child rules explicitly if the component
298
+ * needs to validate its children.
299
+ */
300
+ readonly subComponents?: SubComponentMap;
301
+ /**
302
+ * Called once per instance, when the real underlying DOM element first
303
+ * exists, in every adapter — via that adapter's own native mount
304
+ * lifecycle, never through the props/attribute pipeline. Use this for
305
+ * wiring that needs the actual element (native imperative methods like
306
+ * `dialogEl.showModal()`, native events like `close`/`cancel` that have
307
+ * no prop-based equivalent), not for anything expressible as a plain
308
+ * prop.
309
+ *
310
+ * `getProps` returns the instance's *current* resolved props at call
311
+ * time — read it from inside a listener registered once at mount, rather
312
+ * than re-subscribing on every prop change.
313
+ *
314
+ * Return a cleanup function to run when the instance unmounts.
315
+ */
316
+ readonly onElement?: (element: Element, getProps: () => Readonly<Props>) => void | (() => void);
288
317
  };
289
318
 
290
319
  type FilterPredicate = (key: string, variantKeys: ReadonlySet<string>) => boolean;
@@ -349,7 +378,9 @@ type WebContractComponent<TVariants extends Readonly<VariantMap> = Readonly<Empt
349
378
  * For non-reactive attributes (`aria-*`, `role`, `data-*`) call `element.update()`
350
379
  * after setting them to trigger an explicit pipeline re-run.
351
380
  */
352
- declare function createContractComponent<TDefault extends ElementType, TProps extends UnknownProps = EmptyRecord, TVariants extends Readonly<VariantMap> = Readonly<EmptyRecord>, TPreset extends RecipeMap<TVariants> = Readonly<EmptyRecord>, TPlugin extends AnyClassPluginFactory = AnyClassPluginFactory>(options: WebFactoryOptions<TDefault, TProps, TVariants, TPreset, TPlugin>): WebContractComponent<TVariants, ExtractPluginProps<TPlugin>>;
381
+ declare function createContractComponent<TDefault extends ElementType, TProps extends UnknownProps = EmptyRecord, TVariants extends Readonly<VariantMap> = Readonly<EmptyRecord>, TPreset extends RecipeMap<TVariants> = Readonly<EmptyRecord>, TPlugin extends AnyClassPluginFactory = AnyClassPluginFactory, TSubComponents extends Readonly<AnyRecord> = EmptyRecord>(options: WebFactoryOptions<TDefault, TProps, TVariants, TPreset, TPlugin> & {
382
+ readonly subComponents?: TSubComponents;
383
+ }): WebContractComponent<TVariants, ExtractPluginProps<TPlugin>> & TSubComponents;
353
384
 
354
385
  /**
355
386
  * Renders a praxis-kit web component to an HTML string without requiring a DOM.