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

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 (44) hide show
  1. package/build/legacy/_tsup-dts-rollup.d.ts +3 -1
  2. package/build/legacy/aria-helpers/tabs.aria.js +2 -2
  3. package/build/{modern/chunk-ODSSU3JD.js → legacy/chunk-5GSXIYD3.js} +8 -2
  4. package/build/legacy/chunk-5GSXIYD3.js.map +1 -0
  5. package/build/legacy/{chunk-57HOQM4E.js → chunk-BT2B5C7M.js} +2 -2
  6. package/build/legacy/{chunk-HQK7SM56.js → chunk-DQOYTLGB.js} +19 -13
  7. package/build/legacy/chunk-DQOYTLGB.js.map +1 -0
  8. package/build/legacy/{chunk-36QCFAIS.js → chunk-MYRKQVDI.js} +10 -5
  9. package/build/legacy/chunk-MYRKQVDI.js.map +1 -0
  10. package/build/{modern/chunk-RCE2XXL7.js → legacy/chunk-SVZU6LPF.js} +2 -2
  11. package/build/legacy/components/Tab.js +3 -3
  12. package/build/legacy/components/TabList.js +3 -1
  13. package/build/legacy/components/TabPanel.js +2 -2
  14. package/build/legacy/context/tabs.js +1 -1
  15. package/build/legacy/index.js +5 -5
  16. package/build/modern/_tsup-dts-rollup.d.ts +3 -1
  17. package/build/modern/aria-helpers/tabs.aria.js +2 -2
  18. package/build/{legacy/chunk-ODSSU3JD.js → modern/chunk-5GSXIYD3.js} +8 -2
  19. package/build/modern/chunk-5GSXIYD3.js.map +1 -0
  20. package/build/modern/{chunk-57HOQM4E.js → chunk-BT2B5C7M.js} +2 -2
  21. package/build/modern/{chunk-HQK7SM56.js → chunk-DQOYTLGB.js} +19 -13
  22. package/build/modern/chunk-DQOYTLGB.js.map +1 -0
  23. package/build/modern/{chunk-LAUJGQO2.js → chunk-IQP6HSC4.js} +10 -5
  24. package/build/modern/chunk-IQP6HSC4.js.map +1 -0
  25. package/build/{legacy/chunk-RCE2XXL7.js → modern/chunk-SVZU6LPF.js} +2 -2
  26. package/build/modern/components/Tab.js +3 -3
  27. package/build/modern/components/TabList.js +3 -1
  28. package/build/modern/components/TabPanel.js +2 -2
  29. package/build/modern/context/tabs.js +1 -1
  30. package/build/modern/index.js +5 -5
  31. package/package.json +1 -1
  32. package/src/components/Tab.tsx +9 -2
  33. package/src/components/TabList.tsx +6 -0
  34. package/src/context/tabs.tsx +23 -13
  35. package/build/legacy/chunk-36QCFAIS.js.map +0 -1
  36. package/build/legacy/chunk-HQK7SM56.js.map +0 -1
  37. package/build/legacy/chunk-ODSSU3JD.js.map +0 -1
  38. package/build/modern/chunk-HQK7SM56.js.map +0 -1
  39. package/build/modern/chunk-LAUJGQO2.js.map +0 -1
  40. package/build/modern/chunk-ODSSU3JD.js.map +0 -1
  41. /package/build/legacy/{chunk-57HOQM4E.js.map → chunk-BT2B5C7M.js.map} +0 -0
  42. /package/build/legacy/{chunk-RCE2XXL7.js.map → chunk-SVZU6LPF.js.map} +0 -0
  43. /package/build/modern/{chunk-57HOQM4E.js.map → chunk-BT2B5C7M.js.map} +0 -0
  44. /package/build/modern/{chunk-RCE2XXL7.js.map → chunk-SVZU6LPF.js.map} +0 -0
@@ -385,14 +385,16 @@ export { TabsContext as TabsContext_alias_1 }
385
385
  * @module
386
386
  */
387
387
  declare interface TabsContextValue {
388
- active: string;
389
388
  tabs: MutableRefObject<HTMLButtonElement[]>;
389
+ id: string;
390
+ active: string;
390
391
  onTabUpdate: (active: string) => void;
391
392
  }
392
393
  export { TabsContextValue }
393
394
  export { TabsContextValue as TabsContextValue_alias_1 }
394
395
 
395
396
  declare interface TabsProps {
397
+ id?: string;
396
398
  active?: string;
397
399
  cache?: boolean;
398
400
  }
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  import {
3
3
  useTabsKeyboardNavigation
4
- } from "../chunk-57HOQM4E.js";
5
- import "../chunk-HQK7SM56.js";
4
+ } from "../chunk-BT2B5C7M.js";
5
+ import "../chunk-DQOYTLGB.js";
6
6
  export {
7
7
  useTabsKeyboardNavigation
8
8
  };
@@ -1,9 +1,14 @@
1
+ import {
2
+ useTabsContext
3
+ } from "./chunk-DQOYTLGB.js";
4
+
1
5
  // src/components/TabList.tsx
2
6
  import { cx } from "@cerberus/styled-system/css";
3
7
  import { hstack } from "@cerberus/styled-system/patterns";
4
8
  import { jsx } from "react/jsx-runtime";
5
9
  function TabList(props) {
6
10
  const { description, ...nativeProps } = props;
11
+ const { id } = useTabsContext();
7
12
  return /* @__PURE__ */ jsx(
8
13
  "div",
9
14
  {
@@ -17,7 +22,8 @@ function TabList(props) {
17
22
  gap: "0",
18
23
  w: "full"
19
24
  })
20
- )
25
+ ),
26
+ id: id ?? nativeProps.id
21
27
  }
22
28
  );
23
29
  }
@@ -25,4 +31,4 @@ function TabList(props) {
25
31
  export {
26
32
  TabList
27
33
  };
28
- //# sourceMappingURL=chunk-ODSSU3JD.js.map
34
+ //# sourceMappingURL=chunk-5GSXIYD3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/TabList.tsx"],"sourcesContent":["'use client'\n\nimport { cx } from '@cerberus/styled-system/css'\nimport { hstack } from '@cerberus/styled-system/patterns'\nimport type { HTMLAttributes, PropsWithChildren } from 'react'\nimport { useTabsContext } from '../context/tabs'\n\n/**\n * This module provides a TabList component.\n * @module\n */\n\nexport interface TabListProps extends HTMLAttributes<HTMLDivElement> {\n 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 const { id } = useTabsContext()\n\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 id={id ?? nativeProps.id}\n />\n )\n}\n"],"mappings":";;;;;AAEA,SAAS,UAAU;AACnB,SAAS,cAAc;AA6BnB;AALG,SAAS,QAAQ,OAAwC;AAC9D,QAAM,EAAE,aAAa,GAAG,YAAY,IAAI;AACxC,QAAM,EAAE,GAAG,IAAI,eAAe;AAE9B,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,MACA,IAAI,MAAM,YAAY;AAAA;AAAA,EACxB;AAEJ;","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  useTabsContext
3
- } from "./chunk-HQK7SM56.js";
3
+ } from "./chunk-DQOYTLGB.js";
4
4
 
5
5
  // src/aria-helpers/tabs.aria.ts
6
6
  import { useEffect, useState } from "react";
@@ -62,4 +62,4 @@ function useTabsKeyboardNavigation() {
62
62
  export {
63
63
  useTabsKeyboardNavigation
64
64
  };
65
- //# sourceMappingURL=chunk-57HOQM4E.js.map
65
+ //# sourceMappingURL=chunk-BT2B5C7M.js.map
@@ -10,28 +10,34 @@ import {
10
10
  import { jsx } from "react/jsx-runtime";
11
11
  var TabsContext = createContext(null);
12
12
  function Tabs(props) {
13
- const { cache } = props;
14
- const [active, setActive] = useState(() => cache ? "" : props.active ?? "");
13
+ const { cache, active, id } = props;
14
+ const [activeTab, setActiveTab] = useState(() => cache ? "" : active ?? "");
15
15
  const tabs = useRef([]);
16
+ const uuid = useMemo(() => {
17
+ return id ? `cerberus-tabs-${id}` : "cerberus-tabs";
18
+ }, [id]);
16
19
  const value = useMemo(
17
20
  () => ({
18
- active,
19
21
  tabs,
20
- onTabUpdate: setActive
22
+ id: uuid,
23
+ active: activeTab,
24
+ onTabUpdate: setActiveTab
21
25
  }),
22
- [active, setActive]
26
+ [activeTab, setActiveTab, uuid, tabs]
23
27
  );
24
28
  useEffect(() => {
25
- const cachedTab = window.localStorage.getItem("cerberus-tabs");
26
- if (cache && cachedTab) {
27
- setActive(cachedTab);
29
+ if (cache) {
30
+ const cachedTab = window.localStorage.getItem(uuid);
31
+ setActiveTab(
32
+ cache ? cachedTab || (props.active ?? "") : props.active ?? ""
33
+ );
28
34
  }
29
- }, [cache]);
35
+ }, [cache, active, uuid]);
30
36
  useEffect(() => {
31
- if (cache) {
32
- window.localStorage.setItem("cerberus-tabs", active);
37
+ if (cache && activeTab) {
38
+ window.localStorage.setItem(uuid, activeTab);
33
39
  }
34
- }, [active, cache]);
40
+ }, [activeTab, cache]);
35
41
  return /* @__PURE__ */ jsx(TabsContext.Provider, { value, children: props.children });
36
42
  }
37
43
  function useTabsContext() {
@@ -47,4 +53,4 @@ export {
47
53
  Tabs,
48
54
  useTabsContext
49
55
  };
50
- //# sourceMappingURL=chunk-HQK7SM56.js.map
56
+ //# sourceMappingURL=chunk-DQOYTLGB.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 tabs: MutableRefObject<HTMLButtonElement[]>\n id: string\n active: string\n onTabUpdate: (active: string) => void\n}\n\nexport const TabsContext = createContext<TabsContextValue | null>(null)\n\nexport interface TabsProps {\n id?: string\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, active, id } = props\n const [activeTab, setActiveTab] = useState(() => (cache ? '' : active ?? ''))\n const tabs = useRef<HTMLButtonElement[]>([])\n const uuid = useMemo(() => {\n return id ? `cerberus-tabs-${id}` : 'cerberus-tabs'\n }, [id])\n\n const value = useMemo(\n () => ({\n tabs,\n id: uuid,\n active: activeTab,\n onTabUpdate: setActiveTab,\n }),\n [activeTab, setActiveTab, uuid, tabs],\n )\n\n // Get the active tab from local storage\n useEffect(() => {\n if (cache) {\n const cachedTab = window.localStorage.getItem(uuid)\n setActiveTab(\n cache ? cachedTab || (props.active ?? '') : props.active ?? '',\n )\n }\n }, [cache, active, uuid])\n\n // Update the active tab in local storage\n useEffect(() => {\n if (cache && activeTab) {\n window.localStorage.setItem(uuid, activeTab)\n }\n }, [activeTab, cache])\n\n return (\n <TabsContext.Provider value={value}>{props.children}</TabsContext.Provider>\n )\n}\n\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;AA4EH;AA9DG,IAAM,cAAc,cAAuC,IAAI;AA0B/D,SAAS,KAAK,OAAkD;AACrE,QAAM,EAAE,OAAO,QAAQ,GAAG,IAAI;AAC9B,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,MAAO,QAAQ,KAAK,UAAU,EAAG;AAC5E,QAAM,OAAO,OAA4B,CAAC,CAAC;AAC3C,QAAM,OAAO,QAAQ,MAAM;AACzB,WAAO,KAAK,iBAAiB,EAAE,KAAK;AAAA,EACtC,GAAG,CAAC,EAAE,CAAC;AAEP,QAAM,QAAQ;AAAA,IACZ,OAAO;AAAA,MACL;AAAA,MACA,IAAI;AAAA,MACJ,QAAQ;AAAA,MACR,aAAa;AAAA,IACf;AAAA,IACA,CAAC,WAAW,cAAc,MAAM,IAAI;AAAA,EACtC;AAGA,YAAU,MAAM;AACd,QAAI,OAAO;AACT,YAAM,YAAY,OAAO,aAAa,QAAQ,IAAI;AAClD;AAAA,QACE,QAAQ,cAAc,MAAM,UAAU,MAAM,MAAM,UAAU;AAAA,MAC9D;AAAA,IACF;AAAA,EACF,GAAG,CAAC,OAAO,QAAQ,IAAI,CAAC;AAGxB,YAAU,MAAM;AACd,QAAI,SAAS,WAAW;AACtB,aAAO,aAAa,QAAQ,MAAM,SAAS;AAAA,IAC7C;AAAA,EACF,GAAG,CAAC,WAAW,KAAK,CAAC;AAErB,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,23 +1,27 @@
1
1
  import {
2
2
  useTabsKeyboardNavigation
3
- } from "./chunk-57HOQM4E.js";
3
+ } from "./chunk-BT2B5C7M.js";
4
4
  import {
5
5
  useTabsContext
6
- } from "./chunk-HQK7SM56.js";
6
+ } from "./chunk-DQOYTLGB.js";
7
7
 
8
8
  // src/components/Tab.tsx
9
- import { useMemo } from "react";
9
+ import {
10
+ useMemo,
11
+ useTransition
12
+ } from "react";
10
13
  import { css, cx } from "@cerberus/styled-system/css";
11
14
  import { jsx } from "react/jsx-runtime";
12
15
  function Tab(props) {
13
16
  const { value, ...nativeProps } = props;
14
17
  const { active, onTabUpdate } = useTabsContext();
18
+ const [isPending, startTransition] = useTransition();
15
19
  const { ref } = useTabsKeyboardNavigation();
16
20
  const isActive = useMemo(() => active === value, [active, value]);
17
21
  function handleClick(e) {
18
22
  var _a;
19
23
  (_a = props.onClick) == null ? void 0 : _a.call(props, e);
20
- onTabUpdate(e.currentTarget.value);
24
+ startTransition(() => onTabUpdate(e.currentTarget.value));
21
25
  }
22
26
  return /* @__PURE__ */ jsx(
23
27
  "button",
@@ -25,6 +29,7 @@ function Tab(props) {
25
29
  ...nativeProps,
26
30
  ...!isActive && { tabIndex: -1 },
27
31
  "aria-controls": `panel:${value}`,
32
+ "aria-busy": isPending,
28
33
  "aria-selected": isActive,
29
34
  id: value,
30
35
  className: cx(nativeProps.className, btnStyles),
@@ -118,4 +123,4 @@ var btnStyles = css({
118
123
  export {
119
124
  Tab
120
125
  };
121
- //# sourceMappingURL=chunk-36QCFAIS.js.map
126
+ //# sourceMappingURL=chunk-MYRKQVDI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/Tab.tsx"],"sourcesContent":["'use client'\n\nimport {\n useMemo,\n useTransition,\n type ButtonHTMLAttributes,\n type MouseEvent,\n} 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 [isPending, startTransition] = useTransition()\n const { ref } = useTabsKeyboardNavigation()\n const isActive = useMemo(() => active === value, [active, value])\n\n function handleClick(e: MouseEvent<HTMLButtonElement>) {\n props.onClick?.(e)\n startTransition(() => onTabUpdate(e.currentTarget.value))\n }\n\n return (\n <button\n {...nativeProps}\n {...(!isActive && { tabIndex: -1 })}\n aria-controls={`panel:${value}`}\n aria-busy={isPending}\n aria-selected={isActive}\n id={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;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAEP,SAAS,KAAK,UAAU;AAqCpB;AAbG,SAAS,IAAI,OAAiB;AACnC,QAAM,EAAE,OAAO,GAAG,YAAY,IAAI;AAClC,QAAM,EAAE,QAAQ,YAAY,IAAI,eAAe;AAC/C,QAAM,CAAC,WAAW,eAAe,IAAI,cAAc;AACnD,QAAM,EAAE,IAAI,IAAI,0BAA0B;AAC1C,QAAM,WAAW,QAAQ,MAAM,WAAW,OAAO,CAAC,QAAQ,KAAK,CAAC;AAEhE,WAAS,YAAY,GAAkC;AAxCzD;AAyCI,gBAAM,YAAN,+BAAgB;AAChB,oBAAgB,MAAM,YAAY,EAAE,cAAc,KAAK,CAAC;AAAA,EAC1D;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACH,GAAI,CAAC,YAAY,EAAE,UAAU,GAAG;AAAA,MACjC,iBAAe,SAAS,KAAK;AAAA,MAC7B,aAAW;AAAA,MACX,iBAAe;AAAA,MACf,IAAI;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":[]}
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-R4H3352X.js";
4
4
  import {
5
5
  useTabsContext
6
- } from "./chunk-HQK7SM56.js";
6
+ } from "./chunk-DQOYTLGB.js";
7
7
 
8
8
  // src/components/TabPanel.tsx
9
9
  import { css, cx } from "@cerberus/styled-system/css";
@@ -40,4 +40,4 @@ function TabPanel(props) {
40
40
  export {
41
41
  TabPanel
42
42
  };
43
- //# sourceMappingURL=chunk-RCE2XXL7.js.map
43
+ //# sourceMappingURL=chunk-SVZU6LPF.js.map
@@ -1,9 +1,9 @@
1
1
  "use client";
2
2
  import {
3
3
  Tab
4
- } from "../chunk-36QCFAIS.js";
5
- import "../chunk-57HOQM4E.js";
6
- import "../chunk-HQK7SM56.js";
4
+ } from "../chunk-MYRKQVDI.js";
5
+ import "../chunk-BT2B5C7M.js";
6
+ import "../chunk-DQOYTLGB.js";
7
7
  export {
8
8
  Tab
9
9
  };
@@ -1,6 +1,8 @@
1
+ "use client";
1
2
  import {
2
3
  TabList
3
- } from "../chunk-ODSSU3JD.js";
4
+ } from "../chunk-5GSXIYD3.js";
5
+ import "../chunk-DQOYTLGB.js";
4
6
  export {
5
7
  TabList
6
8
  };
@@ -1,9 +1,9 @@
1
1
  "use client";
2
2
  import {
3
3
  TabPanel
4
- } from "../chunk-RCE2XXL7.js";
4
+ } from "../chunk-SVZU6LPF.js";
5
5
  import "../chunk-R4H3352X.js";
6
- import "../chunk-HQK7SM56.js";
6
+ import "../chunk-DQOYTLGB.js";
7
7
  export {
8
8
  TabPanel
9
9
  };
@@ -3,7 +3,7 @@ import {
3
3
  Tabs,
4
4
  TabsContext,
5
5
  useTabsContext
6
- } from "../chunk-HQK7SM56.js";
6
+ } from "../chunk-DQOYTLGB.js";
7
7
  export {
8
8
  Tabs,
9
9
  TabsContext,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  TabPanel
3
- } from "./chunk-RCE2XXL7.js";
3
+ } from "./chunk-SVZU6LPF.js";
4
4
  import {
5
5
  Input
6
6
  } from "./chunk-LD5ZV46F.js";
@@ -26,22 +26,22 @@ import {
26
26
  } from "./chunk-R4H3352X.js";
27
27
  import {
28
28
  Tab
29
- } from "./chunk-36QCFAIS.js";
29
+ } from "./chunk-MYRKQVDI.js";
30
30
  import {
31
31
  TabList
32
- } from "./chunk-ODSSU3JD.js";
32
+ } from "./chunk-5GSXIYD3.js";
33
33
  import "./chunk-55J6XMHW.js";
34
34
  import {
35
35
  createNavTriggerProps
36
36
  } from "./chunk-JF76VIL3.js";
37
37
  import {
38
38
  useTabsKeyboardNavigation
39
- } from "./chunk-57HOQM4E.js";
39
+ } from "./chunk-BT2B5C7M.js";
40
40
  import {
41
41
  Tabs,
42
42
  TabsContext,
43
43
  useTabsContext
44
- } from "./chunk-HQK7SM56.js";
44
+ } from "./chunk-DQOYTLGB.js";
45
45
  import {
46
46
  MODE_KEY,
47
47
  THEME_KEY,
@@ -385,14 +385,16 @@ export { TabsContext as TabsContext_alias_1 }
385
385
  * @module
386
386
  */
387
387
  declare interface TabsContextValue {
388
- active: string;
389
388
  tabs: MutableRefObject<HTMLButtonElement[]>;
389
+ id: string;
390
+ active: string;
390
391
  onTabUpdate: (active: string) => void;
391
392
  }
392
393
  export { TabsContextValue }
393
394
  export { TabsContextValue as TabsContextValue_alias_1 }
394
395
 
395
396
  declare interface TabsProps {
397
+ id?: string;
396
398
  active?: string;
397
399
  cache?: boolean;
398
400
  }
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  import {
3
3
  useTabsKeyboardNavigation
4
- } from "../chunk-57HOQM4E.js";
5
- import "../chunk-HQK7SM56.js";
4
+ } from "../chunk-BT2B5C7M.js";
5
+ import "../chunk-DQOYTLGB.js";
6
6
  export {
7
7
  useTabsKeyboardNavigation
8
8
  };
@@ -1,9 +1,14 @@
1
+ import {
2
+ useTabsContext
3
+ } from "./chunk-DQOYTLGB.js";
4
+
1
5
  // src/components/TabList.tsx
2
6
  import { cx } from "@cerberus/styled-system/css";
3
7
  import { hstack } from "@cerberus/styled-system/patterns";
4
8
  import { jsx } from "react/jsx-runtime";
5
9
  function TabList(props) {
6
10
  const { description, ...nativeProps } = props;
11
+ const { id } = useTabsContext();
7
12
  return /* @__PURE__ */ jsx(
8
13
  "div",
9
14
  {
@@ -17,7 +22,8 @@ function TabList(props) {
17
22
  gap: "0",
18
23
  w: "full"
19
24
  })
20
- )
25
+ ),
26
+ id: id ?? nativeProps.id
21
27
  }
22
28
  );
23
29
  }
@@ -25,4 +31,4 @@ function TabList(props) {
25
31
  export {
26
32
  TabList
27
33
  };
28
- //# sourceMappingURL=chunk-ODSSU3JD.js.map
34
+ //# sourceMappingURL=chunk-5GSXIYD3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/TabList.tsx"],"sourcesContent":["'use client'\n\nimport { cx } from '@cerberus/styled-system/css'\nimport { hstack } from '@cerberus/styled-system/patterns'\nimport type { HTMLAttributes, PropsWithChildren } from 'react'\nimport { useTabsContext } from '../context/tabs'\n\n/**\n * This module provides a TabList component.\n * @module\n */\n\nexport interface TabListProps extends HTMLAttributes<HTMLDivElement> {\n 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 const { id } = useTabsContext()\n\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 id={id ?? nativeProps.id}\n />\n )\n}\n"],"mappings":";;;;;AAEA,SAAS,UAAU;AACnB,SAAS,cAAc;AA6BnB;AALG,SAAS,QAAQ,OAAwC;AAC9D,QAAM,EAAE,aAAa,GAAG,YAAY,IAAI;AACxC,QAAM,EAAE,GAAG,IAAI,eAAe;AAE9B,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,MACA,IAAI,MAAM,YAAY;AAAA;AAAA,EACxB;AAEJ;","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  useTabsContext
3
- } from "./chunk-HQK7SM56.js";
3
+ } from "./chunk-DQOYTLGB.js";
4
4
 
5
5
  // src/aria-helpers/tabs.aria.ts
6
6
  import { useEffect, useState } from "react";
@@ -62,4 +62,4 @@ function useTabsKeyboardNavigation() {
62
62
  export {
63
63
  useTabsKeyboardNavigation
64
64
  };
65
- //# sourceMappingURL=chunk-57HOQM4E.js.map
65
+ //# sourceMappingURL=chunk-BT2B5C7M.js.map
@@ -10,28 +10,34 @@ import {
10
10
  import { jsx } from "react/jsx-runtime";
11
11
  var TabsContext = createContext(null);
12
12
  function Tabs(props) {
13
- const { cache } = props;
14
- const [active, setActive] = useState(() => cache ? "" : props.active ?? "");
13
+ const { cache, active, id } = props;
14
+ const [activeTab, setActiveTab] = useState(() => cache ? "" : active ?? "");
15
15
  const tabs = useRef([]);
16
+ const uuid = useMemo(() => {
17
+ return id ? `cerberus-tabs-${id}` : "cerberus-tabs";
18
+ }, [id]);
16
19
  const value = useMemo(
17
20
  () => ({
18
- active,
19
21
  tabs,
20
- onTabUpdate: setActive
22
+ id: uuid,
23
+ active: activeTab,
24
+ onTabUpdate: setActiveTab
21
25
  }),
22
- [active, setActive]
26
+ [activeTab, setActiveTab, uuid, tabs]
23
27
  );
24
28
  useEffect(() => {
25
- const cachedTab = window.localStorage.getItem("cerberus-tabs");
26
- if (cache && cachedTab) {
27
- setActive(cachedTab);
29
+ if (cache) {
30
+ const cachedTab = window.localStorage.getItem(uuid);
31
+ setActiveTab(
32
+ cache ? cachedTab || (props.active ?? "") : props.active ?? ""
33
+ );
28
34
  }
29
- }, [cache]);
35
+ }, [cache, active, uuid]);
30
36
  useEffect(() => {
31
- if (cache) {
32
- window.localStorage.setItem("cerberus-tabs", active);
37
+ if (cache && activeTab) {
38
+ window.localStorage.setItem(uuid, activeTab);
33
39
  }
34
- }, [active, cache]);
40
+ }, [activeTab, cache]);
35
41
  return /* @__PURE__ */ jsx(TabsContext.Provider, { value, children: props.children });
36
42
  }
37
43
  function useTabsContext() {
@@ -47,4 +53,4 @@ export {
47
53
  Tabs,
48
54
  useTabsContext
49
55
  };
50
- //# sourceMappingURL=chunk-HQK7SM56.js.map
56
+ //# sourceMappingURL=chunk-DQOYTLGB.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 tabs: MutableRefObject<HTMLButtonElement[]>\n id: string\n active: string\n onTabUpdate: (active: string) => void\n}\n\nexport const TabsContext = createContext<TabsContextValue | null>(null)\n\nexport interface TabsProps {\n id?: string\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, active, id } = props\n const [activeTab, setActiveTab] = useState(() => (cache ? '' : active ?? ''))\n const tabs = useRef<HTMLButtonElement[]>([])\n const uuid = useMemo(() => {\n return id ? `cerberus-tabs-${id}` : 'cerberus-tabs'\n }, [id])\n\n const value = useMemo(\n () => ({\n tabs,\n id: uuid,\n active: activeTab,\n onTabUpdate: setActiveTab,\n }),\n [activeTab, setActiveTab, uuid, tabs],\n )\n\n // Get the active tab from local storage\n useEffect(() => {\n if (cache) {\n const cachedTab = window.localStorage.getItem(uuid)\n setActiveTab(\n cache ? cachedTab || (props.active ?? '') : props.active ?? '',\n )\n }\n }, [cache, active, uuid])\n\n // Update the active tab in local storage\n useEffect(() => {\n if (cache && activeTab) {\n window.localStorage.setItem(uuid, activeTab)\n }\n }, [activeTab, cache])\n\n return (\n <TabsContext.Provider value={value}>{props.children}</TabsContext.Provider>\n )\n}\n\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;AA4EH;AA9DG,IAAM,cAAc,cAAuC,IAAI;AA0B/D,SAAS,KAAK,OAAkD;AACrE,QAAM,EAAE,OAAO,QAAQ,GAAG,IAAI;AAC9B,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,MAAO,QAAQ,KAAK,UAAU,EAAG;AAC5E,QAAM,OAAO,OAA4B,CAAC,CAAC;AAC3C,QAAM,OAAO,QAAQ,MAAM;AACzB,WAAO,KAAK,iBAAiB,EAAE,KAAK;AAAA,EACtC,GAAG,CAAC,EAAE,CAAC;AAEP,QAAM,QAAQ;AAAA,IACZ,OAAO;AAAA,MACL;AAAA,MACA,IAAI;AAAA,MACJ,QAAQ;AAAA,MACR,aAAa;AAAA,IACf;AAAA,IACA,CAAC,WAAW,cAAc,MAAM,IAAI;AAAA,EACtC;AAGA,YAAU,MAAM;AACd,QAAI,OAAO;AACT,YAAM,YAAY,OAAO,aAAa,QAAQ,IAAI;AAClD;AAAA,QACE,QAAQ,cAAc,MAAM,UAAU,MAAM,MAAM,UAAU;AAAA,MAC9D;AAAA,IACF;AAAA,EACF,GAAG,CAAC,OAAO,QAAQ,IAAI,CAAC;AAGxB,YAAU,MAAM;AACd,QAAI,SAAS,WAAW;AACtB,aAAO,aAAa,QAAQ,MAAM,SAAS;AAAA,IAC7C;AAAA,EACF,GAAG,CAAC,WAAW,KAAK,CAAC;AAErB,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,22 +1,26 @@
1
1
  import {
2
2
  useTabsKeyboardNavigation
3
- } from "./chunk-57HOQM4E.js";
3
+ } from "./chunk-BT2B5C7M.js";
4
4
  import {
5
5
  useTabsContext
6
- } from "./chunk-HQK7SM56.js";
6
+ } from "./chunk-DQOYTLGB.js";
7
7
 
8
8
  // src/components/Tab.tsx
9
- import { useMemo } from "react";
9
+ import {
10
+ useMemo,
11
+ useTransition
12
+ } from "react";
10
13
  import { css, cx } from "@cerberus/styled-system/css";
11
14
  import { jsx } from "react/jsx-runtime";
12
15
  function Tab(props) {
13
16
  const { value, ...nativeProps } = props;
14
17
  const { active, onTabUpdate } = useTabsContext();
18
+ const [isPending, startTransition] = useTransition();
15
19
  const { ref } = useTabsKeyboardNavigation();
16
20
  const isActive = useMemo(() => active === value, [active, value]);
17
21
  function handleClick(e) {
18
22
  props.onClick?.(e);
19
- onTabUpdate(e.currentTarget.value);
23
+ startTransition(() => onTabUpdate(e.currentTarget.value));
20
24
  }
21
25
  return /* @__PURE__ */ jsx(
22
26
  "button",
@@ -24,6 +28,7 @@ function Tab(props) {
24
28
  ...nativeProps,
25
29
  ...!isActive && { tabIndex: -1 },
26
30
  "aria-controls": `panel:${value}`,
31
+ "aria-busy": isPending,
27
32
  "aria-selected": isActive,
28
33
  id: value,
29
34
  className: cx(nativeProps.className, btnStyles),
@@ -117,4 +122,4 @@ var btnStyles = css({
117
122
  export {
118
123
  Tab
119
124
  };
120
- //# sourceMappingURL=chunk-LAUJGQO2.js.map
125
+ //# sourceMappingURL=chunk-IQP6HSC4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/Tab.tsx"],"sourcesContent":["'use client'\n\nimport {\n useMemo,\n useTransition,\n type ButtonHTMLAttributes,\n type MouseEvent,\n} 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 [isPending, startTransition] = useTransition()\n const { ref } = useTabsKeyboardNavigation()\n const isActive = useMemo(() => active === value, [active, value])\n\n function handleClick(e: MouseEvent<HTMLButtonElement>) {\n props.onClick?.(e)\n startTransition(() => onTabUpdate(e.currentTarget.value))\n }\n\n return (\n <button\n {...nativeProps}\n {...(!isActive && { tabIndex: -1 })}\n aria-controls={`panel:${value}`}\n aria-busy={isPending}\n aria-selected={isActive}\n id={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;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAEP,SAAS,KAAK,UAAU;AAqCpB;AAbG,SAAS,IAAI,OAAiB;AACnC,QAAM,EAAE,OAAO,GAAG,YAAY,IAAI;AAClC,QAAM,EAAE,QAAQ,YAAY,IAAI,eAAe;AAC/C,QAAM,CAAC,WAAW,eAAe,IAAI,cAAc;AACnD,QAAM,EAAE,IAAI,IAAI,0BAA0B;AAC1C,QAAM,WAAW,QAAQ,MAAM,WAAW,OAAO,CAAC,QAAQ,KAAK,CAAC;AAEhE,WAAS,YAAY,GAAkC;AACrD,UAAM,UAAU,CAAC;AACjB,oBAAgB,MAAM,YAAY,EAAE,cAAc,KAAK,CAAC;AAAA,EAC1D;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACH,GAAI,CAAC,YAAY,EAAE,UAAU,GAAG;AAAA,MACjC,iBAAe,SAAS,KAAK;AAAA,MAC7B,aAAW;AAAA,MACX,iBAAe;AAAA,MACf,IAAI;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":[]}
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-R4H3352X.js";
4
4
  import {
5
5
  useTabsContext
6
- } from "./chunk-HQK7SM56.js";
6
+ } from "./chunk-DQOYTLGB.js";
7
7
 
8
8
  // src/components/TabPanel.tsx
9
9
  import { css, cx } from "@cerberus/styled-system/css";
@@ -40,4 +40,4 @@ function TabPanel(props) {
40
40
  export {
41
41
  TabPanel
42
42
  };
43
- //# sourceMappingURL=chunk-RCE2XXL7.js.map
43
+ //# sourceMappingURL=chunk-SVZU6LPF.js.map
@@ -1,9 +1,9 @@
1
1
  "use client";
2
2
  import {
3
3
  Tab
4
- } from "../chunk-LAUJGQO2.js";
5
- import "../chunk-57HOQM4E.js";
6
- import "../chunk-HQK7SM56.js";
4
+ } from "../chunk-IQP6HSC4.js";
5
+ import "../chunk-BT2B5C7M.js";
6
+ import "../chunk-DQOYTLGB.js";
7
7
  export {
8
8
  Tab
9
9
  };
@@ -1,6 +1,8 @@
1
+ "use client";
1
2
  import {
2
3
  TabList
3
- } from "../chunk-ODSSU3JD.js";
4
+ } from "../chunk-5GSXIYD3.js";
5
+ import "../chunk-DQOYTLGB.js";
4
6
  export {
5
7
  TabList
6
8
  };
@@ -1,9 +1,9 @@
1
1
  "use client";
2
2
  import {
3
3
  TabPanel
4
- } from "../chunk-RCE2XXL7.js";
4
+ } from "../chunk-SVZU6LPF.js";
5
5
  import "../chunk-R4H3352X.js";
6
- import "../chunk-HQK7SM56.js";
6
+ import "../chunk-DQOYTLGB.js";
7
7
  export {
8
8
  TabPanel
9
9
  };
@@ -3,7 +3,7 @@ import {
3
3
  Tabs,
4
4
  TabsContext,
5
5
  useTabsContext
6
- } from "../chunk-HQK7SM56.js";
6
+ } from "../chunk-DQOYTLGB.js";
7
7
  export {
8
8
  Tabs,
9
9
  TabsContext,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  TabPanel
3
- } from "./chunk-RCE2XXL7.js";
3
+ } from "./chunk-SVZU6LPF.js";
4
4
  import {
5
5
  Input
6
6
  } from "./chunk-LD5ZV46F.js";
@@ -26,22 +26,22 @@ import {
26
26
  } from "./chunk-R4H3352X.js";
27
27
  import {
28
28
  Tab
29
- } from "./chunk-LAUJGQO2.js";
29
+ } from "./chunk-IQP6HSC4.js";
30
30
  import {
31
31
  TabList
32
- } from "./chunk-ODSSU3JD.js";
32
+ } from "./chunk-5GSXIYD3.js";
33
33
  import "./chunk-55J6XMHW.js";
34
34
  import {
35
35
  createNavTriggerProps
36
36
  } from "./chunk-JF76VIL3.js";
37
37
  import {
38
38
  useTabsKeyboardNavigation
39
- } from "./chunk-57HOQM4E.js";
39
+ } from "./chunk-BT2B5C7M.js";
40
40
  import {
41
41
  Tabs,
42
42
  TabsContext,
43
43
  useTabsContext
44
- } from "./chunk-HQK7SM56.js";
44
+ } from "./chunk-DQOYTLGB.js";
45
45
  import {
46
46
  MODE_KEY,
47
47
  THEME_KEY,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cerberus-design/react",
3
- "version": "0.3.1-next-f5a8b6a",
3
+ "version": "0.3.2",
4
4
  "description": "The Cerberus Design React component library.",
5
5
  "browserslist": "> 0.25%, not dead",
6
6
  "sideEffects": false,
@@ -1,6 +1,11 @@
1
1
  'use client'
2
2
 
3
- import { useMemo, type ButtonHTMLAttributes, type MouseEvent } from 'react'
3
+ import {
4
+ useMemo,
5
+ useTransition,
6
+ type ButtonHTMLAttributes,
7
+ type MouseEvent,
8
+ } from 'react'
4
9
  import { useTabsContext } from '../context/tabs'
5
10
  import { css, cx } from '@cerberus/styled-system/css'
6
11
  import { useTabsKeyboardNavigation } from '../aria-helpers/tabs.aria'
@@ -29,12 +34,13 @@ export interface TabProps extends ButtonHTMLAttributes<HTMLButtonElement> {
29
34
  export function Tab(props: TabProps) {
30
35
  const { value, ...nativeProps } = props
31
36
  const { active, onTabUpdate } = useTabsContext()
37
+ const [isPending, startTransition] = useTransition()
32
38
  const { ref } = useTabsKeyboardNavigation()
33
39
  const isActive = useMemo(() => active === value, [active, value])
34
40
 
35
41
  function handleClick(e: MouseEvent<HTMLButtonElement>) {
36
42
  props.onClick?.(e)
37
- onTabUpdate(e.currentTarget.value)
43
+ startTransition(() => onTabUpdate(e.currentTarget.value))
38
44
  }
39
45
 
40
46
  return (
@@ -42,6 +48,7 @@ export function Tab(props: TabProps) {
42
48
  {...nativeProps}
43
49
  {...(!isActive && { tabIndex: -1 })}
44
50
  aria-controls={`panel:${value}`}
51
+ aria-busy={isPending}
45
52
  aria-selected={isActive}
46
53
  id={value}
47
54
  className={cx(nativeProps.className, btnStyles)}
@@ -1,6 +1,9 @@
1
+ 'use client'
2
+
1
3
  import { cx } from '@cerberus/styled-system/css'
2
4
  import { hstack } from '@cerberus/styled-system/patterns'
3
5
  import type { HTMLAttributes, PropsWithChildren } from 'react'
6
+ import { useTabsContext } from '../context/tabs'
4
7
 
5
8
  /**
6
9
  * This module provides a TabList component.
@@ -24,6 +27,8 @@ export interface TabListProps extends HTMLAttributes<HTMLDivElement> {
24
27
  */
25
28
  export function TabList(props: PropsWithChildren<TabListProps>) {
26
29
  const { description, ...nativeProps } = props
30
+ const { id } = useTabsContext()
31
+
27
32
  return (
28
33
  <div
29
34
  {...nativeProps}
@@ -37,6 +42,7 @@ export function TabList(props: PropsWithChildren<TabListProps>) {
37
42
  w: 'full',
38
43
  }),
39
44
  )}
45
+ id={id ?? nativeProps.id}
40
46
  />
41
47
  )
42
48
  }
@@ -17,14 +17,16 @@ import {
17
17
  */
18
18
 
19
19
  export interface TabsContextValue {
20
- active: string
21
20
  tabs: MutableRefObject<HTMLButtonElement[]>
21
+ id: string
22
+ active: string
22
23
  onTabUpdate: (active: string) => void
23
24
  }
24
25
 
25
26
  export const TabsContext = createContext<TabsContextValue | null>(null)
26
27
 
27
28
  export interface TabsProps {
29
+ id?: string
28
30
  active?: string
29
31
  cache?: boolean
30
32
  }
@@ -48,31 +50,39 @@ export interface TabsProps {
48
50
  * ```
49
51
  */
50
52
  export function Tabs(props: PropsWithChildren<TabsProps>): JSX.Element {
51
- const { cache } = props
52
- const [active, setActive] = useState(() => (cache ? '' : props.active ?? ''))
53
+ const { cache, active, id } = props
54
+ const [activeTab, setActiveTab] = useState(() => (cache ? '' : active ?? ''))
53
55
  const tabs = useRef<HTMLButtonElement[]>([])
56
+ const uuid = useMemo(() => {
57
+ return id ? `cerberus-tabs-${id}` : 'cerberus-tabs'
58
+ }, [id])
54
59
 
55
60
  const value = useMemo(
56
61
  () => ({
57
- active,
58
62
  tabs,
59
- onTabUpdate: setActive,
63
+ id: uuid,
64
+ active: activeTab,
65
+ onTabUpdate: setActiveTab,
60
66
  }),
61
- [active, setActive],
67
+ [activeTab, setActiveTab, uuid, tabs],
62
68
  )
63
69
 
70
+ // Get the active tab from local storage
64
71
  useEffect(() => {
65
- const cachedTab = window.localStorage.getItem('cerberus-tabs')
66
- if (cache && cachedTab) {
67
- setActive(cachedTab)
72
+ if (cache) {
73
+ const cachedTab = window.localStorage.getItem(uuid)
74
+ setActiveTab(
75
+ cache ? cachedTab || (props.active ?? '') : props.active ?? '',
76
+ )
68
77
  }
69
- }, [cache])
78
+ }, [cache, active, uuid])
70
79
 
80
+ // Update the active tab in local storage
71
81
  useEffect(() => {
72
- if (cache) {
73
- window.localStorage.setItem('cerberus-tabs', active)
82
+ if (cache && activeTab) {
83
+ window.localStorage.setItem(uuid, activeTab)
74
84
  }
75
- }, [active, cache])
85
+ }, [activeTab, cache])
76
86
 
77
87
  return (
78
88
  <TabsContext.Provider value={value}>{props.children}</TabsContext.Provider>
@@ -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'\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":[]}
@@ -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 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 +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 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":[]}
@@ -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 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 +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'\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;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,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":[]}
@@ -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 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":[]}