@cerberus-design/react 0.6.1-next-2d28489 → 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 (92) hide show
  1. package/build/legacy/_tsup-dts-rollup.d.ts +119 -9
  2. package/build/legacy/chunk-2F5TB2EV.js +25 -0
  3. package/build/legacy/chunk-2F5TB2EV.js.map +1 -0
  4. package/build/legacy/{chunk-7ISHDUYN.js → chunk-5GEC53G7.js} +4 -4
  5. package/build/legacy/{chunk-JJGZRBIR.js → chunk-CU7HXAKM.js} +4 -4
  6. package/build/legacy/chunk-D3ZXZA3U.js +155 -0
  7. package/build/legacy/chunk-D3ZXZA3U.js.map +1 -0
  8. package/build/legacy/{chunk-SNSBODYR.js → chunk-DGPLSWFJ.js} +55 -71
  9. package/build/legacy/chunk-DGPLSWFJ.js.map +1 -0
  10. package/build/legacy/chunk-G3JEWPLM.js +29 -0
  11. package/build/legacy/chunk-G3JEWPLM.js.map +1 -0
  12. package/build/legacy/chunk-OGSAAB6K.js +12 -0
  13. package/build/legacy/chunk-OGSAAB6K.js.map +1 -0
  14. package/build/legacy/chunk-TPFNVGYA.js +21 -0
  15. package/build/legacy/chunk-TPFNVGYA.js.map +1 -0
  16. package/build/legacy/chunk-TZNYJ3G7.js +25 -0
  17. package/build/legacy/chunk-TZNYJ3G7.js.map +1 -0
  18. package/build/legacy/chunk-UPODPCRD.js +12 -0
  19. package/build/legacy/chunk-UPODPCRD.js.map +1 -0
  20. package/build/legacy/components/Input.js +2 -2
  21. package/build/legacy/components/Label.js +2 -2
  22. package/build/legacy/components/Modal.js +7 -0
  23. package/build/legacy/components/Modal.js.map +1 -0
  24. package/build/legacy/components/ModalDescription.js +7 -0
  25. package/build/legacy/components/ModalDescription.js.map +1 -0
  26. package/build/legacy/components/ModalHeader.js +7 -0
  27. package/build/legacy/components/ModalHeader.js.map +1 -0
  28. package/build/legacy/components/ModalHeading.js +7 -0
  29. package/build/legacy/components/ModalHeading.js.map +1 -0
  30. package/build/legacy/components/ModalIcon.js +7 -0
  31. package/build/legacy/components/ModalIcon.js.map +1 -0
  32. package/build/legacy/context/confirm-modal.js +7 -3
  33. package/build/legacy/context/prompt-modal.js +10 -7
  34. package/build/legacy/hooks/useModal.js +8 -0
  35. package/build/legacy/hooks/useModal.js.map +1 -0
  36. package/build/legacy/index.js +59 -39
  37. package/build/modern/_tsup-dts-rollup.d.ts +119 -9
  38. package/build/modern/chunk-2F5TB2EV.js +25 -0
  39. package/build/modern/chunk-2F5TB2EV.js.map +1 -0
  40. package/build/modern/{chunk-7ISHDUYN.js → chunk-5GEC53G7.js} +4 -4
  41. package/build/modern/chunk-C5HLLGME.js +23 -0
  42. package/build/modern/chunk-C5HLLGME.js.map +1 -0
  43. package/build/modern/{chunk-JJGZRBIR.js → chunk-CU7HXAKM.js} +4 -4
  44. package/build/modern/chunk-G3JEWPLM.js +29 -0
  45. package/build/modern/chunk-G3JEWPLM.js.map +1 -0
  46. package/build/modern/chunk-OGSAAB6K.js +12 -0
  47. package/build/modern/chunk-OGSAAB6K.js.map +1 -0
  48. package/build/modern/chunk-TAVCJ54A.js +154 -0
  49. package/build/modern/chunk-TAVCJ54A.js.map +1 -0
  50. package/build/modern/chunk-TPFNVGYA.js +21 -0
  51. package/build/modern/chunk-TPFNVGYA.js.map +1 -0
  52. package/build/modern/chunk-UPODPCRD.js +12 -0
  53. package/build/modern/chunk-UPODPCRD.js.map +1 -0
  54. package/build/modern/{chunk-FZ75OJLJ.js → chunk-WWG5QWXY.js} +54 -69
  55. package/build/modern/chunk-WWG5QWXY.js.map +1 -0
  56. package/build/modern/components/Input.js +2 -2
  57. package/build/modern/components/Label.js +2 -2
  58. package/build/modern/components/Modal.js +7 -0
  59. package/build/modern/components/Modal.js.map +1 -0
  60. package/build/modern/components/ModalDescription.js +7 -0
  61. package/build/modern/components/ModalDescription.js.map +1 -0
  62. package/build/modern/components/ModalHeader.js +7 -0
  63. package/build/modern/components/ModalHeader.js.map +1 -0
  64. package/build/modern/components/ModalHeading.js +7 -0
  65. package/build/modern/components/ModalHeading.js.map +1 -0
  66. package/build/modern/components/ModalIcon.js +7 -0
  67. package/build/modern/components/ModalIcon.js.map +1 -0
  68. package/build/modern/context/confirm-modal.js +7 -3
  69. package/build/modern/context/prompt-modal.js +10 -7
  70. package/build/modern/hooks/useModal.js +8 -0
  71. package/build/modern/hooks/useModal.js.map +1 -0
  72. package/build/modern/index.js +59 -39
  73. package/package.json +2 -2
  74. package/src/components/Modal.tsx +37 -0
  75. package/src/components/ModalDescription.tsx +23 -0
  76. package/src/components/ModalHeader.tsx +37 -0
  77. package/src/components/ModalHeading.tsx +23 -0
  78. package/src/components/ModalIcon.tsx +28 -0
  79. package/src/context/confirm-modal.tsx +50 -70
  80. package/src/context/prompt-modal.tsx +41 -63
  81. package/src/hooks/useModal.ts +34 -0
  82. package/src/index.ts +6 -0
  83. package/build/legacy/chunk-BLJ4SRAF.js +0 -167
  84. package/build/legacy/chunk-BLJ4SRAF.js.map +0 -1
  85. package/build/legacy/chunk-SNSBODYR.js.map +0 -1
  86. package/build/modern/chunk-4GURONLE.js +0 -165
  87. package/build/modern/chunk-4GURONLE.js.map +0 -1
  88. package/build/modern/chunk-FZ75OJLJ.js.map +0 -1
  89. /package/build/legacy/{chunk-7ISHDUYN.js.map → chunk-5GEC53G7.js.map} +0 -0
  90. /package/build/legacy/{chunk-JJGZRBIR.js.map → chunk-CU7HXAKM.js.map} +0 -0
  91. /package/build/modern/{chunk-7ISHDUYN.js.map → chunk-5GEC53G7.js.map} +0 -0
  92. /package/build/modern/{chunk-JJGZRBIR.js.map → chunk-CU7HXAKM.js.map} +0 -0
@@ -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,33 +1,14 @@
1
- import {
2
- Tag
3
- } from "./chunk-Z6IWNVPN.js";
4
- import {
5
- Textarea
6
- } from "./chunk-TCO46FK7.js";
7
1
  import {
8
2
  Toggle
9
3
  } from "./chunk-TAZI77TP.js";
10
- import {
11
- PromptModal,
12
- PromptModalIcon,
13
- usePromptModal
14
- } from "./chunk-FZ75OJLJ.js";
15
4
  import {
16
5
  ConfirmModal,
17
- ConfirmModalIcon,
18
6
  useConfirmModal
19
- } from "./chunk-4GURONLE.js";
7
+ } from "./chunk-TAVCJ54A.js";
20
8
  import {
21
- NavMenuList,
22
- getPosition
23
- } from "./chunk-PMCYXRAH.js";
24
- import {
25
- NavMenuTrigger
26
- } from "./chunk-RPZAPUCF.js";
27
- import {
28
- NavMenu,
29
- useNavMenuContext
30
- } from "./chunk-KJUCHZHV.js";
9
+ PromptModal,
10
+ usePromptModal
11
+ } from "./chunk-WWG5QWXY.js";
31
12
  import {
32
13
  Portal
33
14
  } from "./chunk-4CAT3FHV.js";
@@ -43,6 +24,48 @@ import {
43
24
  import {
44
25
  TabPanel
45
26
  } from "./chunk-67S42J4B.js";
27
+ import {
28
+ Tag
29
+ } from "./chunk-Z6IWNVPN.js";
30
+ import {
31
+ Textarea
32
+ } from "./chunk-TCO46FK7.js";
33
+ import {
34
+ Modal
35
+ } from "./chunk-TPFNVGYA.js";
36
+ import {
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";
48
+ import {
49
+ NavMenuLink
50
+ } from "./chunk-6DIGPXAD.js";
51
+ import {
52
+ NavMenuList,
53
+ getPosition
54
+ } from "./chunk-PMCYXRAH.js";
55
+ import {
56
+ NavMenuTrigger
57
+ } from "./chunk-RPZAPUCF.js";
58
+ import {
59
+ NavMenu,
60
+ useNavMenuContext
61
+ } from "./chunk-KJUCHZHV.js";
62
+ import {
63
+ MODE_KEY,
64
+ THEME_KEY,
65
+ ThemeProvider,
66
+ useTheme,
67
+ useThemeContext
68
+ } from "./chunk-SXXWC6UD.js";
46
69
  import {
47
70
  useToggle
48
71
  } from "./chunk-QEA6N6TN.js";
@@ -64,20 +87,17 @@ import {
64
87
  } from "./chunk-SLHX5K6I.js";
65
88
  import {
66
89
  Input
67
- } from "./chunk-7ISHDUYN.js";
90
+ } from "./chunk-5GEC53G7.js";
68
91
  import {
69
92
  Label
70
- } from "./chunk-JJGZRBIR.js";
93
+ } from "./chunk-CU7HXAKM.js";
94
+ import {
95
+ Show
96
+ } from "./chunk-4O4QFF4S.js";
71
97
  import {
72
98
  Field,
73
99
  useFieldContext
74
100
  } from "./chunk-ZAU4JVLL.js";
75
- import {
76
- NavMenuLink
77
- } from "./chunk-6DIGPXAD.js";
78
- import {
79
- Show
80
- } from "./chunk-4O4QFF4S.js";
81
101
  import "./chunk-55J6XMHW.js";
82
102
  import {
83
103
  createNavTriggerProps
@@ -99,17 +119,12 @@ import {
99
119
  } from "./chunk-6TXQZ3PB.js";
100
120
  import "./chunk-C45DY4VE.js";
101
121
  import {
102
- MODE_KEY,
103
- THEME_KEY,
104
- ThemeProvider,
105
- useTheme,
106
- useThemeContext
107
- } from "./chunk-SXXWC6UD.js";
122
+ useModal
123
+ } from "./chunk-C5HLLGME.js";
108
124
  export {
109
125
  $cerberusIcons,
110
126
  Button,
111
127
  ConfirmModal,
112
- ConfirmModalIcon,
113
128
  FeatureFlag,
114
129
  FeatureFlags,
115
130
  Field,
@@ -118,13 +133,17 @@ export {
118
133
  Input,
119
134
  Label,
120
135
  MODE_KEY,
136
+ Modal,
137
+ ModalDescription,
138
+ ModalHeader,
139
+ ModalHeading,
140
+ ModalIcon,
121
141
  NavMenu,
122
142
  NavMenuLink,
123
143
  NavMenuList,
124
144
  NavMenuTrigger,
125
145
  Portal,
126
146
  PromptModal,
127
- PromptModalIcon,
128
147
  Radio,
129
148
  Show,
130
149
  THEME_KEY,
@@ -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-2d28489",
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-2d28489"
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
+ }
@@ -0,0 +1,28 @@
1
+ import { cx } from '@cerberus-design/styled-system/css'
2
+ import { circle } from '@cerberus-design/styled-system/patterns'
3
+ import {
4
+ modalIcon,
5
+ type ModalIconVariantProps,
6
+ } from '@cerberus-design/styled-system/recipes'
7
+ import type { HTMLAttributes, PropsWithChildren } from 'react'
8
+
9
+ export type ModalIconBaseProps = HTMLAttributes<HTMLDivElement>
10
+ export type ModalIconProps = ModalIconBaseProps & ModalIconVariantProps
11
+
12
+ export function ModalIcon(props: PropsWithChildren<ModalIconProps>) {
13
+ const { palette, ...nativeProps } = props
14
+ return (
15
+ <div
16
+ {...nativeProps}
17
+ className={cx(
18
+ nativeProps.className,
19
+ modalIcon({
20
+ palette,
21
+ }),
22
+ circle(),
23
+ )}
24
+ >
25
+ {props.children}
26
+ </div>
27
+ )
28
+ }
@@ -12,15 +12,17 @@ import {
12
12
  } from 'react'
13
13
  import { Portal } from '../components/Portal'
14
14
  import { Button } from '../components/Button'
15
- import { css, cx } from '@cerberus-design/styled-system/css'
16
- import { circle, hstack, vstack } from '@cerberus-design/styled-system/patterns'
15
+ import { css } from '@cerberus-design/styled-system/css'
16
+ import { hstack } from '@cerberus-design/styled-system/patterns'
17
17
  import { $cerberusIcons } from '../config/defineIcons'
18
- import {
19
- confirmModal,
20
- type ConfirmModalVariantProps,
21
- } from '@cerberus-design/styled-system/recipes'
22
18
  import { trapFocus } from '../aria-helpers/trap-focus.aria'
19
+ import { ModalIcon } from '../components/ModalIcon'
23
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'
24
26
 
25
27
  /**
26
28
  * This module provides a context and hook for the confirm modal.
@@ -73,33 +75,39 @@ export interface ConfirmModalProviderProps {}
73
75
  export function ConfirmModal(
74
76
  props: PropsWithChildren<ConfirmModalProviderProps>,
75
77
  ) {
76
- const dialogRef = useRef<HTMLDialogElement>(null)
78
+ const { modalRef, show, close } = useModal()
77
79
  const resolveRef = useRef<ShowResult>(null)
78
80
  const [content, setContent] = useState<ShowConfirmModalOptions | null>(null)
79
- const focusTrap = trapFocus(dialogRef)
81
+ const focusTrap = trapFocus(modalRef)
82
+ const ConfirmIcon = $cerberusIcons.confirmModal
80
83
 
81
84
  const palette = useMemo(
82
85
  () => (content?.kind === 'destructive' ? 'danger' : 'action'),
83
86
  [content],
84
87
  )
85
- const styles = confirmModal({ palette })
86
88
 
87
- const handleChoice = useCallback((e: MouseEvent<HTMLButtonElement>) => {
88
- const target = e.currentTarget as HTMLButtonElement
89
- if (target.value === 'true') {
90
- resolveRef.current?.(true)
91
- }
92
- resolveRef.current?.(false)
93
- dialogRef?.current?.close()
94
- }, [])
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
+ )
95
100
 
96
- const handleShow = useCallback((options: ShowConfirmModalOptions) => {
97
- return new Promise<boolean>((resolve) => {
98
- setContent({ ...options, kind: options.kind || 'non-destructive' })
99
- dialogRef?.current?.showModal()
100
- resolveRef.current = resolve
101
- })
102
- }, [])
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
+ )
103
111
 
104
112
  const value = useMemo(
105
113
  () => ({
@@ -113,22 +121,26 @@ export function ConfirmModal(
113
121
  {props.children}
114
122
 
115
123
  <Portal>
116
- <dialog className={styles.dialog} onKeyDown={focusTrap} ref={dialogRef}>
117
- <div
118
- className={vstack({
119
- alignItems: 'flex-start',
120
- gap: '4',
121
- mb: '8',
122
- })}
123
- >
124
- <ConfirmModalIcon palette={palette} />
125
- <h2 className={styles.heading}>{content?.heading}</h2>
126
- <p className={styles.description}>{content?.description}</p>
127
- </div>
124
+ <Modal onKeyDown={focusTrap} ref={modalRef}>
125
+ <ModalHeader>
126
+ <Show
127
+ when={palette === 'danger'}
128
+ fallback={
129
+ <ModalIcon palette="action">
130
+ <ConfirmIcon size={24} />
131
+ </ModalIcon>
132
+ }
133
+ >
134
+ <ModalIcon palette="danger">
135
+ <ConfirmIcon size={24} />
136
+ </ModalIcon>
137
+ </Show>
138
+ <ModalHeading>{content?.heading}</ModalHeading>
139
+ <ModalDescription>{content?.description}</ModalDescription>
140
+ </ModalHeader>
128
141
 
129
142
  <div
130
143
  className={hstack({
131
- justifyContent: 'stretch',
132
144
  gap: '4',
133
145
  })}
134
146
  >
@@ -156,44 +168,12 @@ export function ConfirmModal(
156
168
  {content?.cancelText}
157
169
  </Button>
158
170
  </div>
159
- </dialog>
171
+ </Modal>
160
172
  </Portal>
161
173
  </ConfirmModalContext.Provider>
162
174
  )
163
175
  }
164
176
 
165
- // This is to help show the variant styles for the icon since Panda is
166
- // not syncing correctly for the danger variant.
167
- export function ConfirmModalIcon(props: ConfirmModalVariantProps) {
168
- const InfoIcon = $cerberusIcons.confirmModal
169
- return (
170
- <Show
171
- when={props.palette === 'danger'}
172
- fallback={
173
- <div className={cx(confirmModal().icon, circle())}>
174
- <InfoIcon size={24} />
175
- </div>
176
- }
177
- >
178
- <div
179
- className={cx(
180
- confirmModal({
181
- palette: 'danger',
182
- }).icon,
183
- circle({
184
- bgColor: 'danger.surface.initial',
185
- }),
186
- )}
187
- style={{
188
- color: 'var(--cerberus-colors-danger-text-100)',
189
- }}
190
- >
191
- <InfoIcon size={24} />
192
- </div>
193
- </Show>
194
- )
195
- }
196
-
197
177
  export function useConfirmModal(): ConfirmModalValue {
198
178
  const context = useContext(ConfirmModalContext)
199
179
  if (context === null) {
@@ -13,19 +13,20 @@ import {
13
13
  } from 'react'
14
14
  import { Portal } from '../components/Portal'
15
15
  import { Button } from '../components/Button'
16
- import { css, cx } from '@cerberus-design/styled-system/css'
17
- import { circle, hstack, vstack } from '@cerberus-design/styled-system/patterns'
18
- import {
19
- confirmModal,
20
- type ConfirmModalVariantProps,
21
- } from '@cerberus-design/styled-system/recipes'
16
+ import { css } from '@cerberus-design/styled-system/css'
17
+ import { hstack, vstack } from '@cerberus-design/styled-system/patterns'
22
18
  import { trapFocus } from '../aria-helpers/trap-focus.aria'
23
19
  import { Input } from '../components/Input'
24
20
  import { Field } from './field'
25
21
  import { Label } from '../components/Label'
26
- import { ConfirmModalIcon } from './confirm-modal'
27
22
  import { $cerberusIcons } from '../config/defineIcons'
23
+ import { ModalIcon } from '../components/ModalIcon'
28
24
  import { Show } from '../components/Show'
25
+ import { useModal } from '../hooks/useModal'
26
+ import { Modal } from '../components/Modal'
27
+ import { ModalHeader } from '../components/ModalHeader'
28
+ import { ModalHeading } from '../components/ModalHeading'
29
+ import { ModalDescription } from '../components/ModalDescription'
29
30
 
30
31
  /**
31
32
  * This module provides a context and hook for the prompt modal.
@@ -81,11 +82,12 @@ export interface PromptModalProviderProps {}
81
82
  export function PromptModal(
82
83
  props: PropsWithChildren<PromptModalProviderProps>,
83
84
  ) {
84
- const dialogRef = useRef<HTMLDialogElement>(null)
85
+ const { modalRef, show, close } = useModal()
85
86
  const resolveRef = useRef<PromptShowResult>(null)
86
87
  const [content, setContent] = useState<ShowPromptModalOptions | null>(null)
87
88
  const [inputValue, setInputValue] = useState<string>('')
88
- const focusTrap = trapFocus(dialogRef)
89
+ const focusTrap = trapFocus(modalRef)
90
+ const PromptIcon = $cerberusIcons.promptModal
89
91
 
90
92
  const isValid = useMemo(
91
93
  () => inputValue === content?.key,
@@ -96,7 +98,6 @@ export function PromptModal(
96
98
  () => (content?.kind === 'destructive' ? 'danger' : 'action'),
97
99
  [content],
98
100
  )
99
- const styles = confirmModal({ palette })
100
101
 
101
102
  const handleChange = useCallback(
102
103
  (e: ChangeEvent<HTMLInputElement>) => {
@@ -111,18 +112,21 @@ export function PromptModal(
111
112
  if (target.value === 'true') {
112
113
  resolveRef.current?.(inputValue)
113
114
  }
114
- dialogRef?.current?.close()
115
+ close()
115
116
  },
116
- [inputValue],
117
+ [inputValue, close],
117
118
  )
118
119
 
119
- const handleShow = useCallback((options: ShowPromptModalOptions) => {
120
- return new Promise<string>((resolve) => {
121
- setContent({ ...options, kind: options.kind || 'non-destructive' })
122
- dialogRef?.current?.showModal()
123
- resolveRef.current = resolve
124
- })
125
- }, [])
120
+ const handleShow = useCallback(
121
+ (options: ShowPromptModalOptions) => {
122
+ return new Promise<string>((resolve) => {
123
+ setContent({ ...options, kind: options.kind || 'non-destructive' })
124
+ show()
125
+ resolveRef.current = resolve
126
+ })
127
+ },
128
+ [show],
129
+ )
126
130
 
127
131
  const value = useMemo(
128
132
  () => ({
@@ -136,17 +140,23 @@ export function PromptModal(
136
140
  {props.children}
137
141
 
138
142
  <Portal>
139
- <dialog className={styles.dialog} onKeyDown={focusTrap} ref={dialogRef}>
140
- <div
141
- className={vstack({
142
- alignItems: 'flex-start',
143
- gap: '4',
144
- })}
145
- >
146
- <ConfirmModalIcon palette={palette} />
147
- <h2 className={styles.heading}>{content?.heading}</h2>
148
- <p className={styles.description}>{content?.description}</p>
149
- </div>
143
+ <Modal onKeyDown={focusTrap} ref={modalRef}>
144
+ <ModalHeader>
145
+ <Show
146
+ when={palette === 'danger'}
147
+ fallback={
148
+ <ModalIcon palette="action">
149
+ <PromptIcon size={24} />
150
+ </ModalIcon>
151
+ }
152
+ >
153
+ <ModalIcon palette="danger">
154
+ <PromptIcon size={24} />
155
+ </ModalIcon>
156
+ </Show>
157
+ <ModalHeading>{content?.heading}</ModalHeading>
158
+ <ModalDescription>{content?.description}</ModalDescription>
159
+ </ModalHeader>
150
160
 
151
161
  <div
152
162
  className={vstack({
@@ -207,44 +217,12 @@ export function PromptModal(
207
217
  {content?.cancelText}
208
218
  </Button>
209
219
  </div>
210
- </dialog>
220
+ </Modal>
211
221
  </Portal>
212
222
  </PromptModalContext.Provider>
213
223
  )
214
224
  }
215
225
 
216
- // This is to help show the variant styles for the icon since Panda is
217
- // not syncing correctly for the danger variant.
218
- export function PromptModalIcon(props: ConfirmModalVariantProps) {
219
- const PromptIcon = $cerberusIcons.promptModal
220
- return (
221
- <Show
222
- when={props.palette === 'danger'}
223
- fallback={
224
- <div className={cx(confirmModal().icon, circle())}>
225
- <PromptIcon size={24} />
226
- </div>
227
- }
228
- >
229
- <div
230
- className={cx(
231
- confirmModal({
232
- palette: 'danger',
233
- }).icon,
234
- circle({
235
- bgColor: 'danger.surface.initial',
236
- }),
237
- )}
238
- style={{
239
- color: 'var(--cerberus-colors-danger-text-100)',
240
- }}
241
- >
242
- <PromptIcon size={24} />
243
- </div>
244
- </Show>
245
- )
246
- }
247
-
248
226
  export function usePromptModal(): PromptModalValue {
249
227
  const context = useContext(PromptModalContext)
250
228
  if (context === null) {