From da73fec96c803d366c8be1aabc00d33138cf4aaa Mon Sep 17 00:00:00 2001 From: "rose.liang@vimeo.com" Date: Thu, 10 Aug 2023 14:02:49 -0400 Subject: [PATCH 1/5] feature: create accordion component and story --- .../Accordion/Accordion.examples.story.tsx | 135 ++++++++++++++++++ src/components/Accordion/Accordion.minors.tsx | 77 ++++++++++ .../Accordion/Accordion.props.story.tsx | 38 +++++ src/components/Accordion/Accordion.story.tsx | 35 +++++ src/components/Accordion/Accordion.style.ts | 118 +++++++++++++++ src/components/Accordion/Accordion.tsx | 42 ++++++ src/components/Accordion/Accordion.types.ts | 26 ++++ 7 files changed, 471 insertions(+) create mode 100644 src/components/Accordion/Accordion.examples.story.tsx create mode 100644 src/components/Accordion/Accordion.minors.tsx create mode 100644 src/components/Accordion/Accordion.props.story.tsx create mode 100644 src/components/Accordion/Accordion.story.tsx create mode 100644 src/components/Accordion/Accordion.style.ts create mode 100644 src/components/Accordion/Accordion.tsx create mode 100644 src/components/Accordion/Accordion.types.ts diff --git a/src/components/Accordion/Accordion.examples.story.tsx b/src/components/Accordion/Accordion.examples.story.tsx new file mode 100644 index 00000000..d2dea90d --- /dev/null +++ b/src/components/Accordion/Accordion.examples.story.tsx @@ -0,0 +1,135 @@ +import React from 'react'; +import { Accordion } from './Accordion'; +import { Layout } from '../../storybook'; +import styled from 'styled-components'; +import { Gear } from '../../icons'; +import { rem } from 'polished'; +import { core } from '../../tokens'; + +export default { + title: 'components/Accordion/examples', + component: Accordion, + argTypes: { + allowMultiple: { control: { disable: true } }, + defaultIndex: { control: { disable: true } }, + format: { control: { disable: true } }, + }, +}; + +export function AccordionWithSubcopy({ args }) { + return ( + + + + Accordion content + + + + ); +} + +AccordionWithSubcopy.storyName = 'Accordion - subcopy'; + +export function AccordionWithIcon({ args }) { + return ( + + + } + > + Accordion content + + + + ); +} + +const GearIcon = styled(Gear)` + width: ${rem(22)}; + margin-right: ${rem(10)}; + path { + fill: ${core.color.text.primary}; + } +`; + +AccordionWithIcon.storyName = 'Accordion - icon'; + +export function DisabledAccordion({ args }) { + return ( + + + + Accordion content + + + + ); +} + +DisabledAccordion.storyName = 'Accordion - disabled'; + +export function AccordionWithError({ args }) { + return ( + + + + Accordion content + + + + ); +} + +AccordionWithError.storyName = 'Accordion - error'; + +export function AccordionWithAllowMultipleFalse({ args }) { + return ( + + + + Accordion content + + + Accordion content + + + Accordion content + + + + ); +} + +AccordionWithAllowMultipleFalse.storyName = + 'Accordion - allowMultiple is false'; + +export function AccordionAllowMultiple({ args }) { + return ( + + + + Accordion content + + + Accordion content + + + Accordion content + + + + ); +} + +AccordionAllowMultiple.storyName = + 'Accordion - allowMultiple is true (default)'; diff --git a/src/components/Accordion/Accordion.minors.tsx b/src/components/Accordion/Accordion.minors.tsx new file mode 100644 index 00000000..ec653b26 --- /dev/null +++ b/src/components/Accordion/Accordion.minors.tsx @@ -0,0 +1,77 @@ +import React, { useState } from 'react'; + +import { + Content, + ChevronUp, + CircleWarningIcon, + Header, + StyledChevronDown, + Subcopy, + Title, + TitleContainer, + TriggerContainer, + Wrapper, +} from './Accordion.style'; +import { MinorComponent } from '../../utils'; +import { AccordionItemProps } from './Accordion.types'; + +export interface Minors { + Item: MinorComponent; +} + +export function Item({ + children, + title, + format, + index, + allowMultiple, + defaultActive, + setActiveIndex, + itemActive, + subcopy = '', + icon, + hasError = false, + disabled = false, +}: AccordionItemProps) { + const [active, setActive] = useState(defaultActive); + const isActive = allowMultiple + ? active && !disabled + : itemActive && !disabled; + + return ( + + { + if (allowMultiple) { + setActive(!active); + } else { + setActiveIndex({ index }); + } + }} + tabIndex={0} + format={format} + active={isActive} + > +
+ {hasError && } + {!hasError && icon && icon} + + {title} + {subcopy && {subcopy}} + +
+ {isActive ? ( + + ) : ( + + )} +
+ {isActive && {children}} +
+ ); +} diff --git a/src/components/Accordion/Accordion.props.story.tsx b/src/components/Accordion/Accordion.props.story.tsx new file mode 100644 index 00000000..585ba61f --- /dev/null +++ b/src/components/Accordion/Accordion.props.story.tsx @@ -0,0 +1,38 @@ +import React from 'react'; +import styled, { css } from 'styled-components'; +import { rem } from 'polished'; + +import { Accordion } from './Accordion'; + +export default { + title: 'components/Accordion/props', + component: Accordion, + argTypes: { + allowMultiple: { control: { disable: true } }, + defaultIndex: { control: { disable: true } }, + format: { control: { disable: true } }, + }, +}; + +const formats = ['basic', 'secondary']; + +export function Formats({ args }) { + return ( + + {formats.map((format, i) => ( + + + Accordion content + + + ))} + + ); +} + +const Container = styled.div` + width: 50%; + display: flex; + flex-direction: column; + gap: ${rem(8)}; +`; diff --git a/src/components/Accordion/Accordion.story.tsx b/src/components/Accordion/Accordion.story.tsx new file mode 100644 index 00000000..0dd4a137 --- /dev/null +++ b/src/components/Accordion/Accordion.story.tsx @@ -0,0 +1,35 @@ +import React from 'react'; +import { Story } from '@storybook/react'; + +import { Accordion } from './Accordion'; +import { Props } from './Accordion.types'; +import styled from 'styled-components'; +import { Gear } from '../../icons'; +import { rem } from 'polished'; + +export default { + title: 'components/Accordion', + component: Accordion, +}; + +const Template: Story = (args) => { + return ( + + + + Accordion content + + + Accordion content + + + + ); +}; + +const Container = styled.div` + width: 50%; +`; + +export const Controls = Template.bind({}); +Controls.storyName = 'Accordion'; diff --git a/src/components/Accordion/Accordion.style.ts b/src/components/Accordion/Accordion.style.ts new file mode 100644 index 00000000..c92382d5 --- /dev/null +++ b/src/components/Accordion/Accordion.style.ts @@ -0,0 +1,118 @@ +import { rem } from 'polished'; +import styled, { css } from 'styled-components'; + +import { ChevronDown, CircleWarning } from '../../icons'; +import { Paragraph } from '../../typography'; + +import { grayscale } from '../../color'; +import { core } from '../../tokens'; + +export const AccordionStyled = styled.div` + display: flex; + flex-direction: column; + gap: ${rem(8)}; +`; + +export const Wrapper = styled.div<{ + format: 'basic' | 'secondary'; + active: boolean; + disabled: boolean; +}>` + ${({ disabled }) => + disabled && + css` + pointer-events: none; + opacity: 0.4; + `} + ${({ active, theme, format }) => + active && + css` + background-color: ${format === 'basic' + ? theme.name === 'dark' + ? grayscale(800) + : grayscale(50) + : 'none'}; + `} + border-radius: ${rem(10)}; + color: ${core.color.text.primary}; + ${({ active, theme, format }) => + active && + css` + border: ${format === 'secondary' + ? theme.name === 'dark' + ? `${rem(1)} solid ${grayscale(800)}` + : `${rem(1)} solid ${grayscale(50)}` + : 'none'}; + `} +`; + +export const TriggerContainer = styled.div<{ + format: 'basic' | 'secondary'; + active: boolean; +}>` + display: flex; + justify-content: space-between; + cursor: pointer; + padding: ${rem(12)} ${rem(15)}; + border-radius: ${rem(10)}; + &:hover { + background-color: ${({ theme, format }) => + format === 'basic' + ? theme.name === 'dark' + ? grayscale(800) + : grayscale(50) + : 'none'}; + border: ${({ active, theme, format }) => + !active && format === 'secondary' + ? theme.name === 'dark' + ? `${rem(1)} solid ${grayscale(800)}` + : `${rem(1)} solid ${grayscale(50)}` + : 'none'}; + } +`; + +export const Header = styled.div` + display: flex; + margin-right: ${rem(10)}; +`; + +export const TitleContainer = styled.div` + display: flex; + flex-direction: column; +`; + +export const Title = styled(Paragraph)` + font-size: ${rem(16)}; + font-weight: 700; + margin-bottom: 0; +`; + +export const Subcopy = styled(Paragraph)` + font-size: ${rem(14)}; + font-weight: 400; + margin-bottom: -${rem(0.2)}; +`; + +export const CircleWarningIcon = styled(CircleWarning)` + width: ${rem(22)}; + margin-right: ${rem(10)}; + path { + fill: ${core.color.status.negative}; + } +`; + +export const StyledChevronDown = styled(ChevronDown)` + path { + fill: ${core.color.text.primary}; + } +`; + +export const ChevronUp = styled(StyledChevronDown)` + transform: rotate(180deg); +`; + +export const Content = styled.div<{ active: boolean }>` + padding: ${rem(0)} ${rem(15)} ${rem(20)}; + max-height: ${({ active }) => (active ? '100%' : '0')}; + overflow: hidden; +`; diff --git a/src/components/Accordion/Accordion.tsx b/src/components/Accordion/Accordion.tsx new file mode 100644 index 00000000..16663220 --- /dev/null +++ b/src/components/Accordion/Accordion.tsx @@ -0,0 +1,42 @@ +import React, { cloneElement, useState } from 'react'; + +import { withIris } from '../../utils'; +import { Item, Minors } from './Accordion.minors'; +import { Props } from './Accordion.types'; +import { AccordionStyled } from './Accordion.style'; + +export const Accordion = withIris( + AccordionComponent +); + +Accordion.Item = Item; + +function AccordionComponent({ + children, + defaultIndex, + allowMultiple = true, + format = 'basic', +}: Props) { + const [activeIndex, setActiveIndex] = useState(defaultIndex); + + function childClone(child, i) { + return cloneElement(child, { + format, + index: i, + allowMultiple, + defaultActive: defaultIndex === i, + setActiveIndex: ({ index }) => { + setActiveIndex(index); + }, + itemActive: !allowMultiple && activeIndex === i, + }); + } + + return ( + + {children.length > 1 + ? children.map(childClone) + : childClone(children, 0)} + + ); +} diff --git a/src/components/Accordion/Accordion.types.ts b/src/components/Accordion/Accordion.types.ts new file mode 100644 index 00000000..bf3af9bb --- /dev/null +++ b/src/components/Accordion/Accordion.types.ts @@ -0,0 +1,26 @@ +import { IrisProps } from '../../utils'; + +export type Props = IrisProps< + { + children: any; + allowMultiple?: boolean; + defaultIndex?: number; + format?: 'basic' | 'secondary'; + }, + HTMLDivElement +>; + +export type AccordionItemProps = IrisProps<{ + children: React.ReactElement; + title: string; + format: 'basic' | 'secondary'; + index: number; + allowMultiple: boolean; + defaultActive: boolean; + setActiveIndex: ({ index }) => void; + itemActive: boolean; + subcopy?: string; + icon?: string; + hasError?: boolean; + disabled?: boolean; +}>; From de1e01f5b5b266c9f9b4704bc2986a11e4b06301 Mon Sep 17 00:00:00 2001 From: "rose.liang@vimeo.com" Date: Wed, 16 Aug 2023 16:32:20 -0400 Subject: [PATCH 2/5] feat: add test, aria labels, update storybook --- .../Accordion/Accordion.examples.story.tsx | 135 ------------------ src/components/Accordion/Accordion.minors.tsx | 14 +- .../Accordion/Accordion.props.story.tsx | 38 ----- src/components/Accordion/Accordion.story.tsx | 36 ++++- src/components/Accordion/Accordion.style.ts | 6 +- src/components/Accordion/Accordion.test.tsx | 95 ++++++++++++ 6 files changed, 142 insertions(+), 182 deletions(-) delete mode 100644 src/components/Accordion/Accordion.examples.story.tsx delete mode 100644 src/components/Accordion/Accordion.props.story.tsx create mode 100644 src/components/Accordion/Accordion.test.tsx diff --git a/src/components/Accordion/Accordion.examples.story.tsx b/src/components/Accordion/Accordion.examples.story.tsx deleted file mode 100644 index d2dea90d..00000000 --- a/src/components/Accordion/Accordion.examples.story.tsx +++ /dev/null @@ -1,135 +0,0 @@ -import React from 'react'; -import { Accordion } from './Accordion'; -import { Layout } from '../../storybook'; -import styled from 'styled-components'; -import { Gear } from '../../icons'; -import { rem } from 'polished'; -import { core } from '../../tokens'; - -export default { - title: 'components/Accordion/examples', - component: Accordion, - argTypes: { - allowMultiple: { control: { disable: true } }, - defaultIndex: { control: { disable: true } }, - format: { control: { disable: true } }, - }, -}; - -export function AccordionWithSubcopy({ args }) { - return ( - - - - Accordion content - - - - ); -} - -AccordionWithSubcopy.storyName = 'Accordion - subcopy'; - -export function AccordionWithIcon({ args }) { - return ( - - - } - > - Accordion content - - - - ); -} - -const GearIcon = styled(Gear)` - width: ${rem(22)}; - margin-right: ${rem(10)}; - path { - fill: ${core.color.text.primary}; - } -`; - -AccordionWithIcon.storyName = 'Accordion - icon'; - -export function DisabledAccordion({ args }) { - return ( - - - - Accordion content - - - - ); -} - -DisabledAccordion.storyName = 'Accordion - disabled'; - -export function AccordionWithError({ args }) { - return ( - - - - Accordion content - - - - ); -} - -AccordionWithError.storyName = 'Accordion - error'; - -export function AccordionWithAllowMultipleFalse({ args }) { - return ( - - - - Accordion content - - - Accordion content - - - Accordion content - - - - ); -} - -AccordionWithAllowMultipleFalse.storyName = - 'Accordion - allowMultiple is false'; - -export function AccordionAllowMultiple({ args }) { - return ( - - - - Accordion content - - - Accordion content - - - Accordion content - - - - ); -} - -AccordionAllowMultiple.storyName = - 'Accordion - allowMultiple is true (default)'; diff --git a/src/components/Accordion/Accordion.minors.tsx b/src/components/Accordion/Accordion.minors.tsx index ec653b26..e1b51636 100644 --- a/src/components/Accordion/Accordion.minors.tsx +++ b/src/components/Accordion/Accordion.minors.tsx @@ -56,6 +56,9 @@ export function Item({ tabIndex={0} format={format} active={isActive} + aria-expanded={isActive} + aria-controls={`accordion-${index}-content`} + id={`accordion-${index}-trigger`} >
{hasError && } @@ -71,7 +74,16 @@ export function Item({ )} - {isActive && {children}} + {isActive && ( + + {children} + + )} ); } diff --git a/src/components/Accordion/Accordion.props.story.tsx b/src/components/Accordion/Accordion.props.story.tsx deleted file mode 100644 index 585ba61f..00000000 --- a/src/components/Accordion/Accordion.props.story.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import React from 'react'; -import styled, { css } from 'styled-components'; -import { rem } from 'polished'; - -import { Accordion } from './Accordion'; - -export default { - title: 'components/Accordion/props', - component: Accordion, - argTypes: { - allowMultiple: { control: { disable: true } }, - defaultIndex: { control: { disable: true } }, - format: { control: { disable: true } }, - }, -}; - -const formats = ['basic', 'secondary']; - -export function Formats({ args }) { - return ( - - {formats.map((format, i) => ( - - - Accordion content - - - ))} - - ); -} - -const Container = styled.div` - width: 50%; - display: flex; - flex-direction: column; - gap: ${rem(8)}; -`; diff --git a/src/components/Accordion/Accordion.story.tsx b/src/components/Accordion/Accordion.story.tsx index 0dd4a137..7dabaed8 100644 --- a/src/components/Accordion/Accordion.story.tsx +++ b/src/components/Accordion/Accordion.story.tsx @@ -6,6 +6,8 @@ import { Props } from './Accordion.types'; import styled from 'styled-components'; import { Gear } from '../../icons'; import { rem } from 'polished'; +import { core } from '../../tokens'; +import { Layout } from '../../storybook'; export default { title: 'components/Accordion', @@ -14,21 +16,43 @@ export default { const Template: Story = (args) => { return ( - + - + Accordion content - + } + > + Accordion content + + + Accordion content + + Accordion content - + ); }; -const Container = styled.div` - width: 50%; +const GearIcon = styled(Gear)` + width: ${rem(22)}; + margin-right: ${rem(10)}; + path { + fill: ${core.color.text.primary}; + } `; export const Controls = Template.bind({}); diff --git a/src/components/Accordion/Accordion.style.ts b/src/components/Accordion/Accordion.style.ts index c92382d5..87438224 100644 --- a/src/components/Accordion/Accordion.style.ts +++ b/src/components/Accordion/Accordion.style.ts @@ -46,7 +46,7 @@ export const Wrapper = styled.div<{ `} `; -export const TriggerContainer = styled.div<{ +export const TriggerContainer = styled.button<{ format: 'basic' | 'secondary'; active: boolean; }>` @@ -55,6 +55,7 @@ export const TriggerContainer = styled.div<{ cursor: pointer; padding: ${rem(12)} ${rem(15)}; border-radius: ${rem(10)}; + width: 100%; &:hover { background-color: ${({ theme, format }) => format === 'basic' @@ -62,7 +63,7 @@ export const TriggerContainer = styled.div<{ ? grayscale(800) : grayscale(50) : 'none'}; - border: ${({ active, theme, format }) => + outline: ${({ active, theme, format }) => !active && format === 'secondary' ? theme.name === 'dark' ? `${rem(1)} solid ${grayscale(800)}` @@ -79,6 +80,7 @@ export const Header = styled.div` export const TitleContainer = styled.div` display: flex; flex-direction: column; + text-align: left; `; export const Title = styled(Paragraph)` diff --git a/src/components/Accordion/Accordion.test.tsx b/src/components/Accordion/Accordion.test.tsx new file mode 100644 index 00000000..cc99b653 --- /dev/null +++ b/src/components/Accordion/Accordion.test.tsx @@ -0,0 +1,95 @@ +import React from 'react'; +import '@testing-library/jest-dom'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + +import { ThemeProvider } from 'styled-components'; +import { themes } from '../../themes'; +import { Accordion } from './Accordion'; + +describe('Accordion', () => { + it('renders accordion', () => { + render( + + + + + + ); + + const accordion = screen.getByRole('button'); + expect(accordion).toBeInTheDocument(); + }); + + it('triggers and expands accordion item when clicking the header', () => { + render( + + + + + + ); + + const accordion = screen.getByRole('button'); + userEvent.click(accordion).then(() => { + const content = screen.getByRole('heading'); + expect(content).toBeInTheDocument(); + }); + }); + + it('can receive text as title and subcopy props and render them', () => { + render( + + + + + + ); + + const title = screen.getByText('Accordion item title'); + const subcopy = screen.getByText('Accordion item subcopy'); + expect(title).toBeInTheDocument(); + expect(subcopy).toBeInTheDocument(); + }); + + it('can receive children component and render them', () => { + render( + + + +
Child component
+
+
+
+ ); + + const accordion = screen.getByRole('button'); + userEvent.click(accordion).then(() => { + const childComponentContent = + screen.getByText('Child component'); + expect(childComponentContent).toBeInTheDocument(); + }); + }); + + it('does not render children when disabled prop is true', () => { + render( + + + +
Child component
+
+
+
+ ); + + const accordion = screen.getByRole('button'); + userEvent.click(accordion).then(() => { + const childComponentContent = + screen.getByText('Child component'); + expect(childComponentContent).not.toBeInTheDocument(); + }); + }); +}); From 3700fb80dbe128a5c8889dc956b4b9838ff6f9e5 Mon Sep 17 00:00:00 2001 From: "rose.liang@vimeo.com" Date: Fri, 18 Aug 2023 10:44:59 -0400 Subject: [PATCH 3/5] feat: add animation and update styles --- src/components/Accordion/Accordion.minors.tsx | 14 +++-- src/components/Accordion/Accordion.style.ts | 59 +++++++++++++++---- 2 files changed, 56 insertions(+), 17 deletions(-) diff --git a/src/components/Accordion/Accordion.minors.tsx b/src/components/Accordion/Accordion.minors.tsx index e1b51636..a6ce4639 100644 --- a/src/components/Accordion/Accordion.minors.tsx +++ b/src/components/Accordion/Accordion.minors.tsx @@ -4,7 +4,7 @@ import { Content, ChevronUp, CircleWarningIcon, - Header, + HeaderContainer, StyledChevronDown, Subcopy, Title, @@ -60,14 +60,18 @@ export function Item({ aria-controls={`accordion-${index}-content`} id={`accordion-${index}-trigger`} > -
+ {hasError && } {!hasError && icon && icon} - {title} - {subcopy && {subcopy}} + {title} + {subcopy && ( + + {subcopy} + + )} -
+ {isActive ? ( ) : ( diff --git a/src/components/Accordion/Accordion.style.ts b/src/components/Accordion/Accordion.style.ts index 87438224..6c90529c 100644 --- a/src/components/Accordion/Accordion.style.ts +++ b/src/components/Accordion/Accordion.style.ts @@ -1,8 +1,8 @@ import { rem } from 'polished'; -import styled, { css } from 'styled-components'; +import styled, { css, keyframes } from 'styled-components'; import { ChevronDown, CircleWarning } from '../../icons'; -import { Paragraph } from '../../typography'; +import { Header } from '../../typography'; import { grayscale } from '../../color'; import { core } from '../../tokens'; @@ -72,7 +72,7 @@ export const TriggerContainer = styled.button<{ } `; -export const Header = styled.div` +export const HeaderContainer = styled.div` display: flex; margin-right: ${rem(10)}; `; @@ -81,17 +81,14 @@ export const TitleContainer = styled.div` display: flex; flex-direction: column; text-align: left; + gap: ${rem(4)}; `; -export const Title = styled(Paragraph)` - font-size: ${rem(16)}; - font-weight: 700; - margin-bottom: 0; +export const Title = styled(Header)` + margin-bottom: ${rem(0)}; `; -export const Subcopy = styled(Paragraph)` - font-size: ${rem(14)}; - font-weight: 400; +export const Subcopy = styled(Header)` margin-bottom: -${rem(0.2)}; `; @@ -103,18 +100,56 @@ export const CircleWarningIcon = styled(CircleWarning)` } `; +const rotateUp = keyframes` + from { + transform: rotate(0deg); + } + to { + transform: rotate(-180deg); + } +`; + +const rotateDown = keyframes` + from { + transform: rotate(-180deg); + } + to { + transform: rotate(0deg); + } +`; + export const StyledChevronDown = styled(ChevronDown)` + animation: ${rotateDown} 120ms ease-in-out both; path { fill: ${core.color.text.primary}; } `; export const ChevronUp = styled(StyledChevronDown)` - transform: rotate(180deg); + animation: ${rotateUp} 120ms ease-in-out both; +`; + +const fadeAndExpand = keyframes` + from { + transform: translateY(-50%); + opacity: 0; + } + to { + transform: translateY(0); + opacity: 1; + } `; export const Content = styled.div<{ active: boolean }>` - padding: ${rem(0)} ${rem(15)} ${rem(20)}; + padding: ${rem(0)} ${rem(15)} ${rem(20)} ${rem(20)}; max-height: ${({ active }) => (active ? '100%' : '0')}; overflow: hidden; + transform: translateY(-50%); + opacity: 0; + ${({ active }) => + active && + css` + animation: ${fadeAndExpand} 150ms ease-in-out both; + opacity: 1; + `}; `; From 5c94258d992df5fc7ff812b2a59a65d6e33d2a52 Mon Sep 17 00:00:00 2001 From: Julie Wongbandue Date: Fri, 18 Aug 2023 15:27:00 -0400 Subject: [PATCH 4/5] chore(baseline): update lost-pixel baselines (#344) Co-authored-by: rose-liang --- .../components-accordion--accordion.png | Bin 0 -> 24015 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 lost-pixel/baseline/components-accordion--accordion.png diff --git a/lost-pixel/baseline/components-accordion--accordion.png b/lost-pixel/baseline/components-accordion--accordion.png new file mode 100644 index 0000000000000000000000000000000000000000..4e644df3ef7736af9bede1161fc1b67fa50f5e6a GIT binary patch literal 24015 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 C)h5ya literal 0 HcmV?d00001 From 713402c6a45629d6400f5a443d04c1e467a5b5b6 Mon Sep 17 00:00:00 2001 From: "rose.liang@vimeo.com" Date: Mon, 21 Aug 2023 16:51:50 -0400 Subject: [PATCH 5/5] feat: add prop comments, focus component, optional props --- src/components/Accordion/Accordion.minors.tsx | 16 +++++- src/components/Accordion/Accordion.story.tsx | 51 +++++++++++++++--- src/components/Accordion/Accordion.style.ts | 6 ++- src/components/Accordion/Accordion.types.ts | 53 ++++++++++++++++++- 4 files changed, 115 insertions(+), 11 deletions(-) diff --git a/src/components/Accordion/Accordion.minors.tsx b/src/components/Accordion/Accordion.minors.tsx index a6ce4639..3e340fd7 100644 --- a/src/components/Accordion/Accordion.minors.tsx +++ b/src/components/Accordion/Accordion.minors.tsx @@ -14,6 +14,7 @@ import { } from './Accordion.style'; import { MinorComponent } from '../../utils'; import { AccordionItemProps } from './Accordion.types'; +import { Focus } from '../../utils'; export interface Minors { Item: MinorComponent; @@ -30,6 +31,9 @@ export function Item({ itemActive, subcopy = '', icon, + errorIcon, + iconToTriggerOpen, + iconToTriggerClose, hasError = false, disabled = false, }: AccordionItemProps) { @@ -61,7 +65,8 @@ export function Item({ id={`accordion-${index}-trigger`} > - {hasError && } + {hasError && errorIcon && errorIcon} + {hasError && !errorIcon && } {!hasError && icon && icon} {title} @@ -73,10 +78,17 @@ export function Item({ {isActive ? ( - + iconToTriggerClose ? ( + iconToTriggerClose + ) : ( + + ) + ) : iconToTriggerOpen ? ( + iconToTriggerOpen ) : ( )} + {isActive && ( = (args) => { Accordion content } + title="Accordion item with error" + hasError={true} > Accordion content @@ -37,8 +42,22 @@ const Template: Story = (args) => { Accordion content } + > + Accordion content + + } + iconToTriggerClose={} + > + Accordion content + + } > Accordion content @@ -47,11 +66,31 @@ const Template: Story = (args) => { ); }; +const iconStyle = css` + width: ${rem(22)}; + path { + fill: ${core.color.text.primary}; + } +`; + const GearIcon = styled(Gear)` + ${iconStyle} + margin-right: ${rem(10)}; +`; + +const FullscreenIcon = styled(Fullscreen)` + ${iconStyle} +`; + +const FullscreenOffIcon = styled(FullscreenOff)` + ${iconStyle} +`; + +const FlagFilledIcon = styled(FlagFilled)` width: ${rem(22)}; margin-right: ${rem(10)}; path { - fill: ${core.color.text.primary}; + fill: ${core.color.status.negative}; } `; diff --git a/src/components/Accordion/Accordion.style.ts b/src/components/Accordion/Accordion.style.ts index 6c90529c..53662ccb 100644 --- a/src/components/Accordion/Accordion.style.ts +++ b/src/components/Accordion/Accordion.style.ts @@ -70,6 +70,10 @@ export const TriggerContainer = styled.button<{ : `${rem(1)} solid ${grayscale(50)}` : 'none'}; } + + &:focus { + outline: none; + } `; export const HeaderContainer = styled.div` @@ -141,7 +145,7 @@ const fadeAndExpand = keyframes` `; export const Content = styled.div<{ active: boolean }>` - padding: ${rem(0)} ${rem(15)} ${rem(20)} ${rem(20)}; + padding: ${rem(0)} ${rem(15)} ${rem(20)} ${rem(18)}; max-height: ${({ active }) => (active ? '100%' : '0')}; overflow: hidden; transform: translateY(-50%); diff --git a/src/components/Accordion/Accordion.types.ts b/src/components/Accordion/Accordion.types.ts index bf3af9bb..34a76d9d 100644 --- a/src/components/Accordion/Accordion.types.ts +++ b/src/components/Accordion/Accordion.types.ts @@ -1,10 +1,22 @@ +import React, { ReactNode } from 'react'; import { IrisProps } from '../../utils'; export type Props = IrisProps< { children: any; + /** + * Whether the accordion will permit multiple accordion items to be expanded at once + * + * [default = true] + */ allowMultiple?: boolean; + /** + * Index of the accordion item that should start as open/active + */ defaultIndex?: number; + /** + * [default = 'basic'] + */ format?: 'basic' | 'secondary'; }, HTMLDivElement @@ -12,15 +24,52 @@ export type Props = IrisProps< export type AccordionItemProps = IrisProps<{ children: React.ReactElement; - title: string; format: 'basic' | 'secondary'; index: number; allowMultiple: boolean; defaultActive: boolean; setActiveIndex: ({ index }) => void; itemActive: boolean; + /** + * Header title + */ + title: string; + /** + * Optional header subcopy + */ subcopy?: string; - icon?: string; + /** + * Optional header icon + */ + icon?: ReactNode; + /** + * Optional icon to be displayed when `hasError` is true + * + * [default = `CircleWarning`] + */ + errorIcon?: ReactNode; + /** + * Optional icon to open accordion item + * + * [default = `ChevronDown`] + */ + iconToTriggerOpen?: ReactNode; + /** + * Optional icon to close accordion item + * + * [default = `ChevronUp`] + */ + iconToTriggerClose?: ReactNode; + /** + * Whether to show the accordion item's error state + * + * [default = false] + */ hasError?: boolean; + /** + * Whether to show the accordion item's disabled state + * + * [default = false] + */ disabled?: boolean; }>;