From e093fdeab7e0b252c37eaccd33b45e9b90b40f38 Mon Sep 17 00:00:00 2001 From: Marcin Sawicki Date: Tue, 2 Jul 2024 13:20:48 +0200 Subject: [PATCH 1/5] fix(Modal): close button always visible, animation change, new modal variant with component --- .../src/components/Modal/Modal.module.scss | 25 +++---- .../src/components/Modal/Modal.stories.tsx | 28 +++++++- .../src/components/Modal/Modal.tsx | 24 ++++--- .../components/Modal/StoriesComponents.tsx | 3 - .../components/ActionModalContent.module.scss | 35 ++++++++++ .../Modal/components/ActionModalContent.tsx | 70 +++++++++++++++++++ 6 files changed, 155 insertions(+), 30 deletions(-) create mode 100644 packages/react-components/src/components/Modal/components/ActionModalContent.module.scss create mode 100644 packages/react-components/src/components/Modal/components/ActionModalContent.tsx diff --git a/packages/react-components/src/components/Modal/Modal.module.scss b/packages/react-components/src/components/Modal/Modal.module.scss index 864b1373f..0d4161af5 100644 --- a/packages/react-components/src/components/Modal/Modal.module.scss +++ b/packages/react-components/src/components/Modal/Modal.module.scss @@ -12,8 +12,8 @@ padding: var(--spacing-6) var(--spacing-7); max-width: 100%; height: fit-content; - animation: var(--transition-duration-moderate-1) fade-in-step2 - var(--transition-duration-moderate-1) forwards; + animation: var(--transition-duration-fast-2) fade-in + var(--transition-duration-fast-2) forwards; color: var(--content-basic-primary); &--full-space { @@ -27,7 +27,7 @@ &--visible { display: flex; - animation: fade-in-step1 var(--transition-duration-moderate-1) forwards; + animation: fade-in var(--transition-duration-fast-2) forwards; @media (prefers-reduced-motion) { animation: none; @@ -100,6 +100,11 @@ padding-bottom: var(--spacing-5); width: 100%; color: var(--content-basic-primary); + + &--without-heading { + flex-direction: row-reverse; + padding-bottom: 0; + } } &__label-header { @@ -134,24 +139,12 @@ } } -@keyframes fade-in-step1 { - 0% { - opacity: var(--transition-initial-fade-in-opacity); - } - - 100% { - opacity: 1; - } -} - -@keyframes fade-in-step2 { +@keyframes fade-in { 0% { opacity: var(--transition-initial-fade-in-opacity); - scale: var(--transition-initial-fade-in-scale); } 100% { opacity: 1; - scale: 1; } } diff --git a/packages/react-components/src/components/Modal/Modal.stories.tsx b/packages/react-components/src/components/Modal/Modal.stories.tsx index d0ccbdc93..2d0bf2dc4 100644 --- a/packages/react-components/src/components/Modal/Modal.stories.tsx +++ b/packages/react-components/src/components/Modal/Modal.stories.tsx @@ -1,11 +1,13 @@ import * as React from 'react'; -import { GreetingQuickReply } from '@livechat/design-system-icons'; +import { GreetingQuickReply, Info } from '@livechat/design-system-icons'; import { Meta, StoryFn } from '@storybook/react'; import noop from '../../utils/noop'; import { Button } from '../Button'; +import { Icon } from '../Icon'; +import { ActionModalContent } from './components/ActionModalContent'; import { ModalContent, ModalFullSpaceContent, @@ -24,7 +26,7 @@ import { export default { title: 'Components/Modal', component: ModalComponent, - subcomponents: { ModalHeader }, + subcomponents: { ModalHeader, ActionModalContent, ModalBase }, parameters: { viewMode: 'story', previewTabs: { @@ -130,6 +132,28 @@ ModalWithFullSpaceContent.args = { footer: null, } as ModalProps; +export const ActionModal = StoryTemplate.bind({}); +ActionModal.args = { + ...defaultModalProps, + children: ( + } + heading="Action Modal Header" + actions={ + <> + + + + } + > + Amet minim mollit non deserunt ullamco est sit aliqua dolor do amet sint. + Velit officia consequat duis enim velit mollit. Exercitation veniam + consequat sunt nostrud amet. + + ), + footer: null, +} as ModalProps; + export const ModalPortal = ({ children, ...args diff --git a/packages/react-components/src/components/Modal/Modal.tsx b/packages/react-components/src/components/Modal/Modal.tsx index 964c716db..a29ab4049 100644 --- a/packages/react-components/src/components/Modal/Modal.tsx +++ b/packages/react-components/src/components/Modal/Modal.tsx @@ -81,15 +81,21 @@ export const Modal: React.FC = ({ /> )} - {!labelHeading && heading && ( -
- - {heading} - + {!labelHeading && ( +
+ {heading && ( + + {heading} + + )}
)} diff --git a/packages/react-components/src/components/Modal/StoriesComponents.tsx b/packages/react-components/src/components/Modal/StoriesComponents.tsx index 0e7c95bcb..c62e134c2 100644 --- a/packages/react-components/src/components/Modal/StoriesComponents.tsx +++ b/packages/react-components/src/components/Modal/StoriesComponents.tsx @@ -45,9 +45,6 @@ export const ModalFullSpaceContent: React.FC = () => { export const ModalContent: React.FC = () => (
- - Content header - Amet minim mollit non deserunt ullamco est sit aliqua dolor do amet sint. Velit officia consequat duis enim velit mollit. Exercitation veniam diff --git a/packages/react-components/src/components/Modal/components/ActionModalContent.module.scss b/packages/react-components/src/components/Modal/components/ActionModalContent.module.scss new file mode 100644 index 000000000..e46ad8803 --- /dev/null +++ b/packages/react-components/src/components/Modal/components/ActionModalContent.module.scss @@ -0,0 +1,35 @@ +$base-class: 'action-modal-content'; + +.#{$base-class} { + display: flex; + flex-direction: column; + align-items: center; + padding-top: var(--spacing-3); + padding-bottom: var(--spacing-10); + width: 100%; + width: 480px; + height: 100%; + + &__icon { + display: flex; + align-items: center; + justify-content: center; + margin-bottom: var(--spacing-3); + min-width: 48px; + min-height: 48px; + } + + &__heading { + margin-bottom: var(--spacing-2); + } + + &__content { + margin-bottom: var(--spacing-10); + text-align: center; + } + + &__actions { + display: flex; + gap: var(--spacing-2); + } +} diff --git a/packages/react-components/src/components/Modal/components/ActionModalContent.tsx b/packages/react-components/src/components/Modal/components/ActionModalContent.tsx new file mode 100644 index 000000000..3e5ff42ae --- /dev/null +++ b/packages/react-components/src/components/Modal/components/ActionModalContent.tsx @@ -0,0 +1,70 @@ +import * as React from 'react'; + +import cx from 'clsx'; + +import { Heading, Text } from '../../Typography'; + +import styles from './ActionModalContent.module.scss'; + +const baseClass = 'action-modal-content'; + +interface IActionModalProps { + /** + * Optional element to render icon or image + */ + icon?: React.ReactNode; + /** + * Set the header text + */ + heading?: React.ReactNode; + /** + * Optional element to render action buttons + */ + actions?: React.ReactNode; + /** + * The CSS class for main container + */ + className?: string; + /** + * The CSS class for header container + */ + headerClassName?: string; + /** + * The CSS class for content container + */ + contentClassName?: string; +} + +export const ActionModalContent: React.FC = ({ + children, + className, + icon, + heading, + actions, + headerClassName, + contentClassName, +}) => { + const mergedClassNames = cx(styles[baseClass], className); + + return ( +
+ {icon &&
{icon}
} + {heading && ( + + {heading} + + )} + + {children} + + {actions && ( +
{actions}
+ )} +
+ ); +}; From d9e1a834d0763a3280aa4f67bdefe4d896b891e2 Mon Sep 17 00:00:00 2001 From: Marcin Sawicki Date: Tue, 2 Jul 2024 14:24:31 +0200 Subject: [PATCH 2/5] fix(Modal): changes after review --- .../src/components/Modal/Modal.stories.tsx | 16 ++++++++++++---- .../components/ActionModalContent.module.scss | 1 + 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/react-components/src/components/Modal/Modal.stories.tsx b/packages/react-components/src/components/Modal/Modal.stories.tsx index 2d0bf2dc4..6516bf17b 100644 --- a/packages/react-components/src/components/Modal/Modal.stories.tsx +++ b/packages/react-components/src/components/Modal/Modal.stories.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; -import { GreetingQuickReply, Info } from '@livechat/design-system-icons'; +import { GreetingQuickReply, Error } from '@livechat/design-system-icons'; import { Meta, StoryFn } from '@storybook/react'; import noop from '../../utils/noop'; @@ -137,12 +137,20 @@ ActionModal.args = { ...defaultModalProps, children: ( } + icon={ + + } heading="Action Modal Header" actions={ <> - - + + } > diff --git a/packages/react-components/src/components/Modal/components/ActionModalContent.module.scss b/packages/react-components/src/components/Modal/components/ActionModalContent.module.scss index e46ad8803..7dfd3a606 100644 --- a/packages/react-components/src/components/Modal/components/ActionModalContent.module.scss +++ b/packages/react-components/src/components/Modal/components/ActionModalContent.module.scss @@ -20,6 +20,7 @@ $base-class: 'action-modal-content'; } &__heading { + margin-top: 0; margin-bottom: var(--spacing-2); } From 9e626130ca6e1f1faeaf9067af2abbfffd5bdb9e Mon Sep 17 00:00:00 2001 From: Marcin Sawicki Date: Tue, 2 Jul 2024 14:36:18 +0200 Subject: [PATCH 3/5] fix(Modal): rwd fix --- .../components/Modal/components/ActionModalContent.module.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-components/src/components/Modal/components/ActionModalContent.module.scss b/packages/react-components/src/components/Modal/components/ActionModalContent.module.scss index 7dfd3a606..ab3488dad 100644 --- a/packages/react-components/src/components/Modal/components/ActionModalContent.module.scss +++ b/packages/react-components/src/components/Modal/components/ActionModalContent.module.scss @@ -7,7 +7,7 @@ $base-class: 'action-modal-content'; padding-top: var(--spacing-3); padding-bottom: var(--spacing-10); width: 100%; - width: 480px; + max-width: 480px; height: 100%; &__icon { From 4fa9168417eaf5766b9ac35103055d3cc33d983b Mon Sep 17 00:00:00 2001 From: Marcin Sawicki Date: Fri, 12 Jul 2024 13:02:14 +0200 Subject: [PATCH 4/5] fix(Modal): docs update --- .../src/components/Modal/Modal.mdx | 143 ++++++++++++++++-- .../src/components/Modal/Modal.stories.tsx | 12 +- 2 files changed, 137 insertions(+), 18 deletions(-) diff --git a/packages/react-components/src/components/Modal/Modal.mdx b/packages/react-components/src/components/Modal/Modal.mdx index 106b279da..475d6b0ad 100644 --- a/packages/react-components/src/components/Modal/Modal.mdx +++ b/packages/react-components/src/components/Modal/Modal.mdx @@ -1,4 +1,4 @@ -import { ArgTypes, Meta, Title } from '@storybook/blocks'; +import { ArgTypes, Meta, Title, Canvas } from '@storybook/blocks'; import * as ModalStories from './Modal.stories'; @@ -8,24 +8,31 @@ import * as ModalStories from './Modal.stories'; [Component API](#ComponentAPI) | [Content Spec](#ContentSpec) +## How to use modals + +### Default Modal + +Default Modal window is used to gather user input without navigating away from the current page. + +Use it for Data Entry: +- Edit details or preferences. +- Invite agents +- Gather necessary information for specific tasks + +Modal includes: + +- Form fields +- Labels and placeholders for guidance +- Error messages and validation +- Submit (Primary button kind) and cancel buttons (Secondary, Plain buttons kinds) + + + #### Example implementation ```jsx -import { GreetingQuickReply } from '@livechat/design-system-icons'; - - Modal description - - } + heading='Modal header' footer={
+ + + } + > + Amet minim mollit non deserunt ullamco est sit aliqua dolor do amet sint. + Velit officia consequat duis enim velit mollit. Exercitation veniam + consequat sunt nostrud amet. + + +``` + +### Action Modal - Confirmation + +A Confirmation Modal is used to verify a user's intent before proceeding with important actions. + +Use it in these scenarios: +- Deleting Data: Prevent accidental data loss. +- Submitting a Form: Confirm critical information submission. +- Exiting or Logging Out: Ensure unsaved changes are saved or confirm exit. +- Executing a Command: Double-check significant commands (e.g., start/stop services). +- Irreversible Actions: Confirm actions that cannot be undone. + +Confirmation modal includes: +- Attention icon. (error) +- Action Title +- Action Description +- Primary (kind=Destructive) and secondary buttons (optional). +- Close icon + +The implementation is the same as [Action Modal - Info](#ActionModalInfo) + +### Full space content “Promo modal” + +A Promotional Modal is used to introduce new features or updates to users in an engaging way. + +Use it for: +- New Feature Announcements: Highlight and explain new features or tools. +- Product Updates: Inform users about major updates or improvements. +- Special Offers: Promote limited-time deals, discounts, or promotions. +- User Onboarding: Guide new users through key features and benefits. +- Engagement Boost: Encourage users to try out new or underused features. + + + +```jsx + + {' '} + Modal description{' '} + + } + fullSpaceContent +> + + ``` ## Component API diff --git a/packages/react-components/src/components/Modal/Modal.stories.tsx b/packages/react-components/src/components/Modal/Modal.stories.tsx index 6516bf17b..cf081b38a 100644 --- a/packages/react-components/src/components/Modal/Modal.stories.tsx +++ b/packages/react-components/src/components/Modal/Modal.stories.tsx @@ -53,7 +53,15 @@ const StoryTemplate: StoryFn = ({ const [isOpen, setIsOpen] = React.useState(true); return ( - <> +
{isOpen && ( = ({ {children} )} - +
); }; From 79dc1a62e7909854bb0fa68c43d3a47603b95c53 Mon Sep 17 00:00:00 2001 From: Marcin Sawicki Date: Fri, 12 Jul 2024 14:28:33 +0200 Subject: [PATCH 5/5] fix(Modal): changes after review --- .../src/components/Modal/Modal.mdx | 12 +++++++++--- .../src/components/Modal/Modal.stories.tsx | 18 +++++++++--------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/packages/react-components/src/components/Modal/Modal.mdx b/packages/react-components/src/components/Modal/Modal.mdx index 475d6b0ad..7c1dacedc 100644 --- a/packages/react-components/src/components/Modal/Modal.mdx +++ b/packages/react-components/src/components/Modal/Modal.mdx @@ -19,7 +19,7 @@ Use it for Data Entry: - Invite agents - Gather necessary information for specific tasks -Modal includes: +Modal should includes: - Form fields - Labels and placeholders for guidance @@ -31,6 +31,8 @@ Modal includes: #### Example implementation ```jsx +import { Modal, Button } from '@livechat/design-system-react-components'; + Confirmation of actions - Confirm that an action has been successfully completed (e.g., "Your changes have been saved"). - Educational content - Offer tutorials, walkthroughs, or additional information about how to use a feature. -Info modal includes: +Info modal should includes: - An icon to indicate the type of information (e.g., info icon). - Action Title - Action Description @@ -73,6 +75,8 @@ Info modal includes: #### Example implementation ```jsx +import { Modal, ActionModalContent, Button } from '@livechat/design-system-react-components'; + Executing a Command: Double-check significant commands (e.g., start/stop services). - Irreversible Actions: Confirm actions that cannot be undone. -Confirmation modal includes: +Confirmation modal should includes: - Attention icon. (error) - Action Title - Action Description @@ -133,6 +137,8 @@ Use it for: ```jsx +import { Modal, ModalHeader } from '@livechat/design-system-react-components'; + ; +const StoryContainerStyles = { + width: '80vh', + height: '50vh', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', +}; + const defaultModalProps = { children: , closeOnEscPress: true, @@ -53,15 +61,7 @@ const StoryTemplate: StoryFn = ({ const [isOpen, setIsOpen] = React.useState(true); return ( -
+
{isOpen && (