From ca36b19b181c0a88185bc024c89ee1080c675ac9 Mon Sep 17 00:00:00 2001 From: Mathew Morris Date: Fri, 6 Sep 2019 15:55:58 -0500 Subject: [PATCH] feat(Dropdown): Style updates (#68) --- src/Dropdown/Dropdown.js | 125 ++++++------- src/Dropdown/Dropdown.spec.js | 14 +- src/Dropdown/Dropdown.stories.js | 164 ++++++++---------- .../__snapshots__/Dropdown.spec.js.snap | 101 +++++------ 4 files changed, 179 insertions(+), 225 deletions(-) diff --git a/src/Dropdown/Dropdown.js b/src/Dropdown/Dropdown.js index dd70511..7a5e74f 100644 --- a/src/Dropdown/Dropdown.js +++ b/src/Dropdown/Dropdown.js @@ -6,8 +6,9 @@ import { Manager, Reference, Popper } from 'react-popper'; import { css, keyframes } from 'styled-components'; import Box from '../Box'; import Portal from '../Portal'; +import Icon from '../Icon'; import { useKeyPress } from '../hooks'; -import { createComponent, themeGet, findNextFocusableElement, findPreviousFocusableElement } from '../utils'; +import { createComponent, findNextFocusableElement, findPreviousFocusableElement } from '../utils'; const DropdownContext = React.createContext({}); @@ -238,6 +239,7 @@ const DropdownMenu = createComponent({ opacity: 0.75; transform: scale(0.75); transform-origin: ${PLACEMENT_TRANSITION_ORIGINS[placement]}; + padding: 8px; ${(transitionState === 'entering' || transitionState === 'entered') && css` @@ -246,57 +248,25 @@ const DropdownMenu = createComponent({ `, }); -const DropdownHeader = createComponent({ - name: 'DropdownHeader', - tag: 'header', - style: css` - padding: 0.75rem 1rem 0; - `, -}); - -const DropdownHeaderInner = createComponent({ - name: 'DropdownHeaderInner', - style: css` - padding: 0 0 0.25rem; - border-bottom: 2px solid ${p => p.theme.colors.greyLight}; +Dropdown.Divider = createComponent({ + name: 'DropdownDivider', + tag: 'hr', + style: ({ theme }) => css` + background: ${theme.colors.greyLight}; + height: 1px; + border: 0; + margin-left: -8px; + margin-right: -8px; `, }); Dropdown.Title = createComponent({ name: 'DropdownTitle', tag: 'span', - style: css` - display: block; - font-weight: bold; - font-size: 1rem; - margin: 0; - `, -}); - -Dropdown.Header = ({ title, children }) => ( - - - {title && {title}} - {children} - - -); - -Dropdown.Body = createComponent({ - name: 'DropdownBody', - as: Box, - style: css` - padding: 1rem; - `, -}); - -Dropdown.SectionTitle = createComponent({ - name: 'DropdownSectionTitle', - tag: 'span', style: ({ theme }) => css` display: block; - font-weight: 600; - color: ${theme.colors.primary}; + font-weight: 700; + color: ${theme.colors.greyDark}; `, }); @@ -307,37 +277,62 @@ const StyledDropdownItem = createComponent({ role: 'button', }), as: Box, - style: ({ disabled, theme }) => css` + style: ({ disabled, theme, color, icon, iconProps, selected }) => css` display: block; - width: calc(100% + 2rem); + flex: 1; opacity: ${disabled ? 0.3 : 1}; pointer-events: ${disabled ? 'none' : 'initial'}; user-select: ${disabled ? 'none' : 'initial'}; text-decoration: none; - color: inherit; + color: ${color || theme.colors.greyDarkest}; cursor: pointer; - margin: 0 calc(-1rem); - padding: 0.25rem 1rem; + margin: 0; + padding: 8px; transition: 125ms background; outline: none; appearance: none; border: 0; + border-radius: ${theme.radius}px; font: inherit; + font-size: 14px; + font-weight: 500; text-align: left; - - & + ${Dropdown.SectionTitle} { - margin-top: 1rem; - } + position: relative; &:hover, &:focus { - color: inherit; + color: ${color || theme.colors.greyDarkest}; background: ${theme.colors.greyLightest}; } + + ${icon && + css` + padding-left: ${(iconProps.size || 16) + 16}px; + `} + + ${selected && + css` + color: ${theme.colors.primary}; + + &:hover, + &:active, + &:focus { + color: ${theme.colors.primary}; + } + `} `, }); -Dropdown.Item = function DropdownItem({ closeOnClick = true, onClick, ...props }) { +const StyledIcon = createComponent({ + name: 'DropdownIcon', + as: Icon, + style: css` + position: absolute; + left: 8px; + `, +}); + +Dropdown.Item = ({ closeOnClick = true, onClick, children, icon, iconProps = {}, ...props }) => { const { close } = useContext(DropdownContext); const handleClick = () => { if (closeOnClick) { @@ -347,18 +342,10 @@ Dropdown.Item = function DropdownItem({ closeOnClick = true, onClick, ...props } onClick(); } }; - return ; + return ( + + {icon && } + {children} + + ); }; - -Dropdown.Footer = createComponent({ - name: 'DropdownFooter', - as: Box, - props: () => ({ - as: 'footer', - }), - style: ({ theme }) => css` - background: ${theme.colors.greyLightest}; - padding: 0.75rem 1rem; - border-radius: 0 0 ${themeGet('radius')}px ${themeGet('radius')}px; - `, -}); diff --git a/src/Dropdown/Dropdown.spec.js b/src/Dropdown/Dropdown.spec.js index 174eac8..37e2d87 100644 --- a/src/Dropdown/Dropdown.spec.js +++ b/src/Dropdown/Dropdown.spec.js @@ -25,12 +25,10 @@ describe('', () => { wrapper.setAttribute('tabindex', 1); const utils = renderWithTheme( Trigger}> - Header - - One - Two - - Footer + Title + One + + Two , { container: document.body.appendChild(wrapper), @@ -44,12 +42,12 @@ describe('', () => { const assertDropdownOpen = (utils = renderUtils) => wait(() => { - expect(utils.queryByText('Header')).toBeInTheDocument(); + expect(utils.queryByText('Title')).toBeInTheDocument(); }); const assertDropdownClosed = (utils = renderUtils) => wait(() => { - expect(utils.queryByText('Header')).not.toBeInTheDocument(); + expect(utils.queryByText('Title')).not.toBeInTheDocument(); }); const openDropdown = async (utils = renderUtils) => { diff --git a/src/Dropdown/Dropdown.stories.js b/src/Dropdown/Dropdown.stories.js index 57a12a7..b58534a 100644 --- a/src/Dropdown/Dropdown.stories.js +++ b/src/Dropdown/Dropdown.stories.js @@ -1,6 +1,5 @@ import React, { useState } from 'react'; import Dropdown, { PLACEMENT_TRANSITION_ORIGINS } from './Dropdown'; -import Icon from '../Icon'; import Flex from '../Flex'; import RadioGroup from '../Form/RadioGroup'; import Button from '../Button'; @@ -11,96 +10,77 @@ export default { }; export const Basic = () => { - function Example() { - const [placement, setPlacement] = useState('top'); - return ( - <> - - Placement} - value={placement} - choices={Object.keys(PLACEMENT_TRANSITION_ORIGINS).map(placement => ({ - value: placement, - label: placement, - }))} - onChange={(_, val) => setPlacement(val)} - /> - - Open Dropdown}> - - - - Section One - I don't close when clicked - Item Two - - Section Two - - Item One - - Item Two - - - Footer - - - - - Open Other Dropdown}> - - - - Section One - Item One - Item Two - - Section Two - Item One - Item Two - - - Footer - - - - - }> - - - - Section One - Item One - Item Two - - - Footer - - - - - - - - }> - + const [ placement, setPlacement ] = useState('bottom-start') + return ( + + + Placement} + value={placement} + choices={Object.keys(PLACEMENT_TRANSITION_ORIGINS).map(placement => ({ + value: placement, + label: placement, + }))} + onChange={(_, val) => setPlacement(val)} + /> + + + + Basic Dropdown + + }> + Dropdown Item + Dropdown Item + Dropdown Item + Dropdown Item + Cancel + + + + ); +}; - - Section One - Item One - Item Two - +export const WithTitles = () => ( + + Dropdown w/Titles}> + Section Title + Dropdown Item + Dropdown Item + Dropdown Item + + Section Title + Dropdown Item + Dropdown Item + Dropdown Item + + Cancel + + +); - Footer - - - - - ); - } - return ; -}; +export const WithIcons = () => ( + + + Dropdown w/Icons + + }> + Dropdown Item + Dropdown Item + + Dropdown Item + Dropdown Item + + Dropdown Item + + Cancel + + +); diff --git a/src/Dropdown/__snapshots__/Dropdown.spec.js.snap b/src/Dropdown/__snapshots__/Dropdown.spec.js.snap index b7442cf..8bb5102 100644 --- a/src/Dropdown/__snapshots__/Dropdown.spec.js.snap +++ b/src/Dropdown/__snapshots__/Dropdown.spec.js.snap @@ -68,26 +68,30 @@ exports[` opens menu with focus when trigger is clicked 1`] = ` -webkit-transform-origin: 0 0; -ms-transform-origin: 0 0; transform-origin: 0 0; + padding: 8px; -webkit-animation: gPsOjp 225ms cubic-bezier(0.25,0.1,0.17,1.2) forwards; animation: gPsOjp 225ms cubic-bezier(0.25,0.1,0.17,1.2) forwards; } -.c1 { - padding: 0.75rem 1rem 0; -} - -.c2 { - padding: 0 0 0.25rem; - border-bottom: 2px solid #E8E9EA; +.c3 { + background: #E8E9EA; + height: 1px; + border: 0; + margin-left: -8px; + margin-right: -8px; } -.c3 { - padding: 1rem; +.c1 { + display: block; + font-weight: 700; + color: #A4A6AA; } -.c4 { +.c2 { display: block; - width: calc(100% + 2rem); + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; opacity: 1; pointer-events: initial; -webkit-user-select: initial; @@ -96,10 +100,10 @@ exports[` opens menu with focus when trigger is clicked 1`] = ` user-select: initial; -webkit-text-decoration: none; text-decoration: none; - color: inherit; + color: #494D55; cursor: pointer; - margin: 0 calc(-1rem); - padding: 0.25rem 1rem; + margin: 0; + padding: 8px; -webkit-transition: 125ms background; transition: 125ms background; outline: none; @@ -107,26 +111,20 @@ exports[` opens menu with focus when trigger is clicked 1`] = ` -moz-appearance: none; appearance: none; border: 0; + border-radius: 8px; font: inherit; + font-size: 14px; + font-weight: 500; text-align: left; + position: relative; } -.c4 + .c6 { - margin-top: 1rem; -} - -.c4:hover, -.c4:focus { - color: inherit; +.c2:hover, +.c2:focus { + color: #494D55; background: #F8F8F9; } -.c5 { - background: #F8F8F9; - padding: 0.75rem 1rem; - border-radius: 0 0 8px 8px; -} -