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.
- package/dist/{build-runtime-CJ_nQEaZ.js → build-runtime-cNkW-D62.js} +331 -207
- package/dist/contract/index.d.ts +396 -14
- package/dist/contract/index.js +66 -1
- package/dist/eslint/index.js +11 -5
- package/dist/{index-DiPzmjWW.d.ts → index-zJDSXTxL.d.ts} +342 -66
- package/dist/lit/index.d.ts +251 -55
- package/dist/lit/index.js +275 -215
- package/dist/preact/index.d.ts +296 -52
- package/dist/preact/index.js +277 -210
- package/dist/react/index.d.ts +13 -4
- package/dist/react/index.js +22 -72
- package/dist/react/legacy.d.ts +9 -4
- package/dist/react/legacy.js +14 -2
- package/dist/solid/index.d.ts +253 -40
- package/dist/solid/index.js +271 -210
- package/dist/svelte/index.d.ts +203 -33
- package/dist/svelte/index.js +270 -207
- package/dist/tailwind/index.d.ts +12 -1
- package/dist/vite-plugin/index.js +289 -199
- package/dist/vue/index.d.ts +252 -41
- package/dist/vue/index.js +277 -210
- package/dist/web/index.d.ts +271 -53
- package/dist/web/index.js +275 -215
- package/package.json +5 -5
package/dist/web/index.d.ts
CHANGED
|
@@ -31,13 +31,6 @@ type SubComponentMap = Readonly<AnyRecord>;
|
|
|
31
31
|
* editor hovers remain self-descriptive.
|
|
32
32
|
*/
|
|
33
33
|
type NoVariants = Readonly<EmptyRecord>;
|
|
34
|
-
/**
|
|
35
|
-
* Default `TPreset` type for components that declare no named presets.
|
|
36
|
-
*
|
|
37
|
-
* Structurally identical to `Readonly<EmptyRecord>`, but named separately so
|
|
38
|
-
* editor hovers remain self-descriptive.
|
|
39
|
-
*/
|
|
40
|
-
type NoPreset = Readonly<EmptyRecord>;
|
|
41
34
|
/**
|
|
42
35
|
* Fallback for `ExtractPluginProps<TPlugin>` when a plugin contributes no
|
|
43
36
|
* props, including the no-plugin case.
|
|
@@ -46,6 +39,30 @@ type NoPreset = Readonly<EmptyRecord>;
|
|
|
46
39
|
* hovers remain self-descriptive.
|
|
47
40
|
*/
|
|
48
41
|
type NoPluginProps = EmptyRecord;
|
|
42
|
+
/**
|
|
43
|
+
* Determines whether an object type should be treated as empty.
|
|
44
|
+
*
|
|
45
|
+
* `keyof T` ignores call and construct signatures...
|
|
46
|
+
*/
|
|
47
|
+
type IsEmptyRecord<T extends object> = T extends ((...args: never[]) => unknown) ? false : T extends (new (...args: never[]) => unknown) ? false : keyof T extends never ? true : false;
|
|
48
|
+
/**
|
|
49
|
+
* Merges two object types while eliding empty operands.
|
|
50
|
+
*
|
|
51
|
+
* If either operand is {@link EmptyRecord}, the other operand is returned
|
|
52
|
+
* directly instead of producing intersections such as
|
|
53
|
+
* `Component & EmptyRecord` in editor hovers.
|
|
54
|
+
*
|
|
55
|
+
* Unlike a homomorphic mapped type (for example `Simplify<T>`), this preserves
|
|
56
|
+
* call and construct signatures. Many component types are callable objects,
|
|
57
|
+
* and mapped types silently discard those signatures.
|
|
58
|
+
*
|
|
59
|
+
* @remarks
|
|
60
|
+
* Instantiate `MergeRecords` directly. Introducing an intermediate alias for
|
|
61
|
+
* one operand (for example `type C = PolymorphicComponent<G>`) can prevent
|
|
62
|
+
* `IsEmptyRecord` from evaluating eagerly, which breaks assignability under
|
|
63
|
+
* `exactOptionalPropertyTypes`.
|
|
64
|
+
*/
|
|
65
|
+
type MergeRecords<A extends object, B extends object> = IsEmptyRecord<A> extends true ? B : IsEmptyRecord<B> extends true ? A : A & B;
|
|
49
66
|
//#endregion
|
|
50
67
|
//#region ../../lib/primitive/src/types/intrinsic-tag.d.ts
|
|
51
68
|
type IntrinsicTag = keyof HTMLElementTagNameMap;
|
|
@@ -509,16 +526,6 @@ type StylingOptions<V extends Readonly<VariantMap> = Readonly<EmptyRecord>, TPre
|
|
|
509
526
|
type NormalizeFn<Props extends AnyRecord = AnyRecord> = {
|
|
510
527
|
normalize(props: Readonly<Props & IntrinsicProps>): Props & IntrinsicProps;
|
|
511
528
|
}['normalize'];
|
|
512
|
-
/**
|
|
513
|
-
* The type-erased shape of {@link FactoryOptions} — every generic parameter widened to its bound.
|
|
514
|
-
*
|
|
515
|
-
* Use it for a value that must hold *any* factory config (a registry, a generic wrapper). It
|
|
516
|
-
* cannot check `styling.compounds` conditions against the real variant keys/values, because it
|
|
517
|
-
* has forgotten what they are — for that, annotate against `FactoryOptions<...>` with the concrete
|
|
518
|
-
* generics (or `satisfies FactoryOptions<'button', Props, typeof variants>`), which keeps an
|
|
519
|
-
* invalid compound condition a type error rather than a silent no-op.
|
|
520
|
-
*/
|
|
521
|
-
type AnyFactoryOptions = FactoryOptions<ElementType, AnyRecord, VariantMap, RecipeMap<VariantMap>, AnyClassPluginFactory>;
|
|
522
529
|
/**
|
|
523
530
|
* The framework-neutral component-authoring config passed to `createContractComponent` in every
|
|
524
531
|
* adapter: default tag + name, own-prop defaults, a `normalize` transform, `styling` (variants,
|
|
@@ -528,7 +535,9 @@ type AnyFactoryOptions = FactoryOptions<ElementType, AnyRecord, VariantMap, Reci
|
|
|
528
535
|
* `satisfies FactoryOptions<TDefault, Props, typeof variants, ...>` on a config object narrows
|
|
529
536
|
* `styling.compounds` conditions to the real per-variant-key shape — including resolving a
|
|
530
537
|
* boolean-shaped axis (`{ true, false }`) to a real `boolean` — so a condition naming a variant or
|
|
531
|
-
* value that does not exist is a compile error. `
|
|
538
|
+
* value that does not exist is a compile error. Leaving `V` at the bare `VariantMap` instead
|
|
539
|
+
* (whether via `FactoryOptions`'s own default or an explicit erased instantiation) forgets that
|
|
540
|
+
* shape entirely, so the same invalid condition becomes a silent no-op instead.
|
|
532
541
|
*/
|
|
533
542
|
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> = {
|
|
534
543
|
/** The intrinsic tag the component renders by default. Overridable per instance via `as`. */
|
|
@@ -537,6 +546,33 @@ type FactoryOptions<TDefault extends ElementType = ElementType, Props extends An
|
|
|
537
546
|
readonly name?: string;
|
|
538
547
|
/** Values used for the component's own (non-variant) props when the consumer omits them. */
|
|
539
548
|
readonly defaults?: Partial<NoInfer<Props>>;
|
|
549
|
+
/**
|
|
550
|
+
* Optional, type-only declaration of this component's complete own-prop shape — present purely
|
|
551
|
+
* for type recovery, never read at runtime (see `declareProps` in `@praxis-kit/adapter-utils`).
|
|
552
|
+
*
|
|
553
|
+
* `defaults` alone can only prove a prop *has a default*, not that it's the complete prop model
|
|
554
|
+
* a component accepts — a `defaults: { size: 'md' }` component may still take `onClick`,
|
|
555
|
+
* `disabled`, and other props with no default at all, none of which a `defaults`-only recovery
|
|
556
|
+
* can see (see `ContractPropsFrom`'s own doc comment for the general shape of this problem).
|
|
557
|
+
* `props` closes that gap: when present, `ContractPropsOf<C>` / `ContractProps<typeof Component>`
|
|
558
|
+
* recover this declared type directly and exactly, in place of the necessarily-partial,
|
|
559
|
+
* literal-widened recovery `defaults` alone allows.
|
|
560
|
+
*
|
|
561
|
+
* Typed as `object | undefined`, not `NoInfer<Props> | undefined` like `defaults`/`onElement` —
|
|
562
|
+
* deliberately decoupled from this interface's own `Props` generic, unlike those two fields.
|
|
563
|
+
* `defaults`/`onElement` are tied to `Props` because real runtime code reads them against a
|
|
564
|
+
* concretely-resolved `Props` for a real call; `props` is never read at runtime at all (see
|
|
565
|
+
* above), so it has no such need, and tying it to `Props extends AnyRecord` would force every
|
|
566
|
+
* hand-declared prop `interface`/`type` an author passes through `declareProps<Props>()` to
|
|
567
|
+
* structurally satisfy `Record<string, unknown>` — a real TypeScript limitation (a named type
|
|
568
|
+
* without an index signature never satisfies that, even via plain assignment, only a fresh
|
|
569
|
+
* object literal does) that would make this field far more awkward to use for its one real job:
|
|
570
|
+
* carrying an author's own already-precise prop type through untouched. `ContractPropsFrom`
|
|
571
|
+
* (`contract-model.ts`) recovers the real value here structurally, straight off `O`'s own
|
|
572
|
+
* literal type — independent of this field's declared type, same as every other `Contract*From`
|
|
573
|
+
* derivation in that file.
|
|
574
|
+
*/
|
|
575
|
+
readonly props?: object | undefined;
|
|
540
576
|
/**
|
|
541
577
|
* A pure `(props) => props` transform run on every render, after `enforcement.props`'s
|
|
542
578
|
* normalizers see the same input. Use this for component-specific prop shaping — anything
|
|
@@ -591,11 +627,158 @@ type FactoryOptions<TDefault extends ElementType = ElementType, Props extends An
|
|
|
591
627
|
*
|
|
592
628
|
* Return a cleanup function to run when the instance unmounts.
|
|
593
629
|
*/
|
|
594
|
-
readonly onElement?:
|
|
630
|
+
readonly onElement?: {
|
|
631
|
+
onElement(element: ElementForTag<TDefault | TAllowed>, getProps: () => Readonly<Props>): void | (() => void);
|
|
632
|
+
}['onElement'];
|
|
595
633
|
};
|
|
596
634
|
//#endregion
|
|
597
|
-
//#region ../../
|
|
598
|
-
|
|
635
|
+
//#region ../../lib/primitive/src/types/factory/contract-model.d.ts
|
|
636
|
+
/**
|
|
637
|
+
* The pipeline this file implements:
|
|
638
|
+
*
|
|
639
|
+
* ```text
|
|
640
|
+
* O (a raw contract literal)
|
|
641
|
+
* → Contract*From<O> one derivation per dimension, straight off O's own shape
|
|
642
|
+
* → ContractDimensions<O> the six derivations, assembled
|
|
643
|
+
* → ContractModel<...> the same six values, as a required-field carrier
|
|
644
|
+
* → ContractModelOf<C> resolves an already-`defineContract`-ed C's real model,
|
|
645
|
+
* or reconstructs one from a raw C via ContractModelFrom
|
|
646
|
+
* ```
|
|
647
|
+
*
|
|
648
|
+
* See `DECISIONS.md`'s `defineContract` entry for the TypeScript limitations that shaped the
|
|
649
|
+
* derivations below.
|
|
650
|
+
*/
|
|
651
|
+
/**
|
|
652
|
+
* Canonical type-level representation of a contract's dimensions — the contract-level counterpart
|
|
653
|
+
* to `PolymorphicGenerics`. Every field is required, so a field's presence is never ambiguous the
|
|
654
|
+
* way it is on an optional `FactoryOptions` field.
|
|
655
|
+
*/
|
|
656
|
+
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> {
|
|
657
|
+
readonly tag: TDefault;
|
|
658
|
+
readonly props: Props;
|
|
659
|
+
readonly variants: V;
|
|
660
|
+
readonly preset: TPreset;
|
|
661
|
+
readonly plugin: TPlugin;
|
|
662
|
+
readonly allowed: TAllowed;
|
|
663
|
+
}
|
|
664
|
+
/**
|
|
665
|
+
* The phantom-marker shape read back via `T extends HasContractModel<infer M> ? M : ...` — the
|
|
666
|
+
* contract-level counterpart to `lib/contract-props`'s `HasGenerics<G>`. Type-only: never assigned
|
|
667
|
+
* at runtime.
|
|
668
|
+
*
|
|
669
|
+
* `__model` is **required**, not optional like `HasGenerics<G>`'s `__generics?` — an optional field
|
|
670
|
+
* would make `C extends HasContractModel<infer M>` trivially succeed for any `C`, defeating the
|
|
671
|
+
* one thing this marker exists to answer: did `C` really go through `defineContract`?
|
|
672
|
+
*/
|
|
673
|
+
interface HasContractModel<M extends ContractModel = ContractModel> {
|
|
674
|
+
readonly __model: M;
|
|
675
|
+
}
|
|
676
|
+
type ContractTagFrom<O> = O extends {
|
|
677
|
+
tag: infer TDefault extends ElementType;
|
|
678
|
+
} ? TDefault : ElementType;
|
|
679
|
+
/** `'img'` → `string`, `1` → `number`, `true` → `boolean` — undoes `defineContract`'s `const O`
|
|
680
|
+
* literal narrowing so a `defaults` value doesn't become the only value a caller may pass. */
|
|
681
|
+
type WidenLiteral<T> = T extends string ? string : T extends number ? number : T extends boolean ? boolean : T;
|
|
682
|
+
type WidenShallow<T> = { [K in keyof T]: WidenLiteral<T[K]>; };
|
|
683
|
+
/** What the author explicitly declared, via `props: declareProps<Props>()`
|
|
684
|
+
* (`@praxis-kit/adapter-utils`) — used exactly as declared, no `Partial`/widening/`data-*`
|
|
685
|
+
* stripping (see `DefaultPropsFrom` for why those exist there but not here). */
|
|
686
|
+
type DeclaredPropsFrom<O> = O extends {
|
|
687
|
+
props: infer Props extends object | undefined;
|
|
688
|
+
} ? [NonNullable<Props>] extends [never] ? never : NonNullable<Props> & AnyRecord : never;
|
|
689
|
+
/** What can be inferred from `defaults` — partial at best, since a default only proves a prop
|
|
690
|
+
* *has* one, not that it's the complete prop set. `Partial`: a defaulted prop is optional to the
|
|
691
|
+
* caller by definition. `data-*` keys are dropped — every adapter has its own passthrough for
|
|
692
|
+
* those already (finding #43). */
|
|
693
|
+
type DefaultPropsFrom<O> = O extends {
|
|
694
|
+
defaults: infer Props extends AnyRecord;
|
|
695
|
+
} ? Partial<WidenShallow<Omit<Props, Extract<keyof Props, `data-${string}`>>>> : never;
|
|
696
|
+
/** Declared beats defaulted beats nothing. `[X] extends [never]`, not bare `X extends never` —
|
|
697
|
+
* tuple-wrapped so the check doesn't distribute if `X` is ever a union containing `never`. */
|
|
698
|
+
type ContractPropsFrom<O> = [DeclaredPropsFrom<O>] extends [never] ? [DefaultPropsFrom<O>] extends [never] ? EmptyRecord : DefaultPropsFrom<O> : DeclaredPropsFrom<O>;
|
|
699
|
+
type ContractVariantsFrom<O> = O extends {
|
|
700
|
+
styling: {
|
|
701
|
+
variants: infer V extends Readonly<VariantMap>;
|
|
702
|
+
};
|
|
703
|
+
} ? V : Readonly<EmptyRecord>;
|
|
704
|
+
type ContractPresetFrom<O> = O extends {
|
|
705
|
+
styling: {
|
|
706
|
+
presets: infer TPreset extends RecipeMap<VariantMap>;
|
|
707
|
+
};
|
|
708
|
+
} ? TPreset : Readonly<EmptyRecord>;
|
|
709
|
+
type ContractPluginFrom<O> = O extends {
|
|
710
|
+
styling: {
|
|
711
|
+
plugin: infer TPlugin extends AnyClassPluginFactory;
|
|
712
|
+
};
|
|
713
|
+
} ? TPlugin : AnyClassPluginFactory;
|
|
714
|
+
type ContractAllowedFrom<O> = O extends {
|
|
715
|
+
enforcement: {
|
|
716
|
+
allowedAs: readonly (infer TAllowed extends ElementType)[];
|
|
717
|
+
};
|
|
718
|
+
} ? TAllowed : ElementType;
|
|
719
|
+
/** The six derivations above, assembled — the direct input to `ContractModel`. */
|
|
720
|
+
type ContractDimensions<O> = {
|
|
721
|
+
readonly tag: ContractTagFrom<O>;
|
|
722
|
+
readonly props: ContractPropsFrom<O>;
|
|
723
|
+
readonly variants: ContractVariantsFrom<O>;
|
|
724
|
+
readonly preset: ContractPresetFrom<O>;
|
|
725
|
+
readonly plugin: ContractPluginFrom<O>;
|
|
726
|
+
readonly allowed: ContractAllowedFrom<O>;
|
|
727
|
+
};
|
|
728
|
+
/**
|
|
729
|
+
* Builds a `ContractModel` from a raw literal `O` — the fallback path `ContractModelOf<C>` uses
|
|
730
|
+
* when `C` never went through `defineContract` (no `__model` marker to read directly), and what
|
|
731
|
+
* `defineContract` itself attaches as that marker for a `C` that did.
|
|
732
|
+
*/
|
|
733
|
+
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;
|
|
734
|
+
/**
|
|
735
|
+
* Resolves "does `C` carry a real `ContractModel` already, or do we need to build one from its raw
|
|
736
|
+
* shape" — every `Contract*Of` accessor (`contract-of.ts`) is a one-line projection off this.
|
|
737
|
+
*/
|
|
738
|
+
type ContractModelOf<C> = C extends HasContractModel<infer M> ? M : ContractModelFrom<C>;
|
|
739
|
+
//#endregion
|
|
740
|
+
//#region ../../lib/primitive/src/types/factory/contract-of.d.ts
|
|
741
|
+
/**
|
|
742
|
+
* `FactoryOptions`-level accessor family, mirroring `polymorphic-generics.ts`'s `*Of<T>`
|
|
743
|
+
* convention (`DefaultOf<G>`, `PropsOf<G>`, etc.) but applied one layer up, to a contract itself
|
|
744
|
+
* rather than to the `PolymorphicGenerics` an adapter derives from it.
|
|
745
|
+
*
|
|
746
|
+
* Named with a `Contract` prefix specifically to avoid colliding with `polymorphic-generics.ts`'s
|
|
747
|
+
* own `PropsOf`/`VariantsOf`/`RecipeOf`/`AllowedOf`/`DefaultOf` — both families are re-exported
|
|
748
|
+
* from `@praxis-kit/core`, so a name clash would be a real conflict, not a style nit.
|
|
749
|
+
*
|
|
750
|
+
* Each accessor is a trivial projection off `ContractModelOf<C>` (`contract-model.ts`) — the one
|
|
751
|
+
* place that resolves "does `C` carry a real `ContractModel` (via `defineContract`) or does one
|
|
752
|
+
* need reconstructing from `C`'s raw shape," so every accessor shares one implementation of that
|
|
753
|
+
* resolution rather than repeating it. See `contract-model.ts`'s own doc comments for the
|
|
754
|
+
* `ContractXFrom<O>` derivation each of these ultimately reads through, and `DECISIONS.md`'s
|
|
755
|
+
* `defineContract` entry for the design history behind the required-pattern-match technique.
|
|
756
|
+
*/
|
|
757
|
+
type ContractTagOf<C extends FactoryOptions> = ContractModelOf<C>['tag'];
|
|
758
|
+
/** See this file's own doc comment. Best-effort when `C` has no `ContractModel` marker — see
|
|
759
|
+
* `ContractPropsFrom`'s own doc comment for why. */
|
|
760
|
+
type ContractPropsOf<C extends FactoryOptions> = ContractModelOf<C>['props'];
|
|
761
|
+
/** See this file's own doc comment. */
|
|
762
|
+
type ContractVariantsOf<C extends FactoryOptions> = ContractModelOf<C>['variants'];
|
|
763
|
+
/** See this file's own doc comment. */
|
|
764
|
+
type ContractPresetOf<C extends FactoryOptions> = ContractModelOf<C>['preset'];
|
|
765
|
+
/** See this file's own doc comment. */
|
|
766
|
+
type ContractPluginOf<C extends FactoryOptions> = ContractModelOf<C>['plugin'];
|
|
767
|
+
//#endregion
|
|
768
|
+
//#region ../../lib/primitive/src/types/factory/contract-generics.d.ts
|
|
769
|
+
/**
|
|
770
|
+
* The canonical projection from a defined contract `C` to the `PolymorphicGenerics` shape every
|
|
771
|
+
* adapter's prop types are built from — the one place "G" gets computed, so it can no longer
|
|
772
|
+
* silently drift per adapter the way today's hand-assembled `PolymorphicGenerics<...>` instantiation
|
|
773
|
+
* at each `createContractComponent` call site can (see `ContractGenericsWithAllowedOf` below for
|
|
774
|
+
* the one confirmed instance of that drift).
|
|
775
|
+
*
|
|
776
|
+
* Folds the class-resolution plugin's own contributed props (`ExtractPluginProps<TPlugin>`) into
|
|
777
|
+
* `props` here, once, rather than leaving each adapter's `ContractProps` to re-derive that merge
|
|
778
|
+
* via its own distributive conditional type on every read — the root cause of the ~22-member
|
|
779
|
+
* layout-union bug PR #95 patched per-adapter (see `DECISIONS.md`'s `defineContract` entry).
|
|
780
|
+
*/
|
|
781
|
+
type ContractGenericsOf<C extends FactoryOptions> = PolymorphicGenerics<ContractTagOf<C>, MergeRecords<ContractPropsOf<C>, ExtractPluginProps<ContractPluginOf<C>>>, ContractVariantsOf<C>, ContractPresetOf<C>>;
|
|
599
782
|
//#endregion
|
|
600
783
|
//#region ../../lib/adapter-utils/src/types/filter-predicate.d.ts
|
|
601
784
|
/**
|
|
@@ -612,17 +795,20 @@ type RuntimeG<TDefault extends ElementType, Props extends AnyRecord, Variants ex
|
|
|
612
795
|
*/
|
|
613
796
|
type FilterPredicate = (key: string, variantKeys: ReadonlySet<string>) => boolean;
|
|
614
797
|
//#endregion
|
|
615
|
-
//#region ../../lib/adapter-utils/src/runtime/define-component.d.ts
|
|
616
|
-
export declare function defineContractComponent<O extends FactoryOptions>(options: O): <R>(factory: (options: O) => R) => R;
|
|
617
|
-
//#endregion
|
|
618
798
|
//#region ../../adapters/web/src/types/web-options.d.ts
|
|
619
799
|
/**
|
|
620
800
|
* Options accepted by createContractComponent in the web adapter.
|
|
621
801
|
*
|
|
622
802
|
* Identical shape to LitFactoryOptions — a plain HTMLElement subclass with
|
|
623
803
|
* no framework dependency. Light DOM only; Shadow DOM is out of scope.
|
|
804
|
+
*
|
|
805
|
+
* Every generic parameter has a default (widened to that parameter's own *bound*, matching
|
|
806
|
+
* a wide-bound, type-erased philosophy, not `FactoryOptions`'s own narrower `EmptyRecord`-style
|
|
807
|
+
* defaults) so `WebFactoryOptions` can be used bare, as `createContractComponent`'s single
|
|
808
|
+
* `C extends WebFactoryOptions` constraint — see `ReactFactoryOptions`'s identical fix for the
|
|
809
|
+
* same reason.
|
|
624
810
|
*/
|
|
625
|
-
type WebFactoryOptions<TDefault extends ElementType = ElementType, TProps extends AnyRecord =
|
|
811
|
+
type WebFactoryOptions<TDefault extends ElementType = ElementType, TProps extends AnyRecord = AnyRecord, TVariants extends Readonly<VariantMap> = Readonly<VariantMap>, TPreset extends RecipeMap<TVariants> = RecipeMap<TVariants>, TPlugin extends AnyClassPluginFactory = AnyClassPluginFactory> = FactoryOptions<TDefault, TProps, TVariants, TPreset, TPlugin> & {
|
|
626
812
|
readonly filterProps?: FilterPredicate;
|
|
627
813
|
};
|
|
628
814
|
//#endregion
|
|
@@ -641,8 +827,12 @@ type UnknownProps = AnyRecord;
|
|
|
641
827
|
* `G` is a phantom marker only — see `__generics` below — and defaults to the
|
|
642
828
|
* widest `PolymorphicGenerics` so existing two-argument usages of this type keep
|
|
643
829
|
* resolving exactly as before. Mirrors the Lit adapter's `LitContractComponent`.
|
|
830
|
+
*
|
|
831
|
+
* `C` is a second phantom marker — see `__contract` below — added alongside `G`, not replacing
|
|
832
|
+
* it (Phase 3 of the `defineContract` refactor), defaulting to the widest `FactoryOptions` for the
|
|
833
|
+
* same reason. Mirrors `LitContractComponent`'s identical addition.
|
|
644
834
|
*/
|
|
645
|
-
type WebContractComponent<TVariants extends Readonly<VariantMap> = NoVariants, TPluginProps extends AnyRecord = EmptyRecord, G extends PolymorphicGenerics = PolymorphicGenerics> = {
|
|
835
|
+
type WebContractComponent<TVariants extends Readonly<VariantMap> = NoVariants, TPluginProps extends AnyRecord = EmptyRecord, G extends PolymorphicGenerics = PolymorphicGenerics, C extends FactoryOptions = FactoryOptions> = {
|
|
646
836
|
new (): HTMLElement & {
|
|
647
837
|
recipe: string | undefined;
|
|
648
838
|
praxisClass: string | undefined;
|
|
@@ -662,28 +852,45 @@ type WebContractComponent<TVariants extends Readonly<VariantMap> = NoVariants, T
|
|
|
662
852
|
* the file that built it — identical to `LitContractComponent.__generics`.
|
|
663
853
|
*/
|
|
664
854
|
readonly __generics?: G;
|
|
855
|
+
/**
|
|
856
|
+
* Type-only; never assigned at runtime — same rationale as `__generics` above and
|
|
857
|
+
* React's/Preact's `__contract` (see `HasContract<C>`, `@praxis-kit/contract-props`). Carries
|
|
858
|
+
* the *complete* contract this component was built from (`C`, the argument
|
|
859
|
+
* `createContractComponent<C extends WebFactoryOptions>` was actually called with), not just
|
|
860
|
+
* its `PolymorphicGenerics` projection. `GenericsOf`/`ContractProps` (./contract-props) recover
|
|
861
|
+
* `G` *through* this field now (`ContractGenericsOf<C>`), rather than from a separately-computed
|
|
862
|
+
* `G` that never carried plugin-contributed props — see that file's doc comment for the bug this
|
|
863
|
+
* closes. Mirrors `LitContractComponent.__contract`.
|
|
864
|
+
*/
|
|
865
|
+
readonly __contract?: C;
|
|
665
866
|
};
|
|
666
867
|
//#endregion
|
|
667
|
-
//#region ../../lib/contract-props/src/has-
|
|
868
|
+
//#region ../../lib/contract-props/src/has-contract.d.ts
|
|
668
869
|
/**
|
|
669
|
-
* The phantom-marker shape read back via `T extends
|
|
670
|
-
*
|
|
870
|
+
* The phantom-marker shape read back via `T extends HasContract<infer C> ? C : never` — the
|
|
871
|
+
* contract-retention counterpart to `HasGenerics<G>` in this same package. Where `HasGenerics<G>`
|
|
872
|
+
* lets a built component recover the `PolymorphicGenerics` an adapter derived for it,
|
|
873
|
+
* `HasContract<C>` lets it recover the *complete, authoritative contract* (`C`, the argument
|
|
874
|
+
* `createContractComponent<C extends XFactoryOptions>` was actually called with) it was derived
|
|
875
|
+
* from — the two are deliberately separate markers, not one broadened to do both jobs: `G` is
|
|
876
|
+
* "what the adapter needs to implement the component," `C` is "what the component was configured
|
|
877
|
+
* with" (see `DECISIONS.md`'s `defineContract` entry). A component carries both.
|
|
671
878
|
*
|
|
672
|
-
* Type-only: never assigned at runtime
|
|
673
|
-
*
|
|
674
|
-
*
|
|
675
|
-
* assignable — confirmed directly against that adapter's own real component type (see
|
|
676
|
-
* `adapters/react/src/shared/types/polymorphic-props.test.ts`), not reproducible in an isolated
|
|
677
|
-
* minimal mock (see this file's own `has-generics.test.ts`), so treat "inline, not intersected"
|
|
678
|
-
* as an adapter-level implementation detail this package's marker shape must stay compatible
|
|
679
|
-
* with, not a property `HasGenerics<G>` itself enforces.
|
|
879
|
+
* Type-only: never assigned at runtime, same rationale as `HasGenerics<G>` (see that type's own
|
|
880
|
+
* doc comment) — a `createContractComponent` return value gets this shape via a type assertion,
|
|
881
|
+
* not a real property write.
|
|
680
882
|
*
|
|
681
|
-
*
|
|
682
|
-
*
|
|
683
|
-
*
|
|
883
|
+
* Unconstrained (no `C extends FactoryOptions` bound), matching `HasGenerics<G>`'s own choice —
|
|
884
|
+
* this package has no dependency on `@praxis-kit/core`/`@praxis-kit/primitive`, and adding one
|
|
885
|
+
* just to write a bound here isn't worth it: the accessor types that actually consume `C`
|
|
886
|
+
* (`ContractTagOf<C>`, etc., in `@praxis-kit/primitive`) already declare their own constraint.
|
|
887
|
+
*
|
|
888
|
+
* Do **not** "harden" this with a `unique symbol` or other nominal brand, for the same reason
|
|
889
|
+
* `HasGenerics<G>` doesn't: a real component's callable type needs to structurally satisfy this
|
|
890
|
+
* shape by declaring the same inline optional field, not by importing a nominal brand.
|
|
684
891
|
*/
|
|
685
|
-
interface
|
|
686
|
-
readonly
|
|
892
|
+
interface HasContract<C> {
|
|
893
|
+
readonly __contract?: C;
|
|
687
894
|
}
|
|
688
895
|
//#endregion
|
|
689
896
|
//#region ../../adapters/web/src/types/contract-props.d.ts
|
|
@@ -691,14 +898,20 @@ interface HasGenerics<G> {
|
|
|
691
898
|
* Recovers a `WebContractComponent`'s `PolymorphicGenerics` descriptor from its own value type —
|
|
692
899
|
* identical to the Lit adapter's `GenericsOf<T>` (`adapters/lit/src/types/contract-props.ts`),
|
|
693
900
|
* since both adapters build a fixed-identity custom element with the same erased return type.
|
|
694
|
-
* Needs
|
|
695
|
-
* `
|
|
696
|
-
* `
|
|
697
|
-
* type
|
|
698
|
-
*
|
|
699
|
-
*
|
|
901
|
+
* Needs a marker (unlike Svelte's `GenericsOf<T>`) because `createContractComponent` here returns
|
|
902
|
+
* `WebContractComponent<TVariants, TPluginProps, G, C>`, not a `BuiltRuntime<G, TOptions>` —
|
|
903
|
+
* `TDefault`/`TProps`/`TPreset` are genuinely erased from the return type, so there is no ordinary
|
|
904
|
+
* type parameter left to `infer` them back out of.
|
|
905
|
+
*
|
|
906
|
+
* Re-pointed at `__contract` (Phase 4 of the `defineContract` refactor) rather than the
|
|
907
|
+
* separately-computed `__generics` field it used to read — see the Lit adapter's identical doc
|
|
908
|
+
* comment for the full reasoning: `__generics`'s own `G` never folded in plugin-contributed props
|
|
909
|
+
* (`findings.md` #44), and `ContractGenericsOf<C>` fixes that for free by folding
|
|
910
|
+
* `ExtractPluginProps<TPlugin>` into `props` once, at the canonical projection point.
|
|
911
|
+
*
|
|
912
|
+
* Falls back to the widest `PolymorphicGenerics` for any non-praxis-kit value.
|
|
700
913
|
*/
|
|
701
|
-
type GenericsOf<T extends
|
|
914
|
+
type GenericsOf<T extends HasContract<FactoryOptions>> = T extends HasContract<infer C extends FactoryOptions> ? ContractGenericsOf<C> extends (infer G extends PolymorphicGenerics) ? G : PolymorphicGenerics : PolymorphicGenerics;
|
|
702
915
|
/**
|
|
703
916
|
* A component's full prop contract — the attributes a caller can set on the custom element,
|
|
704
917
|
* recovered from outside the file that built it. The Web adapter has exactly one render mode (no
|
|
@@ -728,7 +941,7 @@ type GenericsOf<T extends HasGenerics<PolymorphicGenerics>> = T extends HasGener
|
|
|
728
941
|
* type ButtonProps = ContractProps<typeof Button>
|
|
729
942
|
* ```
|
|
730
943
|
*/
|
|
731
|
-
type ContractProps<T extends
|
|
944
|
+
type ContractProps<T extends HasContract<FactoryOptions>> = Simplify<OmitIndexSignature<PropsOf<GenericsOf<T>>> & OmitIndexSignature<VariantProps<VariantsOf<GenericsOf<T>>>> & DataAttributes & {
|
|
732
945
|
as?: never;
|
|
733
946
|
recipe?: keyof RecipeOf<GenericsOf<T>>;
|
|
734
947
|
}>;
|
|
@@ -815,10 +1028,15 @@ type DataAttributes = {
|
|
|
815
1028
|
* resolve to `options.tag` here, on both the client and SSR paths. Need different semantics for one
|
|
816
1029
|
* instance? Register a second component with a different `tag`, or set `role` directly — both
|
|
817
1030
|
* already work today, unaffected by this.
|
|
1031
|
+
*
|
|
1032
|
+
* `TDefault`/`TProps`/`TVariants`/`TPreset`/`TPlugin` are each `ContractXOf<C>`-derived *defaults*
|
|
1033
|
+
* on this function's own type parameter list, mirroring every other adapter's identical fix — see
|
|
1034
|
+
* `@praxis-kit/react`'s own doc comment for why (computed as function type-parameter defaults, not
|
|
1035
|
+
* inline body computations, which doesn't resolve for a still-abstract `C`).
|
|
818
1036
|
*/
|
|
819
|
-
export declare function createContractComponent<TDefault extends ElementType
|
|
1037
|
+
export declare function createContractComponent<C extends WebFactoryOptions, TDefault extends ElementType = ContractTagOf<C>, TProps extends UnknownProps = ContractPropsOf<C>, TVariants extends Readonly<VariantMap> = ContractVariantsOf<C>, TPreset extends RecipeMap<VariantMap> = ContractPresetOf<C>, TPlugin extends AnyClassPluginFactory = ContractPluginOf<C>, TSubComponents extends Readonly<AnyRecord> = EmptyRecord>(options: C & {
|
|
820
1038
|
readonly subComponents?: TSubComponents;
|
|
821
|
-
}): WebContractComponent<TVariants, ExtractPluginProps<TPlugin>,
|
|
1039
|
+
}): WebContractComponent<TVariants, ExtractPluginProps<TPlugin>, ContractGenericsOf<C>, C> & TSubComponents;
|
|
822
1040
|
//#endregion
|
|
823
1041
|
//#region ../../adapters/web/src/render-to-string.d.ts
|
|
824
1042
|
/**
|
|
@@ -845,4 +1063,4 @@ export declare function createContractComponent<TDefault extends ElementType, TP
|
|
|
845
1063
|
*/
|
|
846
1064
|
export declare function renderContractToString(component: WebContractComponent, props?: UnknownProps, innerHTML?: string): string;
|
|
847
1065
|
//#endregion
|
|
848
|
-
export type {
|
|
1066
|
+
export type { ContractProps, ElementType, EmptyRecord, FactoryOptions, GenericsOf, PolymorphicGenerics, WebContractComponent, WebFactoryOptions };
|