import { Atomico, DOMProps } from "./dom.js"; import { ConstructorType, FillObject, NoTypeFor, SchemaInfer, SchemaProps, Type, TypeCustom, TypeForInstance, TypeForJsx } from "./schema.js"; import { Sheets } from "./css.js"; /** * Infer the types from `component.props`. * ```tsx * function component({value}: Props){ * return * } * * component.props = {value:Number} * ``` */ export type GetProps = P extends { readonly "##props"?: infer P; } ? P : P extends { props: SchemaProps } ? GetProps : { [K in GetKeysWithConfigValue

]: GetPropType; } & { [K in GetKeysWithoutConfigValue

]?: GetPropType; }; type GetKeysWithConfigValue

= { [I in keyof P]-?: P[I] extends { value: any; } ? I : never; }[keyof P]; type GetKeysWithoutConfigValue

= { [I in keyof P]-?: P[I] extends { value: any; } ? never : I; }[keyof P]; type GetPropType = Value extends { type: infer T; value: infer V; } ? T extends TypeCustom ? ConstructorType : FunctionConstructor extends T ? V : V extends () => infer T ? T : V : Value extends { type: infer T } ? ConstructorType : Type extends Value // Sometimes TS saturates, this verification limits the effort of TS to infer ? Value extends Type ? R : ConstructorType : ConstructorType; /** * metaProps allow to hide the props assigned by Component */ interface MetaProps { readonly "##props"?: Props; } /** * The MetaComponent type allows to identify as * validate types generated by Component */ export interface MetaComponent { (props: any): any; props: MetaProps; styles?: Sheets; render?: (props: any) => any; } /** * Infers the props from the component's props object, example: * ### Syntax * ```tsx * const myProps = { message: String } * Props; * // {message: string} * ``` * ### Usage * You can use the `Prop` type on components, objects or constructors, example: * ```tsx * function component({message}: Props){ * return * } * * component.props = {message: String} * ``` * * ### Advanced use * * It also allows to replace types of those already inferred, example: * ```tsx * Props; * // {message?: "hello"|"bye bye"} * * ``` */ export type Props

= P extends null ? SchemaProps : GetProps; export type Component = Props extends null ? { (props: FillObject): Host; props?: SchemaProps; styles?: Sheets; } : { (props: DOMProps): Host; props: SchemaInfer & MetaProps< Meta extends null ? Props : Props & SyntheticMetaProps >; styles?: Sheets; }; export type CreateElement = CheckMeta extends true ? C extends (props: any) => Host ? CreateElement }, Base, false> : CreateElement : C extends { props: infer P } ? Atomico, Props, Base> : Atomico<{}, {}, Base>; export type SyntheticProps = { [Prop in keyof Props]: Prop extends `on${string}` ? { type: Function; value: (event: Props[Prop]) => any; } : { type: Function; value: Props[Prop]; }; }; export type SyntheticMetaProps = { [Prop in keyof Meta]?: Prop extends `on${string}` ? (event: Meta[Prop]) => any : Meta[Prop]; }; export type Host = {}; export type ComponentOptions = { props?: SchemaProps; styles?: Sheets; base?: CustomElementConstructor; }; export function c< Component extends (props: Props) => Host, Options extends ComponentOptions >( fn: Component, options: Options ): CreateElement< Component & { props: Options["props"]; sheets: Options["styles"]; }, Options extends { base: infer BaseElement; } ? BaseElement : typeof HTMLElement >; export function c< FnComponent extends Component | MetaComponent, BaseElement extends typeof HTMLElement >( component: FnComponent, baseElement?: BaseElement ): CreateElement;