@sineways/react-tablefront
Version:
React Data Table and Data Grid for TypeScript. Zero config with fast search and filters, pagination and infinite scroll, table grid and masonry layouts. Built on TanStack Table.
1,256 lines (1,241 loc) • 241 kB
JavaScript
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
ClearFiltersButton: () => ClearFiltersButton,
DEFAULT_RESIZE_DOUBLE_CLICK_DELAY: () => DEFAULT_RESIZE_DOUBLE_CLICK_DELAY,
DEFAULT_RESIZE_RESET_DEBOUNCE: () => DEFAULT_RESIZE_RESET_DEBOUNCE,
DataGrid: () => DataGrid,
DataMasonry: () => DataMasonry,
DataTable: () => DataTable,
DataTableBody: () => DataTableBody,
DataTableHeader: () => DataTableHeader,
DataTablePagination: () => DataTablePagination,
DataTableStates: () => DataTableStates,
DefaultIcons: () => DefaultIcons,
EmptyState: () => EmptyState,
ExpandButton: () => ExpandButton,
FilterProcessor: () => FilterProcessor,
GridField: () => GridField,
GridItem: () => GridItem,
LicenseEnforcer: () => LicenseEnforcer,
LoadingState: () => LoadingState,
MasonryField: () => MasonryField,
MasonryItem: () => MasonryItem,
PaginationControls: () => PaginationControls,
PaginationInfo: () => PaginationInfo,
SearchInput: () => SearchInput,
SmartHeader: () => SmartHeader,
TableCell: () => TableCell,
TableRow: () => TableRow,
applyColumnOverrides: () => applyColumnOverrides,
applyColumnVisibilityOverrides: () => applyColumnVisibilityOverrides,
applyFieldOverrides: () => applyFieldOverrides,
applySmartSizing: () => applySmartSizing,
autoGenerateFields: () => autoGenerateFields,
buildFields: () => buildFields,
cn: () => cn,
compactTableStyles: () => compactTableStyles,
createAutoDataTable: () => createAutoDataTable,
createDataTable: () => createDataTable,
createSimpleDataTable: () => createSimpleDataTable,
defaultTableStyles: () => defaultTableStyles,
generateStableStoreId: () => generateStableStoreId,
getFirstField: () => getFirstField,
getTableStylePreset: () => getTableStylePreset,
isValidId: () => isValidId,
modernTableStyles: () => modernTableStyles,
quickColumns: () => quickColumns,
safeEquals: () => safeEquals,
safeStringId: () => safeStringId,
tableStylePresets: () => tableStylePresets,
useDataTableIcons: () => useDataTableIcons,
useInfiniteScrollManager: () => useInfiniteScrollManager,
useLicenseStatus: () => useLicenseStatus,
useTableStyles: () => useTableStyles
});
module.exports = __toCommonJS(index_exports);
// src/DataTable.tsx
var import_react19 = __toESM(require("react"), 1);
// src/hooks/useWindowResize.ts
var import_react = require("react");
function useWindowResize() {
const [windowSize, setWindowSize] = (0, import_react.useState)({
width: typeof window !== "undefined" ? window.innerWidth : 1200,
height: typeof window !== "undefined" ? window.innerHeight : 800
});
(0, import_react.useEffect)(() => {
function handleResize() {
setWindowSize({
width: window.innerWidth,
height: window.innerHeight
});
}
window.addEventListener("resize", handleResize);
handleResize();
return () => window.removeEventListener("resize", handleResize);
}, []);
return windowSize;
}
// src/constants/resize.ts
var DEFAULT_RESIZE_DOUBLE_CLICK_DELAY = 150;
var DEFAULT_RESIZE_RESET_DEBOUNCE = 50;
// src/utils.ts
var import_clsx = require("clsx");
var import_tailwind_merge = require("tailwind-merge");
var import_date_fns = require("date-fns");
var import_date_fns_tz = require("date-fns-tz");
function cn(...inputs) {
return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
}
function parseDate(value, timeZone = "UTC") {
if (!value) return void 0;
if (value instanceof Date) return value;
try {
if (typeof value === "string" && value.includes("T")) {
return (0, import_date_fns_tz.toDate)((0, import_date_fns.parseISO)(value), { timeZone });
}
const date = new Date(value);
return (0, import_date_fns.isValid)(date) ? date : void 0;
} catch {
return void 0;
}
}
var createDragState = () => ({
isDragging: false,
draggedColumnId: null,
dragStartX: 0,
dragStartY: 0,
currentX: 0,
currentY: 0,
dropTargetIndex: null,
dropTargetColumnId: null
});
var getColumnIdFromElement = (element) => {
return element.getAttribute("data-column-id");
};
var setDragImage = (event, element) => {
if (event.dataTransfer) {
event.dataTransfer.effectAllowed = "move";
event.dataTransfer.setDragImage(element, 0, 0);
}
};
var getDropTargetIndex = (x, headerCells, draggedIndex) => {
if (headerCells.length === 0) return { index: -1, columnId: null };
let left = 0;
let right = headerCells.length - 1;
while (left <= right) {
const mid = Math.floor((left + right) / 2);
const cell = headerCells[mid];
const rect = cell.getBoundingClientRect();
const centerX = rect.left + rect.width / 2;
if (x < centerX) {
right = mid - 1;
} else {
left = mid + 1;
}
}
const targetIndex = left;
const targetCell = headerCells[targetIndex] || headerCells[headerCells.length - 1];
return {
index: targetIndex,
columnId: getColumnIdFromElement(targetCell)
};
};
var addDropIndicator = (targetElement, position, dropIndicatorClass = "absolute top-0 bottom-0 w-1 bg-primary z-10") => {
const indicator = document.createElement("div");
indicator.className = dropIndicatorClass;
if (position === "before") {
indicator.style.left = "0";
} else {
indicator.style.right = "0";
}
targetElement.style.position = "relative";
targetElement.appendChild(indicator);
return indicator;
};
var removeDropIndicator = (indicator) => {
if (indicator && indicator.parentNode) {
indicator.parentNode.removeChild(indicator);
}
};
var createResizeState = () => ({
isResizing: false,
columnId: null,
startX: 0,
startWidth: 0
});
var RESIZE_CONSTRAINTS = {
MIN_WIDTH: 50,
MAX_WIDTH: 8e3
};
var applyResizeCursor = (isResizing) => {
if (typeof document === "undefined") return;
if (isResizing) {
document.body.style.cursor = "col-resize";
document.body.style.userSelect = "none";
} else {
document.body.style.cursor = "";
document.body.style.userSelect = "";
}
};
var getColumnWidth = (element) => {
return element.getBoundingClientRect().width;
};
var applyColumnWidthToDomImmediate = (columnId, width) => {
const clampedWidth = Math.max(RESIZE_CONSTRAINTS.MIN_WIDTH, Math.min(RESIZE_CONSTRAINTS.MAX_WIDTH, width));
const headerCell = document.querySelector(`th[data-column-id="${columnId}"]`);
if (!headerCell) return clampedWidth;
const table = headerCell.closest("table");
const columnIndex = Array.from(headerCell.parentElement?.children || []).indexOf(headerCell);
applyColumnStyles(headerCell, clampedWidth);
if (table && columnIndex >= 0) {
const bodyCells = table.querySelectorAll(`tbody td:nth-child(${columnIndex + 1})`);
bodyCells.forEach((cell) => {
applyColumnStyles(cell, clampedWidth);
});
}
headerCell.offsetWidth;
return clampedWidth;
};
var applyColumnStyles = (element, width) => {
element.style.width = `${width}px`;
element.style.minWidth = `${width}px`;
element.style.maxWidth = `${width}px`;
};
var clearColumnStyles = (columnId) => {
const headerCell = document.querySelector(`th[data-column-id="${columnId}"]`);
if (!headerCell) return;
const table = headerCell.closest("table");
const columnIndex = Array.from(headerCell.parentElement?.children || []).indexOf(headerCell);
clearElementStyles(headerCell);
if (table && columnIndex >= 0) {
const bodyCells = table.querySelectorAll(`tbody td:nth-child(${columnIndex + 1})`);
bodyCells.forEach((cell) => {
clearElementStyles(cell);
});
}
headerCell.offsetWidth;
};
var clearElementStyles = (element) => {
element.style.width = "";
element.style.minWidth = "";
element.style.maxWidth = "";
};
var HEADER_MIN_WIDTH_FOR_TEXT = 40;
var shouldShowHeaderText = (columnWidth) => {
return columnWidth > HEADER_MIN_WIDTH_FOR_TEXT;
};
var truncateHeaderText = (text, maxLength = 15) => {
if (!text || text.length <= maxLength) return text;
return text.substring(0, maxLength).trim() + "...";
};
var getCurrentColumnWidth = (columnId) => {
const headerCell = document.querySelector(`th[data-column-id="${columnId}"]`);
if (!headerCell) return 0;
return headerCell.getBoundingClientRect().width;
};
// src/variants.tsx
var import_react2 = require("react");
// src/defaultStyles.ts
var defaultTableStyles = {
container: "flex-1 w-full min-h-0 flex flex-col focus:outline-none",
searchBar: {
wrapper: "px-0 pt-0 mb-2",
containerWrapper: "relative",
container: "pr-1.5 relative flex items-center w-full h-12 rounded-lg bg-foreground/5 hover:bg-foreground/10 focus-within:ring-1 focus-within:ring-primary transition-colors",
icon: "absolute left-3 w-5 h-5 text-muted-foreground",
input: "w-full bg-transparent border-none focus:outline-none text-sm pl-10 pr-2 py-1.5 placeholder:text-muted-foreground",
clearButton: "",
clearButtonIcon: "w-4 h-4"
},
header: {
container: "flex items-center justify-between py-1 pl-3 pr-1 border-b border-border shrink-0 bg-foreground/5 rounded-t-lg",
leftSection: "flex items-center gap-2",
resultCount: "text-xs font-medium text-muted-foreground",
clearFiltersButton: "text-xs px-3",
clearFiltersIcon: "size-5",
rightSection: "flex items-center gap-1"
},
table: {
scrollArea: "w-full flex-1 min-h-0 overflow-auto",
table: "w-full caption-bottom text-sm bg-foreground/2",
tableHeader: "h-10 sticky top-0 bg-background border-b border-border shadow-sm",
tableRow: "border-b h-10",
tableRowSelected: "bg-primary/10 hover:bg-primary/10",
tableRowHover: "hover:bg-foreground/5",
tableCell: "px-4 align-middle",
tableHeaderCell: "h-10 px-4 font-medium text-muted-foreground cursor-pointer select-none hover:bg-foreground/5",
expandHeader: "min-w-10 w-10 px-0 text-center",
expandButton: "size-1 px-0"
},
grid: {
container: "grid w-full h-full gap-1 py-1",
item: "bg-card border border-border rounded-lg p-4 cursor-pointer transition-all duration-200",
itemHover: "hover:bg-accent/50 hover:border-accent/50 hover:shadow-md",
itemSelected: "bg-primary/10 border-primary/30 shadow-lg",
itemContent: "space-y-3",
expandButton: "w-8 h-8 flex items-center justify-center rounded hover:bg-foreground/5",
itemFields: "space-y-2",
field: "space-y-1",
fieldLabel: "text-xs font-medium text-muted-foreground uppercase tracking-wide",
fieldValue: "text-sm font-medium text-foreground",
expandedContent: "mt-4 pt-4 border-t border-border"
},
masonry: {
container: "flex w-full h-full py-1 gap-1",
column: "flex flex-col gap-1",
item: "bg-card border border-border rounded-lg p-4 cursor-pointer transition-all duration-200",
itemHover: "hover:bg-accent/50 hover:border-accent/50 hover:shadow-md",
itemSelected: "bg-primary/10 border-primary/30 shadow-lg",
itemContent: "space-y-3",
expandButton: "w-8 h-8 flex items-center justify-center rounded hover:bg-foreground/5",
itemFields: "space-y-2",
field: "space-y-1",
fieldLabel: "text-xs font-medium text-muted-foreground uppercase tracking-wide",
fieldValue: "text-sm font-medium text-foreground",
expandedContent: "mt-4 pt-4 border-t border-border"
},
loadingState: {
container: "flex items-center justify-center h-full w-full p-6 text-muted-foreground",
content: "space-y-1 text-center",
icon: "h-6 w-6 animate-spin",
text: "text-sm"
},
emptyState: {
container: "flex items-center justify-center h-full w-full p-6 text-muted-foreground",
content: "space-y-2 text-center",
text: "text-sm"
},
pagination: {
variant: "version2",
container: "flex items-center justify-center px-2 py-1 border-t border-border bg-background",
info: "text-xs text-muted-foreground px-3",
controls: "flex items-center gap-2",
buttonGroup: "flex items-center gap-2",
button: "h-8 w-8 p-0 hover:bg-muted disabled:opacity-50 disabled:cursor-not-allowed",
buttonIcon: "h-4 w-4"
},
columnVisibility: {
trigger: "size-9",
triggerIcon: "size-5",
content: "w-72 p-4",
header: "space-y-4",
toggleAllButton: "text-sm font-medium cursor-pointer",
itemList: "space-y-0",
item: "flex items-center justify-between space-x-2",
checkbox: "cursor-pointer"
},
filterPopover: {
trigger: "size-9",
triggerIcon: "size-5",
content: "max-w-[95vw] p-4 bg-card",
container: "",
header: "",
title: "text-sm font-medium mb-3",
grid: "grid grid-cols-1 sm:grid-cols-2 gap-3",
column: "space-y-1.5",
filterButton: "min-w-[170px] text-xs bg-foreground/5 hover:bg-foreground/10 cursor-pointer",
filterButtonActive: "bg-primary/15 hover:bg-primary/20 text-primary hover:text-primary font-medium shadow-sm",
filterButtonInactive: "bg-foreground/5 hover:bg-foreground/10",
filterLabel: "text-xs whitespace-nowrap"
},
dragDrop: {
dragGhost: "pointer-events-none z-[9999] opacity-80 bg-background",
dropIndicator: "absolute top-0 bottom-0 w-1 bg-primary z-10",
dragTarget: "bg-muted/50",
dragSource: "opacity-50"
},
resize: {
handle: "absolute top-0 right-0 bottom-0 w-1 group-hover:bg-primary/20 z-10",
indicator: "absolute top-1/2 right-0 w-1 h-4 group-hover:bg-primary/40 transform -translate-y-1/2 rounded-full",
overlay: "fixed inset-0 z-[9999] cursor-col-resize",
hitslop: "absolute top-0 right-0 bottom-0 w-2 cursor-col-resize group z-10"
}
};
var modernTableStyles = {
container: "flex-1 w-full min-h-0 flex flex-col focus:outline-none bg-background",
searchBar: {
wrapper: "px-0 pt-0 mb-1",
containerWrapper: "relative",
container: "relative flex items-center w-full h-12 rounded-xl bg-gradient-to-r from-card to-card/80 hover:from-accent/5 hover:to-accent/10 focus-within:ring-2 focus-within:ring-primary transition-all duration-300 shadow-inner border border-border/50",
icon: "absolute left-3 w-5 h-5 text-primary",
input: "w-full bg-transparent border-none focus:outline-none text-sm pl-10 pr-4 py-1.5 placeholder:text-muted-foreground transition-all duration-200",
clearButton: "absolute right-2",
clearButtonIcon: "w-4 h-4"
},
header: {
container: "flex items-center justify-between py-3 px-4 border-b border-border bg-gradient-to-r from-card/50 to-card/70 backdrop-blur-md shadow-sm",
leftSection: "flex items-center gap-3",
resultCount: "text-sm font-semibold text-foreground",
clearFiltersButton: "",
clearFiltersIcon: "size-5",
rightSection: "flex items-center gap-1"
},
table: {
scrollArea: "w-full flex-1 min-h-0 bg-card/20 overflow-auto",
table: "w-full text-sm",
tableHeader: "sticky top-0 bg-gradient-to-b from-card/90 to-card/70 backdrop-blur-md border-b border-border shadow-md",
tableRow: "border-b border-border/50 cursor-pointer transition-all duration-200",
tableRowSelected: "bg-gradient-to-r from-primary/5 via-primary/15 to-primary/5 hover:from-primary/10 hover:via-primary/25 hover:to-primary/10 shadow-lg",
tableRowHover: "hover:bg-gradient-to-r hover:from-accent/40 hover:via-accent/60 hover:to-accent/40",
tableCell: "p-4 align-middle",
tableHeaderCell: "h-12 px-4 text-left align-middle font-semibold text-card-foreground cursor-pointer select-none hover:bg-gradient-to-r hover:from-accent/40 hover:via-accent/60 hover:to-accent/40 transition-colors duration-200",
expandHeader: "w-10 px-0 text-center",
expandButton: "w-10 px-0"
},
grid: {
container: "grid gap-6 p-6",
item: "bg-gradient-to-br from-card to-card/80 border border-border/50 rounded-xl p-6 cursor-pointer transition-all duration-300 shadow-lg hover:shadow-xl",
itemHover: "hover:bg-gradient-to-br hover:from-accent/20 hover:via-accent/30 hover:to-accent/20 hover:border-accent/50 hover:scale-105",
itemSelected: "bg-gradient-to-br from-primary/10 via-primary/20 to-primary/10 border-primary/50 shadow-2xl scale-105",
itemContent: "space-y-4",
expandButton: "w-10 h-10 flex items-center justify-center rounded-lg hover:bg-foreground/10 transition-all duration-200",
itemFields: "space-y-3",
field: "space-y-1.5",
fieldLabel: "text-xs font-semibold text-primary uppercase tracking-wider",
fieldValue: "text-sm font-semibold text-foreground",
expandedContent: "mt-6 pt-6 border-t border-border/50"
},
masonry: {
container: "flex gap-6 p-6",
column: "flex flex-col gap-6",
item: "bg-gradient-to-br from-card to-card/80 border border-border/50 rounded-xl p-6 cursor-pointer transition-all duration-300 shadow-lg hover:shadow-xl",
itemHover: "hover:bg-gradient-to-br hover:from-accent/20 hover:via-accent/30 hover:to-accent/20 hover:border-accent/50 hover:scale-105",
itemSelected: "bg-gradient-to-br from-primary/10 via-primary/20 to-primary/10 border-primary/50 shadow-2xl scale-105",
itemContent: "space-y-4",
expandButton: "w-10 h-10 flex items-center justify-center rounded-lg hover:bg-foreground/10 transition-all duration-200",
itemFields: "space-y-3",
field: "space-y-1.5",
fieldLabel: "text-xs font-semibold text-primary uppercase tracking-wider",
fieldValue: "text-sm font-semibold text-foreground",
expandedContent: "mt-6 pt-6 border-t border-border/50"
},
loadingState: {
container: "flex items-center justify-center h-full w-full p-6 bg-gradient-to-br from-background to-background/80 text-muted-foreground",
content: "space-y-1 text-center",
icon: "h-6 w-6 animate-spin text-primary",
text: "text-sm"
},
emptyState: {
container: "flex items-center justify-center h-full w-full p-6 bg-gradient-to-br from-background to-background/80 text-muted-foreground",
content: "space-y-2 text-center",
text: "text-sm"
},
pagination: {
container: "flex items-center justify-center px-4 py-2 border-t border-border bg-gradient-to-r from-background to-background/90",
info: "text-xs text-muted-foreground px-3",
controls: "flex items-center gap-2",
buttonGroup: "flex items-center gap-2",
button: "h-8 w-8 p-0 hover:bg-gradient-to-r hover:from-accent/20 hover:via-accent/30 hover:to-accent/20 disabled:opacity-50 disabled:cursor-not-allowed rounded-full",
buttonIcon: "h-4 w-4"
},
columnVisibility: {
trigger: "h-10 w-10",
triggerIcon: "size-5 text-primary",
content: "w-80 p-6 bg-gradient-to-br from-card to-card/80 shadow-lg rounded-xl border border-border/50 backdrop-blur-md",
header: "space-y-4",
toggleAllButton: "text-sm font-medium cursor-pointer",
itemList: "space-y-1 pr-2",
item: "flex items-center justify-between space-x-2",
checkbox: "cursor-pointer"
},
filterPopover: {
trigger: "h-10 w-10",
triggerIcon: "size-5 text-primary",
content: "max-w-[95vw] p-6 bg-gradient-to-br from-card to-card/80 shadow-lg rounded-xl border border-border/50 backdrop-blur-md",
container: "p-0",
header: "bg-gradient-to-r from-card/50 to-card/70 backdrop-blur-md rounded-t-xl p-3",
title: "text-sm font-semibold mb-3 text-foreground",
grid: "grid grid-cols-1 sm:grid-cols-2 gap-4",
column: "space-y-2",
filterButton: "min-w-[150px] rounded-xl py-2.5 px-3 text-center text-xs transition-all duration-200 shadow-sm hover:scale-105",
filterButtonActive: "bg-gradient-to-r from-primary/15 via-primary/25 to-primary/15 text-primary font-semibold shadow-md border border-primary/30 hover:shadow-xl hover:scale-105",
filterButtonInactive: "bg-gradient-to-r from-accent/40 via-accent/50 to-accent/40 hover:from-accent/50 hover:via-accent/60 hover:to-accent/50 text-foreground",
filterLabel: "text-xs whitespace-nowrap text-muted-foreground font-medium"
},
dragDrop: {
dragGhost: "pointer-events-none z-[9999] opacity-80 bg-background/50",
dropIndicator: "absolute top-0 bottom-0 w-1 bg-primary/50 z-10",
dragTarget: "bg-accent/50",
dragSource: "opacity-50"
},
resize: {
handle: "absolute top-0 right-0 bottom-0 w-1 group-hover:bg-primary/20 z-10",
indicator: "absolute top-1/2 right-0 w-1 h-4 bg-border group-hover:bg-primary/40 transform -translate-y-1/2 rounded-full",
overlay: "fixed inset-0 z-[9999] cursor-col-resize",
hitslop: "absolute top-0 right-0 bottom-0 w-2 cursor-col-resize group z-10"
}
};
var compactTableStyles = {
container: "flex-1 w-full min-h-0 flex flex-col focus:outline-none",
searchBar: {
wrapper: "px-0 pt-0 mb-1",
containerWrapper: "relative",
container: "relative flex items-center w-full h-8 rounded bg-muted hover:bg-accent focus-within:ring-1 focus-within:ring-primary transition-colors",
icon: "absolute left-2 w-3.5 h-3.5 text-muted-foreground",
input: "w-full bg-transparent border-none focus:outline-none text-xs pl-7 pr-3 py-1 placeholder:text-muted-foreground",
clearButton: "absolute right-1",
clearButtonIcon: "w-3 h-3"
},
header: {
container: "flex items-center justify-between py-1 px-2 border-b border-border bg-muted/30 min-h-8",
leftSection: "flex items-center gap-1",
resultCount: "text-xs text-muted-foreground",
clearFiltersButton: "",
clearFiltersIcon: "size-4",
rightSection: "flex items-center gap-1"
},
table: {
scrollArea: "w-full flex-1 min-h-0 overflow-auto",
table: "w-full text-xs",
tableHeader: "sticky top-0 bg-muted/50 border-b border-border backdrop-blur-md",
tableRow: "border-b transition-colors cursor-pointer",
tableRowSelected: "bg-primary/10 hover:bg-primary/15",
tableRowHover: "hover:bg-muted/30",
tableCell: "p-2 align-middle text-xs",
tableHeaderCell: "h-8 px-2 text-left align-middle font-medium text-muted-foreground cursor-pointer select-none hover:bg-muted/50 text-xs",
expandHeader: "w-6 px-0 text-center",
expandButton: "w-6 px-0"
},
grid: {
container: "grid gap-2 p-2",
item: "bg-card border border-border rounded p-2 cursor-pointer transition-colors",
itemHover: "hover:bg-accent/30 hover:border-accent/50",
itemSelected: "bg-primary/10 border-primary/30 shadow-sm",
itemContent: "space-y-1.5",
expandButton: "w-6 h-6 flex items-center justify-center rounded hover:bg-foreground/5",
itemFields: "space-y-1",
field: "space-y-0.5",
fieldLabel: "text-xs font-medium text-muted-foreground",
fieldValue: "text-xs font-medium text-foreground",
expandedContent: "mt-2 pt-2 border-t border-border"
},
masonry: {
container: "flex gap-2 p-2",
column: "flex flex-col gap-2",
item: "bg-card border border-border rounded p-2 cursor-pointer transition-colors",
itemHover: "hover:bg-accent/30 hover:border-accent/50",
itemSelected: "bg-primary/10 border-primary/30 shadow-sm",
itemContent: "space-y-1.5",
expandButton: "w-6 h-6 flex items-center justify-center rounded hover:bg-foreground/5",
itemFields: "space-y-1",
field: "space-y-0.5",
fieldLabel: "text-xs font-medium text-muted-foreground",
fieldValue: "text-xs font-medium text-foreground",
expandedContent: "mt-2 pt-2 border-t border-border"
},
loadingState: {
container: "flex items-center justify-center h-full w-full p-4 text-muted-foreground",
content: "space-y-1 text-center",
icon: "h-4 w-4 animate-spin",
text: "text-xs"
},
emptyState: {
container: "flex items-center justify-center h-full w-full p-4 text-muted-foreground",
content: "space-y-1 text-center",
text: "text-xs"
},
pagination: {
container: "flex items-center justify-center px-2 py-1 border-t border-border bg-background",
info: "text-xs text-muted-foreground px-2",
controls: "flex items-center gap-1",
buttonGroup: "flex items-center gap-1",
button: "h-6 w-6 p-0 hover:bg-muted disabled:opacity-50 disabled:cursor-not-allowed",
buttonIcon: "h-3 w-3"
},
columnVisibility: {
trigger: "h-8 w-8",
triggerIcon: "size-4",
content: "min-w-64 p-4",
header: "space-y-4",
toggleAllButton: "text-sm font-medium cursor-pointer",
itemList: "space-y-1 pr-2",
item: "flex items-center justify-between space-x-2",
checkbox: "cursor-pointer"
},
filterPopover: {
trigger: "h-8 w-8",
triggerIcon: "size-4",
content: "max-w-[95vw] p-4",
container: "p-0",
header: "bg-muted/30 rounded p-1.5",
title: "text-xs font-medium mb-2 px-1",
grid: "grid grid-cols-1 sm:grid-cols-2 gap-2 px-1 pb-1",
column: "space-y-1",
filterButton: "min-w-[120px] rounded py-1.5 px-2 text-center text-xs transition-colors",
filterButtonActive: "bg-primary/15 text-primary font-medium",
filterButtonInactive: "bg-muted/50 hover:bg-muted/70 text-foreground",
filterLabel: "text-xs whitespace-nowrap text-muted-foreground"
},
dragDrop: {
dragGhost: "pointer-events-none z-[9999] opacity-80 bg-background",
dropIndicator: "absolute top-0 bottom-0 w-0.5 bg-primary z-10",
dragTarget: "bg-muted/50",
dragSource: "opacity-50"
},
resize: {
handle: "absolute top-0 right-0 bottom-0 w-1 group-hover:bg-primary/20 z-10",
indicator: "absolute top-1/2 right-0 w-1 h-4 bg-border group-hover:bg-primary/40 transform -translate-y-1/2 rounded-full",
overlay: "fixed inset-0 z-[9999] cursor-col-resize",
hitslop: "absolute top-0 right-0 bottom-0 w-2 cursor-col-resize group z-10"
}
};
var tableStylePresets = {
default: defaultTableStyles,
modern: modernTableStyles,
compact: compactTableStyles
};
function getTableStylePreset(preset) {
return tableStylePresets[preset];
}
// src/variants.tsx
var baseStyles = {
container: "flex-1 w-full min-h-0 flex flex-col",
searchBar: {
wrapper: "",
containerWrapper: "",
container: "",
icon: "",
input: "",
clearButton: "",
clearButtonIcon: ""
},
header: {
container: "",
leftSection: "",
resultCount: "",
clearFiltersButton: "",
clearFiltersIcon: "",
rightSection: ""
},
table: {
scrollArea: "",
table: "",
tableHeader: "",
tableRow: "",
tableRowSelected: "",
tableRowHover: "",
tableCell: "",
tableHeaderCell: "",
expandHeader: "",
expandButton: ""
},
grid: {
container: "",
item: "",
itemHover: "",
itemSelected: "",
itemContent: "",
expandButton: "",
itemFields: "",
field: "",
fieldLabel: "",
fieldValue: "",
expandedContent: ""
},
masonry: {
container: "",
column: "",
item: "",
itemHover: "",
itemSelected: "",
itemContent: "",
expandButton: "",
itemFields: "",
field: "",
fieldLabel: "",
fieldValue: "",
expandedContent: ""
},
loadingState: {
container: "",
content: "",
icon: "",
text: ""
},
emptyState: {
container: "",
content: "",
text: ""
},
pagination: {
variant: "version1",
container: "",
info: "",
controls: "",
buttonGroup: "",
button: "",
buttonIcon: ""
},
columnVisibility: {
trigger: "",
triggerIcon: "",
content: "",
header: "",
toggleAllButton: "",
itemList: "",
item: "",
checkbox: ""
},
filterPopover: {
trigger: "",
triggerIcon: "",
content: "",
container: "",
header: "",
title: "",
grid: "",
column: "",
filterButton: "",
filterButtonActive: "",
filterButtonInactive: "",
filterLabel: ""
},
dragDrop: {
dragGhost: "",
dropIndicator: "",
dragTarget: "",
dragSource: ""
},
resize: {
handle: "",
indicator: "",
overlay: "",
hitslop: ""
}
};
function mergeStyles(base, custom) {
const result = { ...base };
Object.entries(custom).forEach(([key, value]) => {
if (value === void 0) return;
if (typeof value === "string") {
;
result[key] = value;
} else if (typeof value === "object" && value !== null) {
const r = result;
const existing = r[key] || {};
r[key] = { ...existing, ...value };
}
});
return result;
}
function getTableStyles(customStyles) {
return customStyles ? mergeStyles(baseStyles, customStyles) : mergeStyles(baseStyles, defaultTableStyles);
}
function useTableStyles(customStyles) {
return (0, import_react2.useMemo)(() => getTableStyles(customStyles), [customStyles]);
}
// src/components/LicenseEnforcer.tsx
var import_react4 = require("react");
// src/licensing.ts
var import_react3 = require("react");
function useLicenseStatus() {
const [status, setStatus] = (0, import_react3.useState)({ valid: false, ready: false });
(0, import_react3.useEffect)(() => {
let cancelled = false;
(async () => {
try {
try {
await import("../dist/license.globals.mjs");
} catch {
}
let token = globalThis.__TABLEFRONT_VALIDATION_TOKEN;
let publicKeyB64u = globalThis.__TABLEFRONT_VALIDATION_KEY;
if (!token || !publicKeyB64u) {
if (!cancelled) setStatus({ valid: false, ready: true });
return;
}
const derivedValid = getJwtValidFlag(token);
if (!cancelled) setStatus({ valid: derivedValid, ready: true });
} catch {
if (!cancelled) setStatus({ valid: false, ready: true });
}
})();
return () => {
cancelled = true;
};
}, []);
return status;
}
function getJwtValidFlag(token) {
try {
if (!token) return false;
const parts = token.split(".");
if (parts.length !== 3) return false;
const payloadB64u = parts[1];
const payloadJson = base64UrlToString(payloadB64u);
const payload = JSON.parse(payloadJson);
return !!(payload && payload.valid === true);
} catch {
return false;
}
}
function base64UrlToString(b64u) {
const s = base64UrlToBase64(b64u);
return decodeURIComponent(escape(atob(s)));
}
function base64UrlToBase64(b64u) {
let s = b64u.replace(/-/g, "+").replace(/_/g, "/");
const pad = s.length % 4;
if (pad === 2) s += "==";
else if (pad === 3) s += "=";
else if (pad !== 0) s += "==";
return s;
}
// src/watermark.ts
var containerToOverlay = /* @__PURE__ */ new WeakMap();
function createAndMountHost(container, text) {
const uniqueId = Math.random().toString(36).slice(2);
const host = document.createElement("div");
host.setAttribute("data-rtf-wm", uniqueId);
const hostStyle = [
"position:absolute !important",
"inset:0 !important",
"pointer-events:none !important",
"z-index:2147483647 !important",
"contain:layout style paint !important",
"mix-blend-mode:normal !important",
"all:initial !important",
"position:absolute !important",
"top:0 !important",
"left:0 !important",
"right:0 !important",
"bottom:0 !important",
"display:block !important"
].join("; ");
host.setAttribute("style", hostStyle);
const shadow = host.attachShadow({ mode: "closed" });
const escapeForSvg = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
const svgWidth = 320;
const svgHeight = 220;
const svg = `<?xml version="1.0" encoding="UTF-8"?><svg xmlns='http://www.w3.org/2000/svg' width='${svgWidth}' height='${svgHeight}' viewBox='0 0 ${svgWidth} ${svgHeight}'> <defs> <pattern id='p' width='${svgWidth}' height='${svgHeight}' patternUnits='userSpaceOnUse' patternTransform='rotate(-20)'> <text x='0' y='${Math.floor(svgHeight / 2)}' font-size='28' font-family='system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif' fill='rgba(0,0,0,0.12)' font-weight='700'>${escapeForSvg(text)}</text> </pattern> </defs> <rect width='100%' height='100%' fill='url(#p)'/></svg>`;
const dataUrl = `url("data:image/svg+xml;utf8,${encodeURIComponent(svg)}")`;
const styleEl = document.createElement("style");
styleEl.textContent = `
:host { all: initial !important; }
.overlay {
position: absolute !important;
inset: 0 !important;
pointer-events: none !important;
z-index: 2147483647 !important;
background-image: repeating-linear-gradient(45deg, rgba(0,0,0,0.08) 0 20px, transparent 20px 40px), ${dataUrl} !important;
background-repeat: repeat, repeat !important;
background-size: auto, ${svgWidth}px ${svgHeight}px !important;
background-position: 0 0, 0 0 !important;
user-select: none !important;
}
`;
const overlay = document.createElement("div");
overlay.className = "overlay";
shadow.appendChild(styleEl);
shadow.appendChild(overlay);
if (container.isConnected && !container.contains(host)) container.appendChild(host);
const observer = new MutationObserver(() => {
if (container.isConnected && !container.contains(host)) container.appendChild(host);
});
observer.observe(container, { childList: true });
return { host, observer };
}
function mountWatermarkTo(container, text) {
if (typeof document === "undefined" || !container) return;
const existing = containerToOverlay.get(container);
if (existing) {
if (existing.text === (text || "Unlicensed")) return;
unmountWatermarkFrom(container);
}
const { host, observer } = createAndMountHost(container, text || "Unlicensed");
containerToOverlay.set(container, { host, observer, text: text || "Unlicensed" });
}
function unmountWatermarkFrom(container) {
if (typeof document === "undefined" || !container) return;
const entry = containerToOverlay.get(container);
if (!entry) return;
try {
entry.observer.disconnect();
} catch {
}
try {
entry.host.remove();
} catch {
}
containerToOverlay.delete(container);
}
// src/components/LicenseEnforcer.tsx
function LicenseEnforcer({ containerRef, watermarkText = "Sineways Tablefront" }) {
const license = useLicenseStatus();
(0, import_react4.useEffect)(() => {
const container = containerRef.current;
if (!container || !license?.ready) return;
if (!license.valid) {
mountWatermarkTo(container, watermarkText);
} else {
unmountWatermarkFrom(container);
}
return () => {
if (container) unmountWatermarkFrom(container);
};
}, [license?.ready, license?.valid, containerRef, watermarkText]);
(0, import_react4.useEffect)(() => {
if (!license?.ready) return;
if (license.valid) return;
try {
console.error(
"[tablefront]",
`License key not found or invalid. You can still use Tablefront, but a watermark will appear.
To activate, add TABLEFRONT_LICENSE="your-license-key-here" to your .env file and add "tablefront activate" to your package.json build script (for example: "build": "tablefront activate && next build").
If you do not have a license key yet, you can purchase one at https://tablefront.sineways.tech/`
);
} catch {
}
}, [license?.ready, license?.valid]);
return null;
}
// src/defaultUIComponents.tsx
var import_react5 = __toESM(require("react"), 1);
var import_react_dom = require("react-dom");
var import_jsx_runtime = require("react/jsx-runtime");
var SmartButton = import_react5.default.forwardRef(({ children, className, disabled, ...props }, ref) => {
const hasTextContent = import_react5.default.useMemo(() => {
const checkForText = (node) => {
if (typeof node === "string" && node.trim()) return true;
if (typeof node === "number") return true;
if (import_react5.default.isValidElement(node)) {
if (node.type === "span" || typeof node.type === "string") {
return checkForText(node.props?.children);
}
}
if (Array.isArray(node)) {
return node.some(checkForText);
}
return false;
};
return checkForText(children);
}, [children]);
const smartClassName = import_react5.default.useMemo(() => {
if (!className) return "";
if (hasTextContent) {
return className.replace(/\bsize-(\d+)\b/g, "h-$1").replace(/\bw-(\d+)\b/g, "").replace(/\s+/g, " ").trim();
}
return className;
}, [className, hasTextContent]);
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"button",
{
ref,
className: cn(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
"hover:bg-foreground/5 hover:text-accent-foreground",
'[&_svg]:pointer-events-none [&_svg:not([class*="size-"])]:size-4 [&_svg]:shrink-0',
"gap-2 px-2",
smartClassName
),
disabled,
...props,
children
}
);
});
SmartButton.displayName = "SmartButton";
var SimpleButton = import_react5.default.forwardRef(({ children, className, disabled, size = "default", ...props }, ref) => {
const hasTextContent = import_react5.default.useMemo(() => {
const checkForText = (node) => {
if (typeof node === "string" && node.trim()) return true;
if (typeof node === "number") return true;
if (import_react5.default.isValidElement(node)) {
if (node.type === "span" || typeof node.type === "string") {
return checkForText(node.props?.children);
}
}
if (Array.isArray(node)) {
return node.some(checkForText);
}
return false;
};
return checkForText(children);
}, [children]);
const getSizeClasses = () => {
switch (size) {
case "xs":
return hasTextContent ? "h-8" : "h-8 w-8";
case "default":
return hasTextContent ? "h-9 py-2" : "h-10 w-10";
case "sm":
return hasTextContent ? "h-9 rounded-md" : "h-9 w-9 rounded-md";
case "lg":
return hasTextContent ? "h-11 rounded-md" : "h-11 w-11 rounded-md";
case "icon":
return hasTextContent ? "h-10" : "h-10 w-10";
case "auto":
return "";
// No size classes, let className handle all sizing
default:
return hasTextContent ? "h-10 py-2" : "h-10 w-10";
}
};
const smartClassName = import_react5.default.useMemo(() => {
if (!className) return "";
if (hasTextContent) {
return className.replace(/\bsize-(\d+)\b/g, "h-$1").replace(/\bw-(\d+)\b/g, "").replace(/\s+/g, " ").trim();
}
return className;
}, [className, hasTextContent]);
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"button",
{
ref,
className: cn(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
"hover:bg-foreground/5 hover:text-accent-foreground",
'[&_svg]:pointer-events-none [&_svg:not([class*="size-"])]:size-4 [&_svg]:shrink-0',
"gap-2 px-2",
getSizeClasses(),
smartClassName
),
disabled,
...props,
children
}
);
});
SimpleButton.displayName = "SimpleButton";
var SimpleScrollArea = import_react5.default.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref, className: cn("relative", className), ...props, children }));
SimpleScrollArea.displayName = "SimpleScrollArea";
var PopoverContext = (0, import_react5.createContext)(null);
var SimplePopover = import_react5.default.memo(({
children,
open: controlledOpen,
onOpenChange
}) => {
const [internalOpen, setInternalOpen] = (0, import_react5.useState)(false);
const effectiveOpen = controlledOpen !== void 0 ? controlledOpen : internalOpen;
const effectiveSetOpen = (0, import_react5.useCallback)((b) => {
onOpenChange?.(b);
if (onOpenChange === void 0) setInternalOpen(b);
}, [onOpenChange]);
const triggerRef = (0, import_react5.useRef)(null);
const contentRef = (0, import_react5.useRef)(null);
const handleClickOutside = (0, import_react5.useCallback)((e) => {
if (effectiveOpen && !triggerRef.current?.contains(e.target) && !contentRef.current?.contains(e.target)) {
effectiveSetOpen(false);
}
}, [effectiveOpen, effectiveSetOpen]);
(0, import_react5.useEffect)(() => {
document.addEventListener("mousedown", handleClickOutside);
return () => document.removeEventListener("mousedown", handleClickOutside);
}, [handleClickOutside]);
const contextValue = (0, import_react5.useMemo)(() => ({
open: effectiveOpen,
setOpen: effectiveSetOpen,
triggerRef,
contentRef
}), [effectiveOpen, effectiveSetOpen]);
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PopoverContext.Provider, { value: contextValue, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "relative inline-block", children }) });
});
SimplePopover.displayName = "SimplePopover";
var SimplePopoverTrigger = import_react5.default.memo(({
children,
asChild = false
}) => {
const context = (0, import_react5.useContext)(PopoverContext);
if (!context) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children });
const { setOpen, triggerRef, open } = context;
const handleClick = (0, import_react5.useCallback)((e) => {
e.preventDefault();
setOpen(!open);
}, [setOpen, open]);
const handleRef = (0, import_react5.useCallback)((el) => {
triggerRef.current = el;
if (import_react5.default.isValidElement(children)) {
const childProps = children.props;
if (typeof childProps.ref === "function") {
childProps.ref(el);
} else if (childProps.ref) {
childProps.ref.current = el;
}
}
}, [triggerRef, children]);
if (asChild && import_react5.default.isValidElement(children)) {
const childProps = children.props;
const mergedClickHandler = (0, import_react5.useCallback)((e) => {
handleClick(e);
childProps.onClick?.(e);
}, [handleClick, childProps.onClick]);
return import_react5.default.cloneElement(
children,
{
onClick: mergedClickHandler,
ref: handleRef
}
);
}
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { onClick: handleClick, ref: handleRef, children });
});
SimplePopoverTrigger.displayName = "SimplePopoverTrigger";
var SimplePopoverContent = import_react5.default.memo(({
children,
className,
align = "center",
sideOffset = 8
}) => {
const context = (0, import_react5.useContext)(PopoverContext);
const [position, setPosition] = (0, import_react5.useState)({ top: -9999, left: -9999 });
const [measured, setMeasured] = (0, import_react5.useState)(false);
const [side, setSide] = (0, import_react5.useState)("bottom");
const innerRef = (0, import_react5.useRef)(null);
const updatePosition = (0, import_react5.useCallback)(() => {
if (!context || !context.triggerRef.current || !context.contentRef.current) return;
const triggerRect = context.triggerRef.current.getBoundingClientRect();
const contentRef = context.contentRef.current;
if (innerRef.current) {
innerRef.current.style.maxHeight = "";
innerRef.current.style.overflowY = "";
}
contentRef.style.visibility = "hidden";
const contentRect = contentRef.getBoundingClientRect();
const style2 = window.getComputedStyle(contentRef);
const paddingTop = parseFloat(style2.paddingTop);
const paddingBottom = parseFloat(style2.paddingBottom);
const borderTop = parseFloat(style2.borderTopWidth);
const borderBottom = parseFloat(style2.borderBottomWidth);
const extraVertical = paddingTop + paddingBottom + borderTop + borderBottom;
const viewportHeight = window.innerHeight;
const viewportWidth = window.innerWidth;
const edgeMargin = 8;
const spaceBelow = viewportHeight - triggerRect.bottom - sideOffset - edgeMargin;
const spaceAbove = triggerRect.top - sideOffset - edgeMargin;
let chosenSide = "bottom";
const fullHeight = contentRect.height;
if (spaceBelow < fullHeight && spaceAbove >= fullHeight) {
chosenSide = "top";
} else if (spaceBelow < fullHeight && spaceAbove < fullHeight) {
chosenSide = spaceBelow > spaceAbove ? "bottom" : "top";
}
setSide(chosenSide);
let top;
let maxHeight;
if (chosenSide === "bottom") {
top = triggerRect.bottom + sideOffset;
const available = viewportHeight - top - edgeMargin;
if (available < fullHeight) {
maxHeight = available - extraVertical;
}
} else {
top = triggerRect.top - fullHeight - sideOffset;
const available = triggerRect.top - sideOffset - edgeMargin;
if (top < edgeMargin) {
top = edgeMargin;
maxHeight = triggerRect.top - sideOffset - edgeMargin - extraVertical;
}
}
let left = triggerRect.left;
if (align === "center") {
left = triggerRect.left + triggerRect.width / 2 - contentRect.width / 2;
} else if (align === "end") {
left = triggerRect.right - contentRect.width;
}
if (left < edgeMargin) left = edgeMargin;
if (left + contentRect.width > viewportWidth - edgeMargin) {
left = viewportWidth - contentRect.width - edgeMargin;
}
setPosition({ top, left });
setMeasured(true);
if (maxHeight !== void 0 && innerRef.current) {
innerRef.current.style.maxHeight = `${Math.max(0, maxHeight)}px`;
innerRef.current.style.overflowY = "auto";
}
contentRef.style.visibility = "";
}, [align, sideOffset, context]);
(0, import_react5.useLayoutEffect)(() => {
if (context?.open) {
updatePosition();
}
}, [context?.open, updatePosition]);
const handleResize = (0, import_react5.useCallback)(() => updatePosition(), [updatePosition]);
const handleScroll = (0, import_react5.useCallback)(() => updatePosition(), [updatePosition]);
(0, import_react5.useEffect)(() => {
window.addEventListener("resize", handleResize);
window.addEventListener("scroll", handleScroll, true);
return () => {
window.removeEventListener("resize", handleResize);
window.removeEventListener("scroll", handleScroll, true);
};
}, [handleResize, handleScroll]);
const style = (0, import_react5.useMemo)(() => ({
position: "fixed",
top: `${position.top}px`,
left: `${position.left}px`,
visibility: measured ? "visible" : "hidden"
}), [position.top, position.left, measured]);
if (!context || !context.open) return null;
return (0, import_react_dom.createPortal)(
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"div",
{
ref: context.contentRef,
style,
className: cn(
"z-50 rounded-md border bg-white p-1 shadow-md",
className
),
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref: innerRef, className: "pr-2", children })
}
),
document.body
);
});
SimplePopoverContent.displayName = "SimplePopoverContent";
var SimpleTooltip = import_react5.default.memo(({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "relative group", children }));
SimpleTooltip.displayName = "SimpleTooltip";
var SimpleTooltipTrigger = import_react5.default.memo(({ children, asChild }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "inline-block", children }));
SimpleTooltipTrigger.displayName = "SimpleTooltipTrigger";
var SimpleTooltipContent = import_react5.default.memo(({ children, className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: cn(
"absolute bg-card text-card-foreground animate-in fade-in-0 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 z-50 max-w-md whitespace-nowrap rounded-sm px-3 py-3 text-xs duration-100 shadow-[0_0_0_1px_rgba(0,0,0,0.05),0_3px_6px_rgba(0,0,0,0.1),0_5px_15px_rgba(0,0,0,0.1)] hidden group-hover:block bottom-full left-1/2 -translate-x-1/2 mb-1",
className
), children }));
SimpleTooltipContent.displayName = "SimpleTooltipContent";
var SimpleSwitch = import_react5.default.memo(({ checked, onCheckedChange, className, id }) => {
const handleChange = (0, import_react5.useCallback)((e) => {
onCheckedChange?.(e.target.checked);
}, [onCheckedChange]);
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"input",
{
id,
type: "checkbox",
checked,
onChange: handleChange,
className: cn("w-4 h-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500", className),
suppressHydrationWarning: true
}
);
});
SimpleSwitch.displayName = "SimpleSwitch";
var SimpleLabel = import_react5.default.memo(({ children, htmlFor, className }) => /* @__PURE__ */ (0