@cerberus-design/react 0.2.0 → 0.3.1-next-f5a8b6a

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 (69) hide show
  1. package/build/legacy/_tsup-dts-rollup.d.ts +132 -0
  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-36QCFAIS.js +121 -0
  6. package/build/legacy/chunk-36QCFAIS.js.map +1 -0
  7. package/build/legacy/chunk-57HOQM4E.js +65 -0
  8. package/build/legacy/chunk-57HOQM4E.js.map +1 -0
  9. package/build/legacy/chunk-HQK7SM56.js +50 -0
  10. package/build/legacy/chunk-HQK7SM56.js.map +1 -0
  11. package/build/legacy/{chunk-X6PHIZRM.js → chunk-MJB3V6J4.js} +4 -4
  12. package/build/legacy/chunk-ODSSU3JD.js +28 -0
  13. package/build/legacy/chunk-ODSSU3JD.js.map +1 -0
  14. package/build/legacy/chunk-RCE2XXL7.js +43 -0
  15. package/build/legacy/chunk-RCE2XXL7.js.map +1 -0
  16. package/build/legacy/components/NavMenuTrigger.js +2 -2
  17. package/build/legacy/components/Tab.d.ts +2 -0
  18. package/build/legacy/components/Tab.js +10 -0
  19. package/build/legacy/components/Tab.js.map +1 -0
  20. package/build/legacy/components/TabList.d.ts +2 -0
  21. package/build/legacy/components/TabList.js +7 -0
  22. package/build/legacy/components/TabList.js.map +1 -0
  23. package/build/legacy/components/TabPanel.d.ts +2 -0
  24. package/build/legacy/components/TabPanel.js +10 -0
  25. package/build/legacy/components/TabPanel.js.map +1 -0
  26. package/build/legacy/context/tabs.d.ts +5 -0
  27. package/build/legacy/context/tabs.js +12 -0
  28. package/build/legacy/context/tabs.js.map +1 -0
  29. package/build/legacy/index.d.ts +12 -0
  30. package/build/legacy/index.js +34 -10
  31. package/build/modern/_tsup-dts-rollup.d.ts +132 -0
  32. package/build/modern/aria-helpers/tabs.aria.d.ts +1 -0
  33. package/build/modern/aria-helpers/tabs.aria.js +9 -0
  34. package/build/modern/aria-helpers/tabs.aria.js.map +1 -0
  35. package/build/modern/chunk-57HOQM4E.js +65 -0
  36. package/build/modern/chunk-57HOQM4E.js.map +1 -0
  37. package/build/modern/chunk-HQK7SM56.js +50 -0
  38. package/build/modern/chunk-HQK7SM56.js.map +1 -0
  39. package/build/modern/chunk-LAUJGQO2.js +120 -0
  40. package/build/modern/chunk-LAUJGQO2.js.map +1 -0
  41. package/build/modern/{chunk-X6PHIZRM.js → chunk-MJB3V6J4.js} +4 -4
  42. package/build/modern/chunk-ODSSU3JD.js +28 -0
  43. package/build/modern/chunk-ODSSU3JD.js.map +1 -0
  44. package/build/modern/chunk-RCE2XXL7.js +43 -0
  45. package/build/modern/chunk-RCE2XXL7.js.map +1 -0
  46. package/build/modern/components/NavMenuTrigger.js +2 -2
  47. package/build/modern/components/Tab.d.ts +2 -0
  48. package/build/modern/components/Tab.js +10 -0
  49. package/build/modern/components/Tab.js.map +1 -0
  50. package/build/modern/components/TabList.d.ts +2 -0
  51. package/build/modern/components/TabList.js +7 -0
  52. package/build/modern/components/TabList.js.map +1 -0
  53. package/build/modern/components/TabPanel.d.ts +2 -0
  54. package/build/modern/components/TabPanel.js +10 -0
  55. package/build/modern/components/TabPanel.js.map +1 -0
  56. package/build/modern/context/tabs.d.ts +5 -0
  57. package/build/modern/context/tabs.js +12 -0
  58. package/build/modern/context/tabs.js.map +1 -0
  59. package/build/modern/index.d.ts +12 -0
  60. package/build/modern/index.js +34 -10
  61. package/package.json +1 -1
  62. package/src/aria-helpers/tabs.aria.ts +70 -0
  63. package/src/components/Tab.tsx +134 -0
  64. package/src/components/TabList.tsx +42 -0
  65. package/src/components/TabPanel.tsx +55 -0
  66. package/src/context/tabs.tsx +88 -0
  67. package/src/index.ts +5 -0
  68. /package/build/legacy/{chunk-X6PHIZRM.js.map → chunk-MJB3V6J4.js.map} +0 -0
  69. /package/build/modern/{chunk-X6PHIZRM.js.map → chunk-MJB3V6J4.js.map} +0 -0
@@ -1,9 +1,11 @@
1
1
  import type { AnchorHTMLAttributes } from 'react';
2
2
  import { ButtonHTMLAttributes } from 'react';
3
+ import { Context } from 'react';
3
4
  import { ElementType } from 'react';
4
5
  import { HTMLAttributes } from 'react';
5
6
  import type { InputHTMLAttributes } from 'react';
6
7
  import { JSX as JSX_2 } from 'react/jsx-runtime';
8
+ import { MutableRefObject } from 'react';
7
9
  import { PropsWithChildren } from 'react';
8
10
  import { ReactNode } from 'react';
9
11
  import { RefObject } from 'react';
@@ -277,6 +279,126 @@ declare interface ShowProps {
277
279
  export { ShowProps }
278
280
  export { ShowProps as ShowProps_alias_1 }
279
281
 
282
+ /**
283
+ * The Tab component provides a tab element to be used in a TabList.
284
+ * @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)
285
+ * @definition [Tab docs](https://cerberus.digitalu.design/react/tabs)
286
+ * @param value - the id of the tab that will be tracked as the active tab and used for aria attributes
287
+ * @example
288
+ * ```tsx
289
+ * <Tab value="overview">
290
+ * Overview
291
+ * </Tab>
292
+ * ```
293
+ */
294
+ declare function Tab(props: TabProps): JSX_2.Element;
295
+ export { Tab }
296
+ export { Tab as Tab_alias_1 }
297
+
298
+ /**
299
+ * The TabList component provides a container for tab elements.
300
+ * @param description - a description of what the tab list contains
301
+ * @example
302
+ * ```tsx
303
+ * <TabList description="Button details">
304
+ * <Tab id="overview">Overview</Tab>
305
+ * <Tab id="guidelines">Guidelines</Tab>
306
+ * </TabList>
307
+ * ```
308
+ */
309
+ declare function TabList(props: PropsWithChildren<TabListProps>): JSX_2.Element;
310
+ export { TabList }
311
+ export { TabList as TabList_alias_1 }
312
+
313
+ /**
314
+ * This module provides a TabList component.
315
+ * @module
316
+ */
317
+ declare interface TabListProps extends HTMLAttributes<HTMLDivElement> {
318
+ description: string;
319
+ }
320
+ export { TabListProps }
321
+ export { TabListProps as TabListProps_alias_1 }
322
+
323
+ /**
324
+ * The TabPanel component provides a panel element to be used in a Tabs provider.
325
+ * @param tab - the value of the tab that will be tracked as the active tab and used for aria attributes
326
+ * @example
327
+ * ```tsx
328
+ * <TabPanel tab="overview">
329
+ * Overview content
330
+ * </TabPanel>
331
+ * ```
332
+ */
333
+ declare function TabPanel(props: TabPanelProps): JSX_2.Element;
334
+ export { TabPanel }
335
+ export { TabPanel as TabPanel_alias_1 }
336
+
337
+ /**
338
+ * This module provides a TabPanel component.
339
+ * @module
340
+ */
341
+ declare interface TabPanelProps extends HTMLAttributes<HTMLDivElement> {
342
+ tab: string;
343
+ }
344
+ export { TabPanelProps }
345
+ export { TabPanelProps as TabPanelProps_alias_1 }
346
+
347
+ /**
348
+ * This module provides a Tab component.
349
+ * @module
350
+ */
351
+ declare interface TabProps extends ButtonHTMLAttributes<HTMLButtonElement> {
352
+ value: string;
353
+ }
354
+ export { TabProps }
355
+ export { TabProps as TabProps_alias_1 }
356
+
357
+ /**
358
+ * The Tabs component provides a context to manage tab state.
359
+ * @param active - the default active tab id,
360
+ * @param cache - whether to cache the active tab state in local storage
361
+ * @example
362
+ * ```tsx
363
+ * <Tabs cache>
364
+ * <TabList description="Button details">
365
+ * <Tab id="overview">Overview</Tab>
366
+ * <Tab id="guidelines">Guidelines</Tab>
367
+ * </TabList>
368
+ * <TabPanels>
369
+ * <TabPanel id="overview">Overview content</TabPanel>
370
+ * <TabPanel id="guidelines">Guidelines content</TabPanel>
371
+ * </TabPanels>
372
+ * </Tabs>
373
+ * ```
374
+ */
375
+ declare function Tabs(props: PropsWithChildren<TabsProps>): JSX.Element;
376
+ export { Tabs }
377
+ export { Tabs as Tabs_alias_1 }
378
+
379
+ declare const TabsContext: Context<TabsContextValue | null>;
380
+ export { TabsContext }
381
+ export { TabsContext as TabsContext_alias_1 }
382
+
383
+ /**
384
+ * This module provides a Tabs component and a hook to access its context.
385
+ * @module
386
+ */
387
+ declare interface TabsContextValue {
388
+ active: string;
389
+ tabs: MutableRefObject<HTMLButtonElement[]>;
390
+ onTabUpdate: (active: string) => void;
391
+ }
392
+ export { TabsContextValue }
393
+ export { TabsContextValue as TabsContextValue_alias_1 }
394
+
395
+ declare interface TabsProps {
396
+ active?: string;
397
+ cache?: boolean;
398
+ }
399
+ export { TabsProps }
400
+ export { TabsProps as TabsProps_alias_1 }
401
+
280
402
  declare const THEME_KEY = "cerberus-theme";
281
403
  export { THEME_KEY }
282
404
  export { THEME_KEY as THEME_KEY_alias_1 }
@@ -311,6 +433,16 @@ declare function useNavMenuContext(): NavMenuContextValue;
311
433
  export { useNavMenuContext }
312
434
  export { useNavMenuContext as useNavMenuContext_alias_1 }
313
435
 
436
+ declare function useTabsContext(): TabsContextValue;
437
+ export { useTabsContext }
438
+ export { useTabsContext as useTabsContext_alias_1 }
439
+
440
+ declare function useTabsKeyboardNavigation(): {
441
+ ref: (tab: HTMLButtonElement) => void;
442
+ };
443
+ export { useTabsKeyboardNavigation }
444
+ export { useTabsKeyboardNavigation as useTabsKeyboardNavigation_alias_1 }
445
+
314
446
  declare function useTheme<C extends string = DefaultThemes>(defaultTheme?: CustomThemes<C>, defaultColorMode?: ColorModes): ThemeContextValue<C>;
315
447
  export { useTheme }
316
448
  export { useTheme as useTheme_alias_1 }
@@ -0,0 +1 @@
1
+ export { useTabsKeyboardNavigation_alias_1 as useTabsKeyboardNavigation } from '../_tsup-dts-rollup';
@@ -0,0 +1,9 @@
1
+ "use client";
2
+ import {
3
+ useTabsKeyboardNavigation
4
+ } from "../chunk-57HOQM4E.js";
5
+ import "../chunk-HQK7SM56.js";
6
+ export {
7
+ useTabsKeyboardNavigation
8
+ };
9
+ //# sourceMappingURL=tabs.aria.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,121 @@
1
+ import {
2
+ useTabsKeyboardNavigation
3
+ } from "./chunk-57HOQM4E.js";
4
+ import {
5
+ useTabsContext
6
+ } from "./chunk-HQK7SM56.js";
7
+
8
+ // src/components/Tab.tsx
9
+ import { useMemo } from "react";
10
+ import { css, cx } from "@cerberus/styled-system/css";
11
+ import { jsx } from "react/jsx-runtime";
12
+ function Tab(props) {
13
+ const { value, ...nativeProps } = props;
14
+ const { active, onTabUpdate } = useTabsContext();
15
+ const { ref } = useTabsKeyboardNavigation();
16
+ const isActive = useMemo(() => active === value, [active, value]);
17
+ function handleClick(e) {
18
+ var _a;
19
+ (_a = props.onClick) == null ? void 0 : _a.call(props, e);
20
+ onTabUpdate(e.currentTarget.value);
21
+ }
22
+ return /* @__PURE__ */ jsx(
23
+ "button",
24
+ {
25
+ ...nativeProps,
26
+ ...!isActive && { tabIndex: -1 },
27
+ "aria-controls": `panel:${value}`,
28
+ "aria-selected": isActive,
29
+ id: value,
30
+ className: cx(nativeProps.className, btnStyles),
31
+ onClick: handleClick,
32
+ role: "tab",
33
+ ref,
34
+ value
35
+ }
36
+ );
37
+ }
38
+ var btnStyles = css({
39
+ alignItems: "center",
40
+ display: "inline-flex",
41
+ borderTopLeftRadius: "md",
42
+ borderTopRightRadius: "md",
43
+ fontSize: "sm",
44
+ fontWeight: "600",
45
+ gap: "2",
46
+ h: "2.75rem",
47
+ justifyContent: "center",
48
+ position: "relative",
49
+ pxi: "4",
50
+ zIndex: "base",
51
+ _motionSafe: {
52
+ transition: "all 200ms ease-in-out",
53
+ _before: {
54
+ transitionProperty: "height",
55
+ transitionDuration: "200ms",
56
+ transitionTimingFunction: "ease-in-out"
57
+ },
58
+ _after: {
59
+ transitionProperty: "height",
60
+ transitionDuration: "200ms",
61
+ transitionTimingFunction: "ease-in-out"
62
+ }
63
+ },
64
+ _before: {
65
+ bgColor: "action.border.initial",
66
+ bottom: "0",
67
+ content: '""',
68
+ h: "0",
69
+ position: "absolute",
70
+ left: "0",
71
+ right: "0",
72
+ w: "full",
73
+ willChange: "height",
74
+ zIndex: "decorator"
75
+ },
76
+ _after: {
77
+ borderTopLeftRadius: "md",
78
+ borderTopRightRadius: "md",
79
+ bottom: "0",
80
+ bgColor: "neutral.surface.100",
81
+ content: '""',
82
+ left: "0",
83
+ position: "absolute",
84
+ right: "0",
85
+ h: "0",
86
+ w: "full",
87
+ willChange: "height",
88
+ zIndex: "-1"
89
+ },
90
+ _hover: {
91
+ _after: {
92
+ h: "full"
93
+ }
94
+ },
95
+ _focusVisible: {
96
+ boxShadow: "none",
97
+ outline: "3px solid",
98
+ outlineColor: "action.border.focus",
99
+ outlineOffset: "2px"
100
+ },
101
+ _disabled: {
102
+ cursor: "not-allowed",
103
+ opacity: "0.5"
104
+ },
105
+ _selected: {
106
+ color: "action.text.200",
107
+ _before: {
108
+ h: "3px"
109
+ },
110
+ _hover: {
111
+ _after: {
112
+ h: "0"
113
+ }
114
+ }
115
+ }
116
+ });
117
+
118
+ export {
119
+ Tab
120
+ };
121
+ //# sourceMappingURL=chunk-36QCFAIS.js.map
@@ -0,0 +1 @@
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'\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 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 * @definition [Tab docs](https://cerberus.digitalu.design/react/tabs)\n * @param value - the id of the tab that will be tracked as the active tab and used for aria attributes\n * @example\n * ```tsx\n * <Tab value=\"overview\">\n * Overview\n * </Tab>\n * ```\n */\nexport function Tab(props: TabProps) {\n const { value, ...nativeProps } = props\n const { active, onTabUpdate } = useTabsContext()\n const { ref } = useTabsKeyboardNavigation()\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={`panel:${value}`}\n aria-selected={isActive}\n id={value}\n className={cx(nativeProps.className, btnStyles)}\n onClick={handleClick}\n role=\"tab\"\n ref={ref}\n value={value}\n />\n )\n}\n\nconst btnStyles = css({\n alignItems: 'center',\n display: 'inline-flex',\n borderTopLeftRadius: 'md',\n borderTopRightRadius: 'md',\n fontSize: 'sm',\n fontWeight: '600',\n gap: '2',\n h: '2.75rem',\n justifyContent: 'center',\n position: 'relative',\n pxi: '4',\n zIndex: 'base',\n _motionSafe: {\n transition: 'all 200ms ease-in-out',\n _before: {\n transitionProperty: 'height',\n transitionDuration: '200ms',\n transitionTimingFunction: 'ease-in-out',\n },\n _after: {\n transitionProperty: 'height',\n transitionDuration: '200ms',\n transitionTimingFunction: 'ease-in-out',\n },\n },\n _before: {\n bgColor: 'action.border.initial',\n bottom: '0',\n content: '\"\"',\n h: '0',\n position: 'absolute',\n left: '0',\n right: '0',\n w: 'full',\n willChange: 'height',\n zIndex: 'decorator',\n },\n _after: {\n borderTopLeftRadius: 'md',\n borderTopRightRadius: 'md',\n bottom: '0',\n bgColor: 'neutral.surface.100',\n content: '\"\"',\n left: '0',\n position: 'absolute',\n right: '0',\n h: '0',\n w: 'full',\n willChange: 'height',\n zIndex: '-1',\n },\n _hover: {\n _after: {\n h: 'full',\n },\n },\n _focusVisible: {\n boxShadow: 'none',\n outline: '3px solid',\n outlineColor: 'action.border.focus',\n outlineOffset: '2px',\n },\n _disabled: {\n cursor: 'not-allowed',\n opacity: '0.5',\n },\n _selected: {\n color: 'action.text.200',\n _before: {\n h: '3px',\n },\n _hover: {\n _after: {\n h: '0',\n },\n },\n },\n})\n"],"mappings":";;;;;;;;AAEA,SAAS,eAA2D;AAEpE,SAAS,KAAK,UAAU;AAoCpB;AAZG,SAAS,IAAI,OAAiB;AACnC,QAAM,EAAE,OAAO,GAAG,YAAY,IAAI;AAClC,QAAM,EAAE,QAAQ,YAAY,IAAI,eAAe;AAC/C,QAAM,EAAE,IAAI,IAAI,0BAA0B;AAC1C,QAAM,WAAW,QAAQ,MAAM,WAAW,OAAO,CAAC,QAAQ,KAAK,CAAC;AAEhE,WAAS,YAAY,GAAkC;AAlCzD;AAmCI,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,SAAS,KAAK;AAAA,MAC7B,iBAAe;AAAA,MACf,IAAI;AAAA,MACJ,WAAW,GAAG,YAAY,WAAW,SAAS;AAAA,MAC9C,SAAS;AAAA,MACT,MAAK;AAAA,MACL;AAAA,MACA;AAAA;AAAA,EACF;AAEJ;AAEA,IAAM,YAAY,IAAI;AAAA,EACpB,YAAY;AAAA,EACZ,SAAS;AAAA,EACT,qBAAqB;AAAA,EACrB,sBAAsB;AAAA,EACtB,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,KAAK;AAAA,EACL,GAAG;AAAA,EACH,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,aAAa;AAAA,IACX,YAAY;AAAA,IACZ,SAAS;AAAA,MACP,oBAAoB;AAAA,MACpB,oBAAoB;AAAA,MACpB,0BAA0B;AAAA,IAC5B;AAAA,IACA,QAAQ;AAAA,MACN,oBAAoB;AAAA,MACpB,oBAAoB;AAAA,MACpB,0BAA0B;AAAA,IAC5B;AAAA,EACF;AAAA,EACA,SAAS;AAAA,IACP,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,GAAG;AAAA,IACH,UAAU;AAAA,IACV,MAAM;AAAA,IACN,OAAO;AAAA,IACP,GAAG;AAAA,IACH,YAAY;AAAA,IACZ,QAAQ;AAAA,EACV;AAAA,EACA,QAAQ;AAAA,IACN,qBAAqB;AAAA,IACrB,sBAAsB;AAAA,IACtB,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,SAAS;AAAA,IACT,MAAM;AAAA,IACN,UAAU;AAAA,IACV,OAAO;AAAA,IACP,GAAG;AAAA,IACH,GAAG;AAAA,IACH,YAAY;AAAA,IACZ,QAAQ;AAAA,EACV;AAAA,EACA,QAAQ;AAAA,IACN,QAAQ;AAAA,MACN,GAAG;AAAA,IACL;AAAA,EACF;AAAA,EACA,eAAe;AAAA,IACb,WAAW;AAAA,IACX,SAAS;AAAA,IACT,cAAc;AAAA,IACd,eAAe;AAAA,EACjB;AAAA,EACA,WAAW;AAAA,IACT,QAAQ;AAAA,IACR,SAAS;AAAA,EACX;AAAA,EACA,WAAW;AAAA,IACT,OAAO;AAAA,IACP,SAAS;AAAA,MACP,GAAG;AAAA,IACL;AAAA,IACA,QAAQ;AAAA,MACN,QAAQ;AAAA,QACN,GAAG;AAAA,MACL;AAAA,IACF;AAAA,EACF;AACF,CAAC;","names":[]}
@@ -0,0 +1,65 @@
1
+ import {
2
+ useTabsContext
3
+ } from "./chunk-HQK7SM56.js";
4
+
5
+ // src/aria-helpers/tabs.aria.ts
6
+ import { useEffect, useState } from "react";
7
+ function getNextIndex(index, length) {
8
+ return index === length - 1 ? 0 : index + 1;
9
+ }
10
+ function getPrevIndex(index, length) {
11
+ return index === 0 ? length - 1 : index - 1;
12
+ }
13
+ function useTabsKeyboardNavigation() {
14
+ const { tabs } = useTabsContext();
15
+ const [activeTab, setActiveTab] = useState(-1);
16
+ useEffect(() => {
17
+ const handleKeyDown = (event) => {
18
+ const index = activeTab === -1 ? tabs.current.findIndex((tab) => tab.ariaSelected === "true") : activeTab;
19
+ const nextIndex = getNextIndex(index, tabs.current.length);
20
+ const prevIndex = getPrevIndex(index, tabs.current.length);
21
+ if (index === -1)
22
+ return;
23
+ switch (event.key) {
24
+ case "ArrowLeft":
25
+ event.preventDefault();
26
+ setActiveTab(prevIndex);
27
+ tabs.current[prevIndex].focus();
28
+ break;
29
+ case "ArrowRight":
30
+ event.preventDefault();
31
+ setActiveTab(nextIndex);
32
+ tabs.current[nextIndex].focus();
33
+ break;
34
+ case "Home":
35
+ event.preventDefault();
36
+ setActiveTab(0);
37
+ tabs.current[0].focus();
38
+ break;
39
+ case "End":
40
+ event.preventDefault();
41
+ setActiveTab(tabs.current.length - 1);
42
+ tabs.current[tabs.current.length - 1].focus();
43
+ break;
44
+ default:
45
+ break;
46
+ }
47
+ };
48
+ document.addEventListener("keydown", handleKeyDown);
49
+ return () => {
50
+ document.removeEventListener("keydown", handleKeyDown);
51
+ };
52
+ }, [activeTab, tabs.current]);
53
+ return {
54
+ ref: (tab) => {
55
+ if (tab && !tabs.current.includes(tab)) {
56
+ tabs.current.push(tab);
57
+ }
58
+ }
59
+ };
60
+ }
61
+
62
+ export {
63
+ useTabsKeyboardNavigation
64
+ };
65
+ //# sourceMappingURL=chunk-57HOQM4E.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/aria-helpers/tabs.aria.ts"],"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"],"mappings":";;;;;AAEA,SAAS,WAAW,gBAAgB;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,KAAK,IAAI,eAAe;AAChC,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,EAAE;AAE7C,YAAU,MAAM;AACd,UAAM,gBAAgB,CAAC,UAAyB;AAC9C,YAAM,QACJ,cAAc,KACV,KAAK,QAAQ,UAAU,CAAC,QAAQ,IAAI,iBAAiB,MAAM,IAC3D;AACN,YAAM,YAAY,aAAa,OAAO,KAAK,QAAQ,MAAM;AACzD,YAAM,YAAY,aAAa,OAAO,KAAK,QAAQ,MAAM;AAGzD,UAAI,UAAU;AAAI;AAElB,cAAQ,MAAM,KAAK;AAAA,QACjB,KAAK;AACH,gBAAM,eAAe;AACrB,uBAAa,SAAS;AACtB,eAAK,QAAQ,SAAS,EAAE,MAAM;AAC9B;AAAA,QACF,KAAK;AACH,gBAAM,eAAe;AACrB,uBAAa,SAAS;AACtB,eAAK,QAAQ,SAAS,EAAE,MAAM;AAC9B;AAAA,QACF,KAAK;AACH,gBAAM,eAAe;AACrB,uBAAa,CAAC;AACd,eAAK,QAAQ,CAAC,EAAE,MAAM;AACtB;AAAA,QACF,KAAK;AACH,gBAAM,eAAe;AACrB,uBAAa,KAAK,QAAQ,SAAS,CAAC;AACpC,eAAK,QAAQ,KAAK,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,WAAW,KAAK,OAAO,CAAC;AAE5B,SAAO;AAAA,IACL,KAAK,CAAC,QAA2B;AAC/B,UAAI,OAAO,CAAC,KAAK,QAAQ,SAAS,GAAG,GAAG;AACtC,aAAK,QAAQ,KAAK,GAAG;AAAA,MACvB;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,50 @@
1
+ // src/context/tabs.tsx
2
+ import {
3
+ createContext,
4
+ useContext,
5
+ useEffect,
6
+ useMemo,
7
+ useRef,
8
+ useState
9
+ } from "react";
10
+ import { jsx } from "react/jsx-runtime";
11
+ var TabsContext = createContext(null);
12
+ function Tabs(props) {
13
+ const { cache } = props;
14
+ const [active, setActive] = useState(() => cache ? "" : props.active ?? "");
15
+ const tabs = useRef([]);
16
+ const value = useMemo(
17
+ () => ({
18
+ active,
19
+ tabs,
20
+ onTabUpdate: setActive
21
+ }),
22
+ [active, setActive]
23
+ );
24
+ useEffect(() => {
25
+ const cachedTab = window.localStorage.getItem("cerberus-tabs");
26
+ if (cache && cachedTab) {
27
+ setActive(cachedTab);
28
+ }
29
+ }, [cache]);
30
+ useEffect(() => {
31
+ if (cache) {
32
+ window.localStorage.setItem("cerberus-tabs", active);
33
+ }
34
+ }, [active, cache]);
35
+ return /* @__PURE__ */ jsx(TabsContext.Provider, { value, children: props.children });
36
+ }
37
+ function useTabsContext() {
38
+ const context = useContext(TabsContext);
39
+ if (!context) {
40
+ throw new Error("useTabsContext must be used within a Tabs Provider.");
41
+ }
42
+ return context;
43
+ }
44
+
45
+ export {
46
+ TabsContext,
47
+ Tabs,
48
+ useTabsContext
49
+ };
50
+ //# sourceMappingURL=chunk-HQK7SM56.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/context/tabs.tsx"],"sourcesContent":["'use client'\n\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\n */\n\nexport interface TabsContextValue {\n active: string\n tabs: MutableRefObject<HTMLButtonElement[]>\n onTabUpdate: (active: string) => void\n}\n\nexport const 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 in local storage\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(() => (cache ? '' : props.active ?? ''))\n const tabs = useRef<HTMLButtonElement[]>([])\n\n const value = useMemo(\n () => ({\n active,\n tabs,\n onTabUpdate: setActive,\n }),\n [active, setActive],\n )\n\n useEffect(() => {\n const cachedTab = window.localStorage.getItem('cerberus-tabs')\n if (cache && cachedTab) {\n setActive(cachedTab)\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,EACA;AAAA,OAGK;AAkEH;AArDG,IAAM,cAAc,cAAuC,IAAI;AAyB/D,SAAS,KAAK,OAAkD;AACrE,QAAM,EAAE,MAAM,IAAI;AAClB,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,MAAO,QAAQ,KAAK,MAAM,UAAU,EAAG;AAC5E,QAAM,OAAO,OAA4B,CAAC,CAAC;AAE3C,QAAM,QAAQ;AAAA,IACZ,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,aAAa;AAAA,IACf;AAAA,IACA,CAAC,QAAQ,SAAS;AAAA,EACpB;AAEA,YAAU,MAAM;AACd,UAAM,YAAY,OAAO,aAAa,QAAQ,eAAe;AAC7D,QAAI,SAAS,WAAW;AACtB,gBAAU,SAAS;AAAA,IACrB;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,12 +1,12 @@
1
1
  import {
2
2
  useNavMenuContext
3
3
  } from "./chunk-KJUCHZHV.js";
4
- import {
5
- createNavTriggerProps
6
- } from "./chunk-JF76VIL3.js";
7
4
  import {
8
5
  Show
9
6
  } from "./chunk-R4H3352X.js";
7
+ import {
8
+ createNavTriggerProps
9
+ } from "./chunk-JF76VIL3.js";
10
10
 
11
11
  // src/components/NavMenuTrigger.tsx
12
12
  import {
@@ -79,4 +79,4 @@ function NavMenuTrigger(props) {
79
79
  export {
80
80
  NavMenuTrigger
81
81
  };
82
- //# sourceMappingURL=chunk-X6PHIZRM.js.map
82
+ //# sourceMappingURL=chunk-MJB3V6J4.js.map
@@ -0,0 +1,28 @@
1
+ // src/components/TabList.tsx
2
+ import { cx } from "@cerberus/styled-system/css";
3
+ import { hstack } from "@cerberus/styled-system/patterns";
4
+ import { jsx } from "react/jsx-runtime";
5
+ function TabList(props) {
6
+ const { description, ...nativeProps } = props;
7
+ return /* @__PURE__ */ jsx(
8
+ "div",
9
+ {
10
+ ...nativeProps,
11
+ "aria-describedby": description,
12
+ className: cx(
13
+ nativeProps.className,
14
+ hstack({
15
+ borderBottom: "1px solid",
16
+ borderBottomColor: "action.border.100",
17
+ gap: "0",
18
+ w: "full"
19
+ })
20
+ )
21
+ }
22
+ );
23
+ }
24
+
25
+ export {
26
+ TabList
27
+ };
28
+ //# sourceMappingURL=chunk-ODSSU3JD.js.map
@@ -0,0 +1 @@
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 borderBottom: '1px solid',\n borderBottomColor: 'action.border.100',\n gap: '0',\n w: 'full',\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,cAAc;AAAA,UACd,mBAAmB;AAAA,UACnB,KAAK;AAAA,UACL,GAAG;AAAA,QACL,CAAC;AAAA,MACH;AAAA;AAAA,EACF;AAEJ;","names":[]}
@@ -0,0 +1,43 @@
1
+ import {
2
+ Show
3
+ } from "./chunk-R4H3352X.js";
4
+ import {
5
+ useTabsContext
6
+ } from "./chunk-HQK7SM56.js";
7
+
8
+ // src/components/TabPanel.tsx
9
+ import { css, cx } from "@cerberus/styled-system/css";
10
+ import { useMemo } from "react";
11
+ import { jsx } from "react/jsx-runtime";
12
+ function TabPanel(props) {
13
+ const { tab, ...nativeProps } = props;
14
+ const { active } = useTabsContext();
15
+ const isActive = useMemo(() => active === tab, [active, tab]);
16
+ return /* @__PURE__ */ jsx(Show, { when: isActive, children: /* @__PURE__ */ jsx(
17
+ "div",
18
+ {
19
+ ...nativeProps,
20
+ ...isActive && { tabIndex: 0 },
21
+ "aria-labelledby": tab,
22
+ className: cx(
23
+ nativeProps.className,
24
+ css({
25
+ rounded: "md",
26
+ _focusVisible: {
27
+ boxShadow: "none",
28
+ outline: "3px solid",
29
+ outlineColor: "action.border.focus",
30
+ outlineOffset: "2px"
31
+ }
32
+ })
33
+ ),
34
+ id: `panel:${tab}`,
35
+ role: "tabpanel"
36
+ }
37
+ ) });
38
+ }
39
+
40
+ export {
41
+ TabPanel
42
+ };
43
+ //# sourceMappingURL=chunk-RCE2XXL7.js.map
@@ -0,0 +1 @@
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\n/**\n * This module provides a TabPanel component.\n * @module\n */\n\nexport interface TabPanelProps extends HTMLAttributes<HTMLDivElement> {\n tab: string\n}\n\n/**\n * The TabPanel component provides a panel element to be used in a Tabs provider.\n * @param tab - the value of the tab that will be tracked as the active tab and used for aria attributes\n * @example\n * ```tsx\n * <TabPanel tab=\"overview\">\n * Overview content\n * </TabPanel>\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(\n nativeProps.className,\n css({\n rounded: 'md',\n _focusVisible: {\n boxShadow: 'none',\n outline: '3px solid',\n outlineColor: 'action.border.focus',\n outlineOffset: '2px',\n },\n }),\n )}\n id={`panel:${tab}`}\n role=\"tabpanel\"\n />\n </Show>\n )\n}\n"],"mappings":";;;;;;;;AAEA,SAAS,KAAK,UAAU;AACxB,SAAS,eAAoC;AA8BvC;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;AAAA,QACT,YAAY;AAAA,QACZ,IAAI;AAAA,UACF,SAAS;AAAA,UACT,eAAe;AAAA,YACb,WAAW;AAAA,YACX,SAAS;AAAA,YACT,cAAc;AAAA,YACd,eAAe;AAAA,UACjB;AAAA,QACF,CAAC;AAAA,MACH;AAAA,MACA,IAAI,SAAS,GAAG;AAAA,MAChB,MAAK;AAAA;AAAA,EACP,GACF;AAEJ;","names":[]}
@@ -1,10 +1,10 @@
1
1
  "use client";
2
2
  import {
3
3
  NavMenuTrigger
4
- } from "../chunk-X6PHIZRM.js";
4
+ } from "../chunk-MJB3V6J4.js";
5
5
  import "../chunk-KJUCHZHV.js";
6
- import "../chunk-JF76VIL3.js";
7
6
  import "../chunk-R4H3352X.js";
7
+ import "../chunk-JF76VIL3.js";
8
8
  export {
9
9
  NavMenuTrigger
10
10
  };
@@ -0,0 +1,2 @@
1
+ export { Tab_alias_1 as Tab } from '../_tsup-dts-rollup';
2
+ export { TabProps_alias_1 as TabProps } from '../_tsup-dts-rollup';
@@ -0,0 +1,10 @@
1
+ "use client";
2
+ import {
3
+ Tab
4
+ } from "../chunk-36QCFAIS.js";
5
+ import "../chunk-57HOQM4E.js";
6
+ import "../chunk-HQK7SM56.js";
7
+ export {
8
+ Tab
9
+ };
10
+ //# sourceMappingURL=Tab.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,2 @@
1
+ export { TabList_alias_1 as TabList } from '../_tsup-dts-rollup';
2
+ export { TabListProps_alias_1 as TabListProps } from '../_tsup-dts-rollup';
@@ -0,0 +1,7 @@
1
+ import {
2
+ TabList
3
+ } from "../chunk-ODSSU3JD.js";
4
+ export {
5
+ TabList
6
+ };
7
+ //# sourceMappingURL=TabList.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,2 @@
1
+ export { TabPanel_alias_1 as TabPanel } from '../_tsup-dts-rollup';
2
+ export { TabPanelProps_alias_1 as TabPanelProps } from '../_tsup-dts-rollup';
@@ -0,0 +1,10 @@
1
+ "use client";
2
+ import {
3
+ TabPanel
4
+ } from "../chunk-RCE2XXL7.js";
5
+ import "../chunk-R4H3352X.js";
6
+ import "../chunk-HQK7SM56.js";
7
+ export {
8
+ TabPanel
9
+ };
10
+ //# sourceMappingURL=TabPanel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,5 @@
1
+ export { Tabs_alias_1 as Tabs } from '../_tsup-dts-rollup';
2
+ export { useTabsContext_alias_1 as useTabsContext } from '../_tsup-dts-rollup';
3
+ export { TabsContextValue_alias_1 as TabsContextValue } from '../_tsup-dts-rollup';
4
+ export { TabsContext_alias_1 as TabsContext } from '../_tsup-dts-rollup';
5
+ export { TabsProps_alias_1 as TabsProps } from '../_tsup-dts-rollup';
@@ -0,0 +1,12 @@
1
+ "use client";
2
+ import {
3
+ Tabs,
4
+ TabsContext,
5
+ useTabsContext
6
+ } from "../chunk-HQK7SM56.js";
7
+ export {
8
+ Tabs,
9
+ TabsContext,
10
+ useTabsContext
11
+ };
12
+ //# sourceMappingURL=tabs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}