UNPKG

@corvu/dialog

Version:

Unstyled, accessible and customizable UI primitives for SolidJS

444 lines (432 loc) 21.6 kB
import * as solid_js_web from 'solid-js/web'; import { Portal } from 'solid-js/web'; import * as solid_js from 'solid-js'; import { ValidComponent, JSX, Accessor, Setter, ComponentProps, Component } from 'solid-js'; import { ElementOf, Ref } from '@corvu/utils/dom'; import { DynamicButtonSharedElementProps, DynamicButtonElementProps, DynamicProps } from '@corvu/utils/dynamic'; export { DynamicProps } from '@corvu/utils/dynamic'; type DialogCloseCorvuProps = { /** * The `id` of the dialog context to use. */ contextId?: string; }; type DialogCloseSharedElementProps<T extends ValidComponent = 'button'> = { onClick: JSX.EventHandlerUnion<ElementOf<T>, MouseEvent>; } & DynamicButtonSharedElementProps<T>; type DialogCloseElementProps = DialogCloseSharedElementProps & { 'aria-label': 'close'; 'data-corvu-dialog-close': '' | null; } & DynamicButtonElementProps; type DialogCloseProps<T extends ValidComponent = 'button'> = DialogCloseCorvuProps & Partial<DialogCloseSharedElementProps<T>>; /** Close button that changes the open state to false when clicked. * * @data `data-corvu-dialog-close` - Present on every dialog close element. */ declare const DialogClose: <T extends ValidComponent = "button">(props: DynamicProps<T, DialogCloseProps<T>>) => JSX.Element; type DialogContentCorvuProps = { /** * Whether the dialog content should be forced to render. Useful when using third-party animation libraries. * @defaultValue `false` */ forceMount?: boolean; /** * The `id` of the dialog context to use. */ contextId?: string; }; type DialogContentSharedElementProps<T extends ValidComponent = 'div'> = { ref: Ref<ElementOf<T>>; style: string | JSX.CSSProperties; }; type DialogContentElementProps = DialogContentSharedElementProps & { id: string; role: 'dialog' | 'alertdialog'; tabIndex: '-1'; 'aria-describedby': string | undefined; 'aria-labelledby': string | undefined; 'aria-modal': 'true' | 'false'; 'data-closed': '' | undefined; 'data-open': '' | undefined; 'data-corvu-dialog-content': '' | null; }; type DialogContentProps<T extends ValidComponent = 'div'> = DialogContentCorvuProps & Partial<DialogContentSharedElementProps<T>>; /** Content of the dialog. Can be animated. * * @data `data-corvu-dialog-content` - Present on every dialog content element. * @data `data-open` - Present when the dialog is open. * @data `data-closed` - Present when the dialog is closed. */ declare const DialogContent: <T extends ValidComponent = "div">(props: DynamicProps<T, DialogContentProps<T>>) => JSX.Element; type DialogContextValue = { /** The `role` attribute of the dialog element. */ role: Accessor<'dialog' | 'alertdialog'>; /** Whether the dialog is open. */ open: Accessor<boolean>; /** Change the open state of the dialog. */ setOpen: Setter<boolean>; /** Whether the dialog should be rendered as a modal. */ modal: Accessor<boolean>; /** Whether the dialog should close when the user presses the `Escape` key. */ closeOnEscapeKeyDown: Accessor<boolean>; /** Whether the dialog should be closed if a focus event happens outside the bounds of `<Dialog.Content />`. */ closeOnOutsideFocus: Accessor<boolean>; /** Whether the dialog should be closed if the user interacts outside the bounds of `<Dialog.Content />`. */ closeOnOutsidePointer: Accessor<boolean>; /** Whether `closeOnOutsidePointer` should be triggered on `pointerdown` or `pointerup`. */ closeOnOutsidePointerStrategy: Accessor<'pointerdown' | 'pointerup'>; /** Whether pointer events outside of `<Dialog.Content />` should be disabled. */ noOutsidePointerEvents: Accessor<boolean>; /** Whether scroll outside of the dialog should be prevented. */ preventScroll: Accessor<boolean>; /** Whether the scrollbar of the `<body>` element should be hidden. */ hideScrollbar: Accessor<boolean>; /** Whether padding should be added to the `<body>` element to avoid layout shift. */ preventScrollbarShift: Accessor<boolean>; /** Whether padding or margin should be used to avoid layout shift. */ preventScrollbarShiftMode: Accessor<'padding' | 'margin'>; /** Whether to restore the `<body>` scroll position with `window.scrollTo` to avoid possible layout shift after closing the dialog. */ restoreScrollPosition: Accessor<boolean>; /** Whether the dialog should allow pinch zoom while scroll is disabled. */ allowPinchZoom: Accessor<boolean>; /** Whether the dialog should trap focus. */ trapFocus: Accessor<boolean>; /** Whether the dialog should restore focus to the previous active element when it closes. */ restoreFocus: Accessor<boolean>; /** The element to receive focus when the dialog opens. */ initialFocusEl?: Accessor<HTMLElement | undefined>; /** The element to receive focus when the dialog closes. */ finalFocusEl?: Accessor<HTMLElement | undefined>; /** Whether the dialog content is present. This differes from `open` as it tracks pending animations. */ contentPresent: Accessor<boolean>; /** The ref of the dialog content. */ contentRef: Accessor<HTMLElement | null>; /** Whether the dialog overlay is present. This differes from `open` as it tracks pending animations. */ overlayPresent: Accessor<boolean>; /** The ref of the dialog overlay. */ overlayRef: Accessor<HTMLElement | null>; /** The `id` attribute of the dialog element. */ dialogId: Accessor<string>; /** The `id` attribute of the dialog label element. Is undefined if no `Dialog.Label` is present. */ labelId: Accessor<string | undefined>; /** The `id` attribute of the dialog description element. Is undefined if no `Dialog.Description` is present. */ descriptionId: Accessor<string | undefined>; }; /** Context which exposes various properties to interact with the dialog. Optionally provide a contextId to access a keyed context. */ declare const useDialogContext: (contextId?: string) => DialogContextValue; type DialogDescriptionCorvuProps = { /** * The `id` of the dialog context to use. */ contextId?: string; }; type DialogDescriptionSharedElementProps<T extends ValidComponent = 'p'> = {}; type DialogDescriptionElementProps = DialogDescriptionSharedElementProps & { id: string | undefined; 'data-corvu-dialog-description': '' | null; }; type DialogDescriptionProps<T extends ValidComponent = 'p'> = DialogDescriptionCorvuProps & Partial<DialogDescriptionSharedElementProps<T>>; /** Description element to announce the dialog to accessibility tools. * * @data `data-corvu-dialog-description` - Present on every dialog description element. */ declare const DialogDescription: <T extends ValidComponent = "p">(props: DynamicProps<T, DialogDescriptionProps<T>>) => solid_js.JSX.Element; type DialogLabelCorvuProps = { /** * The `id` of the dialog context to use. */ contextId?: string; }; type DialogLabelSharedElementProps<T extends ValidComponent = 'h2'> = {}; type DialogLabelElementProps = DialogLabelSharedElementProps & { id: string | undefined; 'data-corvu-dialog-label': string | null; }; type DialogLabelProps<T extends ValidComponent = 'h2'> = DialogLabelCorvuProps & Partial<DialogLabelSharedElementProps<T>>; /** Label element to announce the dialog to accessibility tools. * * @data `data-corvu-dialog-label` - Present on every dialog label element. */ declare const DialogLabel: <T extends ValidComponent = "h2">(props: DynamicProps<T, DialogLabelProps<T>>) => solid_js.JSX.Element; type DialogOverlayCorvuProps = { /** * Whether the dialog overlay should be forced to render. Useful when using third-party animation libraries. * @defaultValue `false` */ forceMount?: boolean; /** * The `id` of the dialog context to use. */ contextId?: string; }; type DialogOverlaySharedElementProps<T extends ValidComponent = 'div'> = { ref: Ref<ElementOf<T>>; style: string | JSX.CSSProperties; }; type DialogOverlayElementProps = DialogOverlaySharedElementProps & { 'aria-hidden': 'true' | undefined; 'data-closed': '' | undefined; 'data-open': '' | undefined; 'data-corvu-dialog-overlay': '' | null; }; type DialogOverlayProps<T extends ValidComponent = 'div'> = DialogOverlayCorvuProps & Partial<DialogOverlaySharedElementProps<T>>; /** Component which can be used to create a faded background. Can be animated. * * @data `data-corvu-dialog-overlay` - Present on every dialog overlay element. * @data `data-open` - Present when the dialog is open. * @data `data-closed` - Present when the dialog is closed. */ declare const DialogOverlay: <T extends ValidComponent = "div">(props: DynamicProps<T, DialogOverlayProps<T>>) => JSX.Element; type DialogPortalProps = { /** * Whether the dialog portal should be forced to render. Useful when using third-party animation libraries. * @defaultValue `false` */ forceMount?: boolean; /** * The `id` of the dialog context to use. */ contextId?: string; }; /** Portals its children at the end of the body element to ensure that the dialog always rendered on top. */ declare const DialogPortal: (props: DialogPortalProps & ComponentProps<typeof Portal>) => solid_js.JSX.Element; type DialogRootProps = { /** * The `role` attribute of the dialog element. * @defaultValue `'dialog'` */ role?: 'dialog' | 'alertdialog'; /** * Whether the dialog is open. */ open?: boolean; /** * Callback fired when the open state changes. */ onOpenChange?: (open: boolean) => void; /** * Whether the dialog is open initially. * @defaultValue `false` */ initialOpen?: boolean; /** * Whether the dialog should be rendered as a modal. * @defaultValue `true` */ modal?: boolean; /** * Whether the dialog should close when the user presses the `Escape` key. * @defaultValue `true` */ closeOnEscapeKeyDown?: boolean; /** * Callback fired when the user presses the `Escape` key. Can be prevented by calling `event.preventDefault`. */ onEscapeKeyDown?: (event: KeyboardEvent) => void; /** * Whether the dialog should be closed if a focus event happens outside the bounds of `<Dialog.Content />`. * @defaultValue `true` if `trapFocus` is `true`, `false` otherwise */ closeOnOutsideFocus?: boolean; /** * Whether the dialog should be closed if the user interacts outside the bounds of `<Dialog.Content />`. * @defaultValue `true` if `modal` is `true`, `false` otherwise */ closeOnOutsidePointer?: boolean; /** * Whether `closeOnOutsidePointer` should be triggered on `pointerdown` or `pointerup`. * @defaultValue `'pointerup'` */ closeOnOutsidePointerStrategy?: 'pointerdown' | 'pointerup'; /** * Callback fired when a focus event happens outside the bounds of `<Dialog.Content />`. Can only happen if `trapFocus` is set to `false` and can be prevented by calling `event.preventDefault`. */ onOutsideFocus?: (event: CustomEvent) => void; /** * Callback fired when the user interacts outside the bounds of `<Dialog.Content />`. Can be prevented by calling `event.preventDefault`. */ onOutsidePointer?: (event: PointerEvent) => void; /** * Whether pointer events outside of `<Dialog.Content />` should be disabled. * @defaultValue `true` if `modal` is `true`, `false` otherwise */ noOutsidePointerEvents?: boolean; /** * Whether scroll outside of the dialog should be prevented. * @defaultValue `true` if `modal` is `true`, `false` otherwise */ preventScroll?: boolean; /** * Whether the scrollbar of the `<body>` element should be hidden. Only applies if `preventScroll` is `true`. * @defaultValue `true` */ hideScrollbar?: boolean; /** * Whether padding should be added to the `<body>` element to avoid layout shift. * @defaultValue `true` */ preventScrollbarShift?: boolean; /** * Whether padding or margin should be used to avoid layout shift. * @defaultValue `'padding'` */ preventScrollbarShiftMode?: 'padding' | 'margin'; /** * Whether to restore the `<body>` scroll position with `window.scrollTo` to avoid possible layout shift after closing the dialog. * @defaultValue `true` */ restoreScrollPosition?: boolean; /** * Whether the dialog should allow pinch zoom while scroll is disabled. * @defaultValue `true` */ allowPinchZoom?: boolean; /** * Whether the dialog should trap focus. * @defaultValue `true` */ trapFocus?: boolean; /** * Whether the dialog should restore focus to the previous active element when it closes. * @defaultValue `true` */ restoreFocus?: boolean; /** * The element to receive focus when the dialog opens. */ initialFocusEl?: HTMLElement; /** * Callback fired when focus moves into the dialog. Can be prevented by calling `event.preventDefault`. */ onInitialFocus?: (event: Event) => void; /** * The element to receive focus when the dialog closes. */ finalFocusEl?: HTMLElement; /** * Callback fired when focus moves out of the dialog. Can be prevented by calling `event.preventDefault`. */ onFinalFocus?: (event: Event) => void; /** * Callback fired when the dialog content present state changes. */ onContentPresentChange?: (present: boolean) => void; /** * Callback fired when the dialog overlay present state changes. */ onOverlayPresentChange?: (present: boolean) => void; /** * The `id` attribute of the dialog element. * @defaultValue `createUniqueId()` */ dialogId?: string; /** * The `id` attribute of the dialog label element. * @defaultValue `createUniqueId()` */ labelId?: string; /** * The `id` attribute of the dialog description element. * @defaultValue `createUniqueId()` */ descriptionId?: string; /** * The `id` of the dialog context. Useful if you have nested dialogs and want to create components that belong to a dialog higher up in the tree. */ contextId?: string; /** @hidden */ children: JSX.Element | ((props: DialogRootChildrenProps) => JSX.Element); }; /** Props that are passed to the Root component children callback. */ type DialogRootChildrenProps = { /** The `role` attribute of the dialog element. */ role: 'dialog' | 'alertdialog'; /** Whether the dialog is open. */ open: boolean; /** Change the open state of the dialog. */ setOpen: Setter<boolean>; /** Whether the dialog should be rendered as a modal. */ modal: boolean; /** Whether the dialog should close when the user presses the `Escape` key. */ closeOnEscapeKeyDown: boolean; /** Whether the dialog should be closed if a focus event happens outside the bounds of `<Dialog.Content />`. */ closeOnOutsideFocus: boolean; /** Whether the dialog should be closed if the user interacts outside the bounds of the dialog content. */ closeOnOutsidePointer: boolean; /** Whether `closeOnOutsidePointer` should be triggered on `pointerdown` or `pointerup`. */ closeOnOutsidePointerStrategy: 'pointerdown' | 'pointerup'; /** Whether pointer events outside of `<Dialog.Content />` should be disabled. */ noOutsidePointerEvents: boolean; /** Whether scroll outside of the dialog should be prevented. */ preventScroll: boolean; /** Whether the scrollbar of the `<body>` element should be hidden. */ hideScrollbar: boolean; /** Whether padding should be added to the `<body>` element to avoid layout shift. */ preventScrollbarShift: boolean; /** Whether padding or margin should be used to avoid layout shift. */ preventScrollbarShiftMode: 'padding' | 'margin'; /** Whether to restore the `<body>` scroll position with `window.scrollTo` to avoid possible layout shift after closing the dialog. */ restoreScrollPosition: boolean; /** Whether the dialog should allow pinch zoom while scroll is disabled. */ allowPinchZoom: boolean; /** Whether the dialog should trap focus. */ trapFocus: boolean; /** Whether the dialog should restore focus to the previous active element when it closes. */ restoreFocus: boolean; /** The element to receive focus when the dialog opens. */ initialFocusEl?: HTMLElement; /** The element to receive focus when the dialog closes. */ finalFocusEl?: HTMLElement; /** Whether the dialog content is present. This differes from `open` as it tracks pending animations. */ contentPresent: boolean; /** The ref of the dialog content. */ contentRef: HTMLElement | null; /** Whether the dialog overlay is present. This differes from `open` as it tracks pending animations. */ overlayPresent: boolean; /** The ref of the dialog overlay. */ overlayRef: HTMLElement | null; /** The `id` attribute of the dialog description element. */ dialogId: string; /** The `id` attribute of the dialog label element. Is undefined if no `Dialog.Label` is present. */ labelId: string | undefined; /** The `id` attribute of the dialog description element. Is undefined if no `Dialog.Description` is present. */ descriptionId: string | undefined; }; /** Context wrapper for the dialog. Is required for every dialog you create. */ declare const DialogRoot: Component<DialogRootProps>; type DialogTriggerCorvuProps = { /** * The `id` of the dialog context to use. */ contextId?: string; }; type DialogTriggerSharedElementProps<T extends ValidComponent = 'button'> = { onClick: JSX.EventHandlerUnion<ElementOf<T>, MouseEvent>; } & DynamicButtonSharedElementProps<T>; type DialogTriggerElementProps = DialogTriggerSharedElementProps & { 'aria-controls': string; 'aria-expanded': 'true' | 'false'; 'aria-haspopup': 'dialog'; 'data-closed': '' | undefined; 'data-open': '' | undefined; 'data-corvu-dialog-trigger': '' | null; } & DynamicButtonElementProps; type DialogTriggerProps<T extends ValidComponent = 'button'> = DialogTriggerCorvuProps & Partial<DialogTriggerSharedElementProps<T>>; /** Button that changes the open state of the dialog when clicked. * * @data `data-corvu-dialog-trigger` - Present on every dialog trigger element. * @data `data-open` - Present when the dialog is open. * @data `data-closed` - Present when the dialog is closed. */ declare const DialogTrigger: <T extends ValidComponent = "button">(props: DynamicProps<T, DialogTriggerProps<T>>) => JSX.Element; declare const Dialog: solid_js.Component<DialogRootProps> & { Trigger: <T extends solid_js.ValidComponent = "button">(props: DynamicProps<T, DialogTriggerProps<T>>) => solid_js.JSX.Element; Portal: (props: DialogPortalProps & solid_js.ComponentProps<typeof solid_js_web.Portal>) => solid_js.JSX.Element; Overlay: <T extends solid_js.ValidComponent = "div">(props: DynamicProps<T, DialogOverlayProps<T>>) => solid_js.JSX.Element; Content: <T extends solid_js.ValidComponent = "div">(props: DynamicProps<T, DialogContentProps<T>>) => solid_js.JSX.Element; Label: <T extends solid_js.ValidComponent = "h2">(props: DynamicProps<T, DialogLabelProps<T>>) => solid_js.JSX.Element; Description: <T extends solid_js.ValidComponent = "p">(props: DynamicProps<T, DialogDescriptionProps<T>>) => solid_js.JSX.Element; Close: <T extends solid_js.ValidComponent = "button">(props: DynamicProps<T, DialogCloseProps<T>>) => solid_js.JSX.Element; useContext: (contextId?: string) => DialogContextValue; }; export { DialogClose as Close, type DialogCloseCorvuProps as CloseCorvuProps, type DialogCloseElementProps as CloseElementProps, type DialogCloseProps as CloseProps, type DialogCloseSharedElementProps as CloseSharedElementProps, DialogContent as Content, type DialogContentCorvuProps as ContentCorvuProps, type DialogContentElementProps as ContentElementProps, type DialogContentProps as ContentProps, type DialogContentSharedElementProps as ContentSharedElementProps, type DialogContextValue as ContextValue, DialogDescription as Description, type DialogDescriptionCorvuProps as DescriptionCorvuProps, type DialogDescriptionElementProps as DescriptionElementProps, type DialogDescriptionProps as DescriptionProps, type DialogDescriptionSharedElementProps as DescriptionSharedElementProps, DialogLabel as Label, type DialogLabelCorvuProps as LabelCorvuProps, type DialogLabelElementProps as LabelElementProps, type DialogLabelProps as LabelProps, type DialogLabelSharedElementProps as LabelSharedElementProps, DialogOverlay as Overlay, type DialogOverlayCorvuProps as OverlayCorvuProps, type DialogOverlayElementProps as OverlayElementProps, type DialogOverlayProps as OverlayProps, type DialogOverlaySharedElementProps as OverlaySharedElementProps, DialogPortal as Portal, type DialogPortalProps as PortalProps, DialogRoot as Root, type DialogRootChildrenProps as RootChildrenProps, type DialogRootProps as RootProps, DialogTrigger as Trigger, type DialogTriggerCorvuProps as TriggerCorvuProps, type DialogTriggerElementProps as TriggerElementProps, type DialogTriggerProps as TriggerProps, type DialogTriggerSharedElementProps as TriggerSharedElementProps, Dialog as default, useDialogContext as useContext };