@cerberus-design/react 0.13.2 → 0.14.0

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 (224) hide show
  1. package/build/legacy/_tsup-dts-rollup.d.cts +607 -129
  2. package/build/legacy/components/Accordion.cjs +101 -0
  3. package/build/legacy/components/Accordion.cjs.map +1 -0
  4. package/build/legacy/components/AccordionItemGroup.cjs +119 -0
  5. package/build/legacy/components/AccordionItemGroup.cjs.map +1 -0
  6. package/build/legacy/components/Admonition.cjs +3 -0
  7. package/build/legacy/components/Admonition.cjs.map +1 -1
  8. package/build/legacy/components/Avatar.cjs +3 -0
  9. package/build/legacy/components/Avatar.cjs.map +1 -1
  10. package/build/legacy/components/Checkbox.cjs +3 -0
  11. package/build/legacy/components/Checkbox.cjs.map +1 -1
  12. package/build/legacy/components/DatePicker.client.cjs +497 -0
  13. package/build/legacy/components/DatePicker.client.cjs.map +1 -0
  14. package/build/legacy/components/DatePicker.server.cjs +364 -0
  15. package/build/legacy/components/DatePicker.server.cjs.map +1 -0
  16. package/build/legacy/components/FileStatus.cjs +3 -0
  17. package/build/legacy/components/FileStatus.cjs.map +1 -1
  18. package/build/legacy/components/FileUploader.cjs +3 -0
  19. package/build/legacy/components/FileUploader.cjs.map +1 -1
  20. package/build/legacy/components/Input.cjs +3 -0
  21. package/build/legacy/components/Input.cjs.map +1 -1
  22. package/build/legacy/components/Notification.cjs +3 -0
  23. package/build/legacy/components/Notification.cjs.map +1 -1
  24. package/build/legacy/components/NotificationDescription.cjs.map +1 -1
  25. package/build/legacy/components/NotificationHeading.cjs.map +1 -1
  26. package/build/legacy/components/ProgressBar.cjs.map +1 -1
  27. package/build/legacy/components/Select.cjs +3 -0
  28. package/build/legacy/components/Select.cjs.map +1 -1
  29. package/build/legacy/components/Tabs.client.cjs +104 -0
  30. package/build/legacy/components/Tabs.client.cjs.map +1 -0
  31. package/build/legacy/components/Tag.cjs +3 -0
  32. package/build/legacy/components/Tag.cjs.map +1 -1
  33. package/build/legacy/components/Text.cjs +59 -0
  34. package/build/legacy/components/Text.cjs.map +1 -0
  35. package/build/legacy/components/Toggle.cjs +3 -0
  36. package/build/legacy/components/Toggle.cjs.map +1 -1
  37. package/build/legacy/components/Tooltip.cjs +2 -2
  38. package/build/legacy/components/Tooltip.cjs.map +1 -1
  39. package/build/legacy/config/cerbIcons.cjs +3 -0
  40. package/build/legacy/config/cerbIcons.cjs.map +1 -1
  41. package/build/legacy/config/defineIcons.cjs +3 -0
  42. package/build/legacy/config/defineIcons.cjs.map +1 -1
  43. package/build/legacy/config/icons/checkbox.icons.cjs.map +1 -1
  44. package/build/legacy/context/confirm-modal.cjs +3 -0
  45. package/build/legacy/context/confirm-modal.cjs.map +1 -1
  46. package/build/legacy/context/cta-modal.cjs +5 -3
  47. package/build/legacy/context/cta-modal.cjs.map +1 -1
  48. package/build/legacy/context/notification-center.cjs +3 -0
  49. package/build/legacy/context/notification-center.cjs.map +1 -1
  50. package/build/legacy/context/prompt-modal.cjs +3 -0
  51. package/build/legacy/context/prompt-modal.cjs.map +1 -1
  52. package/build/legacy/context/tabs.cjs +53 -24
  53. package/build/legacy/context/tabs.cjs.map +1 -1
  54. package/build/legacy/hooks/useDate.cjs +8 -0
  55. package/build/legacy/hooks/useDate.cjs.map +1 -1
  56. package/build/legacy/index.cjs +1083 -711
  57. package/build/legacy/index.cjs.map +1 -1
  58. package/build/legacy/utils/index.cjs +21 -2
  59. package/build/legacy/utils/index.cjs.map +1 -1
  60. package/build/legacy/utils/localStorage.cjs +44 -0
  61. package/build/legacy/utils/localStorage.cjs.map +1 -0
  62. package/build/modern/_tsup-dts-rollup.d.ts +607 -129
  63. package/build/modern/chunk-2ZNIYPDV.js +47 -0
  64. package/build/modern/chunk-2ZNIYPDV.js.map +1 -0
  65. package/build/modern/chunk-34E3UFFB.js +75 -0
  66. package/build/modern/chunk-34E3UFFB.js.map +1 -0
  67. package/build/modern/{chunk-CZND26FC.js → chunk-3BM6MZ4A.js} +8 -1
  68. package/build/modern/{chunk-CZND26FC.js.map → chunk-3BM6MZ4A.js.map} +1 -1
  69. package/build/modern/{chunk-N4QTLDVM.js → chunk-4IMOKN2D.js} +3 -3
  70. package/build/modern/{chunk-F27AAKQ3.js → chunk-5KHU6MM5.js} +8 -2
  71. package/build/modern/chunk-5KHU6MM5.js.map +1 -0
  72. package/build/modern/{chunk-WFJWCZ7E.js → chunk-77B4HFKT.js} +13 -14
  73. package/build/modern/chunk-77B4HFKT.js.map +1 -0
  74. package/build/modern/{chunk-FBSESDWJ.js → chunk-BHSYQCDV.js} +16 -16
  75. package/build/modern/chunk-BHSYQCDV.js.map +1 -0
  76. package/build/modern/{chunk-SPZYPRZ6.js → chunk-BU5JK37R.js} +2 -2
  77. package/build/modern/{chunk-UTGEFJ3L.js → chunk-C5EHJUS5.js} +1 -1
  78. package/build/modern/{chunk-UTGEFJ3L.js.map → chunk-C5EHJUS5.js.map} +1 -1
  79. package/build/modern/{chunk-VERRHMW4.js → chunk-DDOTCGGA.js} +2 -2
  80. package/build/modern/{chunk-CP7OUC2Q.js → chunk-E3PAEB7Y.js} +1 -1
  81. package/build/modern/chunk-E3PAEB7Y.js.map +1 -0
  82. package/build/modern/{chunk-F72ZABKX.js → chunk-F4LTOZAN.js} +2 -2
  83. package/build/modern/{chunk-NKM6PISB.js → chunk-F7EWTOML.js} +2 -2
  84. package/build/modern/chunk-F7XWOSN3.js +39 -0
  85. package/build/modern/chunk-F7XWOSN3.js.map +1 -0
  86. package/build/modern/chunk-FQLMPEYX.js +18 -0
  87. package/build/modern/chunk-FQLMPEYX.js.map +1 -0
  88. package/build/modern/{chunk-7MM5KYEX.js → chunk-GI6CSUU4.js} +7 -7
  89. package/build/modern/{chunk-7SGPJM66.js → chunk-HP4ZN473.js} +2 -2
  90. package/build/modern/chunk-HP4ZN473.js.map +1 -0
  91. package/build/modern/chunk-IP5VFOPZ.js +132 -0
  92. package/build/modern/chunk-IP5VFOPZ.js.map +1 -0
  93. package/build/modern/{chunk-KML4CTMK.js → chunk-LPALHB6R.js} +3 -3
  94. package/build/modern/chunk-LPALHB6R.js.map +1 -0
  95. package/build/modern/{chunk-3XGLNXJJ.js → chunk-M73ECA25.js} +8 -8
  96. package/build/modern/chunk-M73ECA25.js.map +1 -0
  97. package/build/modern/chunk-N7O6D7BW.js +63 -0
  98. package/build/modern/chunk-N7O6D7BW.js.map +1 -0
  99. package/build/modern/{chunk-W4DXACNV.js → chunk-O7QVCF3H.js} +3 -3
  100. package/build/modern/chunk-RIZGWERR.js +161 -0
  101. package/build/modern/chunk-RIZGWERR.js.map +1 -0
  102. package/build/modern/chunk-RZ7NG77U.js +77 -0
  103. package/build/modern/chunk-RZ7NG77U.js.map +1 -0
  104. package/build/modern/{chunk-XL4JREDT.js → chunk-S25RHYZV.js} +2 -2
  105. package/build/modern/{chunk-SXIXDXG3.js → chunk-SLHYBPJ5.js} +1 -1
  106. package/build/modern/chunk-SLHYBPJ5.js.map +1 -0
  107. package/build/modern/{chunk-GRUXP3NG.js → chunk-T6U7AKKP.js} +10 -10
  108. package/build/modern/chunk-T6U7AKKP.js.map +1 -0
  109. package/build/modern/{chunk-XEW6TJJ4.js → chunk-UXY3KCC3.js} +1 -1
  110. package/build/modern/chunk-UXY3KCC3.js.map +1 -0
  111. package/build/modern/{chunk-NB6DV4VA.js → chunk-W2LSPRQ3.js} +2 -2
  112. package/build/modern/{chunk-KCANMM64.js → chunk-WZJ5UQNM.js} +1 -1
  113. package/build/modern/chunk-WZJ5UQNM.js.map +1 -0
  114. package/build/modern/{chunk-NMNONSHU.js → chunk-XVU2NQCW.js} +2 -2
  115. package/build/modern/components/Accordion.js +15 -0
  116. package/build/modern/components/AccordionItemGroup.js +9 -0
  117. package/build/modern/components/Admonition.js +5 -5
  118. package/build/modern/components/Avatar.js +4 -4
  119. package/build/modern/components/Checkbox.js +4 -4
  120. package/build/modern/components/DatePicker.client.js +31 -0
  121. package/build/modern/components/DatePicker.server.js +31 -0
  122. package/build/modern/components/FileStatus.js +7 -7
  123. package/build/modern/components/FileUploader.js +5 -5
  124. package/build/modern/components/Input.js +4 -4
  125. package/build/modern/components/Notification.js +4 -4
  126. package/build/modern/components/NotificationDescription.js +1 -1
  127. package/build/modern/components/NotificationHeading.js +1 -1
  128. package/build/modern/components/ProgressBar.js +1 -1
  129. package/build/modern/components/Select.js +4 -4
  130. package/build/modern/components/Tabs.client.js +18 -0
  131. package/build/modern/components/Tabs.client.js.map +1 -0
  132. package/build/modern/components/Tag.js +4 -4
  133. package/build/modern/components/Text.js +7 -0
  134. package/build/modern/components/Text.js.map +1 -0
  135. package/build/modern/components/Toggle.js +4 -4
  136. package/build/modern/components/Tooltip.js +1 -1
  137. package/build/modern/config/cerbIcons.js +2 -2
  138. package/build/modern/config/defineIcons.js +3 -3
  139. package/build/modern/config/icons/checkbox.icons.js +1 -1
  140. package/build/modern/context/confirm-modal.js +8 -8
  141. package/build/modern/context/cta-modal.js +8 -8
  142. package/build/modern/context/notification-center.js +7 -7
  143. package/build/modern/context/prompt-modal.js +11 -11
  144. package/build/modern/context/tabs.js +2 -1
  145. package/build/modern/hooks/useDate.js +3 -1
  146. package/build/modern/index.js +158 -94
  147. package/build/modern/index.js.map +1 -1
  148. package/build/modern/utils/index.js +8 -2
  149. package/build/modern/utils/localStorage.js +10 -0
  150. package/build/modern/utils/localStorage.js.map +1 -0
  151. package/package.json +2 -2
  152. package/src/components/Accordion.tsx +160 -0
  153. package/src/components/AccordionItemGroup.tsx +79 -0
  154. package/src/components/DatePicker.client.tsx +365 -0
  155. package/src/components/DatePicker.server.tsx +229 -0
  156. package/src/components/Notification.tsx +6 -3
  157. package/src/components/NotificationDescription.tsx +2 -2
  158. package/src/components/NotificationHeading.tsx +1 -2
  159. package/src/components/ProgressBar.tsx +1 -1
  160. package/src/components/Tabs.client.tsx +113 -0
  161. package/src/components/Text.tsx +70 -0
  162. package/src/components/Tooltip.tsx +2 -2
  163. package/src/config/cerbIcons.ts +9 -0
  164. package/src/config/icons/checkbox.icons.tsx +2 -2
  165. package/src/context/confirm-modal.tsx +1 -1
  166. package/src/context/cta-modal.tsx +6 -7
  167. package/src/context/notification-center.tsx +1 -1
  168. package/src/context/prompt-modal.tsx +1 -1
  169. package/src/context/tabs.tsx +66 -65
  170. package/src/hooks/useDate.ts +12 -0
  171. package/src/index.ts +6 -4
  172. package/src/utils/index.ts +2 -0
  173. package/src/utils/localStorage.ts +28 -0
  174. package/build/legacy/aria-helpers/tabs.aria.cjs +0 -100
  175. package/build/legacy/aria-helpers/tabs.aria.cjs.map +0 -1
  176. package/build/legacy/components/Tab.cjs +0 -135
  177. package/build/legacy/components/Tab.cjs.map +0 -1
  178. package/build/legacy/components/TabList.cjs +0 -69
  179. package/build/legacy/components/TabList.cjs.map +0 -1
  180. package/build/legacy/components/TabPanel.cjs +0 -76
  181. package/build/legacy/components/TabPanel.cjs.map +0 -1
  182. package/build/modern/aria-helpers/tabs.aria.js +0 -9
  183. package/build/modern/chunk-3XGLNXJJ.js.map +0 -1
  184. package/build/modern/chunk-7SGPJM66.js.map +0 -1
  185. package/build/modern/chunk-AYIRV5CL.js +0 -32
  186. package/build/modern/chunk-AYIRV5CL.js.map +0 -1
  187. package/build/modern/chunk-CP7OUC2Q.js.map +0 -1
  188. package/build/modern/chunk-F27AAKQ3.js.map +0 -1
  189. package/build/modern/chunk-FBSESDWJ.js.map +0 -1
  190. package/build/modern/chunk-GRUXP3NG.js.map +0 -1
  191. package/build/modern/chunk-ITOIXNJS.js +0 -64
  192. package/build/modern/chunk-ITOIXNJS.js.map +0 -1
  193. package/build/modern/chunk-KCANMM64.js.map +0 -1
  194. package/build/modern/chunk-KML4CTMK.js.map +0 -1
  195. package/build/modern/chunk-RIFQSCHT.js +0 -58
  196. package/build/modern/chunk-RIFQSCHT.js.map +0 -1
  197. package/build/modern/chunk-SLF6SIPB.js +0 -46
  198. package/build/modern/chunk-SLF6SIPB.js.map +0 -1
  199. package/build/modern/chunk-SXIXDXG3.js.map +0 -1
  200. package/build/modern/chunk-UKPF7JOB.js +0 -33
  201. package/build/modern/chunk-UKPF7JOB.js.map +0 -1
  202. package/build/modern/chunk-WFJWCZ7E.js.map +0 -1
  203. package/build/modern/chunk-XEW6TJJ4.js.map +0 -1
  204. package/build/modern/components/Tab.js +0 -10
  205. package/build/modern/components/TabList.js +0 -9
  206. package/build/modern/components/TabPanel.js +0 -10
  207. package/src/aria-helpers/tabs.aria.ts +0 -70
  208. package/src/components/Tab.tsx +0 -68
  209. package/src/components/TabList.tsx +0 -51
  210. package/src/components/TabPanel.tsx +0 -49
  211. /package/build/modern/{chunk-N4QTLDVM.js.map → chunk-4IMOKN2D.js.map} +0 -0
  212. /package/build/modern/{chunk-SPZYPRZ6.js.map → chunk-BU5JK37R.js.map} +0 -0
  213. /package/build/modern/{chunk-VERRHMW4.js.map → chunk-DDOTCGGA.js.map} +0 -0
  214. /package/build/modern/{chunk-F72ZABKX.js.map → chunk-F4LTOZAN.js.map} +0 -0
  215. /package/build/modern/{chunk-NKM6PISB.js.map → chunk-F7EWTOML.js.map} +0 -0
  216. /package/build/modern/{chunk-7MM5KYEX.js.map → chunk-GI6CSUU4.js.map} +0 -0
  217. /package/build/modern/{chunk-W4DXACNV.js.map → chunk-O7QVCF3H.js.map} +0 -0
  218. /package/build/modern/{chunk-XL4JREDT.js.map → chunk-S25RHYZV.js.map} +0 -0
  219. /package/build/modern/{chunk-NB6DV4VA.js.map → chunk-W2LSPRQ3.js.map} +0 -0
  220. /package/build/modern/{chunk-NMNONSHU.js.map → chunk-XVU2NQCW.js.map} +0 -0
  221. /package/build/modern/{aria-helpers/tabs.aria.js.map → components/Accordion.js.map} +0 -0
  222. /package/build/modern/components/{Tab.js.map → AccordionItemGroup.js.map} +0 -0
  223. /package/build/modern/components/{TabList.js.map → DatePicker.client.js.map} +0 -0
  224. /package/build/modern/components/{TabPanel.js.map → DatePicker.server.js.map} +0 -0
@@ -1,17 +1,18 @@
1
1
  'use client'
2
2
 
3
+ import { Tabs as ArkTabs } from '@ark-ui/react/tabs'
3
4
  import { tabs, type TabsVariantProps } from '@cerberus/styled-system/recipes'
4
5
  import type { Pretty } from '@cerberus/styled-system/types'
5
6
  import {
6
7
  createContext,
8
+ useCallback,
7
9
  useContext,
8
10
  useEffect,
9
11
  useMemo,
10
- useRef,
11
12
  useState,
12
- type MutableRefObject,
13
13
  type PropsWithChildren,
14
14
  } from 'react'
15
+ import { getLocalStorage, setLocalStorage } from '../utils/localStorage'
15
16
 
16
17
  /**
17
18
  * This module provides a Tabs component and a hook to access its context.
@@ -19,103 +20,103 @@ import {
19
20
  */
20
21
 
21
22
  export interface TabsContextValue {
22
- /**
23
- * The ref for the tabs.
24
- */
25
- tabs: MutableRefObject<HTMLButtonElement[]>
26
- /**
27
- * The id of the tabs component.
28
- */
29
- id: string
30
- /**
31
- * The active tab id.
32
- */
33
- active: string
34
23
  /**
35
24
  * The styles for the tabs.
36
25
  */
37
- styles: Pretty<Record<'tabList' | 'tab' | 'tabPanel', string>>
38
- /**
39
- * Called when the active tab is updated.
40
- */
41
- onTabUpdate: (active: string) => void
26
+ styles: {
27
+ list: Pretty<string>
28
+ trigger: Pretty<string>
29
+ content: Pretty<string>
30
+ indicator: Pretty<string>
31
+ }
42
32
  }
43
33
 
44
34
  export const TabsContext = createContext<TabsContextValue | null>(null)
45
35
 
46
- export interface TabsProps {
36
+ export interface TabsProviderBaseProps extends ArkTabs.RootProps {
47
37
  /**
48
38
  * A unique identifier for the Tabs component. Typically used when there are
49
- * multiple Tabs components on the same page.
39
+ * multiple Tabs components on the same page and you want to uniquely cache
40
+ * the active tab state.
50
41
  */
51
- id?: string
42
+ uuid?: string
52
43
  /**
53
- * The default active tab id.
44
+ * The default tab to display when the component is first rendered.
54
45
  */
55
- active?: string
46
+ defaultValue?: string
56
47
  /**
57
48
  * Whether to cache the active tab state in local storage.
58
49
  */
59
50
  cache?: boolean
60
51
  }
61
52
 
53
+ export type TabsProviderProps = TabsProviderBaseProps & TabsVariantProps
54
+
62
55
  /**
63
56
  * The Tabs component provides a context to manage tab state.
64
- * @see https://cerberus.digitalu.design/react/tabs
57
+ * @definition [Tabs docs](https://cerberus.digitalu.design/react/tabs)
65
58
  * @example
66
59
  * ```tsx
67
60
  * <Tabs cache>
68
- * <TabList description="Button details">
69
- * <Tab id="overview">Overview</Tab>
70
- * <Tab id="guidelines">Guidelines</Tab>
71
- * </TabList>
72
- * <TabPanels>
73
- * <TabPanel id="overview">Overview content</TabPanel>
74
- * <TabPanel id="guidelines">Guidelines content</TabPanel>
75
- * </TabPanels>
61
+ * <TabsList>
62
+ * <Tab value="overview">Overview</Tab>
63
+ * <Tab value="guidelines">Guidelines</Tab>
64
+ * </TabsList>
65
+ * <TabPanel value="overview">Overview content</TabPanel>
66
+ * <TabPanel value="guidelines">Guidelines content</TabPanel>
76
67
  * </Tabs>
77
68
  * ```
78
69
  */
79
- export function Tabs(
80
- props: PropsWithChildren<TabsProps & TabsVariantProps>,
81
- ): JSX.Element {
82
- const { cache, active, id, palette } = props
83
- const [activeTab, setActiveTab] = useState(() => (cache ? '' : active ?? ''))
84
- const tabsList = useRef<HTMLButtonElement[]>([])
85
- const uuid = useMemo(() => {
86
- return id ? `cerberus-tabs-${id}` : 'cerberus-tabs'
87
- }, [id])
70
+ export function Tabs(props: PropsWithChildren<TabsProviderProps>): JSX.Element {
71
+ const { cache, defaultValue, palette, uuid, ...arkProps } = props
72
+ const [activeTab, setActiveTab] = useState<string | undefined>(() =>
73
+ cache ? '' : defaultValue,
74
+ )
75
+ const styles = tabs({ palette })
88
76
 
89
- const value = useMemo(
90
- () => ({
91
- tabs: tabsList,
92
- id: uuid,
93
- active: activeTab,
94
- styles: tabs({ palette }),
95
- onTabUpdate: setActiveTab,
96
- }),
97
- [activeTab, setActiveTab, palette, uuid, tabsList],
77
+ const cacheKey = useMemo(
78
+ () => (uuid ? `cerberus-tabs-${uuid}` : 'cerberus-tabs'),
79
+ [uuid],
98
80
  )
99
81
 
100
- // Get the active tab from local storage
101
- useEffect(() => {
102
- if (cache) {
103
- const cachedTab = window.localStorage.getItem(uuid)
104
- setActiveTab(
105
- cache ? cachedTab || (props.active ?? '') : props.active ?? '',
106
- )
107
- }
108
- }, [cache, active, uuid])
82
+ const handleValueChange = useCallback(
83
+ (details: { value: string }) => {
84
+ if (cache) {
85
+ setLocalStorage(cacheKey, details.value)
86
+ }
87
+ setActiveTab(details.value)
88
+ },
89
+ [cache],
90
+ )
109
91
 
110
- // Update the active tab in local storage
111
92
  useEffect(() => {
112
- if (cache && activeTab) {
113
- window.localStorage.setItem(uuid, activeTab)
93
+ if (cache && !activeTab) {
94
+ const cachedTab = getLocalStorage(cacheKey, defaultValue ?? '')
95
+ setActiveTab(cachedTab)
114
96
  }
115
- }, [activeTab, cache])
97
+ }, [cache, defaultValue, activeTab])
98
+
99
+ const value = useMemo(
100
+ () => ({
101
+ active: activeTab,
102
+ styles,
103
+ }),
104
+ [activeTab, palette, styles],
105
+ )
116
106
 
117
107
  return (
118
- <TabsContext.Provider value={value}>{props.children}</TabsContext.Provider>
108
+ <TabsContext.Provider value={value}>
109
+ <ArkTabs.Root
110
+ {...arkProps}
111
+ aria-busy={!activeTab}
112
+ className={styles.root}
113
+ defaultValue={defaultValue}
114
+ onValueChange={handleValueChange}
115
+ value={activeTab}
116
+ >
117
+ {props.children}
118
+ </ArkTabs.Root>
119
+ </TabsContext.Provider>
119
120
  )
120
121
  }
121
122
 
@@ -129,6 +129,18 @@ export function formatMilitaryDate(input: string): string {
129
129
  return [day, month, year].filter(Boolean).join(' ')
130
130
  }
131
131
 
132
+ /**
133
+ * Formats a date string to US Military format.
134
+ * @param date The date string to format (i.e., '2024-01-01')
135
+ * @returns The formatted date string in US Military format (DD MMM YYYY)
136
+ */
137
+ export function formatISOToMilitary(date: string): string {
138
+ const [year, month, day] = date.split('-')
139
+ const monthIndex = parseInt(month, 10) - 1
140
+ const monthStr = MONTHS[monthIndex]
141
+ return `${day} ${monthStr} ${year}`
142
+ }
143
+
132
144
  /**
133
145
  * Date formatting options
134
146
  * @example
package/src/index.ts CHANGED
@@ -5,11 +5,15 @@
5
5
 
6
6
  // components
7
7
 
8
+ export * from './components/Accordion'
9
+ export * from './components/AccordionItemGroup'
8
10
  export * from './components/Admonition'
9
11
  export * from './components/Avatar'
10
12
  export * from './components/Button'
11
13
  export * from './components/Checkbox'
12
14
  export * from './components/CircularProgress'
15
+ export * from './components/DatePicker.client'
16
+ export * from './components/DatePicker.server'
13
17
  export * from './components/Droppable'
14
18
  export * from './components/FieldMessage'
15
19
  export * from './components/FeatureFlag'
@@ -37,15 +41,14 @@ export * from './components/ProgressBar'
37
41
  export * from './components/Radio'
38
42
  export * from './components/Select'
39
43
  export * from './components/Spinner'
40
- export * from './components/Tab'
41
- export * from './components/TabList'
42
- export * from './components/TabPanel'
44
+ export * from './components/Tabs.client'
43
45
  export * from './components/Table'
44
46
  export * from './components/Thead'
45
47
  export * from './components/Th'
46
48
  export * from './components/Td'
47
49
  export * from './components/Tbody'
48
50
  export * from './components/Tag'
51
+ export * from './components/Text'
49
52
  export * from './components/Textarea'
50
53
  export * from './components/Toggle'
51
54
  export * from './components/Tooltip'
@@ -74,7 +77,6 @@ export * from './hooks/useRootColors'
74
77
  // aria-helpers
75
78
 
76
79
  export * from './aria-helpers/nav-menu.aria'
77
- export * from './aria-helpers/tabs.aria'
78
80
  export * from './aria-helpers/trap-focus.aria'
79
81
 
80
82
  // utils
@@ -17,3 +17,5 @@ export function formatNotifyCount(count: number): string {
17
17
  if (count > 99) return '99+'
18
18
  return count.toString()
19
19
  }
20
+
21
+ export * from './localStorage'
@@ -0,0 +1,28 @@
1
+ 'use client'
2
+
3
+ /**
4
+ * A utility function to get a value from local storage.
5
+ * @param key The key to get from local storage.
6
+ * @param defaultValue The fallback value if the key is not found.
7
+ * @returns key or defaultValue
8
+ */
9
+ export function getLocalStorage<T extends string>(
10
+ key: string,
11
+ defaultValue: T,
12
+ ): T {
13
+ const value = window.localStorage.getItem(key)
14
+ if (value) {
15
+ return value as T
16
+ }
17
+ return defaultValue
18
+ }
19
+
20
+ /**
21
+ * A utility function to set a value in local storage.
22
+ * @param key The key to set in local storage.
23
+ * @param value The value to set in local storage.
24
+ */
25
+ export function setLocalStorage<T>(key: string, value: T): void {
26
+ const stringValue = typeof value === 'string' ? value : JSON.stringify(value)
27
+ window.localStorage.setItem(key, stringValue)
28
+ }
@@ -1,100 +0,0 @@
1
- "use strict";
2
- "use client";
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __export = (target, all) => {
8
- for (var name in all)
9
- __defProp(target, name, { get: all[name], enumerable: true });
10
- };
11
- var __copyProps = (to, from, except, desc) => {
12
- if (from && typeof from === "object" || typeof from === "function") {
13
- for (let key of __getOwnPropNames(from))
14
- if (!__hasOwnProp.call(to, key) && key !== except)
15
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
- }
17
- return to;
18
- };
19
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
-
21
- // src/aria-helpers/tabs.aria.ts
22
- var tabs_aria_exports = {};
23
- __export(tabs_aria_exports, {
24
- useTabsKeyboardNavigation: () => useTabsKeyboardNavigation
25
- });
26
- module.exports = __toCommonJS(tabs_aria_exports);
27
- var import_react2 = require("react");
28
-
29
- // src/context/tabs.tsx
30
- var import_recipes = require("@cerberus/styled-system/recipes");
31
- var import_react = require("react");
32
- var import_jsx_runtime = require("react/jsx-runtime");
33
- var TabsContext = (0, import_react.createContext)(null);
34
- function useTabsContext() {
35
- const context = (0, import_react.useContext)(TabsContext);
36
- if (!context) {
37
- throw new Error("useTabsContext must be used within a Tabs Provider.");
38
- }
39
- return context;
40
- }
41
-
42
- // src/aria-helpers/tabs.aria.ts
43
- function getNextIndex(index, length) {
44
- return index === length - 1 ? 0 : index + 1;
45
- }
46
- function getPrevIndex(index, length) {
47
- return index === 0 ? length - 1 : index - 1;
48
- }
49
- function useTabsKeyboardNavigation() {
50
- const { tabs: tabs2 } = useTabsContext();
51
- const [activeTab, setActiveTab] = (0, import_react2.useState)(-1);
52
- (0, import_react2.useEffect)(() => {
53
- const handleKeyDown = (event) => {
54
- const index = activeTab === -1 ? tabs2.current.findIndex((tab) => tab.ariaSelected === "true") : activeTab;
55
- const nextIndex = getNextIndex(index, tabs2.current.length);
56
- const prevIndex = getPrevIndex(index, tabs2.current.length);
57
- if (index === -1) return;
58
- switch (event.key) {
59
- case "ArrowLeft":
60
- event.preventDefault();
61
- setActiveTab(prevIndex);
62
- tabs2.current[prevIndex].focus();
63
- break;
64
- case "ArrowRight":
65
- event.preventDefault();
66
- setActiveTab(nextIndex);
67
- tabs2.current[nextIndex].focus();
68
- break;
69
- case "Home":
70
- event.preventDefault();
71
- setActiveTab(0);
72
- tabs2.current[0].focus();
73
- break;
74
- case "End":
75
- event.preventDefault();
76
- setActiveTab(tabs2.current.length - 1);
77
- tabs2.current[tabs2.current.length - 1].focus();
78
- break;
79
- default:
80
- break;
81
- }
82
- };
83
- document.addEventListener("keydown", handleKeyDown);
84
- return () => {
85
- document.removeEventListener("keydown", handleKeyDown);
86
- };
87
- }, [activeTab, tabs2.current]);
88
- return {
89
- ref: (tab) => {
90
- if (tab && !tabs2.current.includes(tab)) {
91
- tabs2.current.push(tab);
92
- }
93
- }
94
- };
95
- }
96
- // Annotate the CommonJS export names for ESM import in node:
97
- 0 && (module.exports = {
98
- useTabsKeyboardNavigation
99
- });
100
- //# sourceMappingURL=tabs.aria.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/aria-helpers/tabs.aria.ts","../../../src/context/tabs.tsx"],"sourcesContent":["'use client'\n\nimport { useEffect, useState } from 'react'\nimport { useTabsContext } from '../context/tabs'\n\nfunction getNextIndex(index: number, length: number) {\n return index === length - 1 ? 0 : index + 1\n}\n\nfunction getPrevIndex(index: number, length: number) {\n return index === 0 ? length - 1 : index - 1\n}\n\nexport function useTabsKeyboardNavigation() {\n const { tabs } = useTabsContext()\n const [activeTab, setActiveTab] = useState(-1)\n\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n const index =\n activeTab === -1\n ? tabs.current.findIndex((tab) => tab.ariaSelected === 'true')\n : activeTab\n const nextIndex = getNextIndex(index, tabs.current.length)\n const prevIndex = getPrevIndex(index, tabs.current.length)\n\n // If the active tab is not found, do nothing\n if (index === -1) return\n\n switch (event.key) {\n case 'ArrowLeft':\n event.preventDefault()\n setActiveTab(prevIndex)\n tabs.current[prevIndex].focus()\n break\n case 'ArrowRight':\n event.preventDefault()\n setActiveTab(nextIndex)\n tabs.current[nextIndex].focus()\n break\n case 'Home':\n event.preventDefault()\n setActiveTab(0)\n tabs.current[0].focus()\n break\n case 'End':\n event.preventDefault()\n setActiveTab(tabs.current.length - 1)\n tabs.current[tabs.current.length - 1].focus()\n break\n default:\n break\n }\n }\n\n document.addEventListener('keydown', handleKeyDown)\n\n return () => {\n document.removeEventListener('keydown', handleKeyDown)\n }\n }, [activeTab, tabs.current])\n\n return {\n ref: (tab: HTMLButtonElement) => {\n if (tab && !tabs.current.includes(tab)) {\n tabs.current.push(tab)\n }\n },\n }\n}\n","'use client'\n\nimport { tabs, type TabsVariantProps } from '@cerberus/styled-system/recipes'\nimport type { Pretty } from '@cerberus/styled-system/types'\nimport {\n createContext,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type MutableRefObject,\n type PropsWithChildren,\n} from 'react'\n\n/**\n * This module provides a Tabs component and a hook to access its context.\n * @module Tabs\n */\n\nexport interface TabsContextValue {\n /**\n * The ref for the tabs.\n */\n tabs: MutableRefObject<HTMLButtonElement[]>\n /**\n * The id of the tabs component.\n */\n id: string\n /**\n * The active tab id.\n */\n active: string\n /**\n * The styles for the tabs.\n */\n styles: Pretty<Record<'tabList' | 'tab' | 'tabPanel', string>>\n /**\n * Called when the active tab is updated.\n */\n onTabUpdate: (active: string) => void\n}\n\nexport const TabsContext = createContext<TabsContextValue | null>(null)\n\nexport interface TabsProps {\n /**\n * A unique identifier for the Tabs component. Typically used when there are\n * multiple Tabs components on the same page.\n */\n id?: string\n /**\n * The default active tab id.\n */\n active?: string\n /**\n * Whether to cache the active tab state in local storage.\n */\n cache?: boolean\n}\n\n/**\n * The Tabs component provides a context to manage tab state.\n * @see https://cerberus.digitalu.design/react/tabs\n * @example\n * ```tsx\n * <Tabs cache>\n * <TabList description=\"Button details\">\n * <Tab id=\"overview\">Overview</Tab>\n * <Tab id=\"guidelines\">Guidelines</Tab>\n * </TabList>\n * <TabPanels>\n * <TabPanel id=\"overview\">Overview content</TabPanel>\n * <TabPanel id=\"guidelines\">Guidelines content</TabPanel>\n * </TabPanels>\n * </Tabs>\n * ```\n */\nexport function Tabs(\n props: PropsWithChildren<TabsProps & TabsVariantProps>,\n): JSX.Element {\n const { cache, active, id, palette } = props\n const [activeTab, setActiveTab] = useState(() => (cache ? '' : active ?? ''))\n const tabsList = useRef<HTMLButtonElement[]>([])\n const uuid = useMemo(() => {\n return id ? `cerberus-tabs-${id}` : 'cerberus-tabs'\n }, [id])\n\n const value = useMemo(\n () => ({\n tabs: tabsList,\n id: uuid,\n active: activeTab,\n styles: tabs({ palette }),\n onTabUpdate: setActiveTab,\n }),\n [activeTab, setActiveTab, palette, uuid, tabsList],\n )\n\n // Get the active tab from local storage\n useEffect(() => {\n if (cache) {\n const cachedTab = window.localStorage.getItem(uuid)\n setActiveTab(\n cache ? cachedTab || (props.active ?? '') : props.active ?? '',\n )\n }\n }, [cache, active, uuid])\n\n // Update the active tab in local storage\n useEffect(() => {\n if (cache && activeTab) {\n window.localStorage.setItem(uuid, activeTab)\n }\n }, [activeTab, cache])\n\n return (\n <TabsContext.Provider value={value}>{props.children}</TabsContext.Provider>\n )\n}\n\n/**\n * Used to access the tabs context.\n * @returns The tabs context.\n */\nexport function useTabsContext(): TabsContextValue {\n const context = useContext(TabsContext)\n if (!context) {\n throw new Error('useTabsContext must be used within a Tabs Provider.')\n }\n return context\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,IAAAA,gBAAoC;;;ACApC,qBAA4C;AAE5C,mBASO;AAwGH;AA1EG,IAAM,kBAAc,4BAAuC,IAAI;AAkF/D,SAAS,iBAAmC;AACjD,QAAM,cAAU,yBAAW,WAAW;AACtC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,qDAAqD;AAAA,EACvE;AACA,SAAO;AACT;;;AD9HA,SAAS,aAAa,OAAe,QAAgB;AACnD,SAAO,UAAU,SAAS,IAAI,IAAI,QAAQ;AAC5C;AAEA,SAAS,aAAa,OAAe,QAAgB;AACnD,SAAO,UAAU,IAAI,SAAS,IAAI,QAAQ;AAC5C;AAEO,SAAS,4BAA4B;AAC1C,QAAM,EAAE,MAAAC,MAAK,IAAI,eAAe;AAChC,QAAM,CAAC,WAAW,YAAY,QAAI,wBAAS,EAAE;AAE7C,+BAAU,MAAM;AACd,UAAM,gBAAgB,CAAC,UAAyB;AAC9C,YAAM,QACJ,cAAc,KACVA,MAAK,QAAQ,UAAU,CAAC,QAAQ,IAAI,iBAAiB,MAAM,IAC3D;AACN,YAAM,YAAY,aAAa,OAAOA,MAAK,QAAQ,MAAM;AACzD,YAAM,YAAY,aAAa,OAAOA,MAAK,QAAQ,MAAM;AAGzD,UAAI,UAAU,GAAI;AAElB,cAAQ,MAAM,KAAK;AAAA,QACjB,KAAK;AACH,gBAAM,eAAe;AACrB,uBAAa,SAAS;AACtB,UAAAA,MAAK,QAAQ,SAAS,EAAE,MAAM;AAC9B;AAAA,QACF,KAAK;AACH,gBAAM,eAAe;AACrB,uBAAa,SAAS;AACtB,UAAAA,MAAK,QAAQ,SAAS,EAAE,MAAM;AAC9B;AAAA,QACF,KAAK;AACH,gBAAM,eAAe;AACrB,uBAAa,CAAC;AACd,UAAAA,MAAK,QAAQ,CAAC,EAAE,MAAM;AACtB;AAAA,QACF,KAAK;AACH,gBAAM,eAAe;AACrB,uBAAaA,MAAK,QAAQ,SAAS,CAAC;AACpC,UAAAA,MAAK,QAAQA,MAAK,QAAQ,SAAS,CAAC,EAAE,MAAM;AAC5C;AAAA,QACF;AACE;AAAA,MACJ;AAAA,IACF;AAEA,aAAS,iBAAiB,WAAW,aAAa;AAElD,WAAO,MAAM;AACX,eAAS,oBAAoB,WAAW,aAAa;AAAA,IACvD;AAAA,EACF,GAAG,CAAC,WAAWA,MAAK,OAAO,CAAC;AAE5B,SAAO;AAAA,IACL,KAAK,CAAC,QAA2B;AAC/B,UAAI,OAAO,CAACA,MAAK,QAAQ,SAAS,GAAG,GAAG;AACtC,QAAAA,MAAK,QAAQ,KAAK,GAAG;AAAA,MACvB;AAAA,IACF;AAAA,EACF;AACF;","names":["import_react","tabs"]}
@@ -1,135 +0,0 @@
1
- "use strict";
2
- "use client";
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __export = (target, all) => {
8
- for (var name in all)
9
- __defProp(target, name, { get: all[name], enumerable: true });
10
- };
11
- var __copyProps = (to, from, except, desc) => {
12
- if (from && typeof from === "object" || typeof from === "function") {
13
- for (let key of __getOwnPropNames(from))
14
- if (!__hasOwnProp.call(to, key) && key !== except)
15
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
- }
17
- return to;
18
- };
19
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
-
21
- // src/components/Tab.tsx
22
- var Tab_exports = {};
23
- __export(Tab_exports, {
24
- Tab: () => Tab
25
- });
26
- module.exports = __toCommonJS(Tab_exports);
27
- var import_react3 = require("react");
28
-
29
- // src/context/tabs.tsx
30
- var import_recipes = require("@cerberus/styled-system/recipes");
31
- var import_react = require("react");
32
- var import_jsx_runtime = require("react/jsx-runtime");
33
- var TabsContext = (0, import_react.createContext)(null);
34
- function useTabsContext() {
35
- const context = (0, import_react.useContext)(TabsContext);
36
- if (!context) {
37
- throw new Error("useTabsContext must be used within a Tabs Provider.");
38
- }
39
- return context;
40
- }
41
-
42
- // src/components/Tab.tsx
43
- var import_css = require("@cerberus/styled-system/css");
44
-
45
- // src/aria-helpers/tabs.aria.ts
46
- var import_react2 = require("react");
47
- function getNextIndex(index, length) {
48
- return index === length - 1 ? 0 : index + 1;
49
- }
50
- function getPrevIndex(index, length) {
51
- return index === 0 ? length - 1 : index - 1;
52
- }
53
- function useTabsKeyboardNavigation() {
54
- const { tabs: tabs2 } = useTabsContext();
55
- const [activeTab, setActiveTab] = (0, import_react2.useState)(-1);
56
- (0, import_react2.useEffect)(() => {
57
- const handleKeyDown = (event) => {
58
- const index = activeTab === -1 ? tabs2.current.findIndex((tab) => tab.ariaSelected === "true") : activeTab;
59
- const nextIndex = getNextIndex(index, tabs2.current.length);
60
- const prevIndex = getPrevIndex(index, tabs2.current.length);
61
- if (index === -1) return;
62
- switch (event.key) {
63
- case "ArrowLeft":
64
- event.preventDefault();
65
- setActiveTab(prevIndex);
66
- tabs2.current[prevIndex].focus();
67
- break;
68
- case "ArrowRight":
69
- event.preventDefault();
70
- setActiveTab(nextIndex);
71
- tabs2.current[nextIndex].focus();
72
- break;
73
- case "Home":
74
- event.preventDefault();
75
- setActiveTab(0);
76
- tabs2.current[0].focus();
77
- break;
78
- case "End":
79
- event.preventDefault();
80
- setActiveTab(tabs2.current.length - 1);
81
- tabs2.current[tabs2.current.length - 1].focus();
82
- break;
83
- default:
84
- break;
85
- }
86
- };
87
- document.addEventListener("keydown", handleKeyDown);
88
- return () => {
89
- document.removeEventListener("keydown", handleKeyDown);
90
- };
91
- }, [activeTab, tabs2.current]);
92
- return {
93
- ref: (tab) => {
94
- if (tab && !tabs2.current.includes(tab)) {
95
- tabs2.current.push(tab);
96
- }
97
- }
98
- };
99
- }
100
-
101
- // src/components/Tab.tsx
102
- var import_jsx_runtime2 = require("react/jsx-runtime");
103
- function Tab(props) {
104
- const { value, ...nativeProps } = props;
105
- const { active, onTabUpdate, styles } = useTabsContext();
106
- const [isPending, startTransition] = (0, import_react3.useTransition)();
107
- const { ref } = useTabsKeyboardNavigation();
108
- const isActive = (0, import_react3.useMemo)(() => active === value, [active, value]);
109
- function handleClick(e) {
110
- var _a;
111
- (_a = props.onClick) == null ? void 0 : _a.call(props, e);
112
- startTransition(() => onTabUpdate(e.currentTarget.value));
113
- }
114
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
115
- "button",
116
- {
117
- ...nativeProps,
118
- ...!isActive && { tabIndex: -1 },
119
- "aria-controls": `panel:${value}`,
120
- "aria-busy": isPending,
121
- "aria-selected": isActive,
122
- id: `tab:${value}`,
123
- className: (0, import_css.cx)(nativeProps.className, styles.tab),
124
- onClick: handleClick,
125
- role: "tab",
126
- ref,
127
- value
128
- }
129
- );
130
- }
131
- // Annotate the CommonJS export names for ESM import in node:
132
- 0 && (module.exports = {
133
- Tab
134
- });
135
- //# sourceMappingURL=Tab.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/components/Tab.tsx","../../../src/context/tabs.tsx","../../../src/aria-helpers/tabs.aria.ts"],"sourcesContent":["'use client'\n\nimport {\n useMemo,\n useTransition,\n type ButtonHTMLAttributes,\n type MouseEvent,\n} from 'react'\nimport { useTabsContext } from '../context/tabs'\nimport { cx } from '@cerberus/styled-system/css'\nimport { useTabsKeyboardNavigation } from '../aria-helpers/tabs.aria'\n\n/**\n * This module provides a Tab component.\n * @module\n */\n\nexport interface TabProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n /**\n * The id of the tab that will be tracked as the active tab and used for aria\n * attributes.\n */\n value: string\n}\n\n/**\n * The Tab component provides a tab element to be used in a TabList.\n * @definition [ARIA Target Size](https://www.w3.org/WAI/WCAG21/Understanding/target-size.html#:~:text=Understanding%20SC%202.5.,%3ATarget%20Size%20(Level%20AAA)&text=The%20size%20of%20the%20target,Equivalent)\n * @see https://cerberus.digitalu.design/react/tabs\n * @memberof module:Tabs\n * @example\n * ```tsx\n * <Tabs>\n * <TabList description=\"Profile settings\">\n * <Tab value=\"overview\">Overview</Tab>\n * </TabList>\n * <TabPanel tab=\"overview\">...</TabPanel>\n * </Tabs>\n * ```\n */\nexport function Tab(props: TabProps) {\n const { value, ...nativeProps } = props\n const { active, onTabUpdate, styles } = useTabsContext()\n const [isPending, startTransition] = useTransition()\n const { ref } = useTabsKeyboardNavigation()\n const isActive = useMemo(() => active === value, [active, value])\n\n function handleClick(e: MouseEvent<HTMLButtonElement>) {\n props.onClick?.(e)\n startTransition(() => onTabUpdate(e.currentTarget.value))\n }\n\n return (\n <button\n {...nativeProps}\n {...(!isActive && { tabIndex: -1 })}\n aria-controls={`panel:${value}`}\n aria-busy={isPending}\n aria-selected={isActive}\n id={`tab:${value}`}\n className={cx(nativeProps.className, styles.tab)}\n onClick={handleClick}\n role=\"tab\"\n ref={ref}\n value={value}\n />\n )\n}\n","'use client'\n\nimport { tabs, type TabsVariantProps } from '@cerberus/styled-system/recipes'\nimport type { Pretty } from '@cerberus/styled-system/types'\nimport {\n createContext,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type MutableRefObject,\n type PropsWithChildren,\n} from 'react'\n\n/**\n * This module provides a Tabs component and a hook to access its context.\n * @module Tabs\n */\n\nexport interface TabsContextValue {\n /**\n * The ref for the tabs.\n */\n tabs: MutableRefObject<HTMLButtonElement[]>\n /**\n * The id of the tabs component.\n */\n id: string\n /**\n * The active tab id.\n */\n active: string\n /**\n * The styles for the tabs.\n */\n styles: Pretty<Record<'tabList' | 'tab' | 'tabPanel', string>>\n /**\n * Called when the active tab is updated.\n */\n onTabUpdate: (active: string) => void\n}\n\nexport const TabsContext = createContext<TabsContextValue | null>(null)\n\nexport interface TabsProps {\n /**\n * A unique identifier for the Tabs component. Typically used when there are\n * multiple Tabs components on the same page.\n */\n id?: string\n /**\n * The default active tab id.\n */\n active?: string\n /**\n * Whether to cache the active tab state in local storage.\n */\n cache?: boolean\n}\n\n/**\n * The Tabs component provides a context to manage tab state.\n * @see https://cerberus.digitalu.design/react/tabs\n * @example\n * ```tsx\n * <Tabs cache>\n * <TabList description=\"Button details\">\n * <Tab id=\"overview\">Overview</Tab>\n * <Tab id=\"guidelines\">Guidelines</Tab>\n * </TabList>\n * <TabPanels>\n * <TabPanel id=\"overview\">Overview content</TabPanel>\n * <TabPanel id=\"guidelines\">Guidelines content</TabPanel>\n * </TabPanels>\n * </Tabs>\n * ```\n */\nexport function Tabs(\n props: PropsWithChildren<TabsProps & TabsVariantProps>,\n): JSX.Element {\n const { cache, active, id, palette } = props\n const [activeTab, setActiveTab] = useState(() => (cache ? '' : active ?? ''))\n const tabsList = useRef<HTMLButtonElement[]>([])\n const uuid = useMemo(() => {\n return id ? `cerberus-tabs-${id}` : 'cerberus-tabs'\n }, [id])\n\n const value = useMemo(\n () => ({\n tabs: tabsList,\n id: uuid,\n active: activeTab,\n styles: tabs({ palette }),\n onTabUpdate: setActiveTab,\n }),\n [activeTab, setActiveTab, palette, uuid, tabsList],\n )\n\n // Get the active tab from local storage\n useEffect(() => {\n if (cache) {\n const cachedTab = window.localStorage.getItem(uuid)\n setActiveTab(\n cache ? cachedTab || (props.active ?? '') : props.active ?? '',\n )\n }\n }, [cache, active, uuid])\n\n // Update the active tab in local storage\n useEffect(() => {\n if (cache && activeTab) {\n window.localStorage.setItem(uuid, activeTab)\n }\n }, [activeTab, cache])\n\n return (\n <TabsContext.Provider value={value}>{props.children}</TabsContext.Provider>\n )\n}\n\n/**\n * Used to access the tabs context.\n * @returns The tabs context.\n */\nexport function useTabsContext(): TabsContextValue {\n const context = useContext(TabsContext)\n if (!context) {\n throw new Error('useTabsContext must be used within a Tabs Provider.')\n }\n return context\n}\n","'use client'\n\nimport { useEffect, useState } from 'react'\nimport { useTabsContext } from '../context/tabs'\n\nfunction getNextIndex(index: number, length: number) {\n return index === length - 1 ? 0 : index + 1\n}\n\nfunction getPrevIndex(index: number, length: number) {\n return index === 0 ? length - 1 : index - 1\n}\n\nexport function useTabsKeyboardNavigation() {\n const { tabs } = useTabsContext()\n const [activeTab, setActiveTab] = useState(-1)\n\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n const index =\n activeTab === -1\n ? tabs.current.findIndex((tab) => tab.ariaSelected === 'true')\n : activeTab\n const nextIndex = getNextIndex(index, tabs.current.length)\n const prevIndex = getPrevIndex(index, tabs.current.length)\n\n // If the active tab is not found, do nothing\n if (index === -1) return\n\n switch (event.key) {\n case 'ArrowLeft':\n event.preventDefault()\n setActiveTab(prevIndex)\n tabs.current[prevIndex].focus()\n break\n case 'ArrowRight':\n event.preventDefault()\n setActiveTab(nextIndex)\n tabs.current[nextIndex].focus()\n break\n case 'Home':\n event.preventDefault()\n setActiveTab(0)\n tabs.current[0].focus()\n break\n case 'End':\n event.preventDefault()\n setActiveTab(tabs.current.length - 1)\n tabs.current[tabs.current.length - 1].focus()\n break\n default:\n break\n }\n }\n\n document.addEventListener('keydown', handleKeyDown)\n\n return () => {\n document.removeEventListener('keydown', handleKeyDown)\n }\n }, [activeTab, tabs.current])\n\n return {\n ref: (tab: HTMLButtonElement) => {\n if (tab && !tabs.current.includes(tab)) {\n tabs.current.push(tab)\n }\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,IAAAA,gBAKO;;;ACLP,qBAA4C;AAE5C,mBASO;AAwGH;AA1EG,IAAM,kBAAc,4BAAuC,IAAI;AAkF/D,SAAS,iBAAmC;AACjD,QAAM,cAAU,yBAAW,WAAW;AACtC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,qDAAqD;AAAA,EACvE;AACA,SAAO;AACT;;;AD1HA,iBAAmB;;;AEPnB,IAAAC,gBAAoC;AAGpC,SAAS,aAAa,OAAe,QAAgB;AACnD,SAAO,UAAU,SAAS,IAAI,IAAI,QAAQ;AAC5C;AAEA,SAAS,aAAa,OAAe,QAAgB;AACnD,SAAO,UAAU,IAAI,SAAS,IAAI,QAAQ;AAC5C;AAEO,SAAS,4BAA4B;AAC1C,QAAM,EAAE,MAAAC,MAAK,IAAI,eAAe;AAChC,QAAM,CAAC,WAAW,YAAY,QAAI,wBAAS,EAAE;AAE7C,+BAAU,MAAM;AACd,UAAM,gBAAgB,CAAC,UAAyB;AAC9C,YAAM,QACJ,cAAc,KACVA,MAAK,QAAQ,UAAU,CAAC,QAAQ,IAAI,iBAAiB,MAAM,IAC3D;AACN,YAAM,YAAY,aAAa,OAAOA,MAAK,QAAQ,MAAM;AACzD,YAAM,YAAY,aAAa,OAAOA,MAAK,QAAQ,MAAM;AAGzD,UAAI,UAAU,GAAI;AAElB,cAAQ,MAAM,KAAK;AAAA,QACjB,KAAK;AACH,gBAAM,eAAe;AACrB,uBAAa,SAAS;AACtB,UAAAA,MAAK,QAAQ,SAAS,EAAE,MAAM;AAC9B;AAAA,QACF,KAAK;AACH,gBAAM,eAAe;AACrB,uBAAa,SAAS;AACtB,UAAAA,MAAK,QAAQ,SAAS,EAAE,MAAM;AAC9B;AAAA,QACF,KAAK;AACH,gBAAM,eAAe;AACrB,uBAAa,CAAC;AACd,UAAAA,MAAK,QAAQ,CAAC,EAAE,MAAM;AACtB;AAAA,QACF,KAAK;AACH,gBAAM,eAAe;AACrB,uBAAaA,MAAK,QAAQ,SAAS,CAAC;AACpC,UAAAA,MAAK,QAAQA,MAAK,QAAQ,SAAS,CAAC,EAAE,MAAM;AAC5C;AAAA,QACF;AACE;AAAA,MACJ;AAAA,IACF;AAEA,aAAS,iBAAiB,WAAW,aAAa;AAElD,WAAO,MAAM;AACX,eAAS,oBAAoB,WAAW,aAAa;AAAA,IACvD;AAAA,EACF,GAAG,CAAC,WAAWA,MAAK,OAAO,CAAC;AAE5B,SAAO;AAAA,IACL,KAAK,CAAC,QAA2B;AAC/B,UAAI,OAAO,CAACA,MAAK,QAAQ,SAAS,GAAG,GAAG;AACtC,QAAAA,MAAK,QAAQ,KAAK,GAAG;AAAA,MACvB;AAAA,IACF;AAAA,EACF;AACF;;;AFhBI,IAAAC,sBAAA;AAbG,SAAS,IAAI,OAAiB;AACnC,QAAM,EAAE,OAAO,GAAG,YAAY,IAAI;AAClC,QAAM,EAAE,QAAQ,aAAa,OAAO,IAAI,eAAe;AACvD,QAAM,CAAC,WAAW,eAAe,QAAI,6BAAc;AACnD,QAAM,EAAE,IAAI,IAAI,0BAA0B;AAC1C,QAAM,eAAW,uBAAQ,MAAM,WAAW,OAAO,CAAC,QAAQ,KAAK,CAAC;AAEhE,WAAS,YAAY,GAAkC;AA/CzD;AAgDI,gBAAM,YAAN,+BAAgB;AAChB,oBAAgB,MAAM,YAAY,EAAE,cAAc,KAAK,CAAC;AAAA,EAC1D;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACH,GAAI,CAAC,YAAY,EAAE,UAAU,GAAG;AAAA,MACjC,iBAAe,SAAS,KAAK;AAAA,MAC7B,aAAW;AAAA,MACX,iBAAe;AAAA,MACf,IAAI,OAAO,KAAK;AAAA,MAChB,eAAW,eAAG,YAAY,WAAW,OAAO,GAAG;AAAA,MAC/C,SAAS;AAAA,MACT,MAAK;AAAA,MACL;AAAA,MACA;AAAA;AAAA,EACF;AAEJ;","names":["import_react","import_react","tabs","import_jsx_runtime"]}
@@ -1,69 +0,0 @@
1
- "use strict";
2
- "use client";
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __export = (target, all) => {
8
- for (var name in all)
9
- __defProp(target, name, { get: all[name], enumerable: true });
10
- };
11
- var __copyProps = (to, from, except, desc) => {
12
- if (from && typeof from === "object" || typeof from === "function") {
13
- for (let key of __getOwnPropNames(from))
14
- if (!__hasOwnProp.call(to, key) && key !== except)
15
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
- }
17
- return to;
18
- };
19
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
-
21
- // src/components/TabList.tsx
22
- var TabList_exports = {};
23
- __export(TabList_exports, {
24
- TabList: () => TabList
25
- });
26
- module.exports = __toCommonJS(TabList_exports);
27
- var import_css = require("@cerberus/styled-system/css");
28
- var import_patterns = require("@cerberus/styled-system/patterns");
29
-
30
- // src/context/tabs.tsx
31
- var import_recipes = require("@cerberus/styled-system/recipes");
32
- var import_react = require("react");
33
- var import_jsx_runtime = require("react/jsx-runtime");
34
- var TabsContext = (0, import_react.createContext)(null);
35
- function useTabsContext() {
36
- const context = (0, import_react.useContext)(TabsContext);
37
- if (!context) {
38
- throw new Error("useTabsContext must be used within a Tabs Provider.");
39
- }
40
- return context;
41
- }
42
-
43
- // src/components/TabList.tsx
44
- var import_jsx_runtime2 = require("react/jsx-runtime");
45
- function TabList(props) {
46
- const { description, ...nativeProps } = props;
47
- const { id, styles } = useTabsContext();
48
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
49
- "div",
50
- {
51
- ...nativeProps,
52
- "aria-label": description,
53
- className: (0, import_css.cx)(
54
- nativeProps.className,
55
- (0, import_patterns.hstack)({
56
- gap: "0"
57
- }),
58
- styles.tabList
59
- ),
60
- id: id ?? nativeProps.id,
61
- role: "tablist"
62
- }
63
- );
64
- }
65
- // Annotate the CommonJS export names for ESM import in node:
66
- 0 && (module.exports = {
67
- TabList
68
- });
69
- //# sourceMappingURL=TabList.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/components/TabList.tsx","../../../src/context/tabs.tsx"],"sourcesContent":["'use client'\n\nimport { cx } from '@cerberus/styled-system/css'\nimport { hstack } from '@cerberus/styled-system/patterns'\nimport type { HTMLAttributes, PropsWithChildren } from 'react'\nimport { useTabsContext } from '../context/tabs'\n\n/**\n * This module provides a TabList component.\n * @module\n */\n\nexport interface TabListProps extends HTMLAttributes<HTMLDivElement> {\n /**\n * A description of what the tab list contains. Required for accessibility.\n */\n description: string\n}\n\n/**\n * The TabList component provides a container for tab elements.\n * @see https://cerberus.digitalu.design/react/tabs\n * @memberof module:Tabs\n * @example\n * ```tsx\n * <TabList description=\"Button details\">\n * <Tab id=\"overview\">Overview</Tab>\n * <Tab id=\"guidelines\">Guidelines</Tab>\n * </TabList>\n * ```\n */\nexport function TabList(props: PropsWithChildren<TabListProps>) {\n const { description, ...nativeProps } = props\n const { id, styles } = useTabsContext()\n\n return (\n <div\n {...nativeProps}\n aria-label={description}\n className={cx(\n nativeProps.className,\n hstack({\n gap: '0',\n }),\n styles.tabList,\n )}\n id={id ?? nativeProps.id}\n role=\"tablist\"\n />\n )\n}\n","'use client'\n\nimport { tabs, type TabsVariantProps } from '@cerberus/styled-system/recipes'\nimport type { Pretty } from '@cerberus/styled-system/types'\nimport {\n createContext,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type MutableRefObject,\n type PropsWithChildren,\n} from 'react'\n\n/**\n * This module provides a Tabs component and a hook to access its context.\n * @module Tabs\n */\n\nexport interface TabsContextValue {\n /**\n * The ref for the tabs.\n */\n tabs: MutableRefObject<HTMLButtonElement[]>\n /**\n * The id of the tabs component.\n */\n id: string\n /**\n * The active tab id.\n */\n active: string\n /**\n * The styles for the tabs.\n */\n styles: Pretty<Record<'tabList' | 'tab' | 'tabPanel', string>>\n /**\n * Called when the active tab is updated.\n */\n onTabUpdate: (active: string) => void\n}\n\nexport const TabsContext = createContext<TabsContextValue | null>(null)\n\nexport interface TabsProps {\n /**\n * A unique identifier for the Tabs component. Typically used when there are\n * multiple Tabs components on the same page.\n */\n id?: string\n /**\n * The default active tab id.\n */\n active?: string\n /**\n * Whether to cache the active tab state in local storage.\n */\n cache?: boolean\n}\n\n/**\n * The Tabs component provides a context to manage tab state.\n * @see https://cerberus.digitalu.design/react/tabs\n * @example\n * ```tsx\n * <Tabs cache>\n * <TabList description=\"Button details\">\n * <Tab id=\"overview\">Overview</Tab>\n * <Tab id=\"guidelines\">Guidelines</Tab>\n * </TabList>\n * <TabPanels>\n * <TabPanel id=\"overview\">Overview content</TabPanel>\n * <TabPanel id=\"guidelines\">Guidelines content</TabPanel>\n * </TabPanels>\n * </Tabs>\n * ```\n */\nexport function Tabs(\n props: PropsWithChildren<TabsProps & TabsVariantProps>,\n): JSX.Element {\n const { cache, active, id, palette } = props\n const [activeTab, setActiveTab] = useState(() => (cache ? '' : active ?? ''))\n const tabsList = useRef<HTMLButtonElement[]>([])\n const uuid = useMemo(() => {\n return id ? `cerberus-tabs-${id}` : 'cerberus-tabs'\n }, [id])\n\n const value = useMemo(\n () => ({\n tabs: tabsList,\n id: uuid,\n active: activeTab,\n styles: tabs({ palette }),\n onTabUpdate: setActiveTab,\n }),\n [activeTab, setActiveTab, palette, uuid, tabsList],\n )\n\n // Get the active tab from local storage\n useEffect(() => {\n if (cache) {\n const cachedTab = window.localStorage.getItem(uuid)\n setActiveTab(\n cache ? cachedTab || (props.active ?? '') : props.active ?? '',\n )\n }\n }, [cache, active, uuid])\n\n // Update the active tab in local storage\n useEffect(() => {\n if (cache && activeTab) {\n window.localStorage.setItem(uuid, activeTab)\n }\n }, [activeTab, cache])\n\n return (\n <TabsContext.Provider value={value}>{props.children}</TabsContext.Provider>\n )\n}\n\n/**\n * Used to access the tabs context.\n * @returns The tabs context.\n */\nexport function useTabsContext(): TabsContextValue {\n const context = useContext(TabsContext)\n if (!context) {\n throw new Error('useTabsContext must be used within a Tabs Provider.')\n }\n return context\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,iBAAmB;AACnB,sBAAuB;;;ACDvB,qBAA4C;AAE5C,mBASO;AAwGH;AA1EG,IAAM,kBAAc,4BAAuC,IAAI;AAkF/D,SAAS,iBAAmC;AACjD,QAAM,cAAU,yBAAW,WAAW;AACtC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,qDAAqD;AAAA,EACvE;AACA,SAAO;AACT;;;AD/FI,IAAAA,sBAAA;AALG,SAAS,QAAQ,OAAwC;AAC9D,QAAM,EAAE,aAAa,GAAG,YAAY,IAAI;AACxC,QAAM,EAAE,IAAI,OAAO,IAAI,eAAe;AAEtC,SACE;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ,cAAY;AAAA,MACZ,eAAW;AAAA,QACT,YAAY;AAAA,YACZ,wBAAO;AAAA,UACL,KAAK;AAAA,QACP,CAAC;AAAA,QACD,OAAO;AAAA,MACT;AAAA,MACA,IAAI,MAAM,YAAY;AAAA,MACtB,MAAK;AAAA;AAAA,EACP;AAEJ;","names":["import_jsx_runtime"]}