feat: add dropdown component

This commit is contained in:
Sonny
2024-05-12 20:06:05 +02:00
committed by Sonny
parent 3531038321
commit 0f1dc9b69c
13 changed files with 142 additions and 16 deletions

View File

@@ -0,0 +1,56 @@
import KEYS from '#constants/keys';
import styled from '@emotion/styled';
import { ReactNode, useRef } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import DropdownContainer from '~/components/common/dropdown/dropdown_container';
import DropdownLabel from '~/components/common/dropdown/dropdown_label';
import useClickOutside from '~/hooks/use_click_outside';
import useGlobalHotkeys from '~/hooks/use_global_hotkeys';
import useToggle from '~/hooks/use_modal';
const DropdownStyle = styled.div<{ opened: boolean }>(({ opened, theme }) => ({
cursor: 'pointer',
userSelect: 'none',
position: 'relative',
minWidth: 'fit-content',
width: 'fit-content',
maxWidth: '250px',
backgroundColor: opened ? theme.colors.secondary : theme.colors.background,
padding: '4px',
borderRadius: theme.border.radius,
'&:hover': {
backgroundColor: theme.colors.secondary,
},
'& svg': {
height: '24px',
width: '24px',
},
}));
export default function Dropdown({
children,
label,
}: {
children: ReactNode;
label: ReactNode | string;
}) {
const dropdownRef = useRef<HTMLDivElement>(null);
const { isShowing, toggle, close } = useToggle();
const { globalHotkeysEnabled } = useGlobalHotkeys();
useClickOutside(dropdownRef, close);
useHotkeys(KEYS.ESCAPE_KEY, close, {
enabled: globalHotkeysEnabled,
enableOnFormTags: ['INPUT'],
});
return (
<DropdownStyle opened={isShowing} onClick={toggle} ref={dropdownRef}>
<DropdownLabel>{label}</DropdownLabel>
<DropdownContainer show={isShowing}>{children}</DropdownContainer>
</DropdownStyle>
);
}

View File

@@ -0,0 +1,17 @@
import styled from '@emotion/styled';
const DropdownContainer = styled.div<{ show: boolean }>(({ show, theme }) => ({
position: 'absolute',
top: 'calc(100% + 0.5em)',
right: 0,
minWidth: '175px',
backgroundColor: show ? theme.colors.secondary : theme.colors.background,
border: `2px solid ${theme.colors.secondary}`,
borderRadius: theme.border.radius,
boxShadow: theme.colors.boxShadow,
display: show ? 'flex' : 'none',
flexDirection: 'column',
overflow: 'hidden',
}));
export default DropdownContainer;

View File

@@ -0,0 +1,16 @@
import styled from '@emotion/styled';
const DropdownItem = styled.div(({ theme }) => ({
fontSize: '14px',
padding: '8px 12px',
display: 'flex',
gap: '0.35em',
alignItems: 'center',
borderRadius: theme.border.radius,
'&:hover': {
backgroundColor: theme.colors.background,
},
}));
export default DropdownItem;

View File

@@ -0,0 +1,11 @@
import styled from '@emotion/styled';
const DropdownLabel = styled.p(({ theme }) => ({
height: 'auto',
width: 'auto',
color: theme.colors.font,
display: 'flex',
gap: '0.35em',
}));
export default DropdownLabel;