From cdb0ea8fc7d4d3378ff7647065538f5baf6b2df3 Mon Sep 17 00:00:00 2001 From: Vadim Kudriavtsev Date: Wed, 13 Nov 2024 02:12:58 +0300 Subject: [PATCH] feat: add Modal designed body --- ...web ModalBase -- hasBody hasClose.snap.png | Bin 0 -> 9385 bytes .../plasma-web ModalBase -- hasBody.snap.png | Bin 0 -> 8876 bytes .../plasma-web ModalBase -- withBlur.snap.png | Bin 17082 -> 15916 bytes ...web ModalBase -- hasBody hasClose.snap.png | Bin 0 -> 9799 bytes .../plasma-web ModalBase -- hasBody.snap.png | Bin 0 -> 9287 bytes .../src/components/ModalBase/Modal.config.ts | 11 +- .../ModalBase/ModalBase.stories.tsx | 145 +++++++++++++++- .../src/components/Modal/Modal.styles.ts | 59 +++++++ .../components/Modal/Modal.template-doc.mdx | 47 ++++++ .../src/components/Modal/Modal.tokens.ts | 9 + .../src/components/Modal/Modal.tsx | 48 ++++-- .../src/components/Modal/Modal.types.ts | 20 ++- .../src/components/Modal/index.ts | 2 +- .../components/Modal/Modal.config.ts | 9 + .../components/Modal/Modal.stories.tsx | 93 ++++++++++- .../components/Modal/Modal.config.ts | 9 + .../components/Modal/Modal.stories.tsx | 91 +++++++++- .../src/components/ModalBase/Modal.config.ts | 9 + .../ModalBase/ModalBase.component-test.tsx | 60 +++++++ .../ModalBase/ModalBase.stories.tsx | 145 +++++++++++++++- .../src/components/Modal/Modal.config.ts | 9 + .../src/components/Modal/Modal.stories.tsx | 157 ++++++++++++++++-- .../src/components/Modal/Modal.config.ts | 9 + .../src/components/Modal/Modal.stories.tsx | 156 +++++++++++++++-- .../src/components/Modal/Modal.config.ts | 9 + .../src/components/Modal/Modal.stories.tsx | 156 +++++++++++++++-- .../src/components/Modal/Modal.config.ts | 9 + .../src/components/Modal/Modal.stories.tsx | 156 +++++++++++++++-- .../src/components/Modal/Modal.config.ts | 9 + .../src/components/Modal/Modal.stories.tsx | 156 +++++++++++++++-- .../docs/components/ModalBase.mdx | 47 ++++++ .../docs/components/ModalBase.mdx | 47 ++++++ .../sdds-cs-docs/docs/components/Modal.mdx | 47 ++++++ .../sdds-dfa-docs/docs/components/Modal.mdx | 47 ++++++ .../sdds-insol-docs/docs/components/Modal.mdx | 47 ++++++ .../sdds-serv-docs/docs/components/Modal.mdx | 47 ++++++ 36 files changed, 1769 insertions(+), 96 deletions(-) create mode 100644 cypress/snapshots/b2c/components/ModalBase/ModalBase.component-test.tsx/plasma-web ModalBase -- hasBody hasClose.snap.png create mode 100644 cypress/snapshots/b2c/components/ModalBase/ModalBase.component-test.tsx/plasma-web ModalBase -- hasBody.snap.png create mode 100644 cypress/snapshots/web/components/ModalBase/ModalBase.component-test.tsx/plasma-web ModalBase -- hasBody hasClose.snap.png create mode 100644 cypress/snapshots/web/components/ModalBase/ModalBase.component-test.tsx/plasma-web ModalBase -- hasBody.snap.png create mode 100644 packages/plasma-new-hope/src/components/Modal/Modal.styles.ts diff --git a/cypress/snapshots/b2c/components/ModalBase/ModalBase.component-test.tsx/plasma-web ModalBase -- hasBody hasClose.snap.png b/cypress/snapshots/b2c/components/ModalBase/ModalBase.component-test.tsx/plasma-web ModalBase -- hasBody hasClose.snap.png new file mode 100644 index 0000000000000000000000000000000000000000..c4b806144d636ba0f2ca294f03c6a5e18b06b40d GIT binary patch literal 9385 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 U-V*?Sg0z94qH!`+`O>Zb0)4IS1^@s6 literal 0 HcmV?d00001 diff --git a/cypress/snapshots/b2c/components/ModalBase/ModalBase.component-test.tsx/plasma-web ModalBase -- hasBody.snap.png b/cypress/snapshots/b2c/components/ModalBase/ModalBase.component-test.tsx/plasma-web ModalBase -- hasBody.snap.png new file mode 100644 index 0000000000000000000000000000000000000000..6246e2891097ca3ddc71d6848944bd6b97ab02b9 GIT binary patch literal 8876 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�(USeEfH!su@@<1hkQ>}Z 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 literal 0 HcmV?d00001 diff --git a/cypress/snapshots/web/components/ModalBase/ModalBase.component-test.tsx/plasma-web ModalBase -- hasBody.snap.png b/cypress/snapshots/web/components/ModalBase/ModalBase.component-test.tsx/plasma-web ModalBase -- hasBody.snap.png new file mode 100644 index 0000000000000000000000000000000000000000..c5818c43bed54219d7c5c8a76281a43087dfba99 GIT binary patch literal 9287 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 = { docs: { story: { inline: false, iframeHeight: '30rem' } }, }, argTypes: { + ...disableProps([ + 'onEscKeyDown', + 'onOverlayClick', + 'initialFocusRef', + 'focusAfterRef', + 'onClose', + 'view', + 'isOpen', + 'opened', + 'offset', + 'frame', + 'children', + 'overlay', + 'zIndex', + 'popupInfo', + 'withAnimation', + 'hasBody', + ]), placement: { options: [ 'center', @@ -35,6 +53,37 @@ const meta: Meta = { control: { type: 'select', }, + table: { defaultValue: { summary: 'center' } }, + }, + offsetX: { + control: { + type: 'number', + }, + table: { defaultValue: { summary: 0 } }, + }, + offsetY: { + control: { + type: 'number', + }, + table: { defaultValue: { summary: 0 } }, + }, + closeOnEsc: { + control: { + type: 'boolean', + }, + table: { defaultValue: { summary: true } }, + }, + closeOnOverlayClick: { + control: { + type: 'boolean', + }, + table: { defaultValue: { summary: true } }, + }, + withBlur: { + control: { + type: 'boolean', + }, + table: { defaultValue: { summary: false } }, }, }, }; @@ -48,6 +97,7 @@ type StoryModalBaseProps = { closeOnEsc: boolean; closeOnOverlayClick: boolean; withBlur: boolean; + hasClose?: boolean; }; const StyledButton = styled(Button)` @@ -98,7 +148,90 @@ const StyledModal = styled(ModalBase)` } `; -const StoryModalBaseDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalBaseProps) => { +const StoryCustomModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalBaseProps) => { + const [isOpenA, setIsOpenA] = useState(false); + const [isOpenB, setIsOpenB] = useState(false); + const [isOpenC, setIsOpenC] = useState(false); + + return ( + + + +
+ setIsOpenA(true)} /> +
+ setIsOpenA(false)} + opened={isOpenA} + placement={placement} + offset={[offsetX, offsetY]} + hasBody + {...rest} + > + +
+ setIsOpenB(true)} /> +
+ setIsOpenB(false)} + opened={isOpenB} + placement="left" + offset={[offsetX, offsetY]} + hasBody + {...rest} + > + +
+ setIsOpenC(true)} /> +
+ setIsOpenC(false)} + opened={isOpenC} + placement="top" + offset={[offsetX, offsetY]} + hasBody + {...rest} + > + + <>Content + +
+
+
+
+
+ ); +}; + +export const Default: StoryObj = { + args: { + placement: 'center', + withBlur: false, + closeOnEsc: true, + closeOnOverlayClick: true, + offsetX: 0, + offsetY: 0, + hasClose: true, + }, + argTypes: { + hasClose: { + control: { + type: 'boolean', + }, + }, + }, + render: (args) => , +}; + +const StoryCustomModalBaseDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalBaseProps) => { const [isOpenA, setIsOpenA] = useState(false); const [isOpenB, setIsOpenB] = useState(false); const [isOpenC, setIsOpenC] = useState(false); @@ -173,7 +306,10 @@ export const ModalBaseDemo: StoryObj = { offsetX: 0, offsetY: 0, }, - render: (args) => , + argTypes: { + ...disableProps(['hasClose']), + }, + render: (args) => , }; const StyledModalAnimation = styled(ModalBase)` @@ -295,5 +431,8 @@ export const ModalBottomAnimation: StoryObj = { offsetX: 0, offsetY: 0, }, + argTypes: { + ...disableProps(['hasClose']), + }, render: (args) => , }; diff --git a/packages/plasma-new-hope/src/components/Modal/Modal.styles.ts b/packages/plasma-new-hope/src/components/Modal/Modal.styles.ts new file mode 100644 index 0000000000..f97c142ddb --- /dev/null +++ b/packages/plasma-new-hope/src/components/Modal/Modal.styles.ts @@ -0,0 +1,59 @@ +import { styled } from '@linaria/react'; + +import { addFocus } from '../../mixins'; + +import { tokens } from './Modal.tokens'; + +export const ModalBody = styled.div` + border-radius: var(${tokens.modalBodyBorderRadius}); + padding: var(${tokens.modalBodyPadding}); + background: var(${tokens.modalBodyBackground}); + box-shadow: var(--shadow-down-soft-l); +`; + +export const ModalContent = styled.div` + position: relative; + padding: var(${tokens.modalContentPadding}); +`; + +export const CloseButton = styled.button` + top: 0; + right: 0; + + width: 1.5rem; + height: 1.5rem; + + display: flex; + align-items: center; + justify-content: center; + + border: none; + border-radius: var(${tokens.modalCloseButtonRadius}); + + padding: 0; + margin: 0; + outline: none; + + cursor: pointer; + + background: transparent; + + ${addFocus({ + outlineSize: '0.063rem', + outlineOffset: '-0.125rem', + outlineColor: `var(${tokens.modalOutlineFocusColor})`, + outlineRadius: `calc(var(${tokens.modalCloseButtonRadius}) + 0.063rem)`, + })}; + + color: var(${tokens.modalCloseButtonColor}); + + &:hover { + color: var(${tokens.modalCloseButtonHoverColor}); + } + + &:active { + color: var(${tokens.modalCloseButtonActiveColor}); + } + + position: absolute; +`; diff --git a/packages/plasma-new-hope/src/components/Modal/Modal.template-doc.mdx b/packages/plasma-new-hope/src/components/Modal/Modal.template-doc.mdx index a5e89bbab3..e613b93d34 100644 --- a/packages/plasma-new-hope/src/components/Modal/Modal.template-doc.mdx +++ b/packages/plasma-new-hope/src/components/Modal/Modal.template-doc.mdx @@ -62,6 +62,53 @@ export function App() { } ``` +## Использование стилизованной обертки + +Для использования стилизованного модального окна с отступами и крестиком для закрытия, добавьте свойство `hasBody`. +```tsx live +import React, { useState } from 'react'; +import { SSRProvider, Button, Modal, PopupProvider } from '@salutejs/{{ package }}'; + +export function App() { + const [isOpenA, setIsOpenA] = useState(false); + const [isOpenB, setIsOpenB] = useState(false); + + return ( + + +
+
+
+ setIsOpenA(false)} + opened={isOpenA} + placement="center" + offset={[0, 0]} + hasBody + > + + + Content + + +
+
+
+ ); +} +``` + ## Подключение анимации Подключение анимации аналогично тому, как это происходит в `Popup` - через свойство `withAnimation`(управление через `popupClasses`, `modalClasses`). Для добавления анимации в оверлей необходимо использовать класс `.modal-overlay` через переменную `modalClasses.overlay` из пакета. diff --git a/packages/plasma-new-hope/src/components/Modal/Modal.tokens.ts b/packages/plasma-new-hope/src/components/Modal/Modal.tokens.ts index dbeab540e3..5b82b14f4b 100644 --- a/packages/plasma-new-hope/src/components/Modal/Modal.tokens.ts +++ b/packages/plasma-new-hope/src/components/Modal/Modal.tokens.ts @@ -8,4 +8,13 @@ export const classes = { export const tokens = { modalOverlayWithBlurColor: '--plasma-modal-overlay-with-blur-color', modalOverlayColor: '--plasma-modal-overlay-color', + modalBodyBackground: '--plasma-modal-body-background', + modalBodyBorderRadius: '--plasma-modal-body-border-radius', + modalBodyPadding: '--plasma-modal-body-padding', + modalContentPadding: '--plasma-modal-content-padding', + modalOutlineFocusColor: '--plasma-modal-outline-focus-color', + modalCloseButtonRadius: '--plasma-modal-close-button-radius', + modalCloseButtonColor: '--plasma-modal-close-button-color', + modalCloseButtonHoverColor: '--plasma-modal-close-button-hover-color', + modalCloseButtonActiveColor: '--plasma-modal-close-button-active-color', }; diff --git a/packages/plasma-new-hope/src/components/Modal/Modal.tsx b/packages/plasma-new-hope/src/components/Modal/Modal.tsx index ca551bff69..d6cfe42ec5 100644 --- a/packages/plasma-new-hope/src/components/Modal/Modal.tsx +++ b/packages/plasma-new-hope/src/components/Modal/Modal.tsx @@ -6,12 +6,14 @@ import { popupConfig, usePopupContext } from '../Popup'; import { Overlay } from '../Overlay'; import { DEFAULT_Z_INDEX } from '../Popup/utils'; import { useFocusTrap } from '../../hooks'; +import { IconClose } from '../_Icon/Icons/IconClose'; import { classes, tokens } from './Modal.tokens'; import { ModalProps } from './Modal.types'; import { useModal } from './hooks'; import { base as viewCSS } from './variations/_view/base'; import { getIdLastModal } from './ModalContext'; +import { CloseButton, ModalBody, ModalContent } from './Modal.styles'; // issue #823 const Popup = component(popupConfig); @@ -40,11 +42,14 @@ export const modalRoot = (Root: RootProps) => view, opened, isOpen, + hasBody, + hasClose, ...rest }, outerRootRef, ) => { const innerIsOpen = Boolean(isOpen || opened); + const innerHasClose = (hasClose === undefined && hasBody) || hasClose; const trapRef = useFocusTrap(true, initialFocusRef, focusAfterRef, true); const popupController = usePopupContext(); @@ -84,6 +89,18 @@ export const modalRoot = (Root: RootProps) => [closeOnOverlayClick, onOverlayClick, onClose], ); + const overlayNode = ( + + ); + return ( ) => popupInfo={modalInfo} withAnimation={withAnimation} zIndex={zIndex} - overlay={ - - - - } + overlay={hasBody ? overlayNode : {overlayNode}} {...rest} > - {children} + {hasBody ? ( + + + + {innerHasClose && ( + + + + )} + {children} + + + + ) : ( + <>{children} + )} ); }, diff --git a/packages/plasma-new-hope/src/components/Modal/Modal.types.ts b/packages/plasma-new-hope/src/components/Modal/Modal.types.ts index e8c503f874..a1bb14b3e0 100644 --- a/packages/plasma-new-hope/src/components/Modal/Modal.types.ts +++ b/packages/plasma-new-hope/src/components/Modal/Modal.types.ts @@ -1,6 +1,22 @@ import { PopupHookArgs, PopupProps, PopupRootProps } from '../Popup/Popup.types'; -export interface ModalProps extends PopupProps { +export type ModalBodyProps = + | { + /** + * Оборачивает children в стилизованную обертку + */ + hasBody: true; + /** + * Отображает кнопку с крестиком для закрытия + */ + hasClose?: boolean; + } + | { + hasBody?: never; + hasClose?: never; + }; + +export interface CommonModalProps extends PopupProps { /** * Нужно ли применять blur для подложки. */ @@ -37,6 +53,8 @@ export interface ModalProps extends PopupProps { view?: string; } +export type ModalProps = CommonModalProps & ModalBodyProps; + export type ModalBaseRootProps = PopupRootProps & Pick; export type ModalOverlayProps = Pick & diff --git a/packages/plasma-new-hope/src/components/Modal/index.ts b/packages/plasma-new-hope/src/components/Modal/index.ts index fa65055a9e..5d65da0299 100644 --- a/packages/plasma-new-hope/src/components/Modal/index.ts +++ b/packages/plasma-new-hope/src/components/Modal/index.ts @@ -1,3 +1,3 @@ export { modalConfig, modalRoot } from './Modal'; export { classes as modalClasses, tokens as modalTokens } from './Modal.tokens'; -export type { ModalProps, ModalOverlayProps } from './Modal.types'; +export type { ModalBodyProps, CommonModalProps, ModalProps, ModalOverlayProps } from './Modal.types'; diff --git a/packages/plasma-new-hope/src/examples/plasma_b2c/components/Modal/Modal.config.ts b/packages/plasma-new-hope/src/examples/plasma_b2c/components/Modal/Modal.config.ts index 066fff6029..e964ad353f 100644 --- a/packages/plasma-new-hope/src/examples/plasma_b2c/components/Modal/Modal.config.ts +++ b/packages/plasma-new-hope/src/examples/plasma_b2c/components/Modal/Modal.config.ts @@ -11,6 +11,15 @@ export const config = { default: css` ${modalTokens.modalOverlayWithBlurColor}: var(--overlay-blur); ${modalTokens.modalOverlayColor}: var(--overlay-soft); + ${modalTokens.modalBodyBackground}: var(--surface-solid-card); + ${modalTokens.modalBodyBorderRadius}: 1.25rem; + ${modalTokens.modalBodyPadding}: 2rem; + ${modalTokens.modalContentPadding}: 0.625rem; + ${modalTokens.modalCloseButtonRadius}: 0.375rem; + ${modalTokens.modalCloseButtonColor}: var(--text-secondary); + ${modalTokens.modalCloseButtonHoverColor}: var(--text-secondary-hover); + ${modalTokens.modalCloseButtonActiveColor}: var(--text-secondary-active); + ${modalTokens.modalOutlineFocusColor}: var(--surface-accent); `, }, }, diff --git a/packages/plasma-new-hope/src/examples/plasma_b2c/components/Modal/Modal.stories.tsx b/packages/plasma-new-hope/src/examples/plasma_b2c/components/Modal/Modal.stories.tsx index a6f2c1b0b9..5c9f6ccdff 100644 --- a/packages/plasma-new-hope/src/examples/plasma_b2c/components/Modal/Modal.stories.tsx +++ b/packages/plasma-new-hope/src/examples/plasma_b2c/components/Modal/Modal.stories.tsx @@ -3,6 +3,7 @@ import { styled } from '@linaria/react'; import type { ComponentProps } from 'react'; import type { StoryObj, Meta } from '@storybook/react'; import { SSRProvider } from '@salutejs/plasma-core'; +import { disableProps } from '@salutejs/plasma-sb-utils'; import { PopupProvider, popupClasses } from '../Popup/Popup'; import { Button } from '../Button/Button'; @@ -18,6 +19,7 @@ export default { docs: { story: { inline: false, iframeHeight: '30rem' } }, }, argTypes: { + ...disableProps(['hasBody']), placement: { options: [ 'center', @@ -75,6 +77,7 @@ type StoryModalProps = ComponentProps & { closeOnEsc: boolean; closeOnOverlayClick: boolean; withBlur: boolean; + hasClose?: boolean; }; const StyledButton = styled(Button)` @@ -135,6 +138,74 @@ const StoryModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProp const [isOpenB, setIsOpenB] = useState(false); const [isOpenC, setIsOpenC] = useState(false); + return ( + + + + + setIsOpenA(true)} /> + + setIsOpenA(false)} + opened={isOpenA} + placement={placement} + offset={[offsetX, offsetY]} + hasBody + {...rest} + > + + + setIsOpenB(true)} /> + + setIsOpenB(false)} + opened={isOpenB} + placement="left" + offset={[offsetX, offsetY]} + hasBody + {...rest} + > + + + setIsOpenC(true)} /> + + setIsOpenC(false)} + opened={isOpenC} + placement="top" + offset={[offsetX, offsetY]} + hasBody + {...rest} + > +
+ + <>Content +
+
+
+
+
+
+
+ ); +}; + +const StoryCustomModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProps) => { + const [isOpenA, setIsOpenA] = useState(false); + const [isOpenB, setIsOpenB] = useState(false); + const [isOpenC, setIsOpenC] = useState(false); + return ( @@ -199,7 +270,7 @@ const StoryModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProp ); }; -export const ModalDemo: StoryObj = { +export const Default: StoryObj = { args: { placement: 'center', withBlur: false, @@ -207,10 +278,30 @@ export const ModalDemo: StoryObj = { closeOnOverlayClick: true, offsetX: 0, offsetY: 0, + hasClose: true, + }, + argTypes: { + hasClose: { + control: { + type: 'boolean', + }, + }, }, render: (args) => , }; +export const CustomModalDemo: StoryObj = { + args: { + placement: 'center', + withBlur: false, + closeOnEsc: true, + closeOnOverlayClick: true, + offsetX: 0, + offsetY: 0, + }, + render: (args) => , +}; + const StyledModalAnimation = styled(Modal)` /* stylelint-disable */ && .${popupClasses.root} { diff --git a/packages/plasma-new-hope/src/examples/plasma_web/components/Modal/Modal.config.ts b/packages/plasma-new-hope/src/examples/plasma_web/components/Modal/Modal.config.ts index 066fff6029..e964ad353f 100644 --- a/packages/plasma-new-hope/src/examples/plasma_web/components/Modal/Modal.config.ts +++ b/packages/plasma-new-hope/src/examples/plasma_web/components/Modal/Modal.config.ts @@ -11,6 +11,15 @@ export const config = { default: css` ${modalTokens.modalOverlayWithBlurColor}: var(--overlay-blur); ${modalTokens.modalOverlayColor}: var(--overlay-soft); + ${modalTokens.modalBodyBackground}: var(--surface-solid-card); + ${modalTokens.modalBodyBorderRadius}: 1.25rem; + ${modalTokens.modalBodyPadding}: 2rem; + ${modalTokens.modalContentPadding}: 0.625rem; + ${modalTokens.modalCloseButtonRadius}: 0.375rem; + ${modalTokens.modalCloseButtonColor}: var(--text-secondary); + ${modalTokens.modalCloseButtonHoverColor}: var(--text-secondary-hover); + ${modalTokens.modalCloseButtonActiveColor}: var(--text-secondary-active); + ${modalTokens.modalOutlineFocusColor}: var(--surface-accent); `, }, }, diff --git a/packages/plasma-new-hope/src/examples/plasma_web/components/Modal/Modal.stories.tsx b/packages/plasma-new-hope/src/examples/plasma_web/components/Modal/Modal.stories.tsx index f4c45bf766..e6d3abcfd5 100644 --- a/packages/plasma-new-hope/src/examples/plasma_web/components/Modal/Modal.stories.tsx +++ b/packages/plasma-new-hope/src/examples/plasma_web/components/Modal/Modal.stories.tsx @@ -3,6 +3,7 @@ import { styled } from '@linaria/react'; import type { ComponentProps } from 'react'; import type { StoryObj, Meta } from '@storybook/react'; import { SSRProvider } from '@salutejs/plasma-core'; +import { disableProps } from '@salutejs/plasma-sb-utils'; import { PopupProvider, popupClasses } from '../Popup/Popup'; import { Button } from '../Button/Button'; @@ -18,6 +19,7 @@ export default { docs: { story: { inline: false, iframeHeight: '30rem' } }, }, argTypes: { + ...disableProps(['hasBody']), placement: { options: [ 'center', @@ -75,6 +77,7 @@ type StoryModalProps = ComponentProps & { closeOnEsc: boolean; closeOnOverlayClick: boolean; withBlur: boolean; + hasClose?: boolean; }; const StyledButton = styled(Button)` @@ -135,6 +138,72 @@ const StoryModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProp const [isOpenB, setIsOpenB] = useState(false); const [isOpenC, setIsOpenC] = useState(false); + return ( + + + + + setIsOpenA(true)} /> + + setIsOpenA(false)} + opened={isOpenA} + placement={placement} + offset={[offsetX, offsetY]} + hasBody + {...rest} + > + + + setIsOpenB(true)} /> + + setIsOpenB(false)} + opened={isOpenB} + placement="left" + offset={[offsetX, offsetY]} + hasBody + {...rest} + > + + + setIsOpenC(true)} /> + + setIsOpenC(false)} + opened={isOpenC} + placement="top" + offset={[offsetX, offsetY]} + hasBody + {...rest} + > + + <>Content + + + + + + + ); +}; + +const StoryCustomModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProps) => { + const [isOpenA, setIsOpenA] = useState(false); + const [isOpenB, setIsOpenB] = useState(false); + const [isOpenC, setIsOpenC] = useState(false); + return ( @@ -199,7 +268,7 @@ const StoryModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProp ); }; -export const ModalDemo: StoryObj = { +export const Default: StoryObj = { args: { placement: 'center', withBlur: false, @@ -207,10 +276,30 @@ export const ModalDemo: StoryObj = { closeOnOverlayClick: true, offsetX: 0, offsetY: 0, + hasClose: true, + }, + argTypes: { + hasClose: { + control: { + type: 'boolean', + }, + }, }, render: (args) => , }; +export const CustomModalDemo: StoryObj = { + args: { + placement: 'center', + withBlur: false, + closeOnEsc: true, + closeOnOverlayClick: true, + offsetX: 0, + offsetY: 0, + }, + render: (args) => , +}; + const StyledModalAnimation = styled(Modal)` /* stylelint-disable */ && .${popupClasses.root} { diff --git a/packages/plasma-web/src/components/ModalBase/Modal.config.ts b/packages/plasma-web/src/components/ModalBase/Modal.config.ts index edc1be758d..8b107b98ea 100644 --- a/packages/plasma-web/src/components/ModalBase/Modal.config.ts +++ b/packages/plasma-web/src/components/ModalBase/Modal.config.ts @@ -9,6 +9,15 @@ export const config = { default: css` ${modalTokens.modalOverlayWithBlurColor}: rgba(35, 35, 35, 0.2); ${modalTokens.modalOverlayColor}: var(--overlay-soft); + ${modalTokens.modalBodyBackground}: var(--surface-solid-card); + ${modalTokens.modalBodyBorderRadius}: 1.25rem; + ${modalTokens.modalBodyPadding}: 2rem; + ${modalTokens.modalContentPadding}: 0.625rem; + ${modalTokens.modalCloseButtonRadius}: 0.375rem; + ${modalTokens.modalCloseButtonColor}: var(--text-secondary); + ${modalTokens.modalCloseButtonHoverColor}: var(--text-secondary-hover); + ${modalTokens.modalCloseButtonActiveColor}: var(--text-secondary-active); + ${modalTokens.modalOutlineFocusColor}: var(--surface-accent); `, }, }, diff --git a/packages/plasma-web/src/components/ModalBase/ModalBase.component-test.tsx b/packages/plasma-web/src/components/ModalBase/ModalBase.component-test.tsx index a2d549ef8a..254a583db9 100644 --- a/packages/plasma-web/src/components/ModalBase/ModalBase.component-test.tsx +++ b/packages/plasma-web/src/components/ModalBase/ModalBase.component-test.tsx @@ -49,6 +49,37 @@ describe('plasma-web: ModalBase', () => { ); } + function DemoWithBody({ + open = false, + withBlur = false, + placement, + hasClose, + }: { + open?: boolean; + withBlur?: boolean; + placement?: string; + hasClose?: boolean; + }) { + const [isOpen, setIsOpen] = React.useState(open); + + return ( + + +
+ setIsOpenB(true)} /> +
+ setIsOpenB(false)} + opened={isOpenB} + placement="left" + offset={[offsetX, offsetY]} + hasBody + {...rest} + > + +
+ setIsOpenC(true)} /> +
+ setIsOpenC(false)} + opened={isOpenC} + placement="top" + offset={[offsetX, offsetY]} + hasBody + {...rest} + > + + <>Content + +
+ +
+
+
+ ); +}; + +export const Default: StoryObj = { + args: { + placement: 'center', + withBlur: false, + closeOnEsc: true, + closeOnOverlayClick: true, + offsetX: 0, + offsetY: 0, + hasClose: true, + }, + argTypes: { + hasClose: { + control: { + type: 'boolean', + }, + }, + }, + render: (args) => , +}; + +const StoryCustomModalBaseDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalBaseProps) => { const [isOpenA, setIsOpenA] = useState(false); const [isOpenB, setIsOpenB] = useState(false); const [isOpenC, setIsOpenC] = useState(false); @@ -173,7 +306,10 @@ export const ModalBaseDemo: StoryObj = { offsetX: 0, offsetY: 0, }, - render: (args) => , + argTypes: { + ...disableProps(['hasClose']), + }, + render: (args) => , }; const StyledModalAnimation = styled(ModalBase)` @@ -295,5 +431,8 @@ export const ModalBottomAnimation: StoryObj = { offsetX: 0, offsetY: 0, }, + argTypes: { + ...disableProps(['hasClose']), + }, render: (args) => , }; diff --git a/packages/sdds-cs/src/components/Modal/Modal.config.ts b/packages/sdds-cs/src/components/Modal/Modal.config.ts index edc1be758d..8b107b98ea 100644 --- a/packages/sdds-cs/src/components/Modal/Modal.config.ts +++ b/packages/sdds-cs/src/components/Modal/Modal.config.ts @@ -9,6 +9,15 @@ export const config = { default: css` ${modalTokens.modalOverlayWithBlurColor}: rgba(35, 35, 35, 0.2); ${modalTokens.modalOverlayColor}: var(--overlay-soft); + ${modalTokens.modalBodyBackground}: var(--surface-solid-card); + ${modalTokens.modalBodyBorderRadius}: 1.25rem; + ${modalTokens.modalBodyPadding}: 2rem; + ${modalTokens.modalContentPadding}: 0.625rem; + ${modalTokens.modalCloseButtonRadius}: 0.375rem; + ${modalTokens.modalCloseButtonColor}: var(--text-secondary); + ${modalTokens.modalCloseButtonHoverColor}: var(--text-secondary-hover); + ${modalTokens.modalCloseButtonActiveColor}: var(--text-secondary-active); + ${modalTokens.modalOutlineFocusColor}: var(--surface-accent); `, }, }, diff --git a/packages/sdds-cs/src/components/Modal/Modal.stories.tsx b/packages/sdds-cs/src/components/Modal/Modal.stories.tsx index ee950ba52a..bab20ebd3a 100644 --- a/packages/sdds-cs/src/components/Modal/Modal.stories.tsx +++ b/packages/sdds-cs/src/components/Modal/Modal.stories.tsx @@ -1,7 +1,8 @@ import React, { useCallback, useRef, useState } from 'react'; -import styled, { css } from 'styled-components'; +import type { ComponentProps } from 'react'; +import styled from 'styled-components'; import type { Meta, StoryObj } from '@storybook/react'; -import { disableProps, InSpacingDecorator } from '@salutejs/plasma-sb-utils'; +import { InSpacingDecorator, disableProps } from '@salutejs/plasma-sb-utils'; import { SSRProvider } from '../SSRProvider'; import { Button } from '../Button'; @@ -18,7 +19,7 @@ const meta: Meta = { docs: { story: { inline: false, iframeHeight: '30rem' } }, }, argTypes: { - ...disableProps(['view']), + ...disableProps(['view', 'hasBody']), placement: { options: [ 'center', @@ -34,19 +35,51 @@ const meta: Meta = { control: { type: 'select', }, + table: { defaultValue: { summary: 'center' } }, + }, + offsetX: { + control: { + type: 'number', + }, + table: { defaultValue: { summary: 0 } }, + }, + offsetY: { + control: { + type: 'number', + }, + table: { defaultValue: { summary: 0 } }, + }, + closeOnEsc: { + control: { + type: 'boolean', + }, + table: { defaultValue: { summary: true } }, + }, + closeOnOverlayClick: { + control: { + type: 'boolean', + }, + table: { defaultValue: { summary: true } }, + }, + withBlur: { + control: { + type: 'boolean', + }, + table: { defaultValue: { summary: false } }, }, }, -}; +} as Meta; export default meta; -type StoryModalProps = { +type StoryModalProps = ComponentProps & { placement: string; offsetX: number; offsetY: number; closeOnEsc: boolean; closeOnOverlayClick: boolean; withBlur: boolean; + hasClose?: boolean; }; const StyledButton = styled(Button)` @@ -64,6 +97,11 @@ const Content = styled.div` border-radius: 1rem; `; +const ButtonWrapper = styled.div` + display: flex; + flex-direction: column; +`; + const StyledModal = styled(Modal)` && > .${popupClasses.root}, .${modalClasses.overlay} { animation: fadeIn 1s forwards; @@ -99,19 +137,86 @@ const StyledModal = styled(Modal)` `; const StoryModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProps) => { - const [isOpenA, setIsOpenA] = React.useState(false); - const [isOpenB, setIsOpenB] = React.useState(false); - const [isOpenC, setIsOpenC] = React.useState(false); + const [isOpenA, setIsOpenA] = useState(false); + const [isOpenB, setIsOpenB] = useState(false); + const [isOpenC, setIsOpenC] = useState(false); + + return ( + + + + + setIsOpenA(true)} /> + + setIsOpenA(false)} + opened={isOpenA} + placement={placement} + offset={[offsetX, offsetY]} + hasBody + {...rest} + > + + + setIsOpenB(true)} /> + + setIsOpenB(false)} + opened={isOpenB} + placement="left" + offset={[offsetX, offsetY]} + hasBody + {...rest} + > + + + setIsOpenC(true)} /> + + setIsOpenC(false)} + opened={isOpenC} + placement="top" + offset={[offsetX, offsetY]} + hasBody + {...rest} + > + + <>Content + + + + + + + ); +}; + +const StoryCustomModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProps) => { + const [isOpenA, setIsOpenA] = useState(false); + const [isOpenB, setIsOpenB] = useState(false); + const [isOpenC, setIsOpenC] = useState(false); return ( -
+ setIsOpenA(true)} /> -
+ setIsOpenA(false)} opened={isOpenA} @@ -121,11 +226,12 @@ const StoryModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProp > -
+ setIsOpenB(true)} /> -
+ setIsOpenB(false)} opened={isOpenB} placement="left" @@ -136,11 +242,12 @@ const StoryModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProp -
+ setIsOpenC(true)} /> -
+ setIsOpenC(false)} opened={isOpenC} placement="top" @@ -164,7 +271,7 @@ const StoryModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProp ); }; -export const ModalDemo: StoryObj = { +export const Default: StoryObj = { args: { placement: 'center', withBlur: false, @@ -172,10 +279,30 @@ export const ModalDemo: StoryObj = { closeOnOverlayClick: true, offsetX: 0, offsetY: 0, + hasClose: true, + }, + argTypes: { + hasClose: { + control: { + type: 'boolean', + }, + }, }, render: (args) => , }; +export const CustomModalDemo: StoryObj = { + args: { + placement: 'center', + withBlur: false, + closeOnEsc: true, + closeOnOverlayClick: true, + offsetX: 0, + offsetY: 0, + }, + render: (args) => , +}; + const StyledModalAnimation = styled(Modal)` /* stylelint-disable */ ${({ placement }) => diff --git a/packages/sdds-dfa/src/components/Modal/Modal.config.ts b/packages/sdds-dfa/src/components/Modal/Modal.config.ts index edc1be758d..8b107b98ea 100644 --- a/packages/sdds-dfa/src/components/Modal/Modal.config.ts +++ b/packages/sdds-dfa/src/components/Modal/Modal.config.ts @@ -9,6 +9,15 @@ export const config = { default: css` ${modalTokens.modalOverlayWithBlurColor}: rgba(35, 35, 35, 0.2); ${modalTokens.modalOverlayColor}: var(--overlay-soft); + ${modalTokens.modalBodyBackground}: var(--surface-solid-card); + ${modalTokens.modalBodyBorderRadius}: 1.25rem; + ${modalTokens.modalBodyPadding}: 2rem; + ${modalTokens.modalContentPadding}: 0.625rem; + ${modalTokens.modalCloseButtonRadius}: 0.375rem; + ${modalTokens.modalCloseButtonColor}: var(--text-secondary); + ${modalTokens.modalCloseButtonHoverColor}: var(--text-secondary-hover); + ${modalTokens.modalCloseButtonActiveColor}: var(--text-secondary-active); + ${modalTokens.modalOutlineFocusColor}: var(--surface-accent); `, }, }, diff --git a/packages/sdds-dfa/src/components/Modal/Modal.stories.tsx b/packages/sdds-dfa/src/components/Modal/Modal.stories.tsx index e6fc6db601..ed100b6801 100644 --- a/packages/sdds-dfa/src/components/Modal/Modal.stories.tsx +++ b/packages/sdds-dfa/src/components/Modal/Modal.stories.tsx @@ -1,7 +1,8 @@ import React, { useCallback, useRef, useState } from 'react'; -import styled, { css } from 'styled-components'; +import type { ComponentProps } from 'react'; +import styled from 'styled-components'; import type { Meta, StoryObj } from '@storybook/react'; -import { InSpacingDecorator } from '@salutejs/plasma-sb-utils'; +import { InSpacingDecorator, disableProps } from '@salutejs/plasma-sb-utils'; import { SSRProvider } from '../SSRProvider'; import { Button } from '../Button'; @@ -18,6 +19,7 @@ const meta: Meta = { docs: { story: { inline: false, iframeHeight: '30rem' } }, }, argTypes: { + ...disableProps(['hasBody']), placement: { options: [ 'center', @@ -33,19 +35,51 @@ const meta: Meta = { control: { type: 'select', }, + table: { defaultValue: { summary: 'center' } }, + }, + offsetX: { + control: { + type: 'number', + }, + table: { defaultValue: { summary: 0 } }, + }, + offsetY: { + control: { + type: 'number', + }, + table: { defaultValue: { summary: 0 } }, + }, + closeOnEsc: { + control: { + type: 'boolean', + }, + table: { defaultValue: { summary: true } }, + }, + closeOnOverlayClick: { + control: { + type: 'boolean', + }, + table: { defaultValue: { summary: true } }, + }, + withBlur: { + control: { + type: 'boolean', + }, + table: { defaultValue: { summary: false } }, }, }, -}; +} as Meta; export default meta; -type StoryModalProps = { +type StoryModalProps = ComponentProps & { placement: string; offsetX: number; offsetY: number; closeOnEsc: boolean; closeOnOverlayClick: boolean; withBlur: boolean; + hasClose?: boolean; }; const StyledButton = styled(Button)` @@ -62,6 +96,11 @@ const Content = styled.div` padding: 1rem; `; +const ButtonWrapper = styled.div` + display: flex; + flex-direction: column; +`; + const StyledModal = styled(Modal)` && > .${popupClasses.root}, .${modalClasses.overlay} { animation: fadeIn 1s forwards; @@ -97,19 +136,86 @@ const StyledModal = styled(Modal)` `; const StoryModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProps) => { - const [isOpenA, setIsOpenA] = React.useState(false); - const [isOpenB, setIsOpenB] = React.useState(false); - const [isOpenC, setIsOpenC] = React.useState(false); + const [isOpenA, setIsOpenA] = useState(false); + const [isOpenB, setIsOpenB] = useState(false); + const [isOpenC, setIsOpenC] = useState(false); + + return ( + + + + + setIsOpenA(true)} /> + + setIsOpenA(false)} + opened={isOpenA} + placement={placement} + offset={[offsetX, offsetY]} + hasBody + {...rest} + > + + + setIsOpenB(true)} /> + + setIsOpenB(false)} + opened={isOpenB} + placement="left" + offset={[offsetX, offsetY]} + hasBody + {...rest} + > + + + setIsOpenC(true)} /> + + setIsOpenC(false)} + opened={isOpenC} + placement="top" + offset={[offsetX, offsetY]} + hasBody + {...rest} + > + + <>Content + + + + + + + ); +}; + +const StoryCustomModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProps) => { + const [isOpenA, setIsOpenA] = useState(false); + const [isOpenB, setIsOpenB] = useState(false); + const [isOpenC, setIsOpenC] = useState(false); return ( -
+ setIsOpenA(true)} /> -
+ setIsOpenA(false)} opened={isOpenA} @@ -119,11 +225,12 @@ const StoryModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProp > -
+ setIsOpenB(true)} /> -
+ setIsOpenB(false)} opened={isOpenB} placement="left" @@ -134,11 +241,12 @@ const StoryModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProp -
+ setIsOpenC(true)} /> -
+ setIsOpenC(false)} opened={isOpenC} placement="top" @@ -162,7 +270,7 @@ const StoryModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProp ); }; -export const ModalDemo: StoryObj = { +export const Default: StoryObj = { args: { placement: 'center', withBlur: false, @@ -170,10 +278,30 @@ export const ModalDemo: StoryObj = { closeOnOverlayClick: true, offsetX: 0, offsetY: 0, + hasClose: true, + }, + argTypes: { + hasClose: { + control: { + type: 'boolean', + }, + }, }, render: (args) => , }; +export const CustomModalDemo: StoryObj = { + args: { + placement: 'center', + withBlur: false, + closeOnEsc: true, + closeOnOverlayClick: true, + offsetX: 0, + offsetY: 0, + }, + render: (args) => , +}; + const StyledModalAnimation = styled(Modal)` /* stylelint-disable */ ${({ placement }) => diff --git a/packages/sdds-finportal/src/components/Modal/Modal.config.ts b/packages/sdds-finportal/src/components/Modal/Modal.config.ts index edc1be758d..8b107b98ea 100644 --- a/packages/sdds-finportal/src/components/Modal/Modal.config.ts +++ b/packages/sdds-finportal/src/components/Modal/Modal.config.ts @@ -9,6 +9,15 @@ export const config = { default: css` ${modalTokens.modalOverlayWithBlurColor}: rgba(35, 35, 35, 0.2); ${modalTokens.modalOverlayColor}: var(--overlay-soft); + ${modalTokens.modalBodyBackground}: var(--surface-solid-card); + ${modalTokens.modalBodyBorderRadius}: 1.25rem; + ${modalTokens.modalBodyPadding}: 2rem; + ${modalTokens.modalContentPadding}: 0.625rem; + ${modalTokens.modalCloseButtonRadius}: 0.375rem; + ${modalTokens.modalCloseButtonColor}: var(--text-secondary); + ${modalTokens.modalCloseButtonHoverColor}: var(--text-secondary-hover); + ${modalTokens.modalCloseButtonActiveColor}: var(--text-secondary-active); + ${modalTokens.modalOutlineFocusColor}: var(--surface-accent); `, }, }, diff --git a/packages/sdds-finportal/src/components/Modal/Modal.stories.tsx b/packages/sdds-finportal/src/components/Modal/Modal.stories.tsx index e6fc6db601..ed100b6801 100644 --- a/packages/sdds-finportal/src/components/Modal/Modal.stories.tsx +++ b/packages/sdds-finportal/src/components/Modal/Modal.stories.tsx @@ -1,7 +1,8 @@ import React, { useCallback, useRef, useState } from 'react'; -import styled, { css } from 'styled-components'; +import type { ComponentProps } from 'react'; +import styled from 'styled-components'; import type { Meta, StoryObj } from '@storybook/react'; -import { InSpacingDecorator } from '@salutejs/plasma-sb-utils'; +import { InSpacingDecorator, disableProps } from '@salutejs/plasma-sb-utils'; import { SSRProvider } from '../SSRProvider'; import { Button } from '../Button'; @@ -18,6 +19,7 @@ const meta: Meta = { docs: { story: { inline: false, iframeHeight: '30rem' } }, }, argTypes: { + ...disableProps(['hasBody']), placement: { options: [ 'center', @@ -33,19 +35,51 @@ const meta: Meta = { control: { type: 'select', }, + table: { defaultValue: { summary: 'center' } }, + }, + offsetX: { + control: { + type: 'number', + }, + table: { defaultValue: { summary: 0 } }, + }, + offsetY: { + control: { + type: 'number', + }, + table: { defaultValue: { summary: 0 } }, + }, + closeOnEsc: { + control: { + type: 'boolean', + }, + table: { defaultValue: { summary: true } }, + }, + closeOnOverlayClick: { + control: { + type: 'boolean', + }, + table: { defaultValue: { summary: true } }, + }, + withBlur: { + control: { + type: 'boolean', + }, + table: { defaultValue: { summary: false } }, }, }, -}; +} as Meta; export default meta; -type StoryModalProps = { +type StoryModalProps = ComponentProps & { placement: string; offsetX: number; offsetY: number; closeOnEsc: boolean; closeOnOverlayClick: boolean; withBlur: boolean; + hasClose?: boolean; }; const StyledButton = styled(Button)` @@ -62,6 +96,11 @@ const Content = styled.div` padding: 1rem; `; +const ButtonWrapper = styled.div` + display: flex; + flex-direction: column; +`; + const StyledModal = styled(Modal)` && > .${popupClasses.root}, .${modalClasses.overlay} { animation: fadeIn 1s forwards; @@ -97,19 +136,86 @@ const StyledModal = styled(Modal)` `; const StoryModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProps) => { - const [isOpenA, setIsOpenA] = React.useState(false); - const [isOpenB, setIsOpenB] = React.useState(false); - const [isOpenC, setIsOpenC] = React.useState(false); + const [isOpenA, setIsOpenA] = useState(false); + const [isOpenB, setIsOpenB] = useState(false); + const [isOpenC, setIsOpenC] = useState(false); + + return ( + + + + + setIsOpenA(true)} /> + + setIsOpenA(false)} + opened={isOpenA} + placement={placement} + offset={[offsetX, offsetY]} + hasBody + {...rest} + > + + + setIsOpenB(true)} /> + + setIsOpenB(false)} + opened={isOpenB} + placement="left" + offset={[offsetX, offsetY]} + hasBody + {...rest} + > + + + setIsOpenC(true)} /> + + setIsOpenC(false)} + opened={isOpenC} + placement="top" + offset={[offsetX, offsetY]} + hasBody + {...rest} + > + + <>Content + + + + + + + ); +}; + +const StoryCustomModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProps) => { + const [isOpenA, setIsOpenA] = useState(false); + const [isOpenB, setIsOpenB] = useState(false); + const [isOpenC, setIsOpenC] = useState(false); return ( -
+ setIsOpenA(true)} /> -
+ setIsOpenA(false)} opened={isOpenA} @@ -119,11 +225,12 @@ const StoryModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProp > -
+ setIsOpenB(true)} /> -
+ setIsOpenB(false)} opened={isOpenB} placement="left" @@ -134,11 +241,12 @@ const StoryModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProp -
+ setIsOpenC(true)} /> -
+ setIsOpenC(false)} opened={isOpenC} placement="top" @@ -162,7 +270,7 @@ const StoryModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProp ); }; -export const ModalDemo: StoryObj = { +export const Default: StoryObj = { args: { placement: 'center', withBlur: false, @@ -170,10 +278,30 @@ export const ModalDemo: StoryObj = { closeOnOverlayClick: true, offsetX: 0, offsetY: 0, + hasClose: true, + }, + argTypes: { + hasClose: { + control: { + type: 'boolean', + }, + }, }, render: (args) => , }; +export const CustomModalDemo: StoryObj = { + args: { + placement: 'center', + withBlur: false, + closeOnEsc: true, + closeOnOverlayClick: true, + offsetX: 0, + offsetY: 0, + }, + render: (args) => , +}; + const StyledModalAnimation = styled(Modal)` /* stylelint-disable */ ${({ placement }) => diff --git a/packages/sdds-insol/src/components/Modal/Modal.config.ts b/packages/sdds-insol/src/components/Modal/Modal.config.ts index edc1be758d..8b107b98ea 100644 --- a/packages/sdds-insol/src/components/Modal/Modal.config.ts +++ b/packages/sdds-insol/src/components/Modal/Modal.config.ts @@ -9,6 +9,15 @@ export const config = { default: css` ${modalTokens.modalOverlayWithBlurColor}: rgba(35, 35, 35, 0.2); ${modalTokens.modalOverlayColor}: var(--overlay-soft); + ${modalTokens.modalBodyBackground}: var(--surface-solid-card); + ${modalTokens.modalBodyBorderRadius}: 1.25rem; + ${modalTokens.modalBodyPadding}: 2rem; + ${modalTokens.modalContentPadding}: 0.625rem; + ${modalTokens.modalCloseButtonRadius}: 0.375rem; + ${modalTokens.modalCloseButtonColor}: var(--text-secondary); + ${modalTokens.modalCloseButtonHoverColor}: var(--text-secondary-hover); + ${modalTokens.modalCloseButtonActiveColor}: var(--text-secondary-active); + ${modalTokens.modalOutlineFocusColor}: var(--surface-accent); `, }, }, diff --git a/packages/sdds-insol/src/components/Modal/Modal.stories.tsx b/packages/sdds-insol/src/components/Modal/Modal.stories.tsx index e6fc6db601..ed100b6801 100644 --- a/packages/sdds-insol/src/components/Modal/Modal.stories.tsx +++ b/packages/sdds-insol/src/components/Modal/Modal.stories.tsx @@ -1,7 +1,8 @@ import React, { useCallback, useRef, useState } from 'react'; -import styled, { css } from 'styled-components'; +import type { ComponentProps } from 'react'; +import styled from 'styled-components'; import type { Meta, StoryObj } from '@storybook/react'; -import { InSpacingDecorator } from '@salutejs/plasma-sb-utils'; +import { InSpacingDecorator, disableProps } from '@salutejs/plasma-sb-utils'; import { SSRProvider } from '../SSRProvider'; import { Button } from '../Button'; @@ -18,6 +19,7 @@ const meta: Meta = { docs: { story: { inline: false, iframeHeight: '30rem' } }, }, argTypes: { + ...disableProps(['hasBody']), placement: { options: [ 'center', @@ -33,19 +35,51 @@ const meta: Meta = { control: { type: 'select', }, + table: { defaultValue: { summary: 'center' } }, + }, + offsetX: { + control: { + type: 'number', + }, + table: { defaultValue: { summary: 0 } }, + }, + offsetY: { + control: { + type: 'number', + }, + table: { defaultValue: { summary: 0 } }, + }, + closeOnEsc: { + control: { + type: 'boolean', + }, + table: { defaultValue: { summary: true } }, + }, + closeOnOverlayClick: { + control: { + type: 'boolean', + }, + table: { defaultValue: { summary: true } }, + }, + withBlur: { + control: { + type: 'boolean', + }, + table: { defaultValue: { summary: false } }, }, }, -}; +} as Meta; export default meta; -type StoryModalProps = { +type StoryModalProps = ComponentProps & { placement: string; offsetX: number; offsetY: number; closeOnEsc: boolean; closeOnOverlayClick: boolean; withBlur: boolean; + hasClose?: boolean; }; const StyledButton = styled(Button)` @@ -62,6 +96,11 @@ const Content = styled.div` padding: 1rem; `; +const ButtonWrapper = styled.div` + display: flex; + flex-direction: column; +`; + const StyledModal = styled(Modal)` && > .${popupClasses.root}, .${modalClasses.overlay} { animation: fadeIn 1s forwards; @@ -97,19 +136,86 @@ const StyledModal = styled(Modal)` `; const StoryModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProps) => { - const [isOpenA, setIsOpenA] = React.useState(false); - const [isOpenB, setIsOpenB] = React.useState(false); - const [isOpenC, setIsOpenC] = React.useState(false); + const [isOpenA, setIsOpenA] = useState(false); + const [isOpenB, setIsOpenB] = useState(false); + const [isOpenC, setIsOpenC] = useState(false); + + return ( + + + + + setIsOpenA(true)} /> + + setIsOpenA(false)} + opened={isOpenA} + placement={placement} + offset={[offsetX, offsetY]} + hasBody + {...rest} + > + + + setIsOpenB(true)} /> + + setIsOpenB(false)} + opened={isOpenB} + placement="left" + offset={[offsetX, offsetY]} + hasBody + {...rest} + > + + + setIsOpenC(true)} /> + + setIsOpenC(false)} + opened={isOpenC} + placement="top" + offset={[offsetX, offsetY]} + hasBody + {...rest} + > + + <>Content + + + + + + + ); +}; + +const StoryCustomModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProps) => { + const [isOpenA, setIsOpenA] = useState(false); + const [isOpenB, setIsOpenB] = useState(false); + const [isOpenC, setIsOpenC] = useState(false); return ( -
+ setIsOpenA(true)} /> -
+ setIsOpenA(false)} opened={isOpenA} @@ -119,11 +225,12 @@ const StoryModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProp > -
+ setIsOpenB(true)} /> -
+ setIsOpenB(false)} opened={isOpenB} placement="left" @@ -134,11 +241,12 @@ const StoryModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProp -
+ setIsOpenC(true)} /> -
+ setIsOpenC(false)} opened={isOpenC} placement="top" @@ -162,7 +270,7 @@ const StoryModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProp ); }; -export const ModalDemo: StoryObj = { +export const Default: StoryObj = { args: { placement: 'center', withBlur: false, @@ -170,10 +278,30 @@ export const ModalDemo: StoryObj = { closeOnOverlayClick: true, offsetX: 0, offsetY: 0, + hasClose: true, + }, + argTypes: { + hasClose: { + control: { + type: 'boolean', + }, + }, }, render: (args) => , }; +export const CustomModalDemo: StoryObj = { + args: { + placement: 'center', + withBlur: false, + closeOnEsc: true, + closeOnOverlayClick: true, + offsetX: 0, + offsetY: 0, + }, + render: (args) => , +}; + const StyledModalAnimation = styled(Modal)` /* stylelint-disable */ ${({ placement }) => diff --git a/packages/sdds-serv/src/components/Modal/Modal.config.ts b/packages/sdds-serv/src/components/Modal/Modal.config.ts index edc1be758d..8b107b98ea 100644 --- a/packages/sdds-serv/src/components/Modal/Modal.config.ts +++ b/packages/sdds-serv/src/components/Modal/Modal.config.ts @@ -9,6 +9,15 @@ export const config = { default: css` ${modalTokens.modalOverlayWithBlurColor}: rgba(35, 35, 35, 0.2); ${modalTokens.modalOverlayColor}: var(--overlay-soft); + ${modalTokens.modalBodyBackground}: var(--surface-solid-card); + ${modalTokens.modalBodyBorderRadius}: 1.25rem; + ${modalTokens.modalBodyPadding}: 2rem; + ${modalTokens.modalContentPadding}: 0.625rem; + ${modalTokens.modalCloseButtonRadius}: 0.375rem; + ${modalTokens.modalCloseButtonColor}: var(--text-secondary); + ${modalTokens.modalCloseButtonHoverColor}: var(--text-secondary-hover); + ${modalTokens.modalCloseButtonActiveColor}: var(--text-secondary-active); + ${modalTokens.modalOutlineFocusColor}: var(--surface-accent); `, }, }, diff --git a/packages/sdds-serv/src/components/Modal/Modal.stories.tsx b/packages/sdds-serv/src/components/Modal/Modal.stories.tsx index e6fc6db601..ed100b6801 100644 --- a/packages/sdds-serv/src/components/Modal/Modal.stories.tsx +++ b/packages/sdds-serv/src/components/Modal/Modal.stories.tsx @@ -1,7 +1,8 @@ import React, { useCallback, useRef, useState } from 'react'; -import styled, { css } from 'styled-components'; +import type { ComponentProps } from 'react'; +import styled from 'styled-components'; import type { Meta, StoryObj } from '@storybook/react'; -import { InSpacingDecorator } from '@salutejs/plasma-sb-utils'; +import { InSpacingDecorator, disableProps } from '@salutejs/plasma-sb-utils'; import { SSRProvider } from '../SSRProvider'; import { Button } from '../Button'; @@ -18,6 +19,7 @@ const meta: Meta = { docs: { story: { inline: false, iframeHeight: '30rem' } }, }, argTypes: { + ...disableProps(['hasBody']), placement: { options: [ 'center', @@ -33,19 +35,51 @@ const meta: Meta = { control: { type: 'select', }, + table: { defaultValue: { summary: 'center' } }, + }, + offsetX: { + control: { + type: 'number', + }, + table: { defaultValue: { summary: 0 } }, + }, + offsetY: { + control: { + type: 'number', + }, + table: { defaultValue: { summary: 0 } }, + }, + closeOnEsc: { + control: { + type: 'boolean', + }, + table: { defaultValue: { summary: true } }, + }, + closeOnOverlayClick: { + control: { + type: 'boolean', + }, + table: { defaultValue: { summary: true } }, + }, + withBlur: { + control: { + type: 'boolean', + }, + table: { defaultValue: { summary: false } }, }, }, -}; +} as Meta; export default meta; -type StoryModalProps = { +type StoryModalProps = ComponentProps & { placement: string; offsetX: number; offsetY: number; closeOnEsc: boolean; closeOnOverlayClick: boolean; withBlur: boolean; + hasClose?: boolean; }; const StyledButton = styled(Button)` @@ -62,6 +96,11 @@ const Content = styled.div` padding: 1rem; `; +const ButtonWrapper = styled.div` + display: flex; + flex-direction: column; +`; + const StyledModal = styled(Modal)` && > .${popupClasses.root}, .${modalClasses.overlay} { animation: fadeIn 1s forwards; @@ -97,19 +136,86 @@ const StyledModal = styled(Modal)` `; const StoryModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProps) => { - const [isOpenA, setIsOpenA] = React.useState(false); - const [isOpenB, setIsOpenB] = React.useState(false); - const [isOpenC, setIsOpenC] = React.useState(false); + const [isOpenA, setIsOpenA] = useState(false); + const [isOpenB, setIsOpenB] = useState(false); + const [isOpenC, setIsOpenC] = useState(false); + + return ( + + + + + setIsOpenA(true)} /> + + setIsOpenA(false)} + opened={isOpenA} + placement={placement} + offset={[offsetX, offsetY]} + hasBody + {...rest} + > + + + setIsOpenB(true)} /> + + setIsOpenB(false)} + opened={isOpenB} + placement="left" + offset={[offsetX, offsetY]} + hasBody + {...rest} + > + + + setIsOpenC(true)} /> + + setIsOpenC(false)} + opened={isOpenC} + placement="top" + offset={[offsetX, offsetY]} + hasBody + {...rest} + > + + <>Content + + + + + + + ); +}; + +const StoryCustomModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProps) => { + const [isOpenA, setIsOpenA] = useState(false); + const [isOpenB, setIsOpenB] = useState(false); + const [isOpenC, setIsOpenC] = useState(false); return ( -
+ setIsOpenA(true)} /> -
+ setIsOpenA(false)} opened={isOpenA} @@ -119,11 +225,12 @@ const StoryModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProp > -
+ setIsOpenB(true)} /> -
+ setIsOpenB(false)} opened={isOpenB} placement="left" @@ -134,11 +241,12 @@ const StoryModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProp -
+ setIsOpenC(true)} /> -
+ setIsOpenC(false)} opened={isOpenC} placement="top" @@ -162,7 +270,7 @@ const StoryModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProp ); }; -export const ModalDemo: StoryObj = { +export const Default: StoryObj = { args: { placement: 'center', withBlur: false, @@ -170,10 +278,30 @@ export const ModalDemo: StoryObj = { closeOnOverlayClick: true, offsetX: 0, offsetY: 0, + hasClose: true, + }, + argTypes: { + hasClose: { + control: { + type: 'boolean', + }, + }, }, render: (args) => , }; +export const CustomModalDemo: StoryObj = { + args: { + placement: 'center', + withBlur: false, + closeOnEsc: true, + closeOnOverlayClick: true, + offsetX: 0, + offsetY: 0, + }, + render: (args) => , +}; + const StyledModalAnimation = styled(Modal)` /* stylelint-disable */ ${({ placement }) => diff --git a/website/plasma-b2c-docs/docs/components/ModalBase.mdx b/website/plasma-b2c-docs/docs/components/ModalBase.mdx index 451330fee1..b639da89be 100644 --- a/website/plasma-b2c-docs/docs/components/ModalBase.mdx +++ b/website/plasma-b2c-docs/docs/components/ModalBase.mdx @@ -63,6 +63,53 @@ export function App() { } ``` +## Использование стилизованной обертки + +Для использования стилизованного модального окна с отступами и крестиком для закрытия, добавьте свойство `hasBody`. +```tsx live +import React, { useState } from 'react'; +import { SSRProvider, Button, Modal, PopupProvider } from '@salutejs/plasma-b2c'; + +export function App() { + const [isOpenA, setIsOpenA] = useState(false); + const [isOpenB, setIsOpenB] = useState(false); + + return ( + + +
+
+
+ setIsOpenA(false)} + opened={isOpenA} + placement="center" + offset={[0, 0]} + hasBody + > + + + Content + + +
+
+
+ ); +} +``` + ## Подключение анимации Подключение анимации аналогично тому, как это происходит в `PopupBase` - через свойство `withAnimation`(управление через `popupBaseClasses`, `modalBaseClasses`). diff --git a/website/plasma-web-docs/docs/components/ModalBase.mdx b/website/plasma-web-docs/docs/components/ModalBase.mdx index bc021b00a2..d02f8d87a0 100644 --- a/website/plasma-web-docs/docs/components/ModalBase.mdx +++ b/website/plasma-web-docs/docs/components/ModalBase.mdx @@ -65,6 +65,53 @@ export function App() { } ``` +## Использование стилизованной обертки + +Для использования стилизованного модального окна с отступами и крестиком для закрытия, добавьте свойство `hasBody`. +```tsx live +import React, { useState } from 'react'; +import { SSRProvider, Button, Modal, PopupProvider } from '@salutejs/plasma-web'; + +export function App() { + const [isOpenA, setIsOpenA] = useState(false); + const [isOpenB, setIsOpenB] = useState(false); + + return ( + + +
+
+
+ setIsOpenA(false)} + opened={isOpenA} + placement="center" + offset={[0, 0]} + hasBody + > + + + Content + + +
+
+
+ ); +} +``` + ## Подключение анимации Подключение анимации аналогично тому, как это происходит в `PopupBase` - через свойство `withAnimation`(управление через `popupBaseClasses`, `modalBaseClasses`). diff --git a/website/sdds-cs-docs/docs/components/Modal.mdx b/website/sdds-cs-docs/docs/components/Modal.mdx index 38110b9f8b..a41d52e407 100644 --- a/website/sdds-cs-docs/docs/components/Modal.mdx +++ b/website/sdds-cs-docs/docs/components/Modal.mdx @@ -62,6 +62,53 @@ export function App() { } ``` +## Использование стилизованной обертки + +Для использования стилизованного модального окна с отступами и крестиком для закрытия, добавьте свойство `hasBody`. +```tsx live +import React, { useState } from 'react'; +import { SSRProvider, Button, Modal, PopupProvider } from '@salutejs/sdds-cs'; + +export function App() { + const [isOpenA, setIsOpenA] = useState(false); + const [isOpenB, setIsOpenB] = useState(false); + + return ( + + +
+
+
+ setIsOpenA(false)} + opened={isOpenA} + placement="center" + offset={[0, 0]} + hasBody + > + + + Content + + +
+
+
+ ); +} +``` + ## Подключение анимации Подключение анимации аналогично тому, как это происходит в `Popup` - через свойство `withAnimation`(управление через `popupClasses`, `modalClasses`). Для добавления анимации в оверлей необходимо использовать класс `.modal-overlay` через переменную `modalClasses.overlay` из пакета. diff --git a/website/sdds-dfa-docs/docs/components/Modal.mdx b/website/sdds-dfa-docs/docs/components/Modal.mdx index edb612075e..c6f4d4450a 100644 --- a/website/sdds-dfa-docs/docs/components/Modal.mdx +++ b/website/sdds-dfa-docs/docs/components/Modal.mdx @@ -62,6 +62,53 @@ export function App() { } ``` +## Использование стилизованной обертки + +Для использования стилизованного модального окна с отступами и крестиком для закрытия, добавьте свойство `hasBody`. +```tsx live +import React, { useState } from 'react'; +import { SSRProvider, Button, Modal, PopupProvider } from '@salutejs/sdds-dfa'; + +export function App() { + const [isOpenA, setIsOpenA] = useState(false); + const [isOpenB, setIsOpenB] = useState(false); + + return ( + + +
+
+
+ setIsOpenA(false)} + opened={isOpenA} + placement="center" + offset={[0, 0]} + hasBody + > + + + Content + + +
+
+
+ ); +} +``` + ## Подключение анимации Подключение анимации аналогично тому, как это происходит в `Popup` - через свойство `withAnimation`(управление через `popupClasses`, `modalClasses`). Для добавления анимации в оверлей необходимо использовать класс `.modal-overlay` через переменную `modalClasses.overlay` из пакета. diff --git a/website/sdds-insol-docs/docs/components/Modal.mdx b/website/sdds-insol-docs/docs/components/Modal.mdx index f43d6176b7..cd595cb94c 100644 --- a/website/sdds-insol-docs/docs/components/Modal.mdx +++ b/website/sdds-insol-docs/docs/components/Modal.mdx @@ -62,6 +62,53 @@ export function App() { } ``` +## Использование стилизованной обертки + +Для использования стилизованного модального окна с отступами и крестиком для закрытия, добавьте свойство `hasBody`. +```tsx live +import React, { useState } from 'react'; +import { SSRProvider, Button, Modal, PopupProvider } from '@salutejs/sdds-insol'; + +export function App() { + const [isOpenA, setIsOpenA] = useState(false); + const [isOpenB, setIsOpenB] = useState(false); + + return ( + + +
+
+
+ setIsOpenA(false)} + opened={isOpenA} + placement="center" + offset={[0, 0]} + hasBody + > + + + Content + + +
+
+
+ ); +} +``` + ## Подключение анимации Подключение анимации аналогично тому, как это происходит в `Popup` - через свойство `withAnimation`(управление через `popupClasses`, `modalClasses`). Для добавления анимации в оверлей необходимо использовать класс `.modal-overlay` через переменную `modalClasses.overlay` из пакета. diff --git a/website/sdds-serv-docs/docs/components/Modal.mdx b/website/sdds-serv-docs/docs/components/Modal.mdx index f4bd108dde..b88ba3d779 100644 --- a/website/sdds-serv-docs/docs/components/Modal.mdx +++ b/website/sdds-serv-docs/docs/components/Modal.mdx @@ -62,6 +62,53 @@ export function App() { } ``` +## Использование стилизованной обертки + +Для использования стилизованного модального окна с отступами и крестиком для закрытия, добавьте свойство `hasBody`. +```tsx live +import React, { useState } from 'react'; +import { SSRProvider, Button, Modal, PopupProvider } from '@salutejs/sdds-serv'; + +export function App() { + const [isOpenA, setIsOpenA] = useState(false); + const [isOpenB, setIsOpenB] = useState(false); + + return ( + + +
+
+
+ setIsOpenA(false)} + opened={isOpenA} + placement="center" + offset={[0, 0]} + hasBody + > + + + Content + + +
+
+
+ ); +} +``` + ## Подключение анимации Подключение анимации аналогично тому, как это происходит в `Popup` - через свойство `withAnimation`(управление через `popupClasses`, `modalClasses`). Для добавления анимации в оверлей необходимо использовать класс `.modal-overlay` через переменную `modalClasses.overlay` из пакета.