From 4e1a96b4ef0ceda8c486655e16a8d4b8a72e55ad Mon Sep 17 00:00:00 2001 From: Garrett Bear Date: Wed, 19 Apr 2023 10:36:01 -0700 Subject: [PATCH] Feat/18308/ds popover header component (#18489) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add popover component popperjs init popperjs hook init popper arrow styles fix popover story add popover positions constant story testing popover structure popper placement make forwardref fix popover with TS updates modifiers createPortal add useClickAway hook newer popover component build simplifed popperjs with toggle to show/hide toggle popover modal version popover progress 65% add hover functionality hide folder storybook demo add close button props working popover with arrow title prop breaking popover TS conversion TS updates update test add test add arrow test add stories remove unused hook fix docs add popoverheader types fix Fix typo: detetcted-tokens-link -> detected-tokens-link (#18408) Typography to text (#18382) * Typography to text * Update README.md * Update README.md * minor changes in custom file * minor change * Resolved Conflict issues --------- Co-authored-by: Nidhi Kumari fix: Pass correct optimism chain id to gas estimation (#18478) removes unnecessary images (#18484) Fix firsttimeloaded logic (#18344) * use session storage, instead of chrome.runtime.onStartup and globalThis, for firstTimeLoaded architecture * Ensure account tracker accounts remain defined upon service worker restart * lint fix * Simplify code * Only call browser.storage.session in mv3 * Only call browser.storage.session.set after resetStates in mv3 * fix metamask controller reset states unit tests * fix test * fix test * Actually fix tests * lint fix [FLASK] More Snaps E2E Optimization and Delay Reductions (#18245) * bip32 delay reduction * asserts changed to waitFors in 32/44 * scrollTo change * replaced delay for firefox flake * more reduced delays * more delay reductions and changes * raise paralellism to 4 for snaps tests * additional delay changes * fixed update code * removed comment * removed another comment Fix switch-ethereum-chain handler by passing configuration id to setA… (#18483) * Fix switch-ethereum-chain handler by passing configuration id to setActiveNetwork * fix e2e test * Fix e2e tests * Update test/e2e/tests/switch-custom-network.spec.js Co-authored-by: legobeat <109787230+legobeat@users.noreply.github.com> * Revert "Update test/e2e/tests/switch-custom-network.spec.js" This reverts commit be533ff7f25e1fd42e951d9b817b8438035ae256. --------- Co-authored-by: legobeat <109787230+legobeat@users.noreply.github.com> Bumping notification id's to 18 & 19 (#18460) * Popover header update with TS ButtonIcon * update PopoverHeader types * update using new Text enums * readme fix * direct file import * remove forwardRef and add action argtypes * remove console.logs * add arg types and fix TS on HeaderBase * george nits * popover header snapshot update --------- Co-authored-by: legobeat <109787230+legobeat@users.noreply.github.com> --- .../header-base/header-base.stories.tsx | 22 ++--- ui/components/component-library/index.js | 1 + .../popover-header/README.mdx | 98 +++++++++++++++++++ .../popover-header.test.tsx.snap | 20 ++++ .../component-library/popover-header/index.ts | 2 + .../popover-header/popover-header.stories.tsx | 65 ++++++++++++ .../popover-header/popover-header.test.tsx | 61 ++++++++++++ .../popover-header/popover-header.tsx | 61 ++++++++++++ .../popover-header/popover-header.types.ts | 42 ++++++++ 9 files changed, 361 insertions(+), 11 deletions(-) create mode 100644 ui/components/component-library/popover-header/README.mdx create mode 100644 ui/components/component-library/popover-header/__snapshots__/popover-header.test.tsx.snap create mode 100644 ui/components/component-library/popover-header/index.ts create mode 100644 ui/components/component-library/popover-header/popover-header.stories.tsx create mode 100644 ui/components/component-library/popover-header/popover-header.test.tsx create mode 100644 ui/components/component-library/popover-header/popover-header.tsx create mode 100644 ui/components/component-library/popover-header/popover-header.types.ts diff --git a/ui/components/component-library/header-base/header-base.stories.tsx b/ui/components/component-library/header-base/header-base.stories.tsx index c02ade945..6079b9f69 100644 --- a/ui/components/component-library/header-base/header-base.stories.tsx +++ b/ui/components/component-library/header-base/header-base.stories.tsx @@ -14,7 +14,7 @@ import { AlignItems, BackgroundColor, TextVariant, - TEXT_ALIGN, + TextAlign, } from '../../../helpers/constants/design-system'; import { HeaderBase } from './header-base'; import README from './README.mdx'; @@ -37,7 +37,7 @@ export const DefaultStory = Template.bind({}); DefaultStory.args = { children: ( - + Title is sentence case no period ), @@ -62,7 +62,7 @@ DefaultStory.storyName = 'Default'; export const Children = (args) => { return ( - + Title is sentence case no period @@ -82,7 +82,7 @@ export const StartAccessory = (args) => { } {...args} > - + Title is sentence case no period @@ -102,7 +102,7 @@ export const EndAccessory = (args) => { } {...args} > - + Title is sentence case no period @@ -116,7 +116,7 @@ export const UseCaseDemos = (args) => ( Title is sentence case no period @@ -139,7 +139,7 @@ export const UseCaseDemos = (args) => ( > Title is sentence case no period @@ -162,7 +162,7 @@ export const UseCaseDemos = (args) => ( > Title is sentence case no period @@ -193,7 +193,7 @@ export const UseCaseDemos = (args) => ( > Title is sentence case no period @@ -225,7 +225,7 @@ export const UseCaseDemos = (args) => ( > Title is sentence case no period @@ -260,7 +260,7 @@ export const UseCaseDemos = (args) => ( > Title is sentence case no period diff --git a/ui/components/component-library/index.js b/ui/components/component-library/index.js index 329c9e25c..c9eccf654 100644 --- a/ui/components/component-library/index.js +++ b/ui/components/component-library/index.js @@ -39,3 +39,4 @@ export { ModalOverlay } from './modal-overlay'; export { BannerBase } from './banner-base'; export { BannerAlert, BANNER_ALERT_SEVERITIES } from './banner-alert'; export { BannerTip, BannerTipLogoType } from './banner-tip'; +export { PopoverHeader } from './popover-header'; diff --git a/ui/components/component-library/popover-header/README.mdx b/ui/components/component-library/popover-header/README.mdx new file mode 100644 index 000000000..6910ec10c --- /dev/null +++ b/ui/components/component-library/popover-header/README.mdx @@ -0,0 +1,98 @@ +import { Story, Canvas, ArgsTable } from '@storybook/addon-docs'; +import { PopoverHeader } from './popover-header'; + +# PopoverHeader + +PopoverHeader is built on top of [HeaderBase](/docs/components-componentlibrary-headerbase--default-story) component with the most common use case of a back button in the startAccessory position, title, and close button in the endAccessory position. + + + + + +## Props + +The `PopoverHeader` accepts all props below as well as all [Box](/docs/ui-components-ui-box-box-stories-js--default-story#props) component props + + + +### Children + +Wrapping string content in the `PopoverHeader` component will be rendered in the center of the header with the default title `Text` component. + + + + + +```jsx +import { PopoverHeader } from '../../component-library'; + +Title is sentence case no period; +``` + +### onBack + +Use the onClick handler `onBack` prop to render the `ButtonIcon` back button in the startAccessory position. + +Use the `backButtonProps` prop to pass additional props to the `ButtonIcon` back button. + + + + + +```jsx +import { PopoverHeader } from '../../component-library'; + + console.log('Back button click')}> + OnBack Demo +; +``` + +### onClose + +Use the onClick handler `onClose` prop to render the `ButtonIcon` back button in the endAccessory position. + +Use the `backButtonProps` prop to pass additional props to the `ButtonIcon` back button. + + + + + +```jsx +import { PopoverHeader } from '../../component-library'; + + console.log('Back button click')}> + OnClose Demo +; +``` + +### startAccessory + +Use the `startAccessory` prop to render a component in the startAccessory position. This will override the default back `ButtonIcon`. + + + + + +```jsx +import { PopoverHeader, Button, BUTTON_SIZES } from '../../component-library'; + +Demo}> + StartAccessory +; +``` + +### endAccessory + +Use the `endAccessory` prop to render a component in the endAccessory position. This will override the default close `ButtonIcon`. + + + + + +```jsx +import { PopoverHeader, Button, BUTTON_SIZES } from '../../component-library'; + +Demo}> + EndAccessory +; +``` diff --git a/ui/components/component-library/popover-header/__snapshots__/popover-header.test.tsx.snap b/ui/components/component-library/popover-header/__snapshots__/popover-header.test.tsx.snap new file mode 100644 index 000000000..ff2a28597 --- /dev/null +++ b/ui/components/component-library/popover-header/__snapshots__/popover-header.test.tsx.snap @@ -0,0 +1,20 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`PopoverHeader should render PopoverHeader correctly 1`] = ` +
+
+
+

+ Popover Header +

+
+
+
+`; diff --git a/ui/components/component-library/popover-header/index.ts b/ui/components/component-library/popover-header/index.ts new file mode 100644 index 000000000..158a08ff6 --- /dev/null +++ b/ui/components/component-library/popover-header/index.ts @@ -0,0 +1,2 @@ +export { PopoverHeader } from './popover-header'; +export type { PopoverHeaderProps } from './popover-header.types'; diff --git a/ui/components/component-library/popover-header/popover-header.stories.tsx b/ui/components/component-library/popover-header/popover-header.stories.tsx new file mode 100644 index 000000000..a5f5d175d --- /dev/null +++ b/ui/components/component-library/popover-header/popover-header.stories.tsx @@ -0,0 +1,65 @@ +import React from 'react'; +import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { BUTTON_SIZES, Button } from '..'; +import { PopoverHeader } from './popover-header'; +import README from './README.mdx'; + +export default { + title: 'Components/ComponentLibrary/PopoverHeader', + component: PopoverHeader, + parameters: { + docs: { + page: README, + }, + }, + argTypes: { + children: { control: 'text' }, + className: { control: 'text' }, + onBack: { action: 'onBack' }, + onClose: { action: 'onClose' }, + }, + args: { + children: 'PopoverHeader', + }, +} as ComponentMeta; + +const Template: ComponentStory = (args) => { + return PopoverHeader; +}; + +export const DefaultStory = Template.bind({}); +DefaultStory.storyName = 'Default'; + +export const Children: ComponentStory = (args) => ( + +); + +Children.args = { + children: 'PopoverHeader Title', +}; + +export const OnBack: ComponentStory = (args) => ( + OnBack Demo +); + +export const OnClose: ComponentStory = (args) => ( + OnClose Demo +); + +export const StartAccessory: ComponentStory = (args) => ( + Demo} + {...args} + > + StartAccessory + +); + +export const EndAccessory: ComponentStory = (args) => ( + Demo} + {...args} + > + EndAccessory + +); diff --git a/ui/components/component-library/popover-header/popover-header.test.tsx b/ui/components/component-library/popover-header/popover-header.test.tsx new file mode 100644 index 000000000..ec5e4e203 --- /dev/null +++ b/ui/components/component-library/popover-header/popover-header.test.tsx @@ -0,0 +1,61 @@ +/* eslint-disable jest/require-top-level-describe */ +import { render, fireEvent } from '@testing-library/react'; +import React from 'react'; +import { PopoverHeader } from './popover-header'; + +describe('PopoverHeader', () => { + it('should render PopoverHeader correctly', () => { + const { getByTestId, container } = render( + + Popover Header + , + ); + expect(getByTestId('popover-header')).toHaveClass('mm-popover-header'); + expect(container).toMatchSnapshot(); + }); + + it('should render popover header title', () => { + const { getByText } = render( + + Popover Header Test + , + ); + expect(getByText('Popover Header Test')).toBeDefined(); + }); + + it('should render popover header back button', () => { + const onBackTest = jest.fn(); + const { getByTestId } = render( + + Popover + , + ); + + const backButton = getByTestId('back'); + fireEvent.click(backButton); + + expect(onBackTest).toHaveBeenCalled(); + }); + + it('should render popover header close button', () => { + const onCloseTest = jest.fn(); + const { getByTestId } = render( + + Popover + , + ); + + const closeButton = getByTestId('close'); + fireEvent.click(closeButton); + + expect(onCloseTest).toHaveBeenCalled(); + }); +}); diff --git a/ui/components/component-library/popover-header/popover-header.tsx b/ui/components/component-library/popover-header/popover-header.tsx new file mode 100644 index 000000000..1d6039e34 --- /dev/null +++ b/ui/components/component-library/popover-header/popover-header.tsx @@ -0,0 +1,61 @@ +import React from 'react'; +import classnames from 'classnames'; +import { HeaderBase, Text, ButtonIcon, ButtonIconSize, IconName } from '..'; +import { + TextVariant, + TextAlign, +} from '../../../helpers/constants/design-system'; +import { useI18nContext } from '../../../hooks/useI18nContext'; +import { PopoverHeaderProps } from '.'; + +export const PopoverHeader: React.FC = ({ + children, + className = '', + startAccessory, + endAccessory, + onClose, + closeButtonProps, + onBack, + backButtonProps, + ...props +}) => { + const t = useI18nContext(); + return ( + + )) + } + endAccessory={ + endAccessory || + (onClose && ( + + )) + } + {...props} + > + {typeof children === 'string' ? ( + + {children} + + ) : ( + children + )} + + ); +}; diff --git a/ui/components/component-library/popover-header/popover-header.types.ts b/ui/components/component-library/popover-header/popover-header.types.ts new file mode 100644 index 000000000..66f8c7379 --- /dev/null +++ b/ui/components/component-library/popover-header/popover-header.types.ts @@ -0,0 +1,42 @@ +import React from 'react'; +import type { ButtonIconProps } from '../button-icon/button-icon.types'; +import type { HeaderBaseProps } from '../header-base'; + +export interface PopoverHeaderProps extends HeaderBaseProps { + /** + * The contents within the PopoverHeader positioned middle (popular for title use case) + */ + children?: React.ReactNode; + /** + * Additional classNames to be added to the Popover component + */ + className?: string; + /** + * The onClick handler for the back `ButtonIcon` + * When passed this will allow for the back `ButtonIcon` to show + */ + onBack?: () => void; + /** + * The props to pass to the back `ButtonIcon` + */ + backButtonProps?: ButtonIconProps; + /** + * The start (left) content area of PopoverHeader + * Default to have the back `ButtonIcon` when `onBack` is passed, but passing a `startAccessory` will override this + */ + startAccessory?: React.ReactNode; + /** + * The onClick handler for the close `ButtonIcon` + * When passed this will allow for the close `ButtonIcon` to show + */ + onClose?: () => void; + /** + * The props to pass to the close `ButtonIcon` + */ + closeButtonProps?: ButtonIconProps; + /** + * The end (right) content area of PopoverHeader + * Default to have the close `ButtonIcon` when `onClose` is passed, but passing a `endAccessory` will override this + */ + endAccessory?: React.ReactNode; +}