Skip to Content

Modals

Every modals export of @appfunnel-dev/sdk, generated from the SDK source. Signatures and descriptions are exact; for how these fit together, see the guides.

useModal

hook · modals/registry.tsx

useModal(): ModalHandler useModal(modal: string, args?: Record<string, unknown>): ModalHandler useModal<P extends object>(modal: ComponentType<P>, args?: Partial<P>): ModalHandler<P>

component · modals/sheet.tsx

Modal(props: ModalProps): ReactNode

A centered dialog. Auto-binds to its defineModal<Modal>….

Sheet

component · modals/sheet.tsx

Sheet(props: SheetProps): ReactNode

A drawer, or (with variant="floating") a centered card. Inside a defineModal it auto-binds — <Sheet>…; outside one, control it with open/onClose.

defineModal

function · modals/registry.tsx

defineModal<P extends object>(Comp: ComponentType<P>): ComponentType<P & ModalHocProps>

Wrap a component into an id-keyed modal. Inside it, useModal() (no args) gives the handle. Render a controlled <Sheet>/<Modal> with open={m.visible} onClose={m.hide}.

dismissAllModals

function · modals/registry.tsx

dismissAllModals(): void

Close every open modal at once and settle anything awaiting them.

The registry is mounted ABOVE the flow (FunnelProvider renders ModalRoot, FunnelView lives inside it), so a modal a page opened outlives that page — it would otherwise sit on top of the next screen. FunnelView calls this on every page change; authors rarely need it directly.

Pending showModal() promises resolve with undefined rather than hanging forever, so await showModal(...) in a page handler unblocks and can tell “dismissed” from a real result. No-ops when no runtime is mounted (SSR, or a tree rendered without FunnelProvider).

hideModal

function · modals/registry.tsx

hideModal<T = unknown>(modal: string | ComponentType<any>): Promise<T>

Hide a modal. Returns a promise resolved by resolveHide() (post-transition).

registerModal

function · modals/registry.tsx

registerModal(id: string, comp: ComponentType<any>, props?: Record<string, unknown>): void

Register a component as an id-keyed modal so the placeholder can render it.

removeModal

function · modals/registry.tsx

removeModal(modal: string | ComponentType<any>): void

Remove a modal from the tree (frees its state; better than just hiding).

showModal

function · modals/registry.tsx

showModal<T = unknown>(modal: string | ComponentType<any>, args?: Record<string, unknown>): Promise<T>

Show a modal (by component or id). Returns a promise resolved by resolve().

unregisterModal

function · modals/registry.tsx

unregisterModal(id: string): void

ModalHandler

interface · modals/registry.tsx

export interface ModalHandler<Props = Record<string, unknown>> { id: string args?: Record<string, unknown> visible: boolean keepMounted: boolean show: (args?: Props) => Promise<unknown> hide: () => Promise<unknown> remove: () => void resolve: (value?: unknown) => void reject: (value?: unknown) => void resolveHide: (value?: unknown) => void }

The handle useModal() returns to control one modal.

ModalHocProps

interface · modals/registry.tsx

export interface ModalHocProps { id: string defaultVisible?: boolean keepMounted?: boolean }

ModalState

interface · modals/registry.tsx

export interface ModalState { id: string args?: Record<string, unknown> visible?: boolean delayVisible?: boolean keepMounted?: boolean }

ModalProps

type · modals/sheet.tsx

export type ModalProps = OverlayCommon

SheetProps

type · modals/sheet.tsx

export type SheetProps = OverlayCommon & { side?: SheetSide variant?: SheetVariant }

SheetSide

type · modals/sheet.tsx

export type SheetSide = 'bottom' | 'top' | 'left' | 'right'

SheetVariant

type · modals/sheet.tsx

export type SheetVariant = 'edge' | 'floating'

How a <Sheet> presents itself.

  • edge (default) — the classic drawer, flush against the side edge. Every existing consumer is this, unchanged in DOM, geometry and (lack of) motion.
  • floating — a rounded card inset FLOATING_INSET from the viewport, presented two ways by width (see floatingGeometry): bottom-anchored on a phone, centered at FLOATING_WIDTH on a desktop. Both RESERVE their height. Springs in. side does not apply.
Last updated on