lightswind
Version:
A collection of beautifully crafted React Components, Blocks & Templates for Modern Developers. Create stunning web applications effortlessly by using our 160+ professional and animated react components.
206 lines • 9.79 kB
JavaScript
;
"use client";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.TabsContent = exports.TabsTrigger = exports.TabsList = exports.Tabs = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const React = __importStar(require("react"));
const utils_1 = require("@/components/lib/utils");
const framer_motion_1 = require("framer-motion");
const TabsContext = React.createContext({
value: "",
onValueChange: () => { },
updateIndicator: () => { },
scheduleUpdateIndicator: () => { },
indicatorStyle: {},
mounted: false,
registerTabTrigger: () => { },
registerTabsList: () => { },
});
const Tabs = React.forwardRef(({ className, defaultValue, value, onValueChange, children, ...props }, ref) => {
const [internalValue, setInternalValue] = React.useState(defaultValue || "");
const [indicatorStyle, setIndicatorStyle] = React.useState({});
const [mounted, setMounted] = React.useState(false);
const tabsListRef = React.useRef(null);
const tabTriggerRefs = React.useRef(new Map());
const controlled = value !== undefined;
const currentValue = controlled ? value : internalValue;
const registerTabsList = React.useCallback((element) => {
tabsListRef.current = element;
}, []);
const registerTabTrigger = React.useCallback((value, element) => {
if (element) {
tabTriggerRefs.current.set(value, element);
}
else {
tabTriggerRefs.current.delete(value);
}
}, []);
const updateIndicator = React.useCallback(() => {
if (tabsListRef.current && currentValue) {
const activeTab = tabTriggerRefs.current.get(currentValue);
if (activeTab) {
const tabRect = activeTab.getBoundingClientRect();
const listRect = tabsListRef.current.getBoundingClientRect();
// Only update if both rects have valid dimensions (element is visible)
if (tabRect.width > 0 && listRect.width > 0) {
setIndicatorStyle({
left: `${tabRect.left - listRect.left}px`,
width: `${tabRect.width}px`,
});
}
}
}
}, [currentValue]);
const scheduleUpdateIndicator = React.useCallback(() => {
// Use rAF to defer until after browser has painted layout
requestAnimationFrame(() => {
updateIndicator();
});
}, [updateIndicator]);
React.useEffect(() => {
setMounted(true);
// Schedule update after paint so dimensions are correct even inside popovers/dialogs
scheduleUpdateIndicator();
window.addEventListener("resize", scheduleUpdateIndicator);
return () => window.removeEventListener("resize", scheduleUpdateIndicator);
}, [scheduleUpdateIndicator]);
// Watch for when the tabs list becomes visible in the DOM
// (e.g., when a Popover or Dialog opens), then re-compute the indicator
React.useEffect(() => {
const listEl = tabsListRef.current;
if (!listEl)
return;
const observer = new IntersectionObserver((entries) => {
if (entries[0]?.isIntersecting) {
scheduleUpdateIndicator();
}
}, { threshold: 0.1 });
observer.observe(listEl);
return () => observer.disconnect();
}, [scheduleUpdateIndicator]);
const handleValueChange = React.useCallback((newValue) => {
if (!controlled)
setInternalValue(newValue);
onValueChange?.(newValue);
}, [controlled, onValueChange]);
return ((0, jsx_runtime_1.jsx)(TabsContext.Provider, { value: {
value: currentValue,
onValueChange: handleValueChange,
updateIndicator,
scheduleUpdateIndicator,
indicatorStyle,
mounted,
registerTabTrigger,
registerTabsList,
}, children: (0, jsx_runtime_1.jsx)("div", { ref: ref, className: (0, utils_1.cn)("w-full", className), ...props, children: children }) }));
});
exports.Tabs = Tabs;
Tabs.displayName = "Tabs";
const TabsList = React.forwardRef(({ className, ...props }, ref) => {
const { indicatorStyle, registerTabsList, mounted } = React.useContext(TabsContext);
return ((0, jsx_runtime_1.jsxs)("div", { ref: (el) => {
if (typeof ref === "function")
ref(el);
else if (ref)
ref.current = el;
registerTabsList(el);
}, className: (0, utils_1.cn)(`relative inline-flex h-8 items-center justify-center rounded-full bg-muted text-primary`, className), ...props, children: [mounted && ((0, jsx_runtime_1.jsx)(framer_motion_1.motion.div, { layout: true, className: "tabs-bg-indicator absolute top-0 left-0 h-full rounded-full bg-gradient-tabs", style: {
...indicatorStyle,
position: "absolute",
top: 0,
borderRadius: "9999px",
height: "100%",
zIndex: 0,
}, transition: { type: "spring", stiffness: 300, damping: 30 } })), props.children] }));
});
exports.TabsList = TabsList;
TabsList.displayName = "TabsList";
const TabsTrigger = React.forwardRef(({ className, value, ...props }, ref) => {
const { value: selectedValue, onValueChange, registerTabTrigger, updateIndicator, scheduleUpdateIndicator } = React.useContext(TabsContext);
const isActive = selectedValue === value;
const triggerRef = React.useRef(null);
React.useEffect(() => {
registerTabTrigger(value, triggerRef.current);
return () => registerTabTrigger(value, null);
}, [value, registerTabTrigger]);
React.useEffect(() => {
// Use scheduleUpdateIndicator for deferred measurement (fixes popover/dialog initial state)
if (isActive)
scheduleUpdateIndicator();
}, [isActive, scheduleUpdateIndicator]);
return ((0, jsx_runtime_1.jsx)("button", { ref: (el) => {
if (typeof ref === "function")
ref(el);
else if (ref)
ref.current = el;
triggerRef.current = el;
}, type: "button", role: "tab", "aria-selected": isActive, "data-state": isActive ? "active" : "inactive", "data-value": value, className: (0, utils_1.cn)(`relative z-10 inline-flex items-center justify-center whitespace-nowrap rounded-full
px-3 py-0.5 md:py-1.5 text-xs lg:text-sm font-medium transition-all
focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring
focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50`, isActive ? "text-white dark:text-black" : "", className), onClick: () => onValueChange(value), ...props }));
});
exports.TabsTrigger = TabsTrigger;
TabsTrigger.displayName = "TabsTrigger";
const TabsContent = React.forwardRef(({ className, value, ...props }, ref) => {
const { value: selectedValue, updateIndicator } = React.useContext(TabsContext);
const isActive = selectedValue === value;
const contentRef = React.useRef(null);
// Trigger updateIndicator when content resizes
React.useEffect(() => {
if (!isActive || !contentRef.current)
return;
const observer = new ResizeObserver(() => {
updateIndicator();
});
observer.observe(contentRef.current);
return () => observer.disconnect();
}, [isActive, updateIndicator]);
return ((0, jsx_runtime_1.jsx)(framer_motion_1.AnimatePresence, { mode: "wait", children: isActive && ((0, jsx_runtime_1.jsx)("div", { ref: (el) => {
contentRef.current = el;
if (typeof ref === "function")
ref(el);
else if (ref)
ref.current = el;
}, role: "tabpanel", "data-state": "active", "data-value": value, className: (0, utils_1.cn)(`mt-2 ring-offset-background focus-visible:outline-none
focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2
mx-auto w-full`, className), style: {
scrollbarWidth: "none",
msOverflowStyle: "none",
}, ...props }, value)) }));
});
exports.TabsContent = TabsContent;
TabsContent.displayName = "TabsContent";
//# sourceMappingURL=tabs.js.map