@blockle/blocks-react 3.2.0 → 3.3.1

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 (75) hide show
  1. package/dist/components/display/Divider/divider.css.js +3 -3
  2. package/dist/components/form/Label/Label.d.ts +1 -1
  3. package/dist/components/form/Label/Label.d.ts.map +1 -1
  4. package/dist/components/form/Select/select.css.js +1 -1
  5. package/dist/components/navigation/Tabs/Tab.d.ts +21 -0
  6. package/dist/components/navigation/Tabs/Tab.d.ts.map +1 -0
  7. package/dist/components/navigation/Tabs/Tab.js +138 -0
  8. package/dist/components/navigation/Tabs/TabIndicator.d.ts +6 -0
  9. package/dist/components/navigation/Tabs/TabIndicator.d.ts.map +1 -0
  10. package/dist/components/navigation/Tabs/TabIndicator.js +19 -0
  11. package/dist/components/navigation/Tabs/TabList.d.ts +10 -0
  12. package/dist/components/navigation/Tabs/TabList.d.ts.map +1 -0
  13. package/dist/components/navigation/Tabs/TabList.js +101 -0
  14. package/dist/components/navigation/Tabs/TabListContext.d.ts +13 -0
  15. package/dist/components/navigation/Tabs/TabListContext.d.ts.map +1 -0
  16. package/dist/components/navigation/Tabs/TabListContext.js +6 -0
  17. package/dist/components/navigation/Tabs/TabNav.d.ts +15 -0
  18. package/dist/components/navigation/Tabs/TabNav.d.ts.map +1 -0
  19. package/dist/components/navigation/Tabs/TabNav.js +44 -0
  20. package/dist/components/navigation/Tabs/TabPanel.d.ts +14 -0
  21. package/dist/components/navigation/Tabs/TabPanel.d.ts.map +1 -0
  22. package/dist/components/navigation/Tabs/TabPanel.js +31 -0
  23. package/dist/components/navigation/Tabs/Tabs.d.ts +13 -0
  24. package/dist/components/navigation/Tabs/Tabs.d.ts.map +1 -0
  25. package/dist/components/navigation/Tabs/Tabs.js +33 -0
  26. package/dist/components/navigation/Tabs/TabsContext.d.ts +13 -0
  27. package/dist/components/navigation/Tabs/TabsContext.d.ts.map +1 -0
  28. package/dist/components/navigation/Tabs/TabsContext.js +27 -0
  29. package/dist/components/navigation/Tabs/tabs.css.d.ts +7 -0
  30. package/dist/components/navigation/Tabs/tabs.css.d.ts.map +1 -0
  31. package/dist/components/navigation/Tabs/tabs.css.js +122 -0
  32. package/dist/components/overlay/Dialog/Dialog.d.ts +1 -1
  33. package/dist/components/overlay/Dialog/Dialog.d.ts.map +1 -1
  34. package/dist/components/overlay/Dialog/Dialog.js +9 -7
  35. package/dist/components/overlay/Drawer/Drawer.d.ts +1 -1
  36. package/dist/components/overlay/Drawer/Drawer.d.ts.map +1 -1
  37. package/dist/components/overlay/Drawer/Drawer.js +9 -7
  38. package/dist/components/overlay/Menu/Menu.d.ts +52 -0
  39. package/dist/components/overlay/Menu/Menu.d.ts.map +1 -0
  40. package/dist/components/overlay/Menu/Menu.js +273 -0
  41. package/dist/components/overlay/Menu/menu-utils.d.ts +33 -0
  42. package/dist/components/overlay/Menu/menu-utils.d.ts.map +1 -0
  43. package/dist/components/overlay/Menu/menu-utils.js +54 -0
  44. package/dist/components/overlay/Popover/Popover.d.ts +9 -0
  45. package/dist/components/overlay/Popover/Popover.d.ts.map +1 -1
  46. package/dist/components/overlay/Popover/Popover.js +84 -31
  47. package/dist/components/overlay/Popover/popover-utils.d.ts +32 -1
  48. package/dist/components/overlay/Popover/popover-utils.d.ts.map +1 -1
  49. package/dist/components/overlay/Popover/popover-utils.js +77 -22
  50. package/dist/components/overlay/modalOverlayStack.d.ts +8 -0
  51. package/dist/components/overlay/modalOverlayStack.d.ts.map +1 -0
  52. package/dist/components/overlay/modalOverlayStack.js +37 -0
  53. package/dist/components/overlay/useModalOverlay.d.ts +6 -14
  54. package/dist/components/overlay/useModalOverlay.d.ts.map +1 -1
  55. package/dist/components/overlay/useModalOverlay.js +8 -31
  56. package/dist/components/typography/textOverflow.css.d.ts.map +1 -1
  57. package/dist/hooks/useModalDialog/useModalDialog.d.ts +5 -0
  58. package/dist/hooks/useModalDialog/useModalDialog.d.ts.map +1 -1
  59. package/dist/hooks/useModalDialog/useModalDialog.js +3 -2
  60. package/dist/hooks/usePreventBodyScroll/usePreventBodyScroll.d.ts +5 -0
  61. package/dist/hooks/usePreventBodyScroll/usePreventBodyScroll.d.ts.map +1 -1
  62. package/dist/hooks/usePreventBodyScroll/usePreventBodyScroll.js +31 -16
  63. package/dist/index.d.ts +6 -0
  64. package/dist/index.d.ts.map +1 -1
  65. package/dist/index.js +12 -0
  66. package/dist/testUtils/browser/contrast.d.ts +6 -2
  67. package/dist/testUtils/browser/contrast.d.ts.map +1 -1
  68. package/dist/testUtils/browser/emulateNoAnchorPositioning.d.ts +8 -0
  69. package/dist/testUtils/browser/emulateNoAnchorPositioning.d.ts.map +1 -0
  70. package/dist/testUtils/browser/render.d.ts +6 -2
  71. package/dist/testUtils/browser/render.d.ts.map +1 -1
  72. package/dist/testUtils/browser/screenshot.d.ts +2 -0
  73. package/dist/testUtils/browser/screenshot.d.ts.map +1 -0
  74. package/dist/testUtils/testTheme.css.d.ts.map +1 -1
  75. package/package.json +2 -2
@@ -11,9 +11,6 @@ const divider = style({
11
11
  justifyContent: "center",
12
12
  clear: "both",
13
13
  minBlockSize: "1px",
14
- ":empty": {
15
- gap: 0
16
- },
17
14
  ":before": {
18
15
  flex: 1,
19
16
  content: '""',
@@ -27,6 +24,9 @@ const divider = style({
27
24
  backgroundColor: dividerColorVar
28
25
  },
29
26
  selectors: {
27
+ "&:empty:after": {
28
+ display: "none"
29
+ },
30
30
  '&[data-alignment="start"]:before': {
31
31
  maxInlineSize: "3rem"
32
32
  },
@@ -13,7 +13,7 @@ export type LabelProps = {
13
13
  required?: boolean;
14
14
  size?: LabelTheme['variants']['size'];
15
15
  cursor?: Atoms['cursor'];
16
- } & HTMLElementProps<HTMLLabelElement>;
16
+ } & Omit<HTMLElementProps<HTMLLabelElement>, 'size'>;
17
17
  export declare const Label: React.FC<LabelProps>;
18
18
  export {};
19
19
  //# sourceMappingURL=Label.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Label.d.ts","sourceRoot":"","sources":["../../../../src/components/form/Label/Label.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,KAAK,EAEV,KAAK,eAAe,EAEpB,KAAK,gBAAgB,EACtB,MAAM,sBAAsB,CAAC;AAI9B,KAAK,UAAU,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;AAE3C,MAAM,MAAM,UAAU,GAAG;IACvB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;IACtC,MAAM,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;CAC1B,GAAG,gBAAgB,CAAC,gBAAgB,CAAC,CAAC;AAEvC,eAAO,MAAM,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,UAAU,CAuBtC,CAAC"}
1
+ {"version":3,"file":"Label.d.ts","sourceRoot":"","sources":["../../../../src/components/form/Label/Label.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,KAAK,EAEV,KAAK,eAAe,EAEpB,KAAK,gBAAgB,EACtB,MAAM,sBAAsB,CAAC;AAI9B,KAAK,UAAU,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;AAE3C,MAAM,MAAM,UAAU,GAAG;IACvB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;IACtC,MAAM,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;CAC1B,GAAG,IAAI,CAAC,gBAAgB,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC,CAAC;AAErD,eAAO,MAAM,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,UAAU,CAuBtC,CAAC"}
@@ -21,7 +21,7 @@ const icon = style({
21
21
  "@layer": {
22
22
  [layers.molecule]: {
23
23
  position: "absolute",
24
- right: 0,
24
+ insetInlineEnd: 0,
25
25
  top: 0,
26
26
  bottom: 0,
27
27
  pointerEvents: "none",
@@ -0,0 +1,21 @@
1
+ import { HTMLElementProps } from '@blockle/blocks-core';
2
+ export type TabProps = {
3
+ /** In a `TabNav`: render the child element (a router link) as the tab's link */
4
+ asChild?: boolean;
5
+ children?: React.ReactNode;
6
+ /** In a `TabNav`: this tab is the current page. Sets `aria-current="page"` */
7
+ current?: boolean;
8
+ /** Content after the tab, such as a close `IconButton`; never inside the tab itself */
9
+ endSlot?: React.ReactNode;
10
+ ref?: React.Ref<HTMLAnchorElement & HTMLButtonElement>;
11
+ /** Content before the tab, such as a status dot or an Icon */
12
+ startSlot?: React.ReactNode;
13
+ /** In `Tabs`: matches the `value` of the TabPanel this tab shows. Required there. */
14
+ value?: string;
15
+ } & Omit<HTMLElementProps<HTMLElement>, 'children' | 'ref' | 'type' | 'value'>;
16
+ /**
17
+ * Inside `Tabs` a `button` with `role="tab"`; inside `TabNav` a link (`a`, or
18
+ * any element through `asChild`) that is `aria-current="page"` when `current`.
19
+ */
20
+ export declare const Tab: React.FC<TabProps>;
21
+ //# sourceMappingURL=Tab.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Tab.d.ts","sourceRoot":"","sources":["../../../../src/components/navigation/Tabs/Tab.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAc,KAAK,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AASzE,MAAM,MAAM,QAAQ,GAAG;IACrB,gFAAgF;IAChF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,8EAA8E;IAC9E,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,uFAAuF;IACvF,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,iBAAiB,GAAG,iBAAiB,CAAC,CAAC;IACvD,8DAA8D;IAC9D,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC5B,qFAAqF;IACrF,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,IAAI,CAAC,gBAAgB,CAAC,WAAW,CAAC,EAAE,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;AAgK/E;;;GAGG;AACH,eAAO,MAAM,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC,QAAQ,CAIlC,CAAC"}
@@ -0,0 +1,138 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { classnames } from "@blockle/blocks-core";
4
+ import { createSlottable } from "@blockle/blocks-react-slot";
5
+ import { useContext, useRef, useEffect } from "react";
6
+ import { useComponentStyles } from "../../../hooks/useComponentStyles/useComponentStyles.js";
7
+ import { TabListContext } from "./TabListContext.js";
8
+ import { useTabsContext, getPanelId, getTabId } from "./TabsContext.js";
9
+ import { trigger, slot, tab } from "./tabs.css.js";
10
+ function hasContent(node) {
11
+ return node !== null && node !== void 0 && node !== false;
12
+ }
13
+ function revealInline(tab2, list) {
14
+ const tabBox = tab2.getBoundingClientRect();
15
+ const listBox = list.getBoundingClientRect();
16
+ if (tabBox.left < listBox.left) {
17
+ list.scrollLeft -= listBox.left - tabBox.left;
18
+ } else if (tabBox.right > listBox.right) {
19
+ list.scrollLeft += tabBox.right - listBox.right;
20
+ }
21
+ }
22
+ const TabFrame = ({
23
+ active,
24
+ as: Wrapper,
25
+ children,
26
+ endSlot,
27
+ scrollRef,
28
+ startSlot
29
+ }) => {
30
+ const wrapperRef = useRef(null);
31
+ const tabClassName = useComponentStyles("tabs", { tab: true });
32
+ const startSlotClassName = useComponentStyles(
33
+ "tabs",
34
+ { startSlot: true },
35
+ false
36
+ );
37
+ const endSlotClassName = useComponentStyles("tabs", { endSlot: true }, false);
38
+ useEffect(() => {
39
+ if (active && wrapperRef.current && scrollRef?.current) {
40
+ revealInline(wrapperRef.current, scrollRef.current);
41
+ }
42
+ }, [active, scrollRef]);
43
+ return /* @__PURE__ */ jsxs(Wrapper, { ref: wrapperRef, className: classnames(tab, tabClassName), children: [
44
+ hasContent(startSlot) && /* @__PURE__ */ jsx("span", { className: classnames(slot, startSlotClassName), children: startSlot }),
45
+ children,
46
+ hasContent(endSlot) && /* @__PURE__ */ jsx("span", { className: classnames(slot, endSlotClassName), children: endSlot })
47
+ ] });
48
+ };
49
+ const [LinkTemplate, LinkSlot] = createSlottable("a");
50
+ const TabsTab = ({
51
+ asChild: _asChild,
52
+ children,
53
+ className,
54
+ current: _current,
55
+ endSlot,
56
+ onClick,
57
+ startSlot,
58
+ value,
59
+ ...restProps
60
+ }) => {
61
+ const { baseId, setValue, value: selectedValue } = useTabsContext("Tab");
62
+ const list = useContext(TabListContext);
63
+ const triggerClassName = useComponentStyles("tabs", { trigger: true });
64
+ if (value === void 0) {
65
+ throw new Error("Tab needs a value inside Tabs");
66
+ }
67
+ const selected = selectedValue === value;
68
+ return /* @__PURE__ */ jsx(
69
+ TabFrame,
70
+ {
71
+ as: "div",
72
+ active: selected,
73
+ scrollRef: list?.scrollRef,
74
+ startSlot,
75
+ endSlot,
76
+ children: /* @__PURE__ */ jsx(
77
+ "button",
78
+ {
79
+ ...restProps,
80
+ type: "button",
81
+ role: "tab",
82
+ id: getTabId(baseId, value),
83
+ "aria-selected": selected,
84
+ "aria-controls": getPanelId(baseId, value),
85
+ tabIndex: selected || list?.fallbackValue === value ? 0 : -1,
86
+ className: classnames(trigger, triggerClassName, className),
87
+ onClick: (event) => {
88
+ onClick?.(event);
89
+ if (!event.defaultPrevented) {
90
+ setValue(value);
91
+ }
92
+ },
93
+ children
94
+ }
95
+ )
96
+ }
97
+ );
98
+ };
99
+ const TabNavTab = ({
100
+ asChild,
101
+ children,
102
+ className,
103
+ current,
104
+ endSlot,
105
+ startSlot,
106
+ value: _value,
107
+ ...restProps
108
+ }) => {
109
+ const list = useContext(TabListContext);
110
+ const triggerClassName = useComponentStyles("tabs", { trigger: true });
111
+ return /* @__PURE__ */ jsx(
112
+ TabFrame,
113
+ {
114
+ as: "li",
115
+ active: Boolean(current),
116
+ scrollRef: list?.scrollRef,
117
+ startSlot,
118
+ endSlot,
119
+ children: /* @__PURE__ */ jsx(
120
+ LinkTemplate,
121
+ {
122
+ ...restProps,
123
+ asChild,
124
+ "aria-current": current ? "page" : void 0,
125
+ className: classnames(trigger, triggerClassName, className),
126
+ children: /* @__PURE__ */ jsx(LinkSlot, { children })
127
+ }
128
+ )
129
+ }
130
+ );
131
+ };
132
+ const Tab = (props) => {
133
+ const inNav = useContext(TabListContext)?.nav ?? false;
134
+ return inNav ? /* @__PURE__ */ jsx(TabNavTab, { ...props }) : /* @__PURE__ */ jsx(TabsTab, { ...props });
135
+ };
136
+ export {
137
+ Tab
138
+ };
@@ -0,0 +1,6 @@
1
+ /**
2
+ * The Tab indicator: one decorative bar per list, positioned by the base styles
3
+ * against the selected tab and styled by the theme. Shared by `TabList` and `TabNav`.
4
+ */
5
+ export declare const TabIndicator: React.FC;
6
+ //# sourceMappingURL=TabIndicator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TabIndicator.d.ts","sourceRoot":"","sources":["../../../../src/components/navigation/Tabs/TabIndicator.tsx"],"names":[],"mappings":"AAOA;;;GAGG;AACH,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAUhC,CAAC"}
@@ -0,0 +1,19 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { classnames } from "@blockle/blocks-core";
4
+ import { useComponentStyles } from "../../../hooks/useComponentStyles/useComponentStyles.js";
5
+ import { indicator } from "./tabs.css.js";
6
+ const TabIndicator = () => {
7
+ const className = useComponentStyles("tabs", { indicator: true });
8
+ return /* @__PURE__ */ jsx(
9
+ "span",
10
+ {
11
+ "aria-hidden": "true",
12
+ "data-tab-indicator": "",
13
+ className: classnames(indicator, className)
14
+ }
15
+ );
16
+ };
17
+ export {
18
+ TabIndicator
19
+ };
@@ -0,0 +1,10 @@
1
+ import { HTMLElementProps } from '@blockle/blocks-core';
2
+ export type TabListProps = {
3
+ /** Names the tab list; use it or `aria-labelledby` when a page has several */
4
+ 'aria-label'?: string;
5
+ 'aria-labelledby'?: string;
6
+ children?: React.ReactNode;
7
+ ref?: React.Ref<HTMLDivElement>;
8
+ } & Omit<HTMLElementProps<HTMLDivElement>, 'children' | 'ref'>;
9
+ export declare const TabList: React.FC<TabListProps>;
10
+ //# sourceMappingURL=TabList.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TabList.d.ts","sourceRoot":"","sources":["../../../../src/components/navigation/Tabs/TabList.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAc,KAAK,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AASzE,MAAM,MAAM,YAAY,GAAG;IACzB,8EAA8E;IAC9E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;CACjC,GAAG,IAAI,CAAC,gBAAgB,CAAC,cAAc,CAAC,EAAE,UAAU,GAAG,KAAK,CAAC,CAAC;AAE/D,eAAO,MAAM,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,YAAY,CAuG1C,CAAC"}
@@ -0,0 +1,101 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { classnames } from "@blockle/blocks-core";
4
+ import { useRef, useState, useLayoutEffect, useMemo } from "react";
5
+ import { useComponentStyles } from "../../../hooks/useComponentStyles/useComponentStyles.js";
6
+ import { TabIndicator } from "./TabIndicator.js";
7
+ import { TabListContext } from "./TabListContext.js";
8
+ import { useTabsContext, getTabValue } from "./TabsContext.js";
9
+ import { list } from "./tabs.css.js";
10
+ const TabList = ({
11
+ children,
12
+ className,
13
+ onKeyDown,
14
+ ref,
15
+ ...restProps
16
+ }) => {
17
+ const { baseId, setValue } = useTabsContext("TabList");
18
+ const listRef = useRef(null);
19
+ const listClassName = useComponentStyles("tabs", { list: true });
20
+ const [fallbackValue, setFallbackValue] = useState();
21
+ useLayoutEffect(() => {
22
+ const tabs = Array.from(
23
+ listRef.current?.querySelectorAll('[role="tab"]') ?? []
24
+ );
25
+ const hasSelected = tabs.some(
26
+ (tab) => tab.getAttribute("aria-selected") === "true"
27
+ );
28
+ const first = tabs[0];
29
+ setFallbackValue(
30
+ hasSelected || !first ? void 0 : getTabValue(baseId, first.id)
31
+ );
32
+ });
33
+ const context = useMemo(
34
+ () => ({ fallbackValue, nav: false, scrollRef: listRef }),
35
+ [fallbackValue]
36
+ );
37
+ return /* @__PURE__ */ jsx(TabListContext.Provider, { value: context, children: /* @__PURE__ */ jsxs(
38
+ "div",
39
+ {
40
+ ...restProps,
41
+ role: "tablist",
42
+ ref: (node) => {
43
+ listRef.current = node;
44
+ if (typeof ref === "function") {
45
+ ref(node);
46
+ } else if (ref) {
47
+ ref.current = node;
48
+ }
49
+ },
50
+ className: classnames(list, listClassName, className),
51
+ onKeyDown: (event) => {
52
+ onKeyDown?.(event);
53
+ if (event.defaultPrevented || event.altKey || event.ctrlKey || event.metaKey || !listRef.current) {
54
+ return;
55
+ }
56
+ const tabs = Array.from(
57
+ listRef.current.querySelectorAll('[role="tab"]')
58
+ );
59
+ const index = tabs.indexOf(event.target);
60
+ if (index === -1) {
61
+ return;
62
+ }
63
+ const nextIndex = getNextIndex(event.key, index, tabs.length);
64
+ if (nextIndex === void 0) {
65
+ return;
66
+ }
67
+ event.preventDefault();
68
+ const next = tabs[nextIndex];
69
+ if (!next) {
70
+ return;
71
+ }
72
+ const nextValue = getTabValue(baseId, next.id);
73
+ next.focus();
74
+ if (nextValue !== void 0) {
75
+ setValue(nextValue);
76
+ }
77
+ },
78
+ children: [
79
+ children,
80
+ /* @__PURE__ */ jsx(TabIndicator, {})
81
+ ]
82
+ }
83
+ ) });
84
+ };
85
+ function getNextIndex(key, index, count) {
86
+ switch (key) {
87
+ case "ArrowRight":
88
+ return (index + 1) % count;
89
+ case "ArrowLeft":
90
+ return (index - 1 + count) % count;
91
+ case "Home":
92
+ return 0;
93
+ case "End":
94
+ return count - 1;
95
+ default:
96
+ return void 0;
97
+ }
98
+ }
99
+ export {
100
+ TabList
101
+ };
@@ -0,0 +1,13 @@
1
+ export type TabListContextValue = {
2
+ /**
3
+ * The value of the tab that takes the tab stop when no tab is selected, so
4
+ * the list stays reachable by keyboard. Undefined in a `TabNav`.
5
+ */
6
+ fallbackValue: string | undefined;
7
+ /** True inside a `TabNav`, so a Tab renders a link */
8
+ nav: boolean;
9
+ /** The element that scrolls sideways when the tabs overflow */
10
+ scrollRef: React.RefObject<HTMLElement | null>;
11
+ };
12
+ export declare const TabListContext: import('react').Context<TabListContextValue | null>;
13
+ //# sourceMappingURL=TabListContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TabListContext.d.ts","sourceRoot":"","sources":["../../../../src/components/navigation/Tabs/TabListContext.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,mBAAmB,GAAG;IAChC;;;OAGG;IACH,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,sDAAsD;IACtD,GAAG,EAAE,OAAO,CAAC;IACb,+DAA+D;IAC/D,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;CAChD,CAAC;AAEF,eAAO,MAAM,cAAc,qDAAkD,CAAC"}
@@ -0,0 +1,6 @@
1
+ "use client";
2
+ import { createContext } from "react";
3
+ const TabListContext = createContext(null);
4
+ export {
5
+ TabListContext
6
+ };
@@ -0,0 +1,15 @@
1
+ import { HTMLElementProps } from '@blockle/blocks-core';
2
+ export type TabNavProps = {
3
+ /** Names the navigation; use it or `aria-labelledby` when a page has several */
4
+ 'aria-label'?: string;
5
+ 'aria-labelledby'?: string;
6
+ /** `Tab`s, each a link; mark the current page's with `current` */
7
+ children?: React.ReactNode;
8
+ ref?: React.Ref<HTMLElement>;
9
+ } & Omit<HTMLElementProps<HTMLElement>, 'children' | 'ref'>;
10
+ /**
11
+ * Route tabs: a `nav` around a list of links that looks like `Tabs`. It has no
12
+ * tab roles or arrow-key handling; the links are plain links in the tab order.
13
+ */
14
+ export declare const TabNav: React.FC<TabNavProps>;
15
+ //# sourceMappingURL=TabNav.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TabNav.d.ts","sourceRoot":"","sources":["../../../../src/components/navigation/Tabs/TabNav.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAc,KAAK,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAQzE,MAAM,MAAM,WAAW,GAAG;IACxB,gFAAgF;IAChF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kEAAkE;IAClE,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;CAC9B,GAAG,IAAI,CAAC,gBAAgB,CAAC,WAAW,CAAC,EAAE,UAAU,GAAG,KAAK,CAAC,CAAC;AAE5D;;;GAGG;AACH,eAAO,MAAM,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CAqCxC,CAAC"}
@@ -0,0 +1,44 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { classnames } from "@blockle/blocks-core";
4
+ import { useRef, useMemo } from "react";
5
+ import { useComponentStyles } from "../../../hooks/useComponentStyles/useComponentStyles.js";
6
+ import { TabIndicator } from "./TabIndicator.js";
7
+ import { TabListContext } from "./TabListContext.js";
8
+ import { navList, list } from "./tabs.css.js";
9
+ const TabNav = ({
10
+ children,
11
+ className,
12
+ ref,
13
+ ...restProps
14
+ }) => {
15
+ const navRef = useRef(null);
16
+ const listClassName = useComponentStyles("tabs", { list: true });
17
+ const navListClassName = useComponentStyles("tabs", { navList: true });
18
+ const context = useMemo(
19
+ () => ({ fallbackValue: void 0, nav: true, scrollRef: navRef }),
20
+ []
21
+ );
22
+ return /* @__PURE__ */ jsx(TabListContext.Provider, { value: context, children: /* @__PURE__ */ jsxs(
23
+ "nav",
24
+ {
25
+ ref: (node) => {
26
+ navRef.current = node;
27
+ if (typeof ref === "function") {
28
+ ref(node);
29
+ } else if (ref) {
30
+ ref.current = node;
31
+ }
32
+ },
33
+ className: classnames(list, listClassName, className),
34
+ ...restProps,
35
+ children: [
36
+ /* @__PURE__ */ jsx("ul", { className: classnames(navList, navListClassName), children }),
37
+ /* @__PURE__ */ jsx(TabIndicator, {})
38
+ ]
39
+ }
40
+ ) });
41
+ };
42
+ export {
43
+ TabNav
44
+ };
@@ -0,0 +1,14 @@
1
+ import { HTMLElementProps } from '@blockle/blocks-core';
2
+ export type TabPanelProps = {
3
+ children?: React.ReactNode;
4
+ ref?: React.Ref<HTMLDivElement>;
5
+ /** Matches the `value` of the Tab that shows this panel */
6
+ value: string;
7
+ } & Omit<HTMLElementProps<HTMLDivElement>, 'children' | 'ref' | 'value'>;
8
+ /**
9
+ * Stays mounted while inactive, hidden with the `hidden` attribute, so its
10
+ * state (such as a typed draft) survives switching tabs. Render its children
11
+ * conditionally to mount them only while selected.
12
+ */
13
+ export declare const TabPanel: React.FC<TabPanelProps>;
14
+ //# sourceMappingURL=TabPanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TabPanel.d.ts","sourceRoot":"","sources":["../../../../src/components/navigation/Tabs/TabPanel.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAc,KAAK,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAKzE,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC,2DAA2D;IAC3D,KAAK,EAAE,MAAM,CAAC;CACf,GAAG,IAAI,CAAC,gBAAgB,CAAC,cAAc,CAAC,EAAE,UAAU,GAAG,KAAK,GAAG,OAAO,CAAC,CAAC;AAEzE;;;;GAIG;AACH,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CAuB5C,CAAC"}
@@ -0,0 +1,31 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { classnames } from "@blockle/blocks-core";
4
+ import { useComponentStyles } from "../../../hooks/useComponentStyles/useComponentStyles.js";
5
+ import { useTabsContext, getTabId, getPanelId } from "./TabsContext.js";
6
+ const TabPanel = ({
7
+ children,
8
+ className,
9
+ value,
10
+ ...restProps
11
+ }) => {
12
+ const { baseId, value: selectedValue } = useTabsContext("TabPanel");
13
+ const selected = selectedValue === value;
14
+ const panelClassName = useComponentStyles("tabs", { panel: true });
15
+ return /* @__PURE__ */ jsx(
16
+ "div",
17
+ {
18
+ role: "tabpanel",
19
+ id: getPanelId(baseId, value),
20
+ "aria-labelledby": getTabId(baseId, value),
21
+ hidden: !selected,
22
+ tabIndex: selected ? 0 : void 0,
23
+ className: classnames(panelClassName, className),
24
+ ...restProps,
25
+ children
26
+ }
27
+ );
28
+ };
29
+ export {
30
+ TabPanel
31
+ };
@@ -0,0 +1,13 @@
1
+ import { HTMLElementProps } from '@blockle/blocks-core';
2
+ export type TabsProps = {
3
+ children?: React.ReactNode;
4
+ /** The initially selected tab when the selection is uncontrolled */
5
+ defaultValue?: string;
6
+ /** Called with the value of the tab that is selected */
7
+ onValueChange?: (value: string) => void;
8
+ ref?: React.Ref<HTMLDivElement>;
9
+ /** The selected tab, for a controlled selection */
10
+ value?: string;
11
+ } & Omit<HTMLElementProps<HTMLDivElement>, 'children' | 'defaultValue' | 'ref' | 'value'>;
12
+ export declare const Tabs: React.FC<TabsProps>;
13
+ //# sourceMappingURL=Tabs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Tabs.d.ts","sourceRoot":"","sources":["../../../../src/components/navigation/Tabs/Tabs.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAK7D,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,oEAAoE;IACpE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wDAAwD;IACxD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,IAAI,CACN,gBAAgB,CAAC,cAAc,CAAC,EAChC,UAAU,GAAG,cAAc,GAAG,KAAK,GAAG,OAAO,CAC9C,CAAC;AAEF,eAAO,MAAM,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,SAAS,CAiCpC,CAAC"}
@@ -0,0 +1,33 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { useId, useState, useCallback, useMemo } from "react";
4
+ import { TabsContext } from "./TabsContext.js";
5
+ const Tabs = ({
6
+ children,
7
+ defaultValue,
8
+ onValueChange,
9
+ value: controlledValue,
10
+ ...restProps
11
+ }) => {
12
+ const baseId = useId();
13
+ const [internalValue, setInternalValue] = useState(defaultValue);
14
+ const isControlled = controlledValue !== void 0;
15
+ const value = isControlled ? controlledValue : internalValue;
16
+ const setValue = useCallback(
17
+ (nextValue) => {
18
+ if (!isControlled) {
19
+ setInternalValue(nextValue);
20
+ }
21
+ onValueChange?.(nextValue);
22
+ },
23
+ [isControlled, onValueChange]
24
+ );
25
+ const context = useMemo(
26
+ () => ({ value, setValue, baseId }),
27
+ [value, setValue, baseId]
28
+ );
29
+ return /* @__PURE__ */ jsx(TabsContext.Provider, { value: context, children: /* @__PURE__ */ jsx("div", { ...restProps, children }) });
30
+ };
31
+ export {
32
+ Tabs
33
+ };
@@ -0,0 +1,13 @@
1
+ export type TabsContextValue = {
2
+ /** The selected tab's value, or undefined when nothing is selected */
3
+ value: string | undefined;
4
+ setValue: (value: string) => void;
5
+ /** Prefix for the ids generated from each Tab's and TabPanel's value */
6
+ baseId: string;
7
+ };
8
+ export declare const TabsContext: import('react').Context<TabsContextValue | null>;
9
+ export declare function useTabsContext(part: string): TabsContextValue;
10
+ export declare function getTabId(baseId: string, value: string): string;
11
+ export declare function getTabValue(baseId: string, id: string): string | undefined;
12
+ export declare function getPanelId(baseId: string, value: string): string;
13
+ //# sourceMappingURL=TabsContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TabsContext.d.ts","sourceRoot":"","sources":["../../../../src/components/navigation/Tabs/TabsContext.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,sEAAsE;IACtE,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,wEAAwE;IACxE,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,eAAO,MAAM,WAAW,kDAA+C,CAAC;AAExE,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAQ7D;AAGD,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,UAErD;AAGD,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,sBAMrD;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,UAEvD"}
@@ -0,0 +1,27 @@
1
+ "use client";
2
+ import { useContext, createContext } from "react";
3
+ const TabsContext = createContext(null);
4
+ function useTabsContext(part) {
5
+ const context = useContext(TabsContext);
6
+ if (!context) {
7
+ throw new Error(`${part} must be rendered inside Tabs`);
8
+ }
9
+ return context;
10
+ }
11
+ function getTabId(baseId, value) {
12
+ return `${baseId}-tab-${encodeURIComponent(value)}`;
13
+ }
14
+ function getTabValue(baseId, id) {
15
+ const prefix = `${baseId}-tab-`;
16
+ return id.startsWith(prefix) ? decodeURIComponent(id.slice(prefix.length)) : void 0;
17
+ }
18
+ function getPanelId(baseId, value) {
19
+ return `${baseId}-panel-${encodeURIComponent(value)}`;
20
+ }
21
+ export {
22
+ TabsContext,
23
+ getPanelId,
24
+ getTabId,
25
+ getTabValue,
26
+ useTabsContext
27
+ };
@@ -0,0 +1,7 @@
1
+ export declare const list: string;
2
+ export declare const navList: string;
3
+ export declare const indicator: string;
4
+ export declare const tab: string;
5
+ export declare const trigger: string;
6
+ export declare const slot: string;
7
+ //# sourceMappingURL=tabs.css.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tabs.css.d.ts","sourceRoot":"","sources":["../../../../src/components/navigation/Tabs/tabs.css.ts"],"names":[],"mappings":"AA4BA,eAAO,MAAM,IAAI,QAgBf,CAAC;AAIH,eAAO,MAAM,OAAO,QAUlB,CAAC;AAMH,eAAO,MAAM,SAAS,QAiCpB,CAAC;AAEH,eAAO,MAAM,GAAG,QA2Bd,CAAC;AAQH,eAAO,MAAM,OAAO,QAMlB,CAAC;AAIH,eAAO,MAAM,IAAI,QAAY,CAAC"}