import { createVarsResolver, factory, Factory, getDefaultZIndex, getSize, MantineRadius, rem, StylesApiProps, useDirection, useProps, useStyles, } from '../../core'; import { ModalBase, ModalBaseProps, ModalBaseStylesNames } from '../ModalBase'; import { ScrollArea } from '../ScrollArea'; import { MantineTransition } from '../Transition'; import { DrawerProvider, ScrollAreaComponent } from './Drawer.context'; import classes from './Drawer.module.css'; type DrawerPosition = 'bottom' | 'left' | 'right' | 'top'; function getDrawerAlign(position: DrawerPosition | undefined) { switch (position) { case 'top': return 'flex-start'; case 'bottom': return 'flex-end'; default: return undefined; } } function getDrawerFlex(position: DrawerPosition | undefined) { if (position === 'top' || position === 'bottom') { return '0 0 calc(100% - var(--drawer-offset, 0rem) * 2)'; } return undefined; } export type DrawerRootStylesNames = ModalBaseStylesNames; export type DrawerRootCssVariables = { root: | '--drawer-size' | '--drawer-flex' | '--drawer-height' | '--drawer-align' | '--drawer-justify' | '--drawer-offset'; }; export interface DrawerRootProps extends StylesApiProps, ModalBaseProps { /** Scroll area component @default 'div' */ scrollAreaComponent?: ScrollAreaComponent; /** Side of the screen on which drawer will be opened @default 'left' */ position?: DrawerPosition; /** Key of `theme.radius` or any valid CSS value to set `border-radius`, numbers are converted to rem @default 0 */ radius?: MantineRadius; /** Drawer container offset from the viewport end @default 0 */ offset?: number | string; } export type DrawerRootFactory = Factory<{ props: DrawerRootProps; ref: HTMLDivElement; stylesNames: DrawerRootStylesNames; vars: DrawerRootCssVariables; }>; const transitions: Record = { top: 'slide-down', bottom: 'slide-up', left: 'slide-right', right: 'slide-left', }; const rtlTransitions: Record = { top: 'slide-down', bottom: 'slide-up', right: 'slide-right', left: 'slide-left', }; const defaultProps = { closeOnClickOutside: true, withinPortal: true, lockScroll: true, trapFocus: true, returnFocus: true, closeOnEscape: true, keepMounted: false, zIndex: getDefaultZIndex('modal'), position: 'left', } satisfies Partial; const varsResolver = createVarsResolver((_, { position, size, offset }) => ({ root: { '--drawer-size': getSize(size, 'drawer-size'), '--drawer-flex': getDrawerFlex(position), '--drawer-height': position === 'left' || position === 'right' ? undefined : 'var(--drawer-size)', '--drawer-align': getDrawerAlign(position), '--drawer-justify': position === 'right' ? 'flex-end' : undefined, '--drawer-offset': rem(offset), }, })); export const DrawerRoot = factory((_props) => { const props = useProps('DrawerRoot', defaultProps, _props); const { classNames, className, style, styles, unstyled, vars, scrollAreaComponent, position, transitionProps, radius, attributes, ...others } = props; const { dir } = useDirection(); const getStyles = useStyles({ name: 'Drawer', classes, props, className, style, classNames, styles, unstyled, attributes, vars, varsResolver, }); const drawerTransition = (dir === 'rtl' ? rtlTransitions : transitions)[position]; return ( ); }); DrawerRoot.classes = classes; DrawerRoot.varsResolver = varsResolver; DrawerRoot.displayName = '@mantine/core/DrawerRoot';