From 3a201f42c92cd0b1623ab19a97925895dc840f47 Mon Sep 17 00:00:00 2001 From: Arthur Andrade Date: Thu, 23 Jun 2022 12:26:12 -0300 Subject: [PATCH] feat: Extract `RegionalizationModal` (#128) --- CHANGELOG.md | 1 + .../RegionalizationModal.stories.mdx | 182 ++++++++++++++++++ .../RegionalizationModal.tsx | 54 +----- .../RegionalizationModalContent.tsx | 48 +++++ .../RegionalizationModal/index.ts | 1 + .../regionalization-modal-content.module.scss | 81 ++++++++ .../regionalization-modal.scss | 95 --------- src/components/ui/Modal/Modal.stories.mdx | 166 ++++++++++++++++ src/components/ui/Modal/Modal.tsx | 41 ++++ src/components/ui/Modal/index.ts | 1 + src/components/ui/Modal/modal.module.scss | 46 +++++ src/styles/global/components.scss | 1 - 12 files changed, 574 insertions(+), 143 deletions(-) create mode 100644 src/components/regionalization/RegionalizationModal/RegionalizationModal.stories.mdx create mode 100644 src/components/regionalization/RegionalizationModal/RegionalizationModalContent.tsx create mode 100644 src/components/regionalization/RegionalizationModal/regionalization-modal-content.module.scss delete mode 100644 src/components/regionalization/RegionalizationModal/regionalization-modal.scss create mode 100644 src/components/ui/Modal/Modal.stories.mdx create mode 100644 src/components/ui/Modal/Modal.tsx create mode 100644 src/components/ui/Modal/index.ts create mode 100644 src/components/ui/Modal/modal.module.scss diff --git a/CHANGELOG.md b/CHANGELOG.md index 49259e9d..905ef6a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Applies new local tokens to `Modal` and `RegionalizationModal` ([#128](https://github.com/vtex-sites/nextjs.store/pull/128)) - PriceRange component ([#124](https://github.com/vtex-sites/nextjs.store/pull/124)) - PriceRange component to PLP and StoryBook ([#121](https://github.com/vtex-sites/nextjs.store/pull/121)) - Displays the `Sandbox` tab on the storybook along with `Viewport` toolbar and `Accessibility` checks ([#129](https://github.com/vtex-sites/nextjs.store/pull/129)) diff --git a/src/components/regionalization/RegionalizationModal/RegionalizationModal.stories.mdx b/src/components/regionalization/RegionalizationModal/RegionalizationModal.stories.mdx new file mode 100644 index 00000000..bad52327 --- /dev/null +++ b/src/components/regionalization/RegionalizationModal/RegionalizationModal.stories.mdx @@ -0,0 +1,182 @@ +import { Meta, Canvas, Story, ArgsTable } from '@storybook/addon-docs' +import UIProvider, { useUI } from 'src/sdk/ui/Provider' +import Button from 'src/components/ui/Button' +import { SessionProvider } from '@faststore/sdk' +import RegionalizationModal, { RegionalizationModalContent } from '.' +import RegionalizationButton from 'src/components/regionalization/RegionalizationButton' + +import { + TokenTable, + TokenRow, + TokenDivider, +} from 'src/../.storybook/components' + + + +export const ModalTemplate = () => { + const { modal, openModal } = useUI() + return ( +
+ openModal()}>Open Regionalization Modal + { + modal && ( + + ) + } +
+ ) +} + +export const Template = (args) => { + return ( + + + + + + ) +} + +export const RegionalizationModalContentTemplate = (args) => { + return ( + + + {}} /> + + + ) +} + +
+ +# RegionalizationModal + +This component calls a modal with some regionalization configurations. + +
+ +## Overview + +This component uses [Modal](/docs/molecules-modal--overview) as a base. + + + + {RegionalizationModalContentTemplate.bind({})} + + + +--- + +## Usage + +`import RegionalizationModal from src/components/regionalization/RegionalizationModal` + + + + {Template.bind({})} + + + +--- + + + + + + + +### Header + + + + + +### Title + + + + + + + + +### Description + + + + + + + +### Buttons + + + + + + +### Link + + + + + + diff --git a/src/components/regionalization/RegionalizationModal/RegionalizationModal.tsx b/src/components/regionalization/RegionalizationModal/RegionalizationModal.tsx index ed115194..c9425d39 100644 --- a/src/components/regionalization/RegionalizationModal/RegionalizationModal.tsx +++ b/src/components/regionalization/RegionalizationModal/RegionalizationModal.tsx @@ -1,53 +1,13 @@ -import { Modal as UIModal } from '@faststore/ui' +import Modal from 'src/components/ui/Modal' -import RegionalizationInput from 'src/components/regionalization/RegionalizationInput' -import { ButtonIcon } from 'src/components/ui/Button' -import Icon from 'src/components/ui/Icon' -import Link from 'src/components/ui/Link' -import { useUI } from 'src/sdk/ui/Provider' -import { useFadeEffect } from 'src/sdk/ui/useFadeEffect' - -function RegionModal() { - const { closeModal } = useUI() - const { fade, fadeOut } = useFadeEffect() +import { RegionalizationModalContent } from '.' +function RegionalizationModal() { return ( - fade === 'out' && closeModal()} - > -
- } - /> -

- Set your location -

-

- Prices, offers and availability may vary according to your location. -

-
-
- {/* TODO: Remove this div when PostalCodeInput be styled */} -
- -
- - - {"Don't know my Postal Code"} - - - -
-
+ + {({ fadeOut }) => } + ) } -export default RegionModal +export default RegionalizationModal diff --git a/src/components/regionalization/RegionalizationModal/RegionalizationModalContent.tsx b/src/components/regionalization/RegionalizationModal/RegionalizationModalContent.tsx new file mode 100644 index 00000000..e5d1c7b7 --- /dev/null +++ b/src/components/regionalization/RegionalizationModal/RegionalizationModalContent.tsx @@ -0,0 +1,48 @@ +import RegionalizationInput from 'src/components/regionalization/RegionalizationInput' +import { ButtonIcon } from 'src/components/ui/Button' +import Icon from 'src/components/ui/Icon' +import Link from 'src/components/ui/Link' + +import styles from './regionalization-modal-content.module.scss' + +export type RegionalizationModalContentProps = { + onClose?: () => void +} + +function RegionalizationModalContent({ + onClose, +}: RegionalizationModalContentProps) { + return ( +
+
+ {onClose && ( + onClose?.()} + data-fs-regionalization-modal-button + aria-label="Close Regionalization Modal" + data-testid="regionalization-modal-button-close" + icon={} + /> + )} +

Set your location

+

+ Prices, offers and availability may vary according to your location. +

+
+
+
+ onClose?.()} /> +
+ + {"Don't know my Postal Code"} + + +
+
+ ) +} + +export default RegionalizationModalContent diff --git a/src/components/regionalization/RegionalizationModal/index.ts b/src/components/regionalization/RegionalizationModal/index.ts index baa879f4..2307a292 100644 --- a/src/components/regionalization/RegionalizationModal/index.ts +++ b/src/components/regionalization/RegionalizationModal/index.ts @@ -1 +1,2 @@ export { default } from './RegionalizationModal' +export { default as RegionalizationModalContent } from './RegionalizationModalContent' diff --git a/src/components/regionalization/RegionalizationModal/regionalization-modal-content.module.scss b/src/components/regionalization/RegionalizationModal/regionalization-modal-content.module.scss new file mode 100644 index 00000000..79a5080e --- /dev/null +++ b/src/components/regionalization/RegionalizationModal/regionalization-modal-content.module.scss @@ -0,0 +1,81 @@ +@import "src/styles/scaffold"; + +.fs-regionalization-modal-content { + // -------------------------------------------------------- + // Design Tokens for Regionalization Modal + // -------------------------------------------------------- + + // Default properties + --fs-regionalization-modal-padding : var(--fs-spacing-1) var(--fs-spacing-4) var(--fs-spacing-5); + --fs-regionalization-modal-background-color : var(--fs-color-body-bkg); + --fs-regionalization-modal-border-radius : var(--fs-border-radius); + + // Header + --fs-regionalization-modal-header-padding : var(--fs-spacing-4) var(--fs-spacing-7) var(--fs-spacing-4) var(--fs-spacing-4); + + // Title + --fs-regionalization-modal-title-margin-bottom : .625rem; + --fs-regionalization-modal-title-size : var(--fs-text-size-lead); + --fs-regionalization-modal-title-weight : var(--fs-text-weight-bold); + --fs-regionalization-modal-title-line-height : 1.2; + + // Description + --fs-regionalization-modal-description-size : var(--fs-text-size-body); + --fs-regionalization-modal-description-line-height : 1.5; + --fs-regionalization-modal-description-color : var(--fs-color-text-light); + + // Close Button + --fs-regionalization-modal-close-button-position-top : 0; + --fs-regionalization-modal-close-button-position-right : 0; + + // Link + --fs-regionalization-modal-link-padding : 0; + --fs-regionalization-modal-link-color : var(--fs-color-link); + --fs-regionalization-modal-link-margin-right : var(--fs-spacing-0); + + position: relative; + background-color: var(--fs-regionalization-modal-background-color); + border-radius: var(--fs-regionalization-modal-border-radius); + + [data-fs-regionalization-modal-header] { + padding: var(--fs-regionalization-modal-header-padding); + + [data-fs-regionalization-modal-title] { + margin-bottom: var(--fs-regionalization-modal-title-margin-bottom); + font-size: var(--fs-regionalization-modal-title-size); + font-weight: var(--fs-regionalization-modal-title-weight); + line-height: var(--fs-regionalization-modal-title-line-height); + } + + [data-fs-regionalization-modal-description] { + font-size: var(--fs-regionalization-modal-description-size); + line-height: var(--fs-regionalization-modal-description-line-height); + color: var(--fs-regionalization-modal-description-color); + } + + [data-fs-regionalization-modal-button] { + position: absolute; + top: var(--fs-regionalization-modal-close-button-position-top); + right: var(--fs-regionalization-modal-close-button-position-right); + } + } + + [data-fs-regionalization-modal-body] { + padding: var(--fs-regionalization-modal-padding); + + [data-fs-regionalization-modal-input] { + margin-bottom: var(--fs-spacing-6); + } + + [data-fs-regionalization-modal-link] { + display: flex; + flex-direction: row; + align-content: flex-start; + align-items: center; + justify-content: flex-start; + padding: var(--fs-regionalization-modal-link-padding); + margin-right: var(--fs-regionalization-modal-link-margin-right); + color: var(--fs-regionalization-modal-link-color); + } + } +} diff --git a/src/components/regionalization/RegionalizationModal/regionalization-modal.scss b/src/components/regionalization/RegionalizationModal/regionalization-modal.scss deleted file mode 100644 index 11a52256..00000000 --- a/src/components/regionalization/RegionalizationModal/regionalization-modal.scss +++ /dev/null @@ -1,95 +0,0 @@ -@import "src/styles/scaffold"; - -[data-modal-overlay] { - background-color: rgb(0 0 0 / 25%); -} - -[data-regionalization-modal] { - position: fixed; - top: 30vh; - right: rem(24px); - left: rem(24px); - max-width: calc(var(--fs-grid-breakpoint-desktop) / 3); - margin: auto; - background-color: var(--fs-color-body-bkg); - border-radius: var(--fs-spacing-0); - - @include media(">=tablet") { - width: calc(100vw / 3); - min-width: calc(var(--fs-grid-breakpoint-desktop) / 3); - } - - &[data-regionalization-modal-state="in"] { - transition: transform .2s ease-in; - transform: translate3d(0, 0, 0); - } - - &[data-regionalization-modal-state="out"] { - transition: transform .2s ease-out; - transform: translate3d(0, 50%, 0); - } - - .regionalization-modal__header { - padding: var(--fs-spacing-4) var(--fs-spacing-7) var(--fs-spacing-4) var(--fs-spacing-4); - - [data-regionalization-modal-title] { - margin-bottom: rem(10px); - } - - [data-regionalization-modal-description] { - color: var(--fs-color-text-light); - } - - [data-fs-regionalization-modal-button] { - position: absolute; - top: 0; - right: 0; - } - } - - .regionalization-modal__body { - padding: var(--fs-spacing-1) var(--fs-spacing-4) var(--fs-spacing-5); - - [data-regionalization-modal-input] { - margin-bottom: var(--fs-spacing-6); - } - - [data-fs-link] { - display: flex; - flex-direction: row; - align-content: flex-start; - align-items: center; - justify-content: flex-start; - padding: 0; - color: var(--fs-color-link); - - [data-regionalization-modal-link] { - margin-right: var(--fs-spacing-0); - } - } - } -} - -@keyframes motion-in { - from { - opacity: 0; - transform: translate3d(0, 50%, 0); - } - - to { - opacity: 1; - transform: translate3d(0, 0, 0); - } -} - -@keyframes motion-out { - from { - opacity: 1; - transform: translate3d(0, 0, 0); - } - - to { - opacity: 0; - transform: translate3d(0, 50%, 0); - } -} diff --git a/src/components/ui/Modal/Modal.stories.mdx b/src/components/ui/Modal/Modal.stories.mdx new file mode 100644 index 00000000..8f0ae40b --- /dev/null +++ b/src/components/ui/Modal/Modal.stories.mdx @@ -0,0 +1,166 @@ +import { Meta, Canvas, Story, ArgsTable } from '@storybook/addon-docs' +import UIProvider, { useUI } from 'src/sdk/ui/Provider' +import Button from 'src/components/ui/Button' +import { RegionalizationModalContent } from 'src/components/regionalization/RegionalizationModal' +import { SessionProvider } from '@faststore/sdk' + +import Modal from '.' +import { + TokenTable, + TokenRow, + TokenDivider, +} from 'src/../.storybook/components' + + + +export const ModalTemplate = (args) => { + const { modal, openModal } = useUI() + return ( +
+ + { + modal && ( + + {({ fadeOut }) => ( +
+

+ Hello, i'm a Modal! +

+ +
+ )} +
+ ) + } +
+ ) +} + +export const Template = (args) => { + return ( + + + + ) +} + +
+ +# Modal + +Modals are dialog windows that sit on top of an application's main view. Once a Modal is open, interactions with the content behind it are blocked. + +
+ +## Overview + +The `Modal` component uses [FastStore UI Modal](https://www.faststore.dev/reference/ui/molecules/Modal) as base. + +--- + +## Usage + +`import Modal from 'src/components/ui/Modal'` + + + + {Template.bind({})} + + + +--- + + + + + + + + + + + + + + + + + + + +--- + +## Use Cases + +
+ +
+ +--- diff --git a/src/components/ui/Modal/Modal.tsx b/src/components/ui/Modal/Modal.tsx new file mode 100644 index 00000000..e1309421 --- /dev/null +++ b/src/components/ui/Modal/Modal.tsx @@ -0,0 +1,41 @@ +import type { ModalProps as UIModalProps } from '@faststore/ui' +import { Modal as UIModal } from '@faststore/ui' +import type { ReactNode } from 'react' + +import { useUI } from 'src/sdk/ui/Provider' +import { useFadeEffect } from 'src/sdk/ui/useFadeEffect' + +import styles from './modal.module.scss' + +export type ModalChildrenProps = { + fade: 'in' | 'out' + fadeOut: () => void + fadeIn: () => void +} + +export type ModalProps = Omit & { + children: (props: ModalChildrenProps) => ReactNode | ReactNode +} + +function Modal({ className, children, ...props }: ModalProps) { + const { closeModal } = useUI() + const { fade, fadeOut, fadeIn } = useFadeEffect() + + return ( + fade === 'out' && closeModal()} + data-fs-modal + data-fs-modal-state={fade} + className={`${styles.fsModal} ${className}`} + {...props} + isOpen + > + {typeof children === 'function' + ? children({ fade, fadeOut, fadeIn }) + : children} + + ) +} + +export default Modal diff --git a/src/components/ui/Modal/index.ts b/src/components/ui/Modal/index.ts new file mode 100644 index 00000000..e24753a1 --- /dev/null +++ b/src/components/ui/Modal/index.ts @@ -0,0 +1 @@ +export { default } from './Modal' diff --git a/src/components/ui/Modal/modal.module.scss b/src/components/ui/Modal/modal.module.scss new file mode 100644 index 00000000..460a9da9 --- /dev/null +++ b/src/components/ui/Modal/modal.module.scss @@ -0,0 +1,46 @@ +@import "src/styles/scaffold"; + +.fs-modal { + // -------------------------------------------------------- + // Design Tokens for Modal + // -------------------------------------------------------- + + // Default properties + --fs-modal-position-top : 30vh; + --fs-modal-position-right : var(--fs-spacing-4); + --fs-modal-position-left : var(--fs-spacing-4); + --fs-modal-max-width : calc(var(--fs-grid-breakpoint-desktop) / 3); + --fs-modal-min-height : var(--fs-spacing-5); + --fs-modal-margin : auto; + + --fs-modal-width-tablet : calc(100vw / 3); + --fs-modal-min-width-tablet : calc(var(--fs-grid-breakpoint-desktop) / 3); + + --fs-modal-transition-timing : var(--fs-transition-timing); + --fs-modal-transition-property : transform; + --fs-modal-transition-in-function : ease-in; + --fs-modal-transition-out-function : ease-in; + + position: fixed; + top: var(--fs-modal-position-top); + right: var(--fs-modal-position-right); + left: var(--fs-modal-position-left); + max-width: var(--fs-modal-max-width); + min-height: var(--fs-modal-min-height); + margin: var(--fs-modal-margin); + + @include media(">=tablet") { + width: var(--fs-modal-width-tablet); + min-width: var(--fs-modal-min-width-tablet); + } + + &[data-fs-modal-state="in"] { + transition: var(--fs-modal-transition-property) var(--fs-modal-transition-timing) var(--fs-modal-transition-in-function); + transform: translate3d(0, 0, 0); + } + + &[data-fs-modal-state="out"] { + transition: var(--fs-modal-transition-property) var(--fs-modal-transition-timing) var(--fs-modal-transition-in-function); + transform: translate3d(0, 50%, 0); + } +} diff --git a/src/styles/global/components.scss b/src/styles/global/components.scss index f92e85a6..c9c2a9a0 100644 --- a/src/styles/global/components.scss +++ b/src/styles/global/components.scss @@ -9,7 +9,6 @@ @import "src/components/common/Navbar/navbar.scss"; @import "src/components/regionalization/RegionalizationBar/regionalization-bar.scss"; @import "src/components/regionalization/RegionalizationButton/regionalization-button.scss"; -@import "src/components/regionalization/RegionalizationModal/regionalization-modal.scss"; // Search @import "src/components/search/Filter/filter.scss";