Skip to content

Commit

Permalink
feat(Modal): modal improvements, add stories for main Modal and modal…
Browse files Browse the repository at this point in the history
…'s layouts (#2627)
  • Loading branch information
YossiSaadi authored Dec 9, 2024
1 parent e8d093e commit bead0ba
Show file tree
Hide file tree
Showing 61 changed files with 2,054 additions and 93 deletions.
15 changes: 10 additions & 5 deletions packages/core/.eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -97,16 +97,21 @@ module.exports = {
}
},
{
files: [
"*.stories.@(js|jsx|ts|tsx)",
"*.stories.helpers.@(js|jsx|ts|tsx)",
"src/storybook/decorators/**/with*.{js,jsx,ts,tsx}"
],
files: ["*.stories.@(js|jsx)", "*.stories.helpers.@(js|jsx)", "src/storybook/decorators/**/with*.{js,jsx}"],
rules: {
...commonRules,
"react-hooks/rules-of-hooks": "off",
"react/jsx-key": "off"
}
},
{
files: ["*.stories.@(ts|tsx)", "*.stories.helpers.@(ts|tsx)", "src/storybook/decorators/**/with*.{ts,tsx}"],
rules: {
...commonRules,
"react-hooks/rules-of-hooks": "off",
"react/jsx-key": "off",
"react/require-default-props": "off"
}
}
],
env: {
Expand Down
14 changes: 10 additions & 4 deletions packages/core/.storybook/manager.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,20 @@ addons.setConfig({
return <SidebarItem status={parameters.status}>{name.replace(storyStatus, "").trim()}</SidebarItem>;
},
filters: {
patterns: filterStory
patterns: shouldShowStory
},
showRoots: false
}
});

function filterStory(item) {
/**
* In order to hide stories you need to add `tags: ['internal']` to the stories file metadata.
* In order to hide MDX, you need to add `Internal` to the title in the MDX's `Meta` declaration `title` or to the `title` in the stories file metadata.
*
* Notice that all stories are available in development mode and in Chromatic.
*/
function shouldShowStory(item) {
const isDev = isChromatic() || process.env.NODE_ENV === "development";
const isInternal = !item.tags?.includes?.("internal") && !item.title?.startsWith?.("Internal");
return isDev || isInternal;
const isPublic = !item.tags?.includes?.("internal") && !item.title?.startsWith?.("Internal");
return isDev || isPublic;
}
7 changes: 6 additions & 1 deletion packages/core/.storybook/preview-head.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,14 @@
.sbdocs .docs-story {
border: var(--sb-layout-border-color);
}
.sbdocs .docs-story > div {
.sbdocs .docs-story > div:first-child {
background: var(--sb-secondary-background-color);
}
.sbdocs .docs-story > div:nth-child(2) {
/* prevent Show Code from rendering above full-screen components (such as Modal's overlay) */
z-index: unset;
background: unset;
}

.sbdocs {
color: var(--sb-primary-text-color);
Expand Down
52 changes: 5 additions & 47 deletions packages/core/src/components/ModalNew/Modal/Modal.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@

display: flex;
flex-direction: column;
width: var(--modal-width, 50%);
max-height: var(--modal-max-height, 80%);
width: var(--modal-width);
max-height: var(--modal-max-height);
background-color: var(--primary-background-color);
overflow: hidden;
border-radius: var(--border-radius-big);
Expand All @@ -28,58 +28,16 @@

&.sizeSmall {
--modal-max-height: 50%;
--modal-width: 45%;
--modal-width: 480px;
}

&.sizeMedium {
--modal-max-height: 80%;
--modal-width: 50%;
--modal-width: 580px;
}

&.sizeLarge {
--modal-max-height: 80%;
--modal-width: 70%;
}

@media (min-width: 1280px) {
&.sizeSmall {
--modal-width: 40%;
}

&.sizeMedium {
--modal-width: 44%;
}

&.sizeLarge {
--modal-width: 66%;
}
}

@media (min-width: 1440px) {
&.sizeSmall {
--modal-width: 35%;
}

&.sizeMedium {
--modal-width: 38%;
}

&.sizeLarge {
--modal-width: 60%;
}
}

@media (min-width: 1720px) {
&.sizeSmall {
--modal-width: 34%;
}

&.sizeMedium {
--modal-width: 36%;
}

&.sizeLarge {
--modal-width: 58%;
}
--modal-width: 840px;
}
}
2 changes: 1 addition & 1 deletion packages/core/src/components/ModalNew/Modal/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ const Modal = forwardRef(
{children}
<ModalTopActions
renderAction={renderHeaderAction}
color={closeButtonTheme}
theme={closeButtonTheme}
closeButtonAriaLabel={closeButtonAriaLabel}
onClose={onClose}
/>
Expand Down
35 changes: 34 additions & 1 deletion packages/core/src/components/ModalNew/Modal/Modal.types.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,48 @@ export type ModalCloseEvent =
| React.KeyboardEvent<HTMLBodyElement>;

export interface ModalProps extends VibeComponentProps {
/**
* Unique identifier for the modal.
*/
id: string;
/**
* Controls the visibility of the modal.
*/
show: boolean;
/**
* Determines the width and max-height of the modal.
*/
size?: ModalSize;
closeButtonTheme?: ModalTopActionsProps["color"];
/**
* Theme color for the close button.
*/
closeButtonTheme?: ModalTopActionsProps["theme"];
/**
* Accessibility label for the close button.
*/
closeButtonAriaLabel?: ModalTopActionsProps["closeButtonAriaLabel"];
/**
* Callback fired when the modal should close.
*/
onClose?: (event: ModalCloseEvent) => void;
/**
* Additional action to render in the header area.
*/
renderHeaderAction?: ModalTopActionsProps["renderAction"];
/**
* Reference to an element that triggered the modal, used for animations.
*/
anchorElementRef?: React.RefObject<HTMLElement>;
/**
* When true, prevents closing the modal when clicking the overlay ("click-outside") or pressing ESC.
*/
alertModal?: boolean;
/**
* Modal content.
*/
children: React.ReactNode;
/**
* Additional inline styles for the modal.
*/
style?: React.CSSProperties;
}
136 changes: 136 additions & 0 deletions packages/core/src/components/ModalNew/Modal/__stories__/Modal.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import { Canvas, Meta } from "@storybook/blocks";
import { ModalTip } from "./Modal.stories.helpers";
import { Overview as BasicModalPreview } from "../../layouts/ModalBasicLayout/__stories__/ModalBasicLayout.stories";
import { Overview as SideBySideModalPreview } from "../../layouts/ModalSideBySideLayout/__stories__/ModalSideBySideLayout.stories";
import { Overview as MediaModalPreview } from "../../layouts/ModalMediaLayout/__stories__/ModalMediaLayout.stories";
import backdropDo from "./assets/backdrop-do.png";
import backdropDont from "./assets/backdrop-dont.png";
import loadingDo from "./assets/loading-do.png";
import loadingDont from "./assets/loading-dont.png";
import ctaDo from "./assets/cta-do.png";
import ctaDont from "./assets/cta-dont.png";
import styles from "./Modal.stories.module.scss";
import { StorybookLink } from "vibe-storybook-components";
import {
DIALOG,
TIPSEEN,
TOOLTIP
} from "../../../../storybook/components/related-components/component-description-map";

<Meta title="Internal/Components/Modal [New]" />

# Modal

- [Overview](#overview)
- [Props](#props)
- [Usage](#usage)
- [Do's and dont's](do's-and-don'ts)
- [Related components](#related-components)
- [Feedback](#feedback)

## Overview

Modals help users focus on a single task or a piece of information by popping up and blocking the rest of the page’s content. Modals disappear when user complete a required action or dismiss it. Use modals for quick, infrequent tasks.

We have 3 different modal component, each one provide a different layout for a different use case:

### Basic modal

The Basic Modal is intended for straightforward tasks, like selecting items or gathering basic information. Basic Modals help users focus on a single task without distractions. These modals do not support images or videos.

<Canvas of={BasicModalPreview} sourceState="none" />

### Side by side modal

The Side-by-Side Modal offers two distinct sections: the left for text or inputs, and the right for supporting visuals.
It's ideal when users need to reference media alongside information.

<Canvas of={SideBySideModalPreview} sourceState="none" />

### Media modal

The Media Modal includes a highlighted media section followed by text, perfect for grabbing attention with visuals before users interact with the content. Ideal for introducing new features or onboarding.

<Canvas of={MediaModalPreview} sourceState="none" />

## Usage

<UsageGuidelines
guidelines={[
"Use modals only when you need the user's full, immediate attention.",
"Modals are centered on the page. To put the modal in focus, the rest of the page is dimmed.",
"All modals must have a title, a call to action, and a close button. The title and call to action should be simple and clear.",
"By default, users can close modals by clicking the close button, clicking outside the modal, or pressing the ESC key."
]}
/>

<ModalTip />

## Do's and don'ts

<ComponentRules
rules={[
{
componentContainerClassName: styles.largeComponentRule,
positive: {
component: <img src={backdropDo} alt="modal with a backdrop" style={{ maxWidth: "100%" }} />,
description: "Modal must include backdrop element."
},
negative: {
component: <img src={backdropDont} alt="modal without a backdrop" style={{ maxWidth: "100%" }} />,
description: "Don't remove the backdrop element of the modal or the modal's title."
}
},
{
componentContainerClassName: styles.largeComponentRule,
positive: {
component: (
<img
src={loadingDo}
alt="modal with skeleton components as a loading experience"
style={{ maxWidth: "100%" }}
/>
),
description: (
<>
Use our <StorybookLink page="Feedback/Skeleton">Skeleton</StorybookLink> component if loading is needed. Try
that at least the actions will appear immediately.
</>
)
},
negative: {
component: (
<img
src={loadingDont}
alt="modal with a spinner loading components as a loading experience"
style={{ maxWidth: "100%" }}
/>
),
description: "Don't use Loader component in case of necessary loading."
}
},
{
componentContainerClassName: styles.largeComponentRule,
positive: {
component: (
<img
src={ctaDo}
alt="modal with a footer that includes one primary action and one tertiary action"
style={{ maxWidth: "100%" }}
/>
),
description: "Use one primary button as your main call to action, for extra buttons use the tertiary button."
},
negative: {
component: (
<img src={ctaDont} alt="modal with a footer that includes two primary actions" style={{ maxWidth: "100%" }} />
),
description: "Don't use more than one primary button, we don't want to distract the user from the main action."
}
}
]}
/>

## Related components

<RelatedComponents componentsNames={[TOOLTIP, DIALOG, TIPSEEN]} />
Loading

0 comments on commit bead0ba

Please sign in to comment.