react-glide-table 1.0.2 → 1.1.1

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.cjs CHANGED
@@ -20,20 +20,66 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ CELL_SELECTION_EDGES_CLASS: () => CELL_SELECTION_EDGES_CLASS,
24
+ DEFAULT_DATA_TABLE_LABELS: () => DEFAULT_DATA_TABLE_LABELS,
25
+ DEFAULT_TREE_CHILDREN_FIELD: () => DEFAULT_TREE_CHILDREN_FIELD,
26
+ DEFAULT_TREE_ID_FIELD: () => DEFAULT_TREE_ID_FIELD,
27
+ DEFAULT_TREE_PARENT_ID_FIELD: () => DEFAULT_TREE_PARENT_ID_FIELD,
28
+ DEFAULT_TREE_QTY_FIELD: () => DEFAULT_TREE_QTY_FIELD,
23
29
  DataTable: () => DataTable,
24
30
  Table: () => Table,
25
- createTable: () => createTable
31
+ applyCellEdit: () => applyCellEdit,
32
+ applyFillData: () => applyFillData,
33
+ applySelectionUpdater: () => applySelectionUpdater,
34
+ buildColumnRowSpanMap: () => buildColumnRowSpanMap,
35
+ canExpandRow: () => canExpandRow,
36
+ collectFillChanges: () => collectFillChanges,
37
+ collectRowSpanColumns: () => collectRowSpanColumns,
38
+ createTable: () => createTable,
39
+ getCellEditDraftValue: () => getCellEditDraftValue,
40
+ getCellSelectionEdgeStyle: () => getCellSelectionEdgeStyle,
41
+ getColumnEditType: () => getColumnEditType,
42
+ getRowIndexInMergedCell: () => getRowIndexInMergedCell,
43
+ hasCellSelectionEdges: () => hasCellSelectionEdges,
44
+ isCellInSelection: () => isCellInSelection,
45
+ isColumnEditable: () => isColumnEditable,
46
+ parseCellEditValue: () => parseCellEditValue,
47
+ resolveDataTableLabels: () => resolveDataTableLabels,
48
+ resolveRowSelection: () => resolveRowSelection,
49
+ resolveRowSpanAt: () => resolveRowSpanAt,
50
+ toggleExpandedRowId: () => toggleExpandedRowId,
51
+ useCellEdit: () => useCellEdit,
52
+ useCellSelection: () => useCellSelection,
53
+ useConvertTreeData: () => useConvertTreeData,
54
+ useGlideTable: () => useGlideTable
26
55
  });
27
56
  module.exports = __toCommonJS(index_exports);
28
57
 
29
- // src/components/ui/table/components/DataTable/DataTable.tsx
30
- var import_react_table2 = require("@tanstack/react-table");
31
- var import_react_virtual = require("@tanstack/react-virtual");
32
- var import_react6 = require("react");
58
+ // src/core/labels.ts
59
+ var DEFAULT_DATA_TABLE_LABELS = {
60
+ empty: "No data",
61
+ loading: "Loading...",
62
+ selection: (selectedCount) => selectedCount > 0 ? `\u2713 ${selectedCount} selected` : null,
63
+ expandRow: "Expand row",
64
+ collapseRow: "Collapse row"
65
+ };
66
+ function resolveDataTableLabels(partial) {
67
+ return {
68
+ ...DEFAULT_DATA_TABLE_LABELS,
69
+ ...partial
70
+ };
71
+ }
33
72
 
34
- // src/components/ui/table/components/DataTable/DataTableRow.tsx
73
+ // src/core/treeDefaults.ts
74
+ var DEFAULT_TREE_ID_FIELD = "id";
75
+ var DEFAULT_TREE_PARENT_ID_FIELD = "parentId";
76
+ var DEFAULT_TREE_CHILDREN_FIELD = "children";
77
+ var DEFAULT_TREE_QTY_FIELD = "qty";
78
+
79
+ // src/core/useGlideTable.ts
35
80
  var import_react_table = require("@tanstack/react-table");
36
- var import_react3 = require("react");
81
+ var import_react_virtual = require("@tanstack/react-virtual");
82
+ var import_react4 = require("react");
37
83
 
38
84
  // src/components/ui/table/constants.ts
39
85
  var CELL_ALIGN_CLASS = {
@@ -47,23 +93,8 @@ var CELL_SELECTION_FILL_CLASS = "cell-selection-fill";
47
93
  var DATA_TABLE_ROW_HEIGHT = 44;
48
94
  var DATA_TABLE_VIRTUAL_OVERSCAN = 8;
49
95
 
50
- // src/components/ui/table/DataTableContext.tsx
96
+ // src/components/ui/table/features/cell-edit/useCellEdit.ts
51
97
  var import_react = require("react");
52
- var import_jsx_runtime = require("react/jsx-runtime");
53
- var DataTableContext = (0, import_react.createContext)(null);
54
- function useDataTableRowContext() {
55
- const context = (0, import_react.use)(DataTableContext);
56
- if (!context) {
57
- throw new Error("useDataTableRowContext must be used within a DataTableContextProvider");
58
- }
59
- return context;
60
- }
61
- function DataTableContextProvider({
62
- value,
63
- children
64
- }) {
65
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DataTableContext, { value, children });
66
- }
67
98
 
68
99
  // src/components/ui/table/features/cell-edit/cellEdit.ts
69
100
  function getColumnAccessorKey(columnDef) {
@@ -111,6 +142,87 @@ function applyCellEdit(data, rows, rowIndex, colIndex, raw) {
111
142
  return newData;
112
143
  }
113
144
 
145
+ // src/components/ui/table/features/cell-edit/useCellEdit.ts
146
+ function useCellEdit({
147
+ data,
148
+ rows,
149
+ onDataChange,
150
+ onCellChange
151
+ }) {
152
+ const [editingCell, setEditingCell] = (0, import_react.useState)(null);
153
+ const [draftValue, setDraftValue] = (0, import_react.useState)("");
154
+ const draftValueRef = (0, import_react.useRef)(draftValue);
155
+ const editingCellRef = (0, import_react.useRef)(editingCell);
156
+ (0, import_react.useEffect)(() => {
157
+ draftValueRef.current = draftValue;
158
+ }, [draftValue]);
159
+ (0, import_react.useEffect)(() => {
160
+ editingCellRef.current = editingCell;
161
+ }, [editingCell]);
162
+ const cancelEdit = (0, import_react.useCallback)(() => {
163
+ setEditingCell(null);
164
+ setDraftValue("");
165
+ }, []);
166
+ const commitEdit = (0, import_react.useCallback)(
167
+ (raw) => {
168
+ const current = editingCellRef.current;
169
+ if (!current) return true;
170
+ if (!onCellChange && !onDataChange) {
171
+ cancelEdit();
172
+ return true;
173
+ }
174
+ const row = rows[current.rowIndex];
175
+ const cell = row?.getVisibleCells()[current.colIndex];
176
+ if (!row || !cell) {
177
+ cancelEdit();
178
+ return true;
179
+ }
180
+ const value = raw ?? draftValueRef.current;
181
+ if (!isColumnEditable(cell.column.columnDef)) {
182
+ cancelEdit();
183
+ return true;
184
+ }
185
+ const parsed = parseCellEditValue(value, getColumnEditType(cell.column.columnDef));
186
+ if (!parsed.ok) return false;
187
+ if (onCellChange) {
188
+ onCellChange(row.id, cell.column.id, parsed.value);
189
+ cancelEdit();
190
+ return true;
191
+ }
192
+ const next = applyCellEdit(data, rows, current.rowIndex, current.colIndex, value);
193
+ if (!next) return false;
194
+ onDataChange?.(next);
195
+ cancelEdit();
196
+ return true;
197
+ },
198
+ [cancelEdit, data, onCellChange, onDataChange, rows]
199
+ );
200
+ const startEdit = (0, import_react.useCallback)(
201
+ (rowIndex, colIndex) => {
202
+ const cell = rows[rowIndex]?.getVisibleCells()[colIndex];
203
+ if (!cell || !isColumnEditable(cell.column.columnDef)) return;
204
+ const current = editingCellRef.current;
205
+ if (current && (current.rowIndex !== rowIndex || current.colIndex !== colIndex) && !commitEdit()) {
206
+ return;
207
+ }
208
+ setEditingCell({ rowIndex, colIndex });
209
+ setDraftValue(getCellEditDraftValue(cell.getValue()));
210
+ },
211
+ [commitEdit, rows]
212
+ );
213
+ return {
214
+ editingCell,
215
+ draftValue,
216
+ setDraftValue,
217
+ startEdit,
218
+ commitEdit,
219
+ cancelEdit
220
+ };
221
+ }
222
+
223
+ // src/components/ui/table/features/cell-selection/useCellSelection.ts
224
+ var import_react2 = require("react");
225
+
114
226
  // src/components/ui/table/features/cell-selection/cellSelection.ts
115
227
  var INITIAL_DRAG_STATE = {
116
228
  isSelecting: false,
@@ -134,7 +246,10 @@ function getRowIndexInMergedCell(clientY, cellElement, rowIndex, rowSpan) {
134
246
  const rect = cellElement.getBoundingClientRect();
135
247
  const relativeY = clientY - rect.top;
136
248
  const rowHeight = rect.height / rowSpan;
137
- const offset = Math.min(Math.max(Math.floor(relativeY / rowHeight), 0), rowSpan - 1);
249
+ const offset = Math.min(
250
+ Math.max(Math.floor(relativeY / rowHeight), 0),
251
+ rowSpan - 1
252
+ );
138
253
  return rowIndex + offset;
139
254
  }
140
255
  function isCellInSelection(rowIndex, colIndex, bounds, rowSpan = 1) {
@@ -150,31 +265,348 @@ function getActiveSelectionBounds(dragState, selectionBounds) {
150
265
  }
151
266
  var SELECTION_EDGE_WIDTH_PX = 2;
152
267
  var SELECTION_EDGE_COLOR = "var(--color-brand-primary)";
153
- function getCellSelectionEdgeStyle(rowIndex, colIndex, bounds, rowSpan = 1) {
154
- if (!isCellInSelection(rowIndex, colIndex, bounds, rowSpan) || !bounds) return void 0;
268
+ var CELL_SELECTION_EDGES_CLASS = "cell-selection-edges";
269
+ function getMergedCellStepEdges(rowIndex, colIndex, bounds, rowSpan, isVisuallySelectedAt) {
270
+ const cellEndRow = rowIndex + rowSpan - 1;
271
+ const span = cellEndRow - rowIndex + 1;
272
+ if (span <= 1) return [];
273
+ const edges = [];
274
+ const isNeighborSelected = (row, neighborCol) => {
275
+ if (isVisuallySelectedAt) {
276
+ return isVisuallySelectedAt(row, neighborCol);
277
+ }
278
+ return row >= bounds.startRow && row <= bounds.endRow && neighborCol >= bounds.startCol && neighborCol <= bounds.endCol;
279
+ };
280
+ const pushUnselectedRuns = (side, neighborCol, fromRow, toRowExclusive) => {
281
+ let runStart = null;
282
+ for (let row = fromRow; row < toRowExclusive; row++) {
283
+ if (!isNeighborSelected(row, neighborCol)) {
284
+ if (runStart === null) runStart = row;
285
+ continue;
286
+ }
287
+ if (runStart !== null) {
288
+ edges.push({
289
+ side,
290
+ offsetRatio: (runStart - rowIndex) / span,
291
+ heightRatio: (row - runStart) / span
292
+ });
293
+ runStart = null;
294
+ }
295
+ }
296
+ if (runStart !== null) {
297
+ edges.push({
298
+ side,
299
+ offsetRatio: (runStart - rowIndex) / span,
300
+ heightRatio: (toRowExclusive - runStart) / span
301
+ });
302
+ }
303
+ };
304
+ const collectSide = (side, neighborCol) => {
305
+ if (bounds.startRow > rowIndex) {
306
+ pushUnselectedRuns(
307
+ side,
308
+ neighborCol,
309
+ rowIndex,
310
+ Math.min(bounds.startRow, cellEndRow + 1)
311
+ );
312
+ }
313
+ if (bounds.endRow < cellEndRow) {
314
+ pushUnselectedRuns(
315
+ side,
316
+ neighborCol,
317
+ Math.max(bounds.endRow + 1, rowIndex),
318
+ cellEndRow + 1
319
+ );
320
+ }
321
+ };
322
+ if (colIndex < bounds.endCol) {
323
+ collectSide("right", colIndex + 1);
324
+ }
325
+ if (colIndex > bounds.startCol) {
326
+ collectSide("left", colIndex - 1);
327
+ }
328
+ return edges;
329
+ }
330
+ function buildPartialVerticalGradient(edge) {
331
+ const startPct = edge.offsetRatio * 100;
332
+ const endPct = (edge.offsetRatio + edge.heightRatio) * 100;
333
+ const overlapPx = SELECTION_EDGE_WIDTH_PX + 1;
334
+ const isTopProtrusion = edge.offsetRatio === 0 && edge.heightRatio < 1;
335
+ const isBottomProtrusion = edge.offsetRatio > 0;
336
+ const startStop = isBottomProtrusion ? `calc(${startPct}% - ${overlapPx}px)` : `${startPct}%`;
337
+ const endStop = isTopProtrusion ? `calc(${endPct}% + ${overlapPx}px)` : `${endPct}%`;
338
+ const xPos = edge.side === "left" ? "0" : "100%";
339
+ const layers = [
340
+ {
341
+ image: `linear-gradient(to bottom, transparent 0%, transparent ${startStop}, ${SELECTION_EDGE_COLOR} ${startStop}, ${SELECTION_EDGE_COLOR} ${endStop}, transparent ${endStop}, transparent 100%)`,
342
+ size: `${SELECTION_EDGE_WIDTH_PX}px 100%`,
343
+ position: `${xPos} 0`
344
+ }
345
+ ];
346
+ if (isTopProtrusion || isBottomProtrusion) {
347
+ const capTop = isTopProtrusion ? `calc(${endPct}% - ${SELECTION_EDGE_WIDTH_PX}px)` : `calc(${startPct}% - ${SELECTION_EDGE_WIDTH_PX}px)`;
348
+ layers.push({
349
+ image: `linear-gradient(${SELECTION_EDGE_COLOR}, ${SELECTION_EDGE_COLOR})`,
350
+ size: `${SELECTION_EDGE_WIDTH_PX}px ${SELECTION_EDGE_WIDTH_PX}px`,
351
+ position: `${xPos} ${capTop}`
352
+ });
353
+ }
354
+ return layers;
355
+ }
356
+ function getCellSelectionEdgeStyle(rowIndex, colIndex, bounds, rowSpan = 1, isVisuallySelectedAt) {
357
+ if (!isCellInSelection(rowIndex, colIndex, bounds, rowSpan) || !bounds)
358
+ return void 0;
155
359
  const cellEndRow = rowIndex + rowSpan - 1;
156
360
  const isTopEdge = bounds.startRow >= rowIndex && bounds.startRow <= cellEndRow;
157
361
  const isBottomEdge = bounds.endRow >= rowIndex && bounds.endRow <= cellEndRow;
158
362
  const isLeftEdge = colIndex === bounds.startCol;
159
363
  const isRightEdge = colIndex === bounds.endCol;
364
+ const selectionContinuesBelow = cellEndRow < bounds.endRow;
160
365
  const shadows = [];
161
366
  if (isTopEdge) {
162
- shadows.push(`inset 0 ${SELECTION_EDGE_WIDTH_PX}px 0 0 ${SELECTION_EDGE_COLOR}`);
367
+ shadows.push(
368
+ `inset 0 ${SELECTION_EDGE_WIDTH_PX}px 0 0 ${SELECTION_EDGE_COLOR}`
369
+ );
163
370
  }
164
371
  if (isBottomEdge) {
165
- shadows.push(`inset 0 -${SELECTION_EDGE_WIDTH_PX}px 0 0 ${SELECTION_EDGE_COLOR}`);
372
+ shadows.push(
373
+ `inset 0 -${SELECTION_EDGE_WIDTH_PX}px 0 0 ${SELECTION_EDGE_COLOR}`
374
+ );
166
375
  }
167
376
  if (isLeftEdge) {
168
- shadows.push(`inset ${SELECTION_EDGE_WIDTH_PX}px 0 0 0 ${SELECTION_EDGE_COLOR}`);
377
+ shadows.push(
378
+ `inset ${SELECTION_EDGE_WIDTH_PX}px 0 0 0 ${SELECTION_EDGE_COLOR}`
379
+ );
169
380
  }
170
381
  if (isRightEdge) {
171
- shadows.push(`inset -${SELECTION_EDGE_WIDTH_PX}px 0 0 0 ${SELECTION_EDGE_COLOR}`);
382
+ shadows.push(
383
+ `inset -${SELECTION_EDGE_WIDTH_PX}px 0 0 0 ${SELECTION_EDGE_COLOR}`
384
+ );
385
+ }
386
+ const stepEdges = getMergedCellStepEdges(
387
+ rowIndex,
388
+ colIndex,
389
+ bounds,
390
+ rowSpan,
391
+ isVisuallySelectedAt
392
+ );
393
+ const gradients = [];
394
+ const sizes = [];
395
+ const positions = [];
396
+ for (const edge of stepEdges) {
397
+ for (const partial of buildPartialVerticalGradient(edge)) {
398
+ gradients.push(partial.image);
399
+ sizes.push(partial.size);
400
+ positions.push(partial.position);
401
+ }
402
+ }
403
+ if (shadows.length === 0 && gradients.length === 0 && !selectionContinuesBelow) {
404
+ return void 0;
405
+ }
406
+ const style = {};
407
+ if (shadows.length > 0) {
408
+ style["--selection-edge-shadows"] = shadows.join(", ");
409
+ }
410
+ if (gradients.length > 0) {
411
+ style["--selection-edge-gradients"] = gradients.join(", ");
412
+ style["--selection-edge-sizes"] = sizes.join(", ");
413
+ style["--selection-edge-positions"] = positions.join(", ");
414
+ }
415
+ if (selectionContinuesBelow) {
416
+ style.borderBottomColor = "var(--color-brand-surface)";
417
+ }
418
+ return style;
419
+ }
420
+ function hasCellSelectionEdges(style) {
421
+ return Boolean(
422
+ style?.["--selection-edge-shadows"] || style?.["--selection-edge-gradients"]
423
+ );
424
+ }
425
+
426
+ // src/components/ui/table/features/cell-selection/fillData.ts
427
+ function getColumnAccessorKey2(columnDef) {
428
+ if ("accessorKey" in columnDef && columnDef.accessorKey) {
429
+ return String(columnDef.accessorKey);
430
+ }
431
+ return columnDef.id;
432
+ }
433
+ function collectFillTargets(rows, sourceBounds, fillBounds) {
434
+ const targets = [];
435
+ const sourceHeight = sourceBounds.endRow - sourceBounds.startRow + 1;
436
+ const sourceWidth = sourceBounds.endCol - sourceBounds.startCol + 1;
437
+ for (let rowIndex = fillBounds.startRow; rowIndex <= fillBounds.endRow; rowIndex += 1) {
438
+ for (let colIndex = fillBounds.startCol; colIndex <= fillBounds.endCol; colIndex += 1) {
439
+ if (isCellInSelection(rowIndex, colIndex, sourceBounds)) continue;
440
+ const offsetRow = rowIndex - sourceBounds.startRow;
441
+ const offsetCol = colIndex - sourceBounds.startCol;
442
+ const sourceRowIndex = sourceBounds.startRow + (offsetRow % sourceHeight + sourceHeight) % sourceHeight;
443
+ const sourceColIndex = sourceBounds.startCol + (offsetCol % sourceWidth + sourceWidth) % sourceWidth;
444
+ const targetRow = rows[rowIndex];
445
+ const targetCell = targetRow?.getVisibleCells()[colIndex];
446
+ const sourceCell = rows[sourceRowIndex]?.getVisibleCells()[sourceColIndex];
447
+ if (!targetRow || !targetCell || !sourceCell) continue;
448
+ const accessorKey = getColumnAccessorKey2(
449
+ targetCell.column.columnDef
450
+ );
451
+ if (!accessorKey) continue;
452
+ targets.push({
453
+ rowIndex,
454
+ accessorKey,
455
+ columnId: targetCell.column.id,
456
+ value: sourceCell.getValue(),
457
+ rowId: targetRow.id
458
+ });
459
+ }
460
+ }
461
+ return targets;
462
+ }
463
+ function collectFillChanges(rows, sourceBounds, fillBounds) {
464
+ return collectFillTargets(rows, sourceBounds, fillBounds).map(
465
+ ({ rowId, columnId, value }) => ({ rowId, columnId, value })
466
+ );
467
+ }
468
+ function applyFillData(data, rows, sourceBounds, fillBounds) {
469
+ const newData = data.map((row) => ({ ...row }));
470
+ const targets = collectFillTargets(rows, sourceBounds, fillBounds);
471
+ for (const target of targets) {
472
+ if (!newData[target.rowIndex]) continue;
473
+ newData[target.rowIndex][target.accessorKey] = target.value;
172
474
  }
173
- return shadows.length > 0 ? { boxShadow: shadows.join(", ") } : void 0;
475
+ return newData;
476
+ }
477
+ function hasFillExtension(sourceBounds, fillBounds) {
478
+ if (!sourceBounds) return false;
479
+ return fillBounds.startRow < sourceBounds.startRow || fillBounds.endRow > sourceBounds.endRow || fillBounds.startCol < sourceBounds.startCol || fillBounds.endCol > sourceBounds.endCol;
480
+ }
481
+
482
+ // src/components/ui/table/features/cell-selection/useCellSelection.ts
483
+ function useCellSelection({
484
+ data,
485
+ rows,
486
+ enabled = true,
487
+ onDataChange,
488
+ onBatchChange
489
+ }) {
490
+ const [dragState, setDragState] = (0, import_react2.useState)(INITIAL_DRAG_STATE);
491
+ const cellSelectionBounds = getCellSelectionBounds(dragState.start, dragState.end);
492
+ const activeSelectionBounds = enabled ? getActiveSelectionBounds(dragState, cellSelectionBounds) : null;
493
+ const handleCellMouseDown = (0, import_react2.useCallback)(
494
+ (rowIndex, colIndex) => {
495
+ if (!enabled) return;
496
+ setDragState({
497
+ isSelecting: true,
498
+ isFillDragging: false,
499
+ start: { row: rowIndex, col: colIndex },
500
+ end: { row: rowIndex, col: colIndex },
501
+ fillAnchor: null,
502
+ fillEnd: null
503
+ });
504
+ },
505
+ [enabled]
506
+ );
507
+ const handleCellMouseEnter = (0, import_react2.useCallback)(
508
+ (rowIndex, colIndex) => {
509
+ if (!enabled) return;
510
+ setDragState((prev) => {
511
+ if (prev.isSelecting) {
512
+ return { ...prev, end: { row: rowIndex, col: colIndex } };
513
+ }
514
+ if (prev.isFillDragging) {
515
+ return { ...prev, fillEnd: { row: rowIndex, col: colIndex } };
516
+ }
517
+ return prev;
518
+ });
519
+ },
520
+ [enabled]
521
+ );
522
+ const handleFillHandleMouseDown = (0, import_react2.useCallback)(
523
+ (rowIndex, colIndex) => {
524
+ if (!enabled) return;
525
+ setDragState((prev) => {
526
+ const bounds = getCellSelectionBounds(prev.start, prev.end);
527
+ if (!bounds) return prev;
528
+ return {
529
+ ...prev,
530
+ isSelecting: false,
531
+ isFillDragging: true,
532
+ fillAnchor: { row: bounds.startRow, col: bounds.startCol },
533
+ fillEnd: { row: rowIndex, col: colIndex }
534
+ };
535
+ });
536
+ },
537
+ [enabled]
538
+ );
539
+ (0, import_react2.useEffect)(() => {
540
+ if (!enabled) {
541
+ setDragState(INITIAL_DRAG_STATE);
542
+ }
543
+ }, [enabled]);
544
+ (0, import_react2.useEffect)(() => {
545
+ if (!enabled) return;
546
+ const handleKeyDown = (e) => {
547
+ if ((e.ctrlKey || e.metaKey) && e.key === "c" && activeSelectionBounds) {
548
+ const { startRow, endRow, startCol, endCol } = activeSelectionBounds;
549
+ const selectedData = rows.slice(startRow, endRow + 1).map((row) => {
550
+ const cells = row.getVisibleCells();
551
+ return cells.slice(startCol, endCol + 1).map((cell) => cell.getValue()).join(" ");
552
+ }).join("\n");
553
+ navigator.clipboard.writeText(selectedData);
554
+ }
555
+ };
556
+ window.addEventListener("keydown", handleKeyDown);
557
+ return () => window.removeEventListener("keydown", handleKeyDown);
558
+ }, [activeSelectionBounds, enabled, rows]);
559
+ (0, import_react2.useEffect)(() => {
560
+ if (!enabled) return;
561
+ const handleMouseUp = () => {
562
+ setDragState((prev) => {
563
+ if (prev.isFillDragging && prev.fillAnchor && prev.fillEnd) {
564
+ const sourceBounds = getCellSelectionBounds(prev.start, prev.end);
565
+ const newBounds = getCellSelectionBounds(prev.fillAnchor, prev.fillEnd);
566
+ if (newBounds) {
567
+ if (hasFillExtension(sourceBounds, newBounds) && sourceBounds) {
568
+ if (onBatchChange) {
569
+ const changes = collectFillChanges(rows, sourceBounds, newBounds);
570
+ if (changes.length > 0) {
571
+ onBatchChange(changes);
572
+ }
573
+ } else if (onDataChange) {
574
+ onDataChange(applyFillData(data, rows, sourceBounds, newBounds));
575
+ }
576
+ }
577
+ return {
578
+ isSelecting: false,
579
+ isFillDragging: false,
580
+ start: { row: newBounds.startRow, col: newBounds.startCol },
581
+ end: { row: newBounds.endRow, col: newBounds.endCol },
582
+ fillAnchor: null,
583
+ fillEnd: null
584
+ };
585
+ }
586
+ }
587
+ if (prev.isSelecting) {
588
+ return { ...prev, isSelecting: false };
589
+ }
590
+ if (prev.isFillDragging) {
591
+ return { ...prev, isFillDragging: false, fillAnchor: null, fillEnd: null };
592
+ }
593
+ return prev;
594
+ });
595
+ };
596
+ window.addEventListener("mouseup", handleMouseUp);
597
+ return () => window.removeEventListener("mouseup", handleMouseUp);
598
+ }, [data, enabled, onBatchChange, onDataChange, rows]);
599
+ return {
600
+ dragState: enabled ? dragState : INITIAL_DRAG_STATE,
601
+ activeSelectionBounds,
602
+ handleCellMouseDown,
603
+ handleCellMouseEnter,
604
+ handleFillHandleMouseDown
605
+ };
174
606
  }
175
607
 
176
608
  // src/components/ui/table/features/row-expand/row-expand.ts
177
- var import_react2 = require("react");
609
+ var import_react3 = require("react");
178
610
  function getFieldValue(row, key) {
179
611
  return row[key];
180
612
  }
@@ -195,20 +627,21 @@ function toggleExpandedRowId(rowId, previous) {
195
627
  var useConvertTreeData = ({
196
628
  data,
197
629
  enabled = true,
198
- toggleField = "materialCode",
199
- childField = "assemblyCode",
200
- flattenField = "assemblyMaterials",
630
+ toggleField = DEFAULT_TREE_ID_FIELD,
631
+ childField = DEFAULT_TREE_PARENT_ID_FIELD,
632
+ flattenField = DEFAULT_TREE_CHILDREN_FIELD,
633
+ qtyField = DEFAULT_TREE_QTY_FIELD,
201
634
  preventExpand = false,
202
635
  startIndex = 1,
203
636
  expandedRows,
204
637
  onExpandedRowsChange
205
638
  }) => {
206
- const onExpandedRowsChangeRef = (0, import_react2.useRef)(onExpandedRowsChange);
207
- const hasInitializedRef = (0, import_react2.useRef)(false);
208
- (0, import_react2.useEffect)(() => {
639
+ const onExpandedRowsChangeRef = (0, import_react3.useRef)(onExpandedRowsChange);
640
+ const hasInitializedRef = (0, import_react3.useRef)(false);
641
+ (0, import_react3.useEffect)(() => {
209
642
  onExpandedRowsChangeRef.current = onExpandedRowsChange;
210
643
  }, [onExpandedRowsChange]);
211
- (0, import_react2.useEffect)(() => {
644
+ (0, import_react3.useEffect)(() => {
212
645
  if (!data || data.length === 0) {
213
646
  hasInitializedRef.current = false;
214
647
  return;
@@ -218,7 +651,7 @@ var useConvertTreeData = ({
218
651
  onExpandedRowsChangeRef.current?.(new Set(ids));
219
652
  hasInitializedRef.current = true;
220
653
  }, [enabled, data, toggleField]);
221
- const processedData = (0, import_react2.useMemo)(() => {
654
+ const processedData = (0, import_react3.useMemo)(() => {
222
655
  if (!enabled || !data || data.length === 0) return [];
223
656
  const flattenedData = [];
224
657
  const flattenItems = (items) => {
@@ -292,7 +725,7 @@ var useConvertTreeData = ({
292
725
  });
293
726
  return rootItems;
294
727
  }, [enabled, data, toggleField, childField, flattenField]);
295
- const flattenTree = (0, import_react2.useMemo)(() => {
728
+ const flattenTree = (0, import_react3.useMemo)(() => {
296
729
  if (!enabled) return [];
297
730
  const flatten = (nodes, result = [], level = 0) => {
298
731
  nodes.forEach((node, index) => {
@@ -318,19 +751,28 @@ var useConvertTreeData = ({
318
751
  const parentItem = flattenedData.find(
319
752
  (parent) => getFieldValue(parent, toggleField) === getFieldValue(item, childField)
320
753
  );
321
- const parentAmount = parentItem ? Number(getFieldValue(parentItem, "amount") ?? 1) : 1;
754
+ const parentAmount = parentItem ? Number(getFieldValue(parentItem, qtyField) ?? 1) : 1;
322
755
  item.parentCount = parentAmount || 1;
323
756
  } else {
324
757
  item.parentCount = 1;
325
758
  }
326
759
  });
327
760
  return flattenedData;
328
- }, [enabled, processedData, startIndex, toggleField, childField, preventExpand, expandedRows]);
329
- const sortedData = (0, import_react2.useMemo)(() => {
330
- if (!enabled) {
331
- return data ?? [];
332
- }
333
- return [...flattenTree].sort((a, b) => {
761
+ }, [
762
+ enabled,
763
+ processedData,
764
+ startIndex,
765
+ toggleField,
766
+ childField,
767
+ qtyField,
768
+ preventExpand,
769
+ expandedRows
770
+ ]);
771
+ const sortedData = (0, import_react3.useMemo)(() => {
772
+ if (!enabled) {
773
+ return data ?? [];
774
+ }
775
+ return [...flattenTree].sort((a, b) => {
334
776
  const aParts = String(a.treeNo ?? "").split("-").map(Number);
335
777
  const bParts = String(b.treeNo ?? "").split("-").map(Number);
336
778
  for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) {
@@ -346,185 +788,599 @@ var useConvertTreeData = ({
346
788
  return sortedData;
347
789
  };
348
790
 
349
- // src/components/ui/table/components/icons.tsx
350
- var import_jsx_runtime2 = require("react/jsx-runtime");
351
- function ChevronDown({ className, "aria-hidden": ariaHidden = true }) {
352
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
353
- "svg",
354
- {
355
- className,
356
- "aria-hidden": ariaHidden,
357
- width: "16",
358
- height: "16",
359
- viewBox: "0 0 24 24",
360
- fill: "none",
361
- stroke: "currentColor",
362
- strokeWidth: "2",
363
- strokeLinecap: "round",
364
- strokeLinejoin: "round",
365
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "m6 9 6 6 6-6" })
366
- }
367
- );
791
+ // src/components/ui/table/features/row-selection/rowSelection.ts
792
+ function resolveRowSelection(mode, controlledSelection, internalSelection) {
793
+ if (mode === "none") return {};
794
+ return controlledSelection ?? internalSelection;
368
795
  }
369
- function ChevronUp({ className, "aria-hidden": ariaHidden = true }) {
370
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
371
- "svg",
372
- {
373
- className,
374
- "aria-hidden": ariaHidden,
375
- width: "16",
376
- height: "16",
377
- viewBox: "0 0 24 24",
378
- fill: "none",
379
- stroke: "currentColor",
380
- strokeWidth: "2",
381
- strokeLinecap: "round",
382
- strokeLinejoin: "round",
383
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "m18 15-6-6-6 6" })
384
- }
385
- );
796
+ function normalizeSingleSelection(next) {
797
+ const selectedIds = Object.keys(next).filter((id) => next[id]);
798
+ if (selectedIds.length <= 1) return next;
799
+ return { [selectedIds[selectedIds.length - 1]]: true };
386
800
  }
387
- function ChevronLeft({ className, "aria-hidden": ariaHidden = true }) {
388
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
389
- "svg",
390
- {
391
- className,
392
- "aria-hidden": ariaHidden,
393
- width: "16",
394
- height: "16",
395
- viewBox: "0 0 24 24",
396
- fill: "none",
397
- stroke: "currentColor",
398
- strokeWidth: "2",
399
- strokeLinecap: "round",
400
- strokeLinejoin: "round",
401
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "m15 18-6-6 6-6" })
402
- }
403
- );
801
+ function applySelectionUpdater(mode, updater, previous) {
802
+ const next = typeof updater === "function" ? updater(previous) : updater;
803
+ return mode === "single" ? normalizeSingleSelection(next) : next;
404
804
  }
405
- function ChevronRight({ className, "aria-hidden": ariaHidden = true }) {
406
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
407
- "svg",
408
- {
409
- className,
410
- "aria-hidden": ariaHidden,
411
- width: "16",
412
- height: "16",
413
- viewBox: "0 0 24 24",
414
- fill: "none",
415
- stroke: "currentColor",
416
- strokeWidth: "2",
417
- strokeLinecap: "round",
418
- strokeLinejoin: "round",
419
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "m9 18 6-6-6-6" })
420
- }
421
- );
805
+
806
+ // src/components/ui/table/features/row-span/rowSpan.ts
807
+ function getRowFieldValue(row, key) {
808
+ return row[key];
422
809
  }
423
- function ArrowUp({ className, "aria-hidden": ariaHidden = true }) {
424
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
425
- "svg",
426
- {
427
- className,
428
- "aria-hidden": ariaHidden,
429
- width: "14",
430
- height: "14",
431
- viewBox: "0 0 24 24",
432
- fill: "none",
433
- stroke: "currentColor",
434
- strokeWidth: "2",
435
- strokeLinecap: "round",
436
- strokeLinejoin: "round",
437
- children: [
438
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "m18 15-6-6-6 6" }),
439
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M12 21V9" })
440
- ]
810
+ function computeRowSpans(data, rowSpanKey) {
811
+ if (data.length === 0) return [];
812
+ const result = [];
813
+ for (let index = 0; index < data.length; index++) {
814
+ const currentValue = getRowFieldValue(data[index], rowSpanKey);
815
+ const previousValue = index > 0 ? getRowFieldValue(data[index - 1], rowSpanKey) : void 0;
816
+ if (index > 0 && currentValue === previousValue) {
817
+ result.push({ rowSpan: 0, isFirstInGroup: false });
818
+ continue;
441
819
  }
442
- );
443
- }
444
- function ArrowDown({ className, "aria-hidden": ariaHidden = true }) {
445
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
446
- "svg",
447
- {
448
- className,
449
- "aria-hidden": ariaHidden,
450
- width: "14",
451
- height: "14",
452
- viewBox: "0 0 24 24",
453
- fill: "none",
454
- stroke: "currentColor",
455
- strokeWidth: "2",
456
- strokeLinecap: "round",
457
- strokeLinejoin: "round",
458
- children: [
459
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "m6 9 6 6 6-6" }),
460
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M12 3v12" })
461
- ]
820
+ let span = 1;
821
+ for (let nextIndex = index + 1; nextIndex < data.length; nextIndex++) {
822
+ if (getRowFieldValue(data[nextIndex], rowSpanKey) === currentValue) {
823
+ span++;
824
+ } else {
825
+ break;
826
+ }
462
827
  }
463
- );
828
+ result.push({ rowSpan: span, isFirstInGroup: true });
829
+ }
830
+ return result;
464
831
  }
465
- function ArrowUpDown({ className, "aria-hidden": ariaHidden = true }) {
466
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
467
- "svg",
468
- {
469
- className,
470
- "aria-hidden": ariaHidden,
471
- width: "14",
472
- height: "14",
473
- viewBox: "0 0 24 24",
474
- fill: "none",
475
- stroke: "currentColor",
476
- strokeWidth: "2",
477
- strokeLinecap: "round",
478
- strokeLinejoin: "round",
479
- children: [
480
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "m21 16-4 4-4-4" }),
481
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M17 20V4" }),
482
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "m3 8 4-4 4 4" }),
483
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M7 4v16" })
484
- ]
832
+ function resolveRowSpanAt(rowSpans, rowIndex) {
833
+ if (!rowSpans?.[rowIndex]) {
834
+ return { startRow: rowIndex, rowSpan: 1 };
835
+ }
836
+ const current = rowSpans[rowIndex];
837
+ if (current.rowSpan > 0) {
838
+ return { startRow: rowIndex, rowSpan: current.rowSpan };
839
+ }
840
+ for (let row = rowIndex - 1; row >= 0; row--) {
841
+ const info = rowSpans[row];
842
+ if (info && info.rowSpan > 0) {
843
+ return { startRow: row, rowSpan: info.rowSpan };
485
844
  }
486
- );
845
+ }
846
+ return { startRow: rowIndex, rowSpan: 1 };
487
847
  }
488
-
489
- // src/lib/cn.ts
490
- function cn(...inputs) {
491
- return inputs.filter(Boolean).join(" ");
848
+ function buildColumnRowSpanMap(data, columnKeys) {
849
+ const map = /* @__PURE__ */ new Map();
850
+ for (const { columnId, rowSpanKey } of columnKeys) {
851
+ map.set(columnId, computeRowSpans(data, rowSpanKey));
852
+ }
853
+ return map;
854
+ }
855
+ function collectRowSpanColumns(columns) {
856
+ const result = [];
857
+ const visit = (defs) => {
858
+ for (const columnDef of defs) {
859
+ if ("columns" in columnDef && columnDef.columns?.length) {
860
+ visit(columnDef.columns);
861
+ continue;
862
+ }
863
+ const columnId = columnDef.id ?? ("accessorKey" in columnDef && columnDef.accessorKey ? String(columnDef.accessorKey) : void 0);
864
+ if (!columnId || !columnDef.meta?.rowSpan) continue;
865
+ result.push({
866
+ columnId,
867
+ rowSpanKey: columnDef.meta.rowSpanKey ?? columnId
868
+ });
869
+ }
870
+ };
871
+ visit(columns);
872
+ return result;
492
873
  }
493
874
 
494
- // src/components/ui/table/components/DataTable/DataTableRow.tsx
495
- var import_jsx_runtime3 = require("react/jsx-runtime");
496
- function resolveExpandCellIndex(cells, toggleField) {
497
- if (!toggleField) return 0;
498
- const matchedIndex = cells.findIndex(
499
- (cell) => cell.column.id === toggleField
875
+ // src/core/useGlideTable.ts
876
+ function useGlideTable(options) {
877
+ const {
878
+ data,
879
+ columns,
880
+ rowSelectionMode = "none",
881
+ rowSelection: controlledRowSelection,
882
+ onRowSelectionChange,
883
+ selectionLabel,
884
+ emptyText,
885
+ loadingText,
886
+ labels: labelsProp,
887
+ enableRowSpan = false,
888
+ getRowId,
889
+ onRowClick,
890
+ getRowClassName,
891
+ getRowCanSelect,
892
+ selectOnRowClick = true,
893
+ enableCellSelection = true,
894
+ onDataChange,
895
+ onCellChange,
896
+ onBatchChange,
897
+ preserveRowSelection = false,
898
+ toggleField,
899
+ childField,
900
+ flattenField,
901
+ qtyField,
902
+ expandedRows: controlledExpandedRows,
903
+ onExpandedRowsChange,
904
+ preventExpand = false,
905
+ enableVirtualization = true,
906
+ estimateRowHeight = DATA_TABLE_ROW_HEIGHT,
907
+ virtualOverscan = DATA_TABLE_VIRTUAL_OVERSCAN
908
+ } = options;
909
+ const labels = (0, import_react4.useMemo)(() => {
910
+ const resolved = resolveDataTableLabels(labelsProp);
911
+ return {
912
+ ...resolved,
913
+ empty: labelsProp?.empty ?? emptyText ?? resolved.empty,
914
+ loading: labelsProp?.loading ?? loadingText ?? resolved.loading,
915
+ selection: labelsProp?.selection ?? selectionLabel ?? resolved.selection
916
+ };
917
+ }, [labelsProp, emptyText, loadingText, selectionLabel]);
918
+ const enableExpand = Boolean(toggleField);
919
+ const [internalRowSelection, setInternalRowSelection] = (0, import_react4.useState)({});
920
+ const [internalExpandedRows, setInternalExpandedRows] = (0, import_react4.useState)(
921
+ () => /* @__PURE__ */ new Set()
500
922
  );
501
- if (matchedIndex >= 0) return matchedIndex;
502
- const noColumnIndex = cells.findIndex(
503
- (cell) => cell.column.id === "no" || cell.column.id === "treeNo"
923
+ const [hoveredRowIndex, setHoveredRowIndex] = (0, import_react4.useState)(null);
924
+ const [hoveredGroupKey, setHoveredGroupKey] = (0, import_react4.useState)(null);
925
+ const scrollRef = (0, import_react4.useRef)(null);
926
+ const shouldVirtualize = enableVirtualization && !enableRowSpan;
927
+ (0, import_react4.useEffect)(() => {
928
+ if (enableVirtualization && enableRowSpan) {
929
+ console.warn(
930
+ "[useGlideTable] enableRowSpan is on; virtualization is disabled to preserve cell merges."
931
+ );
932
+ }
933
+ }, [enableVirtualization, enableRowSpan]);
934
+ const rowSelection = resolveRowSelection(
935
+ rowSelectionMode,
936
+ controlledRowSelection,
937
+ internalRowSelection
504
938
  );
505
- if (noColumnIndex >= 0 && noColumnIndex + 1 < cells.length) {
506
- return noColumnIndex + 1;
507
- }
508
- return 0;
509
- }
510
- function DataTableRow({
511
- row,
512
- onToggleSelect,
513
- virtualIndex,
514
- measureElement
515
- }) {
516
- const { rowSpan, selection, cellSelection, cellEdit, expand } = useDataTableRowContext();
517
- const {
518
- enableRowSpan,
519
- primaryRowSpanKey,
520
- columnRowSpanMap,
521
- hoveredRowIndex,
522
- hoveredGroupKey,
523
- selectedGroupKeys,
524
- onRowHover
939
+ const expandedRows = controlledExpandedRows ?? internalExpandedRows;
940
+ const handleExpandedRowsChange = (0, import_react4.useCallback)(
941
+ (next) => {
942
+ if (onExpandedRowsChange) {
943
+ onExpandedRowsChange(next);
944
+ return;
945
+ }
946
+ setInternalExpandedRows(next);
947
+ },
948
+ [onExpandedRowsChange]
949
+ );
950
+ const tableData = useConvertTreeData({
951
+ data,
952
+ enabled: enableExpand,
953
+ toggleField,
954
+ childField,
955
+ flattenField,
956
+ qtyField,
957
+ expandedRows,
958
+ onExpandedRowsChange: enableExpand ? handleExpandedRowsChange : void 0,
959
+ preventExpand
960
+ });
961
+ const table = (0, import_react_table.useReactTable)({
962
+ data: tableData,
963
+ columns,
964
+ state: {
965
+ rowSelection: rowSelectionMode === "none" ? {} : rowSelection
966
+ },
967
+ enableRowSelection: rowSelectionMode === "none" ? false : getRowCanSelect ? (row) => getRowCanSelect(row.original, row.index) : true,
968
+ enableMultiRowSelection: rowSelectionMode === "multi",
969
+ onRowSelectionChange: (updater) => {
970
+ if (onRowSelectionChange) {
971
+ onRowSelectionChange(
972
+ (previous) => applySelectionUpdater(rowSelectionMode, updater, previous)
973
+ );
974
+ return;
975
+ }
976
+ setInternalRowSelection(
977
+ (previous) => applySelectionUpdater(rowSelectionMode, updater, previous)
978
+ );
979
+ },
980
+ getCoreRowModel: (0, import_react_table.getCoreRowModel)(),
981
+ getRowId: getRowId ? (originalRow, index) => getRowId(originalRow, index) : (_originalRow, index) => String(index)
982
+ });
983
+ const rowSpanColumnKeys = (0, import_react4.useMemo)(() => {
984
+ if (!enableRowSpan) return [];
985
+ return collectRowSpanColumns(columns);
986
+ }, [enableRowSpan, columns]);
987
+ const primaryRowSpanKey = rowSpanColumnKeys[0]?.rowSpanKey;
988
+ const columnRowSpanMap = (0, import_react4.useMemo)(
989
+ () => buildColumnRowSpanMap(tableData, rowSpanColumnKeys),
990
+ [tableData, rowSpanColumnKeys]
991
+ );
992
+ const selectedRows = table.getSelectedRowModel().rows;
993
+ const selectedCount = selectedRows.length;
994
+ const rows = table.getRowModel().rows;
995
+ const columnCount = table.getAllLeafColumns().length || 1;
996
+ const rowVirtualizer = (0, import_react_virtual.useVirtualizer)({
997
+ count: shouldVirtualize ? rows.length : 0,
998
+ getScrollElement: () => scrollRef.current,
999
+ estimateSize: () => estimateRowHeight,
1000
+ overscan: virtualOverscan
1001
+ });
1002
+ const virtualRows = rowVirtualizer.getVirtualItems();
1003
+ const totalSize = rowVirtualizer.getTotalSize();
1004
+ const paddingTop = virtualRows.length > 0 ? virtualRows[0]?.start ?? 0 : 0;
1005
+ const paddingBottom = virtualRows.length > 0 ? totalSize - (virtualRows[virtualRows.length - 1]?.end ?? 0) : 0;
1006
+ const selectedGroupKeys = (0, import_react4.useMemo)(() => {
1007
+ if (!enableRowSpan || !primaryRowSpanKey) return /* @__PURE__ */ new Set();
1008
+ const keys = /* @__PURE__ */ new Set();
1009
+ for (const selectedRow of selectedRows) {
1010
+ const value = selectedRow.original[primaryRowSpanKey];
1011
+ if (value !== null && value !== void 0) keys.add(String(value));
1012
+ }
1013
+ return keys;
1014
+ }, [enableRowSpan, primaryRowSpanKey, selectedRows]);
1015
+ const {
1016
+ dragState,
1017
+ activeSelectionBounds,
1018
+ handleCellMouseDown,
1019
+ handleCellMouseEnter,
1020
+ handleFillHandleMouseDown
1021
+ } = useCellSelection({
1022
+ data: tableData,
1023
+ rows,
1024
+ enabled: enableCellSelection,
1025
+ onDataChange,
1026
+ onBatchChange
1027
+ });
1028
+ const {
1029
+ editingCell,
1030
+ draftValue,
1031
+ setDraftValue,
1032
+ startEdit,
1033
+ commitEdit,
1034
+ cancelEdit
1035
+ } = useCellEdit({ data: tableData, rows, onDataChange, onCellChange });
1036
+ const handleCellMouseDownWithCommit = (0, import_react4.useCallback)(
1037
+ (rowIndex, colIndex) => {
1038
+ const isSameEditingCell = editingCell?.rowIndex === rowIndex && editingCell?.colIndex === colIndex;
1039
+ if (editingCell && !isSameEditingCell && !commitEdit()) {
1040
+ return;
1041
+ }
1042
+ handleCellMouseDown(rowIndex, colIndex);
1043
+ },
1044
+ [commitEdit, editingCell, handleCellMouseDown]
1045
+ );
1046
+ const clearHover = (0, import_react4.useCallback)(() => {
1047
+ setHoveredRowIndex(null);
1048
+ setHoveredGroupKey(null);
1049
+ }, []);
1050
+ const handleRowHover = (0, import_react4.useCallback)(
1051
+ (rowIndex, rowData) => {
1052
+ setHoveredRowIndex(rowIndex);
1053
+ if (!primaryRowSpanKey) {
1054
+ setHoveredGroupKey(null);
1055
+ return;
1056
+ }
1057
+ const groupValue = rowData[primaryRowSpanKey];
1058
+ setHoveredGroupKey(
1059
+ groupValue === null || groupValue === void 0 ? null : String(groupValue)
1060
+ );
1061
+ },
1062
+ [primaryRowSpanKey]
1063
+ );
1064
+ const handleToggleSelect = (0, import_react4.useCallback)(
1065
+ (row) => {
1066
+ if (!row.getCanSelect()) return;
1067
+ if (preserveRowSelection && row.getIsSelected()) {
1068
+ return;
1069
+ }
1070
+ row.toggleSelected();
1071
+ },
1072
+ [preserveRowSelection]
1073
+ );
1074
+ const handleToggleExpand = (0, import_react4.useCallback)(
1075
+ (rowKey) => {
1076
+ if (preventExpand) return;
1077
+ handleExpandedRowsChange(toggleExpandedRowId(rowKey, expandedRows));
1078
+ },
1079
+ [preventExpand, handleExpandedRowsChange, expandedRows]
1080
+ );
1081
+ const rowContextValue = (0, import_react4.useMemo)(() => {
1082
+ return {
1083
+ rowSpan: {
1084
+ enableRowSpan,
1085
+ primaryRowSpanKey,
1086
+ columnRowSpanMap,
1087
+ hoveredRowIndex,
1088
+ hoveredGroupKey,
1089
+ selectedGroupKeys,
1090
+ onRowHover: handleRowHover
1091
+ },
1092
+ selection: {
1093
+ rowSelectionMode,
1094
+ selectOnRowClick,
1095
+ onRowClick,
1096
+ getRowClassName
1097
+ },
1098
+ cellSelection: {
1099
+ enableCellSelection,
1100
+ activeSelectionBounds,
1101
+ dragState,
1102
+ onCellMouseDown: handleCellMouseDownWithCommit,
1103
+ onCellMouseEnter: handleCellMouseEnter,
1104
+ onFillHandleMouseDown: handleFillHandleMouseDown
1105
+ },
1106
+ cellEdit: {
1107
+ editingCell,
1108
+ draftValue,
1109
+ onDraftValueChange: setDraftValue,
1110
+ onStartEdit: startEdit,
1111
+ onCommitEdit: commitEdit,
1112
+ onCancelEdit: cancelEdit
1113
+ },
1114
+ expand: {
1115
+ enableExpand,
1116
+ toggleField,
1117
+ expandedRows,
1118
+ preventExpand,
1119
+ onToggleExpand: handleToggleExpand,
1120
+ expandRowLabel: labels.expandRow,
1121
+ collapseRowLabel: labels.collapseRow
1122
+ }
1123
+ };
1124
+ }, [
1125
+ enableRowSpan,
1126
+ primaryRowSpanKey,
1127
+ columnRowSpanMap,
1128
+ hoveredRowIndex,
1129
+ hoveredGroupKey,
1130
+ selectedGroupKeys,
1131
+ handleRowHover,
1132
+ rowSelectionMode,
1133
+ selectOnRowClick,
1134
+ onRowClick,
1135
+ getRowClassName,
1136
+ enableCellSelection,
1137
+ activeSelectionBounds,
1138
+ dragState,
1139
+ handleCellMouseDownWithCommit,
1140
+ handleCellMouseEnter,
1141
+ handleFillHandleMouseDown,
1142
+ editingCell,
1143
+ draftValue,
1144
+ setDraftValue,
1145
+ startEdit,
1146
+ commitEdit,
1147
+ cancelEdit,
1148
+ enableExpand,
1149
+ toggleField,
1150
+ expandedRows,
1151
+ preventExpand,
1152
+ handleToggleExpand,
1153
+ labels.expandRow,
1154
+ labels.collapseRow
1155
+ ]);
1156
+ return {
1157
+ table,
1158
+ tableData,
1159
+ rows,
1160
+ columnCount,
1161
+ selectedCount,
1162
+ labels,
1163
+ emptyText: labels.empty,
1164
+ loadingText: labels.loading,
1165
+ selectionLabel: labels.selection,
1166
+ enableCellSelection,
1167
+ shouldVirtualize,
1168
+ scrollRef,
1169
+ rowVirtualizer,
1170
+ virtualRows,
1171
+ paddingTop,
1172
+ paddingBottom,
1173
+ rowContextValue,
1174
+ handleToggleSelect,
1175
+ clearHover
1176
+ };
1177
+ }
1178
+
1179
+ // src/components/ui/table/components/DataTable/DataTable.tsx
1180
+ var import_react_table3 = require("@tanstack/react-table");
1181
+
1182
+ // src/components/ui/table/components/DataTable/DataTableRow.tsx
1183
+ var import_react_table2 = require("@tanstack/react-table");
1184
+ var import_react6 = require("react");
1185
+
1186
+ // src/components/ui/table/DataTableContext.tsx
1187
+ var import_react5 = require("react");
1188
+ var import_jsx_runtime = require("react/jsx-runtime");
1189
+ var DataTableContext = (0, import_react5.createContext)(null);
1190
+ function useDataTableRowContext() {
1191
+ const context = (0, import_react5.use)(DataTableContext);
1192
+ if (!context) {
1193
+ throw new Error("useDataTableRowContext must be used within a DataTableContextProvider");
1194
+ }
1195
+ return context;
1196
+ }
1197
+ function DataTableContextProvider({
1198
+ value,
1199
+ children
1200
+ }) {
1201
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DataTableContext, { value, children });
1202
+ }
1203
+
1204
+ // src/components/ui/table/components/icons.tsx
1205
+ var import_jsx_runtime2 = require("react/jsx-runtime");
1206
+ function ChevronDown({ className, "aria-hidden": ariaHidden = true }) {
1207
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1208
+ "svg",
1209
+ {
1210
+ className,
1211
+ "aria-hidden": ariaHidden,
1212
+ width: "16",
1213
+ height: "16",
1214
+ viewBox: "0 0 24 24",
1215
+ fill: "none",
1216
+ stroke: "currentColor",
1217
+ strokeWidth: "2",
1218
+ strokeLinecap: "round",
1219
+ strokeLinejoin: "round",
1220
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "m6 9 6 6 6-6" })
1221
+ }
1222
+ );
1223
+ }
1224
+ function ChevronUp({ className, "aria-hidden": ariaHidden = true }) {
1225
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1226
+ "svg",
1227
+ {
1228
+ className,
1229
+ "aria-hidden": ariaHidden,
1230
+ width: "16",
1231
+ height: "16",
1232
+ viewBox: "0 0 24 24",
1233
+ fill: "none",
1234
+ stroke: "currentColor",
1235
+ strokeWidth: "2",
1236
+ strokeLinecap: "round",
1237
+ strokeLinejoin: "round",
1238
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "m18 15-6-6-6 6" })
1239
+ }
1240
+ );
1241
+ }
1242
+ function ChevronLeft({ className, "aria-hidden": ariaHidden = true }) {
1243
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1244
+ "svg",
1245
+ {
1246
+ className,
1247
+ "aria-hidden": ariaHidden,
1248
+ width: "16",
1249
+ height: "16",
1250
+ viewBox: "0 0 24 24",
1251
+ fill: "none",
1252
+ stroke: "currentColor",
1253
+ strokeWidth: "2",
1254
+ strokeLinecap: "round",
1255
+ strokeLinejoin: "round",
1256
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "m15 18-6-6 6-6" })
1257
+ }
1258
+ );
1259
+ }
1260
+ function ChevronRight({ className, "aria-hidden": ariaHidden = true }) {
1261
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1262
+ "svg",
1263
+ {
1264
+ className,
1265
+ "aria-hidden": ariaHidden,
1266
+ width: "16",
1267
+ height: "16",
1268
+ viewBox: "0 0 24 24",
1269
+ fill: "none",
1270
+ stroke: "currentColor",
1271
+ strokeWidth: "2",
1272
+ strokeLinecap: "round",
1273
+ strokeLinejoin: "round",
1274
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "m9 18 6-6-6-6" })
1275
+ }
1276
+ );
1277
+ }
1278
+ function ArrowUp({ className, "aria-hidden": ariaHidden = true }) {
1279
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1280
+ "svg",
1281
+ {
1282
+ className,
1283
+ "aria-hidden": ariaHidden,
1284
+ width: "14",
1285
+ height: "14",
1286
+ viewBox: "0 0 24 24",
1287
+ fill: "none",
1288
+ stroke: "currentColor",
1289
+ strokeWidth: "2",
1290
+ strokeLinecap: "round",
1291
+ strokeLinejoin: "round",
1292
+ children: [
1293
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "m18 15-6-6-6 6" }),
1294
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M12 21V9" })
1295
+ ]
1296
+ }
1297
+ );
1298
+ }
1299
+ function ArrowDown({ className, "aria-hidden": ariaHidden = true }) {
1300
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1301
+ "svg",
1302
+ {
1303
+ className,
1304
+ "aria-hidden": ariaHidden,
1305
+ width: "14",
1306
+ height: "14",
1307
+ viewBox: "0 0 24 24",
1308
+ fill: "none",
1309
+ stroke: "currentColor",
1310
+ strokeWidth: "2",
1311
+ strokeLinecap: "round",
1312
+ strokeLinejoin: "round",
1313
+ children: [
1314
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "m6 9 6 6 6-6" }),
1315
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M12 3v12" })
1316
+ ]
1317
+ }
1318
+ );
1319
+ }
1320
+ function ArrowUpDown({ className, "aria-hidden": ariaHidden = true }) {
1321
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1322
+ "svg",
1323
+ {
1324
+ className,
1325
+ "aria-hidden": ariaHidden,
1326
+ width: "14",
1327
+ height: "14",
1328
+ viewBox: "0 0 24 24",
1329
+ fill: "none",
1330
+ stroke: "currentColor",
1331
+ strokeWidth: "2",
1332
+ strokeLinecap: "round",
1333
+ strokeLinejoin: "round",
1334
+ children: [
1335
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "m21 16-4 4-4-4" }),
1336
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M17 20V4" }),
1337
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "m3 8 4-4 4 4" }),
1338
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M7 4v16" })
1339
+ ]
1340
+ }
1341
+ );
1342
+ }
1343
+
1344
+ // src/lib/cn.ts
1345
+ function cn(...inputs) {
1346
+ return inputs.filter(Boolean).join(" ");
1347
+ }
1348
+
1349
+ // src/components/ui/table/components/DataTable/DataTableRow.tsx
1350
+ var import_jsx_runtime3 = require("react/jsx-runtime");
1351
+ function resolveExpandCellIndex(cells, toggleField) {
1352
+ if (!toggleField) return 0;
1353
+ const matchedIndex = cells.findIndex(
1354
+ (cell) => cell.column.id === toggleField
1355
+ );
1356
+ if (matchedIndex >= 0) return matchedIndex;
1357
+ const noColumnIndex = cells.findIndex(
1358
+ (cell) => cell.column.id === "no" || cell.column.id === "treeNo"
1359
+ );
1360
+ if (noColumnIndex >= 0 && noColumnIndex + 1 < cells.length) {
1361
+ return noColumnIndex + 1;
1362
+ }
1363
+ return 0;
1364
+ }
1365
+ function DataTableRow({
1366
+ row,
1367
+ onToggleSelect,
1368
+ virtualIndex,
1369
+ measureElement
1370
+ }) {
1371
+ const { rowSpan, selection, cellSelection, cellEdit, expand } = useDataTableRowContext();
1372
+ const {
1373
+ enableRowSpan,
1374
+ primaryRowSpanKey,
1375
+ columnRowSpanMap,
1376
+ hoveredRowIndex,
1377
+ hoveredGroupKey,
1378
+ selectedGroupKeys,
1379
+ onRowHover
525
1380
  } = rowSpan;
526
1381
  const { rowSelectionMode, selectOnRowClick, onRowClick, getRowClassName } = selection;
527
1382
  const {
1383
+ enableCellSelection,
528
1384
  activeSelectionBounds,
529
1385
  dragState,
530
1386
  onCellMouseDown,
@@ -544,7 +1400,9 @@ function DataTableRow({
544
1400
  toggleField,
545
1401
  expandedRows,
546
1402
  preventExpand,
547
- onToggleExpand
1403
+ onToggleExpand,
1404
+ expandRowLabel,
1405
+ collapseRowLabel
548
1406
  } = expand;
549
1407
  const rowIndex = row.index;
550
1408
  const rowData = row.original;
@@ -554,14 +1412,31 @@ function DataTableRow({
554
1412
  const isGroupHovered = enableRowSpan && hoveredGroupKey !== null && rowGroupKey === hoveredGroupKey;
555
1413
  const isGroupSelected = enableRowSpan && rowGroupKey !== null && selectedGroupKeys.has(rowGroupKey);
556
1414
  const visibleCells = row.getVisibleCells();
1415
+ const columnIdsByIndex = visibleCells.map((cell) => cell.column.id);
1416
+ const isVisuallySelectedAt = activeSelectionBounds ? (targetRow, targetCol) => {
1417
+ if (targetCol < activeSelectionBounds.startCol || targetCol > activeSelectionBounds.endCol) {
1418
+ return false;
1419
+ }
1420
+ const columnId = columnIdsByIndex[targetCol];
1421
+ const { startRow, rowSpan: span } = resolveRowSpanAt(
1422
+ columnId ? columnRowSpanMap.get(columnId) : void 0,
1423
+ targetRow
1424
+ );
1425
+ return isCellInSelection(
1426
+ startRow,
1427
+ targetCol,
1428
+ activeSelectionBounds,
1429
+ span
1430
+ );
1431
+ } : void 0;
557
1432
  const expandCellIndex = enableExpand ? resolveExpandCellIndex(visibleCells, toggleField) : -1;
558
1433
  const canExpand = enableExpand && !preventExpand && canExpandRow(rowData);
559
1434
  const expandKey = toggleField && rowData[toggleField] !== null && rowData[toggleField] !== void 0 ? String(rowData[toggleField]) : null;
560
1435
  const isExpanded = expandKey !== null && Boolean(expandedRows?.has(expandKey));
561
1436
  const rowLevel = typeof rowData.level === "number" ? rowData.level : 0;
562
- const editInputRef = (0, import_react3.useRef)(null);
1437
+ const editInputRef = (0, import_react6.useRef)(null);
563
1438
  const isRowEditing = editingCell?.rowIndex === rowIndex;
564
- (0, import_react3.useEffect)(() => {
1439
+ (0, import_react6.useEffect)(() => {
565
1440
  if (!isRowEditing) return;
566
1441
  editInputRef.current?.focus();
567
1442
  editInputRef.current?.select();
@@ -607,6 +1482,11 @@ function DataTableRow({
607
1482
  const showCellHover = isRowSpanColumn ? isGroupHovered : isRowHovered;
608
1483
  const showCellSelected = isRowSpanColumn ? isGroupSelected : isRowSelected;
609
1484
  const cellRowSpan = rowSpanInfo?.rowSpan ?? 1;
1485
+ const isMerged = cellRowSpan > 1;
1486
+ const showMergedRightEdge = isMerged && (cellIndex === visibleCells.length - 1 || resolveRowSpanAt(
1487
+ columnRowSpanMap.get(columnIdsByIndex[cellIndex + 1]),
1488
+ rowIndex
1489
+ ).rowSpan <= 1);
610
1490
  const isCellDragSelected = isCellInSelection(
611
1491
  rowIndex,
612
1492
  cellIndex,
@@ -614,6 +1494,13 @@ function DataTableRow({
614
1494
  cellRowSpan
615
1495
  );
616
1496
  const isBottomRightCell = !isEditing && activeSelectionBounds && !dragState.isSelecting && activeSelectionBounds.endRow >= rowIndex && activeSelectionBounds.endRow <= rowIndex + cellRowSpan - 1 && cellIndex === activeSelectionBounds.endCol;
1497
+ const selectionEdgeStyle = getCellSelectionEdgeStyle(
1498
+ rowIndex,
1499
+ cellIndex,
1500
+ activeSelectionBounds,
1501
+ cellRowSpan,
1502
+ isVisuallySelectedAt
1503
+ );
617
1504
  const resolveCellRowIndex = (clientY, element) => getRowIndexInMergedCell(clientY, element, rowIndex, cellRowSpan);
618
1505
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
619
1506
  "td",
@@ -624,17 +1511,22 @@ function DataTableRow({
624
1511
  event.stopPropagation();
625
1512
  return;
626
1513
  }
1514
+ if (!enableCellSelection) return;
627
1515
  event.preventDefault();
628
1516
  onCellMouseDown(
629
1517
  resolveCellRowIndex(event.clientY, event.currentTarget),
630
1518
  cellIndex
631
1519
  );
632
1520
  },
633
- onMouseEnter: (event) => onCellMouseEnter(
634
- resolveCellRowIndex(event.clientY, event.currentTarget),
635
- cellIndex
636
- ),
1521
+ onMouseEnter: (event) => {
1522
+ if (!enableCellSelection) return;
1523
+ onCellMouseEnter(
1524
+ resolveCellRowIndex(event.clientY, event.currentTarget),
1525
+ cellIndex
1526
+ );
1527
+ },
637
1528
  onMouseMove: (event) => {
1529
+ if (!enableCellSelection) return;
638
1530
  if (!dragState.isSelecting && !dragState.isFillDragging) return;
639
1531
  onCellMouseEnter(
640
1532
  resolveCellRowIndex(event.clientY, event.currentTarget),
@@ -647,19 +1539,17 @@ function DataTableRow({
647
1539
  event.stopPropagation();
648
1540
  onStartEdit(rowIndex, cellIndex);
649
1541
  },
650
- style: getCellSelectionEdgeStyle(
651
- rowIndex,
652
- cellIndex,
653
- activeSelectionBounds,
654
- cellRowSpan
655
- ),
1542
+ style: selectionEdgeStyle,
656
1543
  className: cn(
657
1544
  "data-table-cell",
658
1545
  CELL_ALIGN_CLASS[align],
659
1546
  cellClassName,
1547
+ isMerged && cellIndex > 0 && "is-merged",
1548
+ showMergedRightEdge && "is-merged-edge-right",
660
1549
  enableRowSpan && showCellSelected && "is-group-selected",
661
1550
  enableRowSpan && showCellHover && !showCellSelected && "is-group-hovered",
662
1551
  isCellDragSelected && CELL_SELECTION_FILL_CLASS,
1552
+ hasCellSelectionEdges(selectionEdgeStyle) && CELL_SELECTION_EDGES_CLASS,
663
1553
  editable && "is-editable"
664
1554
  ),
665
1555
  children: [
@@ -690,13 +1580,13 @@ function DataTableRow({
690
1580
  ) : isExpandCell && enableExpand ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "expand-cell", children: [
691
1581
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "expand-cell-content", children: [
692
1582
  rowLevel > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "expand-cell-indent", children: "\xB7" }),
693
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "expand-cell-value", children: (0, import_react_table.flexRender)(cell.column.columnDef.cell, cell.getContext()) })
1583
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "expand-cell-value", children: (0, import_react_table2.flexRender)(cell.column.columnDef.cell, cell.getContext()) })
694
1584
  ] }),
695
1585
  canExpand && expandKey && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
696
1586
  "button",
697
1587
  {
698
1588
  type: "button",
699
- "aria-label": isExpanded ? "\uD589 \uC811\uAE30" : "\uD589 \uD3BC\uCE58\uAE30",
1589
+ "aria-label": isExpanded ? collapseRowLabel : expandRowLabel,
700
1590
  className: "expand-toggle-button",
701
1591
  onClick: (event) => {
702
1592
  event.stopPropagation();
@@ -706,7 +1596,7 @@ function DataTableRow({
706
1596
  children: isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ChevronUp, { className: "expand-toggle-icon" }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ChevronDown, { className: "expand-toggle-icon" })
707
1597
  }
708
1598
  )
709
- ] }) : (0, import_react_table.flexRender)(cell.column.columnDef.cell, cell.getContext()),
1599
+ ] }) : (0, import_react_table2.flexRender)(cell.column.columnDef.cell, cell.getContext()),
710
1600
  isBottomRightCell && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
711
1601
  "div",
712
1602
  {
@@ -730,14 +1620,6 @@ function DataTableRow({
730
1620
 
731
1621
  // src/components/ui/table/components/DataTable/DataTableToolbar.tsx
732
1622
  var import_jsx_runtime4 = require("react/jsx-runtime");
733
- function DefaultSelectionLabel({ selectedCount }) {
734
- if (selectedCount <= 0) return null;
735
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "toolbar-selection", children: [
736
- "\u2713 ",
737
- selectedCount,
738
- "\uAC1C \uC120\uD0DD\uB428"
739
- ] });
740
- }
741
1623
  function DataTableToolbar({
742
1624
  filteredCount,
743
1625
  totalCount,
@@ -751,625 +1633,166 @@ function DataTableToolbar({
751
1633
  const hasCount = displayFiltered !== void 0 || totalCount !== void 0;
752
1634
  const hasLeftContent = hasCount || Boolean(summary);
753
1635
  const hasToolbar = Boolean(toolbar);
754
- const selectionContent = selectionLabel ? selectionLabel(selectedCount) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(DefaultSelectionLabel, { selectedCount });
755
- const hasSelectionContent = selectionContent !== null && selectionContent !== false;
756
- if (!hasLeftContent && !hasToolbar && !hasSelectionContent) return null;
757
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: cn("DataTableToolbarJSX", className), children: [
758
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "toolbar-left", children: [
759
- hasCount && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "toolbar-count", children: displayFiltered !== void 0 && totalCount !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
760
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "toolbar-count-primary", children: displayFiltered }),
761
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "toolbar-count-placeholder", children: [
762
- " / ",
763
- totalCount
764
- ] })
765
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "toolbar-count-primary", children: displayFiltered ?? totalCount }) }),
766
- summary
767
- ] }),
768
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "toolbar-right", children: [
769
- selectionContent,
770
- hasToolbar && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "toolbar-actions", children: toolbar })
771
- ] })
772
- ] });
773
- }
774
-
775
- // src/components/ui/table/features/cell-edit/useCellEdit.ts
776
- var import_react4 = require("react");
777
- function useCellEdit({
778
- data,
779
- rows,
780
- onDataChange
781
- }) {
782
- const [editingCell, setEditingCell] = (0, import_react4.useState)(null);
783
- const [draftValue, setDraftValue] = (0, import_react4.useState)("");
784
- const draftValueRef = (0, import_react4.useRef)(draftValue);
785
- const editingCellRef = (0, import_react4.useRef)(editingCell);
786
- (0, import_react4.useEffect)(() => {
787
- draftValueRef.current = draftValue;
788
- }, [draftValue]);
789
- (0, import_react4.useEffect)(() => {
790
- editingCellRef.current = editingCell;
791
- }, [editingCell]);
792
- const cancelEdit = (0, import_react4.useCallback)(() => {
793
- setEditingCell(null);
794
- setDraftValue("");
795
- }, []);
796
- const commitEdit = (0, import_react4.useCallback)(
797
- (raw) => {
798
- const current = editingCellRef.current;
799
- if (!current) return true;
800
- if (!onDataChange) {
801
- cancelEdit();
802
- return true;
803
- }
804
- const value = raw ?? draftValueRef.current;
805
- const next = applyCellEdit(data, rows, current.rowIndex, current.colIndex, value);
806
- if (!next) return false;
807
- onDataChange(next);
808
- cancelEdit();
809
- return true;
810
- },
811
- [cancelEdit, data, onDataChange, rows]
812
- );
813
- const startEdit = (0, import_react4.useCallback)(
814
- (rowIndex, colIndex) => {
815
- const cell = rows[rowIndex]?.getVisibleCells()[colIndex];
816
- if (!cell || !isColumnEditable(cell.column.columnDef)) return;
817
- const current = editingCellRef.current;
818
- if (current && (current.rowIndex !== rowIndex || current.colIndex !== colIndex) && !commitEdit()) {
819
- return;
820
- }
821
- setEditingCell({ rowIndex, colIndex });
822
- setDraftValue(getCellEditDraftValue(cell.getValue()));
823
- },
824
- [commitEdit, rows]
825
- );
826
- return {
827
- editingCell,
828
- draftValue,
829
- setDraftValue,
830
- startEdit,
831
- commitEdit,
832
- cancelEdit
833
- };
834
- }
835
-
836
- // src/components/ui/table/features/cell-selection/useCellSelection.ts
837
- var import_react5 = require("react");
838
-
839
- // src/components/ui/table/features/cell-selection/fillData.ts
840
- function getColumnAccessorKey2(columnDef) {
841
- if ("accessorKey" in columnDef && columnDef.accessorKey) {
842
- return String(columnDef.accessorKey);
843
- }
844
- return columnDef.id;
845
- }
846
- function applyFillData(data, rows, sourceBounds, fillBounds) {
847
- const newData = data.map((row) => ({ ...row }));
848
- const sourceHeight = sourceBounds.endRow - sourceBounds.startRow + 1;
849
- const sourceWidth = sourceBounds.endCol - sourceBounds.startCol + 1;
850
- for (let rowIndex = fillBounds.startRow; rowIndex <= fillBounds.endRow; rowIndex += 1) {
851
- for (let colIndex = fillBounds.startCol; colIndex <= fillBounds.endCol; colIndex += 1) {
852
- if (isCellInSelection(rowIndex, colIndex, sourceBounds)) continue;
853
- const offsetRow = rowIndex - sourceBounds.startRow;
854
- const offsetCol = colIndex - sourceBounds.startCol;
855
- const sourceRowIndex = sourceBounds.startRow + (offsetRow % sourceHeight + sourceHeight) % sourceHeight;
856
- const sourceColIndex = sourceBounds.startCol + (offsetCol % sourceWidth + sourceWidth) % sourceWidth;
857
- const targetCell = rows[rowIndex]?.getVisibleCells()[colIndex];
858
- const sourceCell = rows[sourceRowIndex]?.getVisibleCells()[sourceColIndex];
859
- if (!targetCell || !sourceCell) continue;
860
- const accessorKey = getColumnAccessorKey2(
861
- targetCell.column.columnDef
862
- );
863
- if (!accessorKey) continue;
864
- newData[rowIndex][accessorKey] = sourceCell.getValue();
865
- }
866
- }
867
- return newData;
868
- }
869
- function hasFillExtension(sourceBounds, fillBounds) {
870
- if (!sourceBounds) return false;
871
- return fillBounds.startRow < sourceBounds.startRow || fillBounds.endRow > sourceBounds.endRow || fillBounds.startCol < sourceBounds.startCol || fillBounds.endCol > sourceBounds.endCol;
872
- }
873
-
874
- // src/components/ui/table/features/cell-selection/useCellSelection.ts
875
- function useCellSelection({
876
- data,
877
- rows,
878
- onDataChange
879
- }) {
880
- const [dragState, setDragState] = (0, import_react5.useState)(INITIAL_DRAG_STATE);
881
- const cellSelectionBounds = getCellSelectionBounds(dragState.start, dragState.end);
882
- const activeSelectionBounds = getActiveSelectionBounds(dragState, cellSelectionBounds);
883
- const handleCellMouseDown = (0, import_react5.useCallback)((rowIndex, colIndex) => {
884
- setDragState({
885
- isSelecting: true,
886
- isFillDragging: false,
887
- start: { row: rowIndex, col: colIndex },
888
- end: { row: rowIndex, col: colIndex },
889
- fillAnchor: null,
890
- fillEnd: null
891
- });
892
- }, []);
893
- const handleCellMouseEnter = (0, import_react5.useCallback)((rowIndex, colIndex) => {
894
- setDragState((prev) => {
895
- if (prev.isSelecting) {
896
- return { ...prev, end: { row: rowIndex, col: colIndex } };
897
- }
898
- if (prev.isFillDragging) {
899
- return { ...prev, fillEnd: { row: rowIndex, col: colIndex } };
900
- }
901
- return prev;
902
- });
903
- }, []);
904
- const handleFillHandleMouseDown = (0, import_react5.useCallback)((rowIndex, colIndex) => {
905
- setDragState((prev) => {
906
- const bounds = getCellSelectionBounds(prev.start, prev.end);
907
- if (!bounds) return prev;
908
- return {
909
- ...prev,
910
- isSelecting: false,
911
- isFillDragging: true,
912
- fillAnchor: { row: bounds.startRow, col: bounds.startCol },
913
- fillEnd: { row: rowIndex, col: colIndex }
914
- };
915
- });
916
- }, []);
917
- (0, import_react5.useEffect)(() => {
918
- const handleKeyDown = (e) => {
919
- if ((e.ctrlKey || e.metaKey) && e.key === "c" && activeSelectionBounds) {
920
- const { startRow, endRow, startCol, endCol } = activeSelectionBounds;
921
- const selectedData = rows.slice(startRow, endRow + 1).map((row) => {
922
- const cells = row.getVisibleCells();
923
- return cells.slice(startCol, endCol + 1).map((cell) => cell.getValue()).join(" ");
924
- }).join("\n");
925
- navigator.clipboard.writeText(selectedData);
926
- }
927
- };
928
- window.addEventListener("keydown", handleKeyDown);
929
- return () => window.removeEventListener("keydown", handleKeyDown);
930
- }, [activeSelectionBounds, rows]);
931
- (0, import_react5.useEffect)(() => {
932
- const handleMouseUp = () => {
933
- setDragState((prev) => {
934
- if (prev.isFillDragging && prev.fillAnchor && prev.fillEnd) {
935
- const sourceBounds = getCellSelectionBounds(prev.start, prev.end);
936
- const newBounds = getCellSelectionBounds(prev.fillAnchor, prev.fillEnd);
937
- if (newBounds) {
938
- if (hasFillExtension(sourceBounds, newBounds) && sourceBounds && onDataChange) {
939
- onDataChange(applyFillData(data, rows, sourceBounds, newBounds));
940
- }
941
- return {
942
- isSelecting: false,
943
- isFillDragging: false,
944
- start: { row: newBounds.startRow, col: newBounds.startCol },
945
- end: { row: newBounds.endRow, col: newBounds.endCol },
946
- fillAnchor: null,
947
- fillEnd: null
948
- };
949
- }
950
- }
951
- if (prev.isSelecting) {
952
- return { ...prev, isSelecting: false };
953
- }
954
- if (prev.isFillDragging) {
955
- return { ...prev, isFillDragging: false, fillAnchor: null, fillEnd: null };
956
- }
957
- return prev;
958
- });
959
- };
960
- window.addEventListener("mouseup", handleMouseUp);
961
- return () => window.removeEventListener("mouseup", handleMouseUp);
962
- }, [data, onDataChange, rows]);
963
- return {
964
- dragState,
965
- activeSelectionBounds,
966
- handleCellMouseDown,
967
- handleCellMouseEnter,
968
- handleFillHandleMouseDown
969
- };
970
- }
971
-
972
- // src/components/ui/table/features/row-selection/rowSelection.ts
973
- function resolveRowSelection(mode, controlledSelection, internalSelection) {
974
- if (mode === "none") return {};
975
- return controlledSelection ?? internalSelection;
976
- }
977
- function normalizeSingleSelection(next) {
978
- const selectedIds = Object.keys(next).filter((id) => next[id]);
979
- if (selectedIds.length <= 1) return next;
980
- return { [selectedIds[selectedIds.length - 1]]: true };
981
- }
982
- function applySelectionUpdater(mode, updater, previous) {
983
- const next = typeof updater === "function" ? updater(previous) : updater;
984
- return mode === "single" ? normalizeSingleSelection(next) : next;
985
- }
986
-
987
- // src/components/ui/table/features/row-span/rowSpan.ts
988
- function getRowFieldValue(row, key) {
989
- return row[key];
990
- }
991
- function computeRowSpans(data, rowSpanKey) {
992
- if (data.length === 0) return [];
993
- const result = [];
994
- for (let index = 0; index < data.length; index++) {
995
- const currentValue = getRowFieldValue(data[index], rowSpanKey);
996
- const previousValue = index > 0 ? getRowFieldValue(data[index - 1], rowSpanKey) : void 0;
997
- if (index > 0 && currentValue === previousValue) {
998
- result.push({ rowSpan: 0, isFirstInGroup: false });
999
- continue;
1000
- }
1001
- let span = 1;
1002
- for (let nextIndex = index + 1; nextIndex < data.length; nextIndex++) {
1003
- if (getRowFieldValue(data[nextIndex], rowSpanKey) === currentValue) {
1004
- span++;
1005
- } else {
1006
- break;
1007
- }
1008
- }
1009
- result.push({ rowSpan: span, isFirstInGroup: true });
1010
- }
1011
- return result;
1012
- }
1013
- function buildColumnRowSpanMap(data, columnKeys) {
1014
- const map = /* @__PURE__ */ new Map();
1015
- for (const { columnId, rowSpanKey } of columnKeys) {
1016
- map.set(columnId, computeRowSpans(data, rowSpanKey));
1017
- }
1018
- return map;
1019
- }
1020
- function collectRowSpanColumns(columns) {
1021
- const result = [];
1022
- const visit = (defs) => {
1023
- for (const columnDef of defs) {
1024
- if ("columns" in columnDef && columnDef.columns?.length) {
1025
- visit(columnDef.columns);
1026
- continue;
1027
- }
1028
- const columnId = columnDef.id ?? ("accessorKey" in columnDef && columnDef.accessorKey ? String(columnDef.accessorKey) : void 0);
1029
- if (!columnId || !columnDef.meta?.rowSpan) continue;
1030
- result.push({
1031
- columnId,
1032
- rowSpanKey: columnDef.meta.rowSpanKey ?? columnId
1033
- });
1034
- }
1035
- };
1036
- visit(columns);
1037
- return result;
1636
+ const selectionContent = selectionLabel?.(selectedCount) ?? null;
1637
+ const hasSelectionContent = selectionContent !== null && selectionContent !== false && selectionContent !== void 0 && typeof selectionContent !== "boolean";
1638
+ if (!hasLeftContent && !hasToolbar && !hasSelectionContent) return null;
1639
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: cn("DataTableToolbarJSX", className), children: [
1640
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "toolbar-left", children: [
1641
+ hasCount && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "toolbar-count", children: displayFiltered !== void 0 && totalCount !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
1642
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "toolbar-count-primary", children: displayFiltered }),
1643
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "toolbar-count-placeholder", children: [
1644
+ " / ",
1645
+ totalCount
1646
+ ] })
1647
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "toolbar-count-primary", children: displayFiltered ?? totalCount }) }),
1648
+ summary
1649
+ ] }),
1650
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "toolbar-right", children: [
1651
+ hasSelectionContent && (typeof selectionContent === "string" || typeof selectionContent === "number" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "toolbar-selection", children: selectionContent }) : selectionContent),
1652
+ hasToolbar && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "toolbar-actions", children: toolbar })
1653
+ ] })
1654
+ ] });
1038
1655
  }
1039
1656
 
1040
1657
  // src/components/ui/table/components/DataTable/DataTable.tsx
1041
1658
  var import_jsx_runtime5 = require("react/jsx-runtime");
1659
+ function DefaultPending({
1660
+ loadingText,
1661
+ className
1662
+ }) {
1663
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: cn("DataTableJSX", "DataTableJSX--pending", className), children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "data-table-loading-text", children: loadingText }) });
1664
+ }
1665
+ function DefaultEmpty({
1666
+ emptyText,
1667
+ columnCount
1668
+ }) {
1669
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { colSpan: columnCount, className: "data-table-empty-cell", children: emptyText }) });
1670
+ }
1042
1671
  function DataTable({
1043
- data,
1044
- columns,
1045
- rowSelectionMode = "none",
1046
- rowSelection: controlledRowSelection,
1047
- onRowSelectionChange,
1048
- totalCount,
1049
- filteredCount,
1672
+ isPending = false,
1050
1673
  summary,
1051
1674
  toolbar,
1052
- selectionLabel,
1053
- isPending = false,
1054
- emptyText = "\uB370\uC774\uD130\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
1055
- enableRowSpan = false,
1056
- getRowId,
1057
- onRowClick,
1058
- getRowClassName,
1059
- getRowCanSelect,
1060
- selectOnRowClick = true,
1061
- onDataChange,
1675
+ filteredCount,
1676
+ totalCount,
1062
1677
  className,
1063
- preserveRowSelection = false,
1064
- toggleField,
1065
- childField,
1066
- flattenField,
1067
- expandedRows: controlledExpandedRows,
1068
- onExpandedRowsChange,
1069
- preventExpand = false,
1070
- enableVirtualization = true,
1071
- estimateRowHeight = DATA_TABLE_ROW_HEIGHT,
1072
- virtualOverscan = DATA_TABLE_VIRTUAL_OVERSCAN
1678
+ slots,
1679
+ ...glideOptions
1073
1680
  }) {
1074
- const enableExpand = Boolean(toggleField);
1075
- const [internalRowSelection, setInternalRowSelection] = (0, import_react6.useState)({});
1076
- const [internalExpandedRows, setInternalExpandedRows] = (0, import_react6.useState)(() => /* @__PURE__ */ new Set());
1077
- const [hoveredRowIndex, setHoveredRowIndex] = (0, import_react6.useState)(null);
1078
- const [hoveredGroupKey, setHoveredGroupKey] = (0, import_react6.useState)(null);
1079
- const scrollRef = (0, import_react6.useRef)(null);
1080
- const shouldVirtualize = enableVirtualization && !enableRowSpan;
1081
- (0, import_react6.useEffect)(() => {
1082
- if (enableVirtualization && enableRowSpan) {
1083
- console.warn(
1084
- "[DataTable] enableRowSpan\uC774 \uCF1C\uC838 \uC788\uC73C\uBA74 \uC140 \uBCD1\uD569 \uC720\uC9C0\uB97C \uC704\uD574 \uAC00\uC0C1\uD654\uB97C \uBE44\uD65C\uC131\uD654\uD569\uB2C8\uB2E4."
1085
- );
1086
- }
1087
- }, [enableVirtualization, enableRowSpan]);
1088
- const rowSelection = resolveRowSelection(
1089
- rowSelectionMode,
1090
- controlledRowSelection,
1091
- internalRowSelection
1092
- );
1093
- const expandedRows = controlledExpandedRows ?? internalExpandedRows;
1094
- const handleExpandedRowsChange = (0, import_react6.useCallback)(
1095
- (next) => {
1096
- if (onExpandedRowsChange) {
1097
- onExpandedRowsChange(next);
1098
- return;
1099
- }
1100
- setInternalExpandedRows(next);
1101
- },
1102
- [onExpandedRowsChange]
1103
- );
1104
- const tableData = useConvertTreeData({
1105
- data,
1106
- enabled: enableExpand,
1107
- toggleField,
1108
- childField,
1109
- flattenField,
1110
- expandedRows,
1111
- onExpandedRowsChange: enableExpand ? handleExpandedRowsChange : void 0,
1112
- preventExpand
1113
- });
1114
- const table = (0, import_react_table2.useReactTable)({
1115
- data: tableData,
1116
- columns,
1117
- state: {
1118
- rowSelection: rowSelectionMode === "none" ? {} : rowSelection
1119
- },
1120
- enableRowSelection: rowSelectionMode === "none" ? false : getRowCanSelect ? (row) => getRowCanSelect(row.original, row.index) : true,
1121
- enableMultiRowSelection: rowSelectionMode === "multi",
1122
- onRowSelectionChange: (updater) => {
1123
- if (onRowSelectionChange) {
1124
- onRowSelectionChange(
1125
- (previous) => applySelectionUpdater(rowSelectionMode, updater, previous)
1126
- );
1127
- return;
1128
- }
1129
- setInternalRowSelection(
1130
- (previous) => applySelectionUpdater(rowSelectionMode, updater, previous)
1131
- );
1132
- },
1133
- getCoreRowModel: (0, import_react_table2.getCoreRowModel)(),
1134
- getRowId: getRowId ? (originalRow, index) => getRowId(originalRow, index) : (_originalRow, index) => String(index)
1135
- });
1136
- const rowSpanColumnKeys = (0, import_react6.useMemo)(() => {
1137
- if (!enableRowSpan) return [];
1138
- return collectRowSpanColumns(columns);
1139
- }, [enableRowSpan, columns]);
1140
- const primaryRowSpanKey = rowSpanColumnKeys[0]?.rowSpanKey;
1141
- const columnRowSpanMap = (0, import_react6.useMemo)(
1142
- () => buildColumnRowSpanMap(tableData, rowSpanColumnKeys),
1143
- [tableData, rowSpanColumnKeys]
1144
- );
1145
- const selectedRows = table.getSelectedRowModel().rows;
1146
- const selectedCount = selectedRows.length;
1147
- const rows = table.getRowModel().rows;
1148
- const columnCount = table.getAllLeafColumns().length || 1;
1149
- const rowVirtualizer = (0, import_react_virtual.useVirtualizer)({
1150
- count: shouldVirtualize ? rows.length : 0,
1151
- getScrollElement: () => scrollRef.current,
1152
- estimateSize: () => estimateRowHeight,
1153
- overscan: virtualOverscan
1154
- });
1155
- const virtualRows = rowVirtualizer.getVirtualItems();
1156
- const totalSize = rowVirtualizer.getTotalSize();
1157
- const paddingTop = virtualRows.length > 0 ? virtualRows[0]?.start ?? 0 : 0;
1158
- const paddingBottom = virtualRows.length > 0 ? totalSize - (virtualRows[virtualRows.length - 1]?.end ?? 0) : 0;
1159
- const selectedGroupKeys = (0, import_react6.useMemo)(() => {
1160
- if (!enableRowSpan || !primaryRowSpanKey) return /* @__PURE__ */ new Set();
1161
- const keys = /* @__PURE__ */ new Set();
1162
- for (const selectedRow of selectedRows) {
1163
- const value = selectedRow.original[primaryRowSpanKey];
1164
- if (value !== null && value !== void 0) keys.add(String(value));
1165
- }
1166
- return keys;
1167
- }, [enableRowSpan, primaryRowSpanKey, selectedRows]);
1168
1681
  const {
1169
- dragState,
1170
- activeSelectionBounds,
1171
- handleCellMouseDown,
1172
- handleCellMouseEnter,
1173
- handleFillHandleMouseDown
1174
- } = useCellSelection({ data: tableData, rows, onDataChange });
1175
- const { editingCell, draftValue, setDraftValue, startEdit, commitEdit, cancelEdit } = useCellEdit(
1176
- { data: tableData, rows, onDataChange }
1177
- );
1178
- const handleCellMouseDownWithCommit = (0, import_react6.useCallback)(
1179
- (rowIndex, colIndex) => {
1180
- const isSameEditingCell = editingCell?.rowIndex === rowIndex && editingCell?.colIndex === colIndex;
1181
- if (editingCell && !isSameEditingCell && !commitEdit()) {
1182
- return;
1183
- }
1184
- handleCellMouseDown(rowIndex, colIndex);
1185
- },
1186
- [commitEdit, editingCell, handleCellMouseDown]
1187
- );
1188
- const clearHover = () => {
1189
- setHoveredRowIndex(null);
1190
- setHoveredGroupKey(null);
1191
- };
1192
- const handleRowHover = (0, import_react6.useCallback)(
1193
- (rowIndex, rowData) => {
1194
- setHoveredRowIndex(rowIndex);
1195
- if (!primaryRowSpanKey) {
1196
- setHoveredGroupKey(null);
1197
- return;
1198
- }
1199
- const groupValue = rowData[primaryRowSpanKey];
1200
- setHoveredGroupKey(
1201
- groupValue === null || groupValue === void 0 ? null : String(groupValue)
1202
- );
1203
- },
1204
- [primaryRowSpanKey]
1205
- );
1206
- const handleToggleSelect = (0, import_react6.useCallback)(
1207
- (row) => {
1208
- if (!row.getCanSelect()) return;
1209
- if (preserveRowSelection && row.getIsSelected()) {
1210
- return;
1211
- }
1212
- row.toggleSelected();
1213
- },
1214
- [preserveRowSelection]
1215
- );
1216
- const handleToggleExpand = (0, import_react6.useCallback)(
1217
- (rowKey) => {
1218
- if (preventExpand) return;
1219
- handleExpandedRowsChange(toggleExpandedRowId(rowKey, expandedRows));
1220
- },
1221
- [preventExpand, handleExpandedRowsChange, expandedRows]
1222
- );
1223
- const rowContextValue = (0, import_react6.useMemo)(() => {
1224
- return {
1225
- rowSpan: {
1226
- enableRowSpan,
1227
- primaryRowSpanKey,
1228
- columnRowSpanMap,
1229
- hoveredRowIndex,
1230
- hoveredGroupKey,
1231
- selectedGroupKeys,
1232
- onRowHover: handleRowHover
1233
- },
1234
- selection: {
1235
- rowSelectionMode,
1236
- selectOnRowClick,
1237
- onRowClick,
1238
- getRowClassName
1239
- },
1240
- cellSelection: {
1241
- activeSelectionBounds,
1242
- dragState,
1243
- onCellMouseDown: handleCellMouseDownWithCommit,
1244
- onCellMouseEnter: handleCellMouseEnter,
1245
- onFillHandleMouseDown: handleFillHandleMouseDown
1246
- },
1247
- cellEdit: {
1248
- editingCell,
1249
- draftValue,
1250
- onDraftValueChange: setDraftValue,
1251
- onStartEdit: startEdit,
1252
- onCommitEdit: commitEdit,
1253
- onCancelEdit: cancelEdit
1254
- },
1255
- expand: {
1256
- enableExpand,
1257
- toggleField,
1258
- expandedRows,
1259
- preventExpand,
1260
- onToggleExpand: handleToggleExpand
1261
- }
1262
- };
1263
- }, [
1264
- enableRowSpan,
1265
- primaryRowSpanKey,
1266
- columnRowSpanMap,
1267
- hoveredRowIndex,
1268
- hoveredGroupKey,
1269
- selectedGroupKeys,
1270
- handleRowHover,
1271
- rowSelectionMode,
1272
- selectOnRowClick,
1273
- onRowClick,
1274
- getRowClassName,
1275
- activeSelectionBounds,
1276
- dragState,
1277
- handleCellMouseDownWithCommit,
1278
- handleCellMouseEnter,
1279
- handleFillHandleMouseDown,
1280
- editingCell,
1281
- draftValue,
1282
- setDraftValue,
1283
- startEdit,
1284
- commitEdit,
1285
- cancelEdit,
1286
- enableExpand,
1287
- toggleField,
1288
- expandedRows,
1289
- preventExpand,
1290
- handleToggleExpand
1291
- ]);
1682
+ table,
1683
+ tableData,
1684
+ rows,
1685
+ columnCount,
1686
+ selectedCount,
1687
+ emptyText,
1688
+ loadingText,
1689
+ selectionLabel,
1690
+ enableCellSelection,
1691
+ shouldVirtualize,
1692
+ scrollRef,
1693
+ rowVirtualizer,
1694
+ virtualRows,
1695
+ paddingTop,
1696
+ paddingBottom,
1697
+ rowContextValue,
1698
+ handleToggleSelect,
1699
+ clearHover
1700
+ } = useGlideTable(glideOptions);
1701
+ const ToolbarSlot = slots?.Toolbar ?? DataTableToolbar;
1702
+ const RowSlot = slots?.Row ?? DataTableRow;
1703
+ const PendingSlot = slots?.Pending ?? DefaultPending;
1704
+ const EmptySlot = slots?.Empty ?? DefaultEmpty;
1292
1705
  if (isPending) {
1293
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: cn("DataTableJSX", "DataTableJSX--pending", className), children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "data-table-loading-text", children: "\uB85C\uB529 \uC911..." }) });
1706
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PendingSlot, { loadingText, className });
1294
1707
  }
1295
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: cn("DataTableJSX", className), children: [
1296
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1297
- DataTableToolbar,
1298
- {
1299
- filteredCount: filteredCount ?? tableData.length,
1300
- totalCount,
1301
- summary,
1302
- selectedCount,
1303
- selectionLabel,
1304
- toolbar
1305
- }
1306
- ),
1307
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { ref: scrollRef, className: "data-table-scroll", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1308
- "table",
1309
- {
1310
- className: "data-table",
1311
- onDragStart: (event) => event.preventDefault(),
1312
- children: [
1313
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("thead", { className: "data-table-head", children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tr", { className: "data-table-head-row", children: headerGroup.headers.map((header) => {
1314
- const align = header.column.columnDef.meta?.align ?? "center";
1315
- const headerClassName = header.column.columnDef.meta?.headerClassName;
1316
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1317
- "th",
1318
- {
1319
- style: { width: header.getSize() !== 150 ? header.getSize() : void 0 },
1320
- className: cn(
1321
- "data-table-head-cell",
1322
- CELL_ALIGN_CLASS[align],
1323
- headerClassName
1324
- ),
1325
- children: header.isPlaceholder ? null : (0, import_react_table2.flexRender)(header.column.columnDef.header, header.getContext())
1326
- },
1327
- header.id
1328
- );
1329
- }) }, headerGroup.id)) }),
1330
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(DataTableContextProvider, { value: rowContextValue, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tbody", { onMouseLeave: clearHover, className: "data-table-body", children: rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { colSpan: columnCount, className: "data-table-empty-cell", children: emptyText }) }) : shouldVirtualize ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1331
- paddingTop > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tr", { "aria-hidden": true, className: "data-table-virtual-spacer", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1332
- "td",
1333
- {
1334
- colSpan: columnCount,
1335
- style: { height: paddingTop },
1336
- className: "data-table-virtual-spacer-cell"
1337
- }
1338
- ) }),
1339
- virtualRows.map((virtualRow) => {
1340
- const row = rows[virtualRow.index];
1341
- if (!row) return null;
1342
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1343
- DataTableRow,
1708
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1709
+ "div",
1710
+ {
1711
+ className: cn(
1712
+ "DataTableJSX",
1713
+ !enableCellSelection && "DataTableJSX--no-cell-selection",
1714
+ className
1715
+ ),
1716
+ children: [
1717
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1718
+ ToolbarSlot,
1719
+ {
1720
+ filteredCount: filteredCount ?? tableData.length,
1721
+ totalCount,
1722
+ summary,
1723
+ selectedCount,
1724
+ selectionLabel,
1725
+ toolbar
1726
+ }
1727
+ ),
1728
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { ref: scrollRef, className: "data-table-scroll", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1729
+ "table",
1730
+ {
1731
+ className: "data-table",
1732
+ onDragStart: enableCellSelection ? (event) => event.preventDefault() : void 0,
1733
+ children: [
1734
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("thead", { className: "data-table-head", children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tr", { className: "data-table-head-row", children: headerGroup.headers.map((header) => {
1735
+ const align = header.column.columnDef.meta?.align ?? "center";
1736
+ const headerClassName = header.column.columnDef.meta?.headerClassName;
1737
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1738
+ "th",
1739
+ {
1740
+ style: { width: header.getSize() !== 150 ? header.getSize() : void 0 },
1741
+ className: cn(
1742
+ "data-table-head-cell",
1743
+ CELL_ALIGN_CLASS[align],
1744
+ headerClassName
1745
+ ),
1746
+ children: header.isPlaceholder ? null : (0, import_react_table3.flexRender)(header.column.columnDef.header, header.getContext())
1747
+ },
1748
+ header.id
1749
+ );
1750
+ }) }, headerGroup.id)) }),
1751
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(DataTableContextProvider, { value: rowContextValue, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tbody", { onMouseLeave: clearHover, className: "data-table-body", children: rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(EmptySlot, { emptyText, columnCount }) : shouldVirtualize ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1752
+ paddingTop > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tr", { "aria-hidden": true, className: "data-table-virtual-spacer", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1753
+ "td",
1754
+ {
1755
+ colSpan: columnCount,
1756
+ style: { height: paddingTop },
1757
+ className: "data-table-virtual-spacer-cell"
1758
+ }
1759
+ ) }),
1760
+ virtualRows.map((virtualRow) => {
1761
+ const row = rows[virtualRow.index];
1762
+ if (!row) return null;
1763
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1764
+ RowSlot,
1765
+ {
1766
+ row,
1767
+ virtualIndex: virtualRow.index,
1768
+ measureElement: rowVirtualizer.measureElement,
1769
+ onToggleSelect: () => handleToggleSelect(row)
1770
+ },
1771
+ row.id
1772
+ );
1773
+ }),
1774
+ paddingBottom > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tr", { "aria-hidden": true, className: "data-table-virtual-spacer", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1775
+ "td",
1776
+ {
1777
+ colSpan: columnCount,
1778
+ style: { height: paddingBottom },
1779
+ className: "data-table-virtual-spacer-cell"
1780
+ }
1781
+ ) })
1782
+ ] }) : rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1783
+ RowSlot,
1344
1784
  {
1345
1785
  row,
1346
- virtualIndex: virtualRow.index,
1347
- measureElement: rowVirtualizer.measureElement,
1348
1786
  onToggleSelect: () => handleToggleSelect(row)
1349
1787
  },
1350
1788
  row.id
1351
- );
1352
- }),
1353
- paddingBottom > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tr", { "aria-hidden": true, className: "data-table-virtual-spacer", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1354
- "td",
1355
- {
1356
- colSpan: columnCount,
1357
- style: { height: paddingBottom },
1358
- className: "data-table-virtual-spacer-cell"
1359
- }
1360
- ) })
1361
- ] }) : rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1362
- DataTableRow,
1363
- {
1364
- row,
1365
- onToggleSelect: () => handleToggleSelect(row)
1366
- },
1367
- row.id
1368
- )) }) })
1369
- ]
1370
- }
1371
- ) })
1372
- ] });
1789
+ )) }) })
1790
+ ]
1791
+ }
1792
+ ) })
1793
+ ]
1794
+ }
1795
+ );
1373
1796
  }
1374
1797
 
1375
1798
  // src/components/ui/table/components/Table/Table.tsx
@@ -1568,7 +1991,7 @@ function TablePagination({
1568
1991
  className: "pagination-button",
1569
1992
  disabled: !canGoPrev,
1570
1993
  onClick: () => onChange(safePage - 1),
1571
- "aria-label": "\uC774\uC804 \uD398\uC774\uC9C0",
1994
+ "aria-label": "Previous page",
1572
1995
  children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChevronLeft, { className: "pagination-button-icon" })
1573
1996
  }
1574
1997
  ),
@@ -1584,7 +2007,7 @@ function TablePagination({
1584
2007
  className: "pagination-button",
1585
2008
  disabled: !canGoNext,
1586
2009
  onClick: () => onChange(safePage + 1),
1587
- "aria-label": "\uB2E4\uC74C \uD398\uC774\uC9C0",
2010
+ "aria-label": "Next page",
1588
2011
  children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChevronRight, { className: "pagination-button-icon" })
1589
2012
  }
1590
2013
  )
@@ -1633,7 +2056,7 @@ function TableRoot({
1633
2056
  return paginateTableData(sortedData, page, pageSize);
1634
2057
  }, [data, sort, paginationProps, page, pageSize]);
1635
2058
  if (columns.length === 0) {
1636
- console.warn("[Table] Table.Header \uC548\uC5D0 Table.Column\uC744 \uD558\uB098 \uC774\uC0C1 \uC120\uC5B8\uD574 \uC8FC\uC138\uC694.");
2059
+ console.warn("[Table] Declare at least one Table.Column inside Table.Header.");
1637
2060
  }
1638
2061
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "TableJSX", children: [
1639
2062
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
@@ -1685,7 +2108,36 @@ var Table = Object.assign(TableRoot, {
1685
2108
  });
1686
2109
  // Annotate the CommonJS export names for ESM import in node:
1687
2110
  0 && (module.exports = {
2111
+ CELL_SELECTION_EDGES_CLASS,
2112
+ DEFAULT_DATA_TABLE_LABELS,
2113
+ DEFAULT_TREE_CHILDREN_FIELD,
2114
+ DEFAULT_TREE_ID_FIELD,
2115
+ DEFAULT_TREE_PARENT_ID_FIELD,
2116
+ DEFAULT_TREE_QTY_FIELD,
1688
2117
  DataTable,
1689
2118
  Table,
1690
- createTable
2119
+ applyCellEdit,
2120
+ applyFillData,
2121
+ applySelectionUpdater,
2122
+ buildColumnRowSpanMap,
2123
+ canExpandRow,
2124
+ collectFillChanges,
2125
+ collectRowSpanColumns,
2126
+ createTable,
2127
+ getCellEditDraftValue,
2128
+ getCellSelectionEdgeStyle,
2129
+ getColumnEditType,
2130
+ getRowIndexInMergedCell,
2131
+ hasCellSelectionEdges,
2132
+ isCellInSelection,
2133
+ isColumnEditable,
2134
+ parseCellEditValue,
2135
+ resolveDataTableLabels,
2136
+ resolveRowSelection,
2137
+ resolveRowSpanAt,
2138
+ toggleExpandedRowId,
2139
+ useCellEdit,
2140
+ useCellSelection,
2141
+ useConvertTreeData,
2142
+ useGlideTable
1691
2143
  });