UNPKG

react-modal-sheet

Version:

Flexible bottom sheet component for your React apps

193 lines (187 loc) 6.58 kB
import { EasingDefinition, motion, MotionProps, MotionValue } from 'motion/react'; import { ForwardRefExoticComponent, ReactNode, ComponentPropsWithoutRef, RefAttributes, FunctionComponent, HTMLAttributes, RefObject } from 'react'; type SheetDetent = 'default' | 'full' | 'content'; type CommonProps = { className?: string; unstyled?: boolean; }; type MotionCommonProps = Omit<ComponentPropsWithoutRef<typeof motion.div>, 'initial' | 'animate' | 'exit'>; interface SheetTweenConfig { ease: EasingDefinition; duration: number; } type SheetProps = { unstyled?: boolean; avoidKeyboard?: boolean; children: ReactNode; detent?: SheetDetent; disableDismiss?: boolean; disableDrag?: boolean; disableScrollLocking?: boolean; dragCloseThreshold?: number; dragVelocityThreshold?: number; initialSnap?: number; isOpen: boolean; modalEffectRootId?: string; modalEffectThreshold?: number; mountPoint?: Element; prefersReducedMotion?: boolean; snapPoints?: number[]; tweenConfig?: SheetTweenConfig; onClose: () => void; onCloseEnd?: () => void; onCloseStart?: () => void; onOpenEnd?: () => void; onOpenStart?: () => void; onSnap?: (index: number) => void; } & MotionCommonProps; type SheetContainerProps = MotionCommonProps & CommonProps & { children: ReactNode; }; type SheetHeaderProps = MotionCommonProps & CommonProps & { children?: ReactNode; disableDrag?: boolean; }; type SheetContentProps = MotionCommonProps & CommonProps & { disableDrag?: boolean | ((args: SheetStateInfo) => boolean); disableScroll?: boolean | ((args: SheetStateInfo) => boolean); scrollRef?: RefObject<HTMLDivElement | null>; scrollClassName?: string; scrollStyle?: MotionProps['style']; }; type SheetBackdropProps = MotionCommonProps & CommonProps; type SheetDragIndicatorProps = HTMLAttributes<HTMLDivElement> & CommonProps; type SheetStateInfo = { scrollPosition?: 'top' | 'bottom' | 'middle'; currentSnap?: number; }; type SheetSnapPoint = { snapIndex: number; snapValue: number; snapValueY: number; }; type SheetComponent = ForwardRefExoticComponent<SheetProps & RefAttributes<any>>; type ContainerComponent = ForwardRefExoticComponent<SheetContainerProps & RefAttributes<any>>; type HeaderComponent = ForwardRefExoticComponent<SheetHeaderProps & RefAttributes<any>>; type BackdropComponent = ForwardRefExoticComponent<SheetBackdropProps & RefAttributes<any>>; type ContentComponent = ForwardRefExoticComponent<SheetContentProps & RefAttributes<any>>; interface SheetCompoundComponent { Container: ContainerComponent; Header: HeaderComponent; DragIndicator: FunctionComponent<SheetDragIndicatorProps>; Content: ContentComponent; Backdrop: BackdropComponent; } type SheetCompound = SheetComponent & SheetCompoundComponent; type UseScrollPositionOptions = { /** * Debounce delay in ms for scroll event handling. * @default 32 */ debounceDelay?: number; /** * Enable or disable the hook entirely. * @default true */ isEnabled?: boolean; }; /** * Hook to track the scroll position of an element. * * The scroll position can be 'top', 'bottom', 'middle', or undefined if the content is not scrollable. * The hook provides a `scrollRef` callback to assign to the scrollable element. * * Note that the scroll position is only updated when the user stops scrolling * for a short moment (debounced). You can set `debounceDelay` to `0` to disable debouncing entirely. * * @param options Configuration options for the hook. * @returns An object containing the `scrollRef` callback and the current `scrollPosition`. * * @example * ```tsx * import { useScrollPosition } from 'react-modal-sheet'; * * function MyComponent() { * const { scrollRef, scrollPosition } = useScrollPosition(); * * return ( * <div> * <p>Scroll position: {scrollPosition}</p> * <div ref={scrollRef} style={{ overflowY: 'auto', maxHeight: '300px' }}> * ...long content... * </div> * </div> * ); * } * ``` */ declare function useScrollPosition(options?: UseScrollPositionOptions): { scrollRef: (element: HTMLElement | null) => void; scrollPosition: "top" | "bottom" | "middle" | undefined; }; type UseVirtualKeyboardOptions = { /** * Ref to the container element to apply `keyboard-inset-height` CSS variable updates. * @default document.documentElement */ containerRef?: RefObject<HTMLElement | null>; /** * Enable or disable the hook entirely. * @default true */ isEnabled?: boolean; /** * Minimum pixel height difference to consider the keyboard visible. * @default 100 */ visualViewportThreshold?: number; /** * Whether to treat contenteditable elements as text inputs. * @default true */ includeContentEditable?: boolean; /** * Delay in ms for debouncing viewport changes. * @default 100 */ debounceDelay?: number; }; /** * A hook that detects virtual keyboard visibility and height. * It listens to focus events and visual viewport changes to determine * if a text input is focused and the keyboard is likely visible. * * It also sets the `--keyboard-inset-height` CSS variable on the specified container * (or `:root` by default) to allow for easy styling adjustments when the keyboard is open. * * @param options Configuration options for the hook. * @returns An object containing `isKeyboardOpen` and `keyboardHeight`. * * @example * ```tsx * import { useVirtualKeyboard } from 'react-modal-sheet'; * * function MyComponent() { * const { isKeyboardOpen, keyboardHeight } = useVirtualKeyboard(); * * return ( * <div> * <p>Keyboard is {isKeyboardOpen ? 'open' : 'closed'}</p> * <p>Keyboard height: {keyboardHeight}px</p> * </div> * ); * } * ``` */ declare function useVirtualKeyboard(options?: UseVirtualKeyboardOptions): { keyboardHeight: number; isKeyboardOpen: boolean; }; interface SheetRef { y: MotionValue<number>; yInverted: MotionValue<number>; height: number; snapTo: (index: number) => Promise<void>; } declare const Sheet: SheetCompound; export { Sheet, type SheetBackdropProps, type SheetContainerProps, type SheetContentProps, type SheetDetent, type SheetDragIndicatorProps, type SheetHeaderProps, type SheetProps, type SheetRef, type SheetSnapPoint, type SheetStateInfo, type SheetTweenConfig, useScrollPosition, useVirtualKeyboard };