UNPKG

@svelte-put/noti

Version:

type-safe and headless async notification builder

112 lines (97 loc) 4.08 kB
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/ban-types */ import { ComponentEvents, ComponentProps, ComponentType, SvelteComponent } from 'svelte'; import { ActionReturn } from 'svelte/action'; import { Readable } from 'svelte/store'; import { NotificationStoreBuilder } from './store'; type NotificationCommonConfig<Variant extends string, Component extends SvelteComponent> = { /** * milliseconds to wait and automatically pop the notification. * Defaults to `3000`. Set to `false` to disable */ timeout?: number | false; /** * id generator for notifications. Defaults to 'uuid'. * * * - counter: use an auto-incremented counter that is scoped to the store * - uuid: use `crypto.randomUUID()`, fallback to `counter` if not available * - callback: a custom function that accepts {@link NotificationInstanceConfig} and returns a string as the id */ id?: | 'counter' | 'uuid' | ((config: Required<Omit<NotificationInstanceConfig<Variant, Component>, 'id'>>) => string); }; /** predefined variant config provided while building a {@link NotificationStore} */ type NotificationVariantConfig< Variant extends string, Component extends SvelteComponent, > = NotificationCommonConfig<Variant, Component> & { /** string variant representing this config, must be unique within a {@link NotificationStore} */ variant: Variant; /** any Svelte component used for rendering notification UI */ component: ComponentType<Component>; /** inferred props from `component` */ props?: Omit<ComponentProps<Component>, 'notification'>; }; /** a resolved config for a {@link NotificationInstance} */ type NotificationInstanceConfig< Variant extends string, Component extends SvelteComponent, > = Required<Omit<NotificationVariantConfig<Variant, Component>, 'id'>> & { id: string; }; type NotificationByVariantPushConfig< Variant extends string, Component extends SvelteComponent, > = NotificationCommonConfig<Variant, Component> & { props?: Omit<ComponentProps<Component>, 'notification'>; }; type NotificationCustomPushConfig<Component extends SvelteComponent> = NotificationCommonConfig< 'custom', Component > & { component: ComponentType<Component>; props?: Omit<ComponentProps<Component>, 'notification'>; }; type NotificationInstance< Variant extends string = string, Component extends SvelteComponent = SvelteComponent, > = NotificationInstanceConfig<Variant, Component> & { /** reference to the rendered notification component */ instance?: Component; /** internal api for resolving a notification, effectively popping it from the stack */ $resolve: ( e: ComponentEvents<Component>['resolve'], ) => Promise<ComponentEvents<Component>['resolve']['detail']>; progress: NotificationProgressStore; }; type NotificationStoreValue = { /** an HTMLElement registered as portal by the `portal` action (use:portal) */ portal: HTMLElement | null; /** the notification stack */ notifications: NotificationInstance<string, SvelteComponent>[]; }; type NotificationStore = ReturnType<NotificationStoreBuilder['build']>; type NotificationProgressStoreValue = { state: 'idle' | 'running' | 'paused' | 'ended'; }; type NotificationProgressStore = Readable<NotificationProgressStoreValue> & { resume: () => void; pause: () => void; stop: () => void; }; type NotificationPortalAttributes = { 'on:noti:push'?: (event: CustomEvent<NotificationInstance<string, SvelteComponent>>) => void; 'on:noti:pop'?: (event: CustomEvent<NotificationInstance<string, SvelteComponent>>) => void; }; type NotificationPortalActionReturn = ActionReturn<NotificationStore, NotificationPortalAttributes>; type NotificationPushOutput<Component extends SvelteComponent = SvelteComponent> = { id: string; /** * return a promise that resolves to a detail, either provided from invocation of {@link NotificationStore} pop method, * or through the CustomEvent detail of the `resolve` event within the notification component */ resolve: () => Promise<ComponentEvents<Component>['resolve']['detail']>; };