diff options
author | David Cho-Lerat <david.cho-lerat@sonarsource.com> | 2023-05-12 16:25:44 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2023-05-17 20:02:41 +0000 |
commit | 8e10ac9ab50a1e2a0f40ba1ad07907a8017a02df (patch) | |
tree | b49cef0a9647a88dcef14a8adb55cca7ca0c84f4 /server/sonar-web/design-system/src/components/modal | |
parent | a4e7896a64696dab6beacc0219534060a755ad20 (diff) | |
download | sonarqube-8e10ac9ab50a1e2a0f40ba1ad07907a8017a02df.tar.gz sonarqube-8e10ac9ab50a1e2a0f40ba1ad07907a8017a02df.zip |
SONAR-19170 Create new Modal component in design-system/
Diffstat (limited to 'server/sonar-web/design-system/src/components/modal')
11 files changed, 693 insertions, 0 deletions
diff --git a/server/sonar-web/design-system/src/components/modal/Modal.tsx b/server/sonar-web/design-system/src/components/modal/Modal.tsx new file mode 100644 index 00000000000..95d6213cbb8 --- /dev/null +++ b/server/sonar-web/design-system/src/components/modal/Modal.tsx @@ -0,0 +1,158 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import { Global, css, useTheme } from '@emotion/react'; +import classNames from 'classnames'; +import { ReactNode } from 'react'; +import ReactModal from 'react-modal'; +import tw from 'twin.macro'; +import { themeColor } from '../../helpers'; +import { REACT_DOM_CONTAINER } from '../../helpers/constants'; +import { translate } from '../../helpers/l10n'; +import { Theme } from '../../types/theme'; +import { ButtonSecondary } from '../buttons'; +import { ModalBody } from './ModalBody'; +import { ModalFooter } from './ModalFooter'; +import { ModalHeader } from './ModalHeader'; + +ReactModal.setAppElement(REACT_DOM_CONTAINER); + +interface CommonProps { + closeOnOverlayClick?: boolean; + isLarge?: boolean; + isOpen?: boolean; + isScrollable?: boolean; + onClose: VoidFunction; +} + +interface ChildrenProp { + children: React.ReactNode; +} + +interface NotChildrenProp { + children?: never; +} + +interface SectionsProps { + body: React.ReactNode; + headerDescription?: string | ReactNode; + headerTitle: string | ReactNode; + loading?: boolean; + primaryButton?: ReactNode; + secondaryButtonLabel: ReactNode; +} + +type NotSectionsProps = { + [prop in keyof SectionsProps]?: never; +}; + +export type PropsWithChildren = CommonProps & ChildrenProp & NotSectionsProps; + +export type PropsWithSections = CommonProps & SectionsProps & NotChildrenProp; + +type Props = PropsWithChildren | PropsWithSections; + +function hasNoChildren(props: Partial<Props>): props is PropsWithSections { + return (props as PropsWithChildren).children === undefined; +} + +export function Modal({ + closeOnOverlayClick = true, + isLarge, + isOpen = true, + isScrollable = true, + onClose, + ...props +}: Props) { + const theme = useTheme(); + + return ( + <> + <Global styles={globalStyles({ theme })} /> + + <ReactModal + className={classNames('design-system-modal-contents', { large: isLarge })} + isOpen={isOpen} + onRequestClose={onClose} + overlayClassName="design-system-modal-overlay" + shouldCloseOnEsc={true} + shouldCloseOnOverlayClick={closeOnOverlayClick} + shouldFocusAfterRender={true} + shouldReturnFocusAfterClose={true} + > + {hasNoChildren(props) ? ( + <> + <ModalHeader description={props.headerDescription} title={props.headerTitle} /> + + <ModalBody isScrollable={isScrollable}>{props.body}</ModalBody> + + <ModalFooter + loading={props.loading} + primaryButton={props.primaryButton} + secondaryButton={ + <ButtonSecondary + className="js-modal-close sw-capitalize" + disabled={props.loading} + onClick={onClose} + type="reset" + > + {props.secondaryButtonLabel ?? translate('close')} + </ButtonSecondary> + } + /> + </> + ) : ( + (props as PropsWithChildren).children + )} + </ReactModal> + </> + ); +} + +const globalStyles = ({ theme }: { theme: Theme }) => css` + .design-system-modal-contents { + ${tw`sw-container sw-flex sw-flex-col`} + ${tw`sw-p-9`} + ${tw`sw-rounded-2`} + ${tw`sw-z-modal`} + + background-color: ${themeColor('modalContents')({ theme })}; + max-height: calc(100vh - 30px); + min-height: 160px; + width: 544px; + + &.large { + max-width: 1280px; + min-width: 1040px; + } + } + + .design-system-modal-overlay { + ${tw`sw-fixed sw-inset-0`} + ${tw`sw-flex sw-items-center sw-justify-center`} + ${tw`sw-z-modal-overlay`} + + background-color: ${themeColor('modalOverlay')({ theme })}; + } +`; + +Modal.Body = ModalBody; +Modal.Footer = ModalFooter; +Modal.Header = ModalHeader; diff --git a/server/sonar-web/design-system/src/components/modal/ModalBody.tsx b/server/sonar-web/design-system/src/components/modal/ModalBody.tsx new file mode 100644 index 00000000000..5a3b1f19832 --- /dev/null +++ b/server/sonar-web/design-system/src/components/modal/ModalBody.tsx @@ -0,0 +1,47 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import styled from '@emotion/styled'; +import classNames from 'classnames'; +import { ReactNode } from 'react'; +import tw from 'twin.macro'; +import { themeColor } from '../../helpers/theme'; + +interface Props { + children: ReactNode; + isScrollable?: boolean; +} + +export function ModalBody({ children, isScrollable = true }: Props) { + return <StyledMain className={classNames({ scrollable: isScrollable })}>{children}</StyledMain>; +} + +const StyledMain = styled.main` + ${tw`sw-body-sm`} + ${tw`sw-pr-3`} // to accomodate a possible scrollbar + ${tw`sw-my-12`} + ${tw`sw-overflow-x-hidden`} + + color: ${themeColor('pageContent')}; + + &.scrollable { + overflow-y: auto; + } +`; diff --git a/server/sonar-web/design-system/src/components/modal/ModalFooter.tsx b/server/sonar-web/design-system/src/components/modal/ModalFooter.tsx new file mode 100644 index 00000000000..72d75b6cce5 --- /dev/null +++ b/server/sonar-web/design-system/src/components/modal/ModalFooter.tsx @@ -0,0 +1,43 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import styled from '@emotion/styled'; +import tw from 'twin.macro'; +import { DeferredSpinner } from '../DeferredSpinner'; + +interface Props { + loading?: boolean; + primaryButton?: React.ReactNode; + secondaryButton: React.ReactNode; +} + +export function ModalFooter({ loading = false, primaryButton, secondaryButton }: Props) { + return ( + <StyledFooter> + <DeferredSpinner loading={loading} /> + {primaryButton} + {secondaryButton} + </StyledFooter> + ); +} + +const StyledFooter = styled.footer` + ${tw`sw-flex sw-gap-3 sw-items-center sw-justify-end`} +`; diff --git a/server/sonar-web/design-system/src/components/modal/ModalHeader.tsx b/server/sonar-web/design-system/src/components/modal/ModalHeader.tsx new file mode 100644 index 00000000000..eaa02e175cb --- /dev/null +++ b/server/sonar-web/design-system/src/components/modal/ModalHeader.tsx @@ -0,0 +1,51 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import styled from '@emotion/styled'; +import { ReactNode } from 'react'; +import tw from 'twin.macro'; +import { themeColor } from '../../helpers/theme'; + +interface Props { + description?: string | ReactNode; + title: string | ReactNode; +} + +export function ModalHeader({ description, title }: Props) { + return ( + <header> + <Title>{title}</Title> + {description && <Description>{description}</Description>} + </header> + ); +} + +const Description = styled.p` + ${tw`sw-body-sm`} + ${tw`sw-mt-2`} + + color: ${themeColor('pageContent')}; +`; + +const Title = styled.p` + ${tw`sw-heading-lg`} + + color: ${themeColor('pageTitle')}; +`; diff --git a/server/sonar-web/design-system/src/components/modal/__tests__/Modal-test.tsx b/server/sonar-web/design-system/src/components/modal/__tests__/Modal-test.tsx new file mode 100644 index 00000000000..86085f547dd --- /dev/null +++ b/server/sonar-web/design-system/src/components/modal/__tests__/Modal-test.tsx @@ -0,0 +1,90 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import { screen } from '@testing-library/react'; +import { render } from '../../../helpers/testUtils'; +import { Modal, PropsWithChildren, PropsWithSections } from '../Modal'; + +it('should render default modal with predefined content', async () => { + setupPredefinedContent({ + body: 'Modal body', + headerTitle: 'Hello', + headerDescription: 'Does this look OK?', + secondaryButtonLabel: undefined, // should use the default of 'Close' + }); + + expect(await screen.findByText('Modal body')).toBeVisible(); + expect(await screen.findByText('Hello')).toBeVisible(); + expect(await screen.findByText('Does this look OK?')).toBeVisible(); + expect(await screen.findByRole('button', { name: 'close' })).toBeVisible(); +}); + +it('should request close when pressing esc', async () => { + const onClose = jest.fn(); + const { user } = setupPredefinedContent({ onClose }); + + await user.keyboard('{Escape}'); + + expect(onClose).toHaveBeenCalled(); +}); + +it('should render modal with loose content', async () => { + setupLooseContent(undefined, <div>Hello</div>); + + expect(await screen.findByText('Hello')).toBeVisible(); +}); + +it('should request close when pressing esc on loose content', async () => { + const onClose = jest.fn(); + const { user } = setupLooseContentWithMultipleChildren({ onClose }); + + await user.keyboard('{Escape}'); + + expect(onClose).toHaveBeenCalled(); +}); + +function setupPredefinedContent(props: Partial<PropsWithSections> = {}) { + return render( + <Modal + body="Body" + headerTitle="Hello" + onClose={jest.fn()} + secondaryButtonLabel="Close" + {...props} + /> + ); +} + +function setupLooseContent(props: Partial<PropsWithChildren> = {}, children = <div />) { + return render( + <Modal onClose={jest.fn()} {...props}> + {children} + </Modal> + ); +} + +function setupLooseContentWithMultipleChildren(props: Partial<PropsWithChildren> = {}) { + return render( + <Modal onClose={jest.fn()} {...props}> + <div>Hello there!</div> + <div>How are you?</div> + </Modal> + ); +} diff --git a/server/sonar-web/design-system/src/components/modal/__tests__/ModalBody-test.tsx b/server/sonar-web/design-system/src/components/modal/__tests__/ModalBody-test.tsx new file mode 100644 index 00000000000..690cd99d821 --- /dev/null +++ b/server/sonar-web/design-system/src/components/modal/__tests__/ModalBody-test.tsx @@ -0,0 +1,33 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import { render } from '../../../helpers/testUtils'; +import { ModalBody } from '../ModalBody'; + +it('renders with children', () => { + const children = <div>Hello!</div>; + const { container } = setup(children); + + expect(container).toMatchSnapshot(); +}); + +function setup(children = <div />) { + return render(<ModalBody>{children}</ModalBody>); +} diff --git a/server/sonar-web/design-system/src/components/modal/__tests__/ModalFooter-test.tsx b/server/sonar-web/design-system/src/components/modal/__tests__/ModalFooter-test.tsx new file mode 100644 index 00000000000..ab2c19c133d --- /dev/null +++ b/server/sonar-web/design-system/src/components/modal/__tests__/ModalFooter-test.tsx @@ -0,0 +1,56 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import { render } from '../../../helpers/testUtils'; +import { FCProps } from '../../../types/misc'; +import { ModalFooter } from '../ModalFooter'; + +it('should render with secondary button', () => { + const { container } = setupWithProps({ + secondaryButton: ( + <button onClick={() => {}} type="button"> + Close + </button> + ), + }); + + expect(container).toMatchSnapshot(); +}); + +it('should render with primary and secondary buttons', () => { + const { container } = setupWithProps({ + primaryButton: ( + <button onClick={undefined} type="button"> + Primary + </button> + ), + secondaryButton: ( + <button onClick={undefined} type="reset"> + Reset + </button> + ), + }); + + expect(container).toMatchSnapshot(); +}); + +function setupWithProps(props: Partial<FCProps<typeof ModalFooter>> = {}) { + return render(<ModalFooter secondaryButton={<div />} {...props} />); +} diff --git a/server/sonar-web/design-system/src/components/modal/__tests__/ModalHeader-test.tsx b/server/sonar-web/design-system/src/components/modal/__tests__/ModalHeader-test.tsx new file mode 100644 index 00000000000..a3a163a66d1 --- /dev/null +++ b/server/sonar-web/design-system/src/components/modal/__tests__/ModalHeader-test.tsx @@ -0,0 +1,45 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import { render } from '../../../helpers/testUtils'; +import { FCProps } from '../../../types/misc'; +import { ModalHeader } from '../ModalHeader'; + +it('should use the default title if not provided', () => { + const { container } = setupWithProps(); + + expect(container).toMatchSnapshot(); +}); + +it('should render with title', () => { + const { container } = setupWithProps({ title: 'Foo' }); + + expect(container).toMatchSnapshot(); +}); + +it('should render with title and description', () => { + const { container } = setupWithProps({ title: 'Foo', description: 'Bar' }); + + expect(container).toMatchSnapshot(); +}); + +function setupWithProps(props: Partial<FCProps<typeof ModalHeader>> = {}) { + return render(<ModalHeader title="Modal title" {...props} />); +} diff --git a/server/sonar-web/design-system/src/components/modal/__tests__/__snapshots__/ModalBody-test.tsx.snap b/server/sonar-web/design-system/src/components/modal/__tests__/__snapshots__/ModalBody-test.tsx.snap new file mode 100644 index 00000000000..8f64b28df6b --- /dev/null +++ b/server/sonar-web/design-system/src/components/modal/__tests__/__snapshots__/ModalBody-test.tsx.snap @@ -0,0 +1,29 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders with children 1`] = ` +.emotion-0 { + font-family: Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"; + font-size: 0.875rem; + line-height: 1.25rem; + font-weight: 400; + padding-right: 0.75rem; + margin-top: 3rem; + margin-bottom: 3rem; + overflow-x: hidden; + color: rgb(62,67,87); +} + +.emotion-0.scrollable { + overflow-y: auto; +} + +<div> + <main + class="scrollable emotion-0 emotion-1" + > + <div> + Hello! + </div> + </main> +</div> +`; diff --git a/server/sonar-web/design-system/src/components/modal/__tests__/__snapshots__/ModalFooter-test.tsx.snap b/server/sonar-web/design-system/src/components/modal/__tests__/__snapshots__/ModalFooter-test.tsx.snap new file mode 100644 index 00000000000..250bd886c0e --- /dev/null +++ b/server/sonar-web/design-system/src/components/modal/__tests__/__snapshots__/ModalFooter-test.tsx.snap @@ -0,0 +1,66 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render with primary and secondary buttons 1`] = ` +.emotion-0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: end; + -ms-flex-pack: end; + -webkit-justify-content: flex-end; + justify-content: flex-end; + gap: 0.75rem; +} + +<div> + <footer + class="emotion-0 emotion-1" + > + <button + type="button" + > + Primary + </button> + <button + type="reset" + > + Reset + </button> + </footer> +</div> +`; + +exports[`should render with secondary button 1`] = ` +.emotion-0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: end; + -ms-flex-pack: end; + -webkit-justify-content: flex-end; + justify-content: flex-end; + gap: 0.75rem; +} + +<div> + <footer + class="emotion-0 emotion-1" + > + <button + type="button" + > + Close + </button> + </footer> +</div> +`; diff --git a/server/sonar-web/design-system/src/components/modal/__tests__/__snapshots__/ModalHeader-test.tsx.snap b/server/sonar-web/design-system/src/components/modal/__tests__/__snapshots__/ModalHeader-test.tsx.snap new file mode 100644 index 00000000000..10d1204b2e5 --- /dev/null +++ b/server/sonar-web/design-system/src/components/modal/__tests__/__snapshots__/ModalHeader-test.tsx.snap @@ -0,0 +1,75 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render with title 1`] = ` +.emotion-0 { + font-family: Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"; + font-size: 1.5rem; + line-height: 1.75rem; + font-weight: 600; + color: rgb(29,33,47); +} + +<div> + <header> + <p + class="emotion-0 emotion-1" + > + Foo + </p> + </header> +</div> +`; + +exports[`should render with title and description 1`] = ` +.emotion-0 { + font-family: Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"; + font-size: 1.5rem; + line-height: 1.75rem; + font-weight: 600; + color: rgb(29,33,47); +} + +.emotion-2 { + font-family: Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"; + font-size: 0.875rem; + line-height: 1.25rem; + font-weight: 400; + margin-top: 0.5rem; + color: rgb(62,67,87); +} + +<div> + <header> + <p + class="emotion-0 emotion-1" + > + Foo + </p> + <p + class="emotion-2 emotion-3" + > + Bar + </p> + </header> +</div> +`; + +exports[`should use the default title if not provided 1`] = ` +.emotion-0 { + font-family: Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"; + font-size: 1.5rem; + line-height: 1.75rem; + font-weight: 600; + color: rgb(29,33,47); +} + +<div> + <header> + <p + class="emotion-0 emotion-1" + > + Modal title + </p> + </header> +</div> +`; |