@mshafiqyajid/react-tabs 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/styled.cjs CHANGED
@@ -15,7 +15,14 @@ function useStableId() {
15
15
  return ref.current;
16
16
  }
17
17
  function useTabs(opts = {}) {
18
- const { tabs = [], value: controlledValue, defaultValue, onChange } = opts;
18
+ const {
19
+ tabs = [],
20
+ value: controlledValue,
21
+ defaultValue,
22
+ onChange,
23
+ activation = "automatic",
24
+ orientation = "horizontal"
25
+ } = opts;
19
26
  const listId = useStableId();
20
27
  const isControlled = controlledValue !== void 0;
21
28
  const [internalValue, setInternalValue] = react.useState(
@@ -23,19 +30,21 @@ function useTabs(opts = {}) {
23
30
  );
24
31
  const activeValue = isControlled ? controlledValue : internalValue;
25
32
  const tabRefs = react.useRef(/* @__PURE__ */ new Map());
33
+ const onChangeRef = react.useRef(onChange);
34
+ onChangeRef.current = onChange;
26
35
  const setActiveValue = react.useCallback(
27
- (next) => {
36
+ (next, reason = "programmatic") => {
28
37
  const tab = tabs.find((t) => t.value === next);
29
38
  if (tab?.disabled) return;
30
39
  if (isControlled) {
31
- if (next !== controlledValue) onChange?.(next);
40
+ if (next !== controlledValue) onChangeRef.current?.(next, reason);
32
41
  } else {
33
42
  if (next === internalValue) return;
34
43
  setInternalValue(next);
35
- onChange?.(next);
44
+ onChangeRef.current?.(next, reason);
36
45
  }
37
46
  },
38
- [tabs, isControlled, controlledValue, internalValue, onChange]
47
+ [tabs, isControlled, controlledValue, internalValue]
39
48
  );
40
49
  const focusTab = react.useCallback((value) => {
41
50
  tabRefs.current.get(value)?.focus();
@@ -45,37 +54,34 @@ function useTabs(opts = {}) {
45
54
  const enabled = tabs.filter((t) => !t.disabled);
46
55
  if (enabled.length === 0) return;
47
56
  const currentIndex = enabled.findIndex((t) => t.value === currentValue);
57
+ const isForward = orientation === "vertical" ? event.key === "ArrowDown" : event.key === "ArrowRight";
58
+ const isBackward = orientation === "vertical" ? event.key === "ArrowUp" : event.key === "ArrowLeft";
48
59
  let nextValue;
49
- switch (event.key) {
50
- case "ArrowRight":
51
- case "ArrowDown": {
52
- const nextIndex = (currentIndex + 1) % enabled.length;
53
- nextValue = enabled[nextIndex]?.value;
54
- break;
55
- }
56
- case "ArrowLeft":
57
- case "ArrowUp": {
58
- const prevIndex = (currentIndex - 1 + enabled.length) % enabled.length;
59
- nextValue = enabled[prevIndex]?.value;
60
- break;
61
- }
62
- case "Home": {
63
- nextValue = enabled[0]?.value;
64
- break;
65
- }
66
- case "End": {
67
- nextValue = enabled[enabled.length - 1]?.value;
68
- break;
69
- }
70
- default:
71
- return;
60
+ if (isForward) {
61
+ const nextIndex = (currentIndex + 1) % enabled.length;
62
+ nextValue = enabled[nextIndex]?.value;
63
+ } else if (isBackward) {
64
+ const prevIndex = (currentIndex - 1 + enabled.length) % enabled.length;
65
+ nextValue = enabled[prevIndex]?.value;
66
+ } else if (event.key === "Home") {
67
+ nextValue = enabled[0]?.value;
68
+ } else if (event.key === "End") {
69
+ nextValue = enabled[enabled.length - 1]?.value;
70
+ } else if (activation === "manual" && (event.key === "Enter" || event.key === " ")) {
71
+ event.preventDefault();
72
+ setActiveValue(currentValue, "keyboard");
73
+ return;
74
+ } else {
75
+ return;
72
76
  }
73
77
  if (nextValue === void 0 || nextValue === currentValue) return;
74
78
  event.preventDefault();
75
- setActiveValue(nextValue);
76
79
  focusTab(nextValue);
80
+ if (activation === "automatic") {
81
+ setActiveValue(nextValue, "keyboard");
82
+ }
77
83
  },
78
- [tabs, setActiveValue, focusTab]
84
+ [tabs, orientation, activation, setActiveValue, focusTab]
79
85
  );
80
86
  const getTabProps = react.useCallback(
81
87
  (value, options) => {
@@ -87,6 +93,7 @@ function useTabs(opts = {}) {
87
93
  "aria-selected": isSelected,
88
94
  "aria-controls": panelId(listId, value),
89
95
  "aria-disabled": isDisabled || void 0,
96
+ "data-state": isSelected ? "active" : "inactive",
90
97
  tabIndex: isSelected ? 0 : -1,
91
98
  disabled: isDisabled,
92
99
  ref: (node) => {
@@ -97,7 +104,7 @@ function useTabs(opts = {}) {
97
104
  }
98
105
  },
99
106
  onClick: () => {
100
- if (!isDisabled) setActiveValue(value);
107
+ if (!isDisabled) setActiveValue(value, "click");
101
108
  },
102
109
  onKeyDown: handleKeyDown(value)
103
110
  };
@@ -106,11 +113,13 @@ function useTabs(opts = {}) {
106
113
  );
107
114
  const getPanelProps = react.useCallback(
108
115
  (value) => {
116
+ const isActive = activeValue === value;
109
117
  return {
110
118
  id: panelId(listId, value),
111
119
  role: "tabpanel",
112
120
  "aria-labelledby": tabId(listId, value),
113
- hidden: activeValue !== value,
121
+ "data-state": isActive ? "active" : "inactive",
122
+ hidden: !isActive,
114
123
  tabIndex: 0
115
124
  };
116
125
  },
@@ -122,7 +131,7 @@ function useTabs(opts = {}) {
122
131
  );
123
132
  }
124
133
  var useIsoLayoutEffect = typeof window !== "undefined" ? react.useLayoutEffect : react.useEffect;
125
- function useIndicator(tabListRef, activeValue) {
134
+ function useIndicator(tabListRef, activeValue, orientation) {
126
135
  const [style, setStyle] = react.useState({});
127
136
  useIsoLayoutEffect(() => {
128
137
  if (!tabListRef.current || activeValue === void 0) return;
@@ -135,20 +144,30 @@ function useIndicator(tabListRef, activeValue) {
135
144
  if (!activeTab) return;
136
145
  const listRect = list.getBoundingClientRect();
137
146
  const tabRect = activeTab.getBoundingClientRect();
138
- const x = tabRect.left - listRect.left;
139
- const w = tabRect.width;
140
- setStyle({
141
- ["--rtab-indicator-x"]: `${x}px`,
142
- ["--rtab-indicator-width"]: `${w}px`,
143
- ["--rtab-indicator-ready"]: "1"
144
- });
147
+ if (orientation === "vertical") {
148
+ const y = tabRect.top - listRect.top;
149
+ const h = tabRect.height;
150
+ setStyle({
151
+ ["--rtab-indicator-y"]: `${y}px`,
152
+ ["--rtab-indicator-height"]: `${h}px`,
153
+ ["--rtab-indicator-ready"]: "1"
154
+ });
155
+ } else {
156
+ const x = tabRect.left - listRect.left;
157
+ const w = tabRect.width;
158
+ setStyle({
159
+ ["--rtab-indicator-x"]: `${x}px`,
160
+ ["--rtab-indicator-width"]: `${w}px`,
161
+ ["--rtab-indicator-ready"]: "1"
162
+ });
163
+ }
145
164
  };
146
165
  measure();
147
166
  if (typeof ResizeObserver === "undefined") return;
148
167
  const ro = new ResizeObserver(measure);
149
168
  ro.observe(tabListRef.current);
150
169
  return () => ro.disconnect();
151
- }, [activeValue, tabListRef]);
170
+ }, [activeValue, tabListRef, orientation]);
152
171
  return style;
153
172
  }
154
173
  var TabsStyled = react.forwardRef(
@@ -160,54 +179,221 @@ var TabsStyled = react.forwardRef(
160
179
  defaultValue,
161
180
  value,
162
181
  onChange,
182
+ activation = "automatic",
183
+ orientation = "horizontal",
184
+ lazyMount = false,
185
+ forceMount = false,
186
+ onTabClose,
187
+ scrollable = false,
188
+ sortable = false,
189
+ onReorder,
190
+ scrollActiveIntoView,
191
+ renderTab,
192
+ renderPanel,
163
193
  className
164
194
  }, ref) {
195
+ const autoScrollActive = scrollActiveIntoView ?? scrollable;
196
+ const [scrollState, setScrollState] = react.useState({
197
+ left: false,
198
+ right: false
199
+ });
200
+ const typeaheadBufferRef = react.useRef("");
201
+ const typeaheadTimerRef = react.useRef(null);
202
+ const dragValueRef = react.useRef(null);
165
203
  const tabDefs = tabs.map((t) => ({ value: t.value, disabled: t.disabled }));
166
204
  const resolvedDefault = defaultValue ?? tabs.find((t) => !t.disabled)?.value;
167
205
  const { activeValue, getTabProps, getPanelProps } = useTabs({
168
206
  tabs: tabDefs,
169
207
  defaultValue: value === void 0 ? resolvedDefault : void 0,
170
208
  value,
171
- onChange
209
+ onChange,
210
+ activation,
211
+ orientation
172
212
  });
173
213
  const tabListRef = react.useRef(null);
174
- const indicatorStyle = useIndicator(tabListRef, activeValue);
214
+ const indicatorStyle = useIndicator(tabListRef, activeValue, orientation);
215
+ const activatedRef = react.useRef(/* @__PURE__ */ new Set());
216
+ if (activeValue !== void 0) activatedRef.current.add(activeValue);
175
217
  const rootClass = ["rtab-root", className].filter(Boolean).join(" ");
176
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: rootClass, children: [
177
- /* @__PURE__ */ jsxRuntime.jsxs(
178
- "div",
179
- {
180
- ref: tabListRef,
181
- role: "tablist",
182
- className: "rtab-list",
183
- "data-variant": variant,
184
- "data-size": size,
185
- "data-tone": tone,
186
- style: indicatorStyle,
187
- children: [
188
- tabs.map((tab) => /* @__PURE__ */ jsxRuntime.jsx(
218
+ react.useEffect(() => {
219
+ if (!scrollable) return;
220
+ const list = tabListRef.current;
221
+ if (!list) return;
222
+ const update = () => {
223
+ setScrollState({
224
+ left: list.scrollLeft > 4,
225
+ right: list.scrollLeft + list.clientWidth < list.scrollWidth - 4
226
+ });
227
+ };
228
+ update();
229
+ list.addEventListener("scroll", update, { passive: true });
230
+ const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(update) : null;
231
+ ro?.observe(list);
232
+ return () => {
233
+ list.removeEventListener("scroll", update);
234
+ ro?.disconnect();
235
+ };
236
+ }, [scrollable, tabs.length]);
237
+ react.useEffect(() => {
238
+ if (!autoScrollActive || !activeValue) return;
239
+ const list = tabListRef.current;
240
+ if (!list) return;
241
+ const activeEl = list.querySelector(`[aria-selected="true"]`);
242
+ if (!activeEl) return;
243
+ activeEl.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "nearest" });
244
+ }, [autoScrollActive, activeValue]);
245
+ const scrollByAmount = (delta) => {
246
+ tabListRef.current?.scrollBy({ left: delta, behavior: "smooth" });
247
+ };
248
+ const handleTypeahead = (e) => {
249
+ if (e.key.length !== 1 || e.altKey || e.ctrlKey || e.metaKey) return;
250
+ typeaheadBufferRef.current = (typeaheadBufferRef.current + e.key).toLowerCase();
251
+ if (typeaheadTimerRef.current) clearTimeout(typeaheadTimerRef.current);
252
+ typeaheadTimerRef.current = setTimeout(() => {
253
+ typeaheadBufferRef.current = "";
254
+ }, 600);
255
+ const buffer = typeaheadBufferRef.current;
256
+ const startIdx = Math.max(0, tabs.findIndex((t) => t.value === activeValue));
257
+ for (let i = 1; i <= tabs.length; i++) {
258
+ const idx = (startIdx + i) % tabs.length;
259
+ const tab = tabs[idx];
260
+ if (!tab || tab.disabled) continue;
261
+ const labelStr = typeof tab.label === "string" ? tab.label : "";
262
+ if (labelStr.toLowerCase().startsWith(buffer)) {
263
+ const list = tabListRef.current;
264
+ const btn = list?.querySelector(`[data-value="${tab.value}"]`);
265
+ btn?.click();
266
+ btn?.focus();
267
+ break;
268
+ }
269
+ }
270
+ };
271
+ const handleDragStart = (val) => (e) => {
272
+ if (!sortable) return;
273
+ dragValueRef.current = val;
274
+ e.dataTransfer.effectAllowed = "move";
275
+ };
276
+ const handleDragOver = (val) => (e) => {
277
+ if (!sortable || !dragValueRef.current || dragValueRef.current === val) return;
278
+ e.preventDefault();
279
+ e.dataTransfer.dropEffect = "move";
280
+ };
281
+ const handleDrop = (val) => (e) => {
282
+ if (!sortable) return;
283
+ e.preventDefault();
284
+ const from = dragValueRef.current;
285
+ dragValueRef.current = null;
286
+ if (!from || from === val || !onReorder) return;
287
+ const order = tabs.map((t) => t.value);
288
+ const fromIdx = order.indexOf(from);
289
+ const toIdx = order.indexOf(val);
290
+ if (fromIdx === -1 || toIdx === -1) return;
291
+ const next = [...order];
292
+ next.splice(fromIdx, 1);
293
+ next.splice(toIdx, 0, from);
294
+ onReorder(next);
295
+ };
296
+ return /* @__PURE__ */ jsxRuntime.jsxs(
297
+ "div",
298
+ {
299
+ ref,
300
+ className: rootClass,
301
+ "data-orientation": orientation,
302
+ "data-scrollable": scrollable || void 0,
303
+ onKeyDown: handleTypeahead,
304
+ children: [
305
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rtab-list-wrap", children: [
306
+ scrollable && scrollState.left && /* @__PURE__ */ jsxRuntime.jsx(
307
+ "button",
308
+ {
309
+ type: "button",
310
+ className: "rtab-scroll-btn rtab-scroll-btn--left",
311
+ "aria-label": "Scroll left",
312
+ onClick: () => scrollByAmount(-200),
313
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 12 12", width: "12", height: "12", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M7.5 3l-3 3 3 3" }) })
314
+ }
315
+ ),
316
+ /* @__PURE__ */ jsxRuntime.jsxs(
317
+ "div",
318
+ {
319
+ ref: tabListRef,
320
+ role: "tablist",
321
+ "aria-orientation": orientation,
322
+ className: "rtab-list",
323
+ "data-variant": variant,
324
+ "data-size": size,
325
+ "data-tone": tone,
326
+ "data-orientation": orientation,
327
+ "data-scrollable": scrollable || void 0,
328
+ style: indicatorStyle,
329
+ children: [
330
+ tabs.map((tab, index) => {
331
+ const isActive = activeValue === tab.value;
332
+ const isDisabled = !!tab.disabled;
333
+ const tabProps = getTabProps(tab.value, { disabled: tab.disabled });
334
+ return /* @__PURE__ */ jsxRuntime.jsxs(
335
+ "button",
336
+ {
337
+ "data-value": tab.value,
338
+ "data-closable": tab.closable || void 0,
339
+ className: "rtab-tab",
340
+ ...tabProps,
341
+ draggable: sortable && !isDisabled ? true : void 0,
342
+ onDragStart: sortable ? handleDragStart(tab.value) : void 0,
343
+ onDragOver: sortable ? handleDragOver(tab.value) : void 0,
344
+ onDrop: sortable ? handleDrop(tab.value) : void 0,
345
+ children: [
346
+ renderTab ? renderTab({ tab, index, isActive, isDisabled }) : tab.label,
347
+ tab.closable && /* @__PURE__ */ jsxRuntime.jsx(
348
+ "span",
349
+ {
350
+ className: "rtab-close",
351
+ role: "button",
352
+ tabIndex: -1,
353
+ "aria-label": `Close ${typeof tab.label === "string" ? tab.label : "tab"}`,
354
+ onClick: (e) => {
355
+ e.stopPropagation();
356
+ onTabClose?.(tab.value);
357
+ },
358
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 12 12", width: "10", height: "10", fill: "none", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 3l6 6M9 3l-6 6" }) })
359
+ }
360
+ )
361
+ ]
362
+ },
363
+ tab.value
364
+ );
365
+ }),
366
+ (variant === "line" || variant === "solid" || variant === "pill") && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rtab-indicator", "aria-hidden": "true" })
367
+ ]
368
+ }
369
+ ),
370
+ scrollable && scrollState.right && /* @__PURE__ */ jsxRuntime.jsx(
189
371
  "button",
190
372
  {
191
- className: "rtab-tab",
192
- ...getTabProps(tab.value, { disabled: tab.disabled }),
193
- children: tab.label
373
+ type: "button",
374
+ className: "rtab-scroll-btn rtab-scroll-btn--right",
375
+ "aria-label": "Scroll right",
376
+ onClick: () => scrollByAmount(200),
377
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 12 12", width: "12", height: "12", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4.5 3l3 3-3 3" }) })
378
+ }
379
+ )
380
+ ] }),
381
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rtab-panels", children: tabs.map((tab) => {
382
+ const isActive = activeValue === tab.value;
383
+ const shouldRender = forceMount || !lazyMount || activatedRef.current.has(tab.value);
384
+ return /* @__PURE__ */ jsxRuntime.jsx(
385
+ "div",
386
+ {
387
+ className: "rtab-panel",
388
+ ...getPanelProps(tab.value),
389
+ children: shouldRender ? renderPanel ? renderPanel({ tab, isActive }) : tab.content : null
194
390
  },
195
391
  tab.value
196
- )),
197
- (variant === "line" || variant === "solid" || variant === "pill") && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rtab-indicator", "aria-hidden": "true" })
198
- ]
199
- }
200
- ),
201
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rtab-panels", children: tabs.map((tab) => /* @__PURE__ */ jsxRuntime.jsx(
202
- "div",
203
- {
204
- className: "rtab-panel",
205
- ...getPanelProps(tab.value),
206
- children: tab.content
207
- },
208
- tab.value
209
- )) })
210
- ] });
392
+ );
393
+ }) })
394
+ ]
395
+ }
396
+ );
211
397
  }
212
398
  );
213
399
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/useTabs.ts","../src/styled/TabsStyled.tsx"],"names":["useRef","useState","useCallback","useMemo","useLayoutEffect","useEffect","forwardRef","TabsStyled","jsxs","jsx"],"mappings":"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","file":"styled.cjs","sourcesContent":["import {\n type AriaAttributes,\n type HTMLAttributes,\n type KeyboardEvent,\n useCallback,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\nexport interface UseTabsTab {\n value: string;\n disabled?: boolean;\n}\n\nexport interface UseTabsOptions {\n /** Tab definitions — needed for keyboard navigation between tabs. */\n tabs?: UseTabsTab[];\n /** Controlled active value. */\n value?: string;\n /** Initial active value when uncontrolled. */\n defaultValue?: string;\n /** Called when the active tab changes. */\n onChange?: (value: string) => void;\n}\n\nexport interface TabProps extends HTMLAttributes<HTMLButtonElement> {\n id: string;\n role: \"tab\";\n \"aria-selected\": boolean;\n \"aria-controls\": string;\n \"aria-disabled\"?: boolean;\n tabIndex: number;\n}\n\nexport interface PanelProps extends HTMLAttributes<HTMLDivElement> {\n id: string;\n role: \"tabpanel\";\n \"aria-labelledby\": string;\n hidden: boolean;\n}\n\nexport interface UseTabsResult {\n /** Currently active tab value. */\n activeValue: string | undefined;\n /** Returns props to spread onto a tab trigger `<button>`. */\n getTabProps: (value: string, options?: { disabled?: boolean }) => TabProps;\n /** Returns props to spread onto a tab panel. */\n getPanelProps: (value: string) => PanelProps;\n /** Programmatically set the active tab. */\n setActiveValue: (value: string) => void;\n}\n\nconst tabId = (listId: string, value: string) => `${listId}-tab-${value}`;\nconst panelId = (listId: string, value: string) => `${listId}-panel-${value}`;\n\nlet counter = 0;\nfunction useStableId() {\n const ref = useRef<string | null>(null);\n if (ref.current === null) {\n ref.current = `rtabs-${++counter}`;\n }\n return ref.current;\n}\n\nexport function useTabs(opts: UseTabsOptions = {}): UseTabsResult {\n const { tabs = [], value: controlledValue, defaultValue, onChange } = opts;\n\n const listId = useStableId();\n const isControlled = controlledValue !== undefined;\n\n const [internalValue, setInternalValue] = useState<string | undefined>(\n defaultValue,\n );\n\n const activeValue = isControlled ? controlledValue : internalValue;\n\n const tabRefs = useRef<Map<string, HTMLButtonElement>>(new Map());\n\n const setActiveValue = useCallback(\n (next: string) => {\n const tab = tabs.find((t) => t.value === next);\n if (tab?.disabled) return;\n if (isControlled) {\n if (next !== controlledValue) onChange?.(next);\n } else {\n if (next === internalValue) return;\n setInternalValue(next);\n onChange?.(next);\n }\n },\n [tabs, isControlled, controlledValue, internalValue, onChange],\n );\n\n const focusTab = useCallback((value: string) => {\n tabRefs.current.get(value)?.focus();\n }, []);\n\n const handleKeyDown = useCallback(\n (currentValue: string) =>\n (event: KeyboardEvent<HTMLButtonElement>) => {\n const enabled = tabs.filter((t) => !t.disabled);\n if (enabled.length === 0) return;\n\n const currentIndex = enabled.findIndex((t) => t.value === currentValue);\n\n let nextValue: string | undefined;\n\n switch (event.key) {\n case \"ArrowRight\":\n case \"ArrowDown\": {\n const nextIndex = (currentIndex + 1) % enabled.length;\n nextValue = enabled[nextIndex]?.value;\n break;\n }\n case \"ArrowLeft\":\n case \"ArrowUp\": {\n const prevIndex =\n (currentIndex - 1 + enabled.length) % enabled.length;\n nextValue = enabled[prevIndex]?.value;\n break;\n }\n case \"Home\": {\n nextValue = enabled[0]?.value;\n break;\n }\n case \"End\": {\n nextValue = enabled[enabled.length - 1]?.value;\n break;\n }\n default:\n return;\n }\n\n if (nextValue === undefined || nextValue === currentValue) return;\n event.preventDefault();\n setActiveValue(nextValue);\n focusTab(nextValue);\n },\n [tabs, setActiveValue, focusTab],\n );\n\n const getTabProps = useCallback(\n (value: string, options?: { disabled?: boolean }): TabProps => {\n const isDisabled =\n options?.disabled ?? tabs.find((t) => t.value === value)?.disabled;\n const isSelected = activeValue === value;\n return {\n id: tabId(listId, value),\n role: \"tab\",\n \"aria-selected\": isSelected,\n \"aria-controls\": panelId(listId, value),\n \"aria-disabled\": isDisabled || undefined,\n tabIndex: isSelected ? 0 : -1,\n disabled: isDisabled,\n ref: (node: HTMLButtonElement | null) => {\n if (node) {\n tabRefs.current.set(value, node);\n } else {\n tabRefs.current.delete(value);\n }\n },\n onClick: () => {\n if (!isDisabled) setActiveValue(value);\n },\n onKeyDown: handleKeyDown(value),\n } as TabProps & {\n disabled: boolean | undefined;\n ref: (node: HTMLButtonElement | null) => void;\n };\n },\n [activeValue, listId, tabs, setActiveValue, handleKeyDown],\n );\n\n const getPanelProps = useCallback(\n (value: string): PanelProps => {\n return {\n id: panelId(listId, value),\n role: \"tabpanel\",\n \"aria-labelledby\": tabId(listId, value),\n hidden: activeValue !== value,\n tabIndex: 0,\n };\n },\n [activeValue, listId],\n );\n\n return useMemo(\n () => ({ activeValue, getTabProps, getPanelProps, setActiveValue }),\n [activeValue, getTabProps, getPanelProps, setActiveValue],\n );\n}\n","import {\n type CSSProperties,\n type ReactNode,\n forwardRef,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n} from \"react\";\nimport { useTabs } from \"../useTabs\";\n\nexport type TabsVariant = \"line\" | \"solid\" | \"pill\";\nexport type TabsSize = \"sm\" | \"md\" | \"lg\";\nexport type TabsTone = \"neutral\" | \"primary\";\n\nexport interface TabItem {\n value: string;\n label: ReactNode;\n content: ReactNode;\n disabled?: boolean;\n}\n\nexport interface TabsStyledProps {\n tabs: TabItem[];\n variant?: TabsVariant;\n size?: TabsSize;\n tone?: TabsTone;\n defaultValue?: string;\n value?: string;\n onChange?: (value: string) => void;\n className?: string;\n}\n\n// Run layout effects on the client; fall back to a no-op effect on the server.\nconst useIsoLayoutEffect =\n typeof window !== \"undefined\" ? useLayoutEffect : useEffect;\n\nfunction useIndicator(\n tabListRef: React.RefObject<HTMLDivElement | null>,\n activeValue: string | undefined,\n) {\n const [style, setStyle] = useState<CSSProperties>({});\n\n useIsoLayoutEffect(() => {\n if (!tabListRef.current || activeValue === undefined) return;\n\n const measure = () => {\n const list = tabListRef.current;\n if (!list) return;\n const activeTab = list.querySelector<HTMLElement>(\n `[aria-selected=\"true\"]`,\n );\n if (!activeTab) return;\n\n const listRect = list.getBoundingClientRect();\n const tabRect = activeTab.getBoundingClientRect();\n const x = tabRect.left - listRect.left;\n const w = tabRect.width;\n\n setStyle({\n [\"--rtab-indicator-x\" as string]: `${x}px`,\n [\"--rtab-indicator-width\" as string]: `${w}px`,\n [\"--rtab-indicator-ready\" as string]: \"1\",\n });\n };\n\n measure();\n\n if (typeof ResizeObserver === \"undefined\") return;\n const ro = new ResizeObserver(measure);\n ro.observe(tabListRef.current);\n return () => ro.disconnect();\n }, [activeValue, tabListRef]);\n\n return style;\n}\n\nexport const TabsStyled = forwardRef<HTMLDivElement, TabsStyledProps>(\n function TabsStyled(\n {\n tabs,\n variant = \"line\",\n size = \"md\",\n tone = \"neutral\",\n defaultValue,\n value,\n onChange,\n className,\n },\n ref,\n ) {\n const tabDefs = tabs.map((t) => ({ value: t.value, disabled: t.disabled }));\n\n const resolvedDefault =\n defaultValue ?? tabs.find((t) => !t.disabled)?.value;\n\n const { activeValue, getTabProps, getPanelProps } = useTabs({\n tabs: tabDefs,\n defaultValue: value === undefined ? resolvedDefault : undefined,\n value,\n onChange,\n });\n\n const tabListRef = useRef<HTMLDivElement>(null);\n const indicatorStyle = useIndicator(tabListRef, activeValue);\n\n const rootClass = [\"rtab-root\", className].filter(Boolean).join(\" \");\n\n return (\n <div ref={ref} className={rootClass}>\n <div\n ref={tabListRef}\n role=\"tablist\"\n className=\"rtab-list\"\n data-variant={variant}\n data-size={size}\n data-tone={tone}\n style={indicatorStyle}\n >\n {tabs.map((tab) => (\n <button\n key={tab.value}\n className=\"rtab-tab\"\n {...getTabProps(tab.value, { disabled: tab.disabled })}\n >\n {tab.label}\n </button>\n ))}\n {(variant === \"line\" || variant === \"solid\" || variant === \"pill\") && (\n <span className=\"rtab-indicator\" aria-hidden=\"true\" />\n )}\n </div>\n <div className=\"rtab-panels\">\n {tabs.map((tab) => (\n <div\n key={tab.value}\n className=\"rtab-panel\"\n {...getPanelProps(tab.value)}\n >\n {tab.content}\n </div>\n ))}\n </div>\n </div>\n );\n },\n);\n"]}
1
+ {"version":3,"sources":["../src/useTabs.ts","../src/styled/TabsStyled.tsx"],"names":["useRef","useState","useCallback","useMemo","useLayoutEffect","useEffect","forwardRef","TabsStyled","jsxs","jsx"],"mappings":"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","file":"styled.cjs","sourcesContent":["import {\n type HTMLAttributes,\n type KeyboardEvent,\n useCallback,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\nexport type TabsActivation = \"automatic\" | \"manual\";\nexport type TabsOrientation = \"horizontal\" | \"vertical\";\nexport type TabsChangeReason = \"click\" | \"keyboard\" | \"programmatic\";\n\nexport interface UseTabsTab {\n value: string;\n disabled?: boolean;\n}\n\nexport interface UseTabsOptions {\n /** Tab definitions — needed for keyboard navigation between tabs. */\n tabs?: UseTabsTab[];\n /** Controlled active value. */\n value?: string;\n /** Initial active value when uncontrolled. */\n defaultValue?: string;\n /** Called when the active tab changes. Optional second arg reports the trigger reason. */\n onChange?: (value: string, reason: TabsChangeReason) => void;\n /** \"automatic\" (default) — arrow keys move focus AND activate. \"manual\" — arrows move focus only; Enter/Space activates. */\n activation?: TabsActivation;\n /** Affects keyboard nav. Default \"horizontal\". */\n orientation?: TabsOrientation;\n}\n\nexport interface TabProps extends HTMLAttributes<HTMLButtonElement> {\n id: string;\n role: \"tab\";\n \"aria-selected\": boolean;\n \"aria-controls\": string;\n \"aria-disabled\"?: boolean;\n \"data-state\": \"active\" | \"inactive\";\n tabIndex: number;\n}\n\nexport interface PanelProps extends HTMLAttributes<HTMLDivElement> {\n id: string;\n role: \"tabpanel\";\n \"aria-labelledby\": string;\n \"data-state\": \"active\" | \"inactive\";\n hidden: boolean;\n}\n\nexport interface UseTabsResult {\n /** Currently active tab value. */\n activeValue: string | undefined;\n /** Returns props to spread onto a tab trigger `<button>`. */\n getTabProps: (value: string, options?: { disabled?: boolean }) => TabProps;\n /** Returns props to spread onto a tab panel. */\n getPanelProps: (value: string) => PanelProps;\n /** Programmatically set the active tab. */\n setActiveValue: (value: string) => void;\n}\n\nconst tabId = (listId: string, value: string) => `${listId}-tab-${value}`;\nconst panelId = (listId: string, value: string) => `${listId}-panel-${value}`;\n\nlet counter = 0;\nfunction useStableId() {\n const ref = useRef<string | null>(null);\n if (ref.current === null) {\n ref.current = `rtabs-${++counter}`;\n }\n return ref.current;\n}\n\nexport function useTabs(opts: UseTabsOptions = {}): UseTabsResult {\n const {\n tabs = [],\n value: controlledValue,\n defaultValue,\n onChange,\n activation = \"automatic\",\n orientation = \"horizontal\",\n } = opts;\n\n const listId = useStableId();\n const isControlled = controlledValue !== undefined;\n\n const [internalValue, setInternalValue] = useState<string | undefined>(\n defaultValue,\n );\n\n const activeValue = isControlled ? controlledValue : internalValue;\n\n const tabRefs = useRef<Map<string, HTMLButtonElement>>(new Map());\n const onChangeRef = useRef(onChange);\n onChangeRef.current = onChange;\n\n const setActiveValue = useCallback(\n (next: string, reason: TabsChangeReason = \"programmatic\") => {\n const tab = tabs.find((t) => t.value === next);\n if (tab?.disabled) return;\n if (isControlled) {\n if (next !== controlledValue) onChangeRef.current?.(next, reason);\n } else {\n if (next === internalValue) return;\n setInternalValue(next);\n onChangeRef.current?.(next, reason);\n }\n },\n [tabs, isControlled, controlledValue, internalValue],\n );\n\n const focusTab = useCallback((value: string) => {\n tabRefs.current.get(value)?.focus();\n }, []);\n\n const handleKeyDown = useCallback(\n (currentValue: string) =>\n (event: KeyboardEvent<HTMLButtonElement>) => {\n const enabled = tabs.filter((t) => !t.disabled);\n if (enabled.length === 0) return;\n\n const currentIndex = enabled.findIndex((t) => t.value === currentValue);\n\n const isForward =\n orientation === \"vertical\"\n ? event.key === \"ArrowDown\"\n : event.key === \"ArrowRight\";\n const isBackward =\n orientation === \"vertical\"\n ? event.key === \"ArrowUp\"\n : event.key === \"ArrowLeft\";\n\n let nextValue: string | undefined;\n\n if (isForward) {\n const nextIndex = (currentIndex + 1) % enabled.length;\n nextValue = enabled[nextIndex]?.value;\n } else if (isBackward) {\n const prevIndex = (currentIndex - 1 + enabled.length) % enabled.length;\n nextValue = enabled[prevIndex]?.value;\n } else if (event.key === \"Home\") {\n nextValue = enabled[0]?.value;\n } else if (event.key === \"End\") {\n nextValue = enabled[enabled.length - 1]?.value;\n } else if (\n activation === \"manual\" &&\n (event.key === \"Enter\" || event.key === \" \")\n ) {\n event.preventDefault();\n setActiveValue(currentValue, \"keyboard\");\n return;\n } else {\n return;\n }\n\n if (nextValue === undefined || nextValue === currentValue) return;\n event.preventDefault();\n focusTab(nextValue);\n if (activation === \"automatic\") {\n setActiveValue(nextValue, \"keyboard\");\n }\n },\n [tabs, orientation, activation, setActiveValue, focusTab],\n );\n\n const getTabProps = useCallback(\n (value: string, options?: { disabled?: boolean }): TabProps => {\n const isDisabled =\n options?.disabled ?? tabs.find((t) => t.value === value)?.disabled;\n const isSelected = activeValue === value;\n return {\n id: tabId(listId, value),\n role: \"tab\",\n \"aria-selected\": isSelected,\n \"aria-controls\": panelId(listId, value),\n \"aria-disabled\": isDisabled || undefined,\n \"data-state\": isSelected ? \"active\" : \"inactive\",\n tabIndex: isSelected ? 0 : -1,\n disabled: isDisabled,\n ref: (node: HTMLButtonElement | null) => {\n if (node) {\n tabRefs.current.set(value, node);\n } else {\n tabRefs.current.delete(value);\n }\n },\n onClick: () => {\n if (!isDisabled) setActiveValue(value, \"click\");\n },\n onKeyDown: handleKeyDown(value),\n } as TabProps & {\n disabled: boolean | undefined;\n ref: (node: HTMLButtonElement | null) => void;\n };\n },\n [activeValue, listId, tabs, setActiveValue, handleKeyDown],\n );\n\n const getPanelProps = useCallback(\n (value: string): PanelProps => {\n const isActive = activeValue === value;\n return {\n id: panelId(listId, value),\n role: \"tabpanel\",\n \"aria-labelledby\": tabId(listId, value),\n \"data-state\": isActive ? \"active\" : \"inactive\",\n hidden: !isActive,\n tabIndex: 0,\n };\n },\n [activeValue, listId],\n );\n\n return useMemo(\n () => ({ activeValue, getTabProps, getPanelProps, setActiveValue }),\n [activeValue, getTabProps, getPanelProps, setActiveValue],\n );\n}\n","import {\n type CSSProperties,\n type ReactNode,\n forwardRef,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n} from \"react\";\nimport {\n useTabs,\n type TabsActivation,\n type TabsChangeReason,\n type TabsOrientation,\n} from \"../useTabs\";\n\nexport type TabsVariant = \"line\" | \"solid\" | \"pill\";\nexport type TabsSize = \"sm\" | \"md\" | \"lg\";\nexport type TabsTone = \"neutral\" | \"primary\" | \"success\" | \"danger\";\n\nexport interface TabItem {\n value: string;\n label: ReactNode;\n content: ReactNode;\n disabled?: boolean;\n /** When true, renders a × button on the tab. Pair with `onTabClose`. */\n closable?: boolean;\n}\n\nexport interface TabsRenderTabContext {\n tab: TabItem;\n index: number;\n isActive: boolean;\n isDisabled: boolean;\n}\n\nexport interface TabsRenderPanelContext {\n tab: TabItem;\n isActive: boolean;\n}\n\nexport interface TabsStyledProps {\n tabs: TabItem[];\n variant?: TabsVariant;\n size?: TabsSize;\n tone?: TabsTone;\n defaultValue?: string;\n value?: string;\n /** Optional second arg reports the trigger reason (\"click\" | \"keyboard\" | \"programmatic\"). */\n onChange?: (value: string, reason: TabsChangeReason) => void;\n /** \"automatic\" (default) — arrow keys move focus AND activate. \"manual\" — arrows move focus only. */\n activation?: TabsActivation;\n /** Affects keyboard nav direction. Default \"horizontal\". */\n orientation?: TabsOrientation;\n /** Only mount panels after they've been activated at least once. Default: false (all panels mount eagerly). */\n lazyMount?: boolean;\n /** Keep all panels mounted regardless of activation (useful with `lazyMount` overrides). Default: false. */\n forceMount?: boolean;\n /** Fires when the × on a closable tab is clicked. */\n onTabClose?: (value: string) => void;\n /** When true, the tab list scrolls horizontally with chevron buttons at the edges instead of wrapping. */\n scrollable?: boolean;\n /** When true, tabs can be reordered by dragging. Fires `onReorder` with the new value order. */\n sortable?: boolean;\n onReorder?: (values: string[]) => void;\n /** When true, the active tab is scrolled into view on activation. Default: true when `scrollable`. */\n scrollActiveIntoView?: boolean;\n /** Replace the default tab button content. The button shell (a11y, ref, key) stays owned by the component. */\n renderTab?: (ctx: TabsRenderTabContext) => ReactNode;\n /** Replace the default panel rendering. */\n renderPanel?: (ctx: TabsRenderPanelContext) => ReactNode;\n className?: string;\n}\n\n// Run layout effects on the client; fall back to a no-op effect on the server.\nconst useIsoLayoutEffect =\n typeof window !== \"undefined\" ? useLayoutEffect : useEffect;\n\nfunction useIndicator(\n tabListRef: React.RefObject<HTMLDivElement | null>,\n activeValue: string | undefined,\n orientation: TabsOrientation,\n) {\n const [style, setStyle] = useState<CSSProperties>({});\n\n useIsoLayoutEffect(() => {\n if (!tabListRef.current || activeValue === undefined) return;\n\n const measure = () => {\n const list = tabListRef.current;\n if (!list) return;\n const activeTab = list.querySelector<HTMLElement>(\n `[aria-selected=\"true\"]`,\n );\n if (!activeTab) return;\n\n const listRect = list.getBoundingClientRect();\n const tabRect = activeTab.getBoundingClientRect();\n\n if (orientation === \"vertical\") {\n const y = tabRect.top - listRect.top;\n const h = tabRect.height;\n setStyle({\n [\"--rtab-indicator-y\" as string]: `${y}px`,\n [\"--rtab-indicator-height\" as string]: `${h}px`,\n [\"--rtab-indicator-ready\" as string]: \"1\",\n });\n } else {\n const x = tabRect.left - listRect.left;\n const w = tabRect.width;\n setStyle({\n [\"--rtab-indicator-x\" as string]: `${x}px`,\n [\"--rtab-indicator-width\" as string]: `${w}px`,\n [\"--rtab-indicator-ready\" as string]: \"1\",\n });\n }\n };\n\n measure();\n\n if (typeof ResizeObserver === \"undefined\") return;\n const ro = new ResizeObserver(measure);\n ro.observe(tabListRef.current);\n return () => ro.disconnect();\n }, [activeValue, tabListRef, orientation]);\n\n return style;\n}\n\nexport const TabsStyled = forwardRef<HTMLDivElement, TabsStyledProps>(\n function TabsStyled(\n {\n tabs,\n variant = \"line\",\n size = \"md\",\n tone = \"neutral\",\n defaultValue,\n value,\n onChange,\n activation = \"automatic\",\n orientation = \"horizontal\",\n lazyMount = false,\n forceMount = false,\n onTabClose,\n scrollable = false,\n sortable = false,\n onReorder,\n scrollActiveIntoView,\n renderTab,\n renderPanel,\n className,\n },\n ref,\n ) {\n const autoScrollActive = scrollActiveIntoView ?? scrollable;\n const [scrollState, setScrollState] = useState<{ left: boolean; right: boolean }>({\n left: false,\n right: false,\n });\n const typeaheadBufferRef = useRef(\"\");\n const typeaheadTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const dragValueRef = useRef<string | null>(null);\n const tabDefs = tabs.map((t) => ({ value: t.value, disabled: t.disabled }));\n\n const resolvedDefault =\n defaultValue ?? tabs.find((t) => !t.disabled)?.value;\n\n const { activeValue, getTabProps, getPanelProps } = useTabs({\n tabs: tabDefs,\n defaultValue: value === undefined ? resolvedDefault : undefined,\n value,\n onChange,\n activation,\n orientation,\n });\n\n const tabListRef = useRef<HTMLDivElement>(null);\n const indicatorStyle = useIndicator(tabListRef, activeValue, orientation);\n\n // Track which tabs have been activated for lazyMount.\n const activatedRef = useRef<Set<string>>(new Set());\n if (activeValue !== undefined) activatedRef.current.add(activeValue);\n\n const rootClass = [\"rtab-root\", className].filter(Boolean).join(\" \");\n\n // Scroll-state: detect when there's content off the left/right edges so we can\n // toggle the chevron buttons. Only relevant when scrollable.\n useEffect(() => {\n if (!scrollable) return;\n const list = tabListRef.current;\n if (!list) return;\n const update = () => {\n setScrollState({\n left: list.scrollLeft > 4,\n right: list.scrollLeft + list.clientWidth < list.scrollWidth - 4,\n });\n };\n update();\n list.addEventListener(\"scroll\", update, { passive: true });\n const ro = typeof ResizeObserver !== \"undefined\" ? new ResizeObserver(update) : null;\n ro?.observe(list);\n return () => {\n list.removeEventListener(\"scroll\", update);\n ro?.disconnect();\n };\n }, [scrollable, tabs.length]);\n\n // Auto-scroll active tab into view\n useEffect(() => {\n if (!autoScrollActive || !activeValue) return;\n const list = tabListRef.current;\n if (!list) return;\n const activeEl = list.querySelector<HTMLElement>(`[aria-selected=\"true\"]`);\n if (!activeEl) return;\n activeEl.scrollIntoView({ behavior: \"smooth\", block: \"nearest\", inline: \"nearest\" });\n }, [autoScrollActive, activeValue]);\n\n const scrollByAmount = (delta: number) => {\n tabListRef.current?.scrollBy({ left: delta, behavior: \"smooth\" });\n };\n\n // Typeahead: letters jump to the next tab whose label starts with the buffer.\n const handleTypeahead = (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (e.key.length !== 1 || e.altKey || e.ctrlKey || e.metaKey) return;\n typeaheadBufferRef.current = (typeaheadBufferRef.current + e.key).toLowerCase();\n if (typeaheadTimerRef.current) clearTimeout(typeaheadTimerRef.current);\n typeaheadTimerRef.current = setTimeout(() => { typeaheadBufferRef.current = \"\"; }, 600);\n\n const buffer = typeaheadBufferRef.current;\n const startIdx = Math.max(0, tabs.findIndex((t) => t.value === activeValue));\n // Search starting just after the active tab, wrapping around.\n for (let i = 1; i <= tabs.length; i++) {\n const idx = (startIdx + i) % tabs.length;\n const tab = tabs[idx];\n if (!tab || tab.disabled) continue;\n const labelStr = typeof tab.label === \"string\" ? tab.label : \"\";\n if (labelStr.toLowerCase().startsWith(buffer)) {\n // Use the existing tab button's click via aria-selected target.\n const list = tabListRef.current;\n const btn = list?.querySelector<HTMLButtonElement>(`[data-value=\"${tab.value}\"]`);\n btn?.click();\n btn?.focus();\n break;\n }\n }\n };\n\n // Drag-to-reorder: HTML5 DnD is fine here — no external lib.\n const handleDragStart = (val: string) => (e: React.DragEvent<HTMLButtonElement>) => {\n if (!sortable) return;\n dragValueRef.current = val;\n e.dataTransfer.effectAllowed = \"move\";\n };\n const handleDragOver = (val: string) => (e: React.DragEvent<HTMLButtonElement>) => {\n if (!sortable || !dragValueRef.current || dragValueRef.current === val) return;\n e.preventDefault();\n e.dataTransfer.dropEffect = \"move\";\n };\n const handleDrop = (val: string) => (e: React.DragEvent<HTMLButtonElement>) => {\n if (!sortable) return;\n e.preventDefault();\n const from = dragValueRef.current;\n dragValueRef.current = null;\n if (!from || from === val || !onReorder) return;\n const order = tabs.map((t) => t.value);\n const fromIdx = order.indexOf(from);\n const toIdx = order.indexOf(val);\n if (fromIdx === -1 || toIdx === -1) return;\n const next = [...order];\n next.splice(fromIdx, 1);\n next.splice(toIdx, 0, from);\n onReorder(next);\n };\n\n return (\n <div\n ref={ref}\n className={rootClass}\n data-orientation={orientation}\n data-scrollable={scrollable || undefined}\n onKeyDown={handleTypeahead}\n >\n <div className=\"rtab-list-wrap\">\n {scrollable && scrollState.left && (\n <button\n type=\"button\"\n className=\"rtab-scroll-btn rtab-scroll-btn--left\"\n aria-label=\"Scroll left\"\n onClick={() => scrollByAmount(-200)}\n >\n <svg viewBox=\"0 0 12 12\" width=\"12\" height=\"12\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\"><path d=\"M7.5 3l-3 3 3 3\"/></svg>\n </button>\n )}\n <div\n ref={tabListRef}\n role=\"tablist\"\n aria-orientation={orientation}\n className=\"rtab-list\"\n data-variant={variant}\n data-size={size}\n data-tone={tone}\n data-orientation={orientation}\n data-scrollable={scrollable || undefined}\n style={indicatorStyle}\n >\n {tabs.map((tab, index) => {\n const isActive = activeValue === tab.value;\n const isDisabled = !!tab.disabled;\n const tabProps = getTabProps(tab.value, { disabled: tab.disabled });\n return (\n <button\n key={tab.value}\n data-value={tab.value}\n data-closable={tab.closable || undefined}\n className=\"rtab-tab\"\n {...tabProps}\n draggable={sortable && !isDisabled ? true : undefined}\n onDragStart={sortable ? handleDragStart(tab.value) : undefined}\n onDragOver={sortable ? handleDragOver(tab.value) : undefined}\n onDrop={sortable ? handleDrop(tab.value) : undefined}\n >\n {renderTab\n ? renderTab({ tab, index, isActive, isDisabled })\n : tab.label}\n {tab.closable && (\n <span\n className=\"rtab-close\"\n role=\"button\"\n tabIndex={-1}\n aria-label={`Close ${typeof tab.label === \"string\" ? tab.label : \"tab\"}`}\n onClick={(e) => {\n e.stopPropagation();\n onTabClose?.(tab.value);\n }}\n >\n <svg viewBox=\"0 0 12 12\" width=\"10\" height=\"10\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.6\" strokeLinecap=\"round\" aria-hidden=\"true\">\n <path d=\"M3 3l6 6M9 3l-6 6\"/>\n </svg>\n </span>\n )}\n </button>\n );\n })}\n {(variant === \"line\" || variant === \"solid\" || variant === \"pill\") && (\n <span className=\"rtab-indicator\" aria-hidden=\"true\" />\n )}\n </div>\n {scrollable && scrollState.right && (\n <button\n type=\"button\"\n className=\"rtab-scroll-btn rtab-scroll-btn--right\"\n aria-label=\"Scroll right\"\n onClick={() => scrollByAmount(200)}\n >\n <svg viewBox=\"0 0 12 12\" width=\"12\" height=\"12\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\"><path d=\"M4.5 3l3 3-3 3\"/></svg>\n </button>\n )}\n </div>\n <div className=\"rtab-panels\">\n {tabs.map((tab) => {\n const isActive = activeValue === tab.value;\n const shouldRender =\n forceMount || !lazyMount || activatedRef.current.has(tab.value);\n return (\n <div\n key={tab.value}\n className=\"rtab-panel\"\n {...getPanelProps(tab.value)}\n >\n {shouldRender\n ? renderPanel\n ? renderPanel({ tab, isActive })\n : tab.content\n : null}\n </div>\n );\n })}\n </div>\n </div>\n );\n },\n);\n"]}
package/dist/styled.d.cts CHANGED
@@ -1,14 +1,27 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode } from 'react';
3
+ import { TabsChangeReason, TabsActivation, TabsOrientation } from './index.cjs';
3
4
 
4
5
  type TabsVariant = "line" | "solid" | "pill";
5
6
  type TabsSize = "sm" | "md" | "lg";
6
- type TabsTone = "neutral" | "primary";
7
+ type TabsTone = "neutral" | "primary" | "success" | "danger";
7
8
  interface TabItem {
8
9
  value: string;
9
10
  label: ReactNode;
10
11
  content: ReactNode;
11
12
  disabled?: boolean;
13
+ /** When true, renders a × button on the tab. Pair with `onTabClose`. */
14
+ closable?: boolean;
15
+ }
16
+ interface TabsRenderTabContext {
17
+ tab: TabItem;
18
+ index: number;
19
+ isActive: boolean;
20
+ isDisabled: boolean;
21
+ }
22
+ interface TabsRenderPanelContext {
23
+ tab: TabItem;
24
+ isActive: boolean;
12
25
  }
13
26
  interface TabsStyledProps {
14
27
  tabs: TabItem[];
@@ -17,7 +30,29 @@ interface TabsStyledProps {
17
30
  tone?: TabsTone;
18
31
  defaultValue?: string;
19
32
  value?: string;
20
- onChange?: (value: string) => void;
33
+ /** Optional second arg reports the trigger reason ("click" | "keyboard" | "programmatic"). */
34
+ onChange?: (value: string, reason: TabsChangeReason) => void;
35
+ /** "automatic" (default) — arrow keys move focus AND activate. "manual" — arrows move focus only. */
36
+ activation?: TabsActivation;
37
+ /** Affects keyboard nav direction. Default "horizontal". */
38
+ orientation?: TabsOrientation;
39
+ /** Only mount panels after they've been activated at least once. Default: false (all panels mount eagerly). */
40
+ lazyMount?: boolean;
41
+ /** Keep all panels mounted regardless of activation (useful with `lazyMount` overrides). Default: false. */
42
+ forceMount?: boolean;
43
+ /** Fires when the × on a closable tab is clicked. */
44
+ onTabClose?: (value: string) => void;
45
+ /** When true, the tab list scrolls horizontally with chevron buttons at the edges instead of wrapping. */
46
+ scrollable?: boolean;
47
+ /** When true, tabs can be reordered by dragging. Fires `onReorder` with the new value order. */
48
+ sortable?: boolean;
49
+ onReorder?: (values: string[]) => void;
50
+ /** When true, the active tab is scrolled into view on activation. Default: true when `scrollable`. */
51
+ scrollActiveIntoView?: boolean;
52
+ /** Replace the default tab button content. The button shell (a11y, ref, key) stays owned by the component. */
53
+ renderTab?: (ctx: TabsRenderTabContext) => ReactNode;
54
+ /** Replace the default panel rendering. */
55
+ renderPanel?: (ctx: TabsRenderPanelContext) => ReactNode;
21
56
  className?: string;
22
57
  }
23
58
  declare const TabsStyled: react.ForwardRefExoticComponent<TabsStyledProps & react.RefAttributes<HTMLDivElement>>;