praxis-kit 0.1.1 → 1.0.2

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.
@@ -25,20 +25,6 @@ type EmptyRecord = Record<never, never>;
25
25
  * `{ Header, Content, Footer }`.
26
26
  */
27
27
  type SubComponentMap = Readonly<AnyRecord>;
28
- /**
29
- * Default `Variants` type for components that declare no variants.
30
- *
31
- * Structurally identical to `Readonly<EmptyRecord>`, but named separately so
32
- * editor hovers remain self-descriptive.
33
- */
34
- type NoVariants = Readonly<EmptyRecord>;
35
- /**
36
- * Default `TPreset` type for components that declare no named presets.
37
- *
38
- * Structurally identical to `Readonly<EmptyRecord>`, but named separately so
39
- * editor hovers remain self-descriptive.
40
- */
41
- type NoPreset = Readonly<EmptyRecord>;
42
28
  /**
43
29
  * Fallback for `ExtractPluginProps<TPlugin>` when a plugin contributes no
44
30
  * props, including the no-plugin case.
@@ -568,16 +554,6 @@ type StylingOptions<V extends Readonly<VariantMap> = Readonly<EmptyRecord>, TPre
568
554
  type NormalizeFn<Props extends AnyRecord = AnyRecord> = {
569
555
  normalize(props: Readonly<Props & IntrinsicProps>): Props & IntrinsicProps;
570
556
  }['normalize'];
571
- /**
572
- * The type-erased shape of {@link FactoryOptions} — every generic parameter widened to its bound.
573
- *
574
- * Use it for a value that must hold *any* factory config (a registry, a generic wrapper). It
575
- * cannot check `styling.compounds` conditions against the real variant keys/values, because it
576
- * has forgotten what they are — for that, annotate against `FactoryOptions<...>` with the concrete
577
- * generics (or `satisfies FactoryOptions<'button', Props, typeof variants>`), which keeps an
578
- * invalid compound condition a type error rather than a silent no-op.
579
- */
580
- type AnyFactoryOptions = FactoryOptions<ElementType, AnyRecord, VariantMap, RecipeMap<VariantMap>, AnyClassPluginFactory>;
581
557
  /**
582
558
  * The framework-neutral component-authoring config passed to `createContractComponent` in every
583
559
  * adapter: default tag + name, own-prop defaults, a `normalize` transform, `styling` (variants,
@@ -587,7 +563,9 @@ type AnyFactoryOptions = FactoryOptions<ElementType, AnyRecord, VariantMap, Reci
587
563
  * `satisfies FactoryOptions<TDefault, Props, typeof variants, ...>` on a config object narrows
588
564
  * `styling.compounds` conditions to the real per-variant-key shape — including resolving a
589
565
  * boolean-shaped axis (`{ true, false }`) to a real `boolean` — so a condition naming a variant or
590
- * value that does not exist is a compile error. `AnyFactoryOptions` cannot do this.
566
+ * value that does not exist is a compile error. Leaving `V` at the bare `VariantMap` instead
567
+ * (whether via `FactoryOptions`'s own default or an explicit erased instantiation) forgets that
568
+ * shape entirely, so the same invalid condition becomes a silent no-op instead.
591
569
  */
592
570
  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> = {
593
571
  /** The intrinsic tag the component renders by default. Overridable per instance via `as`. */
@@ -596,6 +574,33 @@ type FactoryOptions<TDefault extends ElementType = ElementType, Props extends An
596
574
  readonly name?: string;
597
575
  /** Values used for the component's own (non-variant) props when the consumer omits them. */
598
576
  readonly defaults?: Partial<NoInfer<Props>>;
577
+ /**
578
+ * Optional, type-only declaration of this component's complete own-prop shape — present purely
579
+ * for type recovery, never read at runtime (see `declareProps` in `@praxis-kit/adapter-utils`).
580
+ *
581
+ * `defaults` alone can only prove a prop *has a default*, not that it's the complete prop model
582
+ * a component accepts — a `defaults: { size: 'md' }` component may still take `onClick`,
583
+ * `disabled`, and other props with no default at all, none of which a `defaults`-only recovery
584
+ * can see (see `ContractPropsFrom`'s own doc comment for the general shape of this problem).
585
+ * `props` closes that gap: when present, `ContractPropsOf<C>` / `ContractProps<typeof Component>`
586
+ * recover this declared type directly and exactly, in place of the necessarily-partial,
587
+ * literal-widened recovery `defaults` alone allows.
588
+ *
589
+ * Typed as `object | undefined`, not `NoInfer<Props> | undefined` like `defaults`/`onElement` —
590
+ * deliberately decoupled from this interface's own `Props` generic, unlike those two fields.
591
+ * `defaults`/`onElement` are tied to `Props` because real runtime code reads them against a
592
+ * concretely-resolved `Props` for a real call; `props` is never read at runtime at all (see
593
+ * above), so it has no such need, and tying it to `Props extends AnyRecord` would force every
594
+ * hand-declared prop `interface`/`type` an author passes through `declareProps<Props>()` to
595
+ * structurally satisfy `Record<string, unknown>` — a real TypeScript limitation (a named type
596
+ * without an index signature never satisfies that, even via plain assignment, only a fresh
597
+ * object literal does) that would make this field far more awkward to use for its one real job:
598
+ * carrying an author's own already-precise prop type through untouched. `ContractPropsFrom`
599
+ * (`contract-model.ts`) recovers the real value here structurally, straight off `O`'s own
600
+ * literal type — independent of this field's declared type, same as every other `Contract*From`
601
+ * derivation in that file.
602
+ */
603
+ readonly props?: object | undefined;
599
604
  /**
600
605
  * A pure `(props) => props` transform run on every render, after `enforcement.props`'s
601
606
  * normalizers see the same input. Use this for component-specific prop shaping — anything
@@ -650,7 +655,9 @@ type FactoryOptions<TDefault extends ElementType = ElementType, Props extends An
650
655
  *
651
656
  * Return a cleanup function to run when the instance unmounts.
652
657
  */
653
- readonly onElement?: (element: ElementForTag<TDefault | TAllowed>, getProps: () => Readonly<Props>) => void | (() => void);
658
+ readonly onElement?: {
659
+ onElement(element: ElementForTag<TDefault | TAllowed>, getProps: () => Readonly<Props>): void | (() => void);
660
+ }['onElement'];
654
661
  };
655
662
  //#endregion
656
663
  //#region ../../lib/primitive/src/types/factory/resolved-factory-options.d.ts
@@ -687,6 +694,154 @@ type ResolvedFactoryOptions<TDefault extends ElementType = ElementType, Props ex
687
694
  readonly precomputedClasses?: Readonly<StringMap<string>>;
688
695
  };
689
696
  //#endregion
697
+ //#region ../../lib/primitive/src/types/factory/contract-model.d.ts
698
+ /**
699
+ * The pipeline this file implements:
700
+ *
701
+ * ```text
702
+ * O (a raw contract literal)
703
+ * → Contract*From<O> one derivation per dimension, straight off O's own shape
704
+ * → ContractDimensions<O> the six derivations, assembled
705
+ * → ContractModel<...> the same six values, as a required-field carrier
706
+ * → ContractModelOf<C> resolves an already-`defineContract`-ed C's real model,
707
+ * or reconstructs one from a raw C via ContractModelFrom
708
+ * ```
709
+ *
710
+ * See `DECISIONS.md`'s `defineContract` entry for the TypeScript limitations that shaped the
711
+ * derivations below.
712
+ */
713
+ /**
714
+ * Canonical type-level representation of a contract's dimensions — the contract-level counterpart
715
+ * to `PolymorphicGenerics`. Every field is required, so a field's presence is never ambiguous the
716
+ * way it is on an optional `FactoryOptions` field.
717
+ */
718
+ interface ContractModel<TDefault extends ElementType = ElementType, Props extends AnyRecord = AnyRecord, V extends Readonly<VariantMap> = Readonly<VariantMap>, TPreset extends RecipeMap<VariantMap> = RecipeMap<VariantMap>, TPlugin extends AnyClassPluginFactory = AnyClassPluginFactory, TAllowed extends ElementType = ElementType> {
719
+ readonly tag: TDefault;
720
+ readonly props: Props;
721
+ readonly variants: V;
722
+ readonly preset: TPreset;
723
+ readonly plugin: TPlugin;
724
+ readonly allowed: TAllowed;
725
+ }
726
+ /**
727
+ * The phantom-marker shape read back via `T extends HasContractModel<infer M> ? M : ...` — the
728
+ * contract-level counterpart to `lib/contract-props`'s `HasGenerics<G>`. Type-only: never assigned
729
+ * at runtime.
730
+ *
731
+ * `__model` is **required**, not optional like `HasGenerics<G>`'s `__generics?` — an optional field
732
+ * would make `C extends HasContractModel<infer M>` trivially succeed for any `C`, defeating the
733
+ * one thing this marker exists to answer: did `C` really go through `defineContract`?
734
+ */
735
+ interface HasContractModel<M extends ContractModel = ContractModel> {
736
+ readonly __model: M;
737
+ }
738
+ type ContractTagFrom<O> = O extends {
739
+ tag: infer TDefault extends ElementType;
740
+ } ? TDefault : ElementType;
741
+ /** `'img'` → `string`, `1` → `number`, `true` → `boolean` — undoes `defineContract`'s `const O`
742
+ * literal narrowing so a `defaults` value doesn't become the only value a caller may pass. */
743
+ type WidenLiteral<T> = T extends string ? string : T extends number ? number : T extends boolean ? boolean : T;
744
+ type WidenShallow<T> = { [K in keyof T]: WidenLiteral<T[K]>; };
745
+ /** What the author explicitly declared, via `props: declareProps<Props>()`
746
+ * (`@praxis-kit/adapter-utils`) — used exactly as declared, no `Partial`/widening/`data-*`
747
+ * stripping (see `DefaultPropsFrom` for why those exist there but not here). */
748
+ type DeclaredPropsFrom<O> = O extends {
749
+ props: infer Props extends object | undefined;
750
+ } ? [NonNullable<Props>] extends [never] ? never : NonNullable<Props> & AnyRecord : never;
751
+ /** What can be inferred from `defaults` — partial at best, since a default only proves a prop
752
+ * *has* one, not that it's the complete prop set. `Partial`: a defaulted prop is optional to the
753
+ * caller by definition. `data-*` keys are dropped — every adapter has its own passthrough for
754
+ * those already (finding #43). */
755
+ type DefaultPropsFrom<O> = O extends {
756
+ defaults: infer Props extends AnyRecord;
757
+ } ? Partial<WidenShallow<Omit<Props, Extract<keyof Props, `data-${string}`>>>> : never;
758
+ /** Declared beats defaulted beats nothing. `[X] extends [never]`, not bare `X extends never` —
759
+ * tuple-wrapped so the check doesn't distribute if `X` is ever a union containing `never`. */
760
+ type ContractPropsFrom<O> = [DeclaredPropsFrom<O>] extends [never] ? [DefaultPropsFrom<O>] extends [never] ? EmptyRecord : DefaultPropsFrom<O> : DeclaredPropsFrom<O>;
761
+ type ContractVariantsFrom<O> = O extends {
762
+ styling: {
763
+ variants: infer V extends Readonly<VariantMap>;
764
+ };
765
+ } ? V : Readonly<EmptyRecord>;
766
+ type ContractPresetFrom<O> = O extends {
767
+ styling: {
768
+ presets: infer TPreset extends RecipeMap<VariantMap>;
769
+ };
770
+ } ? TPreset : Readonly<EmptyRecord>;
771
+ type ContractPluginFrom<O> = O extends {
772
+ styling: {
773
+ plugin: infer TPlugin extends AnyClassPluginFactory;
774
+ };
775
+ } ? TPlugin : AnyClassPluginFactory;
776
+ type ContractAllowedFrom<O> = O extends {
777
+ enforcement: {
778
+ allowedAs: readonly (infer TAllowed extends ElementType)[];
779
+ };
780
+ } ? TAllowed : ElementType;
781
+ /** The six derivations above, assembled — the direct input to `ContractModel`. */
782
+ type ContractDimensions<O> = {
783
+ readonly tag: ContractTagFrom<O>;
784
+ readonly props: ContractPropsFrom<O>;
785
+ readonly variants: ContractVariantsFrom<O>;
786
+ readonly preset: ContractPresetFrom<O>;
787
+ readonly plugin: ContractPluginFrom<O>;
788
+ readonly allowed: ContractAllowedFrom<O>;
789
+ };
790
+ /**
791
+ * Builds a `ContractModel` from a raw literal `O` — the fallback path `ContractModelOf<C>` uses
792
+ * when `C` never went through `defineContract` (no `__model` marker to read directly), and what
793
+ * `defineContract` itself attaches as that marker for a `C` that did.
794
+ */
795
+ type ContractModelFrom<O> = ContractDimensions<O> extends (infer D extends ContractDimensions<O>) ? ContractModel<D['tag'], D['props'], D['variants'], D['preset'], D['plugin'], D['allowed']> : never;
796
+ /**
797
+ * Resolves "does `C` carry a real `ContractModel` already, or do we need to build one from its raw
798
+ * shape" — every `Contract*Of` accessor (`contract-of.ts`) is a one-line projection off this.
799
+ */
800
+ type ContractModelOf<C> = C extends HasContractModel<infer M> ? M : ContractModelFrom<C>;
801
+ //#endregion
802
+ //#region ../../lib/primitive/src/types/factory/contract-of.d.ts
803
+ /**
804
+ * `FactoryOptions`-level accessor family, mirroring `polymorphic-generics.ts`'s `*Of<T>`
805
+ * convention (`DefaultOf<G>`, `PropsOf<G>`, etc.) but applied one layer up, to a contract itself
806
+ * rather than to the `PolymorphicGenerics` an adapter derives from it.
807
+ *
808
+ * Named with a `Contract` prefix specifically to avoid colliding with `polymorphic-generics.ts`'s
809
+ * own `PropsOf`/`VariantsOf`/`RecipeOf`/`AllowedOf`/`DefaultOf` — both families are re-exported
810
+ * from `@praxis-kit/core`, so a name clash would be a real conflict, not a style nit.
811
+ *
812
+ * Each accessor is a trivial projection off `ContractModelOf<C>` (`contract-model.ts`) — the one
813
+ * place that resolves "does `C` carry a real `ContractModel` (via `defineContract`) or does one
814
+ * need reconstructing from `C`'s raw shape," so every accessor shares one implementation of that
815
+ * resolution rather than repeating it. See `contract-model.ts`'s own doc comments for the
816
+ * `ContractXFrom<O>` derivation each of these ultimately reads through, and `DECISIONS.md`'s
817
+ * `defineContract` entry for the design history behind the required-pattern-match technique.
818
+ */
819
+ type ContractTagOf<C extends FactoryOptions> = ContractModelOf<C>['tag'];
820
+ /** See this file's own doc comment. Best-effort when `C` has no `ContractModel` marker — see
821
+ * `ContractPropsFrom`'s own doc comment for why. */
822
+ type ContractPropsOf<C extends FactoryOptions> = ContractModelOf<C>['props'];
823
+ /** See this file's own doc comment. */
824
+ type ContractVariantsOf<C extends FactoryOptions> = ContractModelOf<C>['variants'];
825
+ /** See this file's own doc comment. */
826
+ type ContractPresetOf<C extends FactoryOptions> = ContractModelOf<C>['preset'];
827
+ /** See this file's own doc comment. */
828
+ type ContractPluginOf<C extends FactoryOptions> = ContractModelOf<C>['plugin'];
829
+ //#endregion
830
+ //#region ../../lib/primitive/src/types/factory/contract-generics.d.ts
831
+ /**
832
+ * The canonical projection from a defined contract `C` to the `PolymorphicGenerics` shape every
833
+ * adapter's prop types are built from — the one place "G" gets computed, so it can no longer
834
+ * silently drift per adapter the way today's hand-assembled `PolymorphicGenerics<...>` instantiation
835
+ * at each `createContractComponent` call site can (see `ContractGenericsWithAllowedOf` below for
836
+ * the one confirmed instance of that drift).
837
+ *
838
+ * Folds the class-resolution plugin's own contributed props (`ExtractPluginProps<TPlugin>`) into
839
+ * `props` here, once, rather than leaving each adapter's `ContractProps` to re-derive that merge
840
+ * via its own distributive conditional type on every read — the root cause of the ~22-member
841
+ * layout-union bug PR #95 patched per-adapter (see `DECISIONS.md`'s `defineContract` entry).
842
+ */
843
+ type ContractGenericsOf<C extends FactoryOptions> = PolymorphicGenerics<ContractTagOf<C>, MergeRecords<ContractPropsOf<C>, ExtractPluginProps<ContractPluginOf<C>>>, ContractVariantsOf<C>, ContractPresetOf<C>>;
844
+ //#endregion
690
845
  //#region ../../lib/primitive/src/types/polymorphic-runtime/resolve-aria-fn.d.ts
691
846
  type ResolveAriaFn = <P extends IntrinsicProps>(tag: ElementType, props: P, extraProps?: IntrinsicProps) => {
692
847
  props: P;
@@ -829,15 +984,21 @@ declare class SlotValidator extends InvariantBase {
829
984
  assertSingleChild(count: number): void;
830
985
  }
831
986
  //#endregion
832
- //#region ../../lib/adapter-utils/src/runtime/define-component.d.ts
833
- export declare function defineContractComponent<O extends FactoryOptions>(options: O): <R>(factory: (options: O) => R) => R;
834
- //#endregion
835
987
  //#region ../../adapters/svelte/src/types/primitives.d.ts
836
988
  type UnknownProps = AnyRecord;
837
989
  type ResolvedProps = Readonly<UnknownProps>;
838
990
  //#endregion
839
991
  //#region ../../adapters/svelte/src/svelte-options.d.ts
840
- type SvelteFactoryOptions<TDefault extends ElementType, Props extends UnknownProps, Variants extends Readonly<VariantMap>, TPreset extends RecipeMap<Variants> = NoPreset, TPlugin extends AnyClassPluginFactory = AnyClassPluginFactory> = FactoryOptions<TDefault, Props, Variants, TPreset, TPlugin> & {
992
+ /**
993
+ * Every generic parameter has a default (widened to that parameter's own *bound*, matching
994
+ * a wide-bound, type-erased philosophy, not `FactoryOptions`'s own narrower `EmptyRecord`-style
995
+ * defaults) so `SvelteFactoryOptions` can be used bare, as `createContractComponent`'s single
996
+ * `C extends SvelteFactoryOptions` constraint — see `ReactFactoryOptions`'s identical fix for the
997
+ * same reason. Unlike every other adapter's `*FactoryOptions`, none of these five had a default at
998
+ * all before this — `createContractComponent`'s old 7-generic signature always supplied them
999
+ * itself, so nothing here needed to compile bare until Phase 2 of the `defineContract` refactor.
1000
+ */
1001
+ type SvelteFactoryOptions<TDefault extends ElementType = ElementType, Props extends UnknownProps = AnyRecord, Variants extends Readonly<VariantMap> = Readonly<VariantMap>, TPreset extends RecipeMap<Variants> = RecipeMap<Variants>, TPlugin extends AnyClassPluginFactory = AnyClassPluginFactory> = FactoryOptions<TDefault, Props, Variants, TPreset, TPlugin> & {
841
1002
  /**
842
1003
  * Return true for any prop key that should be consumed but not forwarded to the DOM.
843
1004
  * Receives `runtime.options.variantKeys` as a convenience if needed.
@@ -986,9 +1147,18 @@ type ResolvedSlotProps<G extends PolymorphicGenerics> = Partial<OmitIndexSignatu
986
1147
  * the same way on a plain bundle as on a component function/class, so `Card.Header` is itself
987
1148
  * just another bundle, passed to its own `<Polymorphic bundle={Card.Header}>`. Pass `onElement`
988
1149
  * to run setup once the real DOM element exists.
1150
+ *
1151
+ * `TDefault`/`Props`/`Variants`/`TPreset` are each `ContractXOf<C>`-derived *defaults* on this
1152
+ * function's own type parameter list, mirroring every other adapter's identical fix — see
1153
+ * `@praxis-kit/react`'s own doc comment for why. The biggest reduction of any adapter (7 generics
1154
+ * down to `C` + `TSubComponents`): the old `TOptions extends WithChildRules` parameter — needed by
1155
+ * `BuiltRuntime<G, TOptions>` to conditionally include `childrenEvaluator` based on the *literal*
1156
+ * `enforcement.children`/`exclusiveChildren`/`allowText` shape — was never anything but a
1157
+ * self-referential reconstruction of the same options type `C` now *is* directly, so it's simply
1158
+ * `C` itself below, not a separate parameter.
989
1159
  */
990
- export declare function createContractComponent<TDefault extends ElementType, Props extends UnknownProps = EmptyRecord, Variants extends Readonly<VariantMap> = NoVariants, TPreset extends RecipeMap<Variants> = NoPreset, TPlugin extends AnyClassPluginFactory = AnyClassPluginFactory, TSubComponents extends Readonly<AnyRecord> = EmptyRecord, TOptions extends WithChildRules = SvelteFactoryOptions<TDefault, MergeRecords<Props, ExtractPluginProps<TPlugin>>, Variants, TPreset>>(options: SvelteFactoryOptions<TDefault, Props, Variants, TPreset, TPlugin> & TOptions & {
1160
+ export declare function createContractComponent<C extends SvelteFactoryOptions, TDefault extends ElementType = ContractTagOf<C>, Props extends UnknownProps = ContractPropsOf<C>, Variants extends Readonly<VariantMap> = ContractVariantsOf<C>, TPreset extends RecipeMap<VariantMap> = ContractPresetOf<C>, TSubComponents extends Readonly<AnyRecord> = EmptyRecord>(options: C & {
991
1161
  readonly subComponents?: TSubComponents;
992
- }): MergeRecords<BuiltRuntime<PolymorphicGenerics<TDefault, MergeRecords<Props, ExtractPluginProps<TPlugin>>, Variants, TPreset>, TOptions>, TSubComponents>;
1162
+ }): MergeRecords<BuiltRuntime<ContractGenericsOf<C>, C>, TSubComponents>;
993
1163
  //#endregion
994
- export type { AnyBuiltRuntime, AnyFactoryOptions, BuiltRuntime, ElementType, EmptyRecord, FactoryOptions, GenericsOf, PolymorphicComponentProps, PolymorphicGenerics, ResolvedSlotProps, SvelteFactoryOptions };
1164
+ export type { AnyBuiltRuntime, BuiltRuntime, ElementType, EmptyRecord, FactoryOptions, GenericsOf, PolymorphicComponentProps, PolymorphicGenerics, ResolvedSlotProps, SvelteFactoryOptions };