@salutejs/plasma-new-hope 0.193.0 → 0.194.0-canary.1558.11852073996.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. package/cjs/components/Modal/Modal.css +6 -0
  2. package/cjs/components/Modal/Modal.js +27 -13
  3. package/cjs/components/Modal/Modal.js.map +1 -1
  4. package/cjs/components/Modal/Modal.styles.js +27 -0
  5. package/cjs/components/Modal/Modal.styles.js.map +1 -0
  6. package/cjs/components/Modal/Modal.styles_tqsxxy.css +3 -0
  7. package/cjs/components/Modal/Modal.tokens.js +7 -1
  8. package/cjs/components/Modal/Modal.tokens.js.map +1 -1
  9. package/cjs/index.css +4 -0
  10. package/emotion/cjs/components/Modal/Modal.js +26 -12
  11. package/emotion/cjs/components/Modal/Modal.styles.js +27 -0
  12. package/emotion/cjs/components/Modal/Modal.template-doc.mdx +47 -0
  13. package/emotion/cjs/components/Modal/Modal.tokens.js +7 -1
  14. package/emotion/cjs/examples/plasma_b2c/components/Modal/Modal.config.js +1 -1
  15. package/emotion/cjs/examples/plasma_b2c/components/Modal/Modal.stories.tsx +90 -1
  16. package/emotion/cjs/examples/plasma_web/components/Modal/Modal.config.js +1 -1
  17. package/emotion/cjs/examples/plasma_web/components/Modal/Modal.stories.tsx +90 -1
  18. package/emotion/es/components/Modal/Modal.js +26 -12
  19. package/emotion/es/components/Modal/Modal.styles.js +20 -0
  20. package/emotion/es/components/Modal/Modal.template-doc.mdx +47 -0
  21. package/emotion/es/components/Modal/Modal.tokens.js +7 -1
  22. package/emotion/es/examples/plasma_b2c/components/Modal/Modal.config.js +1 -1
  23. package/emotion/es/examples/plasma_b2c/components/Modal/Modal.stories.tsx +90 -1
  24. package/emotion/es/examples/plasma_web/components/Modal/Modal.config.js +1 -1
  25. package/emotion/es/examples/plasma_web/components/Modal/Modal.stories.tsx +90 -1
  26. package/es/components/Modal/Modal.css +6 -0
  27. package/es/components/Modal/Modal.js +27 -13
  28. package/es/components/Modal/Modal.js.map +1 -1
  29. package/es/components/Modal/Modal.styles.js +21 -0
  30. package/es/components/Modal/Modal.styles.js.map +1 -0
  31. package/es/components/Modal/Modal.styles_tqsxxy.css +3 -0
  32. package/es/components/Modal/Modal.tokens.js +7 -1
  33. package/es/components/Modal/Modal.tokens.js.map +1 -1
  34. package/es/index.css +4 -0
  35. package/package.json +2 -2
  36. package/styled-components/cjs/components/Modal/Modal.js +26 -12
  37. package/styled-components/cjs/components/Modal/Modal.styles.js +24 -0
  38. package/styled-components/cjs/components/Modal/Modal.template-doc.mdx +47 -0
  39. package/styled-components/cjs/components/Modal/Modal.tokens.js +7 -1
  40. package/styled-components/cjs/examples/plasma_b2c/components/Modal/Modal.config.js +1 -1
  41. package/styled-components/cjs/examples/plasma_b2c/components/Modal/Modal.stories.tsx +90 -1
  42. package/styled-components/cjs/examples/plasma_web/components/Modal/Modal.config.js +1 -1
  43. package/styled-components/cjs/examples/plasma_web/components/Modal/Modal.stories.tsx +90 -1
  44. package/styled-components/es/components/Modal/Modal.js +26 -12
  45. package/styled-components/es/components/Modal/Modal.styles.js +17 -0
  46. package/styled-components/es/components/Modal/Modal.template-doc.mdx +47 -0
  47. package/styled-components/es/components/Modal/Modal.tokens.js +7 -1
  48. package/styled-components/es/examples/plasma_b2c/components/Modal/Modal.config.js +1 -1
  49. package/styled-components/es/examples/plasma_b2c/components/Modal/Modal.stories.tsx +90 -1
  50. package/styled-components/es/examples/plasma_web/components/Modal/Modal.config.js +1 -1
  51. package/styled-components/es/examples/plasma_web/components/Modal/Modal.stories.tsx +90 -1
  52. package/types/components/Modal/Modal.d.ts.map +1 -1
  53. package/types/components/Modal/Modal.styles.d.ts +5 -0
  54. package/types/components/Modal/Modal.styles.d.ts.map +1 -0
  55. package/types/components/Modal/Modal.tokens.d.ts +6 -0
  56. package/types/components/Modal/Modal.tokens.d.ts.map +1 -1
  57. package/types/components/Modal/Modal.types.d.ts +21 -1
  58. package/types/components/Modal/Modal.types.d.ts.map +1 -1
  59. package/types/components/Modal/index.d.ts +1 -1
  60. package/types/components/Modal/index.d.ts.map +1 -1
  61. package/types/examples/plasma_b2c/components/Modal/Modal.config.d.ts.map +1 -1
  62. package/types/examples/plasma_b2c/components/Modal/Modal.d.ts +7 -1
  63. package/types/examples/plasma_b2c/components/Modal/Modal.d.ts.map +1 -1
  64. package/types/examples/plasma_web/components/Modal/Modal.config.d.ts.map +1 -1
  65. package/types/examples/plasma_web/components/Modal/Modal.d.ts +7 -1
  66. package/types/examples/plasma_web/components/Modal/Modal.d.ts.map +1 -1
@@ -3,6 +3,7 @@ import styled from '@emotion/styled';
3
3
  import type { ComponentProps } from 'react';
4
4
  import type { StoryObj, Meta } from '@storybook/react';
5
5
  import { SSRProvider } from '@salutejs/plasma-core';
6
+ import { disableProps } from '@salutejs/plasma-sb-utils';
6
7
 
7
8
  import { PopupProvider, popupClasses } from '../Popup/Popup';
8
9
  import { Button } from '../Button/Button';
@@ -18,6 +19,7 @@ export default {
18
19
  docs: { story: { inline: false, iframeHeight: '30rem' } },
19
20
  },
20
21
  argTypes: {
22
+ ...disableProps(['hasBody']),
21
23
  placement: {
22
24
  options: [
23
25
  'center',
@@ -75,6 +77,7 @@ type StoryModalProps = ComponentProps<typeof Modal> & {
75
77
  closeOnEsc: boolean;
76
78
  closeOnOverlayClick: boolean;
77
79
  withBlur: boolean;
80
+ hasClose?: boolean;
78
81
  };
79
82
 
80
83
  const StyledButton = styled(Button)`
@@ -135,6 +138,72 @@ const StoryModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProp
135
138
  const [isOpenB, setIsOpenB] = useState(false);
136
139
  const [isOpenC, setIsOpenC] = useState(false);
137
140
 
141
+ return (
142
+ <SSRProvider>
143
+ <StyledWrapper>
144
+ <PopupProvider>
145
+ <ButtonWrapper>
146
+ <StyledButton text="Открыть A" onClick={() => setIsOpenA(true)} />
147
+ </ButtonWrapper>
148
+ <StyledModal
149
+ id="modalA"
150
+ frame="theme-root"
151
+ withAnimation
152
+ onClose={() => setIsOpenA(false)}
153
+ opened={isOpenA}
154
+ placement={placement}
155
+ offset={[offsetX, offsetY]}
156
+ hasBody
157
+ {...rest}
158
+ >
159
+ <Button onClick={() => setIsOpenA(false)}>Close</Button>
160
+ <ButtonWrapper>
161
+ <StyledButton text="Открыть B" onClick={() => setIsOpenB(true)} />
162
+ </ButtonWrapper>
163
+ <Modal
164
+ id="modalB"
165
+ frame="theme-root"
166
+ onClose={() => setIsOpenB(false)}
167
+ opened={isOpenB}
168
+ placement="left"
169
+ offset={[offsetX, offsetY]}
170
+ hasBody
171
+ {...rest}
172
+ >
173
+ <Button style={{ marginRight: '1rem' }} onClick={() => setIsOpenB(false)}>
174
+ Close
175
+ </Button>
176
+ <ButtonWrapper>
177
+ <StyledButton text="Открыть C" onClick={() => setIsOpenC(true)} />
178
+ </ButtonWrapper>
179
+ <Modal
180
+ id="modalC"
181
+ frame="theme-root"
182
+ onClose={() => setIsOpenC(false)}
183
+ opened={isOpenC}
184
+ placement="top"
185
+ offset={[offsetX, offsetY]}
186
+ hasBody
187
+ {...rest}
188
+ >
189
+ <Button style={{ marginRight: '1rem' }} onClick={() => setIsOpenC(false)}>
190
+ Close
191
+ </Button>
192
+ <>Content</>
193
+ </Modal>
194
+ </Modal>
195
+ </StyledModal>
196
+ </PopupProvider>
197
+ </StyledWrapper>
198
+ </SSRProvider>
199
+ );
200
+ };
201
+
202
+ const StoryCustomModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProps) => {
203
+ const [isOpenA, setIsOpenA] = useState(false);
204
+ const [isOpenB, setIsOpenB] = useState(false);
205
+ const [isOpenC, setIsOpenC] = useState(false);
206
+
138
207
  return (
139
208
  <SSRProvider>
140
209
  <StyledWrapper>
@@ -199,7 +268,7 @@ const StoryModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProp
199
268
  );
200
269
  };
201
270
 
202
- export const ModalDemo: StoryObj<StoryModalProps> = {
271
+ export const Default: StoryObj<StoryModalProps> = {
203
272
  args: {
204
273
  placement: 'center',
205
274
  withBlur: false,
@@ -207,10 +276,30 @@ export const ModalDemo: StoryObj<StoryModalProps> = {
207
276
  closeOnOverlayClick: true,
208
277
  offsetX: 0,
209
278
  offsetY: 0,
279
+ hasClose: true,
280
+ },
281
+ argTypes: {
282
+ hasClose: {
283
+ control: {
284
+ type: 'boolean',
285
+ },
286
+ },
210
287
  },
211
288
  render: (args) => <StoryModalDemo {...args} />,
212
289
  };
213
290
 
291
+ export const CustomModalDemo: StoryObj<StoryModalProps> = {
292
+ args: {
293
+ placement: 'center',
294
+ withBlur: false,
295
+ closeOnEsc: true,
296
+ closeOnOverlayClick: true,
297
+ offsetX: 0,
298
+ offsetY: 0,
299
+ },
300
+ render: (args) => <StoryCustomModalDemo {...args} />,
301
+ };
302
+
214
303
  const StyledModalAnimation = styled(Modal)`
215
304
  /* stylelint-disable */
216
305
  && .${popupClasses.root} {
@@ -1,4 +1,5 @@
1
- var _excluded = ["id", "withAnimation", "onClose", "onOverlayClick", "onEscKeyDown", "closeOnEsc", "closeOnOverlayClick", "withBlur", "initialFocusRef", "focusAfterRef", "zIndex", "popupInfo", "children", "view", "opened", "isOpen"];
1
+ var _IconClose;
2
+ var _excluded = ["id", "withAnimation", "onClose", "onOverlayClick", "onEscKeyDown", "closeOnEsc", "closeOnOverlayClick", "withBlur", "initialFocusRef", "focusAfterRef", "zIndex", "popupInfo", "children", "view", "opened", "isOpen", "hasBody", "hasClose"];
2
3
  function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
3
4
  function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
4
5
  function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
@@ -9,10 +10,12 @@ import { popupConfig, usePopupContext } from '../Popup';
9
10
  import { Overlay } from '../Overlay';
10
11
  import { DEFAULT_Z_INDEX } from '../Popup/utils';
11
12
  import { useFocusTrap } from '../../hooks';
13
+ import { IconClose } from '../_Icon/Icons/IconClose';
12
14
  import { classes, tokens } from './Modal.tokens';
13
15
  import { useModal } from './hooks';
14
16
  import { base as viewCSS } from './variations/_view/base';
15
17
  import { getIdLastModal } from './ModalContext';
18
+ import { CloseButton, ModalBody, ModalContent } from './Modal.styles';
16
19
 
17
20
  // issue #823
18
21
  var Popup = /*#__PURE__*/component(popupConfig);
@@ -41,8 +44,11 @@ export var modalRoot = function modalRoot(Root) {
41
44
  view = _ref.view,
42
45
  opened = _ref.opened,
43
46
  isOpen = _ref.isOpen,
47
+ hasBody = _ref.hasBody,
48
+ hasClose = _ref.hasClose,
44
49
  rest = _objectWithoutProperties(_ref, _excluded);
45
50
  var innerIsOpen = Boolean(isOpen || opened);
51
+ var innerHasClose = hasClose === undefined && hasBody || hasClose;
46
52
  var trapRef = useFocusTrap(true, initialFocusRef, focusAfterRef, true);
47
53
  var popupController = usePopupContext();
48
54
  var innerRef = useForkRef(trapRef, outerRootRef);
@@ -70,6 +76,15 @@ export var modalRoot = function modalRoot(Root) {
70
76
  onClose();
71
77
  }
72
78
  }, [closeOnOverlayClick, onOverlayClick, onClose]);
79
+ var overlayNode = /*#__PURE__*/React.createElement(Overlay, {
80
+ className: classes.overlay,
81
+ zIndex: zIndex || DEFAULT_Z_INDEX,
82
+ backgroundColorProperty: overlayBackgroundToken,
83
+ withBlur: withBlur,
84
+ transparent: transparent,
85
+ isClickable: closeOnOverlayClick,
86
+ onOverlayClick: onModalOverlayKeyDown
87
+ });
73
88
  return /*#__PURE__*/React.createElement(Popup, _extends({
74
89
  id: innerId,
75
90
  opened: innerIsOpen,
@@ -77,18 +92,17 @@ export var modalRoot = function modalRoot(Root) {
77
92
  popupInfo: modalInfo,
78
93
  withAnimation: withAnimation,
79
94
  zIndex: zIndex,
80
- overlay: /*#__PURE__*/React.createElement(Root, {
95
+ overlay: hasBody ? overlayNode : /*#__PURE__*/React.createElement(Root, {
81
96
  view: view
82
- }, /*#__PURE__*/React.createElement(Overlay, {
83
- className: classes.overlay,
84
- zIndex: zIndex || DEFAULT_Z_INDEX,
85
- backgroundColorProperty: overlayBackgroundToken,
86
- withBlur: withBlur,
87
- transparent: transparent,
88
- isClickable: closeOnOverlayClick,
89
- onOverlayClick: onModalOverlayKeyDown
90
- }))
91
- }, rest), children);
97
+ }, overlayNode)
98
+ }, rest), hasBody ? /*#__PURE__*/React.createElement(Root, {
99
+ view: view
100
+ }, /*#__PURE__*/React.createElement(ModalBody, null, /*#__PURE__*/React.createElement(ModalContent, null, innerHasClose && /*#__PURE__*/React.createElement(CloseButton, {
101
+ onClick: onClose,
102
+ "data-test": "modal-close"
103
+ }, _IconClose || (_IconClose = /*#__PURE__*/React.createElement(IconClose, {
104
+ size: "s"
105
+ }))), children))) : /*#__PURE__*/React.createElement(React.Fragment, null, children));
92
106
  });
93
107
  };
94
108
  export var modalConfig = {
@@ -0,0 +1,20 @@
1
+ import _styled from "@emotion/styled/base";
2
+ import { addFocus } from '../../mixins';
3
+ import { tokens } from './Modal.tokens';
4
+ export var ModalBody = /*#__PURE__*/_styled("div", {
5
+ target: "e1gvpqag2",
6
+ label: "plasma-new-hope__ModalBody"
7
+ })("border-radius:var(", tokens.modalBodyBorderRadius, ");padding:var(", tokens.modalBodyPadding, ");background:var(", tokens.modalBodyBackground, ");box-shadow:var(--shadow-down-soft-l);" + (process.env.NODE_ENV === "production" ? "" : "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy1lbW90aW9uL2NvbXBvbmVudHMvTW9kYWwvTW9kYWwuc3R5bGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQU1tQyIsImZpbGUiOiIuLi8uLi8uLi8uLi9zcmMtZW1vdGlvbi9jb21wb25lbnRzL01vZGFsL01vZGFsLnN0eWxlcy50cyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBzdHlsZWQgZnJvbSAnQGVtb3Rpb24vc3R5bGVkJztcblxuaW1wb3J0IHsgYWRkRm9jdXMgfSBmcm9tICcuLi8uLi9taXhpbnMnO1xuXG5pbXBvcnQgeyB0b2tlbnMgfSBmcm9tICcuL01vZGFsLnRva2Vucyc7XG5cbmV4cG9ydCBjb25zdCBNb2RhbEJvZHkgPSBzdHlsZWQuZGl2YFxuICAgIGJvcmRlci1yYWRpdXM6IHZhcigke3Rva2Vucy5tb2RhbEJvZHlCb3JkZXJSYWRpdXN9KTtcbiAgICBwYWRkaW5nOiB2YXIoJHt0b2tlbnMubW9kYWxCb2R5UGFkZGluZ30pO1xuICAgIGJhY2tncm91bmQ6IHZhcigke3Rva2Vucy5tb2RhbEJvZHlCYWNrZ3JvdW5kfSk7XG4gICAgYm94LXNoYWRvdzogdmFyKC0tc2hhZG93LWRvd24tc29mdC1sKTtcbmA7XG5cbmV4cG9ydCBjb25zdCBNb2RhbENvbnRlbnQgPSBzdHlsZWQuZGl2YFxuICAgIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgICBwYWRkaW5nOiB2YXIoJHt0b2tlbnMubW9kYWxDb250ZW50UGFkZGluZ30pO1xuYDtcblxuZXhwb3J0IGNvbnN0IENsb3NlQnV0dG9uID0gc3R5bGVkLmJ1dHRvbmBcbiAgICB0b3A6IDA7XG4gICAgcmlnaHQ6IDA7XG5cbiAgICB3aWR0aDogMS41cmVtO1xuICAgIGhlaWdodDogMS41cmVtO1xuXG4gICAgZGlzcGxheTogZmxleDtcbiAgICBhbGlnbi1pdGVtczogY2VudGVyO1xuICAgIGp1c3RpZnktY29udGVudDogY2VudGVyO1xuXG4gICAgYm9yZGVyOiBub25lO1xuICAgIGJvcmRlci1yYWRpdXM6IHZhcigke3Rva2Vucy5tb2RhbENsb3NlQnV0dG9uUmFkaXVzfSk7XG5cbiAgICBwYWRkaW5nOiAwO1xuICAgIG1hcmdpbjogMDtcbiAgICBvdXRsaW5lOiBub25lO1xuXG4gICAgY3Vyc29yOiBwb2ludGVyO1xuXG4gICAgYmFja2dyb3VuZDogdHJhbnNwYXJlbnQ7XG5cbiAgICAke2FkZEZvY3VzKHtcbiAgICAgICAgb3V0bGluZVNpemU6ICcwLjA2M3JlbScsXG4gICAgICAgIG91dGxpbmVPZmZzZXQ6ICctMC4xMjVyZW0nLFxuICAgICAgICBvdXRsaW5lQ29sb3I6IGB2YXIoJHt0b2tlbnMubW9kYWxPdXRsaW5lRm9jdXNDb2xvcn0pYCxcbiAgICAgICAgb3V0bGluZVJhZGl1czogYGNhbGModmFyKCR7dG9rZW5zLm1vZGFsQ2xvc2VCdXR0b25SYWRpdXN9KSArIDAuMDYzcmVtKWAsXG4gICAgfSl9O1xuXG4gICAgcG9zaXRpb246IGFic29sdXRlO1xuYDtcbiJdfQ== */"));
8
+ export var ModalContent = /*#__PURE__*/_styled("div", {
9
+ target: "e1gvpqag1",
10
+ label: "plasma-new-hope__ModalContent"
11
+ })("position:relative;padding:var(", tokens.modalContentPadding, ");" + (process.env.NODE_ENV === "production" ? "" : "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy1lbW90aW9uL2NvbXBvbmVudHMvTW9kYWwvTW9kYWwuc3R5bGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQWFzQyIsImZpbGUiOiIuLi8uLi8uLi8uLi9zcmMtZW1vdGlvbi9jb21wb25lbnRzL01vZGFsL01vZGFsLnN0eWxlcy50cyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBzdHlsZWQgZnJvbSAnQGVtb3Rpb24vc3R5bGVkJztcblxuaW1wb3J0IHsgYWRkRm9jdXMgfSBmcm9tICcuLi8uLi9taXhpbnMnO1xuXG5pbXBvcnQgeyB0b2tlbnMgfSBmcm9tICcuL01vZGFsLnRva2Vucyc7XG5cbmV4cG9ydCBjb25zdCBNb2RhbEJvZHkgPSBzdHlsZWQuZGl2YFxuICAgIGJvcmRlci1yYWRpdXM6IHZhcigke3Rva2Vucy5tb2RhbEJvZHlCb3JkZXJSYWRpdXN9KTtcbiAgICBwYWRkaW5nOiB2YXIoJHt0b2tlbnMubW9kYWxCb2R5UGFkZGluZ30pO1xuICAgIGJhY2tncm91bmQ6IHZhcigke3Rva2Vucy5tb2RhbEJvZHlCYWNrZ3JvdW5kfSk7XG4gICAgYm94LXNoYWRvdzogdmFyKC0tc2hhZG93LWRvd24tc29mdC1sKTtcbmA7XG5cbmV4cG9ydCBjb25zdCBNb2RhbENvbnRlbnQgPSBzdHlsZWQuZGl2YFxuICAgIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgICBwYWRkaW5nOiB2YXIoJHt0b2tlbnMubW9kYWxDb250ZW50UGFkZGluZ30pO1xuYDtcblxuZXhwb3J0IGNvbnN0IENsb3NlQnV0dG9uID0gc3R5bGVkLmJ1dHRvbmBcbiAgICB0b3A6IDA7XG4gICAgcmlnaHQ6IDA7XG5cbiAgICB3aWR0aDogMS41cmVtO1xuICAgIGhlaWdodDogMS41cmVtO1xuXG4gICAgZGlzcGxheTogZmxleDtcbiAgICBhbGlnbi1pdGVtczogY2VudGVyO1xuICAgIGp1c3RpZnktY29udGVudDogY2VudGVyO1xuXG4gICAgYm9yZGVyOiBub25lO1xuICAgIGJvcmRlci1yYWRpdXM6IHZhcigke3Rva2Vucy5tb2RhbENsb3NlQnV0dG9uUmFkaXVzfSk7XG5cbiAgICBwYWRkaW5nOiAwO1xuICAgIG1hcmdpbjogMDtcbiAgICBvdXRsaW5lOiBub25lO1xuXG4gICAgY3Vyc29yOiBwb2ludGVyO1xuXG4gICAgYmFja2dyb3VuZDogdHJhbnNwYXJlbnQ7XG5cbiAgICAke2FkZEZvY3VzKHtcbiAgICAgICAgb3V0bGluZVNpemU6ICcwLjA2M3JlbScsXG4gICAgICAgIG91dGxpbmVPZmZzZXQ6ICctMC4xMjVyZW0nLFxuICAgICAgICBvdXRsaW5lQ29sb3I6IGB2YXIoJHt0b2tlbnMubW9kYWxPdXRsaW5lRm9jdXNDb2xvcn0pYCxcbiAgICAgICAgb3V0bGluZVJhZGl1czogYGNhbGModmFyKCR7dG9rZW5zLm1vZGFsQ2xvc2VCdXR0b25SYWRpdXN9KSArIDAuMDYzcmVtKWAsXG4gICAgfSl9O1xuXG4gICAgcG9zaXRpb246IGFic29sdXRlO1xuYDtcbiJdfQ== */"));
12
+ export var CloseButton = /*#__PURE__*/_styled("button", {
13
+ target: "e1gvpqag0",
14
+ label: "plasma-new-hope__CloseButton"
15
+ })("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;", /*#__PURE__*/addFocus({
16
+ outlineSize: '0.063rem',
17
+ outlineOffset: '-0.125rem',
18
+ outlineColor: /*#__PURE__*/"var(".concat(tokens.modalOutlineFocusColor, ")"),
19
+ outlineRadius: /*#__PURE__*/"calc(var(".concat(tokens.modalCloseButtonRadius, ") + 0.063rem)")
20
+ }), ";position:absolute;" + (process.env.NODE_ENV === "production" ? "" : "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy1lbW90aW9uL2NvbXBvbmVudHMvTW9kYWwvTW9kYWwuc3R5bGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQWtCd0MiLCJmaWxlIjoiLi4vLi4vLi4vLi4vc3JjLWVtb3Rpb24vY29tcG9uZW50cy9Nb2RhbC9Nb2RhbC5zdHlsZXMudHMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgc3R5bGVkIGZyb20gJ0BlbW90aW9uL3N0eWxlZCc7XG5cbmltcG9ydCB7IGFkZEZvY3VzIH0gZnJvbSAnLi4vLi4vbWl4aW5zJztcblxuaW1wb3J0IHsgdG9rZW5zIH0gZnJvbSAnLi9Nb2RhbC50b2tlbnMnO1xuXG5leHBvcnQgY29uc3QgTW9kYWxCb2R5ID0gc3R5bGVkLmRpdmBcbiAgICBib3JkZXItcmFkaXVzOiB2YXIoJHt0b2tlbnMubW9kYWxCb2R5Qm9yZGVyUmFkaXVzfSk7XG4gICAgcGFkZGluZzogdmFyKCR7dG9rZW5zLm1vZGFsQm9keVBhZGRpbmd9KTtcbiAgICBiYWNrZ3JvdW5kOiB2YXIoJHt0b2tlbnMubW9kYWxCb2R5QmFja2dyb3VuZH0pO1xuICAgIGJveC1zaGFkb3c6IHZhcigtLXNoYWRvdy1kb3duLXNvZnQtbCk7XG5gO1xuXG5leHBvcnQgY29uc3QgTW9kYWxDb250ZW50ID0gc3R5bGVkLmRpdmBcbiAgICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gICAgcGFkZGluZzogdmFyKCR7dG9rZW5zLm1vZGFsQ29udGVudFBhZGRpbmd9KTtcbmA7XG5cbmV4cG9ydCBjb25zdCBDbG9zZUJ1dHRvbiA9IHN0eWxlZC5idXR0b25gXG4gICAgdG9wOiAwO1xuICAgIHJpZ2h0OiAwO1xuXG4gICAgd2lkdGg6IDEuNXJlbTtcbiAgICBoZWlnaHQ6IDEuNXJlbTtcblxuICAgIGRpc3BsYXk6IGZsZXg7XG4gICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAgICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcblxuICAgIGJvcmRlcjogbm9uZTtcbiAgICBib3JkZXItcmFkaXVzOiB2YXIoJHt0b2tlbnMubW9kYWxDbG9zZUJ1dHRvblJhZGl1c30pO1xuXG4gICAgcGFkZGluZzogMDtcbiAgICBtYXJnaW46IDA7XG4gICAgb3V0bGluZTogbm9uZTtcblxuICAgIGN1cnNvcjogcG9pbnRlcjtcblxuICAgIGJhY2tncm91bmQ6IHRyYW5zcGFyZW50O1xuXG4gICAgJHthZGRGb2N1cyh7XG4gICAgICAgIG91dGxpbmVTaXplOiAnMC4wNjNyZW0nLFxuICAgICAgICBvdXRsaW5lT2Zmc2V0OiAnLTAuMTI1cmVtJyxcbiAgICAgICAgb3V0bGluZUNvbG9yOiBgdmFyKCR7dG9rZW5zLm1vZGFsT3V0bGluZUZvY3VzQ29sb3J9KWAsXG4gICAgICAgIG91dGxpbmVSYWRpdXM6IGBjYWxjKHZhcigke3Rva2Vucy5tb2RhbENsb3NlQnV0dG9uUmFkaXVzfSkgKyAwLjA2M3JlbSlgLFxuICAgIH0pfTtcblxuICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbmA7XG4iXX0= */"));
@@ -62,6 +62,53 @@ export function App() {
62
62
  }
63
63
  ```
64
64
 
65
+ ## Использование стилизованной обертки
66
+
67
+ Для использования стилизованного мобального окна с отступами и крестиком для закрытия, добавьте свойство `hasBody`.
68
+ ```tsx live
69
+ import React, { useState } from 'react';
70
+ import { SSRProvider, Button, Modal, PopupProvider } from '@salutejs/{{ package }}';
71
+
72
+ export function App() {
73
+ const [isOpenA, setIsOpenA] = useState(false);
74
+ const [isOpenB, setIsOpenB] = useState(false);
75
+
76
+ return (
77
+ <SSRProvider>
78
+ <PopupProvider>
79
+ <div style=\{{ height: "300px" }}>
80
+ <div style=\{{ display: 'flex', flexDirection: 'column' }}>
81
+ <Button text="Открыть A" onClick={() => setIsOpenA(true)} />
82
+ </div>
83
+ <Modal
84
+ id="modalA"
85
+ onClose={() => setIsOpenA(false)}
86
+ opened={isOpenA}
87
+ placement="center"
88
+ offset={[0, 0]}
89
+ hasBody
90
+ >
91
+ <Button onClick={() => setIsOpenA(false)}>Close</Button>
92
+ <Button text="Открыть B" onClick={() => setIsOpenB(true)} />
93
+ Content
94
+ <Modal
95
+ id="modalB"
96
+ onClose={() => setIsOpenB(false)}
97
+ opened={isOpenB}
98
+ placement="right"
99
+ offset={[0, 0]}
100
+ >
101
+ <Button onClick={() => setIsOpenB(false)}>Close</Button>
102
+ Content
103
+ </Modal>
104
+ </Modal>
105
+ </div>
106
+ </PopupProvider>
107
+ </SSRProvider>
108
+ );
109
+ }
110
+ ```
111
+
65
112
  ## Подключение анимации
66
113
  Подключение анимации аналогично тому, как это происходит в `Popup` - через свойство `withAnimation`(управление через `popupClasses`, `modalClasses`).
67
114
  Для добавления анимации в оверлей необходимо использовать класс `.modal-overlay` через переменную `modalClasses.overlay` из пакета.
@@ -6,5 +6,11 @@ export var classes = {
6
6
  };
7
7
  export var tokens = {
8
8
  modalOverlayWithBlurColor: '--plasma-modal-overlay-with-blur-color',
9
- modalOverlayColor: '--plasma-modal-overlay-color'
9
+ modalOverlayColor: '--plasma-modal-overlay-color',
10
+ modalBodyBackground: '--plasma-modal-body-background',
11
+ modalBodyBorderRadius: '--plasma-modal-body-border-radius',
12
+ modalBodyPadding: '--plasma-modal-body-padding',
13
+ modalContentPadding: '--plasma-modal-content-padding',
14
+ modalOutlineFocusColor: '--plasma-modal-outline-focus-color',
15
+ modalCloseButtonRadius: '--plasma-modal-close-button-radius'
10
16
  };
@@ -6,7 +6,7 @@ export var config = {
6
6
  },
7
7
  variations: {
8
8
  view: {
9
- "default": /*#__PURE__*/css(modalTokens.modalOverlayWithBlurColor, ":var(--overlay-blur);", modalTokens.modalOverlayColor, ":var(--overlay-soft);;label:plasma-new-hope__default;" + (process.env.NODE_ENV === "production" ? "" : "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy1lbW90aW9uL2V4YW1wbGVzL3BsYXNtYV9iMmMvY29tcG9uZW50cy9Nb2RhbC9Nb2RhbC5jb25maWcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBVXdCIiwiZmlsZSI6Ii4uLy4uLy4uLy4uLy4uLy4uL3NyYy1lbW90aW9uL2V4YW1wbGVzL3BsYXNtYV9iMmMvY29tcG9uZW50cy9Nb2RhbC9Nb2RhbC5jb25maWcudHMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBjc3MgfSBmcm9tICdAZW1vdGlvbi9yZWFjdCc7XG5cbmltcG9ydCB7IG1vZGFsVG9rZW5zIH0gZnJvbSAnLi4vLi4vLi4vLi4vY29tcG9uZW50cy9Nb2RhbCc7XG5cbmV4cG9ydCBjb25zdCBjb25maWcgPSB7XG4gICAgZGVmYXVsdHM6IHtcbiAgICAgICAgdmlldzogJ2RlZmF1bHQnLFxuICAgIH0sXG4gICAgdmFyaWF0aW9uczoge1xuICAgICAgICB2aWV3OiB7XG4gICAgICAgICAgICBkZWZhdWx0OiBjc3NgXG4gICAgICAgICAgICAgICAgJHttb2RhbFRva2Vucy5tb2RhbE92ZXJsYXlXaXRoQmx1ckNvbG9yfTogdmFyKC0tb3ZlcmxheS1ibHVyKTtcbiAgICAgICAgICAgICAgICAke21vZGFsVG9rZW5zLm1vZGFsT3ZlcmxheUNvbG9yfTogdmFyKC0tb3ZlcmxheS1zb2Z0KTtcbiAgICAgICAgICAgIGAsXG4gICAgICAgIH0sXG4gICAgfSxcbn07XG4iXX0= */"))
9
+ "default": /*#__PURE__*/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.modalOutlineFocusColor, ":var(--surface-accent);;label:plasma-new-hope__default;" + (process.env.NODE_ENV === "production" ? "" : "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy1lbW90aW9uL2V4YW1wbGVzL3BsYXNtYV9iMmMvY29tcG9uZW50cy9Nb2RhbC9Nb2RhbC5jb25maWcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBVXdCIiwiZmlsZSI6Ii4uLy4uLy4uLy4uLy4uLy4uL3NyYy1lbW90aW9uL2V4YW1wbGVzL3BsYXNtYV9iMmMvY29tcG9uZW50cy9Nb2RhbC9Nb2RhbC5jb25maWcudHMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBjc3MgfSBmcm9tICdAZW1vdGlvbi9yZWFjdCc7XG5cbmltcG9ydCB7IG1vZGFsVG9rZW5zIH0gZnJvbSAnLi4vLi4vLi4vLi4vY29tcG9uZW50cy9Nb2RhbCc7XG5cbmV4cG9ydCBjb25zdCBjb25maWcgPSB7XG4gICAgZGVmYXVsdHM6IHtcbiAgICAgICAgdmlldzogJ2RlZmF1bHQnLFxuICAgIH0sXG4gICAgdmFyaWF0aW9uczoge1xuICAgICAgICB2aWV3OiB7XG4gICAgICAgICAgICBkZWZhdWx0OiBjc3NgXG4gICAgICAgICAgICAgICAgJHttb2RhbFRva2Vucy5tb2RhbE92ZXJsYXlXaXRoQmx1ckNvbG9yfTogdmFyKC0tb3ZlcmxheS1ibHVyKTtcbiAgICAgICAgICAgICAgICAke21vZGFsVG9rZW5zLm1vZGFsT3ZlcmxheUNvbG9yfTogdmFyKC0tb3ZlcmxheS1zb2Z0KTtcbiAgICAgICAgICAgICAgICAke21vZGFsVG9rZW5zLm1vZGFsQm9keUJhY2tncm91bmR9OiB2YXIoLS1zdXJmYWNlLXNvbGlkLWNhcmQpO1xuICAgICAgICAgICAgICAgICR7bW9kYWxUb2tlbnMubW9kYWxCb2R5Qm9yZGVyUmFkaXVzfTogMS4yNXJlbTtcbiAgICAgICAgICAgICAgICAke21vZGFsVG9rZW5zLm1vZGFsQm9keVBhZGRpbmd9OiAycmVtO1xuICAgICAgICAgICAgICAgICR7bW9kYWxUb2tlbnMubW9kYWxDb250ZW50UGFkZGluZ306IDAuNjI1cmVtO1xuICAgICAgICAgICAgICAgICR7bW9kYWxUb2tlbnMubW9kYWxDbG9zZUJ1dHRvblJhZGl1c306IDAuMzc1cmVtO1xuICAgICAgICAgICAgICAgICR7bW9kYWxUb2tlbnMubW9kYWxPdXRsaW5lRm9jdXNDb2xvcn06IHZhcigtLXN1cmZhY2UtYWNjZW50KTtcbiAgICAgICAgICAgIGAsXG4gICAgICAgIH0sXG4gICAgfSxcbn07XG4iXX0= */"))
10
10
  }
11
11
  }
12
12
  };
@@ -3,6 +3,7 @@ import styled from '@emotion/styled';
3
3
  import type { ComponentProps } from 'react';
4
4
  import type { StoryObj, Meta } from '@storybook/react';
5
5
  import { SSRProvider } from '@salutejs/plasma-core';
6
+ import { disableProps } from '@salutejs/plasma-sb-utils';
6
7
 
7
8
  import { PopupProvider, popupClasses } from '../Popup/Popup';
8
9
  import { Button } from '../Button/Button';
@@ -18,6 +19,7 @@ export default {
18
19
  docs: { story: { inline: false, iframeHeight: '30rem' } },
19
20
  },
20
21
  argTypes: {
22
+ ...disableProps(['hasBody']),
21
23
  placement: {
22
24
  options: [
23
25
  'center',
@@ -75,6 +77,7 @@ type StoryModalProps = ComponentProps<typeof Modal> & {
75
77
  closeOnEsc: boolean;
76
78
  closeOnOverlayClick: boolean;
77
79
  withBlur: boolean;
80
+ hasClose?: boolean;
78
81
  };
79
82
 
80
83
  const StyledButton = styled(Button)`
@@ -135,6 +138,72 @@ const StoryModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProp
135
138
  const [isOpenB, setIsOpenB] = useState(false);
136
139
  const [isOpenC, setIsOpenC] = useState(false);
137
140
 
141
+ return (
142
+ <SSRProvider>
143
+ <StyledWrapper>
144
+ <PopupProvider>
145
+ <ButtonWrapper>
146
+ <StyledButton text="Открыть A" onClick={() => setIsOpenA(true)} />
147
+ </ButtonWrapper>
148
+ <StyledModal
149
+ id="modalA"
150
+ frame="theme-root"
151
+ withAnimation
152
+ onClose={() => setIsOpenA(false)}
153
+ opened={isOpenA}
154
+ placement={placement}
155
+ offset={[offsetX, offsetY]}
156
+ hasBody
157
+ {...rest}
158
+ >
159
+ <Button onClick={() => setIsOpenA(false)}>Close</Button>
160
+ <ButtonWrapper>
161
+ <StyledButton text="Открыть B" onClick={() => setIsOpenB(true)} />
162
+ </ButtonWrapper>
163
+ <Modal
164
+ id="modalB"
165
+ frame="theme-root"
166
+ onClose={() => setIsOpenB(false)}
167
+ opened={isOpenB}
168
+ placement="left"
169
+ offset={[offsetX, offsetY]}
170
+ hasBody
171
+ {...rest}
172
+ >
173
+ <Button style={{ marginRight: '1rem' }} onClick={() => setIsOpenB(false)}>
174
+ Close
175
+ </Button>
176
+ <ButtonWrapper>
177
+ <StyledButton text="Открыть C" onClick={() => setIsOpenC(true)} />
178
+ </ButtonWrapper>
179
+ <Modal
180
+ id="modalC"
181
+ frame="theme-root"
182
+ onClose={() => setIsOpenC(false)}
183
+ opened={isOpenC}
184
+ placement="top"
185
+ offset={[offsetX, offsetY]}
186
+ hasBody
187
+ {...rest}
188
+ >
189
+ <Button style={{ marginRight: '1rem' }} onClick={() => setIsOpenC(false)}>
190
+ Close
191
+ </Button>
192
+ <>Content</>
193
+ </Modal>
194
+ </Modal>
195
+ </StyledModal>
196
+ </PopupProvider>
197
+ </StyledWrapper>
198
+ </SSRProvider>
199
+ );
200
+ };
201
+
202
+ const StoryCustomModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProps) => {
203
+ const [isOpenA, setIsOpenA] = useState(false);
204
+ const [isOpenB, setIsOpenB] = useState(false);
205
+ const [isOpenC, setIsOpenC] = useState(false);
206
+
138
207
  return (
139
208
  <SSRProvider>
140
209
  <StyledWrapper>
@@ -199,7 +268,7 @@ const StoryModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProp
199
268
  );
200
269
  };
201
270
 
202
- export const ModalDemo: StoryObj<StoryModalProps> = {
271
+ export const Default: StoryObj<StoryModalProps> = {
203
272
  args: {
204
273
  placement: 'center',
205
274
  withBlur: false,
@@ -207,10 +276,30 @@ export const ModalDemo: StoryObj<StoryModalProps> = {
207
276
  closeOnOverlayClick: true,
208
277
  offsetX: 0,
209
278
  offsetY: 0,
279
+ hasClose: true,
280
+ },
281
+ argTypes: {
282
+ hasClose: {
283
+ control: {
284
+ type: 'boolean',
285
+ },
286
+ },
210
287
  },
211
288
  render: (args) => <StoryModalDemo {...args} />,
212
289
  };
213
290
 
291
+ export const CustomModalDemo: StoryObj<StoryModalProps> = {
292
+ args: {
293
+ placement: 'center',
294
+ withBlur: false,
295
+ closeOnEsc: true,
296
+ closeOnOverlayClick: true,
297
+ offsetX: 0,
298
+ offsetY: 0,
299
+ },
300
+ render: (args) => <StoryCustomModalDemo {...args} />,
301
+ };
302
+
214
303
  const StyledModalAnimation = styled(Modal)`
215
304
  /* stylelint-disable */
216
305
  && .${popupClasses.root} {
@@ -6,7 +6,7 @@ export var config = {
6
6
  },
7
7
  variations: {
8
8
  view: {
9
- "default": /*#__PURE__*/css(modalTokens.modalOverlayWithBlurColor, ":var(--overlay-blur);", modalTokens.modalOverlayColor, ":var(--overlay-soft);;label:plasma-new-hope__default;" + (process.env.NODE_ENV === "production" ? "" : "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy1lbW90aW9uL2V4YW1wbGVzL3BsYXNtYV93ZWIvY29tcG9uZW50cy9Nb2RhbC9Nb2RhbC5jb25maWcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBVXdCIiwiZmlsZSI6Ii4uLy4uLy4uLy4uLy4uLy4uL3NyYy1lbW90aW9uL2V4YW1wbGVzL3BsYXNtYV93ZWIvY29tcG9uZW50cy9Nb2RhbC9Nb2RhbC5jb25maWcudHMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBjc3MgfSBmcm9tICdAZW1vdGlvbi9yZWFjdCc7XG5cbmltcG9ydCB7IG1vZGFsVG9rZW5zIH0gZnJvbSAnLi4vLi4vLi4vLi4vY29tcG9uZW50cy9Nb2RhbCc7XG5cbmV4cG9ydCBjb25zdCBjb25maWcgPSB7XG4gICAgZGVmYXVsdHM6IHtcbiAgICAgICAgdmlldzogJ2RlZmF1bHQnLFxuICAgIH0sXG4gICAgdmFyaWF0aW9uczoge1xuICAgICAgICB2aWV3OiB7XG4gICAgICAgICAgICBkZWZhdWx0OiBjc3NgXG4gICAgICAgICAgICAgICAgJHttb2RhbFRva2Vucy5tb2RhbE92ZXJsYXlXaXRoQmx1ckNvbG9yfTogdmFyKC0tb3ZlcmxheS1ibHVyKTtcbiAgICAgICAgICAgICAgICAke21vZGFsVG9rZW5zLm1vZGFsT3ZlcmxheUNvbG9yfTogdmFyKC0tb3ZlcmxheS1zb2Z0KTtcbiAgICAgICAgICAgIGAsXG4gICAgICAgIH0sXG4gICAgfSxcbn07XG4iXX0= */"))
9
+ "default": /*#__PURE__*/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.modalOutlineFocusColor, ":var(--surface-accent);;label:plasma-new-hope__default;" + (process.env.NODE_ENV === "production" ? "" : "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy1lbW90aW9uL2V4YW1wbGVzL3BsYXNtYV93ZWIvY29tcG9uZW50cy9Nb2RhbC9Nb2RhbC5jb25maWcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBVXdCIiwiZmlsZSI6Ii4uLy4uLy4uLy4uLy4uLy4uL3NyYy1lbW90aW9uL2V4YW1wbGVzL3BsYXNtYV93ZWIvY29tcG9uZW50cy9Nb2RhbC9Nb2RhbC5jb25maWcudHMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBjc3MgfSBmcm9tICdAZW1vdGlvbi9yZWFjdCc7XG5cbmltcG9ydCB7IG1vZGFsVG9rZW5zIH0gZnJvbSAnLi4vLi4vLi4vLi4vY29tcG9uZW50cy9Nb2RhbCc7XG5cbmV4cG9ydCBjb25zdCBjb25maWcgPSB7XG4gICAgZGVmYXVsdHM6IHtcbiAgICAgICAgdmlldzogJ2RlZmF1bHQnLFxuICAgIH0sXG4gICAgdmFyaWF0aW9uczoge1xuICAgICAgICB2aWV3OiB7XG4gICAgICAgICAgICBkZWZhdWx0OiBjc3NgXG4gICAgICAgICAgICAgICAgJHttb2RhbFRva2Vucy5tb2RhbE92ZXJsYXlXaXRoQmx1ckNvbG9yfTogdmFyKC0tb3ZlcmxheS1ibHVyKTtcbiAgICAgICAgICAgICAgICAke21vZGFsVG9rZW5zLm1vZGFsT3ZlcmxheUNvbG9yfTogdmFyKC0tb3ZlcmxheS1zb2Z0KTtcbiAgICAgICAgICAgICAgICAke21vZGFsVG9rZW5zLm1vZGFsQm9keUJhY2tncm91bmR9OiB2YXIoLS1zdXJmYWNlLXNvbGlkLWNhcmQpO1xuICAgICAgICAgICAgICAgICR7bW9kYWxUb2tlbnMubW9kYWxCb2R5Qm9yZGVyUmFkaXVzfTogMS4yNXJlbTtcbiAgICAgICAgICAgICAgICAke21vZGFsVG9rZW5zLm1vZGFsQm9keVBhZGRpbmd9OiAycmVtO1xuICAgICAgICAgICAgICAgICR7bW9kYWxUb2tlbnMubW9kYWxDb250ZW50UGFkZGluZ306IDAuNjI1cmVtO1xuICAgICAgICAgICAgICAgICR7bW9kYWxUb2tlbnMubW9kYWxDbG9zZUJ1dHRvblJhZGl1c306IDAuMzc1cmVtO1xuICAgICAgICAgICAgICAgICR7bW9kYWxUb2tlbnMubW9kYWxPdXRsaW5lRm9jdXNDb2xvcn06IHZhcigtLXN1cmZhY2UtYWNjZW50KTtcbiAgICAgICAgICAgIGAsXG4gICAgICAgIH0sXG4gICAgfSxcbn07XG4iXX0= */"))
10
10
  }
11
11
  }
12
12
  };
@@ -3,6 +3,7 @@ import styled from '@emotion/styled';
3
3
  import type { ComponentProps } from 'react';
4
4
  import type { StoryObj, Meta } from '@storybook/react';
5
5
  import { SSRProvider } from '@salutejs/plasma-core';
6
+ import { disableProps } from '@salutejs/plasma-sb-utils';
6
7
 
7
8
  import { PopupProvider, popupClasses } from '../Popup/Popup';
8
9
  import { Button } from '../Button/Button';
@@ -18,6 +19,7 @@ export default {
18
19
  docs: { story: { inline: false, iframeHeight: '30rem' } },
19
20
  },
20
21
  argTypes: {
22
+ ...disableProps(['hasBody']),
21
23
  placement: {
22
24
  options: [
23
25
  'center',
@@ -75,6 +77,7 @@ type StoryModalProps = ComponentProps<typeof Modal> & {
75
77
  closeOnEsc: boolean;
76
78
  closeOnOverlayClick: boolean;
77
79
  withBlur: boolean;
80
+ hasClose?: boolean;
78
81
  };
79
82
 
80
83
  const StyledButton = styled(Button)`
@@ -135,6 +138,72 @@ const StoryModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProp
135
138
  const [isOpenB, setIsOpenB] = useState(false);
136
139
  const [isOpenC, setIsOpenC] = useState(false);
137
140
 
141
+ return (
142
+ <SSRProvider>
143
+ <StyledWrapper>
144
+ <PopupProvider>
145
+ <ButtonWrapper>
146
+ <StyledButton text="Открыть A" onClick={() => setIsOpenA(true)} />
147
+ </ButtonWrapper>
148
+ <StyledModal
149
+ id="modalA"
150
+ frame="theme-root"
151
+ withAnimation
152
+ onClose={() => setIsOpenA(false)}
153
+ opened={isOpenA}
154
+ placement={placement}
155
+ offset={[offsetX, offsetY]}
156
+ hasBody
157
+ {...rest}
158
+ >
159
+ <Button onClick={() => setIsOpenA(false)}>Close</Button>
160
+ <ButtonWrapper>
161
+ <StyledButton text="Открыть B" onClick={() => setIsOpenB(true)} />
162
+ </ButtonWrapper>
163
+ <Modal
164
+ id="modalB"
165
+ frame="theme-root"
166
+ onClose={() => setIsOpenB(false)}
167
+ opened={isOpenB}
168
+ placement="left"
169
+ offset={[offsetX, offsetY]}
170
+ hasBody
171
+ {...rest}
172
+ >
173
+ <Button style={{ marginRight: '1rem' }} onClick={() => setIsOpenB(false)}>
174
+ Close
175
+ </Button>
176
+ <ButtonWrapper>
177
+ <StyledButton text="Открыть C" onClick={() => setIsOpenC(true)} />
178
+ </ButtonWrapper>
179
+ <Modal
180
+ id="modalC"
181
+ frame="theme-root"
182
+ onClose={() => setIsOpenC(false)}
183
+ opened={isOpenC}
184
+ placement="top"
185
+ offset={[offsetX, offsetY]}
186
+ hasBody
187
+ {...rest}
188
+ >
189
+ <Button style={{ marginRight: '1rem' }} onClick={() => setIsOpenC(false)}>
190
+ Close
191
+ </Button>
192
+ <>Content</>
193
+ </Modal>
194
+ </Modal>
195
+ </StyledModal>
196
+ </PopupProvider>
197
+ </StyledWrapper>
198
+ </SSRProvider>
199
+ );
200
+ };
201
+
202
+ const StoryCustomModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProps) => {
203
+ const [isOpenA, setIsOpenA] = useState(false);
204
+ const [isOpenB, setIsOpenB] = useState(false);
205
+ const [isOpenC, setIsOpenC] = useState(false);
206
+
138
207
  return (
139
208
  <SSRProvider>
140
209
  <StyledWrapper>
@@ -199,7 +268,7 @@ const StoryModalDemo = ({ placement, offsetX, offsetY, ...rest }: StoryModalProp
199
268
  );
200
269
  };
201
270
 
202
- export const ModalDemo: StoryObj<StoryModalProps> = {
271
+ export const Default: StoryObj<StoryModalProps> = {
203
272
  args: {
204
273
  placement: 'center',
205
274
  withBlur: false,
@@ -207,10 +276,30 @@ export const ModalDemo: StoryObj<StoryModalProps> = {
207
276
  closeOnOverlayClick: true,
208
277
  offsetX: 0,
209
278
  offsetY: 0,
279
+ hasClose: true,
280
+ },
281
+ argTypes: {
282
+ hasClose: {
283
+ control: {
284
+ type: 'boolean',
285
+ },
286
+ },
210
287
  },
211
288
  render: (args) => <StoryModalDemo {...args} />,
212
289
  };
213
290
 
291
+ export const CustomModalDemo: StoryObj<StoryModalProps> = {
292
+ args: {
293
+ placement: 'center',
294
+ withBlur: false,
295
+ closeOnEsc: true,
296
+ closeOnOverlayClick: true,
297
+ offsetX: 0,
298
+ offsetY: 0,
299
+ },
300
+ render: (args) => <StoryCustomModalDemo {...args} />,
301
+ };
302
+
214
303
  const StyledModalAnimation = styled(Modal)`
215
304
  /* stylelint-disable */
216
305
  && .${popupClasses.root} {
@@ -4,3 +4,9 @@
4
4
  .Popup_styles_gq4luz_p1f40oul__bb610b96{position:var(--p1f40oul-0);z-index:var(--p1f40oul-1);left:var(--p1f40oul-2);right:var(--p1f40oul-3);top:var(--p1f40oul-4);bottom:var(--p1f40oul-5);-webkit-transform:var(--p1f40oul-6);-ms-transform:var(--p1f40oul-6);transform:var(--p1f40oul-6);}
5
5
 
6
6
  .Overlay_styles_cxej3y_s1afr8la__70d4dd9a{position:fixed;inset:0;z-index:var(--s1afr8la-0);--plasma_private-overlay-background-color:var(--s1afr8la-1);--plasma_private-overlay-backdrop-filter:var(--s1afr8la-2);background:var(--s1afr8la-3);-webkit-backdrop-filter:var(--s1afr8la-4);backdrop-filter:var(--s1afr8la-4);cursor:var(--s1afr8la-5);}
7
+
8
+ .IconRoot_7pl7ig_svvlqhf__32c458a1{display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;width:var(--svvlqhf-0);height:var(--svvlqhf-0);-webkit-flex:0 0 var(--svvlqhf-0);-ms-flex:0 0 var(--svvlqhf-0);flex:0 0 var(--svvlqhf-0);}
9
+
10
+ .Modal_styles_tqsxxy_m7npn1w__53552e6a{border-radius:var(--plasma-modal-body-border-radius);padding:var(--plasma-modal-body-padding);background:var(--plasma-modal-body-background);box-shadow:var(--shadow-down-soft-l);}
11
+ .Modal_styles_tqsxxy_m16phoaz__53552e6a{position:relative;padding:var(--plasma-modal-content-padding);}
12
+ .Modal_styles_tqsxxy_c5bx5hr__53552e6a{top:0;right:0;width:1.5rem;height:1.5rem;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;border:none;border-radius:var(--plasma-modal-close-button-radius);padding:0;margin:0;outline:none;cursor:pointer;background:transparent;position:relative;position:absolute;}.Modal_styles_tqsxxy_c5bx5hr__53552e6a::before{content:'';position:absolute;top:-0.125rem;left:-0.125rem;right:-0.125rem;bottom:-0.125rem;z-index:1;display:block;box-sizing:content-box;border:0.063rem solid transparent;border-radius:calc(var(--plasma-modal-close-button-radius) + 0.063rem);-webkit-transition:box-shadow 0.2s ease-in-out;transition:box-shadow 0.2s ease-in-out;pointer-events:none;}.Modal_styles_tqsxxy_c5bx5hr__53552e6a.Modal_styles_tqsxxy_focusVisible__53552e6a:focus::before,.Modal_styles_tqsxxy_c5bx5hr__53552e6a[data-focus-visible-added]::before{outline:none;box-shadow:0 0 0 0.063rem var(--plasma-modal-outline-focus-color);}