@cerberus-design/react 0.6.1-next-8062b70 → 0.6.1-next-fa4208e

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 (69) hide show
  1. package/build/legacy/_tsup-dts-rollup.d.ts +106 -0
  2. package/build/legacy/chunk-2F5TB2EV.js +25 -0
  3. package/build/legacy/chunk-2F5TB2EV.js.map +1 -0
  4. package/build/legacy/{chunk-UZIN7UOS.js → chunk-D3ZXZA3U.js} +57 -49
  5. package/build/legacy/chunk-D3ZXZA3U.js.map +1 -0
  6. package/build/legacy/{chunk-WKSC2WCV.js → chunk-DGPLSWFJ.js} +47 -41
  7. package/build/legacy/chunk-DGPLSWFJ.js.map +1 -0
  8. package/build/legacy/chunk-OGSAAB6K.js +12 -0
  9. package/build/legacy/chunk-OGSAAB6K.js.map +1 -0
  10. package/build/legacy/chunk-TPFNVGYA.js +21 -0
  11. package/build/legacy/chunk-TPFNVGYA.js.map +1 -0
  12. package/build/legacy/chunk-TZNYJ3G7.js +25 -0
  13. package/build/legacy/chunk-TZNYJ3G7.js.map +1 -0
  14. package/build/legacy/chunk-UPODPCRD.js +12 -0
  15. package/build/legacy/chunk-UPODPCRD.js.map +1 -0
  16. package/build/legacy/components/Modal.js +7 -0
  17. package/build/legacy/components/Modal.js.map +1 -0
  18. package/build/legacy/components/ModalDescription.js +7 -0
  19. package/build/legacy/components/ModalDescription.js.map +1 -0
  20. package/build/legacy/components/ModalHeader.js +7 -0
  21. package/build/legacy/components/ModalHeader.js.map +1 -0
  22. package/build/legacy/components/ModalHeading.js +7 -0
  23. package/build/legacy/components/ModalHeading.js.map +1 -0
  24. package/build/legacy/context/confirm-modal.js +7 -2
  25. package/build/legacy/context/prompt-modal.js +7 -2
  26. package/build/legacy/hooks/useModal.js +8 -0
  27. package/build/legacy/hooks/useModal.js.map +1 -0
  28. package/build/legacy/index.js +46 -26
  29. package/build/modern/_tsup-dts-rollup.d.ts +106 -0
  30. package/build/modern/chunk-2F5TB2EV.js +25 -0
  31. package/build/modern/chunk-2F5TB2EV.js.map +1 -0
  32. package/build/modern/chunk-C5HLLGME.js +23 -0
  33. package/build/modern/chunk-C5HLLGME.js.map +1 -0
  34. package/build/modern/chunk-OGSAAB6K.js +12 -0
  35. package/build/modern/chunk-OGSAAB6K.js.map +1 -0
  36. package/build/modern/{chunk-X2GKC3IU.js → chunk-TAVCJ54A.js} +56 -47
  37. package/build/modern/chunk-TAVCJ54A.js.map +1 -0
  38. package/build/modern/chunk-TPFNVGYA.js +21 -0
  39. package/build/modern/chunk-TPFNVGYA.js.map +1 -0
  40. package/build/modern/chunk-UPODPCRD.js +12 -0
  41. package/build/modern/chunk-UPODPCRD.js.map +1 -0
  42. package/build/modern/{chunk-YHJTKBVE.js → chunk-WWG5QWXY.js} +46 -39
  43. package/build/modern/chunk-WWG5QWXY.js.map +1 -0
  44. package/build/modern/components/Modal.js +7 -0
  45. package/build/modern/components/Modal.js.map +1 -0
  46. package/build/modern/components/ModalDescription.js +7 -0
  47. package/build/modern/components/ModalDescription.js.map +1 -0
  48. package/build/modern/components/ModalHeader.js +7 -0
  49. package/build/modern/components/ModalHeader.js.map +1 -0
  50. package/build/modern/components/ModalHeading.js +7 -0
  51. package/build/modern/components/ModalHeading.js.map +1 -0
  52. package/build/modern/context/confirm-modal.js +7 -2
  53. package/build/modern/context/prompt-modal.js +7 -2
  54. package/build/modern/hooks/useModal.js +8 -0
  55. package/build/modern/hooks/useModal.js.map +1 -0
  56. package/build/modern/index.js +46 -26
  57. package/package.json +2 -2
  58. package/src/components/Modal.tsx +37 -0
  59. package/src/components/ModalDescription.tsx +23 -0
  60. package/src/components/ModalHeader.tsx +37 -0
  61. package/src/components/ModalHeading.tsx +23 -0
  62. package/src/context/confirm-modal.tsx +35 -32
  63. package/src/context/prompt-modal.tsx +25 -24
  64. package/src/hooks/useModal.ts +34 -0
  65. package/src/index.ts +5 -0
  66. package/build/legacy/chunk-UZIN7UOS.js.map +0 -1
  67. package/build/legacy/chunk-WKSC2WCV.js.map +0 -1
  68. package/build/modern/chunk-X2GKC3IU.js.map +0 -1
  69. package/build/modern/chunk-YHJTKBVE.js.map +0 -1
@@ -1,6 +1,21 @@
1
1
  import {
2
2
  Portal
3
3
  } from "./chunk-4CAT3FHV.js";
4
+ import {
5
+ Modal
6
+ } from "./chunk-TPFNVGYA.js";
7
+ import {
8
+ ModalDescription
9
+ } from "./chunk-UPODPCRD.js";
10
+ import {
11
+ ModalHeader
12
+ } from "./chunk-2F5TB2EV.js";
13
+ import {
14
+ ModalHeading
15
+ } from "./chunk-OGSAAB6K.js";
16
+ import {
17
+ ModalIcon
18
+ } from "./chunk-G3JEWPLM.js";
4
19
  import {
5
20
  Button
6
21
  } from "./chunk-2ATICEW3.js";
@@ -16,15 +31,15 @@ import {
16
31
  import {
17
32
  Field
18
33
  } from "./chunk-ZAU4JVLL.js";
19
- import {
20
- ModalIcon
21
- } from "./chunk-G3JEWPLM.js";
22
34
  import {
23
35
  trapFocus
24
36
  } from "./chunk-JIZQFTW6.js";
25
37
  import {
26
38
  $cerberusIcons
27
39
  } from "./chunk-6TXQZ3PB.js";
40
+ import {
41
+ useModal
42
+ } from "./chunk-C5HLLGME.js";
28
43
 
29
44
  // src/context/prompt-modal.tsx
30
45
  import {
@@ -37,15 +52,14 @@ import {
37
52
  } from "react";
38
53
  import { css } from "@cerberus-design/styled-system/css";
39
54
  import { hstack, vstack } from "@cerberus-design/styled-system/patterns";
40
- import { modal } from "@cerberus-design/styled-system/recipes";
41
55
  import { jsx, jsxs } from "react/jsx-runtime";
42
56
  var PromptModalContext = createContext(null);
43
57
  function PromptModal(props) {
44
- const dialogRef = useRef(null);
58
+ const { modalRef, show, close } = useModal();
45
59
  const resolveRef = useRef(null);
46
60
  const [content, setContent] = useState(null);
47
61
  const [inputValue, setInputValue] = useState("");
48
- const focusTrap = trapFocus(dialogRef);
62
+ const focusTrap = trapFocus(modalRef);
49
63
  const PromptIcon = $cerberusIcons.promptModal;
50
64
  const isValid = useMemo(
51
65
  () => inputValue === content?.key,
@@ -55,7 +69,6 @@ function PromptModal(props) {
55
69
  () => content?.kind === "destructive" ? "danger" : "action",
56
70
  [content]
57
71
  );
58
- const styles = modal();
59
72
  const handleChange = useCallback(
60
73
  (e) => {
61
74
  setInputValue(e.currentTarget.value);
@@ -68,17 +81,20 @@ function PromptModal(props) {
68
81
  if (target.value === "true") {
69
82
  resolveRef.current?.(inputValue);
70
83
  }
71
- dialogRef?.current?.close();
84
+ close();
72
85
  },
73
- [inputValue]
86
+ [inputValue, close]
87
+ );
88
+ const handleShow = useCallback(
89
+ (options) => {
90
+ return new Promise((resolve) => {
91
+ setContent({ ...options, kind: options.kind || "non-destructive" });
92
+ show();
93
+ resolveRef.current = resolve;
94
+ });
95
+ },
96
+ [show]
74
97
  );
75
- const handleShow = useCallback((options) => {
76
- return new Promise((resolve) => {
77
- setContent({ ...options, kind: options.kind || "non-destructive" });
78
- dialogRef?.current?.showModal();
79
- resolveRef.current = resolve;
80
- });
81
- }, []);
82
98
  const value = useMemo(
83
99
  () => ({
84
100
  show: handleShow
@@ -87,28 +103,19 @@ function PromptModal(props) {
87
103
  );
88
104
  return /* @__PURE__ */ jsxs(PromptModalContext.Provider, { value, children: [
89
105
  props.children,
90
- /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsxs("dialog", { className: styles.dialog, onKeyDown: focusTrap, ref: dialogRef, children: [
91
- /* @__PURE__ */ jsxs(
92
- "div",
93
- {
94
- className: vstack({
95
- alignItems: "flex-start",
96
- gap: "4"
97
- }),
98
- children: [
99
- /* @__PURE__ */ jsx(
100
- Show,
101
- {
102
- when: palette === "danger",
103
- fallback: /* @__PURE__ */ jsx(ModalIcon, { palette: "action", children: /* @__PURE__ */ jsx(PromptIcon, { size: 24 }) }),
104
- children: /* @__PURE__ */ jsx(ModalIcon, { palette: "danger", children: /* @__PURE__ */ jsx(PromptIcon, { size: 24 }) })
105
- }
106
- ),
107
- /* @__PURE__ */ jsx("h2", { className: styles.heading, children: content?.heading }),
108
- /* @__PURE__ */ jsx("p", { className: styles.description, children: content?.description })
109
- ]
110
- }
111
- ),
106
+ /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsxs(Modal, { onKeyDown: focusTrap, ref: modalRef, children: [
107
+ /* @__PURE__ */ jsxs(ModalHeader, { children: [
108
+ /* @__PURE__ */ jsx(
109
+ Show,
110
+ {
111
+ when: palette === "danger",
112
+ fallback: /* @__PURE__ */ jsx(ModalIcon, { palette: "action", children: /* @__PURE__ */ jsx(PromptIcon, { size: 24 }) }),
113
+ children: /* @__PURE__ */ jsx(ModalIcon, { palette: "danger", children: /* @__PURE__ */ jsx(PromptIcon, { size: 24 }) })
114
+ }
115
+ ),
116
+ /* @__PURE__ */ jsx(ModalHeading, { children: content?.heading }),
117
+ /* @__PURE__ */ jsx(ModalDescription, { children: content?.description })
118
+ ] }),
112
119
  /* @__PURE__ */ jsx(
113
120
  "div",
114
121
  {
@@ -197,4 +204,4 @@ export {
197
204
  PromptModal,
198
205
  usePromptModal
199
206
  };
200
- //# sourceMappingURL=chunk-YHJTKBVE.js.map
207
+ //# sourceMappingURL=chunk-WWG5QWXY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/context/prompt-modal.tsx"],"sourcesContent":["'use client'\n\nimport {\n createContext,\n useCallback,\n useContext,\n useMemo,\n useRef,\n useState,\n type ChangeEvent,\n type MouseEvent,\n type PropsWithChildren,\n} from 'react'\nimport { Portal } from '../components/Portal'\nimport { Button } from '../components/Button'\nimport { css } from '@cerberus-design/styled-system/css'\nimport { hstack, vstack } from '@cerberus-design/styled-system/patterns'\nimport { trapFocus } from '../aria-helpers/trap-focus.aria'\nimport { Input } from '../components/Input'\nimport { Field } from './field'\nimport { Label } from '../components/Label'\nimport { $cerberusIcons } from '../config/defineIcons'\nimport { ModalIcon } from '../components/ModalIcon'\nimport { Show } from '../components/Show'\nimport { useModal } from '../hooks/useModal'\nimport { Modal } from '../components/Modal'\nimport { ModalHeader } from '../components/ModalHeader'\nimport { ModalHeading } from '../components/ModalHeading'\nimport { ModalDescription } from '../components/ModalDescription'\n\n/**\n * This module provides a context and hook for the prompt modal.\n * @module\n */\n\nexport interface ShowPromptModalOptions {\n kind?: 'destructive' | 'non-destructive'\n heading: string\n description?: string\n key: string\n actionText: string\n cancelText: string\n}\nexport type PromptShowResult =\n | ((value: string | PromiseLike<string>) => void)\n | null\n\nexport interface PromptModalValue {\n show: (options: ShowPromptModalOptions) => Promise<string>\n}\n\nconst PromptModalContext = createContext<PromptModalValue | null>(null)\n\nexport interface PromptModalProviderProps {}\n\n/**\n * Provides a prompt modal to the app.\n * @example\n * ```tsx\n * // Wrap the Provider around the root of the feature.\n * <PromptModal>\n * <SomeFeatureSection />\n * </PromptModal>\n *\n * // Use the hook to show the prompt modal.\n * const prompt = usePromptModal()\n *\n * const handleClick = useCallback(async () => {\n * const accepted = await prompt.show({\n * kind: 'destructive',\n * heading: 'Delete channel?',\n * description:\n * 'This will permanently delete a channel on your account. There is no going back.',\n * key: CHANNEL_NAME,\n * actionText: 'Yes, delete channel',\n * cancelText: 'No, cancel',\n * })\n * // do something with accepted\n * }, [prompt])\n * ```\n */\nexport function PromptModal(\n props: PropsWithChildren<PromptModalProviderProps>,\n) {\n const { modalRef, show, close } = useModal()\n const resolveRef = useRef<PromptShowResult>(null)\n const [content, setContent] = useState<ShowPromptModalOptions | null>(null)\n const [inputValue, setInputValue] = useState<string>('')\n const focusTrap = trapFocus(modalRef)\n const PromptIcon = $cerberusIcons.promptModal\n\n const isValid = useMemo(\n () => inputValue === content?.key,\n [inputValue, content],\n )\n\n const palette = useMemo(\n () => (content?.kind === 'destructive' ? 'danger' : 'action'),\n [content],\n )\n\n const handleChange = useCallback(\n (e: ChangeEvent<HTMLInputElement>) => {\n setInputValue(e.currentTarget.value)\n },\n [content],\n )\n\n const handleChoice = useCallback(\n (e: MouseEvent<HTMLButtonElement>) => {\n const target = e.currentTarget as HTMLButtonElement\n if (target.value === 'true') {\n resolveRef.current?.(inputValue)\n }\n close()\n },\n [inputValue, close],\n )\n\n const handleShow = useCallback(\n (options: ShowPromptModalOptions) => {\n return new Promise<string>((resolve) => {\n setContent({ ...options, kind: options.kind || 'non-destructive' })\n show()\n resolveRef.current = resolve\n })\n },\n [show],\n )\n\n const value = useMemo(\n () => ({\n show: handleShow,\n }),\n [handleShow],\n )\n\n return (\n <PromptModalContext.Provider value={value}>\n {props.children}\n\n <Portal>\n <Modal onKeyDown={focusTrap} ref={modalRef}>\n <ModalHeader>\n <Show\n when={palette === 'danger'}\n fallback={\n <ModalIcon palette=\"action\">\n <PromptIcon size={24} />\n </ModalIcon>\n }\n >\n <ModalIcon palette=\"danger\">\n <PromptIcon size={24} />\n </ModalIcon>\n </Show>\n <ModalHeading>{content?.heading}</ModalHeading>\n <ModalDescription>{content?.description}</ModalDescription>\n </ModalHeader>\n\n <div\n className={vstack({\n alignItems: 'flex-start',\n mt: '4',\n mb: '8',\n })}\n >\n <Field invalid={!isValid}>\n <Label htmlFor=\"confirm\" size=\"md\">\n Type\n <strong\n className={css({\n textTransform: 'uppercase',\n })}\n >\n {content?.key}\n </strong>\n to confirm\n </Label>\n <Input\n id=\"confirm\"\n name=\"confirm\"\n onChange={handleChange}\n type=\"text\"\n />\n </Field>\n </div>\n\n <div\n className={hstack({\n justifyContent: 'stretch',\n gap: '4',\n })}\n >\n <Button\n autoFocus\n className={css({\n w: '1/2',\n })}\n disabled={!isValid}\n name=\"confirm\"\n onClick={handleChoice}\n palette={palette}\n value=\"true\"\n >\n {content?.actionText}\n </Button>\n <Button\n className={css({\n w: '1/2',\n })}\n name=\"cancel\"\n onClick={handleChoice}\n usage=\"outlined\"\n value=\"false\"\n >\n {content?.cancelText}\n </Button>\n </div>\n </Modal>\n </Portal>\n </PromptModalContext.Provider>\n )\n}\n\nexport function usePromptModal(): PromptModalValue {\n const context = useContext(PromptModalContext)\n if (context === null) {\n throw new Error('usePromptModal must be used within a PromptModal Provider')\n }\n return context\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,7 @@
1
+ import {
2
+ Modal
3
+ } from "../chunk-TPFNVGYA.js";
4
+ export {
5
+ Modal
6
+ };
7
+ //# sourceMappingURL=Modal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,7 @@
1
+ import {
2
+ ModalDescription
3
+ } from "../chunk-UPODPCRD.js";
4
+ export {
5
+ ModalDescription
6
+ };
7
+ //# sourceMappingURL=ModalDescription.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,7 @@
1
+ import {
2
+ ModalHeader
3
+ } from "../chunk-2F5TB2EV.js";
4
+ export {
5
+ ModalHeader
6
+ };
7
+ //# sourceMappingURL=ModalHeader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,7 @@
1
+ import {
2
+ ModalHeading
3
+ } from "../chunk-OGSAAB6K.js";
4
+ export {
5
+ ModalHeading
6
+ };
7
+ //# sourceMappingURL=ModalHeading.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -2,14 +2,19 @@
2
2
  import {
3
3
  ConfirmModal,
4
4
  useConfirmModal
5
- } from "../chunk-X2GKC3IU.js";
5
+ } from "../chunk-TAVCJ54A.js";
6
6
  import "../chunk-4CAT3FHV.js";
7
+ import "../chunk-TPFNVGYA.js";
8
+ import "../chunk-UPODPCRD.js";
9
+ import "../chunk-2F5TB2EV.js";
10
+ import "../chunk-OGSAAB6K.js";
11
+ import "../chunk-G3JEWPLM.js";
7
12
  import "../chunk-2ATICEW3.js";
8
13
  import "../chunk-4O4QFF4S.js";
9
- import "../chunk-G3JEWPLM.js";
10
14
  import "../chunk-JIZQFTW6.js";
11
15
  import "../chunk-6TXQZ3PB.js";
12
16
  import "../chunk-C45DY4VE.js";
17
+ import "../chunk-C5HLLGME.js";
13
18
  export {
14
19
  ConfirmModal,
15
20
  useConfirmModal
@@ -2,17 +2,22 @@
2
2
  import {
3
3
  PromptModal,
4
4
  usePromptModal
5
- } from "../chunk-YHJTKBVE.js";
5
+ } from "../chunk-WWG5QWXY.js";
6
6
  import "../chunk-4CAT3FHV.js";
7
+ import "../chunk-TPFNVGYA.js";
8
+ import "../chunk-UPODPCRD.js";
9
+ import "../chunk-2F5TB2EV.js";
10
+ import "../chunk-OGSAAB6K.js";
11
+ import "../chunk-G3JEWPLM.js";
7
12
  import "../chunk-2ATICEW3.js";
8
13
  import "../chunk-5GEC53G7.js";
9
14
  import "../chunk-CU7HXAKM.js";
10
15
  import "../chunk-4O4QFF4S.js";
11
16
  import "../chunk-ZAU4JVLL.js";
12
- import "../chunk-G3JEWPLM.js";
13
17
  import "../chunk-JIZQFTW6.js";
14
18
  import "../chunk-6TXQZ3PB.js";
15
19
  import "../chunk-C45DY4VE.js";
20
+ import "../chunk-C5HLLGME.js";
16
21
  export {
17
22
  PromptModal,
18
23
  usePromptModal
@@ -0,0 +1,8 @@
1
+ "use client";
2
+ import {
3
+ useModal
4
+ } from "../chunk-C5HLLGME.js";
5
+ export {
6
+ useModal
7
+ };
8
+ //# sourceMappingURL=useModal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1,7 +1,26 @@
1
+ import {
2
+ Toggle
3
+ } from "./chunk-TAZI77TP.js";
4
+ import {
5
+ ConfirmModal,
6
+ useConfirmModal
7
+ } from "./chunk-TAVCJ54A.js";
1
8
  import {
2
9
  PromptModal,
3
10
  usePromptModal
4
- } from "./chunk-YHJTKBVE.js";
11
+ } from "./chunk-WWG5QWXY.js";
12
+ import {
13
+ Portal
14
+ } from "./chunk-4CAT3FHV.js";
15
+ import {
16
+ Radio
17
+ } from "./chunk-WE3JNSNO.js";
18
+ import {
19
+ Tab
20
+ } from "./chunk-HBEEHHON.js";
21
+ import {
22
+ TabList
23
+ } from "./chunk-X2JMXTBH.js";
5
24
  import {
6
25
  TabPanel
7
26
  } from "./chunk-67S42J4B.js";
@@ -12,12 +31,20 @@ import {
12
31
  Textarea
13
32
  } from "./chunk-TCO46FK7.js";
14
33
  import {
15
- Toggle
16
- } from "./chunk-TAZI77TP.js";
34
+ Modal
35
+ } from "./chunk-TPFNVGYA.js";
17
36
  import {
18
- ConfirmModal,
19
- useConfirmModal
20
- } from "./chunk-X2GKC3IU.js";
37
+ ModalDescription
38
+ } from "./chunk-UPODPCRD.js";
39
+ import {
40
+ ModalHeader
41
+ } from "./chunk-2F5TB2EV.js";
42
+ import {
43
+ ModalHeading
44
+ } from "./chunk-OGSAAB6K.js";
45
+ import {
46
+ ModalIcon
47
+ } from "./chunk-G3JEWPLM.js";
21
48
  import {
22
49
  NavMenuLink
23
50
  } from "./chunk-6DIGPXAD.js";
@@ -33,17 +60,12 @@ import {
33
60
  useNavMenuContext
34
61
  } from "./chunk-KJUCHZHV.js";
35
62
  import {
36
- Portal
37
- } from "./chunk-4CAT3FHV.js";
38
- import {
39
- Radio
40
- } from "./chunk-WE3JNSNO.js";
41
- import {
42
- Tab
43
- } from "./chunk-HBEEHHON.js";
44
- import {
45
- TabList
46
- } from "./chunk-X2JMXTBH.js";
63
+ MODE_KEY,
64
+ THEME_KEY,
65
+ ThemeProvider,
66
+ useTheme,
67
+ useThemeContext
68
+ } from "./chunk-SXXWC6UD.js";
47
69
  import {
48
70
  useToggle
49
71
  } from "./chunk-QEA6N6TN.js";
@@ -76,9 +98,6 @@ import {
76
98
  Field,
77
99
  useFieldContext
78
100
  } from "./chunk-ZAU4JVLL.js";
79
- import {
80
- ModalIcon
81
- } from "./chunk-G3JEWPLM.js";
82
101
  import "./chunk-55J6XMHW.js";
83
102
  import {
84
103
  createNavTriggerProps
@@ -100,12 +119,8 @@ import {
100
119
  } from "./chunk-6TXQZ3PB.js";
101
120
  import "./chunk-C45DY4VE.js";
102
121
  import {
103
- MODE_KEY,
104
- THEME_KEY,
105
- ThemeProvider,
106
- useTheme,
107
- useThemeContext
108
- } from "./chunk-SXXWC6UD.js";
122
+ useModal
123
+ } from "./chunk-C5HLLGME.js";
109
124
  export {
110
125
  $cerberusIcons,
111
126
  Button,
@@ -118,6 +133,10 @@ export {
118
133
  Input,
119
134
  Label,
120
135
  MODE_KEY,
136
+ Modal,
137
+ ModalDescription,
138
+ ModalHeader,
139
+ ModalHeading,
121
140
  ModalIcon,
122
141
  NavMenu,
123
142
  NavMenuLink,
@@ -144,6 +163,7 @@ export {
144
163
  useConfirmModal,
145
164
  useFeatureFlags,
146
165
  useFieldContext,
166
+ useModal,
147
167
  useNavMenuContext,
148
168
  usePromptModal,
149
169
  useTabsContext,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cerberus-design/react",
3
- "version": "0.6.1-next-8062b70",
3
+ "version": "0.6.1-next-fa4208e",
4
4
  "description": "The Cerberus Design React component library.",
5
5
  "browserslist": "> 0.25%, not dead",
6
6
  "sideEffects": false,
@@ -23,7 +23,7 @@
23
23
  "react-dom": "^18",
24
24
  "tsup": "^8.1.0",
25
25
  "@cerberus-design/configs": "0.0.0",
26
- "@cerberus-design/styled-system": "0.6.1-next-8062b70"
26
+ "@cerberus-design/styled-system": "0.6.1-next-fa4208e"
27
27
  },
28
28
  "publishConfig": {
29
29
  "access": "public"
@@ -0,0 +1,37 @@
1
+ import { cx } from '@cerberus-design/styled-system/css'
2
+ import { modal } from '@cerberus-design/styled-system/recipes'
3
+ import { forwardRef, type ForwardedRef, type HTMLAttributes } from 'react'
4
+
5
+ /**
6
+ * This module contains the Modal root component for a customizable modal.
7
+ * @module
8
+ */
9
+
10
+ // Modal
11
+
12
+ export type ModalProps = HTMLAttributes<HTMLDialogElement>
13
+
14
+ function ModalEl(props: ModalProps, ref: ForwardedRef<HTMLDialogElement>) {
15
+ return (
16
+ <dialog
17
+ {...props}
18
+ className={cx(props.className, modal().dialog)}
19
+ ref={ref}
20
+ />
21
+ )
22
+ }
23
+
24
+ /**
25
+ * The Modal component is the root element for a customizable modal.
26
+ * @example
27
+ * ```tsx
28
+ * const { modalRef } = useModal()
29
+ *
30
+ * <Modal ref={modalRef}>
31
+ * <ModalIcon icon={$cerberusIcons.alert} />
32
+ * <h2>Modal Heading</h2>
33
+ * <p>Modal description</p>
34
+ * </Modal>
35
+ * ```
36
+ */
37
+ export const Modal = forwardRef(ModalEl)
@@ -0,0 +1,23 @@
1
+ import { cx } from '@cerberus-design/styled-system/css'
2
+ import { modal } from '@cerberus-design/styled-system/recipes'
3
+ import type { HTMLAttributes } from 'react'
4
+
5
+ /**
6
+ * This module contains the ModalDescription component for a customizable modal.
7
+ * @module
8
+ */
9
+
10
+ export type ModalDescriptionProps = HTMLAttributes<HTMLParagraphElement>
11
+
12
+ /**
13
+ * The ModalDescription component is a heading element for a customizable modal.
14
+ * @example
15
+ * ```tsx
16
+ * <Modal>
17
+ * <ModalDescription>Modal Heading</ModalDescription>
18
+ * </Modal>
19
+ * ```
20
+ */
21
+ export function ModalDescription(props: ModalDescriptionProps) {
22
+ return <p {...props} className={cx(props.className, modal().description)} />
23
+ }
@@ -0,0 +1,37 @@
1
+ import { cx } from '@cerberus-design/styled-system/css'
2
+ import { vstack } from '@cerberus-design/styled-system/patterns'
3
+ import type { HTMLAttributes } from 'react'
4
+
5
+ /**
6
+ * This module contains the ModalHeader component for a customizable modal.
7
+ * @module
8
+ */
9
+
10
+ export type ModalHeaderProps = HTMLAttributes<HTMLDivElement>
11
+
12
+ /**
13
+ * The ModalHeader component is a header element for a customizable modal.
14
+ * @example
15
+ * ```tsx
16
+ * <Modal>
17
+ * <ModalHeader>
18
+ * <h2>Modal Heading</h2>
19
+ * </ModalHeader>
20
+ * </Modal>
21
+ * ```
22
+ */
23
+ export function ModalHeader(props: ModalHeaderProps) {
24
+ return (
25
+ <div
26
+ {...props}
27
+ className={cx(
28
+ props.className,
29
+ vstack({
30
+ alignItems: 'flex-start',
31
+ gap: '4',
32
+ mb: '8',
33
+ }),
34
+ )}
35
+ />
36
+ )
37
+ }
@@ -0,0 +1,23 @@
1
+ import { cx } from '@cerberus-design/styled-system/css'
2
+ import { modal } from '@cerberus-design/styled-system/recipes'
3
+ import type { HTMLAttributes } from 'react'
4
+
5
+ /**
6
+ * This module contains the ModalHeading component for a customizable modal.
7
+ * @module
8
+ */
9
+
10
+ export type ModalHeadingProps = HTMLAttributes<HTMLParagraphElement>
11
+
12
+ /**
13
+ * The ModalHeading component is a heading element for a customizable modal.
14
+ * @example
15
+ * ```tsx
16
+ * <Modal>
17
+ * <ModalHeading>Modal Heading</ModalHeading>
18
+ * </Modal>
19
+ * ```
20
+ */
21
+ export function ModalHeading(props: ModalHeadingProps) {
22
+ return <p {...props} className={cx(props.className, modal().heading)} />
23
+ }
@@ -13,12 +13,16 @@ import {
13
13
  import { Portal } from '../components/Portal'
14
14
  import { Button } from '../components/Button'
15
15
  import { css } from '@cerberus-design/styled-system/css'
16
- import { hstack, vstack } from '@cerberus-design/styled-system/patterns'
16
+ import { hstack } from '@cerberus-design/styled-system/patterns'
17
17
  import { $cerberusIcons } from '../config/defineIcons'
18
- import { modal } from '@cerberus-design/styled-system/recipes'
19
18
  import { trapFocus } from '../aria-helpers/trap-focus.aria'
20
19
  import { ModalIcon } from '../components/ModalIcon'
21
20
  import { Show } from '../components/Show'
21
+ import { Modal } from '../components/Modal'
22
+ import { useModal } from '../hooks/useModal'
23
+ import { ModalHeader } from '../components/ModalHeader'
24
+ import { ModalHeading } from '../components/ModalHeading'
25
+ import { ModalDescription } from '../components/ModalDescription'
22
26
 
23
27
  /**
24
28
  * This module provides a context and hook for the confirm modal.
@@ -71,34 +75,39 @@ export interface ConfirmModalProviderProps {}
71
75
  export function ConfirmModal(
72
76
  props: PropsWithChildren<ConfirmModalProviderProps>,
73
77
  ) {
74
- const dialogRef = useRef<HTMLDialogElement>(null)
78
+ const { modalRef, show, close } = useModal()
75
79
  const resolveRef = useRef<ShowResult>(null)
76
80
  const [content, setContent] = useState<ShowConfirmModalOptions | null>(null)
77
- const focusTrap = trapFocus(dialogRef)
81
+ const focusTrap = trapFocus(modalRef)
78
82
  const ConfirmIcon = $cerberusIcons.confirmModal
79
83
 
80
84
  const palette = useMemo(
81
85
  () => (content?.kind === 'destructive' ? 'danger' : 'action'),
82
86
  [content],
83
87
  )
84
- const styles = modal()
85
88
 
86
- const handleChoice = useCallback((e: MouseEvent<HTMLButtonElement>) => {
87
- const target = e.currentTarget as HTMLButtonElement
88
- if (target.value === 'true') {
89
- resolveRef.current?.(true)
90
- }
91
- resolveRef.current?.(false)
92
- dialogRef?.current?.close()
93
- }, [])
89
+ const handleChoice = useCallback(
90
+ (e: MouseEvent<HTMLButtonElement>) => {
91
+ const target = e.currentTarget as HTMLButtonElement
92
+ if (target.value === 'true') {
93
+ resolveRef.current?.(true)
94
+ }
95
+ resolveRef.current?.(false)
96
+ close()
97
+ },
98
+ [close],
99
+ )
94
100
 
95
- const handleShow = useCallback((options: ShowConfirmModalOptions) => {
96
- return new Promise<boolean>((resolve) => {
97
- setContent({ ...options, kind: options.kind || 'non-destructive' })
98
- dialogRef?.current?.showModal()
99
- resolveRef.current = resolve
100
- })
101
- }, [])
101
+ const handleShow = useCallback(
102
+ (options: ShowConfirmModalOptions) => {
103
+ return new Promise<boolean>((resolve) => {
104
+ setContent({ ...options, kind: options.kind || 'non-destructive' })
105
+ show()
106
+ resolveRef.current = resolve
107
+ })
108
+ },
109
+ [show],
110
+ )
102
111
 
103
112
  const value = useMemo(
104
113
  () => ({
@@ -112,14 +121,8 @@ export function ConfirmModal(
112
121
  {props.children}
113
122
 
114
123
  <Portal>
115
- <dialog className={styles.dialog} onKeyDown={focusTrap} ref={dialogRef}>
116
- <section
117
- className={vstack({
118
- alignItems: 'flex-start',
119
- gap: '4',
120
- mb: '8',
121
- })}
122
- >
124
+ <Modal onKeyDown={focusTrap} ref={modalRef}>
125
+ <ModalHeader>
123
126
  <Show
124
127
  when={palette === 'danger'}
125
128
  fallback={
@@ -132,9 +135,9 @@ export function ConfirmModal(
132
135
  <ConfirmIcon size={24} />
133
136
  </ModalIcon>
134
137
  </Show>
135
- <h2 className={styles.heading}>{content?.heading}</h2>
136
- <p className={styles.description}>{content?.description}</p>
137
- </section>
138
+ <ModalHeading>{content?.heading}</ModalHeading>
139
+ <ModalDescription>{content?.description}</ModalDescription>
140
+ </ModalHeader>
138
141
 
139
142
  <div
140
143
  className={hstack({
@@ -165,7 +168,7 @@ export function ConfirmModal(
165
168
  {content?.cancelText}
166
169
  </Button>
167
170
  </div>
168
- </dialog>
171
+ </Modal>
169
172
  </Portal>
170
173
  </ConfirmModalContext.Provider>
171
174
  )