@underverse-ui/underverse 1.0.95 → 1.0.96
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/api-reference.json +1 -1
- package/dist/index.cjs +119 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +119 -52
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/api-reference.json
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -6793,6 +6793,32 @@ var variantStyles5 = {
|
|
|
6793
6793
|
inactiveTab: "text-muted-foreground hover:text-foreground"
|
|
6794
6794
|
}
|
|
6795
6795
|
};
|
|
6796
|
+
function getTabsBaseId(tabs) {
|
|
6797
|
+
const key = tabs.map((t) => t.value).join("-");
|
|
6798
|
+
return `tabs-${key || "default"}`;
|
|
6799
|
+
}
|
|
6800
|
+
function getTabTriggerId(baseId, index) {
|
|
6801
|
+
return `${baseId}-tab-${index}`;
|
|
6802
|
+
}
|
|
6803
|
+
function getTabPanelId(baseId, index) {
|
|
6804
|
+
return `${baseId}-panel-${index}`;
|
|
6805
|
+
}
|
|
6806
|
+
function getTabHref(tab, panelId) {
|
|
6807
|
+
return tab.href ?? `#${panelId}`;
|
|
6808
|
+
}
|
|
6809
|
+
function resolveTabValueFromHash(hash, tabs, baseId) {
|
|
6810
|
+
const normalizedHash = hash.replace(/^#/, "");
|
|
6811
|
+
if (!normalizedHash) return null;
|
|
6812
|
+
const matchIndex = tabs.findIndex((tab, index) => {
|
|
6813
|
+
const tabId = getTabTriggerId(baseId, index);
|
|
6814
|
+
const panelId = getTabPanelId(baseId, index);
|
|
6815
|
+
return normalizedHash === tabId || normalizedHash === panelId;
|
|
6816
|
+
});
|
|
6817
|
+
return matchIndex >= 0 ? tabs[matchIndex]?.value ?? null : null;
|
|
6818
|
+
}
|
|
6819
|
+
function shouldHandleTabClickLocally(event, target) {
|
|
6820
|
+
return !(event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || target === "_blank");
|
|
6821
|
+
}
|
|
6796
6822
|
var Tabs = ({
|
|
6797
6823
|
tabs,
|
|
6798
6824
|
defaultValue,
|
|
@@ -6810,14 +6836,33 @@ var Tabs = ({
|
|
|
6810
6836
|
const [active, setActive] = React22.useState(defaultValue || tabs[0]?.value);
|
|
6811
6837
|
const [underlineStyle, setUnderlineStyle] = React22.useState({});
|
|
6812
6838
|
const tabRefs = React22.useRef([]);
|
|
6813
|
-
const baseId = React22.useMemo(() =>
|
|
6814
|
-
const key = tabs.map((t) => t.value).join("-");
|
|
6815
|
-
return `tabs-${key || "default"}`;
|
|
6816
|
-
}, [tabs]);
|
|
6839
|
+
const baseId = React22.useMemo(() => getTabsBaseId(tabs), [tabs]);
|
|
6817
6840
|
const handleTabChange = (value) => {
|
|
6818
6841
|
setActive(value);
|
|
6819
6842
|
onTabChange?.(value);
|
|
6820
6843
|
};
|
|
6844
|
+
const handleTabKeyDown = (event) => {
|
|
6845
|
+
const count = tabs.length;
|
|
6846
|
+
const idx = tabs.findIndex((t) => t.value === active);
|
|
6847
|
+
let next = idx;
|
|
6848
|
+
if (orientation === "horizontal") {
|
|
6849
|
+
if (event.key === "ArrowRight") next = (idx + 1) % count;
|
|
6850
|
+
if (event.key === "ArrowLeft") next = (idx - 1 + count) % count;
|
|
6851
|
+
} else {
|
|
6852
|
+
if (event.key === "ArrowDown") next = (idx + 1) % count;
|
|
6853
|
+
if (event.key === "ArrowUp") next = (idx - 1 + count) % count;
|
|
6854
|
+
}
|
|
6855
|
+
if (event.key === "Home") next = 0;
|
|
6856
|
+
if (event.key === "End") next = count - 1;
|
|
6857
|
+
if (next !== idx) {
|
|
6858
|
+
event.preventDefault();
|
|
6859
|
+
const nextTab = tabs[next];
|
|
6860
|
+
if (!nextTab?.disabled) {
|
|
6861
|
+
handleTabChange(nextTab.value);
|
|
6862
|
+
}
|
|
6863
|
+
tabRefs.current[next]?.focus();
|
|
6864
|
+
}
|
|
6865
|
+
};
|
|
6821
6866
|
React22.useEffect(() => {
|
|
6822
6867
|
if (variant === "underline" && orientation === "horizontal") {
|
|
6823
6868
|
const activeIndex2 = tabs.findIndex((tab) => tab.value === active);
|
|
@@ -6831,6 +6876,18 @@ var Tabs = ({
|
|
|
6831
6876
|
}
|
|
6832
6877
|
}
|
|
6833
6878
|
}, [active, variant, orientation, tabs]);
|
|
6879
|
+
React22.useEffect(() => {
|
|
6880
|
+
if (typeof window === "undefined") return;
|
|
6881
|
+
const syncFromHash = () => {
|
|
6882
|
+
const nextValue = resolveTabValueFromHash(window.location.hash, tabs, baseId);
|
|
6883
|
+
if (nextValue) {
|
|
6884
|
+
setActive(nextValue);
|
|
6885
|
+
}
|
|
6886
|
+
};
|
|
6887
|
+
syncFromHash();
|
|
6888
|
+
window.addEventListener("hashchange", syncFromHash);
|
|
6889
|
+
return () => window.removeEventListener("hashchange", syncFromHash);
|
|
6890
|
+
}, [baseId, tabs]);
|
|
6834
6891
|
const containerClasses = cn(
|
|
6835
6892
|
"relative",
|
|
6836
6893
|
orientation === "horizontal" ? "w-full flex space-x-1 overflow-x-auto" : "flex flex-col space-y-1 shrink-0",
|
|
@@ -6853,59 +6910,69 @@ var Tabs = ({
|
|
|
6853
6910
|
tabs.map((tab, index) => {
|
|
6854
6911
|
const isActive = active === tab.value;
|
|
6855
6912
|
const Icon = tab.icon;
|
|
6856
|
-
const tabId2 =
|
|
6857
|
-
const panelId2 =
|
|
6913
|
+
const tabId2 = getTabTriggerId(baseId, index);
|
|
6914
|
+
const panelId2 = getTabPanelId(baseId, index);
|
|
6915
|
+
const tabHref = getTabHref(tab, panelId2);
|
|
6916
|
+
const sharedClassName = cn(
|
|
6917
|
+
"font-medium transition-all duration-200 cursor-pointer flex items-center gap-2",
|
|
6918
|
+
"focus:outline-none focus-visible:outline-none",
|
|
6919
|
+
"disabled:opacity-50 disabled:cursor-not-allowed",
|
|
6920
|
+
sizeStyles6[size].tab,
|
|
6921
|
+
variantStyles5[variant].tab,
|
|
6922
|
+
isActive ? variantStyles5[variant].activeTab : variantStyles5[variant].inactiveTab,
|
|
6923
|
+
orientation === "vertical" && "justify-start w-full",
|
|
6924
|
+
stretch && orientation === "horizontal" && "flex-1 justify-center",
|
|
6925
|
+
tab.href && tab.disabled && "pointer-events-none cursor-not-allowed opacity-50"
|
|
6926
|
+
);
|
|
6927
|
+
const sharedStyle = {
|
|
6928
|
+
boxShadow: "none",
|
|
6929
|
+
transform: "none",
|
|
6930
|
+
outline: "none",
|
|
6931
|
+
border: "none"
|
|
6932
|
+
};
|
|
6933
|
+
const sharedProps = {
|
|
6934
|
+
ref: (el) => {
|
|
6935
|
+
tabRefs.current[index] = el;
|
|
6936
|
+
},
|
|
6937
|
+
id: tabId2,
|
|
6938
|
+
role: "tab",
|
|
6939
|
+
"aria-selected": isActive,
|
|
6940
|
+
"aria-controls": panelId2,
|
|
6941
|
+
tabIndex: isActive ? 0 : -1,
|
|
6942
|
+
className: sharedClassName,
|
|
6943
|
+
style: sharedStyle,
|
|
6944
|
+
onKeyDown: handleTabKeyDown
|
|
6945
|
+
};
|
|
6946
|
+
if (!tab.disabled) {
|
|
6947
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
6948
|
+
"a",
|
|
6949
|
+
{
|
|
6950
|
+
...sharedProps,
|
|
6951
|
+
href: tabHref,
|
|
6952
|
+
target: tab.target,
|
|
6953
|
+
rel: tab.rel,
|
|
6954
|
+
onClick: (event) => {
|
|
6955
|
+
if (shouldHandleTabClickLocally(event, tab.target)) {
|
|
6956
|
+
event.preventDefault();
|
|
6957
|
+
handleTabChange(tab.value);
|
|
6958
|
+
}
|
|
6959
|
+
},
|
|
6960
|
+
className: cn(sharedClassName, "no-underline"),
|
|
6961
|
+
children: [
|
|
6962
|
+
Icon && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Icon, { className: "h-4 w-4" }),
|
|
6963
|
+
tab.label
|
|
6964
|
+
]
|
|
6965
|
+
},
|
|
6966
|
+
tab.value
|
|
6967
|
+
);
|
|
6968
|
+
}
|
|
6858
6969
|
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
6859
6970
|
"button",
|
|
6860
6971
|
{
|
|
6861
|
-
|
|
6862
|
-
tabRefs.current[index] = el;
|
|
6863
|
-
},
|
|
6972
|
+
...sharedProps,
|
|
6864
6973
|
onClick: () => !tab.disabled && handleTabChange(tab.value),
|
|
6865
6974
|
disabled: tab.disabled,
|
|
6866
|
-
|
|
6867
|
-
boxShadow: "none",
|
|
6868
|
-
transform: "none",
|
|
6869
|
-
outline: "none",
|
|
6870
|
-
border: "none"
|
|
6871
|
-
},
|
|
6872
|
-
className: cn(
|
|
6873
|
-
"font-medium transition-all duration-200 cursor-pointer flex items-center gap-2",
|
|
6874
|
-
"focus:outline-none focus-visible:outline-none",
|
|
6875
|
-
"disabled:opacity-50 disabled:cursor-not-allowed",
|
|
6876
|
-
"border-0 bg-transparent outline-none",
|
|
6877
|
-
// Reset button default styles
|
|
6878
|
-
sizeStyles6[size].tab,
|
|
6879
|
-
variantStyles5[variant].tab,
|
|
6880
|
-
isActive ? variantStyles5[variant].activeTab : variantStyles5[variant].inactiveTab,
|
|
6881
|
-
orientation === "vertical" && "justify-start w-full",
|
|
6882
|
-
stretch && orientation === "horizontal" && "flex-1 justify-center"
|
|
6883
|
-
),
|
|
6884
|
-
role: "tab",
|
|
6885
|
-
id: tabId2,
|
|
6886
|
-
"aria-selected": isActive,
|
|
6887
|
-
"aria-controls": panelId2,
|
|
6888
|
-
tabIndex: isActive ? 0 : -1,
|
|
6889
|
-
onKeyDown: (e) => {
|
|
6890
|
-
const count = tabs.length;
|
|
6891
|
-
const idx = tabs.findIndex((t) => t.value === active);
|
|
6892
|
-
let next = idx;
|
|
6893
|
-
if (orientation === "horizontal") {
|
|
6894
|
-
if (e.key === "ArrowRight") next = (idx + 1) % count;
|
|
6895
|
-
if (e.key === "ArrowLeft") next = (idx - 1 + count) % count;
|
|
6896
|
-
} else {
|
|
6897
|
-
if (e.key === "ArrowDown") next = (idx + 1) % count;
|
|
6898
|
-
if (e.key === "ArrowUp") next = (idx - 1 + count) % count;
|
|
6899
|
-
}
|
|
6900
|
-
if (e.key === "Home") next = 0;
|
|
6901
|
-
if (e.key === "End") next = count - 1;
|
|
6902
|
-
if (next !== idx) {
|
|
6903
|
-
e.preventDefault();
|
|
6904
|
-
const nextVal = tabs[next].value;
|
|
6905
|
-
handleTabChange(nextVal);
|
|
6906
|
-
tabRefs.current[next]?.focus();
|
|
6907
|
-
}
|
|
6908
|
-
},
|
|
6975
|
+
className: cn(sharedClassName, "border-0 bg-transparent outline-none"),
|
|
6909
6976
|
children: [
|
|
6910
6977
|
Icon && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Icon, { className: "h-4 w-4" }),
|
|
6911
6978
|
tab.label
|