@cerberus-design/react 0.2.0-next-ec538ca → 0.2.0-next-1b244ce

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 (65) hide show
  1. package/build/legacy/_tsup-dts-rollup.d.ts +41 -3
  2. package/build/legacy/aria-helpers/tabs.aria.d.ts +1 -0
  3. package/build/legacy/aria-helpers/tabs.aria.js +9 -0
  4. package/build/legacy/aria-helpers/tabs.aria.js.map +1 -0
  5. package/build/legacy/chunk-57HOQM4E.js +65 -0
  6. package/build/legacy/chunk-57HOQM4E.js.map +1 -0
  7. package/build/legacy/{chunk-24B4KIPX.js → chunk-HQK7SM56.js} +9 -5
  8. package/build/legacy/chunk-HQK7SM56.js.map +1 -0
  9. package/build/legacy/{chunk-X6PHIZRM.js → chunk-MJB3V6J4.js} +4 -4
  10. package/build/{modern/chunk-NWDAYAVH.js → legacy/chunk-ODSSU3JD.js} +5 -2
  11. package/build/legacy/chunk-ODSSU3JD.js.map +1 -0
  12. package/build/{modern/chunk-XVDQL4L6.js → legacy/chunk-RCE2XXL7.js} +17 -5
  13. package/build/legacy/chunk-RCE2XXL7.js.map +1 -0
  14. package/build/legacy/chunk-TG5VW7KN.js +117 -0
  15. package/build/legacy/chunk-TG5VW7KN.js.map +1 -0
  16. package/build/legacy/components/NavMenuTrigger.js +2 -2
  17. package/build/legacy/components/Tab.js +3 -2
  18. package/build/legacy/components/TabList.js +1 -1
  19. package/build/legacy/components/TabPanel.js +2 -2
  20. package/build/legacy/context/tabs.d.ts +1 -0
  21. package/build/legacy/context/tabs.js +3 -1
  22. package/build/legacy/index.d.ts +2 -0
  23. package/build/legacy/index.js +25 -19
  24. package/build/modern/_tsup-dts-rollup.d.ts +41 -3
  25. package/build/modern/aria-helpers/tabs.aria.d.ts +1 -0
  26. package/build/modern/aria-helpers/tabs.aria.js +9 -0
  27. package/build/modern/aria-helpers/tabs.aria.js.map +1 -0
  28. package/build/modern/chunk-57HOQM4E.js +65 -0
  29. package/build/modern/chunk-57HOQM4E.js.map +1 -0
  30. package/build/modern/{chunk-24B4KIPX.js → chunk-HQK7SM56.js} +9 -5
  31. package/build/modern/chunk-HQK7SM56.js.map +1 -0
  32. package/build/modern/{chunk-X6PHIZRM.js → chunk-MJB3V6J4.js} +4 -4
  33. package/build/{legacy/chunk-NWDAYAVH.js → modern/chunk-ODSSU3JD.js} +5 -2
  34. package/build/modern/chunk-ODSSU3JD.js.map +1 -0
  35. package/build/{legacy/chunk-XVDQL4L6.js → modern/chunk-RCE2XXL7.js} +17 -5
  36. package/build/modern/chunk-RCE2XXL7.js.map +1 -0
  37. package/build/modern/chunk-SWCK7V2N.js +116 -0
  38. package/build/modern/chunk-SWCK7V2N.js.map +1 -0
  39. package/build/modern/components/NavMenuTrigger.js +2 -2
  40. package/build/modern/components/Tab.js +3 -2
  41. package/build/modern/components/TabList.js +1 -1
  42. package/build/modern/components/TabPanel.js +2 -2
  43. package/build/modern/context/tabs.d.ts +1 -0
  44. package/build/modern/context/tabs.js +3 -1
  45. package/build/modern/index.d.ts +2 -0
  46. package/build/modern/index.js +25 -19
  47. package/package.json +1 -1
  48. package/src/aria-helpers/tabs.aria.ts +70 -0
  49. package/src/components/Tab.tsx +95 -4
  50. package/src/components/TabList.tsx +4 -1
  51. package/src/components/TabPanel.tsx +28 -1
  52. package/src/context/tabs.tsx +11 -6
  53. package/src/index.ts +1 -0
  54. package/build/legacy/chunk-24B4KIPX.js.map +0 -1
  55. package/build/legacy/chunk-NVA4SWUI.js +0 -36
  56. package/build/legacy/chunk-NVA4SWUI.js.map +0 -1
  57. package/build/legacy/chunk-NWDAYAVH.js.map +0 -1
  58. package/build/legacy/chunk-XVDQL4L6.js.map +0 -1
  59. package/build/modern/chunk-24B4KIPX.js.map +0 -1
  60. package/build/modern/chunk-NWDAYAVH.js.map +0 -1
  61. package/build/modern/chunk-X5PQA2JN.js +0 -35
  62. package/build/modern/chunk-X5PQA2JN.js.map +0 -1
  63. package/build/modern/chunk-XVDQL4L6.js.map +0 -1
  64. /package/build/legacy/{chunk-X6PHIZRM.js.map → chunk-MJB3V6J4.js.map} +0 -0
  65. /package/build/modern/{chunk-X6PHIZRM.js.map → chunk-MJB3V6J4.js.map} +0 -0
@@ -0,0 +1,70 @@
1
+ 'use client'
2
+
3
+ import { useEffect, useState } from 'react'
4
+ import { useTabsContext } from '../context/tabs'
5
+
6
+ function getNextIndex(index: number, length: number) {
7
+ return index === length - 1 ? 0 : index + 1
8
+ }
9
+
10
+ function getPrevIndex(index: number, length: number) {
11
+ return index === 0 ? length - 1 : index - 1
12
+ }
13
+
14
+ export function useTabsKeyboardNavigation() {
15
+ const { tabs } = useTabsContext()
16
+ const [activeTab, setActiveTab] = useState(-1)
17
+
18
+ useEffect(() => {
19
+ const handleKeyDown = (event: KeyboardEvent) => {
20
+ const index =
21
+ activeTab === -1
22
+ ? tabs.current.findIndex((tab) => tab.ariaSelected === 'true')
23
+ : activeTab
24
+ const nextIndex = getNextIndex(index, tabs.current.length)
25
+ const prevIndex = getPrevIndex(index, tabs.current.length)
26
+
27
+ // If the active tab is not found, do nothing
28
+ if (index === -1) return
29
+
30
+ switch (event.key) {
31
+ case 'ArrowLeft':
32
+ event.preventDefault()
33
+ setActiveTab(prevIndex)
34
+ tabs.current[prevIndex].focus()
35
+ break
36
+ case 'ArrowRight':
37
+ event.preventDefault()
38
+ setActiveTab(nextIndex)
39
+ tabs.current[nextIndex].focus()
40
+ break
41
+ case 'Home':
42
+ event.preventDefault()
43
+ setActiveTab(0)
44
+ tabs.current[0].focus()
45
+ break
46
+ case 'End':
47
+ event.preventDefault()
48
+ setActiveTab(tabs.current.length - 1)
49
+ tabs.current[tabs.current.length - 1].focus()
50
+ break
51
+ default:
52
+ break
53
+ }
54
+ }
55
+
56
+ document.addEventListener('keydown', handleKeyDown)
57
+
58
+ return () => {
59
+ document.removeEventListener('keydown', handleKeyDown)
60
+ }
61
+ }, [activeTab, tabs.current])
62
+
63
+ return {
64
+ ref: (tab: HTMLButtonElement) => {
65
+ if (tab && !tabs.current.includes(tab)) {
66
+ tabs.current.push(tab)
67
+ }
68
+ },
69
+ }
70
+ }
@@ -3,6 +3,7 @@
3
3
  import { useMemo, type ButtonHTMLAttributes, type MouseEvent } from 'react'
4
4
  import { useTabsContext } from '../context/tabs'
5
5
  import { css, cx } from '@cerberus/styled-system/css'
6
+ import { useTabsKeyboardNavigation } from '../aria-helpers/tabs.aria'
6
7
 
7
8
  /**
8
9
  * This module provides a Tab component.
@@ -10,13 +11,25 @@ import { css, cx } from '@cerberus/styled-system/css'
10
11
  */
11
12
 
12
13
  export interface TabProps extends ButtonHTMLAttributes<HTMLButtonElement> {
13
- controls: string
14
14
  value: string
15
15
  }
16
16
 
17
+ /**
18
+ * The Tab component provides a tab element to be used in a TabList.
19
+ * @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)
20
+ * @definition [Tab docs](https://cerberus.digitalu.design/react/tabs)
21
+ * @param value - the id of the tab that will be tracked as the active tab and used for aria attributes
22
+ * @example
23
+ * ```tsx
24
+ * <Tab value="overview">
25
+ * Overview
26
+ * </Tab>
27
+ * ```
28
+ */
17
29
  export function Tab(props: TabProps) {
18
- const { controls, value, ...nativeProps } = props
30
+ const { value, ...nativeProps } = props
19
31
  const { active, onTabUpdate } = useTabsContext()
32
+ const { ref } = useTabsKeyboardNavigation()
20
33
  const isActive = useMemo(() => active === value, [active, value])
21
34
 
22
35
  function handleClick(e: MouseEvent<HTMLButtonElement>) {
@@ -28,12 +41,90 @@ export function Tab(props: TabProps) {
28
41
  <button
29
42
  {...nativeProps}
30
43
  {...(!isActive && { tabIndex: -1 })}
31
- aria-controls={controls}
44
+ aria-controls={`panel:${value}`}
32
45
  aria-selected={isActive}
33
- className={cx(nativeProps.className, css())}
46
+ id={value}
47
+ className={cx(nativeProps.className, btnStyles)}
34
48
  onClick={handleClick}
35
49
  role="tab"
50
+ ref={ref}
36
51
  value={value}
37
52
  />
38
53
  )
39
54
  }
55
+
56
+ const btnStyles = css({
57
+ borderTopLeftRadius: 'md',
58
+ borderTopRightRadius: 'md',
59
+ fontSize: 'sm',
60
+ fontWeight: '600',
61
+ h: '2.75rem',
62
+ position: 'relative',
63
+ pxi: '4',
64
+ zIndex: 'base',
65
+ _motionSafe: {
66
+ transition: 'all 200ms ease-in-out',
67
+ _before: {
68
+ transitionProperty: 'height',
69
+ transitionDuration: '200ms',
70
+ transitionTimingFunction: 'ease-in-out',
71
+ },
72
+ _after: {
73
+ transitionProperty: 'height',
74
+ transitionDuration: '200ms',
75
+ transitionTimingFunction: 'ease-in-out',
76
+ },
77
+ },
78
+ _before: {
79
+ bgColor: 'action.border.initial',
80
+ bottom: '0',
81
+ content: '""',
82
+ h: '0',
83
+ position: 'absolute',
84
+ left: '0',
85
+ right: '0',
86
+ w: 'full',
87
+ willChange: 'height',
88
+ zIndex: 'decorator',
89
+ },
90
+ _after: {
91
+ borderTopLeftRadius: 'md',
92
+ borderTopRightRadius: 'md',
93
+ bottom: '0',
94
+ bgColor: 'neutral.surface.100',
95
+ content: '""',
96
+ left: '0',
97
+ position: 'absolute',
98
+ right: '0',
99
+ h: '0',
100
+ w: 'full',
101
+ willChange: 'height',
102
+ zIndex: '-1',
103
+ },
104
+ _hover: {
105
+ _after: {
106
+ h: 'full',
107
+ },
108
+ },
109
+ _focusVisible: {
110
+ boxShadow: 'none',
111
+ outline: '3px solid',
112
+ outlineColor: 'action.border.focus',
113
+ outlineOffset: '2px',
114
+ },
115
+ _disabled: {
116
+ cursor: 'not-allowed',
117
+ opacity: '0.5',
118
+ },
119
+ _selected: {
120
+ color: 'action.text.200',
121
+ _before: {
122
+ h: '3px',
123
+ },
124
+ _hover: {
125
+ _after: {
126
+ h: '0',
127
+ },
128
+ },
129
+ },
130
+ })
@@ -8,7 +8,7 @@ import type { HTMLAttributes, PropsWithChildren } from 'react'
8
8
  */
9
9
 
10
10
  export interface TabListProps extends HTMLAttributes<HTMLDivElement> {
11
- description?: string
11
+ description: string
12
12
  }
13
13
 
14
14
  /**
@@ -31,7 +31,10 @@ export function TabList(props: PropsWithChildren<TabListProps>) {
31
31
  className={cx(
32
32
  nativeProps.className,
33
33
  hstack({
34
+ borderBottom: '1px solid',
35
+ borderBottomColor: 'action.border.100',
34
36
  gap: '0',
37
+ w: 'full',
35
38
  }),
36
39
  )}
37
40
  />
@@ -5,10 +5,25 @@ import { useMemo, type HTMLAttributes } from 'react'
5
5
  import { useTabsContext } from '../context/tabs'
6
6
  import { Show } from './Show'
7
7
 
8
+ /**
9
+ * This module provides a TabPanel component.
10
+ * @module
11
+ */
12
+
8
13
  export interface TabPanelProps extends HTMLAttributes<HTMLDivElement> {
9
14
  tab: string
10
15
  }
11
16
 
17
+ /**
18
+ * The TabPanel component provides a panel element to be used in a Tabs provider.
19
+ * @param tab - the value of the tab that will be tracked as the active tab and used for aria attributes
20
+ * @example
21
+ * ```tsx
22
+ * <TabPanel tab="overview">
23
+ * Overview content
24
+ * </TabPanel>
25
+ * ```
26
+ */
12
27
  export function TabPanel(props: TabPanelProps) {
13
28
  const { tab, ...nativeProps } = props
14
29
  const { active } = useTabsContext()
@@ -20,7 +35,19 @@ export function TabPanel(props: TabPanelProps) {
20
35
  {...nativeProps}
21
36
  {...(isActive && { tabIndex: 0 })}
22
37
  aria-labelledby={tab}
23
- className={cx(nativeProps.className, css())}
38
+ className={cx(
39
+ nativeProps.className,
40
+ css({
41
+ rounded: 'md',
42
+ _focusVisible: {
43
+ boxShadow: 'none',
44
+ outline: '3px solid',
45
+ outlineColor: 'action.border.focus',
46
+ outlineOffset: '2px',
47
+ },
48
+ }),
49
+ )}
50
+ id={`panel:${tab}`}
24
51
  role="tabpanel"
25
52
  />
26
53
  </Show>
@@ -5,7 +5,9 @@ import {
5
5
  useContext,
6
6
  useEffect,
7
7
  useMemo,
8
+ useRef,
8
9
  useState,
10
+ type MutableRefObject,
9
11
  type PropsWithChildren,
10
12
  } from 'react'
11
13
 
@@ -16,10 +18,11 @@ import {
16
18
 
17
19
  export interface TabsContextValue {
18
20
  active: string
21
+ tabs: MutableRefObject<HTMLButtonElement[]>
19
22
  onTabUpdate: (active: string) => void
20
23
  }
21
24
 
22
- const TabsContext = createContext<TabsContextValue | null>(null)
25
+ export const TabsContext = createContext<TabsContextValue | null>(null)
23
26
 
24
27
  export interface TabsProps {
25
28
  active?: string
@@ -29,7 +32,7 @@ export interface TabsProps {
29
32
  /**
30
33
  * The Tabs component provides a context to manage tab state.
31
34
  * @param active - the default active tab id,
32
- * @param cache - whether to cache the active tab state
35
+ * @param cache - whether to cache the active tab state in local storage
33
36
  * @example
34
37
  * ```tsx
35
38
  * <Tabs cache>
@@ -46,20 +49,22 @@ export interface TabsProps {
46
49
  */
47
50
  export function Tabs(props: PropsWithChildren<TabsProps>): JSX.Element {
48
51
  const { cache } = props
49
- const [active, setActive] = useState(() => props.active ?? '')
52
+ const [active, setActive] = useState(() => (cache ? '' : props.active ?? ''))
53
+ const tabs = useRef<HTMLButtonElement[]>([])
50
54
 
51
55
  const value = useMemo(
52
56
  () => ({
53
57
  active,
58
+ tabs,
54
59
  onTabUpdate: setActive,
55
60
  }),
56
61
  [active, setActive],
57
62
  )
58
63
 
59
64
  useEffect(() => {
60
- if (cache) {
61
- const cachedTab = window.localStorage.getItem('cerberus-tabs')
62
- setActive(cachedTab ?? active)
65
+ const cachedTab = window.localStorage.getItem('cerberus-tabs')
66
+ if (cache && cachedTab) {
67
+ setActive(cachedTab)
63
68
  }
64
69
  }, [cache])
65
70
 
package/src/index.ts CHANGED
@@ -32,6 +32,7 @@ export * from './hooks/useTheme'
32
32
  // aria-helpers
33
33
 
34
34
  export * from './aria-helpers/nav-menu.aria'
35
+ export * from './aria-helpers/tabs.aria'
35
36
 
36
37
  // shared types
37
38
 
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/context/tabs.tsx"],"sourcesContent":["'use client'\n\nimport {\n createContext,\n useContext,\n useEffect,\n useMemo,\n useState,\n type PropsWithChildren,\n} from 'react'\n\n/**\n * This module provides a Tabs component and a hook to access its context.\n * @module\n */\n\nexport interface TabsContextValue {\n active: string\n onTabUpdate: (active: string) => void\n}\n\nconst TabsContext = createContext<TabsContextValue | null>(null)\n\nexport interface TabsProps {\n active?: string\n cache?: boolean\n}\n\n/**\n * The Tabs component provides a context to manage tab state.\n * @param active - the default active tab id,\n * @param cache - whether to cache the active tab state\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(props: PropsWithChildren<TabsProps>): JSX.Element {\n const { cache } = props\n const [active, setActive] = useState(() => props.active ?? '')\n\n const value = useMemo(\n () => ({\n active,\n onTabUpdate: setActive,\n }),\n [active, setActive],\n )\n\n useEffect(() => {\n if (cache) {\n const cachedTab = window.localStorage.getItem('cerberus-tabs')\n setActive(cachedTab ?? active)\n }\n }, [cache])\n\n useEffect(() => {\n if (cache) {\n window.localStorage.setItem('cerberus-tabs', active)\n }\n }, [active, cache])\n\n return (\n <TabsContext.Provider value={value}>{props.children}</TabsContext.Provider>\n )\n}\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":";AAEA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AA+DH;AAnDJ,IAAM,cAAc,cAAuC,IAAI;AAyBxD,SAAS,KAAK,OAAkD;AACrE,QAAM,EAAE,MAAM,IAAI;AAClB,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,MAAM,MAAM,UAAU,EAAE;AAE7D,QAAM,QAAQ;AAAA,IACZ,OAAO;AAAA,MACL;AAAA,MACA,aAAa;AAAA,IACf;AAAA,IACA,CAAC,QAAQ,SAAS;AAAA,EACpB;AAEA,YAAU,MAAM;AACd,QAAI,OAAO;AACT,YAAM,YAAY,OAAO,aAAa,QAAQ,eAAe;AAC7D,gBAAU,aAAa,MAAM;AAAA,IAC/B;AAAA,EACF,GAAG,CAAC,KAAK,CAAC;AAEV,YAAU,MAAM;AACd,QAAI,OAAO;AACT,aAAO,aAAa,QAAQ,iBAAiB,MAAM;AAAA,IACrD;AAAA,EACF,GAAG,CAAC,QAAQ,KAAK,CAAC;AAElB,SACE,oBAAC,YAAY,UAAZ,EAAqB,OAAe,gBAAM,UAAS;AAExD;AAEO,SAAS,iBAAmC;AACjD,QAAM,UAAU,WAAW,WAAW;AACtC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,qDAAqD;AAAA,EACvE;AACA,SAAO;AACT;","names":[]}
@@ -1,36 +0,0 @@
1
- import {
2
- useTabsContext
3
- } from "./chunk-24B4KIPX.js";
4
-
5
- // src/components/Tab.tsx
6
- import { useMemo } from "react";
7
- import { css, cx } from "@cerberus/styled-system/css";
8
- import { jsx } from "react/jsx-runtime";
9
- function Tab(props) {
10
- const { controls, value, ...nativeProps } = props;
11
- const { active, onTabUpdate } = useTabsContext();
12
- const isActive = useMemo(() => active === value, [active, value]);
13
- function handleClick(e) {
14
- var _a;
15
- (_a = props.onClick) == null ? void 0 : _a.call(props, e);
16
- onTabUpdate(e.currentTarget.value);
17
- }
18
- return /* @__PURE__ */ jsx(
19
- "button",
20
- {
21
- ...nativeProps,
22
- ...!isActive && { tabIndex: -1 },
23
- "aria-controls": controls,
24
- "aria-selected": isActive,
25
- className: cx(nativeProps.className, css()),
26
- onClick: handleClick,
27
- role: "tab",
28
- value
29
- }
30
- );
31
- }
32
-
33
- export {
34
- Tab
35
- };
36
- //# sourceMappingURL=chunk-NVA4SWUI.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/components/Tab.tsx"],"sourcesContent":["'use client'\n\nimport { useMemo, type ButtonHTMLAttributes, type MouseEvent } from 'react'\nimport { useTabsContext } from '../context/tabs'\nimport { css, cx } from '@cerberus/styled-system/css'\n\n/**\n * This module provides a Tab component.\n * @module\n */\n\nexport interface TabProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n controls: string\n value: string\n}\n\nexport function Tab(props: TabProps) {\n const { controls, value, ...nativeProps } = props\n const { active, onTabUpdate } = useTabsContext()\n const isActive = useMemo(() => active === value, [active, value])\n\n function handleClick(e: MouseEvent<HTMLButtonElement>) {\n props.onClick?.(e)\n onTabUpdate(e.currentTarget.value)\n }\n\n return (\n <button\n {...nativeProps}\n {...(!isActive && { tabIndex: -1 })}\n aria-controls={controls}\n aria-selected={isActive}\n className={cx(nativeProps.className, css())}\n onClick={handleClick}\n role=\"tab\"\n value={value}\n />\n )\n}\n"],"mappings":";;;;;AAEA,SAAS,eAA2D;AAEpE,SAAS,KAAK,UAAU;AAuBpB;AAXG,SAAS,IAAI,OAAiB;AACnC,QAAM,EAAE,UAAU,OAAO,GAAG,YAAY,IAAI;AAC5C,QAAM,EAAE,QAAQ,YAAY,IAAI,eAAe;AAC/C,QAAM,WAAW,QAAQ,MAAM,WAAW,OAAO,CAAC,QAAQ,KAAK,CAAC;AAEhE,WAAS,YAAY,GAAkC;AArBzD;AAsBI,gBAAM,YAAN,+BAAgB;AAChB,gBAAY,EAAE,cAAc,KAAK;AAAA,EACnC;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACH,GAAI,CAAC,YAAY,EAAE,UAAU,GAAG;AAAA,MACjC,iBAAe;AAAA,MACf,iBAAe;AAAA,MACf,WAAW,GAAG,YAAY,WAAW,IAAI,CAAC;AAAA,MAC1C,SAAS;AAAA,MACT,MAAK;AAAA,MACL;AAAA;AAAA,EACF;AAEJ;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/components/TabList.tsx"],"sourcesContent":["import { cx } from '@cerberus/styled-system/css'\nimport { hstack } from '@cerberus/styled-system/patterns'\nimport type { HTMLAttributes, PropsWithChildren } from 'react'\n\n/**\n * This module provides a TabList component.\n * @module\n */\n\nexport interface TabListProps extends HTMLAttributes<HTMLDivElement> {\n description?: string\n}\n\n/**\n * The TabList component provides a container for tab elements.\n * @param description - a description of what the tab list contains\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 return (\n <div\n {...nativeProps}\n aria-describedby={description}\n className={cx(\n nativeProps.className,\n hstack({\n gap: '0',\n }),\n )}\n />\n )\n}\n"],"mappings":";AAAA,SAAS,UAAU;AACnB,SAAS,cAAc;AA0BnB;AAHG,SAAS,QAAQ,OAAwC;AAC9D,QAAM,EAAE,aAAa,GAAG,YAAY,IAAI;AACxC,SACE;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ,oBAAkB;AAAA,MAClB,WAAW;AAAA,QACT,YAAY;AAAA,QACZ,OAAO;AAAA,UACL,KAAK;AAAA,QACP,CAAC;AAAA,MACH;AAAA;AAAA,EACF;AAEJ;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/components/TabPanel.tsx"],"sourcesContent":["'use client'\n\nimport { css, cx } from '@cerberus/styled-system/css'\nimport { useMemo, type HTMLAttributes } from 'react'\nimport { useTabsContext } from '../context/tabs'\nimport { Show } from './Show'\n\nexport interface TabPanelProps extends HTMLAttributes<HTMLDivElement> {\n tab: string\n}\n\nexport function TabPanel(props: TabPanelProps) {\n const { tab, ...nativeProps } = props\n const { active } = useTabsContext()\n const isActive = useMemo(() => active === tab, [active, tab])\n\n return (\n <Show when={isActive}>\n <div\n {...nativeProps}\n {...(isActive && { tabIndex: 0 })}\n aria-labelledby={tab}\n className={cx(nativeProps.className, css())}\n role=\"tabpanel\"\n />\n </Show>\n )\n}\n"],"mappings":";;;;;;;;AAEA,SAAS,KAAK,UAAU;AACxB,SAAS,eAAoC;AAevC;AAPC,SAAS,SAAS,OAAsB;AAC7C,QAAM,EAAE,KAAK,GAAG,YAAY,IAAI;AAChC,QAAM,EAAE,OAAO,IAAI,eAAe;AAClC,QAAM,WAAW,QAAQ,MAAM,WAAW,KAAK,CAAC,QAAQ,GAAG,CAAC;AAE5D,SACE,oBAAC,QAAK,MAAM,UACV;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACH,GAAI,YAAY,EAAE,UAAU,EAAE;AAAA,MAC/B,mBAAiB;AAAA,MACjB,WAAW,GAAG,YAAY,WAAW,IAAI,CAAC;AAAA,MAC1C,MAAK;AAAA;AAAA,EACP,GACF;AAEJ;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/context/tabs.tsx"],"sourcesContent":["'use client'\n\nimport {\n createContext,\n useContext,\n useEffect,\n useMemo,\n useState,\n type PropsWithChildren,\n} from 'react'\n\n/**\n * This module provides a Tabs component and a hook to access its context.\n * @module\n */\n\nexport interface TabsContextValue {\n active: string\n onTabUpdate: (active: string) => void\n}\n\nconst TabsContext = createContext<TabsContextValue | null>(null)\n\nexport interface TabsProps {\n active?: string\n cache?: boolean\n}\n\n/**\n * The Tabs component provides a context to manage tab state.\n * @param active - the default active tab id,\n * @param cache - whether to cache the active tab state\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(props: PropsWithChildren<TabsProps>): JSX.Element {\n const { cache } = props\n const [active, setActive] = useState(() => props.active ?? '')\n\n const value = useMemo(\n () => ({\n active,\n onTabUpdate: setActive,\n }),\n [active, setActive],\n )\n\n useEffect(() => {\n if (cache) {\n const cachedTab = window.localStorage.getItem('cerberus-tabs')\n setActive(cachedTab ?? active)\n }\n }, [cache])\n\n useEffect(() => {\n if (cache) {\n window.localStorage.setItem('cerberus-tabs', active)\n }\n }, [active, cache])\n\n return (\n <TabsContext.Provider value={value}>{props.children}</TabsContext.Provider>\n )\n}\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":";AAEA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AA+DH;AAnDJ,IAAM,cAAc,cAAuC,IAAI;AAyBxD,SAAS,KAAK,OAAkD;AACrE,QAAM,EAAE,MAAM,IAAI;AAClB,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,MAAM,MAAM,UAAU,EAAE;AAE7D,QAAM,QAAQ;AAAA,IACZ,OAAO;AAAA,MACL;AAAA,MACA,aAAa;AAAA,IACf;AAAA,IACA,CAAC,QAAQ,SAAS;AAAA,EACpB;AAEA,YAAU,MAAM;AACd,QAAI,OAAO;AACT,YAAM,YAAY,OAAO,aAAa,QAAQ,eAAe;AAC7D,gBAAU,aAAa,MAAM;AAAA,IAC/B;AAAA,EACF,GAAG,CAAC,KAAK,CAAC;AAEV,YAAU,MAAM;AACd,QAAI,OAAO;AACT,aAAO,aAAa,QAAQ,iBAAiB,MAAM;AAAA,IACrD;AAAA,EACF,GAAG,CAAC,QAAQ,KAAK,CAAC;AAElB,SACE,oBAAC,YAAY,UAAZ,EAAqB,OAAe,gBAAM,UAAS;AAExD;AAEO,SAAS,iBAAmC;AACjD,QAAM,UAAU,WAAW,WAAW;AACtC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,qDAAqD;AAAA,EACvE;AACA,SAAO;AACT;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/components/TabList.tsx"],"sourcesContent":["import { cx } from '@cerberus/styled-system/css'\nimport { hstack } from '@cerberus/styled-system/patterns'\nimport type { HTMLAttributes, PropsWithChildren } from 'react'\n\n/**\n * This module provides a TabList component.\n * @module\n */\n\nexport interface TabListProps extends HTMLAttributes<HTMLDivElement> {\n description?: string\n}\n\n/**\n * The TabList component provides a container for tab elements.\n * @param description - a description of what the tab list contains\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 return (\n <div\n {...nativeProps}\n aria-describedby={description}\n className={cx(\n nativeProps.className,\n hstack({\n gap: '0',\n }),\n )}\n />\n )\n}\n"],"mappings":";AAAA,SAAS,UAAU;AACnB,SAAS,cAAc;AA0BnB;AAHG,SAAS,QAAQ,OAAwC;AAC9D,QAAM,EAAE,aAAa,GAAG,YAAY,IAAI;AACxC,SACE;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ,oBAAkB;AAAA,MAClB,WAAW;AAAA,QACT,YAAY;AAAA,QACZ,OAAO;AAAA,UACL,KAAK;AAAA,QACP,CAAC;AAAA,MACH;AAAA;AAAA,EACF;AAEJ;","names":[]}
@@ -1,35 +0,0 @@
1
- import {
2
- useTabsContext
3
- } from "./chunk-24B4KIPX.js";
4
-
5
- // src/components/Tab.tsx
6
- import { useMemo } from "react";
7
- import { css, cx } from "@cerberus/styled-system/css";
8
- import { jsx } from "react/jsx-runtime";
9
- function Tab(props) {
10
- const { controls, value, ...nativeProps } = props;
11
- const { active, onTabUpdate } = useTabsContext();
12
- const isActive = useMemo(() => active === value, [active, value]);
13
- function handleClick(e) {
14
- props.onClick?.(e);
15
- onTabUpdate(e.currentTarget.value);
16
- }
17
- return /* @__PURE__ */ jsx(
18
- "button",
19
- {
20
- ...nativeProps,
21
- ...!isActive && { tabIndex: -1 },
22
- "aria-controls": controls,
23
- "aria-selected": isActive,
24
- className: cx(nativeProps.className, css()),
25
- onClick: handleClick,
26
- role: "tab",
27
- value
28
- }
29
- );
30
- }
31
-
32
- export {
33
- Tab
34
- };
35
- //# sourceMappingURL=chunk-X5PQA2JN.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/components/Tab.tsx"],"sourcesContent":["'use client'\n\nimport { useMemo, type ButtonHTMLAttributes, type MouseEvent } from 'react'\nimport { useTabsContext } from '../context/tabs'\nimport { css, cx } from '@cerberus/styled-system/css'\n\n/**\n * This module provides a Tab component.\n * @module\n */\n\nexport interface TabProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n controls: string\n value: string\n}\n\nexport function Tab(props: TabProps) {\n const { controls, value, ...nativeProps } = props\n const { active, onTabUpdate } = useTabsContext()\n const isActive = useMemo(() => active === value, [active, value])\n\n function handleClick(e: MouseEvent<HTMLButtonElement>) {\n props.onClick?.(e)\n onTabUpdate(e.currentTarget.value)\n }\n\n return (\n <button\n {...nativeProps}\n {...(!isActive && { tabIndex: -1 })}\n aria-controls={controls}\n aria-selected={isActive}\n className={cx(nativeProps.className, css())}\n onClick={handleClick}\n role=\"tab\"\n value={value}\n />\n )\n}\n"],"mappings":";;;;;AAEA,SAAS,eAA2D;AAEpE,SAAS,KAAK,UAAU;AAuBpB;AAXG,SAAS,IAAI,OAAiB;AACnC,QAAM,EAAE,UAAU,OAAO,GAAG,YAAY,IAAI;AAC5C,QAAM,EAAE,QAAQ,YAAY,IAAI,eAAe;AAC/C,QAAM,WAAW,QAAQ,MAAM,WAAW,OAAO,CAAC,QAAQ,KAAK,CAAC;AAEhE,WAAS,YAAY,GAAkC;AACrD,UAAM,UAAU,CAAC;AACjB,gBAAY,EAAE,cAAc,KAAK;AAAA,EACnC;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACH,GAAI,CAAC,YAAY,EAAE,UAAU,GAAG;AAAA,MACjC,iBAAe;AAAA,MACf,iBAAe;AAAA,MACf,WAAW,GAAG,YAAY,WAAW,IAAI,CAAC;AAAA,MAC1C,SAAS;AAAA,MACT,MAAK;AAAA,MACL;AAAA;AAAA,EACF;AAEJ;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/components/TabPanel.tsx"],"sourcesContent":["'use client'\n\nimport { css, cx } from '@cerberus/styled-system/css'\nimport { useMemo, type HTMLAttributes } from 'react'\nimport { useTabsContext } from '../context/tabs'\nimport { Show } from './Show'\n\nexport interface TabPanelProps extends HTMLAttributes<HTMLDivElement> {\n tab: string\n}\n\nexport function TabPanel(props: TabPanelProps) {\n const { tab, ...nativeProps } = props\n const { active } = useTabsContext()\n const isActive = useMemo(() => active === tab, [active, tab])\n\n return (\n <Show when={isActive}>\n <div\n {...nativeProps}\n {...(isActive && { tabIndex: 0 })}\n aria-labelledby={tab}\n className={cx(nativeProps.className, css())}\n role=\"tabpanel\"\n />\n </Show>\n )\n}\n"],"mappings":";;;;;;;;AAEA,SAAS,KAAK,UAAU;AACxB,SAAS,eAAoC;AAevC;AAPC,SAAS,SAAS,OAAsB;AAC7C,QAAM,EAAE,KAAK,GAAG,YAAY,IAAI;AAChC,QAAM,EAAE,OAAO,IAAI,eAAe;AAClC,QAAM,WAAW,QAAQ,MAAM,WAAW,KAAK,CAAC,QAAQ,GAAG,CAAC;AAE5D,SACE,oBAAC,QAAK,MAAM,UACV;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACH,GAAI,YAAY,EAAE,UAAU,EAAE;AAAA,MAC/B,mBAAiB;AAAA,MACjB,WAAW,GAAG,YAAY,WAAW,IAAI,CAAC;AAAA,MAC1C,MAAK;AAAA;AAAA,EACP,GACF;AAEJ;","names":[]}