praxis-kit 7.0.0 → 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.
@@ -1,3 +1,27 @@
1
+ // ../../lib/adapter-utils/src/invariant.ts
2
+ function panic(message) {
3
+ throw new Error(message);
4
+ }
5
+ function invariant(condition, message) {
6
+ if (!condition) panic(message);
7
+ }
8
+
9
+ // ../../lib/adapter-utils/src/runtime/apply-display-name.ts
10
+ function applyDisplayName(component, name) {
11
+ Object.assign(component, { displayName: name ?? "PolymorphicComponent" });
12
+ }
13
+
14
+ // ../../lib/adapter-utils/src/runtime/define-component.ts
15
+ function defineContractComponent(options) {
16
+ return (factory) => factory(options);
17
+ }
18
+
19
+ // ../../lib/adapter-utils/src/runtime/assemble-compound-component.ts
20
+ function assembleCompoundComponent(root, subComponents) {
21
+ if (!subComponents) return root;
22
+ return Object.assign(root, subComponents);
23
+ }
24
+
1
25
  // ../../lib/primitive/src/tag/resolve-tag.ts
2
26
  function makeResolveTag(defaultTag) {
3
27
  return function tag(as) {
@@ -40,10 +64,13 @@ function isString(value) {
40
64
  function isNumber(value) {
41
65
  return typeof value === "number";
42
66
  }
67
+ function isFunction(value) {
68
+ return typeof value === "function";
69
+ }
43
70
 
44
71
  // ../../lib/primitive/src/rule/is-dynamic-rule.ts
45
72
  function isDynamicRule(rule) {
46
- return isObject(rule, true) && rule[RULE_BRAND] === true;
73
+ return isObject(rule, true) && Reflect.get(rule, RULE_BRAND) === true;
47
74
  }
48
75
 
49
76
  // ../../lib/primitive/src/rule/resolve-rule.ts
@@ -673,17 +700,17 @@ var COMPONENT_DEFAULT_TAG = /* @__PURE__ */ Symbol.for("praxis.component-default
673
700
  // ../../lib/primitive/src/guards/children/is-tag.ts
674
701
  function getAsProp(child) {
675
702
  if (!isObject(child) || !("props" in child)) return void 0;
676
- const props = child.props;
703
+ const { props } = child;
677
704
  if (!isObject(props)) return void 0;
678
- const as = props.as;
705
+ const as = Reflect.get(props, "as");
679
706
  return isString(as) && as !== "" ? as : void 0;
680
707
  }
681
708
  function getTag(child) {
682
709
  if (!isObject(child) || !("type" in child)) return void 0;
683
- const t = child.type;
710
+ const { type: t } = child;
684
711
  if (isString(t)) return t;
685
712
  if (typeof t === "function" || isObject(t)) {
686
- const defaultTag = t[COMPONENT_DEFAULT_TAG];
713
+ const defaultTag = Reflect.get(t, COMPONENT_DEFAULT_TAG);
687
714
  if (!isString(defaultTag)) return void 0;
688
715
  return getAsProp(child) ?? defaultTag;
689
716
  }
@@ -703,14 +730,34 @@ function isTag(...args) {
703
730
  return tag !== void 0 && set2.has(tag);
704
731
  }
705
732
 
706
- // ../../lib/adapter-utils/src/runtime/apply-display-name.ts
707
- function applyDisplayName(component, name) {
708
- Object.assign(component, { displayName: name ?? "PolymorphicComponent" });
733
+ // ../../lib/adapter-utils/src/runtime/finalize-component.ts
734
+ function finalizeComponent(component, defaultTag, subComponents) {
735
+ if (typeof defaultTag === "string") {
736
+ Object.assign(component, { [COMPONENT_DEFAULT_TAG]: defaultTag });
737
+ }
738
+ return assembleCompoundComponent(component, subComponents);
709
739
  }
710
740
 
711
- // ../../lib/adapter-utils/src/runtime/define-component.ts
712
- function defineContractComponent(options) {
713
- return (factory) => factory(options);
741
+ // ../../lib/adapter-utils/src/runtime/is-factory-options-like.ts
742
+ var FACTORY_OPTIONS_FIELD_VALIDATORS = {
743
+ tag: (v) => v === void 0 || isString(v),
744
+ name: (v) => v === void 0 || isString(v),
745
+ defaults: (v) => v === void 0 || isObject(v),
746
+ normalize: (v) => v === void 0 || isFunction(v),
747
+ styling: (v) => v === void 0 || isObject(v),
748
+ enforcement: (v) => v === void 0 || isObject(v),
749
+ diagnostics: (v) => v === void 0 || isObject(v),
750
+ subComponents: (v) => v === void 0 || isObject(v),
751
+ onElement: (v) => v === void 0 || isFunction(v)
752
+ };
753
+ function isFactoryOptionsLike(options, extraFieldValidators) {
754
+ if (!isObject(options)) return false;
755
+ const validators = { ...FACTORY_OPTIONS_FIELD_VALIDATORS, ...extraFieldValidators };
756
+ for (const [key, value] of Object.entries(options)) {
757
+ const validate = validators[key];
758
+ if (!validate || !validate(value)) return false;
759
+ }
760
+ return true;
714
761
  }
715
762
 
716
763
  // ../../lib/contract/src/aria/aria-role-policy.ts
@@ -2863,7 +2910,7 @@ function getChildProp(child, key) {
2863
2910
  if (!isVNodeLike(child)) return void 0;
2864
2911
  const { props } = child;
2865
2912
  if (!isObject(props)) return void 0;
2866
- return props[key];
2913
+ return Reflect.get(props, key);
2867
2914
  }
2868
2915
 
2869
2916
  // ../core/src/html/contracts/aria/landmarks.ts
@@ -3512,6 +3559,9 @@ function composeFilter(ownedKeys, filterProps) {
3512
3559
  return (key, variantKeys) => defaultFilter(key, variantKeys) || filterProps(key, variantKeys);
3513
3560
  }
3514
3561
 
3562
+ // ../../adapters/solid/src/create-contract-component.ts
3563
+ import { mergeProps as mergeProps2, onCleanup } from "solid-js";
3564
+
3515
3565
  // ../../adapters/solid/src/slot/slot-validator.ts
3516
3566
  var SlotValidator = class extends InvariantBase {
3517
3567
  #name;
@@ -3559,6 +3609,13 @@ function buildRuntime(options) {
3559
3609
  };
3560
3610
  }
3561
3611
 
3612
+ // ../../adapters/solid/src/is-polymorphic-component.ts
3613
+ function isPolymorphicComponent(value) {
3614
+ if (!isFunction(value)) return false;
3615
+ if (!("displayName" in value)) return true;
3616
+ return value.displayName === void 0 || isString(value.displayName);
3617
+ }
3618
+
3562
3619
  // ../../adapters/solid/src/render.tsx
3563
3620
  import { createComponent as _$createComponent } from "solid-js/web";
3564
3621
  import { mergeProps as _$mergeProps } from "solid-js/web";
@@ -3673,20 +3730,46 @@ function render({
3673
3730
  }, () => domProps()));
3674
3731
  }
3675
3732
 
3733
+ // ../../adapters/solid/src/to-solid-factory-options.ts
3734
+ var SOLID_FIELD_VALIDATORS = {
3735
+ filterProps: (v) => v === void 0 || isFunction(v)
3736
+ };
3737
+ function isSolidFactoryOptions(options) {
3738
+ return isFactoryOptionsLike(options, SOLID_FIELD_VALIDATORS);
3739
+ }
3740
+
3676
3741
  // ../../adapters/solid/src/create-contract-component.ts
3677
3742
  function createContractComponent(options) {
3743
+ invariant(isSolidFactoryOptions(options), "options is not a valid SolidFactoryOptions object");
3678
3744
  const bundle = buildRuntime(options);
3745
+ const { onElement } = options;
3679
3746
  const Component = (props) => {
3747
+ const propsWithRef = onElement ? mergeProps2(props, {
3748
+ get ref() {
3749
+ const consumerRef = props.ref;
3750
+ return (el) => {
3751
+ if (typeof consumerRef === "function") consumerRef(el);
3752
+ const cleanup = onElement(el, () => props);
3753
+ if (cleanup) onCleanup(cleanup);
3754
+ };
3755
+ }
3756
+ }) : props;
3680
3757
  return render({
3681
3758
  ...bundle,
3682
- props
3759
+ props: propsWithRef
3683
3760
  });
3684
3761
  };
3685
3762
  applyDisplayName(Component, options.name);
3686
- if (typeof bundle.runtime.options.defaultTag === "string") {
3687
- Object.assign(Component, { [COMPONENT_DEFAULT_TAG]: bundle.runtime.options.defaultTag });
3688
- }
3689
- return Component;
3763
+ const assembled = finalizeComponent(
3764
+ Component,
3765
+ bundle.runtime.options.defaultTag,
3766
+ options.subComponents
3767
+ );
3768
+ invariant(
3769
+ isPolymorphicComponent(assembled),
3770
+ "Generated component failed to satisfy the PolymorphicComponent shape"
3771
+ );
3772
+ return assembled;
3690
3773
  }
3691
3774
  export {
3692
3775
  createContractComponent,
@@ -134,6 +134,18 @@
134
134
  ?.(tag)
135
135
  ?.evaluate(childArray, { tag, props: normalizedProps })
136
136
  })
137
+
138
+ const onElement = $derived(bundle.onElement)
139
+
140
+ // Unlike the effect above, this runs in every environment (not dev-only) — onElement is a
141
+ // real runtime feature, not a diagnostic. Re-runs (cleaning up the previous call first, via
142
+ // the returned teardown) whenever hostEl changes identity, e.g. the resolved tag changes and
143
+ // Svelte mounts a new host element.
144
+ $effect(() => {
145
+ if (!hostEl) return
146
+ const cleanup = onElement?.(hostEl, () => normalizedProps)
147
+ return () => cleanup?.()
148
+ })
137
149
  }
138
150
  </script>
139
151
 
@@ -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
 
@@ -131,6 +133,7 @@ interface PolymorphicGenerics<TDefault extends ElementType = ElementType, Props
131
133
  preset: TPreset;
132
134
  allowed: TAllowed;
133
135
  }
136
+ type PropsOf<T extends PolymorphicGenerics> = T['props'];
134
137
 
135
138
  type RequireAtLeastOneIfNotEmpty<T> = keyof T extends never ? EmptyRecord : RequireAtLeastOne<T>;
136
139
  type CompoundVariantConditionValue<V extends VariantMap, K extends keyof V> = VariantKey<V, K> | NonEmptyArray<VariantKey<V, K>>;
@@ -310,6 +313,30 @@ type FactoryOptions<TDefault extends ElementType = ElementType, Props extends An
310
313
  * be set directly by component authors — use `enforcement.diagnostics` to override per component.
311
314
  */
312
315
  readonly diagnostics?: Diagnostics;
316
+ /**
317
+ * Sub-components to attach to the generated root component, producing a
318
+ * compound component API (for example, `Card.Header`, `Card.Content`,
319
+ * and `Card.Footer`). Purely additive — has no effect on
320
+ * `enforcement.children`; author child rules explicitly if the component
321
+ * needs to validate its children.
322
+ */
323
+ readonly subComponents?: SubComponentMap;
324
+ /**
325
+ * Called once per instance, when the real underlying DOM element first
326
+ * exists, in every adapter — via that adapter's own native mount
327
+ * lifecycle, never through the props/attribute pipeline. Use this for
328
+ * wiring that needs the actual element (native imperative methods like
329
+ * `dialogEl.showModal()`, native events like `close`/`cancel` that have
330
+ * no prop-based equivalent), not for anything expressible as a plain
331
+ * prop.
332
+ *
333
+ * `getProps` returns the instance's *current* resolved props at call
334
+ * time — read it from inside a listener registered once at mount, rather
335
+ * than re-subscribing on every prop change.
336
+ *
337
+ * Return a cleanup function to run when the instance unmounts.
338
+ */
339
+ readonly onElement?: (element: Element, getProps: () => Readonly<Props>) => void | (() => void);
313
340
  };
314
341
 
315
342
  type ResolvedFactoryOptions<TDefault extends ElementType = ElementType, Props extends AnyRecord = EmptyRecord, V extends Readonly<VariantMap> = Readonly<EmptyRecord>, TPreset extends RecipeMap<V> = Readonly<EmptyRecord>> = {
@@ -424,12 +451,16 @@ type SvelteFactoryOptions<TDefault extends ElementType, Props extends UnknownPro
424
451
 
425
452
  type TypedRuntime<G extends PolymorphicGenerics> = ReturnType<typeof createPolymorphic2<DefaultOf<G>, PropsOf<G>, VariantsOf<G>, RecipeOf<G>>>;
426
453
 
454
+ type OnElementFn<Props = unknown> = (element: Element, getProps: () => Readonly<Props>) => void | (() => void);
427
455
  type BuiltRuntime<G extends PolymorphicGenerics = PolymorphicGenerics, TOptions extends WithChildRules = WithChildRules> = BuiltChildrenEvaluator<TOptions> & {
428
456
  runtime: TypedRuntime<G>;
429
457
  filterProps: FilterPredicate;
430
458
  slotValidator: SlotValidator;
459
+ onElement?: OnElementFn<PropsOf<G>>;
431
460
  };
432
461
 
433
- declare function createContractComponent<TDefault extends ElementType, Props extends UnknownProps = EmptyRecord, Variants extends Readonly<VariantMap> = Readonly<EmptyRecord>, TPreset extends RecipeMap<Variants> = Readonly<EmptyRecord>, TPlugin extends AnyClassPluginFactory = AnyClassPluginFactory, TOptions extends WithChildRules = SvelteFactoryOptions<TDefault, Props & ExtractPluginProps<TPlugin>, Variants, TPreset>>(options: SvelteFactoryOptions<TDefault, Props, Variants, TPreset, TPlugin> & TOptions): BuiltRuntime<PolymorphicGenerics<TDefault, Props & ExtractPluginProps<TPlugin>, Variants, TPreset>, TOptions>;
462
+ declare function createContractComponent<TDefault extends ElementType, Props extends UnknownProps = EmptyRecord, Variants extends Readonly<VariantMap> = Readonly<EmptyRecord>, TPreset extends RecipeMap<Variants> = Readonly<EmptyRecord>, TPlugin extends AnyClassPluginFactory = AnyClassPluginFactory, TSubComponents extends Readonly<AnyRecord> = EmptyRecord, TOptions extends WithChildRules = SvelteFactoryOptions<TDefault, Props & ExtractPluginProps<TPlugin>, Variants, TPreset>>(options: SvelteFactoryOptions<TDefault, Props, Variants, TPreset, TPlugin> & TOptions & {
463
+ readonly subComponents?: TSubComponents;
464
+ }): BuiltRuntime<PolymorphicGenerics<TDefault, Props & ExtractPluginProps<TPlugin>, Variants, TPreset>, TOptions> & TSubComponents;
434
465
 
435
466
  export { type AnyFactoryOptions, type BuiltRuntime, type ElementType, type EmptyRecord, type FilterPredicate, type PolymorphicGenerics, type SvelteFactoryOptions, type UnknownProps, type WithChildRules, createContractComponent, defineContractComponent };
@@ -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) {
@@ -48,7 +54,7 @@ function isNumber(value) {
48
54
 
49
55
  // ../../lib/primitive/src/rule/is-dynamic-rule.ts
50
56
  function isDynamicRule(rule) {
51
- return isObject(rule, true) && rule[RULE_BRAND] === true;
57
+ return isObject(rule, true) && Reflect.get(rule, RULE_BRAND) === true;
52
58
  }
53
59
 
54
60
  // ../../lib/primitive/src/rule/resolve-rule.ts
@@ -587,17 +593,17 @@ var COMPONENT_DEFAULT_TAG = /* @__PURE__ */ Symbol.for("praxis.component-default
587
593
  // ../../lib/primitive/src/guards/children/is-tag.ts
588
594
  function getAsProp(child) {
589
595
  if (!isObject(child) || !("props" in child)) return void 0;
590
- const props = child.props;
596
+ const { props } = child;
591
597
  if (!isObject(props)) return void 0;
592
- const as = props.as;
598
+ const as = Reflect.get(props, "as");
593
599
  return isString(as) && as !== "" ? as : void 0;
594
600
  }
595
601
  function getTag(child) {
596
602
  if (!isObject(child) || !("type" in child)) return void 0;
597
- const t = child.type;
603
+ const { type: t } = child;
598
604
  if (isString(t)) return t;
599
605
  if (typeof t === "function" || isObject(t)) {
600
- const defaultTag = t[COMPONENT_DEFAULT_TAG];
606
+ const defaultTag = Reflect.get(t, COMPONENT_DEFAULT_TAG);
601
607
  if (!isString(defaultTag)) return void 0;
602
608
  return getAsProp(child) ?? defaultTag;
603
609
  }
@@ -2767,7 +2773,7 @@ function getChildProp(child, key) {
2767
2773
  if (!isVNodeLike(child)) return void 0;
2768
2774
  const { props } = child;
2769
2775
  if (!isObject(props)) return void 0;
2770
- return props[key];
2776
+ return Reflect.get(props, key);
2771
2777
  }
2772
2778
 
2773
2779
  // ../core/src/html/contracts/aria/landmarks.ts
@@ -3440,15 +3446,17 @@ function buildRuntime(options) {
3440
3446
  runtime,
3441
3447
  filterProps,
3442
3448
  slotValidator,
3443
- ...childrenEvaluator !== void 0 && { childrenEvaluator }
3449
+ ...childrenEvaluator !== void 0 && { childrenEvaluator },
3450
+ ...options.onElement !== void 0 && { onElement: options.onElement }
3444
3451
  };
3445
3452
  }
3446
3453
 
3447
3454
  // ../../adapters/svelte/src/create-contract-component.ts
3448
3455
  function createContractComponent(options) {
3449
- return buildRuntime(
3456
+ const bundle = buildRuntime(
3450
3457
  options
3451
3458
  );
3459
+ return assembleCompoundComponent(bundle, options.subComponents);
3452
3460
  }
3453
3461
  export {
3454
3462
  createContractComponent,
@@ -167,10 +167,13 @@ function init(modules) {
167
167
  info.config.calleeNames ?? DEFAULT_CALLEE_NAMES
168
168
  );
169
169
  const proxy = /* @__PURE__ */ Object.create(null);
170
- const proxyRecord = proxy;
171
170
  for (const k of Object.keys(info.languageService)) {
172
171
  const x = info.languageService[k];
173
- proxyRecord[k] = typeof x === "function" ? x.bind(info.languageService) : x;
172
+ Reflect.set(
173
+ proxy,
174
+ k,
175
+ typeof x === "function" ? x.bind(info.languageService) : x
176
+ );
174
177
  }
175
178
  proxy.getSemanticDiagnostics = (fileName) => {
176
179
  const existing = info.languageService.getSemanticDiagnostics(fileName);
@@ -6,6 +6,8 @@ import { AllowedComponentProps } from 'vue';
6
6
  type StringMap<T = unknown> = Record<string, T>;
7
7
  type AnyRecord = StringMap<unknown>;
8
8
  type EmptyRecord = Record<never, never>;
9
+ /** A compound component's named sub-components, e.g. `{ Header, Content, Footer }`. */
10
+ type SubComponentMap = Readonly<AnyRecord>;
9
11
 
10
12
  type IntrinsicTag = keyof HTMLElementTagNameMap;
11
13
 
@@ -307,6 +309,30 @@ type FactoryOptions<TDefault extends ElementType = ElementType, Props extends An
307
309
  * be set directly by component authors — use `enforcement.diagnostics` to override per component.
308
310
  */
309
311
  readonly diagnostics?: Diagnostics;
312
+ /**
313
+ * Sub-components to attach to the generated root component, producing a
314
+ * compound component API (for example, `Card.Header`, `Card.Content`,
315
+ * and `Card.Footer`). Purely additive — has no effect on
316
+ * `enforcement.children`; author child rules explicitly if the component
317
+ * needs to validate its children.
318
+ */
319
+ readonly subComponents?: SubComponentMap;
320
+ /**
321
+ * Called once per instance, when the real underlying DOM element first
322
+ * exists, in every adapter — via that adapter's own native mount
323
+ * lifecycle, never through the props/attribute pipeline. Use this for
324
+ * wiring that needs the actual element (native imperative methods like
325
+ * `dialogEl.showModal()`, native events like `close`/`cancel` that have
326
+ * no prop-based equivalent), not for anything expressible as a plain
327
+ * prop.
328
+ *
329
+ * `getProps` returns the instance's *current* resolved props at call
330
+ * time — read it from inside a listener registered once at mount, rather
331
+ * than re-subscribing on every prop change.
332
+ *
333
+ * Return a cleanup function to run when the instance unmounts.
334
+ */
335
+ readonly onElement?: (element: Element, getProps: () => Readonly<Props>) => void | (() => void);
310
336
  };
311
337
 
312
338
  declare function defineContractComponent<O extends FactoryOptions>(options: O): <R>(factory: (options: O) => R) => R;
@@ -370,6 +396,8 @@ type PolymorphicComponent<G extends PolymorphicGenerics> = {
370
396
  displayName?: string;
371
397
  };
372
398
 
373
- declare function createContractComponent<TDefault extends ElementType, Props extends UnknownProps = EmptyRecord, Variants extends Readonly<VariantMap> = Readonly<EmptyRecord>, TPreset extends RecipeMap<Variants> = Readonly<EmptyRecord>, TPlugin extends AnyClassPluginFactory = AnyClassPluginFactory>(options: VueFactoryOptions<TDefault, Props, Variants, TPreset, TPlugin>): PolymorphicComponent<PolymorphicGenerics<TDefault, Props & ExtractPluginProps<TPlugin>, Variants, TPreset>>;
399
+ declare function createContractComponent<TDefault extends ElementType, Props extends UnknownProps = EmptyRecord, Variants extends Readonly<VariantMap> = Readonly<EmptyRecord>, TPreset extends RecipeMap<Variants> = Readonly<EmptyRecord>, TPlugin extends AnyClassPluginFactory = AnyClassPluginFactory, TSubComponents extends Readonly<AnyRecord> = EmptyRecord>(options: VueFactoryOptions<TDefault, Props, Variants, TPreset, TPlugin> & {
400
+ readonly subComponents?: TSubComponents;
401
+ }): PolymorphicComponent<PolymorphicGenerics<TDefault, Props & ExtractPluginProps<TPlugin>, Variants, TPreset>> & TSubComponents;
374
402
 
375
403
  export { type AnyFactoryOptions, type ElementType, type EmptyRecord, type PolymorphicComponent, type PolymorphicGenerics, type PolymorphicProps, type PolymorphicWithAsChild, Slottable, type SlottableProps, type VueFactoryOptions, createContractComponent, defineContractComponent };