diff --git a/stories/Button.scss b/stories/Button.scss index e489d25..7758cd8 100644 --- a/stories/Button.scss +++ b/stories/Button.scss @@ -38,7 +38,7 @@ a.button { position: relative; height: $min-component-size; - font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; + font-family: $font-family; font-weight: 700; font-size: 15px; border: 0; diff --git a/stories/Button.tsx b/stories/Button.tsx index 994d84f..08bc770 100644 --- a/stories/Button.tsx +++ b/stories/Button.tsx @@ -45,9 +45,9 @@ export function Button({ )} layout={Layout.Horizontal} type={'button'} - onClick={() => { + onClick={onClick ? () => { if (!isDisabled) onClick() - }} + } : null} {...props} > * { + padding: $padding; + } + } + + &:not(.visible) .list { + pointer-events: none; + } + + &.visible .list { + transform: translateY(0); + opacity: 1; + } +} + +.dropdownItem { + color: inherit; + text-decoration: none; + position: relative; + + &.clickable { + @include hover(); + + cursor: pointer; + } +} diff --git a/stories/Dropdown.stories.tsx b/stories/Dropdown.stories.tsx new file mode 100644 index 0000000..223362c --- /dev/null +++ b/stories/Dropdown.stories.tsx @@ -0,0 +1,36 @@ +import React from 'react'; + +import { Dropdown, DropdownItem, DropdownProps } from './Dropdown'; +import { Button } from './Button'; +import { Alignment } from './constants'; + +export default { + title: 'Components/Dropdown', + component: Dropdown, +}; + +const Template = (args: DropdownProps) => ; +export const Simple = Template.bind({}); +Simple.args = { + align: Alignment.Left, + children: ( + <> + + One + + + Two + + + Three + + + ), + button: , +}; diff --git a/stories/Dropdown.tsx b/stories/Dropdown.tsx new file mode 100644 index 0000000..a1e80ae --- /dev/null +++ b/stories/Dropdown.tsx @@ -0,0 +1,73 @@ +import classNames from 'classnames'; +import React, { ReactNode, useEffect, useRef, useState } from 'react'; +import { Alignment, Layout } from './constants'; + +import styles from './Dropdown.scss'; +import { Grid } from './Grid'; +export { DropdownItem } from './DropdownItem'; + +export interface DropdownProps { + align: Alignment; + button: ReactNode; + children: ReactNode; +} + +export function Dropdown({ + align, + button, + children, +}: DropdownProps): JSX.Element { + const elementRef = useRef(); + const listenerRef = useRef<(event: MouseEvent) => void>(); + const [visible, setVisible] = useState(); + + useEffect(() => { + if (visible) { + listenerRef.current = (event: MouseEvent): void => { + const path = event.composedPath(); + if (!path.includes(elementRef.current)) { + setVisible(false); + } + }; + + window.addEventListener('click', listenerRef.current, { + passive: true, + }); + } else if (listenerRef.current) { + window.removeEventListener('click', listenerRef.current); + listenerRef.current = null; + } + + return () => { + if (listenerRef.current) { + window.removeEventListener('click', listenerRef.current); + } + } + }, [visible]); + + return ( +
+
{ + setVisible(!visible); + }} + > + {button} +
+ + {children} + +
+ ); +} diff --git a/stories/DropdownItem.tsx b/stories/DropdownItem.tsx new file mode 100644 index 0000000..0bf104f --- /dev/null +++ b/stories/DropdownItem.tsx @@ -0,0 +1,30 @@ +import classNames from 'classnames'; +import React, { ElementType, ReactNode } from 'react'; + +import styles from './Dropdown.scss'; + +export interface DropdownProps { + [key: string]: any; + children: ReactNode; + type?: ElementType; +} + +export function DropdownItem({ + children, + type: Type = 'div', + ...props +}: DropdownProps): JSX.Element { + const isClickable = Type === 'a' || props.onClick || props.href || props.to; + + return ( + + {children} + + ); +} diff --git a/stories/_variables.scss b/stories/_variables.scss index c67441d..d044c66 100644 --- a/stories/_variables.scss +++ b/stories/_variables.scss @@ -13,3 +13,4 @@ $min-component-size: 36px; $padding: 10px; $margin: 10px; $font-size: 16px; +$font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; diff --git a/stories/index.tsx b/stories/index.tsx index 3183223..c4b65e8 100644 --- a/stories/index.tsx +++ b/stories/index.tsx @@ -12,3 +12,4 @@ export { Separator } from './Separator'; export { Tooltip } from './Tooltip'; export { Typography, TypographyStyles } from './Typography'; export { Toasts, AddToastNotification } from './Toasts'; +export { Dropdown, DropdownItem } from './Dropdown';