@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/{chunk-UCRNSS7N.js → chunk-NNDW3W6L.js} +43 -34
- package/dist/chunk-NNDW3W6L.js.map +1 -0
- package/dist/index.cjs +41 -32
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -3
- package/dist/index.d.ts +12 -3
- package/dist/index.js +1 -1
- package/dist/styled.cjs +260 -74
- package/dist/styled.cjs.map +1 -1
- package/dist/styled.d.cts +37 -2
- package/dist/styled.d.ts +37 -2
- package/dist/styled.js +221 -44
- package/dist/styled.js.map +1 -1
- package/dist/styles.css +120 -0
- package/package.json +1 -1
- package/dist/chunk-UCRNSS7N.js.map +0 -1
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 {
|
|
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)
|
|
40
|
+
if (next !== controlledValue) onChangeRef.current?.(next, reason);
|
|
32
41
|
} else {
|
|
33
42
|
if (next === internalValue) return;
|
|
34
43
|
setInternalValue(next);
|
|
35
|
-
|
|
44
|
+
onChangeRef.current?.(next, reason);
|
|
36
45
|
}
|
|
37
46
|
},
|
|
38
|
-
[tabs, isControlled, controlledValue, internalValue
|
|
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
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
-
|
|
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
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
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
|
-
|
|
192
|
-
|
|
193
|
-
|
|
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
|
-
|
|
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
|
|
package/dist/styled.cjs.map
CHANGED
|
@@ -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
|
-
|
|
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>>;
|