const SelectableButton = ({ selected, ...props }) => {
const [colorMode] = useColorMode();
const { colors } = useTheme();
const focusColor = colors['blue:60'];
let _selectedColor = {
dark: 'blue:60',
light: 'blue:60',
}[colorMode];
_selectedColor = colors[_selectedColor];
const getSelectedProps = {
bg: _selectedColor,
borderColor: _selectedColor,
color: 'white:emphasis',
cursor: 'default',
pointerEvents: 'none',
zIndex: 1,
css: {
'&::before': {
backgroundColor: _selectedColor,
},
'&:focus': {
':not(:active)': {
borderColor: focusColor,
boxShadow: `inset 0 0 0 1px ${focusColor}`,
},
'&::before': {
backgroundColor: focusColor,
},
}
},
_hover: {
bg: _selectedColor,
},
_active: {
bg: _selectedColor,
},
};
return (
<Button
{...(selected && getSelectedProps)}
{...props}
/>
);
};
const useSelection = (defaultValue) => {
const [value, setValue] = React.useState(defaultValue);
const changeBy = (value) => () => setValue(value);
return [value, changeBy];
};
const useToggle = (defaultValue) => {
const [value, setValue] = React.useState(defaultValue);
const toggle = () => setValue(value => !value);
return [value, toggle, setValue];
};
const Divider = (props) => {
const [colorMode] = useColorMode();
const dividerColor = {
dark: 'white:secondary',
light: 'black:secondary',
}[colorMode];
return (
<Box mb="4x" pb="4x" borderBottom={1} borderBottomColor={dividerColor} {...props} />
);
};
const FormGroup = (props) => (
<Box mb="4x">
<Flex display="inline-flex" {...props} />
</Box>
);
function Example() {
const initialFocusRef = React.useRef();
const [colorMode] = useColorMode();
const iconColor = {
dark: 'white:tertiary',
light: 'black:tertiary',
}[colorMode];
const { isOpen, onOpen, onClose } = useDisclosure();
const [placement, changePlacementBy] = useSelection('right');
const [ensureFocus, toggleEnsureFocus] = useToggle(true);
const [autoFocus, toggleAutoFocus] = useToggle(true);
const [backdrop, toggleBackdrop] = useToggle(true);
const [closeOnEsc, toggleCloseOnEsc] = useToggle(true);
const [closeOnOutsideClick, toggleCloseOnOutsideClick, setCloseOnOutsideClick] = useToggle(true);
const [isClosable, toggleIsClosable] = useToggle(true);
const [isOverlayVisible, toggleIsOverlayVisible, setIsOverlayVisible] = useToggle(true);
const [isHeaderVisible, toggleIsHeaderVisible] = useToggle(true);
const [isBodyVisible, toggleIsBodyVisible] = useToggle(true);
const [isFooterVisible, toggleIsFooterVisible] = useToggle(true);
const [isAlertVisible, toggleIsAlertVisible] = useToggle(true);
const [size, changeSizeBy] = useSelection('sm');
return (
<>
<Box>
<Button onClick={onOpen}>
Launch drawer
</Button>
</Box>
<Divider />
<FormGroup>
<ButtonGroup
variant="secondary"
css={{
'> *:not(:first-of-type)': {
marginLeft: -1
}
}}
>
{['left', 'right'].map(value => (
<SelectableButton
key={value}
selected={value === placement}
onClick={changePlacementBy(value)}
minWidth="15x"
>
{value}
</SelectableButton>
))}
</ButtonGroup>
</FormGroup>
<FormGroup>
<ButtonGroup
variant="secondary"
css={{
'> *:not(:first-of-type)': {
marginLeft: -1
}
}}
>
{['auto', 'sm', 'md', 'lg', 'full'].map(value => (
<SelectableButton
key={value}
selected={value === size}
onClick={changeSizeBy(value)}
minWidth="15x"
>
{value}
</SelectableButton>
))}
</ButtonGroup>
</FormGroup>
<FormGroup>
<TextLabel display="flex" alignItems="center">
<Checkbox
checked={ensureFocus}
onChange={toggleEnsureFocus}
/>
<Space width="2x" />
<Text fontFamily="mono" whiteSpace="nowrap">ensureFocus</Text>
</TextLabel>
</FormGroup>
<FormGroup>
<TextLabel display="flex" alignItems="center">
<Checkbox
checked={autoFocus}
disabled={!ensureFocus}
onChange={toggleAutoFocus}
/>
<Space width="2x" />
<Text fontFamily="mono" whiteSpace="nowrap">autoFocus</Text>
</TextLabel>
</FormGroup>
<FormGroup>
<TextLabel display="flex" alignItems="center">
<Checkbox
checked={backdrop}
onChange={(e) => {
const nextBackdrop = !backdrop;
if (!nextBackdrop) {
setCloseOnOutsideClick(false);
setIsOverlayVisible(false);
}
toggleBackdrop(e);
}}
/>
<Space width="2x" />
<Text fontFamily="mono" whiteSpace="nowrap">backdrop</Text>
</TextLabel>
</FormGroup>
<FormGroup>
<TextLabel display="flex" alignItems="center">
<Checkbox
checked={isClosable}
disabled={!closeOnEsc && !closeOnOutsideClick}
onChange={toggleIsClosable}
/>
<Space width="2x" />
<Text fontFamily="mono" whiteSpace="nowrap">isClosable</Text>
</TextLabel>
</FormGroup>
<FormGroup>
<TextLabel display="flex" alignItems="center">
<Checkbox
checked={closeOnEsc}
disabled={!isClosable && !closeOnOutsideClick}
onChange={toggleCloseOnEsc}
/>
<Space width="2x" />
<Text fontFamily="mono" whiteSpace="nowrap">closeOnEsc</Text>
</TextLabel>
</FormGroup>
<FormGroup>
<TextLabel display="flex" alignItems="center">
<Checkbox
checked={closeOnOutsideClick}
disabled={(!isClosable && !closeOnEsc) || !backdrop}
onChange={toggleCloseOnOutsideClick}
/>
<Space width="2x" />
<Text fontFamily="mono" whiteSpace="nowrap">closeOnOutsideClick</Text>
</TextLabel>
</FormGroup>
<FormGroup>
<TextLabel display="flex" alignItems="center">
<Checkbox
checked={isOverlayVisible}
disabled={!backdrop}
onChange={toggleIsOverlayVisible}
/>
<Space width="2x" />
<Text fontFamily="mono" whiteSpace="nowrap">DrawerOverlay</Text>
</TextLabel>
</FormGroup>
<FormGroup>
<TextLabel display="flex" alignItems="center">
<Checkbox checked={isHeaderVisible} onChange={toggleIsHeaderVisible} />
<Space width="2x" />
<Text fontFamily="mono" whiteSpace="nowrap">DrawerHeader</Text>
</TextLabel>
</FormGroup>
<FormGroup>
<TextLabel display="flex" alignItems="center">
<Checkbox checked={isBodyVisible} onChange={toggleIsBodyVisible} />
<Space width="2x" />
<Text fontFamily="mono" whiteSpace="nowrap">DrawerBody</Text>
</TextLabel>
</FormGroup>
<FormGroup>
<TextLabel display="flex" alignItems="center">
<Checkbox checked={isFooterVisible} onChange={toggleIsFooterVisible} />
<Space width="2x" />
<Text fontFamily="mono" whiteSpace="nowrap">DrawerFooter</Text>
</TextLabel>
</FormGroup>
<FormGroup>
<TextLabel display="flex" alignItems="center">
<Checkbox checked={isAlertVisible} onChange={toggleIsAlertVisible} />
<Space width="2x" />
<Text fontFamily="mono" whiteSpace="nowrap">Alert</Text>
</TextLabel>
</FormGroup>
<Slide
in={isOpen}
duration={250}
from={placement}
finalHeight="100vh"
>
{styles => (
<Drawer
ensureFocus={ensureFocus}
autoFocus={autoFocus}
backdrop={backdrop}
initialFocusRef={initialFocusRef}
isClosable={isClosable}
isOpen={true}
closeOnEsc={closeOnEsc}
closeOnOutsideClick={closeOnOutsideClick}
onClose={onClose}
placement={placement}
size={size}
>
{isOverlayVisible && (
<DrawerOverlay opacity={styles.opacity} />
)}
<DrawerContent {...styles}>
{isHeaderVisible && (
<DrawerHeader>
Drawer Title
</DrawerHeader>
)}
{isBodyVisible && (
<DrawerBody>
{isAlertVisible && (
<Alert variant="outline" severity="info" mb="4x" isClosable onClose={() => toggleIsAlertVisible()}>
<Text>This is an info alert</Text>
</Alert>
)}
<Text mb="4x">
You can put any elements you want here.
</Text>
<Grid
templateColumns="auto 1fr"
rowGap="2x"
columnGap="3x"
alignItems="center"
>
<Icon icon="user" color={iconColor} />
<Input ref={initialFocusRef} placeholder="User name" />
<Icon icon="email" color={iconColor} />
<Input placeholder="Email address" />
</Grid>
</DrawerBody>
)}
{isFooterVisible && (
<DrawerFooter>
<Button variant="primary" onClick={onClose} minWidth="20x">
OK
</Button>
<Space width="2x" />
<Button onClick={onClose} minWidth="20x">
Cancel
</Button>
</DrawerFooter>
)}
</DrawerContent>
</Drawer>
)}
</Slide>
</>
);
}
render(<Example />);