jvetrau-ds 0.2.3 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/components/avatar-upload/avatar-upload.cjs +1 -0
  2. package/components/avatar-upload/avatar-upload.cjs.map +1 -1
  3. package/components/avatar-upload/avatar-upload.js +1 -0
  4. package/components/avatar-upload/avatar-upload.js.map +1 -1
  5. package/components/button/button.cjs +11 -18
  6. package/components/button/button.cjs.map +1 -1
  7. package/components/button/button.css +3 -2
  8. package/components/button/button.d.ts +4 -3
  9. package/components/button/button.js +12 -19
  10. package/components/button/button.js.map +1 -1
  11. package/components/card/card.cjs +28 -7
  12. package/components/card/card.cjs.map +1 -1
  13. package/components/card/card.css +36 -5
  14. package/components/card/card.d.ts +1 -1
  15. package/components/card/card.js +28 -7
  16. package/components/card/card.js.map +1 -1
  17. package/components/card-group/card-group.css +81 -4
  18. package/components/dropdown/dropdown.cjs +103 -26
  19. package/components/dropdown/dropdown.cjs.map +1 -1
  20. package/components/dropdown/dropdown.css +142 -0
  21. package/components/dropdown/dropdown.d.ts +2 -0
  22. package/components/dropdown/dropdown.js +103 -26
  23. package/components/dropdown/dropdown.js.map +1 -1
  24. package/components/panel/panel.cjs +29 -7
  25. package/components/panel/panel.cjs.map +1 -1
  26. package/components/panel/panel.css +74 -6
  27. package/components/panel/panel.d.ts +1 -0
  28. package/components/panel/panel.js +29 -7
  29. package/components/panel/panel.js.map +1 -1
  30. package/components/video/video.cjs +5 -17
  31. package/components/video/video.cjs.map +1 -1
  32. package/components/video/video.js +5 -16
  33. package/components/video/video.js.map +1 -1
  34. package/icons/assets/close.cjs +14 -0
  35. package/icons/assets/close.cjs.map +1 -0
  36. package/icons/assets/close.d.ts +2 -0
  37. package/icons/assets/close.js +12 -0
  38. package/icons/assets/close.js.map +1 -0
  39. package/icons/manifest.cjs +6 -0
  40. package/icons/manifest.cjs.map +1 -1
  41. package/icons/manifest.d.ts +5 -0
  42. package/icons/manifest.js +6 -0
  43. package/icons/manifest.js.map +1 -1
  44. package/package.json +1 -1
  45. package/patterns/header/header.cjs +38 -5
  46. package/patterns/header/header.cjs.map +1 -1
  47. package/patterns/header/header.css +45 -0
  48. package/patterns/header/header.d.ts +16 -2
  49. package/patterns/header/header.js +34 -5
  50. package/patterns/header/header.js.map +1 -1
  51. package/patterns/modal/modal.cjs +69 -36
  52. package/patterns/modal/modal.cjs.map +1 -1
  53. package/patterns/modal/modal.css +94 -16
  54. package/patterns/modal/modal.d.ts +6 -2
  55. package/patterns/modal/modal.js +66 -38
  56. package/patterns/modal/modal.js.map +1 -1
  57. package/styles.css +475 -33
@@ -3,66 +3,99 @@
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
4
  var react = require('react');
5
5
  require('./modal.css');
6
+ var Button = require('../../components/button');
6
7
  var classnames = require('../../components/helpers/classnames');
8
+ var Panel = require('../../components/panel');
9
+
10
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
11
+
12
+ var Button__default = /*#__PURE__*/_interopDefault(Button);
13
+ var Panel__default = /*#__PURE__*/_interopDefault(Panel);
7
14
 
8
15
  const Modal = ({
9
16
  open,
10
17
  onClose,
11
- ariaLabel,
18
+ heading,
19
+ description,
20
+ closeLabel,
12
21
  presentation = "dialog",
13
22
  size = "default",
14
23
  closeOnBackdrop = true,
15
24
  closeOnEscape = true,
16
25
  className = "",
17
26
  children,
27
+ onClick,
18
28
  ...props
19
29
  }) => {
30
+ const dialogRef = react.useRef(null);
31
+ const classes = classnames.classnames(
32
+ "modal",
33
+ className,
34
+ {
35
+ "modal--wide": size === "wide",
36
+ "modal--fullscreen": presentation === "fullscreen"
37
+ }
38
+ );
39
+ const panelLayout = presentation === "fullscreen" ? "transparent" : "card";
20
40
  react.useEffect(() => {
21
- if (!open || !closeOnEscape) {
41
+ const dialog = dialogRef.current;
42
+ if (!dialog) {
22
43
  return;
23
44
  }
24
- const handleKeyDown = (event) => {
25
- if (event.key === "Escape") {
26
- onClose();
45
+ if (open) {
46
+ if (!dialog.open) {
47
+ dialog.showModal();
27
48
  }
28
- };
29
- document.addEventListener("keydown", handleKeyDown);
30
- return () => {
31
- document.removeEventListener("keydown", handleKeyDown);
32
- };
33
- }, [open, closeOnEscape, onClose]);
34
- if (!open) {
35
- return null;
36
- }
37
- const classes = classnames.classnames("modal", className, {
38
- "modal--wide": size === "wide",
39
- "modal--fullscreen": presentation === "fullscreen"
40
- });
41
- const handleBackdropClick = () => {
42
- if (!closeOnBackdrop) {
49
+ return;
50
+ }
51
+ if (dialog.open) {
52
+ dialog.close();
53
+ }
54
+ }, [open]);
55
+ const handleCancel = (event) => {
56
+ event.preventDefault();
57
+ if (!closeOnEscape) {
58
+ return;
59
+ }
60
+ onClose();
61
+ };
62
+ const handleClick = (event) => {
63
+ onClick?.(event);
64
+ if (event.defaultPrevented || !closeOnBackdrop || event.target !== event.currentTarget) {
43
65
  return;
44
66
  }
45
67
  onClose();
46
68
  };
47
69
  return /* @__PURE__ */ jsxRuntime.jsx(
48
- "div",
70
+ "dialog",
49
71
  {
72
+ ...props,
73
+ ref: dialogRef,
50
74
  className: classes,
51
- onClick: handleBackdropClick,
52
- children: /* @__PURE__ */ jsxRuntime.jsx(
53
- "div",
54
- {
55
- className: "modal__content",
56
- role: "dialog",
57
- "aria-modal": "true",
58
- "aria-label": ariaLabel,
59
- onClick: (event) => {
60
- event.stopPropagation();
61
- },
62
- ...props,
63
- children
64
- }
65
- )
75
+ onCancel: handleCancel,
76
+ onClick: handleClick,
77
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "modal__surface", children: [
78
+ /* @__PURE__ */ jsxRuntime.jsx(
79
+ Panel__default.default,
80
+ {
81
+ layout: panelLayout,
82
+ heading,
83
+ description,
84
+ children
85
+ }
86
+ ),
87
+ /* @__PURE__ */ jsxRuntime.jsx(
88
+ Button__default.default,
89
+ {
90
+ type: "button",
91
+ mode: "toolbar",
92
+ icon: "close",
93
+ className: "modal__close",
94
+ "aria-label": closeLabel,
95
+ onClick: onClose
96
+ }
97
+ )
98
+ ] })
66
99
  }
67
100
  );
68
101
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/patterns/modal/modal.tsx"],"names":["useEffect","classnames","jsx"],"mappings":";;;;;;;AAeA,MAAM,QAA8B,CAAC;AAAA,EACnC,IAAA;AAAA,EACA,OAAA;AAAA,EACA,SAAA;AAAA,EACA,YAAA,GAAe,QAAA;AAAA,EACf,IAAA,GAAO,SAAA;AAAA,EACP,eAAA,GAAkB,IAAA;AAAA,EAClB,aAAA,GAAgB,IAAA;AAAA,EAChB,SAAA,GAAY,EAAA;AAAA,EACZ,QAAA;AAAA,EACA,GAAG;AACL,CAAA,KAAM;AACJ,EAAAA,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,IAAA,IAAQ,CAAC,aAAA,EAAe;AAC3B,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,aAAA,GAAgB,CAAC,KAAA,KAAyB;AAC9C,MAAA,IAAI,KAAA,CAAM,QAAQ,QAAA,EAAU;AAC1B,QAAA,OAAA,EAAQ;AAAA,MACV;AAAA,IACF,CAAA;AAEA,IAAA,QAAA,CAAS,gBAAA,CAAiB,WAAW,aAAa,CAAA;AAElD,IAAA,OAAO,MAAM;AACX,MAAA,QAAA,CAAS,mBAAA,CAAoB,WAAW,aAAa,CAAA;AAAA,IACvD,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,IAAA,EAAM,aAAA,EAAe,OAAO,CAAC,CAAA;AAEjC,EAAA,IAAI,CAAC,IAAA,EAAM;AACT,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,MAAM,OAAA,GAAUC,qBAAA,CAAW,OAAA,EAAS,SAAA,EAAW;AAAA,IAC7C,eAAe,IAAA,KAAS,MAAA;AAAA,IACxB,qBAAqB,YAAA,KAAiB;AAAA,GACvC,CAAA;AAED,EAAA,MAAM,sBAAsB,MAAM;AAChC,IAAA,IAAI,CAAC,eAAA,EAAiB;AACpB,MAAA;AAAA,IACF;AAEA,IAAA,OAAA,EAAQ;AAAA,EACV,CAAA;AAEA,EAAA,uBACEC,cAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,OAAA;AAAA,MACX,OAAA,EAAS,mBAAA;AAAA,MAET,QAAA,kBAAAA,cAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UACC,SAAA,EAAU,gBAAA;AAAA,UACV,IAAA,EAAK,QAAA;AAAA,UACL,YAAA,EAAW,MAAA;AAAA,UACX,YAAA,EAAY,SAAA;AAAA,UACZ,OAAA,EAAS,CAAC,KAAA,KAAU;AAClB,YAAA,KAAA,CAAM,eAAA,EAAgB;AAAA,UACxB,CAAA;AAAA,UACC,GAAG,KAAA;AAAA,UAEH;AAAA;AAAA;AACH;AAAA,GACF;AAEJ,CAAA;AAEA,IAAO,aAAA,GAAQ","file":"modal.cjs","sourcesContent":["import React, { useEffect } from 'react';\nimport './modal.css';\nimport { classnames } from '../../components/helpers/classnames';\n\nexport interface ModalProps\n extends React.HTMLAttributes<HTMLDivElement> {\n open: boolean;\n onClose: () => void;\n ariaLabel: string;\n presentation?: 'dialog' | 'fullscreen';\n size?: 'default' | 'wide';\n closeOnBackdrop?: boolean;\n closeOnEscape?: boolean;\n}\n\nconst Modal: React.FC<ModalProps> = ({\n open,\n onClose,\n ariaLabel,\n presentation = 'dialog',\n size = 'default',\n closeOnBackdrop = true,\n closeOnEscape = true,\n className = '',\n children,\n ...props\n}) => {\n useEffect(() => {\n if (!open || !closeOnEscape) {\n return;\n }\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n onClose();\n }\n };\n\n document.addEventListener('keydown', handleKeyDown);\n\n return () => {\n document.removeEventListener('keydown', handleKeyDown);\n };\n }, [open, closeOnEscape, onClose]);\n\n if (!open) {\n return null;\n }\n\n const classes = classnames('modal', className, {\n 'modal--wide': size === 'wide',\n 'modal--fullscreen': presentation === 'fullscreen',\n });\n\n const handleBackdropClick = () => {\n if (!closeOnBackdrop) {\n return;\n }\n\n onClose();\n };\n\n return (\n <div\n className={classes}\n onClick={handleBackdropClick}\n >\n <div\n className=\"modal__content\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={ariaLabel}\n onClick={(event) => {\n event.stopPropagation();\n }}\n {...props}\n >\n {children}\n </div>\n </div>\n );\n};\n\nexport default Modal;"]}
1
+ {"version":3,"sources":["../../../src/patterns/modal/modal.tsx"],"names":["useRef","classnames","useEffect","jsx","jsxs","Panel","Button"],"mappings":";;;;;;;;;;;;;;AA0CA,MAAM,QAA8B,CAAC;AAAA,EACnC,IAAA;AAAA,EACA,OAAA;AAAA,EACA,OAAA;AAAA,EACA,WAAA;AAAA,EACA,UAAA;AAAA,EACA,YAAA,GAAe,QAAA;AAAA,EACf,IAAA,GAAO,SAAA;AAAA,EACP,eAAA,GAAkB,IAAA;AAAA,EAClB,aAAA,GAAgB,IAAA;AAAA,EAChB,SAAA,GAAY,EAAA;AAAA,EACZ,QAAA;AAAA,EACA,OAAA;AAAA,EACA,GAAG;AACL,CAAA,KAAM;AACJ,EAAA,MAAM,SAAA,GACJA,aAA0B,IAAI,CAAA;AAEhC,EAAA,MAAM,OAAA,GAAUC,qBAAA;AAAA,IACd,OAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,MACE,eACE,IAAA,KAAS,MAAA;AAAA,MACX,qBACE,YAAA,KACA;AAAA;AACJ,GACF;AAEA,EAAA,MAAM,WAAA,GACJ,YAAA,KAAiB,YAAA,GACb,aAAA,GACA,MAAA;AAEN,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,MAAM,SACJ,SAAA,CAAU,OAAA;AAEZ,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,IAAA,EAAM;AACR,MAAA,IAAI,CAAC,OAAO,IAAA,EAAM;AAChB,QAAA,MAAA,CAAO,SAAA,EAAU;AAAA,MACnB;AAEA,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,OAAO,IAAA,EAAM;AACf,MAAA,MAAA,CAAO,KAAA,EAAM;AAAA,IACf;AAAA,EACF,CAAA,EAAG,CAAC,IAAI,CAAC,CAAA;AAET,EAAA,MAAM,YAAA,GAAe,CACnB,KAAA,KAGG;AACH,IAAA,KAAA,CAAM,cAAA,EAAe;AAErB,IAAA,IAAI,CAAC,aAAA,EAAe;AAClB,MAAA;AAAA,IACF;AAEA,IAAA,OAAA,EAAQ;AAAA,EACV,CAAA;AAEA,EAAA,MAAM,WAAA,GAAc,CAClB,KAAA,KAGG;AACH,IAAA,OAAA,GAAU,KAAK,CAAA;AAEf,IAAA,IACE,MAAM,gBAAA,IACN,CAAC,mBACD,KAAA,CAAM,MAAA,KACJ,MAAM,aAAA,EACR;AACA,MAAA;AAAA,IACF;AAEA,IAAA,OAAA,EAAQ;AAAA,EACV,CAAA;AAEA,EAAA,uBACEC,cAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACE,GAAG,KAAA;AAAA,MACJ,GAAA,EAAK,SAAA;AAAA,MACL,SAAA,EAAW,OAAA;AAAA,MACX,QAAA,EAAU,YAAA;AAAA,MACV,OAAA,EAAS,WAAA;AAAA,MAET,QAAA,kBAAAC,eAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,gBAAA,EACb,QAAA,EAAA;AAAA,wBAAAD,cAAA;AAAA,UAACE,sBAAA;AAAA,UAAA;AAAA,YACC,MAAA,EAAQ,WAAA;AAAA,YACR,OAAA;AAAA,YACA,WAAA;AAAA,YAIC;AAAA;AAAA,SACH;AAAA,wBAEAF,cAAA;AAAA,UAACG,uBAAA;AAAA,UAAA;AAAA,YACC,IAAA,EAAK,QAAA;AAAA,YACL,IAAA,EAAK,SAAA;AAAA,YACL,IAAA,EAAK,OAAA;AAAA,YACL,SAAA,EAAU,cAAA;AAAA,YACV,YAAA,EAAY,UAAA;AAAA,YACZ,OAAA,EAAS;AAAA;AAAA;AACX,OAAA,EACF;AAAA;AAAA,GACF;AAEJ,CAAA;AAEA,IAAO,aAAA,GAAQ","file":"modal.cjs","sourcesContent":["import React, {\n useEffect,\n useRef,\n} from 'react';\n\nimport './modal.css';\nimport Button from '../../components/button';\nimport { classnames } from '../../components/helpers/classnames';\nimport Panel from '../../components/panel';\n\ntype ModalNativeProps = Omit<\n React.DialogHTMLAttributes<HTMLDialogElement>,\n | 'children'\n | 'onCancel'\n | 'onClose'\n | 'open'\n>;\n\nexport interface ModalProps\n extends ModalNativeProps {\n open: boolean;\n onClose: () => void;\n\n heading?: React.ReactNode;\n description?: React.ReactNode;\n\n closeLabel: string;\n\n presentation?:\n | 'dialog'\n | 'fullscreen';\n\n size?:\n | 'default'\n | 'wide';\n\n closeOnBackdrop?: boolean;\n closeOnEscape?: boolean;\n\n children?: React.ReactNode;\n}\n\nconst Modal: React.FC<ModalProps> = ({\n open,\n onClose,\n heading,\n description,\n closeLabel,\n presentation = 'dialog',\n size = 'default',\n closeOnBackdrop = true,\n closeOnEscape = true,\n className = '',\n children,\n onClick,\n ...props\n}) => {\n const dialogRef =\n useRef<HTMLDialogElement>(null);\n\n const classes = classnames(\n 'modal',\n className,\n {\n 'modal--wide':\n size === 'wide',\n 'modal--fullscreen':\n presentation ===\n 'fullscreen',\n },\n );\n\n const panelLayout =\n presentation === 'fullscreen'\n ? 'transparent'\n : 'card';\n\n useEffect(() => {\n const dialog =\n dialogRef.current;\n\n if (!dialog) {\n return;\n }\n\n if (open) {\n if (!dialog.open) {\n dialog.showModal();\n }\n\n return;\n }\n\n if (dialog.open) {\n dialog.close();\n }\n }, [open]);\n\n const handleCancel = (\n event: React.SyntheticEvent<\n HTMLDialogElement\n >,\n ) => {\n event.preventDefault();\n\n if (!closeOnEscape) {\n return;\n }\n\n onClose();\n };\n\n const handleClick = (\n event: React.MouseEvent<\n HTMLDialogElement\n >,\n ) => {\n onClick?.(event);\n\n if (\n event.defaultPrevented ||\n !closeOnBackdrop ||\n event.target !==\n event.currentTarget\n ) {\n return;\n }\n\n onClose();\n };\n\n return (\n <dialog\n {...props}\n ref={dialogRef}\n className={classes}\n onCancel={handleCancel}\n onClick={handleClick}\n >\n <div className=\"modal__surface\">\n <Panel\n layout={panelLayout}\n heading={heading}\n description={\n description\n }\n >\n {children}\n </Panel>\n\n <Button\n type=\"button\"\n mode=\"toolbar\"\n icon=\"close\"\n className=\"modal__close\"\n aria-label={closeLabel}\n onClick={onClose}\n />\n </div>\n </dialog>\n );\n};\n\nexport default Modal;\n"]}
@@ -2,7 +2,7 @@
2
2
  /* color */
3
3
  --modal-backdrop-bg: rgb(0 0 0 / 40%);
4
4
 
5
- background: var(--modal-backdrop-bg);
5
+ color: inherit;
6
6
 
7
7
  /* typography */
8
8
 
@@ -10,17 +10,36 @@
10
10
  --modal-padding: var(--size-grid-padding-horz);
11
11
  --modal-content-width: min(640px, 100%);
12
12
  --modal-content-width-wide: min(1120px, 100%);
13
- --modal-content-height-fullscreen: 100%;
13
+ --modal-close-offset: var(--padding-container);
14
+
15
+ width: 100%;
16
+ max-width: none;
17
+ height: 100%;
18
+ max-height: none;
19
+
20
+ margin: 0;
21
+ padding: var(--modal-padding);
14
22
 
15
- position: fixed;
16
- inset: 0;
17
- z-index: 1000;
23
+ border: 0;
18
24
 
19
25
  display: flex;
20
26
  align-items: center;
21
27
  justify-content: center;
22
28
 
23
- padding: var(--modal-padding);
29
+ /* border */
30
+
31
+ /* depth */
32
+
33
+ /* motion */
34
+ }
35
+
36
+ .modal::backdrop {
37
+ /* color */
38
+ background: var(--modal-backdrop-bg);
39
+
40
+ /* typography */
41
+
42
+ /* size */
24
43
 
25
44
  /* border */
26
45
 
@@ -29,14 +48,17 @@
29
48
  /* motion */
30
49
  }
31
50
 
32
- .modal__content {
51
+ .modal__surface {
33
52
  /* color */
34
53
 
35
54
  /* typography */
36
55
 
37
56
  /* size */
57
+ position: relative;
58
+
38
59
  width: var(--modal-content-width);
39
60
  max-height: 100%;
61
+
40
62
  overflow: auto;
41
63
 
42
64
  /* border */
@@ -46,34 +68,90 @@
46
68
  /* motion */
47
69
  }
48
70
 
49
- .modal--wide .modal__content {
71
+ .modal__close {
72
+ /* color */
73
+
74
+ /* typography */
75
+
76
+ /* size */
77
+ position: absolute;
78
+ top: var(--modal-close-offset);
79
+ right: var(--modal-close-offset);
80
+
81
+ /* border */
82
+
83
+ /* depth */
84
+
85
+ /* motion */
86
+ }
87
+
88
+ .modal--wide .modal__surface {
89
+ /* color */
90
+
91
+ /* typography */
92
+
50
93
  /* size */
51
94
  width: var(--modal-content-width-wide);
95
+
96
+ /* border */
97
+
98
+ /* depth */
99
+
100
+ /* motion */
52
101
  }
53
102
 
54
103
  .modal--fullscreen {
104
+ /* color */
105
+
106
+ /* typography */
107
+
55
108
  /* size */
56
- align-items: flex-start;
109
+ align-items: stretch;
57
110
  justify-content: stretch;
58
111
 
59
112
  padding: 0;
113
+
114
+ /* border */
115
+
116
+ /* depth */
117
+
118
+ /* motion */
60
119
  }
61
120
 
62
- .modal--fullscreen .modal__content {
121
+ .modal--fullscreen .modal__surface {
122
+ /* color */
123
+
124
+ /* typography */
125
+
63
126
  /* size */
64
127
  display: flex;
65
- align-items: flex-start;
66
- justify-content: flex-start;
128
+ align-items: stretch;
67
129
 
68
130
  width: 100%;
69
- height: var(--modal-content-height-fullscreen);
70
-
131
+ height: 100%;
71
132
  max-height: none;
133
+
134
+ overflow: auto;
135
+
136
+ /* border */
137
+
138
+ /* depth */
139
+
140
+ /* motion */
72
141
  }
73
142
 
74
- .modal--fullscreen .modal__content > * {
143
+ .modal--fullscreen .panel {
144
+ /* color */
145
+
146
+ /* typography */
147
+
75
148
  /* size */
76
149
  flex: 1;
77
- width: 100%;
78
150
  min-height: 100%;
151
+
152
+ /* border */
153
+
154
+ /* depth */
155
+
156
+ /* motion */
79
157
  }
@@ -1,13 +1,17 @@
1
1
  import React from 'react';
2
2
  import './modal.css';
3
- export interface ModalProps extends React.HTMLAttributes<HTMLDivElement> {
3
+ type ModalNativeProps = Omit<React.DialogHTMLAttributes<HTMLDialogElement>, 'children' | 'onCancel' | 'onClose' | 'open'>;
4
+ export interface ModalProps extends ModalNativeProps {
4
5
  open: boolean;
5
6
  onClose: () => void;
6
- ariaLabel: string;
7
+ heading?: React.ReactNode;
8
+ description?: React.ReactNode;
9
+ closeLabel: string;
7
10
  presentation?: 'dialog' | 'fullscreen';
8
11
  size?: 'default' | 'wide';
9
12
  closeOnBackdrop?: boolean;
10
13
  closeOnEscape?: boolean;
14
+ children?: React.ReactNode;
11
15
  }
12
16
  declare const Modal: React.FC<ModalProps>;
13
17
  export default Modal;
@@ -1,66 +1,94 @@
1
- import { jsx } from 'react/jsx-runtime';
2
- import { useEffect } from 'react';
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { useRef, useEffect } from 'react';
3
3
  import './modal.css';
4
+ import Button from '../../components/button';
4
5
  import { classnames } from '../../components/helpers/classnames';
6
+ import Panel from '../../components/panel';
5
7
 
6
8
  const Modal = ({
7
9
  open,
8
10
  onClose,
9
- ariaLabel,
11
+ heading,
12
+ description,
13
+ closeLabel,
10
14
  presentation = "dialog",
11
15
  size = "default",
12
16
  closeOnBackdrop = true,
13
17
  closeOnEscape = true,
14
18
  className = "",
15
19
  children,
20
+ onClick,
16
21
  ...props
17
22
  }) => {
23
+ const dialogRef = useRef(null);
24
+ const classes = classnames(
25
+ "modal",
26
+ className,
27
+ {
28
+ "modal--wide": size === "wide",
29
+ "modal--fullscreen": presentation === "fullscreen"
30
+ }
31
+ );
32
+ const panelLayout = presentation === "fullscreen" ? "transparent" : "card";
18
33
  useEffect(() => {
19
- if (!open || !closeOnEscape) {
34
+ const dialog = dialogRef.current;
35
+ if (!dialog) {
20
36
  return;
21
37
  }
22
- const handleKeyDown = (event) => {
23
- if (event.key === "Escape") {
24
- onClose();
38
+ if (open) {
39
+ if (!dialog.open) {
40
+ dialog.showModal();
25
41
  }
26
- };
27
- document.addEventListener("keydown", handleKeyDown);
28
- return () => {
29
- document.removeEventListener("keydown", handleKeyDown);
30
- };
31
- }, [open, closeOnEscape, onClose]);
32
- if (!open) {
33
- return null;
34
- }
35
- const classes = classnames("modal", className, {
36
- "modal--wide": size === "wide",
37
- "modal--fullscreen": presentation === "fullscreen"
38
- });
39
- const handleBackdropClick = () => {
40
- if (!closeOnBackdrop) {
42
+ return;
43
+ }
44
+ if (dialog.open) {
45
+ dialog.close();
46
+ }
47
+ }, [open]);
48
+ const handleCancel = (event) => {
49
+ event.preventDefault();
50
+ if (!closeOnEscape) {
51
+ return;
52
+ }
53
+ onClose();
54
+ };
55
+ const handleClick = (event) => {
56
+ onClick?.(event);
57
+ if (event.defaultPrevented || !closeOnBackdrop || event.target !== event.currentTarget) {
41
58
  return;
42
59
  }
43
60
  onClose();
44
61
  };
45
62
  return /* @__PURE__ */ jsx(
46
- "div",
63
+ "dialog",
47
64
  {
65
+ ...props,
66
+ ref: dialogRef,
48
67
  className: classes,
49
- onClick: handleBackdropClick,
50
- children: /* @__PURE__ */ jsx(
51
- "div",
52
- {
53
- className: "modal__content",
54
- role: "dialog",
55
- "aria-modal": "true",
56
- "aria-label": ariaLabel,
57
- onClick: (event) => {
58
- event.stopPropagation();
59
- },
60
- ...props,
61
- children
62
- }
63
- )
68
+ onCancel: handleCancel,
69
+ onClick: handleClick,
70
+ children: /* @__PURE__ */ jsxs("div", { className: "modal__surface", children: [
71
+ /* @__PURE__ */ jsx(
72
+ Panel,
73
+ {
74
+ layout: panelLayout,
75
+ heading,
76
+ description,
77
+ children
78
+ }
79
+ ),
80
+ /* @__PURE__ */ jsx(
81
+ Button,
82
+ {
83
+ type: "button",
84
+ mode: "toolbar",
85
+ icon: "close",
86
+ className: "modal__close",
87
+ "aria-label": closeLabel,
88
+ onClick: onClose
89
+ }
90
+ )
91
+ ] })
64
92
  }
65
93
  );
66
94
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/patterns/modal/modal.tsx"],"names":[],"mappings":";;;;;AAeA,MAAM,QAA8B,CAAC;AAAA,EACnC,IAAA;AAAA,EACA,OAAA;AAAA,EACA,SAAA;AAAA,EACA,YAAA,GAAe,QAAA;AAAA,EACf,IAAA,GAAO,SAAA;AAAA,EACP,eAAA,GAAkB,IAAA;AAAA,EAClB,aAAA,GAAgB,IAAA;AAAA,EAChB,SAAA,GAAY,EAAA;AAAA,EACZ,QAAA;AAAA,EACA,GAAG;AACL,CAAA,KAAM;AACJ,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,IAAA,IAAQ,CAAC,aAAA,EAAe;AAC3B,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,aAAA,GAAgB,CAAC,KAAA,KAAyB;AAC9C,MAAA,IAAI,KAAA,CAAM,QAAQ,QAAA,EAAU;AAC1B,QAAA,OAAA,EAAQ;AAAA,MACV;AAAA,IACF,CAAA;AAEA,IAAA,QAAA,CAAS,gBAAA,CAAiB,WAAW,aAAa,CAAA;AAElD,IAAA,OAAO,MAAM;AACX,MAAA,QAAA,CAAS,mBAAA,CAAoB,WAAW,aAAa,CAAA;AAAA,IACvD,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,IAAA,EAAM,aAAA,EAAe,OAAO,CAAC,CAAA;AAEjC,EAAA,IAAI,CAAC,IAAA,EAAM;AACT,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,MAAM,OAAA,GAAU,UAAA,CAAW,OAAA,EAAS,SAAA,EAAW;AAAA,IAC7C,eAAe,IAAA,KAAS,MAAA;AAAA,IACxB,qBAAqB,YAAA,KAAiB;AAAA,GACvC,CAAA;AAED,EAAA,MAAM,sBAAsB,MAAM;AAChC,IAAA,IAAI,CAAC,eAAA,EAAiB;AACpB,MAAA;AAAA,IACF;AAEA,IAAA,OAAA,EAAQ;AAAA,EACV,CAAA;AAEA,EAAA,uBACE,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,OAAA;AAAA,MACX,OAAA,EAAS,mBAAA;AAAA,MAET,QAAA,kBAAA,GAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UACC,SAAA,EAAU,gBAAA;AAAA,UACV,IAAA,EAAK,QAAA;AAAA,UACL,YAAA,EAAW,MAAA;AAAA,UACX,YAAA,EAAY,SAAA;AAAA,UACZ,OAAA,EAAS,CAAC,KAAA,KAAU;AAClB,YAAA,KAAA,CAAM,eAAA,EAAgB;AAAA,UACxB,CAAA;AAAA,UACC,GAAG,KAAA;AAAA,UAEH;AAAA;AAAA;AACH;AAAA,GACF;AAEJ,CAAA;AAEA,IAAO,aAAA,GAAQ","file":"modal.js","sourcesContent":["import React, { useEffect } from 'react';\nimport './modal.css';\nimport { classnames } from '../../components/helpers/classnames';\n\nexport interface ModalProps\n extends React.HTMLAttributes<HTMLDivElement> {\n open: boolean;\n onClose: () => void;\n ariaLabel: string;\n presentation?: 'dialog' | 'fullscreen';\n size?: 'default' | 'wide';\n closeOnBackdrop?: boolean;\n closeOnEscape?: boolean;\n}\n\nconst Modal: React.FC<ModalProps> = ({\n open,\n onClose,\n ariaLabel,\n presentation = 'dialog',\n size = 'default',\n closeOnBackdrop = true,\n closeOnEscape = true,\n className = '',\n children,\n ...props\n}) => {\n useEffect(() => {\n if (!open || !closeOnEscape) {\n return;\n }\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n onClose();\n }\n };\n\n document.addEventListener('keydown', handleKeyDown);\n\n return () => {\n document.removeEventListener('keydown', handleKeyDown);\n };\n }, [open, closeOnEscape, onClose]);\n\n if (!open) {\n return null;\n }\n\n const classes = classnames('modal', className, {\n 'modal--wide': size === 'wide',\n 'modal--fullscreen': presentation === 'fullscreen',\n });\n\n const handleBackdropClick = () => {\n if (!closeOnBackdrop) {\n return;\n }\n\n onClose();\n };\n\n return (\n <div\n className={classes}\n onClick={handleBackdropClick}\n >\n <div\n className=\"modal__content\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={ariaLabel}\n onClick={(event) => {\n event.stopPropagation();\n }}\n {...props}\n >\n {children}\n </div>\n </div>\n );\n};\n\nexport default Modal;"]}
1
+ {"version":3,"sources":["../../../src/patterns/modal/modal.tsx"],"names":[],"mappings":";;;;;;;AA0CA,MAAM,QAA8B,CAAC;AAAA,EACnC,IAAA;AAAA,EACA,OAAA;AAAA,EACA,OAAA;AAAA,EACA,WAAA;AAAA,EACA,UAAA;AAAA,EACA,YAAA,GAAe,QAAA;AAAA,EACf,IAAA,GAAO,SAAA;AAAA,EACP,eAAA,GAAkB,IAAA;AAAA,EAClB,aAAA,GAAgB,IAAA;AAAA,EAChB,SAAA,GAAY,EAAA;AAAA,EACZ,QAAA;AAAA,EACA,OAAA;AAAA,EACA,GAAG;AACL,CAAA,KAAM;AACJ,EAAA,MAAM,SAAA,GACJ,OAA0B,IAAI,CAAA;AAEhC,EAAA,MAAM,OAAA,GAAU,UAAA;AAAA,IACd,OAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,MACE,eACE,IAAA,KAAS,MAAA;AAAA,MACX,qBACE,YAAA,KACA;AAAA;AACJ,GACF;AAEA,EAAA,MAAM,WAAA,GACJ,YAAA,KAAiB,YAAA,GACb,aAAA,GACA,MAAA;AAEN,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,SACJ,SAAA,CAAU,OAAA;AAEZ,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,IAAA,EAAM;AACR,MAAA,IAAI,CAAC,OAAO,IAAA,EAAM;AAChB,QAAA,MAAA,CAAO,SAAA,EAAU;AAAA,MACnB;AAEA,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,OAAO,IAAA,EAAM;AACf,MAAA,MAAA,CAAO,KAAA,EAAM;AAAA,IACf;AAAA,EACF,CAAA,EAAG,CAAC,IAAI,CAAC,CAAA;AAET,EAAA,MAAM,YAAA,GAAe,CACnB,KAAA,KAGG;AACH,IAAA,KAAA,CAAM,cAAA,EAAe;AAErB,IAAA,IAAI,CAAC,aAAA,EAAe;AAClB,MAAA;AAAA,IACF;AAEA,IAAA,OAAA,EAAQ;AAAA,EACV,CAAA;AAEA,EAAA,MAAM,WAAA,GAAc,CAClB,KAAA,KAGG;AACH,IAAA,OAAA,GAAU,KAAK,CAAA;AAEf,IAAA,IACE,MAAM,gBAAA,IACN,CAAC,mBACD,KAAA,CAAM,MAAA,KACJ,MAAM,aAAA,EACR;AACA,MAAA;AAAA,IACF;AAEA,IAAA,OAAA,EAAQ;AAAA,EACV,CAAA;AAEA,EAAA,uBACE,GAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACE,GAAG,KAAA;AAAA,MACJ,GAAA,EAAK,SAAA;AAAA,MACL,SAAA,EAAW,OAAA;AAAA,MACX,QAAA,EAAU,YAAA;AAAA,MACV,OAAA,EAAS,WAAA;AAAA,MAET,QAAA,kBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,gBAAA,EACb,QAAA,EAAA;AAAA,wBAAA,GAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,MAAA,EAAQ,WAAA;AAAA,YACR,OAAA;AAAA,YACA,WAAA;AAAA,YAIC;AAAA;AAAA,SACH;AAAA,wBAEA,GAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,IAAA,EAAK,QAAA;AAAA,YACL,IAAA,EAAK,SAAA;AAAA,YACL,IAAA,EAAK,OAAA;AAAA,YACL,SAAA,EAAU,cAAA;AAAA,YACV,YAAA,EAAY,UAAA;AAAA,YACZ,OAAA,EAAS;AAAA;AAAA;AACX,OAAA,EACF;AAAA;AAAA,GACF;AAEJ,CAAA;AAEA,IAAO,aAAA,GAAQ","file":"modal.js","sourcesContent":["import React, {\n useEffect,\n useRef,\n} from 'react';\n\nimport './modal.css';\nimport Button from '../../components/button';\nimport { classnames } from '../../components/helpers/classnames';\nimport Panel from '../../components/panel';\n\ntype ModalNativeProps = Omit<\n React.DialogHTMLAttributes<HTMLDialogElement>,\n | 'children'\n | 'onCancel'\n | 'onClose'\n | 'open'\n>;\n\nexport interface ModalProps\n extends ModalNativeProps {\n open: boolean;\n onClose: () => void;\n\n heading?: React.ReactNode;\n description?: React.ReactNode;\n\n closeLabel: string;\n\n presentation?:\n | 'dialog'\n | 'fullscreen';\n\n size?:\n | 'default'\n | 'wide';\n\n closeOnBackdrop?: boolean;\n closeOnEscape?: boolean;\n\n children?: React.ReactNode;\n}\n\nconst Modal: React.FC<ModalProps> = ({\n open,\n onClose,\n heading,\n description,\n closeLabel,\n presentation = 'dialog',\n size = 'default',\n closeOnBackdrop = true,\n closeOnEscape = true,\n className = '',\n children,\n onClick,\n ...props\n}) => {\n const dialogRef =\n useRef<HTMLDialogElement>(null);\n\n const classes = classnames(\n 'modal',\n className,\n {\n 'modal--wide':\n size === 'wide',\n 'modal--fullscreen':\n presentation ===\n 'fullscreen',\n },\n );\n\n const panelLayout =\n presentation === 'fullscreen'\n ? 'transparent'\n : 'card';\n\n useEffect(() => {\n const dialog =\n dialogRef.current;\n\n if (!dialog) {\n return;\n }\n\n if (open) {\n if (!dialog.open) {\n dialog.showModal();\n }\n\n return;\n }\n\n if (dialog.open) {\n dialog.close();\n }\n }, [open]);\n\n const handleCancel = (\n event: React.SyntheticEvent<\n HTMLDialogElement\n >,\n ) => {\n event.preventDefault();\n\n if (!closeOnEscape) {\n return;\n }\n\n onClose();\n };\n\n const handleClick = (\n event: React.MouseEvent<\n HTMLDialogElement\n >,\n ) => {\n onClick?.(event);\n\n if (\n event.defaultPrevented ||\n !closeOnBackdrop ||\n event.target !==\n event.currentTarget\n ) {\n return;\n }\n\n onClose();\n };\n\n return (\n <dialog\n {...props}\n ref={dialogRef}\n className={classes}\n onCancel={handleCancel}\n onClick={handleClick}\n >\n <div className=\"modal__surface\">\n <Panel\n layout={panelLayout}\n heading={heading}\n description={\n description\n }\n >\n {children}\n </Panel>\n\n <Button\n type=\"button\"\n mode=\"toolbar\"\n icon=\"close\"\n className=\"modal__close\"\n aria-label={closeLabel}\n onClick={onClose}\n />\n </div>\n </dialog>\n );\n};\n\nexport default Modal;\n"]}