import { RemoteComponentType, IdentifierForRemoteComponent, PropsForRemoteComponent, } from '@remote-ui/types'; type NonOptionalKeys = { [K in keyof T]-?: undefined extends T[K] ? never : K; }[keyof T]; type IfAllOptionalKeys = Obj extends Record< string, never > ? If : NonOptionalKeys extends { length: 0; } ? If : Else; export const ACTION_MOUNT = 0; export const ACTION_INSERT_CHILD = 1; export const ACTION_REMOVE_CHILD = 2; export const ACTION_UPDATE_TEXT = 3; export const ACTION_UPDATE_PROPS = 4; export const UPDATE_INSERT = 0; export const UPDATE_REMOVE = 1; export const KIND_ROOT = 0; export const KIND_COMPONENT = 1; export const KIND_TEXT = 2; export const KIND_FRAGMENT = 3; export type Id = string; export interface ActionArgumentMap { [ACTION_MOUNT]: [(RemoteTextSerialization | RemoteComponentSerialization)[]]; [ACTION_INSERT_CHILD]: [ Id | undefined, number, RemoteTextSerialization | RemoteComponentSerialization, Id | undefined | false, ]; [ACTION_REMOVE_CHILD]: [Id | undefined, number]; [ACTION_UPDATE_TEXT]: [Id, string]; [ACTION_UPDATE_PROPS]: [Id, Record]; } export interface RemoteChannel { ( type: T, ...payload: ActionArgumentMap[T] ): void | Promise; } type AllowedRemoteChildren< Children, Root extends RemoteRoot, > = Children extends RemoteComponentType ? RemoteComponent : never; type ExtractChildren = Type extends RemoteComponentType< string, any, infer Children > ? Children : never; type AllowedChildren< Children extends RemoteComponentType | boolean, Root extends RemoteRoot, AllowString extends boolean = false, > = Children extends true ? RemoteComponent | AllowedTextChildren : Children extends false ? never : | AllowedRemoteChildren | AllowedTextChildren; type AllowedTextChildren< Root extends RemoteRoot, AllowString extends boolean = false, > = AllowString extends true ? RemoteText | string : RemoteText; export interface RemoteRootOptions< AllowedComponents extends RemoteComponentType, > { readonly strict?: boolean; readonly components?: ReadonlyArray; } export interface RemoteRoot< AllowedComponents extends RemoteComponentType< string, any > = RemoteComponentType, AllowedChildrenTypes extends | RemoteComponentType | boolean = true, > { readonly kind: typeof KIND_ROOT; readonly children: ReadonlyArray< AllowedChildren< AllowedChildrenTypes, RemoteRoot > >; readonly options: RemoteRootOptions; append( ...children: AllowedChildren< AllowedChildrenTypes, RemoteRoot, true >[] ): void | Promise; /** * @deprecated use `RemoteRoot.append` instead. */ appendChild( child: AllowedChildren< AllowedChildrenTypes, RemoteRoot, true >, ): void | Promise; removeChild( child: AllowedChildren< AllowedChildrenTypes, RemoteRoot >, ): void | Promise; replaceChildren( ...children: AllowedChildren< AllowedChildrenTypes, RemoteRoot, true >[] ): void | Promise; insertBefore( child: AllowedChildren< AllowedChildrenTypes, RemoteRoot >, before?: AllowedChildren< AllowedChildrenTypes, RemoteRoot > | null, ): void | Promise; /** * @deprecated use `RemoteRoot.insertBefore` instead. */ insertChildBefore( child: AllowedChildren< AllowedChildrenTypes, RemoteRoot >, before: AllowedChildren< AllowedChildrenTypes, RemoteRoot >, ): void | Promise; createComponent( type: Type, ...rest: IfAllOptionalKeys< PropsForRemoteComponent, | [ (PropsForRemoteComponent | null)?, ...AllowedChildren< AllowedChildrenTypes, RemoteRoot, true >[], ] | [ (PropsForRemoteComponent | null)?, AllowedChildren< AllowedChildrenTypes, RemoteRoot, true >[]?, ], | [ PropsForRemoteComponent, ...AllowedChildren< AllowedChildrenTypes, RemoteRoot, true >[], ] | [ PropsForRemoteComponent, AllowedChildren< AllowedChildrenTypes, RemoteRoot, true >[]?, ] > ): RemoteComponent>; createText( text?: string, ): RemoteText>; createFragment(): RemoteFragment< RemoteRoot >; mount(): Promise; } export interface RemoteComponent< Type extends RemoteComponentType, Root extends RemoteRoot, > { readonly kind: typeof KIND_COMPONENT; readonly id: string; readonly type: IdentifierForRemoteComponent; readonly props: PropsForRemoteComponent; readonly remoteProps: PropsForRemoteComponent; readonly children: ReadonlyArray< AllowedChildren, Root> >; readonly root: Root; readonly top: RemoteComponent | Root | null; readonly parent: RemoteComponent | Root | null; remove(): void | Promise; updateProps( props: Partial>, ): void | Promise; append( ...children: AllowedChildren, Root, true>[] ): void | Promise; /** * @deprecated use `RemoteComponent.append` instead. */ appendChild( child: AllowedChildren, Root, true>, ): void | Promise; removeChild( child: AllowedChildren, Root>, ): void | Promise; replaceChildren( ...children: AllowedChildren, Root, true>[] ): void | Promise; insertBefore( child: AllowedChildren, Root>, before?: AllowedChildren, Root> | null, ): void | Promise; /** * @deprecated use `RemoteComponent.insertBefore` instead. */ insertChildBefore( child: AllowedChildren, Root>, before: AllowedChildren, Root>, ): void | Promise; } export interface RemoteFragment< Root extends RemoteRoot = RemoteRoot, > { readonly kind: typeof KIND_FRAGMENT; readonly id: string; readonly children: ReadonlyArray, Root>>; readonly root: Root; readonly top: RemoteComponent | Root | null; readonly parent: RemoteComponent | Root | null; append( ...children: AllowedChildren, Root, true>[] ): void | Promise; /** * @deprecated use `RemoteComponent.append` instead. */ appendChild( child: AllowedChildren, Root, true>, ): void | Promise; removeChild( child: AllowedChildren, Root>, ): void | Promise; replaceChildren( ...children: AllowedChildren, Root, true>[] ): void | Promise; insertBefore( child: AllowedChildren, Root>, before?: AllowedChildren, Root> | null, ): void | Promise; /** * @deprecated use `RemoteComponent.insertBefore` instead. */ insertChildBefore( child: AllowedChildren, Root>, before: AllowedChildren, Root>, ): void | Promise; } export interface RemoteText> { readonly kind: typeof KIND_TEXT; readonly id: string; readonly text: string; readonly root: Root; readonly top: RemoteComponent | Root | null; readonly parent: RemoteComponent | Root | null; update(text: string): void | Promise; /** * @deprecated use `RemoteText.update` instead. */ updateText(text: string): void | Promise; remove(): void | Promise; } export type RemoteChild> = | RemoteComponent | RemoteText; export type RemoteComponentSerialization< Type extends RemoteComponentType = RemoteComponentType< string, any >, > = { -readonly [K in 'id' | 'type' | 'kind' | 'props']: RemoteComponent< Type, any >[K]; } & { children: (RemoteComponentSerialization | RemoteTextSerialization)[]; }; export type RemoteTextSerialization = { -readonly [K in 'id' | 'text' | 'kind']: RemoteText[K]; }; export type RemoteFragmentSerialization = { -readonly [K in 'id' | 'kind']: RemoteFragment[K]; } & { children: (RemoteComponentSerialization | RemoteTextSerialization)[]; }; export type Serialized = T extends RemoteComponent ? RemoteComponentSerialization : T extends RemoteText ? RemoteTextSerialization : never;