From efcc9e49f5434f07b95a36ee87da04470fcf926e Mon Sep 17 00:00:00 2001 From: soulBit Date: Tue, 25 Oct 2022 10:24:58 +0100 Subject: [PATCH] Accordion Component SOV-567 (#47) * chore: remove unused file * chore: add missing Icons * feat: add Accordion component * feat: add jest tests * chore: update disabled styling * chore: amends per review comments * Create warm-icons-provide.md Accordion Component SOV-567 * fix: arrow-up svg path --- .changeset/warm-icons-provide.md | 5 ++ .../1_atoms/Accordion/Accordion.module.css | 27 ++++++ .../1_atoms/Accordion/Accordion.stories.tsx | 84 +++++++++++++++++++ .../src/1_atoms/Accordion/Accordion.test.tsx | 73 ++++++++++++++++ .../ui/src/1_atoms/Accordion/Accordion.tsx | 71 ++++++++++++++++ packages/ui/src/1_atoms/Accordion/index.ts | 1 + packages/ui/src/1_atoms/Icon/Icon.types.ts | 3 + packages/ui/src/1_atoms/Icon/iconNames.ts | 26 ------ packages/ui/src/1_atoms/Icon/iconSvgPaths.ts | 6 ++ packages/ui/src/1_atoms/index.tsx | 1 + 10 files changed, 271 insertions(+), 26 deletions(-) create mode 100644 .changeset/warm-icons-provide.md create mode 100644 packages/ui/src/1_atoms/Accordion/Accordion.module.css create mode 100644 packages/ui/src/1_atoms/Accordion/Accordion.stories.tsx create mode 100644 packages/ui/src/1_atoms/Accordion/Accordion.test.tsx create mode 100644 packages/ui/src/1_atoms/Accordion/Accordion.tsx create mode 100644 packages/ui/src/1_atoms/Accordion/index.ts delete mode 100644 packages/ui/src/1_atoms/Icon/iconNames.ts diff --git a/.changeset/warm-icons-provide.md b/.changeset/warm-icons-provide.md new file mode 100644 index 0000000000..2a316b0aad --- /dev/null +++ b/.changeset/warm-icons-provide.md @@ -0,0 +1,5 @@ +--- +"@sovryn/ui": patch +--- + +Accordion Component SOV-567 diff --git a/packages/ui/src/1_atoms/Accordion/Accordion.module.css b/packages/ui/src/1_atoms/Accordion/Accordion.module.css new file mode 100644 index 0000000000..8086ad6310 --- /dev/null +++ b/packages/ui/src/1_atoms/Accordion/Accordion.module.css @@ -0,0 +1,27 @@ +.accordion { + @apply flex flex-col my-3; +} + +.label { + @apply flex flex-row cursor-pointer items-stretch; + + &.disabled, + &:disabled { + @apply opacity-50 cursor-default; + } +} + +.arrow { + @apply ml-2 flex flex-col items-center justify-center; +} + +.icon { + @apply transition-transform; + &.isOpen { + @apply transform rotate-180; + } +} + +.content { + @apply mt-2; +} diff --git a/packages/ui/src/1_atoms/Accordion/Accordion.stories.tsx b/packages/ui/src/1_atoms/Accordion/Accordion.stories.tsx new file mode 100644 index 0000000000..b549234a04 --- /dev/null +++ b/packages/ui/src/1_atoms/Accordion/Accordion.stories.tsx @@ -0,0 +1,84 @@ +import { useArgs } from '@storybook/client-api'; +import { Story, Meta } from '@storybook/react'; + +import React, { ComponentProps, useCallback } from 'react'; + +import { + Dropdown, + DropdownMode, + DropdownSize, + Menu, + MenuItem, +} from '../../2_molecules'; +import { Paragraph } from '../Paragraph/Paragraph'; +import { Accordion } from './Accordion'; + +export default { + title: 'Atoms/Accordion', + component: Accordion, +} as Meta; + +const Template: Story> = args => { + const [, updateArgs] = useArgs(); + const handleOnChange = useCallback( + (toOpen: boolean) => updateArgs({ open: toOpen }), + [updateArgs], + ); + + return ; +}; + +export const Default = Template.bind({}); +Default.args = { + label: 'Test (click to toggle)', + children:
Simple Test content
, + disabled: false, + dataLayoutId: 'accordion-simple', +}; + +export const RichContent = Template.bind({}); +RichContent.args = { + label: 'Test (click to toggle)', + children: ( +
+ Content panel + + + + + + + +
+ ), + disabled: false, + dataLayoutId: 'accordion-richcontent', +}; + +export const OpenAndDisabled = Template.bind({}); +OpenAndDisabled.args = { + label: 'Test (disabled)', + children: ( +
+ Content panel + + + + + + + +
+ ), + disabled: true, + open: true, + dataLayoutId: 'accordion-opendisabled', +}; diff --git a/packages/ui/src/1_atoms/Accordion/Accordion.test.tsx b/packages/ui/src/1_atoms/Accordion/Accordion.test.tsx new file mode 100644 index 0000000000..142d8e6b5f --- /dev/null +++ b/packages/ui/src/1_atoms/Accordion/Accordion.test.tsx @@ -0,0 +1,73 @@ +import { render } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + +import React from 'react'; + +import { Accordion } from './Accordion'; + +describe('Accordion', () => { + it('renders accordion', () => { + const { getByText } = render( + +
Content
+
, + ); + expect(getByText('Test')).toBeInTheDocument(); + }); + + it('calls eventHandler on click', () => { + const handleClick = jest.fn(); + const { getByTestId } = render( + +
Content
+
, + ); + userEvent.click(getByTestId('accordion-simple')); + expect(handleClick).toHaveBeenCalledTimes(1); + }); + + it('shows content on click', async () => { + const handleClick = () => { + render( + +
Content
+
, + ); + }; + const { getByTestId } = render( + +
Content
+
, + ); + userEvent.click(getByTestId('accordion-simple')); + expect(getByTestId('content-to-show')).toBeInTheDocument(); + }); + + it('renders disabled accordion and prevents clicks on it', () => { + const handleClick = jest.fn(); + const { getByTestId } = render( + +
Content
+
, + ); + userEvent.click(getByTestId('accordion-simple')); + expect(handleClick).toHaveBeenCalledTimes(0); + }); +}); diff --git a/packages/ui/src/1_atoms/Accordion/Accordion.tsx b/packages/ui/src/1_atoms/Accordion/Accordion.tsx new file mode 100644 index 0000000000..80384ae5f5 --- /dev/null +++ b/packages/ui/src/1_atoms/Accordion/Accordion.tsx @@ -0,0 +1,71 @@ +import React, { ReactNode, FC, useCallback } from 'react'; + +import classNames from 'classnames'; + +import { Heading } from '../Heading/Heading'; +import { HeadingType } from '../Heading/Heading.types'; +import { Icon } from '../Icon/Icon'; +import { IconNames } from '../Icon/Icon.types'; +import styles from './Accordion.module.css'; + +export interface IAccordionProps { + label: ReactNode; + children: ReactNode; + className?: string; + disabled?: boolean; + open?: boolean; + onClick?: (toOpen: boolean) => void; + dataLayoutId?: string; +} + +export const Accordion: FC = ({ + label, + children, + className, + disabled = false, + open = false, + onClick, + dataLayoutId, +}) => { + const onClickCallback = useCallback( + () => !disabled && onClick?.(!open), + [disabled, open, onClick], + ); + + return ( +
+ + {open && ( +
+ {children} +
+ )} +
+ ); +}; diff --git a/packages/ui/src/1_atoms/Accordion/index.ts b/packages/ui/src/1_atoms/Accordion/index.ts new file mode 100644 index 0000000000..63f62bc659 --- /dev/null +++ b/packages/ui/src/1_atoms/Accordion/index.ts @@ -0,0 +1 @@ +export * from './Accordion'; diff --git a/packages/ui/src/1_atoms/Icon/Icon.types.ts b/packages/ui/src/1_atoms/Icon/Icon.types.ts index fa8376e823..4de038d960 100644 --- a/packages/ui/src/1_atoms/Icon/Icon.types.ts +++ b/packages/ui/src/1_atoms/Icon/Icon.types.ts @@ -3,12 +3,15 @@ import type { IconProp } from '@fortawesome/fontawesome-svg-core'; import { ReactNode } from 'react'; export enum IconNames { + ARROW_UP = 'arrow-up', + ARROW_BACK = 'arrow-back', ARROW_DOWN_WIDE = 'arrow-down-wide', ARROW_DOWN = 'arrow-down', ARROW_RIGHT = 'arrow-right', ARROW_FORWARD = 'arrow-forward', ARROW_BACK = 'arrow-back', DEPOSIT = 'deposit', + DISCONNECT = 'disconnect', EDIT = 'edit', FAILED_TX = 'failed-tx', INFO = 'info', diff --git a/packages/ui/src/1_atoms/Icon/iconNames.ts b/packages/ui/src/1_atoms/Icon/iconNames.ts deleted file mode 100644 index adb470616a..0000000000 --- a/packages/ui/src/1_atoms/Icon/iconNames.ts +++ /dev/null @@ -1,26 +0,0 @@ -export const ARROW_DOWN_WIDE = 'arrow-down-wide'; -export const ARROW_DOWN = 'arrow-down'; -export const ARROW_RIGHT = 'arrow-right'; -export const ARROW_FORWARD = 'arrow-forward'; -export const ARROW_BACK = 'arrow-back'; -export const DEPOSIT = 'deposit'; -export const EDIT = 'edit'; -export const FAILED_TX = 'failed-tx'; -export const INFO = 'info'; -export const MEATBALLS_MENU = 'meatballs-menu'; -export const NEW_TAB = 'new-tab'; -export const NOTIFICATIONS_ACTIVE = 'notifications-active'; -export const NOTIFICATIONS = 'notifications'; -export const PENDING = 'pending'; -export const SEARCH = 'search'; -export const SETTINGS = 'settings'; -export const SUCCESS_ICON = 'success-icon'; -export const SWAP_ARROW = 'swap-arrow'; -export const TRANSFER = 'transfer'; -export const TREND_ARROW_UP = 'trend-arrow-up'; -export const TREND_ARROW_DOWN = 'trend-arrow-down'; -export const WARNING = 'warning'; -export const WITHDRAW = 'withdraw'; -export const X_MARK = 'x-mark'; -export const COPY = 'copy'; -export const EXIT = 'exit'; diff --git a/packages/ui/src/1_atoms/Icon/iconSvgPaths.ts b/packages/ui/src/1_atoms/Icon/iconSvgPaths.ts index 536a71744f..8f1b6c3f88 100644 --- a/packages/ui/src/1_atoms/Icon/iconSvgPaths.ts +++ b/packages/ui/src/1_atoms/Icon/iconSvgPaths.ts @@ -1,6 +1,9 @@ import { IconName } from './Icon.types'; export const IconSvgPaths: Record = { + 'arrow-up': [ + 'M3.70223 18.6016L12.5 9.82311L21.2978 18.6016L24 15.8994L12.5 4.39939L0.999999 15.8994L3.70223 18.6016Z', + ], 'arrow-down-wide': [ 'm24,11.94l-12,12.06l-12,-12.06l8.14,0l0,-11.94l7.72,0l0,11.94l8.14,0z', ], @@ -19,6 +22,9 @@ export const IconSvgPaths: Record = { deposit: [ 'M12.2352 17.7504L8.2832 13.7824H11.2472V6.8112H13.2232V13.7824H16.1872L12.2352 17.7504Z', ], + disconnect: [ + 'M18 5.88889L16.308 7.61222L19.404 10.7778H7.2V13.2222H19.404L16.308 16.3756L18 18.1111L24 12L18 5.88889ZM2.4 3.44444H12V1H2.4C1.08 1 0 2.1 0 3.44444V20.5556C0 21.9 1.08 23 2.4 23H12V20.5556H2.4V3.44444Z', + ], edit: [ 'M3.6 16.8996V20.4H7.1004L17.4204 10.08L13.92 6.5772L3.6 16.8996ZM20.13 7.3704C20.2171 7.28396 20.2862 7.18113 20.3333 7.06786C20.3805 6.95459 20.4048 6.8331 20.4048 6.7104C20.4048 6.5877 20.3805 6.46621 20.3333 6.35294C20.2862 6.23967 20.2171 6.13685 20.13 6.0504L17.946 3.8664C17.8596 3.77932 17.7567 3.71021 17.6435 3.66305C17.5302 3.61589 17.4087 3.59161 17.286 3.59161C17.1633 3.59161 17.0418 3.61589 16.9285 3.66305C16.8153 3.71021 16.7124 3.77932 16.626 3.8664L14.922 5.5776L18.4224 9.078L20.13 7.3704Z', ], diff --git a/packages/ui/src/1_atoms/index.tsx b/packages/ui/src/1_atoms/index.tsx index 3ba3e4ca7e..6619bc3151 100644 --- a/packages/ui/src/1_atoms/index.tsx +++ b/packages/ui/src/1_atoms/index.tsx @@ -6,3 +6,4 @@ export * from './Portal'; export * from './Paragraph'; export * from './Badge'; export * from './Link'; +export * from './Accordion';