bolt-table 0.1.0 → 0.1.2

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/index.js CHANGED
@@ -38,18 +38,87 @@ __export(index_exports, {
38
38
  module.exports = __toCommonJS(index_exports);
39
39
 
40
40
  // src/BoltTable.tsx
41
- var import_core = require("@dnd-kit/core");
42
- var import_sortable2 = require("@dnd-kit/sortable");
43
41
  var import_react_virtual = require("@tanstack/react-virtual");
44
- var import_lucide_react2 = require("lucide-react");
45
42
  var import_react4 = __toESM(require("react"));
43
+ var import_react_dom2 = require("react-dom");
46
44
 
47
45
  // src/DraggableHeader.tsx
48
- var import_sortable = require("@dnd-kit/sortable");
49
- var import_lucide_react = require("lucide-react");
50
46
  var import_react = __toESM(require("react"));
51
47
  var import_react_dom = require("react-dom");
48
+
49
+ // src/icons.tsx
52
50
  var import_jsx_runtime = require("react/jsx-runtime");
51
+ var svgBase = {
52
+ xmlns: "http://www.w3.org/2000/svg",
53
+ width: 24,
54
+ height: 24,
55
+ viewBox: "0 0 24 24",
56
+ fill: "none",
57
+ stroke: "currentColor",
58
+ strokeWidth: 2,
59
+ strokeLinecap: "round",
60
+ strokeLinejoin: "round"
61
+ };
62
+ var GripVerticalIcon = ({ style, className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...svgBase, style, className, children: [
63
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "9", cy: "12", r: "1" }),
64
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "9", cy: "5", r: "1" }),
65
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "9", cy: "19", r: "1" }),
66
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "15", cy: "12", r: "1" }),
67
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "15", cy: "5", r: "1" }),
68
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "15", cy: "19", r: "1" })
69
+ ] });
70
+ var ChevronDownIcon = ({ style, className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { ...svgBase, style, className, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m6 9 6 6 6-6" }) });
71
+ var ChevronLeftIcon = ({ style, className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { ...svgBase, style, className, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m15 18-6-6 6-6" }) });
72
+ var ChevronRightIcon = ({ style, className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { ...svgBase, style, className, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m9 18 6-6-6-6" }) });
73
+ var ChevronsLeftIcon = ({ style, className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...svgBase, style, className, children: [
74
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m11 17-5-5 5-5" }),
75
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m18 17-5-5 5-5" })
76
+ ] });
77
+ var ChevronsRightIcon = ({
78
+ style,
79
+ className
80
+ }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...svgBase, style, className, children: [
81
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m6 17 5-5-5-5" }),
82
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m13 17 5-5-5-5" })
83
+ ] });
84
+ var ArrowUpAZIcon = ({ style, className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...svgBase, style, className, children: [
85
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m3 8 4-4 4 4" }),
86
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M7 4v16" }),
87
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M20 8h-5" }),
88
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M15 10V6.5a2.5 2.5 0 0 1 5 0V10" }),
89
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M15 14h5l-5 6h5" })
90
+ ] });
91
+ var ArrowDownAZIcon = ({ style, className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...svgBase, style, className, children: [
92
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m3 16 4 4 4-4" }),
93
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M7 20V4" }),
94
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M20 8h-5" }),
95
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M15 10V6.5a2.5 2.5 0 0 1 5 0V10" }),
96
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M15 14h5l-5 6h5" })
97
+ ] });
98
+ var FilterIcon = ({ style, className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { ...svgBase, style, className, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("polygon", { points: "22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3" }) });
99
+ var FilterXIcon = ({ style, className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...svgBase, style, className, children: [
100
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M13.013 3H2l8 9.46V19l4 2v-8.54l.9-1.055" }),
101
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m22 3-5 5" }),
102
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m17 3 5 5" })
103
+ ] });
104
+ var PinIcon = ({ style, className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...svgBase, style, className, children: [
105
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "12", x2: "12", y1: "17", y2: "22" }),
106
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M5 17h14v-1.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V6h1a2 2 0 0 0 0-4H8a2 2 0 0 0 0 4h1v4.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24Z" })
107
+ ] });
108
+ var PinOffIcon = ({ style, className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...svgBase, style, className, children: [
109
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "2", x2: "22", y1: "2", y2: "22" }),
110
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "12", x2: "12", y1: "17", y2: "22" }),
111
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M9 9v1.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V17h14v-1.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V6h1a2 2 0 0 0 0-4H8a2 2 0 0 0 0 4" })
112
+ ] });
113
+ var EyeOffIcon = ({ style, className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...svgBase, style, className, children: [
114
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M9.88 9.88a3 3 0 1 0 4.24 4.24" }),
115
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M10.73 5.08A10.43 10.43 0 0 1 12 5c7 0 10 7 10 7a13.16 13.16 0 0 1-1.67 2.68" }),
116
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M6.61 6.61A13.526 13.526 0 0 0 2 12s3 7 10 7a9.74 9.74 0 0 0 5.39-1.61" }),
117
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "2", x2: "22", y1: "2", y2: "22" })
118
+ ] });
119
+
120
+ // src/DraggableHeader.tsx
121
+ var import_jsx_runtime2 = require("react/jsx-runtime");
53
122
  function isColumnSortable(col) {
54
123
  return col.sortable !== false;
55
124
  }
@@ -75,7 +144,9 @@ var DraggableHeader = import_react.default.memo(
75
144
  filterValue = "",
76
145
  onFilter,
77
146
  onClearFilter,
78
- customContextMenuItems
147
+ customContextMenuItems,
148
+ icons,
149
+ onColumnDragStart
79
150
  }) => {
80
151
  const effectivelySortable = isColumnSortable(column);
81
152
  const effectivelyFilterable = isColumnFilterable(column);
@@ -83,21 +154,6 @@ var DraggableHeader = import_react.default.memo(
83
154
  const [showFilterInput, setShowFilterInput] = (0, import_react.useState)(false);
84
155
  const filterInputRef = (0, import_react.useRef)(null);
85
156
  const menuRef = (0, import_react.useRef)(null);
86
- const {
87
- attributes,
88
- listeners,
89
- setNodeRef,
90
- transition,
91
- isDragging,
92
- // true while this header is being dragged
93
- isOver
94
- // true while another header is being dragged over this one
95
- } = (0, import_sortable.useSortable)({
96
- id: column.key,
97
- // Pinned columns cannot be dragged (their position is fixed by pinning)
98
- disabled: Boolean(column.pinned)
99
- });
100
- const theme = typeof document !== "undefined" && document.documentElement.classList.contains("dark") ? "dark" : "light";
101
157
  (0, import_react.useEffect)(() => {
102
158
  const handleClickOutside = (e) => {
103
159
  if (menuRef.current && !menuRef.current.contains(e.target)) {
@@ -133,95 +189,121 @@ var DraggableHeader = import_react.default.memo(
133
189
  const columnWidth = column.width ?? 150;
134
190
  const widthPx = `${columnWidth}px`;
135
191
  const isPinned = Boolean(column.pinned);
136
- const zIndex = isDragging ? 5 : isPinned ? 12 : 10;
137
- const style = {
192
+ const zIndex = isPinned ? 12 : 10;
193
+ const headerStyle = {
138
194
  position: "sticky",
139
195
  top: 0,
140
196
  zIndex,
141
- // Last column stretches to fill remaining space; all others are fixed width
142
197
  width: isLastColumn ? "100%" : widthPx,
143
198
  minWidth: widthPx,
144
199
  ...isLastColumn ? {} : { maxWidth: widthPx },
145
200
  gridColumn: visualIndex + 1,
146
201
  gridRow: 1,
147
- // Fade out slightly while being dragged
148
- opacity: isDragging ? 0.3 : 1,
149
- transition,
150
- borderWidth: "1px",
151
- // Show a dashed accent-colored border when another column is dragged over this one
152
- borderStyle: isOver ? "dashed" : "solid",
153
- ...isOver ? { borderColor: accentColor || "#1788ff" } : { borderLeftColor: "transparent" },
154
- // Sticky positioning for pinned columns
155
- ...column.pinned === "left" && stickyOffset !== void 0 ? { left: `${stickyOffset}px`, position: "sticky" } : {},
156
- ...column.pinned === "right" && stickyOffset !== void 0 ? { right: `${stickyOffset}px`, position: "sticky" } : {},
157
- // Pinned columns get a semi-transparent background so they visually
158
- // separate from scrolling content behind them
202
+ borderTop: "none",
203
+ borderRight: "none",
204
+ borderBottom: "1px solid rgba(128,128,128,0.2)",
205
+ borderLeft: "none",
206
+ ...column.pinned === "left" && stickyOffset !== void 0 ? { left: `${stickyOffset}px` } : {},
207
+ ...column.pinned === "right" && stickyOffset !== void 0 ? { right: `${stickyOffset}px` } : {},
159
208
  ...isPinned ? {
160
- backgroundColor: styles?.pinnedBg ?? theme === "dark" ? "#10182890" : "#f9fafb90",
209
+ backgroundColor: styles?.pinnedBg ?? "Canvas",
161
210
  ...styles?.pinnedHeader
162
211
  } : {},
163
- // Column-level style overrides applied last (highest specificity)
164
212
  ...column.style,
165
- ...styles?.header
213
+ ...styles?.header,
214
+ backgroundColor: styles?.pinnedBg && isPinned ? styles.pinnedBg : isPinned ? "Canvas" : "rgba(128,128,128,0.06)",
215
+ display: "flex",
216
+ height: 36,
217
+ alignItems: "center",
218
+ overflow: "hidden",
219
+ textOverflow: "ellipsis",
220
+ whiteSpace: "nowrap",
221
+ ...isPinned ? {} : { backdropFilter: "blur(8px)", WebkitBackdropFilter: "blur(8px)" }
166
222
  };
167
- const baseClasses = "bg-muted/40 group relative truncate flex h-9 items-center overflow-hidden backdrop-blur ";
168
- const className = `${baseClasses} ${column.className ?? ""} ${classNames?.header ?? ""} ${classNames?.pinnedHeader ?? ""} `;
169
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
170
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
223
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
224
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
171
225
  "div",
172
226
  {
173
- ref: setNodeRef,
174
227
  "data-column-key": column.key,
175
- style,
176
- className,
228
+ "data-bt-header": "",
229
+ style: headerStyle,
230
+ className: `${column.className ?? ""} ${classNames?.header ?? ""} ${isPinned ? classNames?.pinnedHeader ?? "" : ""}`,
177
231
  onContextMenu: handleContextMenu,
178
232
  children: [
179
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
233
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
180
234
  "div",
181
235
  {
182
- ...isPinned ? {} : attributes,
183
- ...isPinned ? {} : listeners,
184
- className: `group relative z-10 flex h-full flex-1 touch-none items-center gap-1 truncate overflow-hidden px-2 font-medium ${isPinned ? "cursor-default" : "cursor-grab active:cursor-grabbing"}`,
236
+ role: isPinned ? void 0 : "button",
237
+ tabIndex: isPinned ? void 0 : 0,
238
+ "aria-roledescription": isPinned ? void 0 : "sortable",
239
+ onPointerDown: isPinned ? void 0 : (e) => {
240
+ if (e.button !== 0) return;
241
+ e.preventDefault();
242
+ onColumnDragStart?.(column.key, e);
243
+ },
244
+ style: {
245
+ position: "relative",
246
+ zIndex: 10,
247
+ display: "flex",
248
+ height: "100%",
249
+ flex: "1 1 0%",
250
+ touchAction: "none",
251
+ alignItems: "center",
252
+ gap: 4,
253
+ overflow: "hidden",
254
+ textOverflow: "ellipsis",
255
+ whiteSpace: "nowrap",
256
+ paddingLeft: 8,
257
+ paddingRight: 8,
258
+ borderLeft: "1px solid rgba(128,128,128,0.2)",
259
+ fontWeight: 500,
260
+ cursor: isPinned ? "default" : "grab"
261
+ },
185
262
  "aria-label": isPinned ? `${column.key} column (pinned)` : `Drag ${column.key} column`,
186
263
  children: [
187
- hideGripIcon || isPinned ? null : gripIcon ?? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.GripVertical, { className: "h-3 w-3 shrink-0 opacity-35 group-hover:opacity-80" }),
188
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
264
+ hideGripIcon || isPinned ? null : icons?.gripVertical ?? gripIcon ?? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { "data-bt-grip": "", style: { opacity: 0.35, flexShrink: 0, display: "flex" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(GripVerticalIcon, { style: { width: 12, height: 12 } }) }),
265
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
189
266
  "div",
190
267
  {
191
- className: `flex min-w-0 items-center gap-1 truncate overflow-hidden text-left select-none`,
268
+ style: {
269
+ display: "flex",
270
+ minWidth: 0,
271
+ alignItems: "center",
272
+ gap: 4,
273
+ overflow: "hidden",
274
+ textOverflow: "ellipsis",
275
+ whiteSpace: "nowrap",
276
+ textAlign: "left",
277
+ userSelect: "none"
278
+ },
192
279
  children: [
193
280
  column.title,
194
- sortDirection === "asc" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
195
- import_lucide_react.ArrowUpAZ,
196
- {
197
- className: "h-3 w-3 shrink-0",
198
- style: { color: accentColor }
199
- }
200
- ),
201
- sortDirection === "desc" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
202
- import_lucide_react.ArrowDownAZ,
203
- {
204
- className: "h-3 w-3 shrink-0",
205
- style: { color: accentColor }
206
- }
207
- ),
208
- filterValue && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
209
- import_lucide_react.Filter,
210
- {
211
- className: "h-2.5 w-2.5 shrink-0",
212
- style: { color: accentColor }
213
- }
214
- )
281
+ sortDirection === "asc" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: accentColor, flexShrink: 0, display: "flex" }, children: icons?.sortAsc ?? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ArrowUpAZIcon, { style: { width: 12, height: 12 } }) }),
282
+ sortDirection === "desc" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: accentColor, flexShrink: 0, display: "flex" }, children: icons?.sortDesc ?? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ArrowDownAZIcon, { style: { width: 12, height: 12 } }) }),
283
+ filterValue && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: accentColor, flexShrink: 0, display: "flex" }, children: icons?.filter ?? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(FilterIcon, { style: { width: 10, height: 10 } }) })
215
284
  ]
216
285
  }
217
286
  )
218
287
  ]
219
288
  }
220
289
  ),
221
- isPinned && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
290
+ isPinned && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
222
291
  "button",
223
292
  {
224
- className: "group/unpin relative h-full w-6 shrink-0 cursor-pointer border-0 bg-transparent p-0",
293
+ style: {
294
+ position: "relative",
295
+ height: "100%",
296
+ width: 24,
297
+ flexShrink: 0,
298
+ cursor: "pointer",
299
+ border: "none",
300
+ background: "transparent",
301
+ padding: 0,
302
+ color: accentColor || "#1788ff",
303
+ display: "flex",
304
+ alignItems: "center",
305
+ justifyContent: "center"
306
+ },
225
307
  onClick: (e) => {
226
308
  e.preventDefault();
227
309
  e.stopPropagation();
@@ -229,21 +311,37 @@ var DraggableHeader = import_react.default.memo(
229
311
  },
230
312
  "aria-label": `Unpin ${column.key} column`,
231
313
  title: "Unpin column",
232
- style: { color: accentColor || "1788ff" },
233
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.PinOff, { className: "mx-auto h-3 w-3" })
314
+ children: icons?.pinOff ?? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PinOffIcon, { style: { width: 12, height: 12 } })
234
315
  }
235
316
  ),
236
- !isPinned && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
317
+ !isPinned && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
237
318
  "button",
238
319
  {
239
- className: "group/resize relative h-full w-3 shrink-0 cursor-col-resize border-0 bg-transparent p-0",
320
+ "data-bt-resize": "",
321
+ style: {
322
+ position: "relative",
323
+ height: "100%",
324
+ width: 12,
325
+ flexShrink: 0,
326
+ cursor: "col-resize",
327
+ border: "none",
328
+ background: "transparent",
329
+ padding: 0
330
+ },
240
331
  onMouseDown: handleResizeStart,
241
332
  "aria-label": `Resize ${column.key} column`,
242
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
333
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
243
334
  "div",
244
335
  {
245
- className: "absolute top-0 right-0 h-full w-0.5 opacity-0 transition-opacity group-hover/resize:opacity-100",
336
+ "data-bt-resize-line": "",
246
337
  style: {
338
+ position: "absolute",
339
+ top: 0,
340
+ right: 0,
341
+ height: "100%",
342
+ width: 2,
343
+ opacity: 0,
344
+ transition: "opacity 0.15s",
247
345
  backgroundColor: accentColor || "#1788ff"
248
346
  }
249
347
  }
@@ -254,113 +352,212 @@ var DraggableHeader = import_react.default.memo(
254
352
  }
255
353
  ),
256
354
  contextMenu && typeof document !== "undefined" && (0, import_react_dom.createPortal)(
257
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
355
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
258
356
  "div",
259
357
  {
260
358
  ref: menuRef,
261
- className: "text-xxs fixed z-[9999] min-w-40 rounded-md border py-1 shadow-lg backdrop-blur",
262
359
  style: {
360
+ fontSize: 10,
361
+ position: "fixed",
362
+ zIndex: 9999,
363
+ minWidth: 160,
364
+ borderRadius: 6,
365
+ border: "1px solid rgba(128,128,128,0.2)",
366
+ paddingTop: 4,
367
+ paddingBottom: 4,
368
+ boxShadow: "0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -4px rgba(0,0,0,0.1)",
369
+ backdropFilter: "blur(12px)",
370
+ backgroundColor: "rgba(128,128,128,0.1)",
263
371
  left: `${contextMenu.x}px`,
264
- top: `${contextMenu.y}px`,
265
- position: "fixed"
372
+ top: `${contextMenu.y}px`
266
373
  },
267
374
  role: "menu",
268
375
  children: [
269
- effectivelySortable && onSort && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
270
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
376
+ effectivelySortable && onSort && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
377
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
271
378
  "button",
272
379
  {
273
- className: `cusror-pointer flex w-full items-center gap-2 px-3 py-1.5 text-left ${sortDirection === "asc" ? "font-semibold" : ""}`,
274
- style: sortDirection === "asc" ? { color: accentColor } : void 0,
380
+ "data-bt-ctx-item": "",
381
+ style: {
382
+ cursor: "pointer",
383
+ display: "flex",
384
+ width: "100%",
385
+ alignItems: "center",
386
+ gap: 8,
387
+ paddingLeft: 12,
388
+ paddingRight: 12,
389
+ paddingTop: 6,
390
+ paddingBottom: 6,
391
+ textAlign: "left",
392
+ background: "none",
393
+ border: "none",
394
+ fontSize: "inherit",
395
+ color: "inherit",
396
+ fontWeight: sortDirection === "asc" ? 600 : void 0,
397
+ ...sortDirection === "asc" ? { color: accentColor } : {}
398
+ },
275
399
  onClick: () => {
276
400
  onSort(column.key, "asc");
277
401
  setContextMenu(null);
278
402
  },
279
403
  children: [
280
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ArrowUpAZ, { className: "h-3 w-3" }),
404
+ icons?.sortAsc ?? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ArrowUpAZIcon, { style: { width: 12, height: 12 } }),
281
405
  "Sort Ascending"
282
406
  ]
283
407
  }
284
408
  ),
285
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
409
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
286
410
  "button",
287
411
  {
288
- className: `cusror-pointer flex w-full items-center gap-2 px-3 py-1.5 text-left ${sortDirection === "desc" ? "font-semibold" : ""}`,
289
- style: sortDirection === "desc" ? { color: accentColor } : void 0,
412
+ "data-bt-ctx-item": "",
413
+ style: {
414
+ cursor: "pointer",
415
+ display: "flex",
416
+ width: "100%",
417
+ alignItems: "center",
418
+ gap: 8,
419
+ paddingLeft: 12,
420
+ paddingRight: 12,
421
+ paddingTop: 6,
422
+ paddingBottom: 6,
423
+ textAlign: "left",
424
+ background: "none",
425
+ border: "none",
426
+ fontSize: "inherit",
427
+ color: "inherit",
428
+ fontWeight: sortDirection === "desc" ? 600 : void 0,
429
+ ...sortDirection === "desc" ? { color: accentColor } : {}
430
+ },
290
431
  onClick: () => {
291
432
  onSort(column.key, "desc");
292
433
  setContextMenu(null);
293
434
  },
294
435
  children: [
295
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ArrowDownAZ, { className: "h-3 w-3" }),
436
+ icons?.sortDesc ?? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ArrowDownAZIcon, { style: { width: 12, height: 12 } }),
296
437
  "Sort Descending"
297
438
  ]
298
439
  }
299
440
  ),
300
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "my-1 border-t dark:border-gray-700" })
441
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { marginTop: 4, marginBottom: 4, borderTop: "1px solid rgba(128,128,128,0.2)" } })
301
442
  ] }),
302
- effectivelyFilterable && onFilter && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
303
- showFilterInput ? (
304
- // Inline text input — pressing Enter applies the filter,
305
- // pressing Escape cancels and returns to the button
306
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex items-center gap-1 px-2 py-1.5", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
307
- "input",
308
- {
309
- ref: filterInputRef,
310
- type: "text",
311
- autoFocus: true,
312
- defaultValue: filterValue,
313
- placeholder: "Filter...",
314
- className: "bg-background text-foreground w-full rounded border px-1.5 py-0.5 text-xs outline-none focus:border-blue-400",
315
- onKeyDown: (e) => {
316
- if (e.key === "Enter") {
317
- onFilter(
318
- column.key,
319
- e.target.value
320
- );
321
- setShowFilterInput(false);
322
- setContextMenu(null);
323
- }
324
- if (e.key === "Escape") {
325
- setShowFilterInput(false);
326
- }
443
+ effectivelyFilterable && onFilter && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
444
+ showFilterInput ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { display: "flex", alignItems: "center", gap: 4, paddingLeft: 8, paddingRight: 8, paddingTop: 6, paddingBottom: 6 }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
445
+ "input",
446
+ {
447
+ ref: filterInputRef,
448
+ type: "text",
449
+ autoFocus: true,
450
+ defaultValue: filterValue,
451
+ placeholder: "Filter...",
452
+ style: {
453
+ width: "100%",
454
+ borderRadius: 4,
455
+ border: "1px solid rgba(128,128,128,0.2)",
456
+ paddingLeft: 6,
457
+ paddingRight: 6,
458
+ paddingTop: 2,
459
+ paddingBottom: 2,
460
+ fontSize: 12,
461
+ outline: "none",
462
+ background: "inherit",
463
+ color: "inherit"
464
+ },
465
+ onKeyDown: (e) => {
466
+ if (e.key === "Enter") {
467
+ onFilter(
468
+ column.key,
469
+ e.target.value
470
+ );
471
+ setShowFilterInput(false);
472
+ setContextMenu(null);
473
+ }
474
+ if (e.key === "Escape") {
475
+ setShowFilterInput(false);
327
476
  }
328
477
  }
329
- ) })
330
- ) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
478
+ }
479
+ ) }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
331
480
  "button",
332
481
  {
333
- className: "cusror-pointer flex w-full items-center gap-2 px-3 py-1.5 text-left",
482
+ "data-bt-ctx-item": "",
483
+ style: {
484
+ cursor: "pointer",
485
+ display: "flex",
486
+ width: "100%",
487
+ alignItems: "center",
488
+ gap: 8,
489
+ paddingLeft: 12,
490
+ paddingRight: 12,
491
+ paddingTop: 6,
492
+ paddingBottom: 6,
493
+ textAlign: "left",
494
+ background: "none",
495
+ border: "none",
496
+ fontSize: "inherit",
497
+ color: "inherit"
498
+ },
334
499
  onClick: () => {
335
500
  setShowFilterInput(true);
336
501
  },
337
502
  children: [
338
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Filter, { className: "h-3 w-3" }),
503
+ icons?.filter ?? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(FilterIcon, { style: { width: 12, height: 12 } }),
339
504
  filterValue ? `Filtered: "${filterValue}"` : "Filter Column"
340
505
  ]
341
506
  }
342
507
  ),
343
- filterValue && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
508
+ filterValue && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
344
509
  "button",
345
510
  {
346
- className: "cusror-pointer flex w-full items-center gap-2 px-3 py-1.5 text-left text-red-500",
511
+ "data-bt-ctx-item": "",
512
+ style: {
513
+ cursor: "pointer",
514
+ display: "flex",
515
+ width: "100%",
516
+ alignItems: "center",
517
+ gap: 8,
518
+ paddingLeft: 12,
519
+ paddingRight: 12,
520
+ paddingTop: 6,
521
+ paddingBottom: 6,
522
+ textAlign: "left",
523
+ background: "none",
524
+ border: "none",
525
+ fontSize: "inherit",
526
+ color: "#ef4444"
527
+ },
347
528
  onClick: () => {
348
529
  onClearFilter?.(column.key);
349
530
  setShowFilterInput(false);
350
531
  setContextMenu(null);
351
532
  },
352
533
  children: [
353
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.FilterX, { className: "h-3 w-3" }),
534
+ icons?.filterClear ?? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(FilterXIcon, { style: { width: 12, height: 12 } }),
354
535
  "Clear Filter"
355
536
  ]
356
537
  }
357
538
  ),
358
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "my-1 border-t dark:border-gray-700" })
539
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { marginTop: 4, marginBottom: 4, borderTop: "1px solid rgba(128,128,128,0.2)" } })
359
540
  ] }),
360
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
541
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
361
542
  "button",
362
543
  {
363
- className: "cusror-pointer flex w-full items-center gap-2 px-3 py-1.5 text-left",
544
+ "data-bt-ctx-item": "",
545
+ style: {
546
+ cursor: "pointer",
547
+ display: "flex",
548
+ width: "100%",
549
+ alignItems: "center",
550
+ gap: 8,
551
+ paddingLeft: 12,
552
+ paddingRight: 12,
553
+ paddingTop: 6,
554
+ paddingBottom: 6,
555
+ textAlign: "left",
556
+ background: "none",
557
+ border: "none",
558
+ fontSize: "inherit",
559
+ color: "inherit"
560
+ },
364
561
  onClick: () => {
365
562
  onTogglePin?.(
366
563
  column.key,
@@ -369,15 +566,31 @@ var DraggableHeader = import_react.default.memo(
369
566
  setContextMenu(null);
370
567
  },
371
568
  children: [
372
- column.pinned === "left" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.PinOff, { className: "h-3 w-3" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Pin, { className: "h-3 w-3" }),
569
+ column.pinned === "left" ? icons?.pinOff ?? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PinOffIcon, { style: { width: 12, height: 12 } }) : icons?.pin ?? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PinIcon, { style: { width: 12, height: 12 } }),
373
570
  column.pinned === "left" ? "Unpin Left" : "Pin Left"
374
571
  ]
375
572
  }
376
573
  ),
377
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
574
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
378
575
  "button",
379
576
  {
380
- className: "cusror-pointer flex w-full items-center gap-2 px-3 py-1.5 text-left",
577
+ "data-bt-ctx-item": "",
578
+ style: {
579
+ cursor: "pointer",
580
+ display: "flex",
581
+ width: "100%",
582
+ alignItems: "center",
583
+ gap: 8,
584
+ paddingLeft: 12,
585
+ paddingRight: 12,
586
+ paddingTop: 6,
587
+ paddingBottom: 6,
588
+ textAlign: "left",
589
+ background: "none",
590
+ border: "none",
591
+ fontSize: "inherit",
592
+ color: "inherit"
593
+ },
381
594
  onClick: () => {
382
595
  onTogglePin?.(
383
596
  column.key,
@@ -386,41 +599,74 @@ var DraggableHeader = import_react.default.memo(
386
599
  setContextMenu(null);
387
600
  },
388
601
  children: [
389
- column.pinned === "right" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.PinOff, { className: "h-3 w-3" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Pin, { className: "h-3 w-3" }),
602
+ column.pinned === "right" ? icons?.pinOff ?? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PinOffIcon, { style: { width: 12, height: 12 } }) : icons?.pin ?? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PinIcon, { style: { width: 12, height: 12 } }),
390
603
  column.pinned === "right" ? "Unpin Right" : "Pin Right"
391
604
  ]
392
605
  }
393
606
  ),
394
- !isPinned && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
395
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "my-1 border-t dark:border-gray-700" }),
396
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
607
+ !isPinned && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
608
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { marginTop: 4, marginBottom: 4, borderTop: "1px solid rgba(128,128,128,0.2)" } }),
609
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
397
610
  "button",
398
611
  {
399
- className: "cusror-pointer flex w-full items-center gap-2 px-3 py-1.5 text-left",
612
+ "data-bt-ctx-item": "",
613
+ style: {
614
+ cursor: "pointer",
615
+ display: "flex",
616
+ width: "100%",
617
+ alignItems: "center",
618
+ gap: 8,
619
+ paddingLeft: 12,
620
+ paddingRight: 12,
621
+ paddingTop: 6,
622
+ paddingBottom: 6,
623
+ textAlign: "left",
624
+ background: "none",
625
+ border: "none",
626
+ fontSize: "inherit",
627
+ color: "inherit"
628
+ },
400
629
  onClick: () => {
401
630
  onToggleHide?.(column.key);
402
631
  setContextMenu(null);
403
632
  },
404
633
  children: [
405
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.EyeOff, { className: "h-3 w-3" }),
634
+ icons?.eyeOff ?? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(EyeOffIcon, { style: { width: 12, height: 12 } }),
406
635
  "Hide Column"
407
636
  ]
408
637
  }
409
638
  )
410
639
  ] }),
411
- customContextMenuItems && customContextMenuItems.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
412
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "my-1 border-t dark:border-gray-700" }),
413
- customContextMenuItems.map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
640
+ customContextMenuItems && customContextMenuItems.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
641
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { marginTop: 4, marginBottom: 4, borderTop: "1px solid rgba(128,128,128,0.2)" } }),
642
+ customContextMenuItems.map((item) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
414
643
  "button",
415
644
  {
645
+ "data-bt-ctx-item": "",
416
646
  disabled: item.disabled,
417
- className: `flex w-full items-center gap-2 px-3 py-1.5 text-left ${item.disabled ? "cursor-not-allowed opacity-50" : "cusror-pointer"} ${item.danger ? "text-red-500" : ""}`,
647
+ style: {
648
+ display: "flex",
649
+ width: "100%",
650
+ alignItems: "center",
651
+ gap: 8,
652
+ paddingLeft: 12,
653
+ paddingRight: 12,
654
+ paddingTop: 6,
655
+ paddingBottom: 6,
656
+ textAlign: "left",
657
+ background: "none",
658
+ border: "none",
659
+ fontSize: "inherit",
660
+ cursor: item.disabled ? "not-allowed" : "pointer",
661
+ opacity: item.disabled ? 0.5 : 1,
662
+ color: item.danger ? "#ef4444" : "inherit"
663
+ },
418
664
  onClick: () => {
419
665
  item.onClick(column.key);
420
666
  setContextMenu(null);
421
667
  },
422
668
  children: [
423
- item.icon && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "flex h-3 w-3 items-center justify-center", children: item.icon }),
669
+ item.icon && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { display: "flex", width: 12, height: 12, alignItems: "center", justifyContent: "center" }, children: item.icon }),
424
670
  item.label
425
671
  ]
426
672
  },
@@ -446,7 +692,7 @@ var DraggableHeader_default = DraggableHeader;
446
692
 
447
693
  // src/ResizeOverlay.tsx
448
694
  var import_react2 = require("react");
449
- var import_jsx_runtime2 = require("react/jsx-runtime");
695
+ var import_jsx_runtime3 = require("react/jsx-runtime");
450
696
  var ResizeOverlay = (0, import_react2.forwardRef)(
451
697
  ({ accentColor = "#1778ff" }, ref) => {
452
698
  const lineRef = (0, import_react2.useRef)(null);
@@ -527,8 +773,8 @@ var ResizeOverlay = (0, import_react2.forwardRef)(
527
773
  const b = parseInt(hex.slice(5, 7), 16);
528
774
  return `rgba(${r}, ${g}, ${b}, ${opacity})`;
529
775
  };
530
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
531
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
776
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
777
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
532
778
  "div",
533
779
  {
534
780
  ref: lineRef,
@@ -548,7 +794,7 @@ var ResizeOverlay = (0, import_react2.forwardRef)(
548
794
  }
549
795
  }
550
796
  ),
551
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
797
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
552
798
  "div",
553
799
  {
554
800
  ref: labelRef,
@@ -582,7 +828,7 @@ var ResizeOverlay_default = ResizeOverlay;
582
828
 
583
829
  // src/TableBody.tsx
584
830
  var import_react3 = __toESM(require("react"));
585
- var import_jsx_runtime3 = require("react/jsx-runtime");
831
+ var import_jsx_runtime4 = require("react/jsx-runtime");
586
832
  var SHIMMER_WIDTHS = [55, 70, 45, 80, 60, 50, 75, 65];
587
833
  var Cell = import_react3.default.memo(
588
834
  ({
@@ -600,26 +846,33 @@ var Cell = import_react3.default.memo(
600
846
  accentColor,
601
847
  isLoading
602
848
  }) => {
603
- const justifyClass = column.key === "__select__" || column.key === "__expand__" ? "justify-center" : "";
604
849
  const isPinned = Boolean(column.pinned);
605
850
  if (isLoading && column.key !== "__select__" && column.key !== "__expand__") {
606
- const shimmerContent = column.shimmerRender ? column.shimmerRender() : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
851
+ const shimmerContent = column.shimmerRender ? column.shimmerRender() : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
607
852
  "div",
608
853
  {
609
- className: "bg-muted-foreground/15 animate-pulse rounded",
610
854
  style: {
611
- // Vary widths across cells so skeletons look more natural
855
+ backgroundColor: "rgba(100, 116, 139, 0.15)",
856
+ animation: "bt-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite",
857
+ borderRadius: 4,
612
858
  width: `${SHIMMER_WIDTHS[(rowIndex + column.key.length) % SHIMMER_WIDTHS.length]}%`,
613
859
  height: 14
614
860
  }
615
861
  }
616
862
  );
617
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
863
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
618
864
  "div",
619
865
  {
620
- className: `flex items-center overflow-hidden border-b px-2 ${column.className ?? ""} ${classNames?.cell ?? ""} ${isPinned ? classNames?.pinnedCell ?? "" : ""}`,
866
+ className: `${column.className ?? ""} ${classNames?.cell ?? ""} ${isPinned ? classNames?.pinnedCell ?? "" : ""}`,
621
867
  style: {
868
+ display: "flex",
869
+ alignItems: "center",
870
+ overflow: "hidden",
871
+ borderBottom: "1px solid rgba(128,128,128,0.2)",
872
+ paddingLeft: 8,
873
+ paddingRight: 8,
622
874
  height: "100%",
875
+ boxSizing: "border-box",
623
876
  ...column.style,
624
877
  ...isPinned ? styles?.pinnedCell : void 0
625
878
  },
@@ -631,7 +884,7 @@ var Cell = import_react3.default.memo(
631
884
  const checkboxProps = rowSelection.getCheckboxProps?.(record) ?? {
632
885
  disabled: false
633
886
  };
634
- const content2 = rowSelection.type === "radio" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
887
+ const content2 = rowSelection.type === "radio" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
635
888
  "input",
636
889
  {
637
890
  type: "radio",
@@ -642,10 +895,9 @@ var Cell = import_react3.default.memo(
642
895
  rowSelection.onSelect?.(record, true, [record], e.nativeEvent);
643
896
  rowSelection.onChange?.([rowKey], [record], { type: "single" });
644
897
  },
645
- className: "cursor-pointer",
646
- style: { accentColor }
898
+ style: { cursor: "pointer", accentColor }
647
899
  }
648
- ) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
900
+ ) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
649
901
  "input",
650
902
  {
651
903
  type: "checkbox",
@@ -672,16 +924,23 @@ var Cell = import_react3.default.memo(
672
924
  type: "multiple"
673
925
  });
674
926
  },
675
- className: "cursor-pointer",
676
- style: { accentColor }
927
+ style: { cursor: "pointer", accentColor }
677
928
  }
678
929
  );
679
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
930
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
680
931
  "div",
681
932
  {
682
- className: `flex items-center overflow-hidden border-b px-2 ${justifyClass} ${column.className ?? ""} ${classNames?.cell ?? ""} `,
933
+ className: `${column.className ?? ""} ${classNames?.cell ?? ""}`,
683
934
  style: {
935
+ display: "flex",
936
+ alignItems: "center",
937
+ overflow: "hidden",
938
+ borderBottom: "1px solid rgba(128,128,128,0.2)",
939
+ paddingLeft: 8,
940
+ paddingRight: 8,
941
+ justifyContent: column.key === "__select__" || column.key === "__expand__" ? "center" : void 0,
684
942
  height: "100%",
943
+ boxSizing: "border-box",
685
944
  ...column.style,
686
945
  ...isPinned ? styles?.pinnedCell : void 0
687
946
  },
@@ -690,12 +949,22 @@ var Cell = import_react3.default.memo(
690
949
  );
691
950
  }
692
951
  const content = column.render ? column.render(value, record, rowIndex) : value ?? "";
693
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
952
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
694
953
  "div",
695
954
  {
696
- className: `flex items-center truncate overflow-hidden border-b px-2 ${justifyClass} ${column.className ?? ""} ${classNames?.cell ?? ""} `,
955
+ className: `${column.className ?? ""} ${classNames?.cell ?? ""}`,
697
956
  style: {
957
+ display: "flex",
958
+ alignItems: "center",
959
+ overflow: "hidden",
960
+ textOverflow: "ellipsis",
961
+ whiteSpace: "nowrap",
962
+ borderBottom: "1px solid rgba(128,128,128,0.2)",
963
+ paddingLeft: 8,
964
+ paddingRight: 8,
965
+ justifyContent: column.key === "__select__" || column.key === "__expand__" ? "center" : void 0,
698
966
  height: "100%",
967
+ boxSizing: "border-box",
699
968
  ...column.style,
700
969
  ...isPinned ? styles?.pinnedCell : void 0
701
970
  },
@@ -743,7 +1012,7 @@ var MeasuredExpandedRow = import_react3.default.memo(
743
1012
  observer.observe(el);
744
1013
  return () => observer.disconnect();
745
1014
  }, [rowKey]);
746
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { ref, children });
1015
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { ref, children });
747
1016
  }
748
1017
  );
749
1018
  MeasuredExpandedRow.displayName = "MeasuredExpandedRow";
@@ -768,7 +1037,7 @@ var TableBody = ({
768
1037
  }) => {
769
1038
  const virtualItems = rowVirtualizer.getVirtualItems();
770
1039
  const totalSize = rowVirtualizer.getTotalSize();
771
- const theme = typeof document !== "undefined" && document.documentElement.classList.contains("dark") ? "dark" : "light";
1040
+ const selectedKeySet = (0, import_react3.useMemo)(() => new Set(normalizedSelectedKeys), [normalizedSelectedKeys]);
772
1041
  const columnStyles = (0, import_react3.useMemo)(() => {
773
1042
  return orderedColumns.map((col, colIndex) => {
774
1043
  const stickyOffset = columnOffsets.get(col.key);
@@ -788,25 +1057,23 @@ var TableBody = ({
788
1057
  else if (col.pinned === "right" && stickyOffset !== void 0)
789
1058
  style.right = `${stickyOffset}px`;
790
1059
  if (isPinned) {
791
- style.backdropFilter = "blur(14px)";
792
- style.backgroundColor = styles?.pinnedBg ?? theme === "dark" ? "#10182890" : "#f9fafb90";
1060
+ style.backgroundColor = styles?.pinnedBg ?? "Canvas";
793
1061
  if (styles?.pinnedCell) Object.assign(style, styles.pinnedCell);
794
1062
  }
795
1063
  return { key: col.key, style, isPinned };
796
1064
  });
797
1065
  }, [orderedColumns, columnOffsets, totalSize, styles]);
798
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1066
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
799
1067
  columnStyles.map((colStyle, colIndex) => {
800
1068
  const col = orderedColumns[colIndex];
801
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1069
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
802
1070
  "div",
803
1071
  {
804
- className: "truncate",
805
1072
  style: colStyle.style,
806
1073
  children: virtualItems.map((virtualRow) => {
807
1074
  const row = data[virtualRow.index];
808
1075
  const rowKey = getRowKey ? getRowKey(row, virtualRow.index) : String(virtualRow.index);
809
- const isSelected = normalizedSelectedKeys.includes(rowKey);
1076
+ const isSelected = selectedKeySet.has(rowKey);
810
1077
  const isExpanded = resolvedExpandedKeys?.has(rowKey) ?? false;
811
1078
  const cellValue = row[col.dataIndex];
812
1079
  const isRowShimmer = isLoading || rowKey.startsWith("__shimmer_");
@@ -821,7 +1088,7 @@ var TableBody = ({
821
1088
  * - Absolute positioned at virtualRow.start for virtualization
822
1089
  * - Height = virtualRow.size (includes expanded row height)
823
1090
  */
824
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1091
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
825
1092
  "div",
826
1093
  {
827
1094
  "data-row-key": rowKey,
@@ -833,13 +1100,14 @@ var TableBody = ({
833
1100
  right: 0,
834
1101
  height: `${virtualRow.size}px`
835
1102
  },
836
- className: "truncate",
837
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1103
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
838
1104
  "div",
839
1105
  {
840
- style: { height: `${rowHeight}px`, position: "relative" },
841
- className: "truncate",
842
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1106
+ style: {
1107
+ height: `${rowHeight}px`,
1108
+ position: "relative"
1109
+ },
1110
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
843
1111
  Cell,
844
1112
  {
845
1113
  value: cellValue,
@@ -870,7 +1138,7 @@ var TableBody = ({
870
1138
  `spacer-${colStyle.key}`
871
1139
  );
872
1140
  }),
873
- expandable && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1141
+ expandable && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
874
1142
  "div",
875
1143
  {
876
1144
  style: {
@@ -887,31 +1155,27 @@ var TableBody = ({
887
1155
  const row = data[virtualRow.index];
888
1156
  const rk = getRowKey ? getRowKey(row, virtualRow.index) : String(virtualRow.index);
889
1157
  if (!(resolvedExpandedKeys?.has(rk) ?? false)) return null;
890
- const expandedContent = /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1158
+ const expandedContent = /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
891
1159
  "div",
892
1160
  {
893
- className: `${classNames?.expandedRow ?? ""}`,
1161
+ className: classNames?.expandedRow ?? "",
894
1162
  style: {
895
- // Sticky left:0 + fixed width = viewport-locked panel
896
- // regardless of how far the user has scrolled horizontally
897
1163
  position: "sticky",
898
1164
  left: 0,
899
1165
  zIndex: 5,
900
1166
  width: scrollAreaWidth && scrollAreaWidth > 0 ? `${scrollAreaWidth}px` : "100%",
901
1167
  overflow: "auto",
902
- // Restore pointer events so the expanded content is interactive
903
1168
  pointerEvents: "auto",
904
- borderBottom: "1px solid hsl(var(--border))",
905
- backgroundColor: "hsl(var(--muted)/0.4)",
1169
+ borderBottom: "1px solid rgba(128,128,128,0.2)",
1170
+ backgroundColor: "rgba(128,128,128,0.06)",
906
1171
  padding: 20,
907
- // Optional max height — makes the panel scrollable for tall content
908
1172
  ...maxExpandedRowHeight ? { maxHeight: `${maxExpandedRowHeight}px` } : void 0,
909
1173
  ...styles?.expandedRow
910
1174
  },
911
1175
  children: expandable.expandedRowRender(row, virtualRow.index, 0, true)
912
1176
  }
913
1177
  );
914
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1178
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
915
1179
  "div",
916
1180
  {
917
1181
  style: {
@@ -921,7 +1185,7 @@ var TableBody = ({
921
1185
  left: 0,
922
1186
  right: 0
923
1187
  },
924
- children: onExpandedRowResize ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1188
+ children: onExpandedRowResize ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
925
1189
  MeasuredExpandedRow,
926
1190
  {
927
1191
  rowKey: rk,
@@ -941,7 +1205,13 @@ TableBody.displayName = "TableBody";
941
1205
  var TableBody_default = TableBody;
942
1206
 
943
1207
  // src/BoltTable.tsx
944
- var import_jsx_runtime4 = require("react/jsx-runtime");
1208
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1209
+ function arrayMove(arr, from, to) {
1210
+ const result = arr.slice();
1211
+ const [item] = result.splice(from, 1);
1212
+ result.splice(to, 0, item);
1213
+ return result;
1214
+ }
945
1215
  var SHIMMER_WIDTHS2 = [55, 70, 45, 80, 60, 50, 75, 65, 40, 72];
946
1216
  function BoltTable({
947
1217
  columns: initialColumns,
@@ -955,6 +1225,7 @@ function BoltTable({
955
1225
  styles = {},
956
1226
  gripIcon,
957
1227
  hideGripIcon,
1228
+ icons,
958
1229
  pagination,
959
1230
  onPaginationChange,
960
1231
  onColumnResize,
@@ -1069,7 +1340,7 @@ function BoltTable({
1069
1340
  const canExpand = expandable.rowExpandable?.(record) ?? true;
1070
1341
  const isExpanded = resolvedExpandedKeys.has(key);
1071
1342
  if (!canExpand)
1072
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { display: "inline-block", width: 16 } });
1343
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { display: "inline-block", width: 16 } });
1073
1344
  if (typeof expandable.expandIcon === "function") {
1074
1345
  return expandable.expandIcon({
1075
1346
  expanded: isExpanded,
@@ -1080,7 +1351,7 @@ function BoltTable({
1080
1351
  record
1081
1352
  });
1082
1353
  }
1083
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1354
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1084
1355
  "button",
1085
1356
  {
1086
1357
  onClick: (e) => {
@@ -1098,7 +1369,7 @@ function BoltTable({
1098
1369
  borderRadius: "3px",
1099
1370
  color: accentColor
1100
1371
  },
1101
- children: isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.ChevronDown, { style: { width: 14, height: 14 } }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.ChevronRight, { style: { width: 14, height: 14 } })
1372
+ children: isExpanded ? icons?.chevronDown ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ChevronDownIcon, { style: { width: 14, height: 14 } }) : icons?.chevronRight ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ChevronRightIcon, { style: { width: 14, height: 14 } })
1102
1373
  }
1103
1374
  );
1104
1375
  }
@@ -1189,25 +1460,91 @@ function BoltTable({
1189
1460
  };
1190
1461
  }, []);
1191
1462
  const resizeStateRef = (0, import_react4.useRef)(null);
1192
- const sensors = (0, import_core.useSensors)((0, import_core.useSensor)(import_core.PointerSensor));
1193
- const handleDragStart = (event) => {
1194
- if (event.active.id === "__select__" || event.active.id === "__expand__")
1195
- return;
1196
- setActiveId(event.active.id);
1197
- };
1198
- const handleDragEnd = (event) => {
1199
- const { active, over } = event;
1200
- if (over && active.id !== over.id) {
1201
- setColumnOrder((items) => {
1202
- const oldIndex = items.indexOf(active.id);
1203
- const newIndex = items.indexOf(over.id);
1204
- const newOrder = (0, import_sortable2.arrayMove)(items, oldIndex, newIndex);
1205
- setTimeout(() => onColumnOrderChange?.(newOrder), 0);
1206
- return newOrder;
1207
- });
1208
- }
1209
- setActiveId(null);
1210
- };
1463
+ const overIdRef = (0, import_react4.useRef)(null);
1464
+ const dragActiveIdRef = (0, import_react4.useRef)(null);
1465
+ const ghostRef = (0, import_react4.useRef)(null);
1466
+ const onColumnOrderChangeRef = (0, import_react4.useRef)(onColumnOrderChange);
1467
+ onColumnOrderChangeRef.current = onColumnOrderChange;
1468
+ const handleColumnDragStart = (0, import_react4.useCallback)(
1469
+ (columnKey, e) => {
1470
+ if (columnKey === "__select__" || columnKey === "__expand__") return;
1471
+ const headerEl = e.currentTarget.closest(
1472
+ "[data-column-key]"
1473
+ );
1474
+ if (!headerEl) return;
1475
+ const rect = headerEl.getBoundingClientRect();
1476
+ const offsetX = e.clientX - rect.left;
1477
+ const offsetY = e.clientY - rect.top;
1478
+ setActiveId(columnKey);
1479
+ dragActiveIdRef.current = columnKey;
1480
+ headerEl.setAttribute("data-dragging", "");
1481
+ const ghost = ghostRef.current;
1482
+ if (ghost) {
1483
+ ghost.style.display = "flex";
1484
+ ghost.style.width = `${rect.width}px`;
1485
+ ghost.style.left = `${e.clientX - offsetX}px`;
1486
+ ghost.style.top = `${rect.top}px`;
1487
+ }
1488
+ const onMove = (ev) => {
1489
+ if (ghost) {
1490
+ ghost.style.left = `${ev.clientX - offsetX}px`;
1491
+ ghost.style.top = `${ev.clientY - offsetY}px`;
1492
+ }
1493
+ const scrollEl = tableAreaRef.current;
1494
+ if (!scrollEl) return;
1495
+ const headers = scrollEl.querySelectorAll("[data-column-key]");
1496
+ let newOverId = null;
1497
+ headers.forEach((h) => {
1498
+ const key = h.dataset.columnKey;
1499
+ if (!key || key === "__select__" || key === "__expand__" || key === columnKey) {
1500
+ h.removeAttribute("data-drag-over");
1501
+ return;
1502
+ }
1503
+ const r = h.getBoundingClientRect();
1504
+ if (ev.clientX >= r.left && ev.clientX <= r.right && ev.clientY >= r.top - 20 && ev.clientY <= r.bottom + 20) {
1505
+ newOverId = key;
1506
+ h.setAttribute("data-drag-over", "");
1507
+ } else {
1508
+ h.removeAttribute("data-drag-over");
1509
+ }
1510
+ });
1511
+ overIdRef.current = newOverId;
1512
+ };
1513
+ const onUp = () => {
1514
+ document.removeEventListener("pointermove", onMove);
1515
+ document.removeEventListener("pointerup", onUp);
1516
+ const scrollEl = tableAreaRef.current;
1517
+ if (scrollEl) {
1518
+ scrollEl.querySelectorAll("[data-dragging]").forEach((h) => h.removeAttribute("data-dragging"));
1519
+ scrollEl.querySelectorAll("[data-drag-over]").forEach((h) => h.removeAttribute("data-drag-over"));
1520
+ }
1521
+ if (ghost) ghost.style.display = "none";
1522
+ const currentOverId = overIdRef.current;
1523
+ const currentActiveId = dragActiveIdRef.current;
1524
+ if (currentOverId && currentActiveId && currentOverId !== currentActiveId) {
1525
+ import_react4.default.startTransition(() => {
1526
+ setColumnOrder((items) => {
1527
+ const oldIndex = items.indexOf(currentActiveId);
1528
+ const newIndex = items.indexOf(currentOverId);
1529
+ if (oldIndex === -1 || newIndex === -1) return items;
1530
+ const newOrder = arrayMove(items, oldIndex, newIndex);
1531
+ setTimeout(
1532
+ () => onColumnOrderChangeRef.current?.(newOrder),
1533
+ 0
1534
+ );
1535
+ return newOrder;
1536
+ });
1537
+ });
1538
+ }
1539
+ setActiveId(null);
1540
+ dragActiveIdRef.current = null;
1541
+ overIdRef.current = null;
1542
+ };
1543
+ document.addEventListener("pointermove", onMove);
1544
+ document.addEventListener("pointerup", onUp);
1545
+ },
1546
+ []
1547
+ );
1211
1548
  const handleResizeStart = (columnKey, e) => {
1212
1549
  e.preventDefault();
1213
1550
  e.stopPropagation();
@@ -1261,17 +1598,19 @@ function BoltTable({
1261
1598
  if (!resizeStateRef.current) return;
1262
1599
  const { startX, startWidth, currentX, columnKey } = resizeStateRef.current;
1263
1600
  const finalWidth = Math.max(40, startWidth + (currentX - startX));
1264
- manuallyResizedRef.current.add(columnKey);
1265
- setColumnWidths((prev) => {
1266
- const next = new Map(prev);
1267
- next.set(columnKey, finalWidth);
1268
- return next;
1269
- });
1270
- onColumnResize?.(columnKey, finalWidth);
1271
1601
  resizeOverlayRef.current?.hide();
1272
1602
  resizeStateRef.current = null;
1273
1603
  document.removeEventListener("mousemove", handleResizeMove);
1274
1604
  document.removeEventListener("mouseup", handleResizeEnd);
1605
+ manuallyResizedRef.current.add(columnKey);
1606
+ import_react4.default.startTransition(() => {
1607
+ setColumnWidths((prev) => {
1608
+ const next = new Map(prev);
1609
+ next.set(columnKey, finalWidth);
1610
+ return next;
1611
+ });
1612
+ });
1613
+ onColumnResize?.(columnKey, finalWidth);
1275
1614
  }, [onColumnResize]);
1276
1615
  const { leftPinned, unpinned, rightPinned } = (0, import_react4.useMemo)(() => {
1277
1616
  const columnMap = new Map(columnsWithSelection.map((c) => [c.key, c]));
@@ -1571,27 +1910,31 @@ function BoltTable({
1571
1910
  };
1572
1911
  const HEADER_HEIGHT = 36;
1573
1912
  const MAX_AUTO_ROWS = 10;
1574
- const naturalContentHeight = rowVirtualizer.getTotalSize() + HEADER_HEIGHT;
1913
+ const virtualTotalSize = rowVirtualizer.getTotalSize();
1914
+ const naturalContentHeight = virtualTotalSize + HEADER_HEIGHT;
1575
1915
  const maxAutoHeight = MAX_AUTO_ROWS * rowHeight + HEADER_HEIGHT;
1576
1916
  const isEmpty = displayData.length === 0 && !showShimmer;
1577
1917
  const emptyMinHeight = 4 * rowHeight + HEADER_HEIGHT;
1578
1918
  const clampedAutoHeight = isEmpty ? emptyMinHeight : Math.min(naturalContentHeight, maxAutoHeight);
1579
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1580
- import_core.DndContext,
1581
- {
1582
- sensors,
1583
- collisionDetection: import_core.closestCenter,
1584
- onDragStart: handleDragStart,
1585
- onDragEnd: handleDragEnd,
1586
- children: [
1587
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1588
- "div",
1589
- {
1590
- className: `flex ${autoHeight ? "max-h-full" : "h-full"} w-full flex-col ${className}`,
1591
- children: [
1592
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("style", { children: `
1919
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1920
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1921
+ "div",
1922
+ {
1923
+ className,
1924
+ style: {
1925
+ display: "flex",
1926
+ width: "100%",
1927
+ flexDirection: "column",
1928
+ ...autoHeight ? { maxHeight: "100%" } : { height: "100%" }
1929
+ },
1930
+ children: [
1931
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("style", { children: `
1932
+ @keyframes bt-pulse {
1933
+ 0%, 100% { opacity: 1; }
1934
+ 50% { opacity: 0.5; }
1935
+ }
1593
1936
  [data-row-key][data-hover] > div {
1594
- background-color: ${styles.rowHover?.backgroundColor ?? `hsl(var(--muted) / 0.5)`};
1937
+ background-color: ${styles.rowHover?.backgroundColor ?? "rgba(0, 0, 0, 0.04)"};
1595
1938
  }
1596
1939
  [data-row-key][data-selected] > div {
1597
1940
  background-color: ${styles.rowSelected?.backgroundColor ?? `${accentColor}15`};
@@ -1599,447 +1942,675 @@ function BoltTable({
1599
1942
  [data-row-key][data-selected][data-hover] > div {
1600
1943
  background-color: ${styles.rowSelected?.backgroundColor ?? `${accentColor}25`};
1601
1944
  }
1945
+ [data-bt-header]:hover [data-bt-grip] {
1946
+ opacity: 0.8 !important;
1947
+ }
1948
+ [data-bt-resize]:hover [data-bt-resize-line] {
1949
+ opacity: 1 !important;
1950
+ }
1951
+ [data-bt-ctx-item]:not(:disabled):hover {
1952
+ background-color: rgba(0, 0, 0, 0.06);
1953
+ }
1954
+ [data-column-key][data-dragging] {
1955
+ opacity: 0.3 !important;
1956
+ }
1957
+ [data-column-key][data-drag-over] {
1958
+ border: 1px dashed ${accentColor} !important;
1959
+ }
1602
1960
  ` }),
1603
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1604
- "div",
1605
- {
1606
- className: `relative ${autoHeight ? "" : "flex-1"}`,
1607
- style: autoHeight ? {
1608
- height: `${clampedAutoHeight}px`,
1609
- maxHeight: `${clampedAutoHeight}px`,
1610
- flexShrink: 1,
1611
- flexGrow: 0
1612
- } : void 0,
1613
- children: layoutLoading ? (
1614
- /*
1615
- * ── Layout loading skeleton ──────────────────────────────────
1616
- * Shown when layoutLoading=true. Renders real column headers
1617
- * (based on orderedColumns) alongside shimmer body rows.
1618
- * Used for initial page load when column widths are not yet known.
1619
- */
1620
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1961
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1962
+ "div",
1963
+ {
1964
+ style: {
1965
+ position: "relative",
1966
+ ...autoHeight ? {
1967
+ height: `${clampedAutoHeight}px`,
1968
+ maxHeight: `${clampedAutoHeight}px`,
1969
+ flexShrink: 1,
1970
+ flexGrow: 0
1971
+ } : { flex: "1 1 0%" }
1972
+ },
1973
+ children: layoutLoading ? (
1974
+ /*
1975
+ * ── Layout loading skeleton ──────────────────────────────────
1976
+ * Shown when layoutLoading=true. Renders real column headers
1977
+ * (based on orderedColumns) alongside shimmer body rows.
1978
+ * Used for initial page load when column widths are not yet known.
1979
+ */
1980
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1981
+ "div",
1982
+ {
1983
+ style: {
1984
+ position: "absolute",
1985
+ inset: 0,
1986
+ overflow: "auto",
1987
+ contain: "layout paint"
1988
+ },
1989
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1621
1990
  "div",
1622
1991
  {
1623
- className: "absolute inset-0 overflow-auto",
1624
- style: { contain: "layout paint" },
1625
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1626
- "div",
1627
- {
1628
- style: {
1629
- display: "grid",
1630
- gridTemplateColumns,
1631
- gridTemplateRows: "36px auto",
1632
- minWidth: `${totalTableWidth}px`,
1633
- width: "100%",
1634
- position: "relative"
1635
- },
1636
- children: [
1637
- orderedColumns.map((column) => {
1992
+ style: {
1993
+ display: "grid",
1994
+ gridTemplateColumns,
1995
+ gridTemplateRows: "36px auto",
1996
+ minWidth: `${totalTableWidth}px`,
1997
+ width: "100%",
1998
+ position: "relative"
1999
+ },
2000
+ children: [
2001
+ orderedColumns.map((column) => {
2002
+ const isPinned = !!column.pinned;
2003
+ const offset = columnOffsets.get(column.key);
2004
+ const isSystem = column.key === "__select__" || column.key === "__expand__";
2005
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2006
+ "div",
2007
+ {
2008
+ className: isPinned ? classNames.pinnedHeader ?? "" : classNames.header ?? "",
2009
+ style: {
2010
+ display: "flex",
2011
+ height: 36,
2012
+ alignItems: "center",
2013
+ overflow: "hidden",
2014
+ textOverflow: "ellipsis",
2015
+ whiteSpace: "nowrap",
2016
+ borderBottom: "1px solid rgba(128,128,128,0.2)",
2017
+ backdropFilter: "blur(8px)",
2018
+ position: "sticky",
2019
+ top: 0,
2020
+ zIndex: isPinned ? 13 : 10,
2021
+ ...isPinned ? {
2022
+ [column.pinned]: offset ?? 0,
2023
+ ...styles.pinnedHeader
2024
+ } : styles.header,
2025
+ paddingLeft: isSystem ? 0 : 8,
2026
+ paddingRight: isSystem ? 0 : 8
2027
+ }
2028
+ },
2029
+ column.key
2030
+ );
2031
+ }),
2032
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { gridColumn: "1 / -1" }, children: Array.from({ length: shimmerCount }).map((_, rowIndex) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2033
+ "div",
2034
+ {
2035
+ style: {
2036
+ display: "grid",
2037
+ gridTemplateColumns,
2038
+ height: rowHeight
2039
+ },
2040
+ children: orderedColumns.map((column, colIndex) => {
1638
2041
  const isPinned = !!column.pinned;
1639
2042
  const offset = columnOffsets.get(column.key);
1640
2043
  const isSystem = column.key === "__select__" || column.key === "__expand__";
1641
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2044
+ const widthPercent = SHIMMER_WIDTHS2[(rowIndex * 7 + colIndex) % SHIMMER_WIDTHS2.length];
2045
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1642
2046
  "div",
1643
2047
  {
1644
- className: `flex h-9 items-center truncate border-t border-b ${isPinned ? `bg-background backdrop-blur ${classNames.pinnedHeader ?? ""}` : `bg-muted/40 backdrop-blur ${classNames.header ?? ""}`}`,
2048
+ className: isPinned ? classNames.pinnedCell ?? "" : "",
1645
2049
  style: {
1646
- position: "sticky",
1647
- top: 0,
1648
- zIndex: isPinned ? 13 : 10,
2050
+ display: "flex",
2051
+ alignItems: "center",
2052
+ borderBottom: "1px solid rgba(128,128,128,0.2)",
1649
2053
  ...isPinned ? {
2054
+ position: "sticky",
1650
2055
  [column.pinned]: offset ?? 0,
1651
- ...styles.pinnedHeader
1652
- } : styles.header,
2056
+ zIndex: 5,
2057
+ ...styles.pinnedCell
2058
+ } : {},
1653
2059
  paddingLeft: isSystem ? 0 : 8,
1654
- paddingRight: isSystem ? 0 : 8
1655
- }
1656
- },
1657
- column.key
1658
- );
1659
- }),
1660
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { gridColumn: "1 / -1" }, children: Array.from({ length: shimmerCount }).map((_, rowIndex) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1661
- "div",
1662
- {
1663
- style: {
1664
- display: "grid",
1665
- gridTemplateColumns,
1666
- height: rowHeight
1667
- },
1668
- children: orderedColumns.map((column, colIndex) => {
1669
- const isPinned = !!column.pinned;
1670
- const offset = columnOffsets.get(column.key);
1671
- const isSystem = column.key === "__select__" || column.key === "__expand__";
1672
- const widthPercent = SHIMMER_WIDTHS2[(rowIndex * 7 + colIndex) % SHIMMER_WIDTHS2.length];
1673
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2060
+ paddingRight: isSystem ? 0 : 8,
2061
+ justifyContent: isSystem ? "center" : void 0
2062
+ },
2063
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1674
2064
  "div",
1675
2065
  {
1676
- className: `flex items-center border-b ${isPinned ? `bg-background ${classNames.pinnedCell ?? ""}` : ""}`,
1677
2066
  style: {
1678
- ...isPinned ? {
1679
- position: "sticky",
1680
- [column.pinned]: offset ?? 0,
1681
- zIndex: 5,
1682
- ...styles.pinnedCell
1683
- } : {},
1684
- paddingLeft: isSystem ? 0 : 8,
1685
- paddingRight: isSystem ? 0 : 8,
1686
- justifyContent: isSystem ? "center" : void 0
1687
- },
1688
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1689
- "div",
1690
- {
1691
- className: "bg-muted-foreground/15 animate-pulse rounded",
1692
- style: {
1693
- height: isSystem ? 16 : 14,
1694
- width: isSystem ? 16 : `${widthPercent}%`,
1695
- borderRadius: isSystem ? 3 : 4,
1696
- animationDelay: `${(rowIndex * 7 + colIndex) * 50}ms`
1697
- }
1698
- }
1699
- )
1700
- },
1701
- column.key
1702
- );
1703
- })
1704
- },
1705
- rowIndex
1706
- )) })
1707
- ]
1708
- }
1709
- )
2067
+ backgroundColor: "rgba(100, 116, 139, 0.15)",
2068
+ animation: "bt-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite",
2069
+ borderRadius: isSystem ? 3 : 4,
2070
+ height: isSystem ? 16 : 14,
2071
+ width: isSystem ? 16 : `${widthPercent}%`,
2072
+ animationDelay: `${(rowIndex * 7 + colIndex) * 50}ms`
2073
+ }
2074
+ }
2075
+ )
2076
+ },
2077
+ column.key
2078
+ );
2079
+ })
2080
+ },
2081
+ rowIndex
2082
+ )) })
2083
+ ]
1710
2084
  }
1711
2085
  )
1712
- ) : (
1713
- /*
1714
- * ── Main scroll container ────────────────────────────────────
1715
- * absolute inset-0 so it fills whatever height the wrapper resolves to.
1716
- * contain: layout paint browser optimization hint that this element
1717
- * is a layout and paint boundary (improves compositing performance).
1718
- */
1719
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1720
- "div",
1721
- {
1722
- ref: tableAreaCallbackRef,
1723
- className: "absolute inset-0 overflow-auto",
1724
- style: { contain: "layout paint" },
1725
- children: [
1726
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ResizeOverlay_default, { ref: resizeOverlayRef, accentColor }),
1727
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1728
- "div",
1729
- {
1730
- style: {
1731
- display: "grid",
1732
- gridTemplateColumns,
1733
- gridTemplateRows: "36px 1fr",
1734
- minWidth: `${totalTableWidth}px`,
1735
- height: "100%",
1736
- width: "100%",
1737
- position: "relative"
1738
- },
1739
- children: [
1740
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1741
- import_sortable2.SortableContext,
2086
+ }
2087
+ )
2088
+ ) : (
2089
+ /*
2090
+ * ── Main scroll container ────────────────────────────────────
2091
+ * absolute inset-0 so it fills whatever height the wrapper resolves to.
2092
+ * contain: layout paint — browser optimization hint that this element
2093
+ * is a layout and paint boundary (improves compositing performance).
2094
+ */
2095
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
2096
+ "div",
2097
+ {
2098
+ ref: tableAreaCallbackRef,
2099
+ style: {
2100
+ position: "absolute",
2101
+ inset: 0,
2102
+ overflow: "auto",
2103
+ contain: "layout paint"
2104
+ },
2105
+ children: [
2106
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ResizeOverlay_default, { ref: resizeOverlayRef, accentColor }),
2107
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
2108
+ "div",
2109
+ {
2110
+ style: {
2111
+ display: "grid",
2112
+ gridTemplateColumns,
2113
+ gridTemplateRows: isEmpty ? "36px 1fr" : `36px ${virtualTotalSize}px`,
2114
+ minWidth: `${totalTableWidth}px`,
2115
+ width: "100%",
2116
+ position: "relative",
2117
+ ...isEmpty ? { height: "100%" } : {}
2118
+ },
2119
+ children: [
2120
+ orderedColumns.map((column, visualIndex) => {
2121
+ if (column.key === "__select__" && rowSelection) {
2122
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2123
+ "div",
1742
2124
  {
1743
- items: columnOrder,
1744
- strategy: import_sortable2.horizontalListSortingStrategy,
1745
- children: orderedColumns.map((column, visualIndex) => {
1746
- if (column.key === "__select__" && rowSelection) {
1747
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1748
- "div",
1749
- {
1750
- className: `bg-muted/40 sticky flex h-9 items-center justify-center truncate border-t border-b backdrop-blur ${classNames.header ?? ""} ${classNames.pinnedHeader ?? ""} `,
1751
- style: {
1752
- position: "sticky",
1753
- left: columnOffsets.get("__select__") ?? 0,
1754
- top: 0,
1755
- zIndex: 13,
1756
- width: "48px",
1757
- ...styles.header,
1758
- ...styles.pinnedHeader
1759
- },
1760
- children: rowSelection.type !== "radio" && !rowSelection.hideSelectAll && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1761
- "input",
1762
- {
1763
- type: "checkbox",
1764
- checked: data.length > 0 && normalizedSelectedKeys.length === data.length,
1765
- ref: (input) => {
1766
- if (input) {
1767
- input.indeterminate = normalizedSelectedKeys.length > 0 && normalizedSelectedKeys.length < data.length;
1768
- }
1769
- },
1770
- onChange: (e) => {
1771
- if (e.target.checked) {
1772
- const allKeys = data.map(
1773
- (row, idx) => getRowKey(row, idx)
1774
- );
1775
- rowSelection.onSelectAll?.(
1776
- true,
1777
- data,
1778
- data
1779
- );
1780
- rowSelection.onChange?.(allKeys, data, {
1781
- type: "all"
1782
- });
1783
- } else {
1784
- rowSelection.onSelectAll?.(false, [], data);
1785
- rowSelection.onChange?.([], [], {
1786
- type: "all"
1787
- });
1788
- }
1789
- },
1790
- className: "cursor-pointer",
1791
- style: { accentColor }
1792
- }
1793
- )
1794
- },
1795
- "__select__"
1796
- );
1797
- }
1798
- if (column.key === "__expand__") {
1799
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1800
- "div",
1801
- {
1802
- className: `bg-muted/40 sticky flex h-9 items-center justify-center truncate border-t border-b backdrop-blur ${classNames.header ?? ""} ${classNames.pinnedHeader ?? ""}`,
1803
- style: {
1804
- position: "sticky",
1805
- left: columnOffsets.get("__expand__") ?? 0,
1806
- top: 0,
1807
- zIndex: 13,
1808
- width: "40px",
1809
- ...styles.header,
1810
- ...styles.pinnedHeader
1811
- }
1812
- },
1813
- "__expand__"
1814
- );
1815
- }
1816
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1817
- DraggableHeader_default,
1818
- {
1819
- column,
1820
- accentColor,
1821
- visualIndex,
1822
- onResizeStart: handleResizeStart,
1823
- styles,
1824
- classNames,
1825
- gripIcon,
1826
- hideGripIcon,
1827
- stickyOffset: columnOffsets.get(column.key),
1828
- onTogglePin: handleTogglePin,
1829
- onToggleHide: handleToggleHide,
1830
- isLastColumn: visualIndex === orderedColumns.length - 1,
1831
- sortDirection: sortState.key === column.key ? sortState.direction : null,
1832
- onSort: handleSort,
1833
- filterValue: columnFilters[column.key] ?? "",
1834
- onFilter: handleColumnFilter,
1835
- onClearFilter: handleClearFilter,
1836
- customContextMenuItems: columnContextMenuItems
2125
+ className: `${classNames.header ?? ""} ${classNames.pinnedHeader ?? ""}`,
2126
+ style: {
2127
+ display: "flex",
2128
+ height: 36,
2129
+ alignItems: "center",
2130
+ justifyContent: "center",
2131
+ overflow: "hidden",
2132
+ textOverflow: "ellipsis",
2133
+ whiteSpace: "nowrap",
2134
+ borderBottom: "1px solid rgba(128,128,128,0.2)",
2135
+ backgroundColor: "Canvas",
2136
+ position: "sticky",
2137
+ left: columnOffsets.get("__select__") ?? 0,
2138
+ top: 0,
2139
+ zIndex: 13,
2140
+ width: "48px",
2141
+ ...styles.header,
2142
+ ...styles.pinnedHeader
2143
+ },
2144
+ children: rowSelection.type !== "radio" && !rowSelection.hideSelectAll && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2145
+ "input",
2146
+ {
2147
+ type: "checkbox",
2148
+ checked: data.length > 0 && normalizedSelectedKeys.length === data.length,
2149
+ ref: (input) => {
2150
+ if (input) {
2151
+ input.indeterminate = normalizedSelectedKeys.length > 0 && normalizedSelectedKeys.length < data.length;
2152
+ }
2153
+ },
2154
+ onChange: (e) => {
2155
+ if (e.target.checked) {
2156
+ const allKeys = data.map(
2157
+ (row, idx) => getRowKey(row, idx)
2158
+ );
2159
+ rowSelection.onSelectAll?.(
2160
+ true,
2161
+ data,
2162
+ data
2163
+ );
2164
+ rowSelection.onChange?.(allKeys, data, {
2165
+ type: "all"
2166
+ });
2167
+ } else {
2168
+ rowSelection.onSelectAll?.(false, [], data);
2169
+ rowSelection.onChange?.([], [], {
2170
+ type: "all"
2171
+ });
2172
+ }
1837
2173
  },
1838
- column.key
1839
- );
1840
- })
1841
- }
1842
- ),
1843
- isEmpty ? (
1844
- /*
1845
- * ── Empty state ────────────────────────────────────────
1846
- * col-span-full + height:100% fills the 1fr body grid row.
1847
- *
1848
- * The inner div uses `position: sticky; left: 0` with a fixed
1849
- * width (scrollAreaWidth) to viewport-lock the empty state panel.
1850
- * Without this, the empty message would scroll horizontally
1851
- * with the grid content when there are many columns.
1852
- */
1853
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2174
+ style: { cursor: "pointer", accentColor }
2175
+ }
2176
+ )
2177
+ },
2178
+ "__select__"
2179
+ );
2180
+ }
2181
+ if (column.key === "__expand__") {
2182
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2183
+ "div",
2184
+ {
2185
+ className: `${classNames.header ?? ""} ${classNames.pinnedHeader ?? ""}`,
2186
+ style: {
2187
+ display: "flex",
2188
+ height: 36,
2189
+ alignItems: "center",
2190
+ justifyContent: "center",
2191
+ overflow: "hidden",
2192
+ textOverflow: "ellipsis",
2193
+ whiteSpace: "nowrap",
2194
+ borderBottom: "1px solid rgba(128,128,128,0.2)",
2195
+ backgroundColor: "Canvas",
2196
+ position: "sticky",
2197
+ left: columnOffsets.get("__expand__") ?? 0,
2198
+ top: 0,
2199
+ zIndex: 13,
2200
+ width: "40px",
2201
+ ...styles.header,
2202
+ ...styles.pinnedHeader
2203
+ }
2204
+ },
2205
+ "__expand__"
2206
+ );
2207
+ }
2208
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2209
+ DraggableHeader_default,
2210
+ {
2211
+ column,
2212
+ accentColor,
2213
+ visualIndex,
2214
+ onResizeStart: handleResizeStart,
2215
+ onColumnDragStart: handleColumnDragStart,
2216
+ styles,
2217
+ classNames,
2218
+ gripIcon,
2219
+ hideGripIcon,
2220
+ icons,
2221
+ stickyOffset: columnOffsets.get(column.key),
2222
+ onTogglePin: handleTogglePin,
2223
+ onToggleHide: handleToggleHide,
2224
+ isLastColumn: visualIndex === orderedColumns.length - 1,
2225
+ sortDirection: sortState.key === column.key ? sortState.direction : null,
2226
+ onSort: handleSort,
2227
+ filterValue: columnFilters[column.key] ?? "",
2228
+ onFilter: handleColumnFilter,
2229
+ onClearFilter: handleClearFilter,
2230
+ customContextMenuItems: columnContextMenuItems
2231
+ },
2232
+ column.key
2233
+ );
2234
+ }),
2235
+ isEmpty ? (
2236
+ /*
2237
+ * ── Empty state ────────────────────────────────────────
2238
+ * col-span-full + height:100% fills the 1fr body grid row.
2239
+ *
2240
+ * The inner div uses `position: sticky; left: 0` with a fixed
2241
+ * width (scrollAreaWidth) to viewport-lock the empty state panel.
2242
+ * Without this, the empty message would scroll horizontally
2243
+ * with the grid content when there are many columns.
2244
+ */
2245
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2246
+ "div",
2247
+ {
2248
+ style: {
2249
+ gridColumn: "1 / -1",
2250
+ height: "100%",
2251
+ position: "relative"
2252
+ },
2253
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1854
2254
  "div",
1855
2255
  {
1856
- className: "col-span-full",
1857
- style: { height: "100%", position: "relative" },
1858
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2256
+ style: {
2257
+ position: "sticky",
2258
+ left: 0,
2259
+ width: scrollAreaWidth > 0 ? `${scrollAreaWidth}px` : "100%",
2260
+ height: "100%",
2261
+ display: "flex",
2262
+ alignItems: "center",
2263
+ justifyContent: "center"
2264
+ },
2265
+ children: emptyRenderer ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1859
2266
  "div",
1860
2267
  {
1861
2268
  style: {
1862
- position: "sticky",
1863
- left: 0,
1864
- width: scrollAreaWidth > 0 ? `${scrollAreaWidth}px` : "100%",
1865
- height: "100%",
1866
2269
  display: "flex",
2270
+ flexDirection: "column",
1867
2271
  alignItems: "center",
1868
- justifyContent: "center"
2272
+ gap: 8,
2273
+ paddingTop: 32,
2274
+ paddingBottom: 32,
2275
+ color: "#6b7280"
1869
2276
  },
1870
- children: emptyRenderer ?? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "text-muted-foreground flex flex-col items-center gap-2 py-8", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-sm", children: "No data" }) })
2277
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { fontSize: 14 }, children: "No data" })
1871
2278
  }
1872
2279
  )
1873
2280
  }
1874
2281
  )
1875
- ) : (
1876
- /* ── Virtualized table body ─────────────────────────── */
1877
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1878
- TableBody_default,
1879
- {
1880
- data: displayData,
1881
- orderedColumns,
1882
- rowVirtualizer,
1883
- columnOffsets,
1884
- styles,
1885
- classNames,
1886
- rowSelection: !showShimmer ? rowSelection : void 0,
1887
- normalizedSelectedKeys,
1888
- getRowKey,
1889
- expandable: !showShimmer ? expandable : void 0,
1890
- resolvedExpandedKeys,
1891
- rowHeight,
1892
- totalTableWidth,
1893
- scrollAreaWidth,
1894
- accentColor,
1895
- scrollContainerRef: tableAreaRef,
1896
- isLoading: showShimmer,
1897
- onExpandedRowResize: handleExpandedRowResize,
1898
- maxExpandedRowHeight
1899
- }
1900
- )
1901
- )
1902
- ]
1903
- }
1904
- )
1905
- ]
1906
- }
1907
- )
1908
- )
1909
- }
1910
- ),
1911
- pagination !== false && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1912
- "div",
1913
- {
1914
- className: "flex h-9 items-center justify-between border-t px-3 text-xs backdrop-blur",
1915
- style: {
1916
- backgroundColor: "hsl(var(--background)/0.4)",
1917
- gap: "12px"
1918
- },
1919
- children: [
1920
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex flex-1 items-center", children: (() => {
1921
- const rangeStart = total > 0 ? (currentPage - 1) * pageSize + 1 : 0;
1922
- const rangeEnd = Math.min(currentPage * pageSize, total);
1923
- return pagination?.showTotal ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "text-muted-foreground text-xs", children: [
1924
- "Showing",
1925
- " ",
1926
- pagination.showTotal(total, [rangeStart, rangeEnd]),
1927
- " of",
1928
- " ",
1929
- total,
1930
- " items"
1931
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "text-muted-foreground text-xs", children: [
1932
- rangeStart,
1933
- "\u2013",
1934
- rangeEnd,
1935
- " of ",
1936
- total
1937
- ] });
1938
- })() }),
1939
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex flex-1 items-center justify-center gap-1", children: [
1940
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2282
+ }
2283
+ )
2284
+ ) : (
2285
+ /* ── Virtualized table body ─────────────────────────── */
2286
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2287
+ TableBody_default,
2288
+ {
2289
+ data: displayData,
2290
+ orderedColumns,
2291
+ rowVirtualizer,
2292
+ columnOffsets,
2293
+ styles,
2294
+ classNames,
2295
+ rowSelection: !showShimmer ? rowSelection : void 0,
2296
+ normalizedSelectedKeys,
2297
+ getRowKey,
2298
+ expandable: !showShimmer ? expandable : void 0,
2299
+ resolvedExpandedKeys,
2300
+ rowHeight,
2301
+ totalTableWidth,
2302
+ scrollAreaWidth,
2303
+ accentColor,
2304
+ scrollContainerRef: tableAreaRef,
2305
+ isLoading: showShimmer,
2306
+ onExpandedRowResize: handleExpandedRowResize,
2307
+ maxExpandedRowHeight
2308
+ }
2309
+ )
2310
+ )
2311
+ ]
2312
+ }
2313
+ )
2314
+ ]
2315
+ }
2316
+ )
2317
+ )
2318
+ }
2319
+ ),
2320
+ pagination !== false && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
2321
+ "div",
2322
+ {
2323
+ style: {
2324
+ display: "flex",
2325
+ height: 36,
2326
+ alignItems: "center",
2327
+ justifyContent: "space-between",
2328
+ borderTop: "1px solid rgba(128,128,128,0.2)",
2329
+ paddingLeft: 12,
2330
+ paddingRight: 12,
2331
+ fontSize: 12,
2332
+ backdropFilter: "blur(8px)",
2333
+ backgroundColor: "rgba(128,128,128,0.06)",
2334
+ gap: 12
2335
+ },
2336
+ children: [
2337
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { display: "flex", flex: "1 1 0%", alignItems: "center" }, children: (() => {
2338
+ const rangeStart = total > 0 ? (currentPage - 1) * pageSize + 1 : 0;
2339
+ const rangeEnd = Math.min(currentPage * pageSize, total);
2340
+ return pagination?.showTotal ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { style: { color: "#6b7280", fontSize: 12 }, children: [
2341
+ "Showing",
2342
+ " ",
2343
+ pagination.showTotal(total, [rangeStart, rangeEnd]),
2344
+ " of",
2345
+ " ",
2346
+ total,
2347
+ " items"
2348
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { style: { color: "#6b7280", fontSize: 12 }, children: [
2349
+ rangeStart,
2350
+ "\u2013",
2351
+ rangeEnd,
2352
+ " of ",
2353
+ total
2354
+ ] });
2355
+ })() }),
2356
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
2357
+ "div",
2358
+ {
2359
+ style: {
2360
+ display: "flex",
2361
+ flex: "1 1 0%",
2362
+ alignItems: "center",
2363
+ justifyContent: "center",
2364
+ gap: 4
2365
+ },
2366
+ children: [
2367
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1941
2368
  "button",
1942
2369
  {
1943
2370
  onClick: () => handlePageChange(1),
1944
2371
  disabled: currentPage === 1,
1945
- className: "inline-flex h-6 w-6 cursor-pointer items-center justify-center text-xs transition-colors disabled:cursor-not-allowed disabled:opacity-30",
2372
+ style: {
2373
+ display: "inline-flex",
2374
+ height: 24,
2375
+ width: 24,
2376
+ cursor: currentPage === 1 ? "not-allowed" : "pointer",
2377
+ alignItems: "center",
2378
+ justifyContent: "center",
2379
+ fontSize: 12,
2380
+ opacity: currentPage === 1 ? 0.3 : 1,
2381
+ background: "none",
2382
+ border: "none",
2383
+ padding: 0,
2384
+ color: "inherit"
2385
+ },
1946
2386
  title: "First page",
1947
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.ChevronsLeft, { className: "h-3 w-3" })
2387
+ children: icons?.chevronsLeft ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ChevronsLeftIcon, { style: { width: 12, height: 12 } })
1948
2388
  }
1949
2389
  ),
1950
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2390
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1951
2391
  "button",
1952
2392
  {
1953
2393
  onClick: () => handlePageChange(currentPage - 1),
1954
2394
  disabled: currentPage === 1,
1955
- className: "inline-flex h-6 w-6 cursor-pointer items-center justify-center text-xs transition-colors disabled:cursor-not-allowed disabled:opacity-30",
2395
+ style: {
2396
+ display: "inline-flex",
2397
+ height: 24,
2398
+ width: 24,
2399
+ cursor: currentPage === 1 ? "not-allowed" : "pointer",
2400
+ alignItems: "center",
2401
+ justifyContent: "center",
2402
+ fontSize: 12,
2403
+ opacity: currentPage === 1 ? 0.3 : 1,
2404
+ background: "none",
2405
+ border: "none",
2406
+ padding: 0,
2407
+ color: "inherit"
2408
+ },
1956
2409
  title: "Previous page",
1957
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.ChevronLeft, { className: "h-3 w-3" })
2410
+ children: icons?.chevronLeft ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ChevronLeftIcon, { style: { width: 12, height: 12 } })
1958
2411
  }
1959
2412
  ),
1960
2413
  getPageNumbers().map((page) => {
1961
2414
  if (page === "ellipsis-left" || page === "ellipsis-right") {
1962
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2415
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1963
2416
  "span",
1964
2417
  {
1965
- className: "text-muted-foreground px-1 text-xs select-none",
2418
+ style: {
2419
+ color: "#6b7280",
2420
+ paddingLeft: 4,
2421
+ paddingRight: 4,
2422
+ fontSize: 12,
2423
+ userSelect: "none"
2424
+ },
1966
2425
  children: "..."
1967
2426
  },
1968
2427
  page
1969
2428
  );
1970
2429
  }
1971
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2430
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1972
2431
  "button",
1973
2432
  {
1974
2433
  style: {
1975
- color: page === currentPage ? accentColor : void 0
2434
+ display: "inline-flex",
2435
+ height: 24,
2436
+ minWidth: 24,
2437
+ cursor: "pointer",
2438
+ alignItems: "center",
2439
+ justifyContent: "center",
2440
+ borderRadius: 4,
2441
+ paddingLeft: 6,
2442
+ paddingRight: 6,
2443
+ fontSize: 12,
2444
+ color: page === currentPage ? accentColor : void 0,
2445
+ background: "none",
2446
+ border: "none"
1976
2447
  },
1977
2448
  onClick: () => handlePageChange(page),
1978
- className: "inline-flex h-6 min-w-6 cursor-pointer items-center justify-center rounded px-1.5 text-xs transition-colors",
1979
2449
  children: page
1980
2450
  },
1981
2451
  page
1982
2452
  );
1983
2453
  }),
1984
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2454
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1985
2455
  "button",
1986
2456
  {
1987
2457
  onClick: () => handlePageChange(currentPage + 1),
1988
2458
  disabled: currentPage === totalPages,
1989
- className: "inline-flex h-6 w-6 cursor-pointer items-center justify-center text-xs transition-colors disabled:cursor-not-allowed disabled:opacity-30",
2459
+ style: {
2460
+ display: "inline-flex",
2461
+ height: 24,
2462
+ width: 24,
2463
+ cursor: currentPage === totalPages ? "not-allowed" : "pointer",
2464
+ alignItems: "center",
2465
+ justifyContent: "center",
2466
+ fontSize: 12,
2467
+ opacity: currentPage === totalPages ? 0.3 : 1,
2468
+ background: "none",
2469
+ border: "none",
2470
+ padding: 0,
2471
+ color: "inherit"
2472
+ },
1990
2473
  title: "Next page",
1991
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.ChevronRight, { className: "h-3 w-3" })
2474
+ children: icons?.chevronRight ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ChevronRightIcon, { style: { width: 12, height: 12 } })
1992
2475
  }
1993
2476
  ),
1994
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2477
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1995
2478
  "button",
1996
2479
  {
1997
2480
  onClick: () => handlePageChange(totalPages),
1998
2481
  disabled: currentPage === totalPages,
1999
- className: "inline-flex h-6 w-6 cursor-pointer items-center justify-center text-xs transition-colors disabled:cursor-not-allowed disabled:opacity-30",
2482
+ style: {
2483
+ display: "inline-flex",
2484
+ height: 24,
2485
+ width: 24,
2486
+ cursor: currentPage === totalPages ? "not-allowed" : "pointer",
2487
+ alignItems: "center",
2488
+ justifyContent: "center",
2489
+ fontSize: 12,
2490
+ opacity: currentPage === totalPages ? 0.3 : 1,
2491
+ background: "none",
2492
+ border: "none",
2493
+ padding: 0,
2494
+ color: "inherit"
2495
+ },
2000
2496
  title: "Last page",
2001
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.ChevronsRight, { className: "h-3 w-3" })
2497
+ children: icons?.chevronsRight ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ChevronsRightIcon, { style: { width: 12, height: 12 } })
2002
2498
  }
2003
2499
  )
2004
- ] }),
2005
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex flex-1 items-center justify-end gap-2", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2500
+ ]
2501
+ }
2502
+ ),
2503
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2504
+ "div",
2505
+ {
2506
+ style: {
2507
+ display: "flex",
2508
+ flex: "1 1 0%",
2509
+ alignItems: "center",
2510
+ justifyContent: "flex-end",
2511
+ gap: 8
2512
+ },
2513
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2006
2514
  "select",
2007
2515
  {
2008
2516
  value: pageSize,
2009
2517
  onChange: (e) => handlePageSizeChange(Number(e.target.value)),
2010
- className: "bg-background text-foreground hover:border-primary cursor-pointer rounded border px-1.5 py-0.5 text-xs",
2011
- style: { height: "24px" },
2012
- children: [10, 15, 20, 25, 50, 100].map((size) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("option", { value: size, children: [
2518
+ style: {
2519
+ cursor: "pointer",
2520
+ borderRadius: 4,
2521
+ border: "1px solid rgba(128,128,128,0.2)",
2522
+ paddingLeft: 6,
2523
+ paddingRight: 6,
2524
+ paddingTop: 2,
2525
+ paddingBottom: 2,
2526
+ fontSize: 12,
2527
+ height: 24,
2528
+ background: "inherit",
2529
+ color: "inherit"
2530
+ },
2531
+ children: [10, 15, 20, 25, 50, 100].map((size) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("option", { value: size, children: [
2013
2532
  size,
2014
2533
  " / page"
2015
2534
  ] }, size))
2016
2535
  }
2017
- ) })
2018
- ]
2019
- }
2020
- )
2021
- ]
2022
- }
2023
- ),
2024
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_core.DragOverlay, { children: activeColumn ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2025
- "div",
2026
- {
2027
- className: `flex h-9 items-center truncate overflow-hidden border border-dashed shadow-md backdrop-blur ${classNames.header ?? ""} ${classNames.dragHeader ?? ""}`,
2028
- style: {
2029
- width: `${activeColumn.width ?? 150}px`,
2030
- cursor: "grabbing",
2031
- ...styles.header,
2032
- ...styles.dragHeader
2033
- },
2034
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "relative z-10 flex h-full flex-1 items-center gap-1 truncate overflow-hidden px-2 font-medium", children: [
2035
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.GripVertical, { className: "h-3 w-3 shrink-0" }),
2036
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "min-w-0 truncate overflow-hidden text-left text-ellipsis whitespace-nowrap select-none", children: typeof activeColumn.title === "string" ? activeColumn.title : activeColumn.key })
2037
- ] })
2038
- }
2039
- ) : null })
2040
- ]
2041
- }
2042
- );
2536
+ )
2537
+ }
2538
+ )
2539
+ ]
2540
+ }
2541
+ )
2542
+ ]
2543
+ }
2544
+ ),
2545
+ typeof document !== "undefined" && (0, import_react_dom2.createPortal)(
2546
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2547
+ "div",
2548
+ {
2549
+ ref: ghostRef,
2550
+ className: `${classNames.header ?? ""} ${classNames.dragHeader ?? ""}`,
2551
+ style: {
2552
+ display: "none",
2553
+ position: "fixed",
2554
+ zIndex: 99999,
2555
+ height: 36,
2556
+ alignItems: "center",
2557
+ overflow: "hidden",
2558
+ textOverflow: "ellipsis",
2559
+ whiteSpace: "nowrap",
2560
+ borderRadius: 6,
2561
+ border: "1px dashed rgba(128,128,128,0.3)",
2562
+ boxShadow: "0 8px 32px rgba(0,0,0,0.18)",
2563
+ backdropFilter: "blur(16px)",
2564
+ WebkitBackdropFilter: "blur(16px)",
2565
+ backgroundColor: "rgba(128,128,128,0.12)",
2566
+ cursor: "grabbing",
2567
+ pointerEvents: "none",
2568
+ ...styles.header,
2569
+ ...styles.dragHeader
2570
+ },
2571
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
2572
+ "div",
2573
+ {
2574
+ style: {
2575
+ display: "flex",
2576
+ height: "100%",
2577
+ flex: "1 1 0%",
2578
+ alignItems: "center",
2579
+ gap: 4,
2580
+ overflow: "hidden",
2581
+ paddingLeft: 8,
2582
+ paddingRight: 8,
2583
+ fontWeight: 500
2584
+ },
2585
+ children: [
2586
+ icons?.gripVertical ?? gripIcon ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2587
+ GripVerticalIcon,
2588
+ {
2589
+ style: { width: 12, height: 12, flexShrink: 0 }
2590
+ }
2591
+ ),
2592
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2593
+ "div",
2594
+ {
2595
+ style: {
2596
+ minWidth: 0,
2597
+ overflow: "hidden",
2598
+ textOverflow: "ellipsis",
2599
+ whiteSpace: "nowrap",
2600
+ textAlign: "left",
2601
+ userSelect: "none"
2602
+ },
2603
+ children: activeColumn ? typeof activeColumn.title === "string" ? activeColumn.title : activeColumn.key : ""
2604
+ }
2605
+ )
2606
+ ]
2607
+ }
2608
+ )
2609
+ }
2610
+ ),
2611
+ document.body
2612
+ )
2613
+ ] });
2043
2614
  }
2044
2615
  // Annotate the CommonJS export names for ESM import in node:
2045
2616
  0 && (module.exports = {