@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.
- package/build/legacy/_tsup-dts-rollup.d.ts +41 -3
- package/build/legacy/aria-helpers/tabs.aria.d.ts +1 -0
- package/build/legacy/aria-helpers/tabs.aria.js +9 -0
- package/build/legacy/aria-helpers/tabs.aria.js.map +1 -0
- package/build/legacy/chunk-57HOQM4E.js +65 -0
- package/build/legacy/chunk-57HOQM4E.js.map +1 -0
- package/build/legacy/{chunk-24B4KIPX.js → chunk-HQK7SM56.js} +9 -5
- package/build/legacy/chunk-HQK7SM56.js.map +1 -0
- package/build/legacy/{chunk-X6PHIZRM.js → chunk-MJB3V6J4.js} +4 -4
- package/build/{modern/chunk-NWDAYAVH.js → legacy/chunk-ODSSU3JD.js} +5 -2
- package/build/legacy/chunk-ODSSU3JD.js.map +1 -0
- package/build/{modern/chunk-XVDQL4L6.js → legacy/chunk-RCE2XXL7.js} +17 -5
- package/build/legacy/chunk-RCE2XXL7.js.map +1 -0
- package/build/legacy/chunk-TG5VW7KN.js +117 -0
- package/build/legacy/chunk-TG5VW7KN.js.map +1 -0
- package/build/legacy/components/NavMenuTrigger.js +2 -2
- package/build/legacy/components/Tab.js +3 -2
- package/build/legacy/components/TabList.js +1 -1
- package/build/legacy/components/TabPanel.js +2 -2
- package/build/legacy/context/tabs.d.ts +1 -0
- package/build/legacy/context/tabs.js +3 -1
- package/build/legacy/index.d.ts +2 -0
- package/build/legacy/index.js +25 -19
- package/build/modern/_tsup-dts-rollup.d.ts +41 -3
- package/build/modern/aria-helpers/tabs.aria.d.ts +1 -0
- package/build/modern/aria-helpers/tabs.aria.js +9 -0
- package/build/modern/aria-helpers/tabs.aria.js.map +1 -0
- package/build/modern/chunk-57HOQM4E.js +65 -0
- package/build/modern/chunk-57HOQM4E.js.map +1 -0
- package/build/modern/{chunk-24B4KIPX.js → chunk-HQK7SM56.js} +9 -5
- package/build/modern/chunk-HQK7SM56.js.map +1 -0
- package/build/modern/{chunk-X6PHIZRM.js → chunk-MJB3V6J4.js} +4 -4
- package/build/{legacy/chunk-NWDAYAVH.js → modern/chunk-ODSSU3JD.js} +5 -2
- package/build/modern/chunk-ODSSU3JD.js.map +1 -0
- package/build/{legacy/chunk-XVDQL4L6.js → modern/chunk-RCE2XXL7.js} +17 -5
- package/build/modern/chunk-RCE2XXL7.js.map +1 -0
- package/build/modern/chunk-SWCK7V2N.js +116 -0
- package/build/modern/chunk-SWCK7V2N.js.map +1 -0
- package/build/modern/components/NavMenuTrigger.js +2 -2
- package/build/modern/components/Tab.js +3 -2
- package/build/modern/components/TabList.js +1 -1
- package/build/modern/components/TabPanel.js +2 -2
- package/build/modern/context/tabs.d.ts +1 -0
- package/build/modern/context/tabs.js +3 -1
- package/build/modern/index.d.ts +2 -0
- package/build/modern/index.js +25 -19
- package/package.json +1 -1
- package/src/aria-helpers/tabs.aria.ts +70 -0
- package/src/components/Tab.tsx +95 -4
- package/src/components/TabList.tsx +4 -1
- package/src/components/TabPanel.tsx +28 -1
- package/src/context/tabs.tsx +11 -6
- package/src/index.ts +1 -0
- package/build/legacy/chunk-24B4KIPX.js.map +0 -1
- package/build/legacy/chunk-NVA4SWUI.js +0 -36
- package/build/legacy/chunk-NVA4SWUI.js.map +0 -1
- package/build/legacy/chunk-NWDAYAVH.js.map +0 -1
- package/build/legacy/chunk-XVDQL4L6.js.map +0 -1
- package/build/modern/chunk-24B4KIPX.js.map +0 -1
- package/build/modern/chunk-NWDAYAVH.js.map +0 -1
- package/build/modern/chunk-X5PQA2JN.js +0 -35
- package/build/modern/chunk-X5PQA2JN.js.map +0 -1
- package/build/modern/chunk-XVDQL4L6.js.map +0 -1
- /package/build/legacy/{chunk-X6PHIZRM.js.map → chunk-MJB3V6J4.js.map} +0 -0
- /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
|
+
}
|
package/src/components/Tab.tsx
CHANGED
|
@@ -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 {
|
|
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={
|
|
44
|
+
aria-controls={`panel:${value}`}
|
|
32
45
|
aria-selected={isActive}
|
|
33
|
-
|
|
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
|
|
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(
|
|
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>
|
package/src/context/tabs.tsx
CHANGED
|
@@ -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
|
-
|
|
61
|
-
|
|
62
|
-
setActive(cachedTab
|
|
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
|
@@ -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":[]}
|
|
File without changes
|
|
File without changes
|