@cerberus-design/react 0.7.4 → 0.8.0-next-a23daaf

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 (163) hide show
  1. package/build/legacy/_tsup-dts-rollup.d.ts +592 -7
  2. package/build/legacy/chunk-2VPKILZ6.js +122 -0
  3. package/build/legacy/chunk-2VPKILZ6.js.map +1 -0
  4. package/build/legacy/chunk-3C2DJSEE.js +16 -0
  5. package/build/legacy/chunk-3C2DJSEE.js.map +1 -0
  6. package/build/legacy/chunk-3GXISGPS.js +47 -0
  7. package/build/legacy/chunk-3GXISGPS.js.map +1 -0
  8. package/build/legacy/{chunk-2ATICEW3.js → chunk-6F34A7NZ.js} +4 -2
  9. package/build/legacy/chunk-6F34A7NZ.js.map +1 -0
  10. package/build/legacy/chunk-7VJOPJVX.js +29 -0
  11. package/build/legacy/chunk-7VJOPJVX.js.map +1 -0
  12. package/build/legacy/chunk-A5WYZVUR.js +28 -0
  13. package/build/legacy/chunk-A5WYZVUR.js.map +1 -0
  14. package/build/legacy/{chunk-XGNAFSMG.js → chunk-AAKIOHAX.js} +3 -3
  15. package/build/{modern/chunk-6TXQZ3PB.js → legacy/chunk-BEYPMC73.js} +2 -2
  16. package/build/legacy/chunk-GVNPFXKL.js +26 -0
  17. package/build/legacy/chunk-GVNPFXKL.js.map +1 -0
  18. package/build/legacy/chunk-HW76XVA3.js +22 -0
  19. package/build/legacy/chunk-HW76XVA3.js.map +1 -0
  20. package/build/legacy/{chunk-JWQJLOX4.js → chunk-IL5ELPTT.js} +2 -2
  21. package/build/legacy/{chunk-CU7HXAKM.js → chunk-JJGZRBIR.js} +4 -4
  22. package/build/legacy/{chunk-7CZ3NIGH.js → chunk-L46XIE3D.js} +11 -11
  23. package/build/legacy/chunk-LF2QFS5S.js +76 -0
  24. package/build/legacy/chunk-LF2QFS5S.js.map +1 -0
  25. package/build/legacy/chunk-N3FUF4TB.js +12 -0
  26. package/build/legacy/chunk-N3FUF4TB.js.map +1 -0
  27. package/build/legacy/chunk-PJ3744I6.js +24 -0
  28. package/build/legacy/chunk-PJ3744I6.js.map +1 -0
  29. package/build/legacy/chunk-SMCEFK6Q.js +63 -0
  30. package/build/legacy/chunk-SMCEFK6Q.js.map +1 -0
  31. package/build/legacy/{chunk-5GEC53G7.js → chunk-XB4ZRAH4.js} +5 -5
  32. package/build/legacy/chunk-XREC5IJE.js +24 -0
  33. package/build/legacy/chunk-XREC5IJE.js.map +1 -0
  34. package/build/legacy/components/Button.js +1 -1
  35. package/build/legacy/components/Droppable.js +8 -0
  36. package/build/legacy/components/Droppable.js.map +1 -0
  37. package/build/legacy/components/FileUploader.js +11 -0
  38. package/build/legacy/components/FileUploader.js.map +1 -0
  39. package/build/legacy/components/Input.js +4 -4
  40. package/build/legacy/components/Label.js +2 -2
  41. package/build/legacy/components/Notification.js +11 -0
  42. package/build/legacy/components/Notification.js.map +1 -0
  43. package/build/legacy/components/NotificationDescription.js +7 -0
  44. package/build/legacy/components/NotificationDescription.js.map +1 -0
  45. package/build/legacy/components/NotificationHeading.js +7 -0
  46. package/build/legacy/components/NotificationHeading.js.map +1 -0
  47. package/build/legacy/components/Table.js +9 -0
  48. package/build/legacy/components/Table.js.map +1 -0
  49. package/build/legacy/components/Tbody.js +7 -0
  50. package/build/legacy/components/Tbody.js.map +1 -0
  51. package/build/legacy/components/Td.js +7 -0
  52. package/build/legacy/components/Td.js.map +1 -0
  53. package/build/legacy/components/Th.js +8 -0
  54. package/build/legacy/components/Th.js.map +1 -0
  55. package/build/legacy/components/Thead.js +7 -0
  56. package/build/legacy/components/Thead.js.map +1 -0
  57. package/build/legacy/components/Toggle.js +3 -3
  58. package/build/legacy/config/cerbIcons.js +1 -1
  59. package/build/legacy/config/defineIcons.js +2 -2
  60. package/build/legacy/context/confirm-modal.js +4 -4
  61. package/build/legacy/context/notification-center.js +19 -0
  62. package/build/legacy/context/notification-center.js.map +1 -0
  63. package/build/legacy/context/prompt-modal.js +7 -7
  64. package/build/legacy/index.js +86 -35
  65. package/build/legacy/index.js.map +1 -1
  66. package/build/modern/_tsup-dts-rollup.d.ts +592 -7
  67. package/build/modern/chunk-3C2DJSEE.js +16 -0
  68. package/build/modern/chunk-3C2DJSEE.js.map +1 -0
  69. package/build/modern/chunk-3GXISGPS.js +47 -0
  70. package/build/modern/chunk-3GXISGPS.js.map +1 -0
  71. package/build/modern/chunk-4N2L357B.js +76 -0
  72. package/build/modern/chunk-4N2L357B.js.map +1 -0
  73. package/build/modern/{chunk-2ATICEW3.js → chunk-6F34A7NZ.js} +4 -2
  74. package/build/modern/chunk-6F34A7NZ.js.map +1 -0
  75. package/build/modern/chunk-7VJOPJVX.js +29 -0
  76. package/build/modern/chunk-7VJOPJVX.js.map +1 -0
  77. package/build/modern/chunk-A5WYZVUR.js +28 -0
  78. package/build/modern/chunk-A5WYZVUR.js.map +1 -0
  79. package/build/{legacy/chunk-6TXQZ3PB.js → modern/chunk-BEYPMC73.js} +2 -2
  80. package/build/modern/chunk-GVNPFXKL.js +26 -0
  81. package/build/modern/chunk-GVNPFXKL.js.map +1 -0
  82. package/build/modern/chunk-HW76XVA3.js +22 -0
  83. package/build/modern/chunk-HW76XVA3.js.map +1 -0
  84. package/build/modern/{chunk-JWQJLOX4.js → chunk-IL5ELPTT.js} +2 -2
  85. package/build/modern/chunk-IOG6XIR5.js +62 -0
  86. package/build/modern/chunk-IOG6XIR5.js.map +1 -0
  87. package/build/modern/{chunk-CU7HXAKM.js → chunk-JJGZRBIR.js} +4 -4
  88. package/build/modern/{chunk-FAXDUWAU.js → chunk-LTDNZRUY.js} +11 -11
  89. package/build/modern/chunk-N3FUF4TB.js +12 -0
  90. package/build/modern/chunk-N3FUF4TB.js.map +1 -0
  91. package/build/modern/chunk-PJ3744I6.js +24 -0
  92. package/build/modern/chunk-PJ3744I6.js.map +1 -0
  93. package/build/modern/chunk-QO2UXGW4.js +122 -0
  94. package/build/modern/chunk-QO2UXGW4.js.map +1 -0
  95. package/build/modern/{chunk-5GEC53G7.js → chunk-XB4ZRAH4.js} +5 -5
  96. package/build/modern/chunk-XREC5IJE.js +24 -0
  97. package/build/modern/chunk-XREC5IJE.js.map +1 -0
  98. package/build/modern/{chunk-TPRGGEVJ.js → chunk-Y5IY7O23.js} +3 -3
  99. package/build/modern/components/Button.js +1 -1
  100. package/build/modern/components/Droppable.js +8 -0
  101. package/build/modern/components/Droppable.js.map +1 -0
  102. package/build/modern/components/FileUploader.js +11 -0
  103. package/build/modern/components/FileUploader.js.map +1 -0
  104. package/build/modern/components/Input.js +4 -4
  105. package/build/modern/components/Label.js +2 -2
  106. package/build/modern/components/Notification.js +11 -0
  107. package/build/modern/components/Notification.js.map +1 -0
  108. package/build/modern/components/NotificationDescription.js +7 -0
  109. package/build/modern/components/NotificationDescription.js.map +1 -0
  110. package/build/modern/components/NotificationHeading.js +7 -0
  111. package/build/modern/components/NotificationHeading.js.map +1 -0
  112. package/build/modern/components/Table.js +9 -0
  113. package/build/modern/components/Table.js.map +1 -0
  114. package/build/modern/components/Tbody.js +7 -0
  115. package/build/modern/components/Tbody.js.map +1 -0
  116. package/build/modern/components/Td.js +7 -0
  117. package/build/modern/components/Td.js.map +1 -0
  118. package/build/modern/components/Th.js +8 -0
  119. package/build/modern/components/Th.js.map +1 -0
  120. package/build/modern/components/Thead.js +7 -0
  121. package/build/modern/components/Thead.js.map +1 -0
  122. package/build/modern/components/Toggle.js +3 -3
  123. package/build/modern/config/cerbIcons.js +1 -1
  124. package/build/modern/config/defineIcons.js +2 -2
  125. package/build/modern/context/confirm-modal.js +4 -4
  126. package/build/modern/context/notification-center.js +19 -0
  127. package/build/modern/context/notification-center.js.map +1 -0
  128. package/build/modern/context/prompt-modal.js +7 -7
  129. package/build/modern/index.js +86 -35
  130. package/build/modern/index.js.map +1 -1
  131. package/package.json +5 -2
  132. package/src/components/Button.tsx +6 -3
  133. package/src/components/Droppable.tsx +33 -0
  134. package/src/components/FileUploader.tsx +55 -0
  135. package/src/components/Notification.tsx +98 -0
  136. package/src/components/NotificationDescription.tsx +31 -0
  137. package/src/components/NotificationHeading.tsx +28 -0
  138. package/src/components/Table.tsx +58 -0
  139. package/src/components/Tbody.tsx +31 -0
  140. package/src/components/Td.tsx +34 -0
  141. package/src/components/Th.tsx +56 -0
  142. package/src/components/Thead.tsx +24 -0
  143. package/src/config/cerbIcons.ts +20 -4
  144. package/src/context/notification-center.tsx +181 -0
  145. package/src/index.ts +15 -0
  146. package/build/legacy/chunk-2ATICEW3.js.map +0 -1
  147. package/build/legacy/chunk-C45DY4VE.js +0 -17
  148. package/build/legacy/chunk-C45DY4VE.js.map +0 -1
  149. package/build/modern/chunk-2ATICEW3.js.map +0 -1
  150. package/build/modern/chunk-C45DY4VE.js +0 -17
  151. package/build/modern/chunk-C45DY4VE.js.map +0 -1
  152. /package/build/legacy/{chunk-XGNAFSMG.js.map → chunk-AAKIOHAX.js.map} +0 -0
  153. /package/build/legacy/{chunk-6TXQZ3PB.js.map → chunk-BEYPMC73.js.map} +0 -0
  154. /package/build/legacy/{chunk-JWQJLOX4.js.map → chunk-IL5ELPTT.js.map} +0 -0
  155. /package/build/legacy/{chunk-CU7HXAKM.js.map → chunk-JJGZRBIR.js.map} +0 -0
  156. /package/build/legacy/{chunk-7CZ3NIGH.js.map → chunk-L46XIE3D.js.map} +0 -0
  157. /package/build/legacy/{chunk-5GEC53G7.js.map → chunk-XB4ZRAH4.js.map} +0 -0
  158. /package/build/modern/{chunk-6TXQZ3PB.js.map → chunk-BEYPMC73.js.map} +0 -0
  159. /package/build/modern/{chunk-JWQJLOX4.js.map → chunk-IL5ELPTT.js.map} +0 -0
  160. /package/build/modern/{chunk-CU7HXAKM.js.map → chunk-JJGZRBIR.js.map} +0 -0
  161. /package/build/modern/{chunk-FAXDUWAU.js.map → chunk-LTDNZRUY.js.map} +0 -0
  162. /package/build/modern/{chunk-5GEC53G7.js.map → chunk-XB4ZRAH4.js.map} +0 -0
  163. /package/build/modern/{chunk-TPRGGEVJ.js.map → chunk-Y5IY7O23.js.map} +0 -0
@@ -0,0 +1,33 @@
1
+ 'use client'
2
+
3
+ import { useDroppable, type UseDroppableArguments } from '@dnd-kit/core'
4
+ import { useId, type HtmlHTMLAttributes, type PropsWithChildren } from 'react'
5
+
6
+ export interface DroppableProps
7
+ extends Omit<HtmlHTMLAttributes<HTMLDivElement>, 'id'>,
8
+ UseDroppableArguments {
9
+ dropped?: boolean
10
+ }
11
+
12
+ export function Droppable(props: PropsWithChildren<DroppableProps>) {
13
+ const { dropped, id, disabled, data, resizeObserverConfig, ...nativeProps } =
14
+ props
15
+ const uuid = useId()
16
+ const { isOver, setNodeRef } = useDroppable({
17
+ data,
18
+ disabled,
19
+ id: id || uuid,
20
+ resizeObserverConfig,
21
+ })
22
+
23
+ return (
24
+ <div
25
+ {...nativeProps}
26
+ data-over={isOver}
27
+ data-dropped={dropped}
28
+ ref={setNodeRef}
29
+ >
30
+ {props.children}
31
+ </div>
32
+ )
33
+ }
@@ -0,0 +1,55 @@
1
+ 'use client'
2
+
3
+ import { cx } from '@cerberus/styled-system/css'
4
+ import { circle, vstack } from '@cerberus/styled-system/patterns'
5
+ import { type InputHTMLAttributes } from 'react'
6
+ import { Show } from './Show'
7
+ import { fileUploader, modalIcon } from '@cerberus/styled-system/recipes'
8
+ import { $cerberusIcons } from '../config/defineIcons'
9
+
10
+ export interface FileUploaderProps
11
+ extends InputHTMLAttributes<HTMLInputElement> {
12
+ heading?: string
13
+ name: string
14
+ }
15
+
16
+ export function FileUploader(props: FileUploaderProps) {
17
+ const styles = fileUploader()
18
+ const Icon = $cerberusIcons.fileUploader
19
+
20
+ return (
21
+ <div
22
+ className={cx(
23
+ vstack({
24
+ justify: 'center',
25
+ }),
26
+ styles.container,
27
+ )}
28
+ >
29
+ <span className={cx(styles.icon, modalIcon(), circle())}>
30
+ <Icon />
31
+ </span>
32
+
33
+ <label
34
+ className={cx(
35
+ vstack({
36
+ justify: 'center',
37
+ }),
38
+ styles.label,
39
+ )}
40
+ htmlFor={props.name}
41
+ >
42
+ <Show when={Boolean(props.heading)}>
43
+ <p className={styles.heading}>{props.heading}</p>
44
+ </Show>
45
+ Import {props.accept?.replace(',', ', ')} files
46
+ <p className={styles.description}>Or click to upload</p>
47
+ <input
48
+ {...props}
49
+ className={cx(props.className, styles.input)}
50
+ type="file"
51
+ />
52
+ </label>
53
+ </div>
54
+ )
55
+ }
@@ -0,0 +1,98 @@
1
+ 'use client'
2
+
3
+ import { cx } from '@cerberus/styled-system/css'
4
+ import { hstack, vstack } from '@cerberus/styled-system/patterns'
5
+ import {
6
+ notification,
7
+ type NotificationVariantProps,
8
+ } from '@cerberus/styled-system/recipes'
9
+ import {
10
+ useRef,
11
+ type DialogHTMLAttributes,
12
+ type PropsWithChildren,
13
+ type MouseEvent,
14
+ } from 'react'
15
+ import { Close } from '@cerberus/icons'
16
+ import { $cerberusIcons } from '../config/defineIcons'
17
+ import type { IconType } from '../config/cerbIcons'
18
+ import { trapFocus } from '../aria-helpers/trap-focus.aria'
19
+
20
+ /**
21
+ * This module exports the Notification component.
22
+ * @module
23
+ */
24
+
25
+ function MatchNotificationIcon(props: NotificationVariantProps) {
26
+ const palette = props.palette || 'info'
27
+ const key = `${palette}Notification` as keyof typeof $cerberusIcons
28
+ const Icon = $cerberusIcons[key] as IconType
29
+ return <Icon />
30
+ }
31
+
32
+ export interface NotificationBaseProps
33
+ extends Omit<DialogHTMLAttributes<HTMLDialogElement>, 'onClose'> {
34
+ id: string
35
+ onClose?: (e: MouseEvent<HTMLButtonElement>) => void
36
+ }
37
+ export type NotificationProps = NotificationBaseProps & NotificationVariantProps
38
+
39
+ /**
40
+ * The info notification component.
41
+ * @param props - The component props.
42
+ * @returns The info notification component.
43
+ * @example
44
+ * ```tsx
45
+ * <Notification id="info:1" open>
46
+ * <NotificationHeading>Info Notification</NotificationHeading>
47
+ * <NotificationDescription>
48
+ * This is a description with a <a href="#">link</a> in the message.
49
+ * </NotificationDescription>
50
+ * </Notification>
51
+ * ```
52
+ */
53
+ export function Notification(props: PropsWithChildren<NotificationProps>) {
54
+ const { children, palette, onClose, ...nativeProps } = props
55
+ const ref = useRef<HTMLDialogElement>(null)
56
+ const onKeyDown = trapFocus(ref)
57
+ const styles = notification({ palette })
58
+
59
+ return (
60
+ <dialog
61
+ {...nativeProps}
62
+ className={cx(
63
+ nativeProps.className,
64
+ hstack({
65
+ position: 'relative',
66
+ gap: '4',
67
+ }),
68
+ styles.dialog,
69
+ )}
70
+ onKeyDown={onKeyDown}
71
+ ref={ref}
72
+ role="alert"
73
+ >
74
+ <span className={styles.icon}>
75
+ <MatchNotificationIcon palette={palette} />
76
+ </span>
77
+
78
+ <div
79
+ className={vstack({
80
+ alignItems: 'flex-start',
81
+ gap: '0',
82
+ py: '2',
83
+ })}
84
+ >
85
+ {children}
86
+ </div>
87
+
88
+ <button
89
+ aria-label="Close"
90
+ className={styles.close}
91
+ onClick={onClose}
92
+ value={props.id}
93
+ >
94
+ <Close />
95
+ </button>
96
+ </dialog>
97
+ )
98
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * This module exports the NotificationDescription component.
3
+ * @module
4
+ */
5
+
6
+ import { cx } from '@cerberus/styled-system/css'
7
+ import {
8
+ notification,
9
+ type NotificationVariantProps,
10
+ } from '@cerberus/styled-system/recipes'
11
+ import type { HTMLAttributes } from 'react'
12
+
13
+ export interface BaseNotificationDescriptionProps
14
+ extends HTMLAttributes<HTMLParagraphElement> {}
15
+ export type NotificationDescriptionProps = BaseNotificationDescriptionProps &
16
+ NotificationVariantProps
17
+
18
+ /**
19
+ * The NotificationDescription component is used to render the description of a notification.
20
+ * @param props - The anything a HTMLParagraphElement can accept.
21
+ */
22
+ export function NotificationDescription(props: NotificationDescriptionProps) {
23
+ const { palette, ...nativeProps } = props
24
+ const styles = notification({ palette })
25
+ return (
26
+ <p
27
+ className={cx(nativeProps.className, styles.description)}
28
+ {...nativeProps}
29
+ />
30
+ )
31
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * This module exports the NotificationHeading component.
3
+ * @module
4
+ */
5
+
6
+ import { cx } from '@cerberus/styled-system/css'
7
+ import {
8
+ notification,
9
+ type NotificationVariantProps,
10
+ } from '@cerberus/styled-system/recipes'
11
+ import type { HTMLAttributes } from 'react'
12
+
13
+ export interface BaseNotificationHeadingProps
14
+ extends HTMLAttributes<HTMLParagraphElement> {}
15
+ export type NotificationHeadingProps = BaseNotificationHeadingProps &
16
+ NotificationVariantProps
17
+
18
+ /**
19
+ * The NotificationHeading component is used to render the heading of a notification.
20
+ * @param props - The anything a HTMLParagraphElement can accept.
21
+ */
22
+ export function NotificationHeading(props: NotificationHeadingProps) {
23
+ const { palette, ...nativeProps } = props
24
+ const styles = notification({ palette })
25
+ return (
26
+ <p className={cx(nativeProps.className, styles.heading)} {...nativeProps} />
27
+ )
28
+ }
@@ -0,0 +1,58 @@
1
+ import { cx } from '@cerberus/styled-system/css'
2
+ import { table } from '@cerberus/styled-system/recipes'
3
+ import type { PropsWithChildren, TableHTMLAttributes } from 'react'
4
+
5
+ /**
6
+ * This module contains the table component.
7
+ * @module
8
+ */
9
+
10
+ export interface TableProps extends TableHTMLAttributes<HTMLTableElement> {
11
+ caption: string
12
+ }
13
+
14
+ /**
15
+ * The Table component is used to render a table.
16
+ * @definition [Table docs](https://cerberus.digitalu.design/react/table)
17
+ * @prop caption - An easy to understand description of the table.
18
+ * @example
19
+ * ```tsx
20
+ * <Table caption="Basic Table">
21
+ * {children}
22
+ * </Table>
23
+ * ```
24
+ */
25
+ export function Table(props: PropsWithChildren<TableProps>) {
26
+ const { caption, children, ...nativeProps } = props
27
+ const styles = table()
28
+
29
+ return (
30
+ <div className={styles.container}>
31
+ <table
32
+ {...nativeProps}
33
+ className={cx(nativeProps.className, styles.table)}
34
+ >
35
+ <caption className={styles.caption}>{caption}</caption>
36
+ {children}
37
+ </table>
38
+ </div>
39
+ )
40
+ }
41
+
42
+ // We only provide this for consistency with the rest of the components
43
+
44
+ export type TrProps = TableHTMLAttributes<HTMLTableRowElement>
45
+
46
+ /**
47
+ * The Tr component is used to render a table row.
48
+ * @definition [Table docs](https://cerberus.digitalu.design/react/table)
49
+ * @example
50
+ * ```tsx
51
+ * <Tr>
52
+ * {children}
53
+ * </Tr>
54
+ * ```
55
+ */
56
+ export function Tr(props: PropsWithChildren<TrProps>) {
57
+ return <tr {...props} />
58
+ }
@@ -0,0 +1,31 @@
1
+ import { tbody, type TbodyVariantProps } from '@cerberus/styled-system/recipes'
2
+ import { cx } from '@cerberus/styled-system/css'
3
+ import type { TableHTMLAttributes } from 'react'
4
+
5
+ export type TbodyBaseProps = TableHTMLAttributes<HTMLTableSectionElement>
6
+ export type TbodyProps = TbodyBaseProps & TbodyVariantProps
7
+
8
+ /**
9
+ * The TBody component is used to render a table body.
10
+ * @definition [Table docs](https://cerberus.digitalu.design/react/table)
11
+ * @example
12
+ * ```tsx
13
+ * <TBody>
14
+ * {children}
15
+ * </TBody>
16
+ * ```
17
+ */
18
+ export function Tbody(props: TbodyProps) {
19
+ const { decoration, ...nativeProps } = props
20
+ return (
21
+ <tbody
22
+ {...nativeProps}
23
+ className={cx(
24
+ nativeProps.className,
25
+ tbody({
26
+ decoration,
27
+ }),
28
+ )}
29
+ />
30
+ )
31
+ }
@@ -0,0 +1,34 @@
1
+ import { cx } from '@cerberus/styled-system/css'
2
+ import { td, type TdVariantProps } from '@cerberus/styled-system/recipes'
3
+ import type { TableHTMLAttributes } from 'react'
4
+
5
+ /**
6
+ * Th component for the Td component
7
+ * @module
8
+ */
9
+
10
+ export type TdBaseProps = TableHTMLAttributes<HTMLTableCellElement>
11
+ export type TdProps = TdBaseProps & TdVariantProps
12
+
13
+ /**
14
+ * Styles for the Th component
15
+ * @definition [Table docs](https://cerberus.digitalu.design/react/table)
16
+ * @example
17
+ * ```tsx
18
+ * <Td>Data cell</Td>
19
+ * ```
20
+ */
21
+ export function Td(props: TdProps) {
22
+ const { size, ...nativeProps } = props
23
+ return (
24
+ <td
25
+ {...nativeProps}
26
+ className={cx(
27
+ nativeProps.className,
28
+ td({
29
+ size,
30
+ }),
31
+ )}
32
+ />
33
+ )
34
+ }
@@ -0,0 +1,56 @@
1
+ import { css, cx } from '@cerberus/styled-system/css'
2
+ import { th, type ThVariantProps } from '@cerberus/styled-system/recipes'
3
+ import type { MouseEvent, TableHTMLAttributes } from 'react'
4
+ import { Show } from './Show'
5
+
6
+ /**
7
+ * Th component for the Table component
8
+ * @module
9
+ */
10
+
11
+ export type ThBaseProps = TableHTMLAttributes<HTMLTableCellElement> & {
12
+ onClick?: (e: MouseEvent<HTMLButtonElement>) => void
13
+ }
14
+ export type ThProps = ThBaseProps & ThVariantProps
15
+
16
+ /**
17
+ * Styles for the Th component
18
+ * @definition [Table docs](https://cerberus.digitalu.design/react/table)
19
+ * @example
20
+ * ```tsx
21
+ * <Th>Header 1</Th>
22
+ * ```
23
+ */
24
+ export function Th(props: ThProps) {
25
+ const { size, onClick, ...nativeProps } = props
26
+ return (
27
+ <Show
28
+ when={Boolean(onClick)}
29
+ fallback={
30
+ <th
31
+ {...nativeProps}
32
+ className={cx(nativeProps.className, th({ size }))}
33
+ />
34
+ }
35
+ >
36
+ <th {...nativeProps}>
37
+ <button
38
+ className={cx(
39
+ nativeProps.className,
40
+ th({ size }),
41
+ css({
42
+ alignItems: 'center',
43
+ display: 'inline-flex',
44
+ justifyContent: 'space-between',
45
+ userSelect: 'none',
46
+ w: 'full',
47
+ }),
48
+ )}
49
+ onClick={onClick}
50
+ >
51
+ {props.children}
52
+ </button>
53
+ </th>
54
+ </Show>
55
+ )
56
+ }
@@ -0,0 +1,24 @@
1
+ import { cx } from '@cerberus/styled-system/css'
2
+ import { thead } from '@cerberus/styled-system/recipes'
3
+ import type { TableHTMLAttributes } from 'react'
4
+
5
+ /**
6
+ * This module contains the Thead component.
7
+ * @module
8
+ */
9
+
10
+ export type TheadProps = TableHTMLAttributes<HTMLTableSectionElement>
11
+
12
+ /**
13
+ * The Thead component is used to render a table header.
14
+ * @definition [Table docs](https://cerberus.digitalu.design/react/table)
15
+ * @example
16
+ * ```tsx
17
+ * <Thead>
18
+ * {children}
19
+ * </Thead>
20
+ * ```
21
+ */
22
+ export function Thead(props: TheadProps) {
23
+ return <thead {...props} className={cx(props.className, thead())} />
24
+ }
@@ -1,21 +1,37 @@
1
1
  import {
2
2
  Checkmark,
3
+ CheckmarkFilled,
4
+ CloudUpload,
5
+ ErrorFilled,
3
6
  Information,
7
+ InformationFilled,
4
8
  WarningFilled,
5
9
  type CarbonIconType,
6
10
  } from '@cerberus/icons'
7
11
  import type { ElementType } from 'react'
8
12
 
13
+ export type IconType = CarbonIconType | ElementType
14
+
9
15
  export interface DefinedIcons {
10
- confirmModal?: CarbonIconType | ElementType
11
- promptModal?: CarbonIconType | ElementType
12
- invalid: CarbonIconType | ElementType
13
- toggleChecked?: CarbonIconType | ElementType
16
+ confirmModal?: IconType
17
+ promptModal?: IconType
18
+ fileUploader?: IconType
19
+ infoNotification?: IconType
20
+ successNotification?: IconType
21
+ warningNotification?: IconType
22
+ dangerNotification?: IconType
23
+ invalid: IconType
24
+ toggleChecked?: IconType
14
25
  }
15
26
 
16
27
  export const defaultIcons: DefinedIcons = {
17
28
  confirmModal: Information,
18
29
  promptModal: Information,
30
+ fileUploader: CloudUpload,
31
+ infoNotification: InformationFilled,
32
+ successNotification: CheckmarkFilled,
33
+ warningNotification: WarningFilled,
34
+ dangerNotification: ErrorFilled,
19
35
  invalid: WarningFilled,
20
36
  toggleChecked: Checkmark,
21
37
  }
@@ -0,0 +1,181 @@
1
+ 'use client'
2
+
3
+ import {
4
+ createContext,
5
+ useCallback,
6
+ useContext,
7
+ useMemo,
8
+ useState,
9
+ type MouseEvent,
10
+ type PropsWithChildren,
11
+ type ReactNode,
12
+ } from 'react'
13
+ import { Show } from '../components/Show'
14
+ import { NotificationHeading } from '../components/NotificationHeading'
15
+ import { NotificationDescription } from '../components/NotificationDescription'
16
+ import { Notification } from '../components/Notification'
17
+ import { animateIn, vstack } from '@cerberus/styled-system/patterns'
18
+ import { Portal, type PortalProps } from '../components/Portal'
19
+ import { notification } from '@cerberus/styled-system/recipes'
20
+ import { Button } from '../components/Button'
21
+ import { cx } from '@cerberus/styled-system/css'
22
+
23
+ /**
24
+ * This module provides a context and hook for notifications.
25
+ * @module
26
+ */
27
+
28
+ export interface NotifyOptions {
29
+ palette: 'info' | 'success' | 'warning' | 'danger'
30
+ heading: string
31
+ id?: string
32
+ description?: ReactNode
33
+ onClose?: () => void
34
+ }
35
+
36
+ export interface NotificationsValue {
37
+ notify: (options: NotifyOptions) => void
38
+ }
39
+
40
+ const NotificationsContext = createContext<NotificationsValue | null>(null)
41
+
42
+ export interface NotificationsProviderProps extends PortalProps {}
43
+
44
+ /**
45
+ * Provides a notification center to the app.
46
+ * @example
47
+ * ```tsx
48
+ * // Wrap the Provider around the root of the feature.
49
+ * <Notifications>
50
+ * <SomeFeatureSection />
51
+ * </Notifications>
52
+ *
53
+ * // Use the hook to show a notification.
54
+ * const notify = useNotifications()
55
+ *
56
+ * const handleClick = useCallback(() => {
57
+ * notify({
58
+ * palette: 'info',
59
+ * heading: 'New feature!',
60
+ * description: 'We have added a new feature to the app.',
61
+ * })
62
+ * }, [notify])
63
+ * ```
64
+ */
65
+ export function NotificationCenter(
66
+ props: PropsWithChildren<NotificationsProviderProps>,
67
+ ) {
68
+ const [activeNotifications, setActiveNotifications] = useState<
69
+ NotifyOptions[]
70
+ >([])
71
+ const styles = notification()
72
+
73
+ const handleNotify = useCallback((options: NotifyOptions) => {
74
+ setActiveNotifications((prev) => {
75
+ const id = `${options.palette}:${prev.length + 1}`
76
+ return [...prev, { ...options, id }]
77
+ })
78
+ }, [])
79
+
80
+ const handleClose = useCallback((e: MouseEvent<HTMLButtonElement>) => {
81
+ const target = e.currentTarget as HTMLButtonElement
82
+ setActiveNotifications((prev) => {
83
+ const item = prev.find((option) => option.id === target.value)
84
+ if (item?.onClose) item.onClose()
85
+ return prev.filter((option) => option.id !== target.value)
86
+ })
87
+ }, [])
88
+
89
+ const handleCloseAll = useCallback(() => {
90
+ setActiveNotifications((prev) => {
91
+ prev.forEach((item) => {
92
+ if (item.onClose) item.onClose()
93
+ })
94
+ return []
95
+ })
96
+ }, [])
97
+
98
+ const value = useMemo(
99
+ () => ({
100
+ notify: handleNotify,
101
+ }),
102
+ [handleNotify],
103
+ )
104
+
105
+ // For some reason, the vstack pattern alignItems is not registering here.
106
+ // So we are forcing it with the style prop.
107
+
108
+ return (
109
+ <NotificationsContext.Provider value={value}>
110
+ {props.children}
111
+
112
+ <Show when={activeNotifications.length > 0}>
113
+ <Portal container={props.container}>
114
+ <div className={styles.center}>
115
+ <Show when={activeNotifications.length >= 4}>
116
+ <Button
117
+ className={cx(styles.closeAll, animateIn())}
118
+ onClick={handleCloseAll}
119
+ palette="action"
120
+ shape="rounded"
121
+ size="sm"
122
+ usage="text"
123
+ >
124
+ Close all
125
+ </Button>
126
+ </Show>
127
+ <div
128
+ className={vstack({
129
+ alignItems: 'flex-end',
130
+ gap: '4',
131
+ })}
132
+ style={{
133
+ alignItems: 'flex-end',
134
+ }}
135
+ >
136
+ {activeNotifications.map((option) => (
137
+ <Notification
138
+ id={option.id!}
139
+ key={option.id}
140
+ onClose={handleClose}
141
+ open
142
+ palette={option.palette}
143
+ >
144
+ <NotificationHeading palette={option.palette}>
145
+ {option.heading}
146
+ </NotificationHeading>
147
+ <NotificationDescription palette={option.palette}>
148
+ {option.description}
149
+ </NotificationDescription>
150
+ </Notification>
151
+ ))}
152
+ </div>
153
+ </div>
154
+ </Portal>
155
+ </Show>
156
+ </NotificationsContext.Provider>
157
+ )
158
+ }
159
+
160
+ /**
161
+ * The hook to use the NotificationCenter.
162
+ * @returns The notify method to trigger a notification.
163
+ * @example
164
+ * ```tsx
165
+ * const {notify} = useNotificationCenter()
166
+ * notify({
167
+ * palette: 'info',
168
+ * heading: 'New feature',
169
+ * description: 'We have added a new feature to the app.',
170
+ * })
171
+ * ```
172
+ */
173
+ export function useNotificationCenter(): NotificationsValue {
174
+ const context = useContext(NotificationsContext)
175
+ if (!context) {
176
+ throw new Error(
177
+ 'useNotificationCenter must be used within a NotificationsProvider',
178
+ )
179
+ }
180
+ return context
181
+ }