react-glide-table 1.0.2 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,45 +1,46 @@
1
- // src/components/ui/table/components/DataTable/DataTable.tsx
1
+ // src/core/labels.ts
2
+ var DEFAULT_DATA_TABLE_LABELS = {
3
+ empty: "No data",
4
+ loading: "Loading...",
5
+ selection: (selectedCount) => selectedCount > 0 ? `\u2713 ${selectedCount} selected` : null,
6
+ expandRow: "Expand row",
7
+ collapseRow: "Collapse row"
8
+ };
9
+ function resolveDataTableLabels(partial) {
10
+ return {
11
+ ...DEFAULT_DATA_TABLE_LABELS,
12
+ ...partial
13
+ };
14
+ }
15
+
16
+ // src/core/treeDefaults.ts
17
+ var DEFAULT_TREE_ID_FIELD = "id";
18
+ var DEFAULT_TREE_PARENT_ID_FIELD = "parentId";
19
+ var DEFAULT_TREE_CHILDREN_FIELD = "children";
20
+ var DEFAULT_TREE_QTY_FIELD = "qty";
21
+
22
+ // src/core/useGlideTable.ts
2
23
  import {
3
- flexRender as flexRender2,
4
24
  getCoreRowModel,
5
25
  useReactTable
6
26
  } from "@tanstack/react-table";
7
- import { useVirtualizer } from "@tanstack/react-virtual";
8
- import { useCallback as useCallback3, useEffect as useEffect5, useMemo as useMemo2, useRef as useRef4, useState as useState3 } from "react";
9
-
10
- // src/components/ui/table/components/DataTable/DataTableRow.tsx
11
- import { flexRender } from "@tanstack/react-table";
12
- import { useEffect as useEffect2, useRef as useRef2 } from "react";
27
+ import {
28
+ useVirtualizer
29
+ } from "@tanstack/react-virtual";
30
+ import {
31
+ useCallback as useCallback3,
32
+ useEffect as useEffect4,
33
+ useMemo as useMemo2,
34
+ useRef as useRef3,
35
+ useState as useState3
36
+ } from "react";
13
37
 
14
38
  // src/components/ui/table/constants.ts
15
- var CELL_ALIGN_CLASS = {
16
- left: "cell-align-left",
17
- center: "cell-align-center",
18
- right: "cell-align-right"
19
- };
20
- var ROW_HOVER_CLASS = "row-hoverable";
21
- var ROW_HOVERED_BG_CLASS = "row-hovered";
22
- var CELL_SELECTION_FILL_CLASS = "cell-selection-fill";
23
39
  var DATA_TABLE_ROW_HEIGHT = 44;
24
40
  var DATA_TABLE_VIRTUAL_OVERSCAN = 8;
25
41
 
26
- // src/components/ui/table/DataTableContext.tsx
27
- import { createContext, use } from "react";
28
- import { jsx } from "react/jsx-runtime";
29
- var DataTableContext = createContext(null);
30
- function useDataTableRowContext() {
31
- const context = use(DataTableContext);
32
- if (!context) {
33
- throw new Error("useDataTableRowContext must be used within a DataTableContextProvider");
34
- }
35
- return context;
36
- }
37
- function DataTableContextProvider({
38
- value,
39
- children
40
- }) {
41
- return /* @__PURE__ */ jsx(DataTableContext, { value, children });
42
- }
42
+ // src/components/ui/table/features/cell-edit/useCellEdit.ts
43
+ import { useCallback, useEffect, useRef, useState } from "react";
43
44
 
44
45
  // src/components/ui/table/features/cell-edit/cellEdit.ts
45
46
  function getColumnAccessorKey(columnDef) {
@@ -87,6 +88,87 @@ function applyCellEdit(data, rows, rowIndex, colIndex, raw) {
87
88
  return newData;
88
89
  }
89
90
 
91
+ // src/components/ui/table/features/cell-edit/useCellEdit.ts
92
+ function useCellEdit({
93
+ data,
94
+ rows,
95
+ onDataChange,
96
+ onCellChange
97
+ }) {
98
+ const [editingCell, setEditingCell] = useState(null);
99
+ const [draftValue, setDraftValue] = useState("");
100
+ const draftValueRef = useRef(draftValue);
101
+ const editingCellRef = useRef(editingCell);
102
+ useEffect(() => {
103
+ draftValueRef.current = draftValue;
104
+ }, [draftValue]);
105
+ useEffect(() => {
106
+ editingCellRef.current = editingCell;
107
+ }, [editingCell]);
108
+ const cancelEdit = useCallback(() => {
109
+ setEditingCell(null);
110
+ setDraftValue("");
111
+ }, []);
112
+ const commitEdit = useCallback(
113
+ (raw) => {
114
+ const current = editingCellRef.current;
115
+ if (!current) return true;
116
+ if (!onCellChange && !onDataChange) {
117
+ cancelEdit();
118
+ return true;
119
+ }
120
+ const row = rows[current.rowIndex];
121
+ const cell = row?.getVisibleCells()[current.colIndex];
122
+ if (!row || !cell) {
123
+ cancelEdit();
124
+ return true;
125
+ }
126
+ const value = raw ?? draftValueRef.current;
127
+ if (!isColumnEditable(cell.column.columnDef)) {
128
+ cancelEdit();
129
+ return true;
130
+ }
131
+ const parsed = parseCellEditValue(value, getColumnEditType(cell.column.columnDef));
132
+ if (!parsed.ok) return false;
133
+ if (onCellChange) {
134
+ onCellChange(row.id, cell.column.id, parsed.value);
135
+ cancelEdit();
136
+ return true;
137
+ }
138
+ const next = applyCellEdit(data, rows, current.rowIndex, current.colIndex, value);
139
+ if (!next) return false;
140
+ onDataChange?.(next);
141
+ cancelEdit();
142
+ return true;
143
+ },
144
+ [cancelEdit, data, onCellChange, onDataChange, rows]
145
+ );
146
+ const startEdit = useCallback(
147
+ (rowIndex, colIndex) => {
148
+ const cell = rows[rowIndex]?.getVisibleCells()[colIndex];
149
+ if (!cell || !isColumnEditable(cell.column.columnDef)) return;
150
+ const current = editingCellRef.current;
151
+ if (current && (current.rowIndex !== rowIndex || current.colIndex !== colIndex) && !commitEdit()) {
152
+ return;
153
+ }
154
+ setEditingCell({ rowIndex, colIndex });
155
+ setDraftValue(getCellEditDraftValue(cell.getValue()));
156
+ },
157
+ [commitEdit, rows]
158
+ );
159
+ return {
160
+ editingCell,
161
+ draftValue,
162
+ setDraftValue,
163
+ startEdit,
164
+ commitEdit,
165
+ cancelEdit
166
+ };
167
+ }
168
+
169
+ // src/components/ui/table/features/cell-selection/useCellSelection.ts
170
+ import { useCallback as useCallback2, useEffect as useEffect2, useState as useState2 } from "react";
171
+
90
172
  // src/components/ui/table/features/cell-selection/cellSelection.ts
91
173
  var INITIAL_DRAG_STATE = {
92
174
  isSelecting: false,
@@ -110,7 +192,10 @@ function getRowIndexInMergedCell(clientY, cellElement, rowIndex, rowSpan) {
110
192
  const rect = cellElement.getBoundingClientRect();
111
193
  const relativeY = clientY - rect.top;
112
194
  const rowHeight = rect.height / rowSpan;
113
- const offset = Math.min(Math.max(Math.floor(relativeY / rowHeight), 0), rowSpan - 1);
195
+ const offset = Math.min(
196
+ Math.max(Math.floor(relativeY / rowHeight), 0),
197
+ rowSpan - 1
198
+ );
114
199
  return rowIndex + offset;
115
200
  }
116
201
  function isCellInSelection(rowIndex, colIndex, bounds, rowSpan = 1) {
@@ -126,31 +211,348 @@ function getActiveSelectionBounds(dragState, selectionBounds) {
126
211
  }
127
212
  var SELECTION_EDGE_WIDTH_PX = 2;
128
213
  var SELECTION_EDGE_COLOR = "var(--color-brand-primary)";
129
- function getCellSelectionEdgeStyle(rowIndex, colIndex, bounds, rowSpan = 1) {
130
- if (!isCellInSelection(rowIndex, colIndex, bounds, rowSpan) || !bounds) return void 0;
214
+ var CELL_SELECTION_EDGES_CLASS = "cell-selection-edges";
215
+ function getMergedCellStepEdges(rowIndex, colIndex, bounds, rowSpan, isVisuallySelectedAt) {
216
+ const cellEndRow = rowIndex + rowSpan - 1;
217
+ const span = cellEndRow - rowIndex + 1;
218
+ if (span <= 1) return [];
219
+ const edges = [];
220
+ const isNeighborSelected = (row, neighborCol) => {
221
+ if (isVisuallySelectedAt) {
222
+ return isVisuallySelectedAt(row, neighborCol);
223
+ }
224
+ return row >= bounds.startRow && row <= bounds.endRow && neighborCol >= bounds.startCol && neighborCol <= bounds.endCol;
225
+ };
226
+ const pushUnselectedRuns = (side, neighborCol, fromRow, toRowExclusive) => {
227
+ let runStart = null;
228
+ for (let row = fromRow; row < toRowExclusive; row++) {
229
+ if (!isNeighborSelected(row, neighborCol)) {
230
+ if (runStart === null) runStart = row;
231
+ continue;
232
+ }
233
+ if (runStart !== null) {
234
+ edges.push({
235
+ side,
236
+ offsetRatio: (runStart - rowIndex) / span,
237
+ heightRatio: (row - runStart) / span
238
+ });
239
+ runStart = null;
240
+ }
241
+ }
242
+ if (runStart !== null) {
243
+ edges.push({
244
+ side,
245
+ offsetRatio: (runStart - rowIndex) / span,
246
+ heightRatio: (toRowExclusive - runStart) / span
247
+ });
248
+ }
249
+ };
250
+ const collectSide = (side, neighborCol) => {
251
+ if (bounds.startRow > rowIndex) {
252
+ pushUnselectedRuns(
253
+ side,
254
+ neighborCol,
255
+ rowIndex,
256
+ Math.min(bounds.startRow, cellEndRow + 1)
257
+ );
258
+ }
259
+ if (bounds.endRow < cellEndRow) {
260
+ pushUnselectedRuns(
261
+ side,
262
+ neighborCol,
263
+ Math.max(bounds.endRow + 1, rowIndex),
264
+ cellEndRow + 1
265
+ );
266
+ }
267
+ };
268
+ if (colIndex < bounds.endCol) {
269
+ collectSide("right", colIndex + 1);
270
+ }
271
+ if (colIndex > bounds.startCol) {
272
+ collectSide("left", colIndex - 1);
273
+ }
274
+ return edges;
275
+ }
276
+ function buildPartialVerticalGradient(edge) {
277
+ const startPct = edge.offsetRatio * 100;
278
+ const endPct = (edge.offsetRatio + edge.heightRatio) * 100;
279
+ const overlapPx = SELECTION_EDGE_WIDTH_PX + 1;
280
+ const isTopProtrusion = edge.offsetRatio === 0 && edge.heightRatio < 1;
281
+ const isBottomProtrusion = edge.offsetRatio > 0;
282
+ const startStop = isBottomProtrusion ? `calc(${startPct}% - ${overlapPx}px)` : `${startPct}%`;
283
+ const endStop = isTopProtrusion ? `calc(${endPct}% + ${overlapPx}px)` : `${endPct}%`;
284
+ const xPos = edge.side === "left" ? "0" : "100%";
285
+ const layers = [
286
+ {
287
+ image: `linear-gradient(to bottom, transparent 0%, transparent ${startStop}, ${SELECTION_EDGE_COLOR} ${startStop}, ${SELECTION_EDGE_COLOR} ${endStop}, transparent ${endStop}, transparent 100%)`,
288
+ size: `${SELECTION_EDGE_WIDTH_PX}px 100%`,
289
+ position: `${xPos} 0`
290
+ }
291
+ ];
292
+ if (isTopProtrusion || isBottomProtrusion) {
293
+ const capTop = isTopProtrusion ? `calc(${endPct}% - ${SELECTION_EDGE_WIDTH_PX}px)` : `calc(${startPct}% - ${SELECTION_EDGE_WIDTH_PX}px)`;
294
+ layers.push({
295
+ image: `linear-gradient(${SELECTION_EDGE_COLOR}, ${SELECTION_EDGE_COLOR})`,
296
+ size: `${SELECTION_EDGE_WIDTH_PX}px ${SELECTION_EDGE_WIDTH_PX}px`,
297
+ position: `${xPos} ${capTop}`
298
+ });
299
+ }
300
+ return layers;
301
+ }
302
+ function getCellSelectionEdgeStyle(rowIndex, colIndex, bounds, rowSpan = 1, isVisuallySelectedAt) {
303
+ if (!isCellInSelection(rowIndex, colIndex, bounds, rowSpan) || !bounds)
304
+ return void 0;
131
305
  const cellEndRow = rowIndex + rowSpan - 1;
132
306
  const isTopEdge = bounds.startRow >= rowIndex && bounds.startRow <= cellEndRow;
133
307
  const isBottomEdge = bounds.endRow >= rowIndex && bounds.endRow <= cellEndRow;
134
308
  const isLeftEdge = colIndex === bounds.startCol;
135
309
  const isRightEdge = colIndex === bounds.endCol;
310
+ const selectionContinuesBelow = cellEndRow < bounds.endRow;
136
311
  const shadows = [];
137
312
  if (isTopEdge) {
138
- shadows.push(`inset 0 ${SELECTION_EDGE_WIDTH_PX}px 0 0 ${SELECTION_EDGE_COLOR}`);
313
+ shadows.push(
314
+ `inset 0 ${SELECTION_EDGE_WIDTH_PX}px 0 0 ${SELECTION_EDGE_COLOR}`
315
+ );
139
316
  }
140
317
  if (isBottomEdge) {
141
- shadows.push(`inset 0 -${SELECTION_EDGE_WIDTH_PX}px 0 0 ${SELECTION_EDGE_COLOR}`);
318
+ shadows.push(
319
+ `inset 0 -${SELECTION_EDGE_WIDTH_PX}px 0 0 ${SELECTION_EDGE_COLOR}`
320
+ );
142
321
  }
143
322
  if (isLeftEdge) {
144
- shadows.push(`inset ${SELECTION_EDGE_WIDTH_PX}px 0 0 0 ${SELECTION_EDGE_COLOR}`);
323
+ shadows.push(
324
+ `inset ${SELECTION_EDGE_WIDTH_PX}px 0 0 0 ${SELECTION_EDGE_COLOR}`
325
+ );
145
326
  }
146
327
  if (isRightEdge) {
147
- shadows.push(`inset -${SELECTION_EDGE_WIDTH_PX}px 0 0 0 ${SELECTION_EDGE_COLOR}`);
328
+ shadows.push(
329
+ `inset -${SELECTION_EDGE_WIDTH_PX}px 0 0 0 ${SELECTION_EDGE_COLOR}`
330
+ );
331
+ }
332
+ const stepEdges = getMergedCellStepEdges(
333
+ rowIndex,
334
+ colIndex,
335
+ bounds,
336
+ rowSpan,
337
+ isVisuallySelectedAt
338
+ );
339
+ const gradients = [];
340
+ const sizes = [];
341
+ const positions = [];
342
+ for (const edge of stepEdges) {
343
+ for (const partial of buildPartialVerticalGradient(edge)) {
344
+ gradients.push(partial.image);
345
+ sizes.push(partial.size);
346
+ positions.push(partial.position);
347
+ }
348
+ }
349
+ if (shadows.length === 0 && gradients.length === 0 && !selectionContinuesBelow) {
350
+ return void 0;
351
+ }
352
+ const style = {};
353
+ if (shadows.length > 0) {
354
+ style["--selection-edge-shadows"] = shadows.join(", ");
355
+ }
356
+ if (gradients.length > 0) {
357
+ style["--selection-edge-gradients"] = gradients.join(", ");
358
+ style["--selection-edge-sizes"] = sizes.join(", ");
359
+ style["--selection-edge-positions"] = positions.join(", ");
360
+ }
361
+ if (selectionContinuesBelow) {
362
+ style.borderBottomColor = "var(--color-brand-surface)";
363
+ }
364
+ return style;
365
+ }
366
+ function hasCellSelectionEdges(style) {
367
+ return Boolean(
368
+ style?.["--selection-edge-shadows"] || style?.["--selection-edge-gradients"]
369
+ );
370
+ }
371
+
372
+ // src/components/ui/table/features/cell-selection/fillData.ts
373
+ function getColumnAccessorKey2(columnDef) {
374
+ if ("accessorKey" in columnDef && columnDef.accessorKey) {
375
+ return String(columnDef.accessorKey);
376
+ }
377
+ return columnDef.id;
378
+ }
379
+ function collectFillTargets(rows, sourceBounds, fillBounds) {
380
+ const targets = [];
381
+ const sourceHeight = sourceBounds.endRow - sourceBounds.startRow + 1;
382
+ const sourceWidth = sourceBounds.endCol - sourceBounds.startCol + 1;
383
+ for (let rowIndex = fillBounds.startRow; rowIndex <= fillBounds.endRow; rowIndex += 1) {
384
+ for (let colIndex = fillBounds.startCol; colIndex <= fillBounds.endCol; colIndex += 1) {
385
+ if (isCellInSelection(rowIndex, colIndex, sourceBounds)) continue;
386
+ const offsetRow = rowIndex - sourceBounds.startRow;
387
+ const offsetCol = colIndex - sourceBounds.startCol;
388
+ const sourceRowIndex = sourceBounds.startRow + (offsetRow % sourceHeight + sourceHeight) % sourceHeight;
389
+ const sourceColIndex = sourceBounds.startCol + (offsetCol % sourceWidth + sourceWidth) % sourceWidth;
390
+ const targetRow = rows[rowIndex];
391
+ const targetCell = targetRow?.getVisibleCells()[colIndex];
392
+ const sourceCell = rows[sourceRowIndex]?.getVisibleCells()[sourceColIndex];
393
+ if (!targetRow || !targetCell || !sourceCell) continue;
394
+ const accessorKey = getColumnAccessorKey2(
395
+ targetCell.column.columnDef
396
+ );
397
+ if (!accessorKey) continue;
398
+ targets.push({
399
+ rowIndex,
400
+ accessorKey,
401
+ columnId: targetCell.column.id,
402
+ value: sourceCell.getValue(),
403
+ rowId: targetRow.id
404
+ });
405
+ }
406
+ }
407
+ return targets;
408
+ }
409
+ function collectFillChanges(rows, sourceBounds, fillBounds) {
410
+ return collectFillTargets(rows, sourceBounds, fillBounds).map(
411
+ ({ rowId, columnId, value }) => ({ rowId, columnId, value })
412
+ );
413
+ }
414
+ function applyFillData(data, rows, sourceBounds, fillBounds) {
415
+ const newData = data.map((row) => ({ ...row }));
416
+ const targets = collectFillTargets(rows, sourceBounds, fillBounds);
417
+ for (const target of targets) {
418
+ if (!newData[target.rowIndex]) continue;
419
+ newData[target.rowIndex][target.accessorKey] = target.value;
148
420
  }
149
- return shadows.length > 0 ? { boxShadow: shadows.join(", ") } : void 0;
421
+ return newData;
422
+ }
423
+ function hasFillExtension(sourceBounds, fillBounds) {
424
+ if (!sourceBounds) return false;
425
+ return fillBounds.startRow < sourceBounds.startRow || fillBounds.endRow > sourceBounds.endRow || fillBounds.startCol < sourceBounds.startCol || fillBounds.endCol > sourceBounds.endCol;
426
+ }
427
+
428
+ // src/components/ui/table/features/cell-selection/useCellSelection.ts
429
+ function useCellSelection({
430
+ data,
431
+ rows,
432
+ enabled = true,
433
+ onDataChange,
434
+ onBatchChange
435
+ }) {
436
+ const [dragState, setDragState] = useState2(INITIAL_DRAG_STATE);
437
+ const cellSelectionBounds = getCellSelectionBounds(dragState.start, dragState.end);
438
+ const activeSelectionBounds = enabled ? getActiveSelectionBounds(dragState, cellSelectionBounds) : null;
439
+ const handleCellMouseDown = useCallback2(
440
+ (rowIndex, colIndex) => {
441
+ if (!enabled) return;
442
+ setDragState({
443
+ isSelecting: true,
444
+ isFillDragging: false,
445
+ start: { row: rowIndex, col: colIndex },
446
+ end: { row: rowIndex, col: colIndex },
447
+ fillAnchor: null,
448
+ fillEnd: null
449
+ });
450
+ },
451
+ [enabled]
452
+ );
453
+ const handleCellMouseEnter = useCallback2(
454
+ (rowIndex, colIndex) => {
455
+ if (!enabled) return;
456
+ setDragState((prev) => {
457
+ if (prev.isSelecting) {
458
+ return { ...prev, end: { row: rowIndex, col: colIndex } };
459
+ }
460
+ if (prev.isFillDragging) {
461
+ return { ...prev, fillEnd: { row: rowIndex, col: colIndex } };
462
+ }
463
+ return prev;
464
+ });
465
+ },
466
+ [enabled]
467
+ );
468
+ const handleFillHandleMouseDown = useCallback2(
469
+ (rowIndex, colIndex) => {
470
+ if (!enabled) return;
471
+ setDragState((prev) => {
472
+ const bounds = getCellSelectionBounds(prev.start, prev.end);
473
+ if (!bounds) return prev;
474
+ return {
475
+ ...prev,
476
+ isSelecting: false,
477
+ isFillDragging: true,
478
+ fillAnchor: { row: bounds.startRow, col: bounds.startCol },
479
+ fillEnd: { row: rowIndex, col: colIndex }
480
+ };
481
+ });
482
+ },
483
+ [enabled]
484
+ );
485
+ useEffect2(() => {
486
+ if (!enabled) {
487
+ setDragState(INITIAL_DRAG_STATE);
488
+ }
489
+ }, [enabled]);
490
+ useEffect2(() => {
491
+ if (!enabled) return;
492
+ const handleKeyDown = (e) => {
493
+ if ((e.ctrlKey || e.metaKey) && e.key === "c" && activeSelectionBounds) {
494
+ const { startRow, endRow, startCol, endCol } = activeSelectionBounds;
495
+ const selectedData = rows.slice(startRow, endRow + 1).map((row) => {
496
+ const cells = row.getVisibleCells();
497
+ return cells.slice(startCol, endCol + 1).map((cell) => cell.getValue()).join(" ");
498
+ }).join("\n");
499
+ navigator.clipboard.writeText(selectedData);
500
+ }
501
+ };
502
+ window.addEventListener("keydown", handleKeyDown);
503
+ return () => window.removeEventListener("keydown", handleKeyDown);
504
+ }, [activeSelectionBounds, enabled, rows]);
505
+ useEffect2(() => {
506
+ if (!enabled) return;
507
+ const handleMouseUp = () => {
508
+ setDragState((prev) => {
509
+ if (prev.isFillDragging && prev.fillAnchor && prev.fillEnd) {
510
+ const sourceBounds = getCellSelectionBounds(prev.start, prev.end);
511
+ const newBounds = getCellSelectionBounds(prev.fillAnchor, prev.fillEnd);
512
+ if (newBounds) {
513
+ if (hasFillExtension(sourceBounds, newBounds) && sourceBounds) {
514
+ if (onBatchChange) {
515
+ const changes = collectFillChanges(rows, sourceBounds, newBounds);
516
+ if (changes.length > 0) {
517
+ onBatchChange(changes);
518
+ }
519
+ } else if (onDataChange) {
520
+ onDataChange(applyFillData(data, rows, sourceBounds, newBounds));
521
+ }
522
+ }
523
+ return {
524
+ isSelecting: false,
525
+ isFillDragging: false,
526
+ start: { row: newBounds.startRow, col: newBounds.startCol },
527
+ end: { row: newBounds.endRow, col: newBounds.endCol },
528
+ fillAnchor: null,
529
+ fillEnd: null
530
+ };
531
+ }
532
+ }
533
+ if (prev.isSelecting) {
534
+ return { ...prev, isSelecting: false };
535
+ }
536
+ if (prev.isFillDragging) {
537
+ return { ...prev, isFillDragging: false, fillAnchor: null, fillEnd: null };
538
+ }
539
+ return prev;
540
+ });
541
+ };
542
+ window.addEventListener("mouseup", handleMouseUp);
543
+ return () => window.removeEventListener("mouseup", handleMouseUp);
544
+ }, [data, enabled, onBatchChange, onDataChange, rows]);
545
+ return {
546
+ dragState: enabled ? dragState : INITIAL_DRAG_STATE,
547
+ activeSelectionBounds,
548
+ handleCellMouseDown,
549
+ handleCellMouseEnter,
550
+ handleFillHandleMouseDown
551
+ };
150
552
  }
151
553
 
152
554
  // src/components/ui/table/features/row-expand/row-expand.ts
153
- import { useEffect, useMemo, useRef } from "react";
555
+ import { useEffect as useEffect3, useMemo, useRef as useRef2 } from "react";
154
556
  function getFieldValue(row, key) {
155
557
  return row[key];
156
558
  }
@@ -171,20 +573,21 @@ function toggleExpandedRowId(rowId, previous) {
171
573
  var useConvertTreeData = ({
172
574
  data,
173
575
  enabled = true,
174
- toggleField = "materialCode",
175
- childField = "assemblyCode",
176
- flattenField = "assemblyMaterials",
576
+ toggleField = DEFAULT_TREE_ID_FIELD,
577
+ childField = DEFAULT_TREE_PARENT_ID_FIELD,
578
+ flattenField = DEFAULT_TREE_CHILDREN_FIELD,
579
+ qtyField = DEFAULT_TREE_QTY_FIELD,
177
580
  preventExpand = false,
178
581
  startIndex = 1,
179
582
  expandedRows,
180
583
  onExpandedRowsChange
181
584
  }) => {
182
- const onExpandedRowsChangeRef = useRef(onExpandedRowsChange);
183
- const hasInitializedRef = useRef(false);
184
- useEffect(() => {
585
+ const onExpandedRowsChangeRef = useRef2(onExpandedRowsChange);
586
+ const hasInitializedRef = useRef2(false);
587
+ useEffect3(() => {
185
588
  onExpandedRowsChangeRef.current = onExpandedRowsChange;
186
589
  }, [onExpandedRowsChange]);
187
- useEffect(() => {
590
+ useEffect3(() => {
188
591
  if (!data || data.length === 0) {
189
592
  hasInitializedRef.current = false;
190
593
  return;
@@ -215,735 +618,121 @@ var useConvertTreeData = ({
215
618
  });
216
619
  flattenItems(children);
217
620
  } else {
218
- flattenedData.push(newItem);
219
- }
220
- });
221
- };
222
- flattenItems(data);
223
- const dataWithLevels = flattenedData.map((item) => ({
224
- ...item,
225
- level: 0,
226
- children: [],
227
- processed: false
228
- }));
229
- const itemMap = /* @__PURE__ */ new Map();
230
- dataWithLevels.forEach((item) => {
231
- const key = getFieldValue(item, toggleField);
232
- if (typeof key !== "string" || !key) return;
233
- if (!itemMap.has(key)) {
234
- itemMap.set(key, []);
235
- }
236
- itemMap.get(key)?.push(item);
237
- });
238
- const rootItems = [];
239
- dataWithLevels.forEach((item) => {
240
- if (!getFieldValue(item, childField)) {
241
- rootItems.push(item);
242
- item.processed = true;
243
- }
244
- });
245
- dataWithLevels.forEach((item) => {
246
- const parentKey = getFieldValue(item, childField);
247
- if (!parentKey || item.processed) return;
248
- const parentItems = dataWithLevels.filter(
249
- (parent) => getFieldValue(parent, toggleField) === parentKey && !getFieldValue(parent, childField)
250
- );
251
- if (parentItems.length > 0) {
252
- const parent = parentItems[0];
253
- item.level = parent.level + 1;
254
- parent.children.push(item);
255
- item.processed = true;
256
- } else {
257
- const otherParents = itemMap.get(String(parentKey)) || [];
258
- if (otherParents.length > 0) {
259
- const parent = otherParents[0];
260
- item.level = parent.level + 1;
261
- parent.children.push(item);
262
- item.processed = true;
263
- } else {
264
- rootItems.push(item);
265
- item.processed = true;
266
- }
267
- }
268
- });
269
- return rootItems;
270
- }, [enabled, data, toggleField, childField, flattenField]);
271
- const flattenTree = useMemo(() => {
272
- if (!enabled) return [];
273
- const flatten = (nodes, result = [], level = 0) => {
274
- nodes.forEach((node, index) => {
275
- const currentIndex = level === 0 ? `${index + startIndex}` : `${level}-${index + 1}`;
276
- const toggleValue = getFieldValue(node, toggleField);
277
- const uniqueId = `${index}-${String(toggleValue ?? "")}`;
278
- result.push({
279
- ...node,
280
- treeNo: currentIndex,
281
- uniqueId,
282
- processed: true
283
- });
284
- const shouldExpandChildren = node.children.length > 0 && (preventExpand || typeof toggleValue === "string" && expandedRows?.has(toggleValue));
285
- if (shouldExpandChildren) {
286
- flatten(node.children, result, index + startIndex);
287
- }
288
- });
289
- return result;
290
- };
291
- const flattenedData = flatten(processedData, [], 0);
292
- flattenedData.forEach((item) => {
293
- if (getFieldValue(item, childField)) {
294
- const parentItem = flattenedData.find(
295
- (parent) => getFieldValue(parent, toggleField) === getFieldValue(item, childField)
296
- );
297
- const parentAmount = parentItem ? Number(getFieldValue(parentItem, "amount") ?? 1) : 1;
298
- item.parentCount = parentAmount || 1;
299
- } else {
300
- item.parentCount = 1;
301
- }
302
- });
303
- return flattenedData;
304
- }, [enabled, processedData, startIndex, toggleField, childField, preventExpand, expandedRows]);
305
- const sortedData = useMemo(() => {
306
- if (!enabled) {
307
- return data ?? [];
308
- }
309
- return [...flattenTree].sort((a, b) => {
310
- const aParts = String(a.treeNo ?? "").split("-").map(Number);
311
- const bParts = String(b.treeNo ?? "").split("-").map(Number);
312
- for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) {
313
- const aVal = aParts[i] || 0;
314
- const bVal = bParts[i] || 0;
315
- if (aVal !== bVal) {
316
- return aVal - bVal;
317
- }
318
- }
319
- return 0;
320
- });
321
- }, [enabled, data, flattenTree]);
322
- return sortedData;
323
- };
324
-
325
- // src/components/ui/table/components/icons.tsx
326
- import { jsx as jsx2, jsxs } from "react/jsx-runtime";
327
- function ChevronDown({ className, "aria-hidden": ariaHidden = true }) {
328
- return /* @__PURE__ */ jsx2(
329
- "svg",
330
- {
331
- className,
332
- "aria-hidden": ariaHidden,
333
- width: "16",
334
- height: "16",
335
- viewBox: "0 0 24 24",
336
- fill: "none",
337
- stroke: "currentColor",
338
- strokeWidth: "2",
339
- strokeLinecap: "round",
340
- strokeLinejoin: "round",
341
- children: /* @__PURE__ */ jsx2("path", { d: "m6 9 6 6 6-6" })
342
- }
343
- );
344
- }
345
- function ChevronUp({ className, "aria-hidden": ariaHidden = true }) {
346
- return /* @__PURE__ */ jsx2(
347
- "svg",
348
- {
349
- className,
350
- "aria-hidden": ariaHidden,
351
- width: "16",
352
- height: "16",
353
- viewBox: "0 0 24 24",
354
- fill: "none",
355
- stroke: "currentColor",
356
- strokeWidth: "2",
357
- strokeLinecap: "round",
358
- strokeLinejoin: "round",
359
- children: /* @__PURE__ */ jsx2("path", { d: "m18 15-6-6-6 6" })
360
- }
361
- );
362
- }
363
- function ChevronLeft({ className, "aria-hidden": ariaHidden = true }) {
364
- return /* @__PURE__ */ jsx2(
365
- "svg",
366
- {
367
- className,
368
- "aria-hidden": ariaHidden,
369
- width: "16",
370
- height: "16",
371
- viewBox: "0 0 24 24",
372
- fill: "none",
373
- stroke: "currentColor",
374
- strokeWidth: "2",
375
- strokeLinecap: "round",
376
- strokeLinejoin: "round",
377
- children: /* @__PURE__ */ jsx2("path", { d: "m15 18-6-6 6-6" })
378
- }
379
- );
380
- }
381
- function ChevronRight({ className, "aria-hidden": ariaHidden = true }) {
382
- return /* @__PURE__ */ jsx2(
383
- "svg",
384
- {
385
- className,
386
- "aria-hidden": ariaHidden,
387
- width: "16",
388
- height: "16",
389
- viewBox: "0 0 24 24",
390
- fill: "none",
391
- stroke: "currentColor",
392
- strokeWidth: "2",
393
- strokeLinecap: "round",
394
- strokeLinejoin: "round",
395
- children: /* @__PURE__ */ jsx2("path", { d: "m9 18 6-6-6-6" })
396
- }
397
- );
398
- }
399
- function ArrowUp({ className, "aria-hidden": ariaHidden = true }) {
400
- return /* @__PURE__ */ jsxs(
401
- "svg",
402
- {
403
- className,
404
- "aria-hidden": ariaHidden,
405
- width: "14",
406
- height: "14",
407
- viewBox: "0 0 24 24",
408
- fill: "none",
409
- stroke: "currentColor",
410
- strokeWidth: "2",
411
- strokeLinecap: "round",
412
- strokeLinejoin: "round",
413
- children: [
414
- /* @__PURE__ */ jsx2("path", { d: "m18 15-6-6-6 6" }),
415
- /* @__PURE__ */ jsx2("path", { d: "M12 21V9" })
416
- ]
417
- }
418
- );
419
- }
420
- function ArrowDown({ className, "aria-hidden": ariaHidden = true }) {
421
- return /* @__PURE__ */ jsxs(
422
- "svg",
423
- {
424
- className,
425
- "aria-hidden": ariaHidden,
426
- width: "14",
427
- height: "14",
428
- viewBox: "0 0 24 24",
429
- fill: "none",
430
- stroke: "currentColor",
431
- strokeWidth: "2",
432
- strokeLinecap: "round",
433
- strokeLinejoin: "round",
434
- children: [
435
- /* @__PURE__ */ jsx2("path", { d: "m6 9 6 6 6-6" }),
436
- /* @__PURE__ */ jsx2("path", { d: "M12 3v12" })
437
- ]
438
- }
439
- );
440
- }
441
- function ArrowUpDown({ className, "aria-hidden": ariaHidden = true }) {
442
- return /* @__PURE__ */ jsxs(
443
- "svg",
444
- {
445
- className,
446
- "aria-hidden": ariaHidden,
447
- width: "14",
448
- height: "14",
449
- viewBox: "0 0 24 24",
450
- fill: "none",
451
- stroke: "currentColor",
452
- strokeWidth: "2",
453
- strokeLinecap: "round",
454
- strokeLinejoin: "round",
455
- children: [
456
- /* @__PURE__ */ jsx2("path", { d: "m21 16-4 4-4-4" }),
457
- /* @__PURE__ */ jsx2("path", { d: "M17 20V4" }),
458
- /* @__PURE__ */ jsx2("path", { d: "m3 8 4-4 4 4" }),
459
- /* @__PURE__ */ jsx2("path", { d: "M7 4v16" })
460
- ]
461
- }
462
- );
463
- }
464
-
465
- // src/lib/cn.ts
466
- function cn(...inputs) {
467
- return inputs.filter(Boolean).join(" ");
468
- }
469
-
470
- // src/components/ui/table/components/DataTable/DataTableRow.tsx
471
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
472
- function resolveExpandCellIndex(cells, toggleField) {
473
- if (!toggleField) return 0;
474
- const matchedIndex = cells.findIndex(
475
- (cell) => cell.column.id === toggleField
476
- );
477
- if (matchedIndex >= 0) return matchedIndex;
478
- const noColumnIndex = cells.findIndex(
479
- (cell) => cell.column.id === "no" || cell.column.id === "treeNo"
480
- );
481
- if (noColumnIndex >= 0 && noColumnIndex + 1 < cells.length) {
482
- return noColumnIndex + 1;
483
- }
484
- return 0;
485
- }
486
- function DataTableRow({
487
- row,
488
- onToggleSelect,
489
- virtualIndex,
490
- measureElement
491
- }) {
492
- const { rowSpan, selection, cellSelection, cellEdit, expand } = useDataTableRowContext();
493
- const {
494
- enableRowSpan,
495
- primaryRowSpanKey,
496
- columnRowSpanMap,
497
- hoveredRowIndex,
498
- hoveredGroupKey,
499
- selectedGroupKeys,
500
- onRowHover
501
- } = rowSpan;
502
- const { rowSelectionMode, selectOnRowClick, onRowClick, getRowClassName } = selection;
503
- const {
504
- activeSelectionBounds,
505
- dragState,
506
- onCellMouseDown,
507
- onCellMouseEnter,
508
- onFillHandleMouseDown
509
- } = cellSelection;
510
- const {
511
- editingCell,
512
- draftValue,
513
- onDraftValueChange,
514
- onStartEdit,
515
- onCommitEdit,
516
- onCancelEdit
517
- } = cellEdit;
518
- const {
519
- enableExpand,
520
- toggleField,
521
- expandedRows,
522
- preventExpand,
523
- onToggleExpand
524
- } = expand;
525
- const rowIndex = row.index;
526
- const rowData = row.original;
527
- const isRowHovered = hoveredRowIndex === rowIndex;
528
- const isRowSelected = row.getIsSelected();
529
- const rowGroupKey = primaryRowSpanKey !== void 0 && rowData[primaryRowSpanKey] !== null && rowData[primaryRowSpanKey] !== void 0 ? String(rowData[primaryRowSpanKey]) : null;
530
- const isGroupHovered = enableRowSpan && hoveredGroupKey !== null && rowGroupKey === hoveredGroupKey;
531
- const isGroupSelected = enableRowSpan && rowGroupKey !== null && selectedGroupKeys.has(rowGroupKey);
532
- const visibleCells = row.getVisibleCells();
533
- const expandCellIndex = enableExpand ? resolveExpandCellIndex(visibleCells, toggleField) : -1;
534
- const canExpand = enableExpand && !preventExpand && canExpandRow(rowData);
535
- const expandKey = toggleField && rowData[toggleField] !== null && rowData[toggleField] !== void 0 ? String(rowData[toggleField]) : null;
536
- const isExpanded = expandKey !== null && Boolean(expandedRows?.has(expandKey));
537
- const rowLevel = typeof rowData.level === "number" ? rowData.level : 0;
538
- const editInputRef = useRef2(null);
539
- const isRowEditing = editingCell?.rowIndex === rowIndex;
540
- useEffect2(() => {
541
- if (!isRowEditing) return;
542
- editInputRef.current?.focus();
543
- editInputRef.current?.select();
544
- }, [isRowEditing, editingCell?.colIndex]);
545
- return /* @__PURE__ */ jsx3(
546
- "tr",
547
- {
548
- ref: measureElement,
549
- "data-index": virtualIndex,
550
- className: cn(
551
- "DataTableRowJSX",
552
- !enableRowSpan && ROW_HOVER_CLASS,
553
- enableRowSpan && isRowHovered && !isRowSelected && ROW_HOVERED_BG_CLASS,
554
- isRowSelected && "is-selected",
555
- enableExpand && canExpand && "is-expandable",
556
- getRowClassName?.(rowData, rowIndex)
557
- ),
558
- onMouseEnter: () => onRowHover(rowIndex, rowData),
559
- onClick: () => {
560
- if (isRowEditing) return;
561
- onRowClick?.(rowData, rowIndex);
562
- if (rowSelectionMode !== "none" && selectOnRowClick) {
563
- onToggleSelect();
564
- }
565
- },
566
- children: visibleCells.map((cell, cellIndex) => {
567
- const columnId = cell.column.id;
568
- const meta = cell.column.columnDef.meta;
569
- const align = meta?.align ?? "center";
570
- const cellClassName = meta?.className;
571
- const isRowSpanColumn = Boolean(enableRowSpan && meta?.rowSpan);
572
- const isExpandCell = cellIndex === expandCellIndex;
573
- const editable = isColumnEditable(cell.column.columnDef);
574
- const editType = getColumnEditType(cell.column.columnDef);
575
- let rowSpanInfo;
576
- if (isRowSpanColumn) {
577
- rowSpanInfo = columnRowSpanMap.get(columnId)?.[rowIndex];
578
- if (rowSpanInfo && rowSpanInfo.rowSpan === 0) {
579
- return null;
580
- }
581
- }
582
- const isEditing = editingCell?.rowIndex === rowIndex && editingCell?.colIndex === cellIndex;
583
- const showCellHover = isRowSpanColumn ? isGroupHovered : isRowHovered;
584
- const showCellSelected = isRowSpanColumn ? isGroupSelected : isRowSelected;
585
- const cellRowSpan = rowSpanInfo?.rowSpan ?? 1;
586
- const isCellDragSelected = isCellInSelection(
587
- rowIndex,
588
- cellIndex,
589
- activeSelectionBounds,
590
- cellRowSpan
591
- );
592
- const isBottomRightCell = !isEditing && activeSelectionBounds && !dragState.isSelecting && activeSelectionBounds.endRow >= rowIndex && activeSelectionBounds.endRow <= rowIndex + cellRowSpan - 1 && cellIndex === activeSelectionBounds.endCol;
593
- const resolveCellRowIndex = (clientY, element) => getRowIndexInMergedCell(clientY, element, rowIndex, cellRowSpan);
594
- return /* @__PURE__ */ jsxs2(
595
- "td",
596
- {
597
- rowSpan: rowSpanInfo && rowSpanInfo.rowSpan > 1 ? rowSpanInfo.rowSpan : void 0,
598
- onMouseDown: (event) => {
599
- if (isEditing) {
600
- event.stopPropagation();
601
- return;
602
- }
603
- event.preventDefault();
604
- onCellMouseDown(
605
- resolveCellRowIndex(event.clientY, event.currentTarget),
606
- cellIndex
607
- );
608
- },
609
- onMouseEnter: (event) => onCellMouseEnter(
610
- resolveCellRowIndex(event.clientY, event.currentTarget),
611
- cellIndex
612
- ),
613
- onMouseMove: (event) => {
614
- if (!dragState.isSelecting && !dragState.isFillDragging) return;
615
- onCellMouseEnter(
616
- resolveCellRowIndex(event.clientY, event.currentTarget),
617
- cellIndex
618
- );
619
- },
620
- onDoubleClick: (event) => {
621
- if (!editable) return;
622
- event.preventDefault();
623
- event.stopPropagation();
624
- onStartEdit(rowIndex, cellIndex);
625
- },
626
- style: getCellSelectionEdgeStyle(
627
- rowIndex,
628
- cellIndex,
629
- activeSelectionBounds,
630
- cellRowSpan
631
- ),
632
- className: cn(
633
- "data-table-cell",
634
- CELL_ALIGN_CLASS[align],
635
- cellClassName,
636
- enableRowSpan && showCellSelected && "is-group-selected",
637
- enableRowSpan && showCellHover && !showCellSelected && "is-group-hovered",
638
- isCellDragSelected && CELL_SELECTION_FILL_CLASS,
639
- editable && "is-editable"
640
- ),
641
- children: [
642
- isEditing ? /* @__PURE__ */ jsx3(
643
- "input",
644
- {
645
- ref: editInputRef,
646
- type: editType === "number" ? "number" : "text",
647
- defaultValue: draftValue,
648
- className: cn("cell-edit-input", CELL_ALIGN_CLASS[align]),
649
- onChange: (event) => onDraftValueChange(event.target.value),
650
- onMouseDown: (event) => event.stopPropagation(),
651
- onClick: (event) => event.stopPropagation(),
652
- onKeyDown: (event) => {
653
- if (event.key === "Enter") {
654
- event.preventDefault();
655
- onCommitEdit(event.currentTarget.value);
656
- }
657
- if (event.key === "Escape") {
658
- event.preventDefault();
659
- onCancelEdit();
660
- }
661
- },
662
- onBlur: (event) => {
663
- onCommitEdit(event.currentTarget.value);
664
- }
665
- }
666
- ) : isExpandCell && enableExpand ? /* @__PURE__ */ jsxs2("div", { className: "expand-cell", children: [
667
- /* @__PURE__ */ jsxs2("div", { className: "expand-cell-content", children: [
668
- rowLevel > 0 && /* @__PURE__ */ jsx3("span", { className: "expand-cell-indent", children: "\xB7" }),
669
- /* @__PURE__ */ jsx3("div", { className: "expand-cell-value", children: flexRender(cell.column.columnDef.cell, cell.getContext()) })
670
- ] }),
671
- canExpand && expandKey && /* @__PURE__ */ jsx3(
672
- "button",
673
- {
674
- type: "button",
675
- "aria-label": isExpanded ? "\uD589 \uC811\uAE30" : "\uD589 \uD3BC\uCE58\uAE30",
676
- className: "expand-toggle-button",
677
- onClick: (event) => {
678
- event.stopPropagation();
679
- onToggleExpand?.(expandKey);
680
- },
681
- onMouseDown: (event) => event.stopPropagation(),
682
- children: isExpanded ? /* @__PURE__ */ jsx3(ChevronUp, { className: "expand-toggle-icon" }) : /* @__PURE__ */ jsx3(ChevronDown, { className: "expand-toggle-icon" })
683
- }
684
- )
685
- ] }) : flexRender(cell.column.columnDef.cell, cell.getContext()),
686
- isBottomRightCell && /* @__PURE__ */ jsx3(
687
- "div",
688
- {
689
- role: "presentation",
690
- className: "fill-handle",
691
- onMouseDown: (event) => {
692
- event.stopPropagation();
693
- event.preventDefault();
694
- onFillHandleMouseDown(rowIndex, cellIndex);
695
- }
696
- }
697
- )
698
- ]
699
- },
700
- cell.id
701
- );
702
- })
703
- }
704
- );
705
- }
706
-
707
- // src/components/ui/table/components/DataTable/DataTableToolbar.tsx
708
- import { Fragment, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
709
- function DefaultSelectionLabel({ selectedCount }) {
710
- if (selectedCount <= 0) return null;
711
- return /* @__PURE__ */ jsxs3("span", { className: "toolbar-selection", children: [
712
- "\u2713 ",
713
- selectedCount,
714
- "\uAC1C \uC120\uD0DD\uB428"
715
- ] });
716
- }
717
- function DataTableToolbar({
718
- filteredCount,
719
- totalCount,
720
- summary,
721
- selectedCount,
722
- selectionLabel,
723
- toolbar,
724
- className
725
- }) {
726
- const displayFiltered = filteredCount ?? totalCount;
727
- const hasCount = displayFiltered !== void 0 || totalCount !== void 0;
728
- const hasLeftContent = hasCount || Boolean(summary);
729
- const hasToolbar = Boolean(toolbar);
730
- const selectionContent = selectionLabel ? selectionLabel(selectedCount) : /* @__PURE__ */ jsx4(DefaultSelectionLabel, { selectedCount });
731
- const hasSelectionContent = selectionContent !== null && selectionContent !== false;
732
- if (!hasLeftContent && !hasToolbar && !hasSelectionContent) return null;
733
- return /* @__PURE__ */ jsxs3("div", { className: cn("DataTableToolbarJSX", className), children: [
734
- /* @__PURE__ */ jsxs3("div", { className: "toolbar-left", children: [
735
- hasCount && /* @__PURE__ */ jsx4("span", { className: "toolbar-count", children: displayFiltered !== void 0 && totalCount !== void 0 ? /* @__PURE__ */ jsxs3(Fragment, { children: [
736
- /* @__PURE__ */ jsx4("span", { className: "toolbar-count-primary", children: displayFiltered }),
737
- /* @__PURE__ */ jsxs3("span", { className: "toolbar-count-placeholder", children: [
738
- " / ",
739
- totalCount
740
- ] })
741
- ] }) : /* @__PURE__ */ jsx4("span", { className: "toolbar-count-primary", children: displayFiltered ?? totalCount }) }),
742
- summary
743
- ] }),
744
- /* @__PURE__ */ jsxs3("div", { className: "toolbar-right", children: [
745
- selectionContent,
746
- hasToolbar && /* @__PURE__ */ jsx4("div", { className: "toolbar-actions", children: toolbar })
747
- ] })
748
- ] });
749
- }
750
-
751
- // src/components/ui/table/features/cell-edit/useCellEdit.ts
752
- import { useCallback, useEffect as useEffect3, useRef as useRef3, useState } from "react";
753
- function useCellEdit({
754
- data,
755
- rows,
756
- onDataChange
757
- }) {
758
- const [editingCell, setEditingCell] = useState(null);
759
- const [draftValue, setDraftValue] = useState("");
760
- const draftValueRef = useRef3(draftValue);
761
- const editingCellRef = useRef3(editingCell);
762
- useEffect3(() => {
763
- draftValueRef.current = draftValue;
764
- }, [draftValue]);
765
- useEffect3(() => {
766
- editingCellRef.current = editingCell;
767
- }, [editingCell]);
768
- const cancelEdit = useCallback(() => {
769
- setEditingCell(null);
770
- setDraftValue("");
771
- }, []);
772
- const commitEdit = useCallback(
773
- (raw) => {
774
- const current = editingCellRef.current;
775
- if (!current) return true;
776
- if (!onDataChange) {
777
- cancelEdit();
778
- return true;
779
- }
780
- const value = raw ?? draftValueRef.current;
781
- const next = applyCellEdit(data, rows, current.rowIndex, current.colIndex, value);
782
- if (!next) return false;
783
- onDataChange(next);
784
- cancelEdit();
785
- return true;
786
- },
787
- [cancelEdit, data, onDataChange, rows]
788
- );
789
- const startEdit = useCallback(
790
- (rowIndex, colIndex) => {
791
- const cell = rows[rowIndex]?.getVisibleCells()[colIndex];
792
- if (!cell || !isColumnEditable(cell.column.columnDef)) return;
793
- const current = editingCellRef.current;
794
- if (current && (current.rowIndex !== rowIndex || current.colIndex !== colIndex) && !commitEdit()) {
795
- return;
796
- }
797
- setEditingCell({ rowIndex, colIndex });
798
- setDraftValue(getCellEditDraftValue(cell.getValue()));
799
- },
800
- [commitEdit, rows]
801
- );
802
- return {
803
- editingCell,
804
- draftValue,
805
- setDraftValue,
806
- startEdit,
807
- commitEdit,
808
- cancelEdit
809
- };
810
- }
811
-
812
- // src/components/ui/table/features/cell-selection/useCellSelection.ts
813
- import { useCallback as useCallback2, useEffect as useEffect4, useState as useState2 } from "react";
814
-
815
- // src/components/ui/table/features/cell-selection/fillData.ts
816
- function getColumnAccessorKey2(columnDef) {
817
- if ("accessorKey" in columnDef && columnDef.accessorKey) {
818
- return String(columnDef.accessorKey);
819
- }
820
- return columnDef.id;
821
- }
822
- function applyFillData(data, rows, sourceBounds, fillBounds) {
823
- const newData = data.map((row) => ({ ...row }));
824
- const sourceHeight = sourceBounds.endRow - sourceBounds.startRow + 1;
825
- const sourceWidth = sourceBounds.endCol - sourceBounds.startCol + 1;
826
- for (let rowIndex = fillBounds.startRow; rowIndex <= fillBounds.endRow; rowIndex += 1) {
827
- for (let colIndex = fillBounds.startCol; colIndex <= fillBounds.endCol; colIndex += 1) {
828
- if (isCellInSelection(rowIndex, colIndex, sourceBounds)) continue;
829
- const offsetRow = rowIndex - sourceBounds.startRow;
830
- const offsetCol = colIndex - sourceBounds.startCol;
831
- const sourceRowIndex = sourceBounds.startRow + (offsetRow % sourceHeight + sourceHeight) % sourceHeight;
832
- const sourceColIndex = sourceBounds.startCol + (offsetCol % sourceWidth + sourceWidth) % sourceWidth;
833
- const targetCell = rows[rowIndex]?.getVisibleCells()[colIndex];
834
- const sourceCell = rows[sourceRowIndex]?.getVisibleCells()[sourceColIndex];
835
- if (!targetCell || !sourceCell) continue;
836
- const accessorKey = getColumnAccessorKey2(
837
- targetCell.column.columnDef
838
- );
839
- if (!accessorKey) continue;
840
- newData[rowIndex][accessorKey] = sourceCell.getValue();
841
- }
842
- }
843
- return newData;
844
- }
845
- function hasFillExtension(sourceBounds, fillBounds) {
846
- if (!sourceBounds) return false;
847
- return fillBounds.startRow < sourceBounds.startRow || fillBounds.endRow > sourceBounds.endRow || fillBounds.startCol < sourceBounds.startCol || fillBounds.endCol > sourceBounds.endCol;
848
- }
849
-
850
- // src/components/ui/table/features/cell-selection/useCellSelection.ts
851
- function useCellSelection({
852
- data,
853
- rows,
854
- onDataChange
855
- }) {
856
- const [dragState, setDragState] = useState2(INITIAL_DRAG_STATE);
857
- const cellSelectionBounds = getCellSelectionBounds(dragState.start, dragState.end);
858
- const activeSelectionBounds = getActiveSelectionBounds(dragState, cellSelectionBounds);
859
- const handleCellMouseDown = useCallback2((rowIndex, colIndex) => {
860
- setDragState({
861
- isSelecting: true,
862
- isFillDragging: false,
863
- start: { row: rowIndex, col: colIndex },
864
- end: { row: rowIndex, col: colIndex },
865
- fillAnchor: null,
866
- fillEnd: null
867
- });
868
- }, []);
869
- const handleCellMouseEnter = useCallback2((rowIndex, colIndex) => {
870
- setDragState((prev) => {
871
- if (prev.isSelecting) {
872
- return { ...prev, end: { row: rowIndex, col: colIndex } };
873
- }
874
- if (prev.isFillDragging) {
875
- return { ...prev, fillEnd: { row: rowIndex, col: colIndex } };
621
+ flattenedData.push(newItem);
622
+ }
623
+ });
624
+ };
625
+ flattenItems(data);
626
+ const dataWithLevels = flattenedData.map((item) => ({
627
+ ...item,
628
+ level: 0,
629
+ children: [],
630
+ processed: false
631
+ }));
632
+ const itemMap = /* @__PURE__ */ new Map();
633
+ dataWithLevels.forEach((item) => {
634
+ const key = getFieldValue(item, toggleField);
635
+ if (typeof key !== "string" || !key) return;
636
+ if (!itemMap.has(key)) {
637
+ itemMap.set(key, []);
876
638
  }
877
- return prev;
878
- });
879
- }, []);
880
- const handleFillHandleMouseDown = useCallback2((rowIndex, colIndex) => {
881
- setDragState((prev) => {
882
- const bounds = getCellSelectionBounds(prev.start, prev.end);
883
- if (!bounds) return prev;
884
- return {
885
- ...prev,
886
- isSelecting: false,
887
- isFillDragging: true,
888
- fillAnchor: { row: bounds.startRow, col: bounds.startCol },
889
- fillEnd: { row: rowIndex, col: colIndex }
890
- };
639
+ itemMap.get(key)?.push(item);
891
640
  });
892
- }, []);
893
- useEffect4(() => {
894
- const handleKeyDown = (e) => {
895
- if ((e.ctrlKey || e.metaKey) && e.key === "c" && activeSelectionBounds) {
896
- const { startRow, endRow, startCol, endCol } = activeSelectionBounds;
897
- const selectedData = rows.slice(startRow, endRow + 1).map((row) => {
898
- const cells = row.getVisibleCells();
899
- return cells.slice(startCol, endCol + 1).map((cell) => cell.getValue()).join(" ");
900
- }).join("\n");
901
- navigator.clipboard.writeText(selectedData);
641
+ const rootItems = [];
642
+ dataWithLevels.forEach((item) => {
643
+ if (!getFieldValue(item, childField)) {
644
+ rootItems.push(item);
645
+ item.processed = true;
902
646
  }
903
- };
904
- window.addEventListener("keydown", handleKeyDown);
905
- return () => window.removeEventListener("keydown", handleKeyDown);
906
- }, [activeSelectionBounds, rows]);
907
- useEffect4(() => {
908
- const handleMouseUp = () => {
909
- setDragState((prev) => {
910
- if (prev.isFillDragging && prev.fillAnchor && prev.fillEnd) {
911
- const sourceBounds = getCellSelectionBounds(prev.start, prev.end);
912
- const newBounds = getCellSelectionBounds(prev.fillAnchor, prev.fillEnd);
913
- if (newBounds) {
914
- if (hasFillExtension(sourceBounds, newBounds) && sourceBounds && onDataChange) {
915
- onDataChange(applyFillData(data, rows, sourceBounds, newBounds));
916
- }
917
- return {
918
- isSelecting: false,
919
- isFillDragging: false,
920
- start: { row: newBounds.startRow, col: newBounds.startCol },
921
- end: { row: newBounds.endRow, col: newBounds.endCol },
922
- fillAnchor: null,
923
- fillEnd: null
924
- };
925
- }
926
- }
927
- if (prev.isSelecting) {
928
- return { ...prev, isSelecting: false };
647
+ });
648
+ dataWithLevels.forEach((item) => {
649
+ const parentKey = getFieldValue(item, childField);
650
+ if (!parentKey || item.processed) return;
651
+ const parentItems = dataWithLevels.filter(
652
+ (parent) => getFieldValue(parent, toggleField) === parentKey && !getFieldValue(parent, childField)
653
+ );
654
+ if (parentItems.length > 0) {
655
+ const parent = parentItems[0];
656
+ item.level = parent.level + 1;
657
+ parent.children.push(item);
658
+ item.processed = true;
659
+ } else {
660
+ const otherParents = itemMap.get(String(parentKey)) || [];
661
+ if (otherParents.length > 0) {
662
+ const parent = otherParents[0];
663
+ item.level = parent.level + 1;
664
+ parent.children.push(item);
665
+ item.processed = true;
666
+ } else {
667
+ rootItems.push(item);
668
+ item.processed = true;
929
669
  }
930
- if (prev.isFillDragging) {
931
- return { ...prev, isFillDragging: false, fillAnchor: null, fillEnd: null };
670
+ }
671
+ });
672
+ return rootItems;
673
+ }, [enabled, data, toggleField, childField, flattenField]);
674
+ const flattenTree = useMemo(() => {
675
+ if (!enabled) return [];
676
+ const flatten = (nodes, result = [], level = 0) => {
677
+ nodes.forEach((node, index) => {
678
+ const currentIndex = level === 0 ? `${index + startIndex}` : `${level}-${index + 1}`;
679
+ const toggleValue = getFieldValue(node, toggleField);
680
+ const uniqueId = `${index}-${String(toggleValue ?? "")}`;
681
+ result.push({
682
+ ...node,
683
+ treeNo: currentIndex,
684
+ uniqueId,
685
+ processed: true
686
+ });
687
+ const shouldExpandChildren = node.children.length > 0 && (preventExpand || typeof toggleValue === "string" && expandedRows?.has(toggleValue));
688
+ if (shouldExpandChildren) {
689
+ flatten(node.children, result, index + startIndex);
932
690
  }
933
- return prev;
934
691
  });
692
+ return result;
935
693
  };
936
- window.addEventListener("mouseup", handleMouseUp);
937
- return () => window.removeEventListener("mouseup", handleMouseUp);
938
- }, [data, onDataChange, rows]);
939
- return {
940
- dragState,
941
- activeSelectionBounds,
942
- handleCellMouseDown,
943
- handleCellMouseEnter,
944
- handleFillHandleMouseDown
945
- };
946
- }
694
+ const flattenedData = flatten(processedData, [], 0);
695
+ flattenedData.forEach((item) => {
696
+ if (getFieldValue(item, childField)) {
697
+ const parentItem = flattenedData.find(
698
+ (parent) => getFieldValue(parent, toggleField) === getFieldValue(item, childField)
699
+ );
700
+ const parentAmount = parentItem ? Number(getFieldValue(parentItem, qtyField) ?? 1) : 1;
701
+ item.parentCount = parentAmount || 1;
702
+ } else {
703
+ item.parentCount = 1;
704
+ }
705
+ });
706
+ return flattenedData;
707
+ }, [
708
+ enabled,
709
+ processedData,
710
+ startIndex,
711
+ toggleField,
712
+ childField,
713
+ qtyField,
714
+ preventExpand,
715
+ expandedRows
716
+ ]);
717
+ const sortedData = useMemo(() => {
718
+ if (!enabled) {
719
+ return data ?? [];
720
+ }
721
+ return [...flattenTree].sort((a, b) => {
722
+ const aParts = String(a.treeNo ?? "").split("-").map(Number);
723
+ const bParts = String(b.treeNo ?? "").split("-").map(Number);
724
+ for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) {
725
+ const aVal = aParts[i] || 0;
726
+ const bVal = bParts[i] || 0;
727
+ if (aVal !== bVal) {
728
+ return aVal - bVal;
729
+ }
730
+ }
731
+ return 0;
732
+ });
733
+ }, [enabled, data, flattenTree]);
734
+ return sortedData;
735
+ };
947
736
 
948
737
  // src/components/ui/table/features/row-selection/rowSelection.ts
949
738
  function resolveRowSelection(mode, controlledSelection, internalSelection) {
@@ -986,6 +775,22 @@ function computeRowSpans(data, rowSpanKey) {
986
775
  }
987
776
  return result;
988
777
  }
778
+ function resolveRowSpanAt(rowSpans, rowIndex) {
779
+ if (!rowSpans?.[rowIndex]) {
780
+ return { startRow: rowIndex, rowSpan: 1 };
781
+ }
782
+ const current = rowSpans[rowIndex];
783
+ if (current.rowSpan > 0) {
784
+ return { startRow: rowIndex, rowSpan: current.rowSpan };
785
+ }
786
+ for (let row = rowIndex - 1; row >= 0; row--) {
787
+ const info = rowSpans[row];
788
+ if (info && info.rowSpan > 0) {
789
+ return { startRow: row, rowSpan: info.rowSpan };
790
+ }
791
+ }
792
+ return { startRow: rowIndex, rowSpan: 1 };
793
+ }
989
794
  function buildColumnRowSpanMap(data, columnKeys) {
990
795
  const map = /* @__PURE__ */ new Map();
991
796
  for (const { columnId, rowSpanKey } of columnKeys) {
@@ -1013,51 +818,62 @@ function collectRowSpanColumns(columns) {
1013
818
  return result;
1014
819
  }
1015
820
 
1016
- // src/components/ui/table/components/DataTable/DataTable.tsx
1017
- import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
1018
- function DataTable({
1019
- data,
1020
- columns,
1021
- rowSelectionMode = "none",
1022
- rowSelection: controlledRowSelection,
1023
- onRowSelectionChange,
1024
- totalCount,
1025
- filteredCount,
1026
- summary,
1027
- toolbar,
1028
- selectionLabel,
1029
- isPending = false,
1030
- emptyText = "\uB370\uC774\uD130\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
1031
- enableRowSpan = false,
1032
- getRowId,
1033
- onRowClick,
1034
- getRowClassName,
1035
- getRowCanSelect,
1036
- selectOnRowClick = true,
1037
- onDataChange,
1038
- className,
1039
- preserveRowSelection = false,
1040
- toggleField,
1041
- childField,
1042
- flattenField,
1043
- expandedRows: controlledExpandedRows,
1044
- onExpandedRowsChange,
1045
- preventExpand = false,
1046
- enableVirtualization = true,
1047
- estimateRowHeight = DATA_TABLE_ROW_HEIGHT,
1048
- virtualOverscan = DATA_TABLE_VIRTUAL_OVERSCAN
1049
- }) {
821
+ // src/core/useGlideTable.ts
822
+ function useGlideTable(options) {
823
+ const {
824
+ data,
825
+ columns,
826
+ rowSelectionMode = "none",
827
+ rowSelection: controlledRowSelection,
828
+ onRowSelectionChange,
829
+ selectionLabel,
830
+ emptyText,
831
+ loadingText,
832
+ labels: labelsProp,
833
+ enableRowSpan = false,
834
+ getRowId,
835
+ onRowClick,
836
+ getRowClassName,
837
+ getRowCanSelect,
838
+ selectOnRowClick = true,
839
+ enableCellSelection = true,
840
+ onDataChange,
841
+ onCellChange,
842
+ onBatchChange,
843
+ preserveRowSelection = false,
844
+ toggleField,
845
+ childField,
846
+ flattenField,
847
+ qtyField,
848
+ expandedRows: controlledExpandedRows,
849
+ onExpandedRowsChange,
850
+ preventExpand = false,
851
+ enableVirtualization = true,
852
+ estimateRowHeight = DATA_TABLE_ROW_HEIGHT,
853
+ virtualOverscan = DATA_TABLE_VIRTUAL_OVERSCAN
854
+ } = options;
855
+ const labels = useMemo2(() => {
856
+ const resolved = resolveDataTableLabels(labelsProp);
857
+ return {
858
+ ...resolved,
859
+ empty: labelsProp?.empty ?? emptyText ?? resolved.empty,
860
+ loading: labelsProp?.loading ?? loadingText ?? resolved.loading,
861
+ selection: labelsProp?.selection ?? selectionLabel ?? resolved.selection
862
+ };
863
+ }, [labelsProp, emptyText, loadingText, selectionLabel]);
1050
864
  const enableExpand = Boolean(toggleField);
1051
865
  const [internalRowSelection, setInternalRowSelection] = useState3({});
1052
- const [internalExpandedRows, setInternalExpandedRows] = useState3(() => /* @__PURE__ */ new Set());
866
+ const [internalExpandedRows, setInternalExpandedRows] = useState3(
867
+ () => /* @__PURE__ */ new Set()
868
+ );
1053
869
  const [hoveredRowIndex, setHoveredRowIndex] = useState3(null);
1054
870
  const [hoveredGroupKey, setHoveredGroupKey] = useState3(null);
1055
- const scrollRef = useRef4(null);
871
+ const scrollRef = useRef3(null);
1056
872
  const shouldVirtualize = enableVirtualization && !enableRowSpan;
1057
- useEffect5(() => {
873
+ useEffect4(() => {
1058
874
  if (enableVirtualization && enableRowSpan) {
1059
875
  console.warn(
1060
- "[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."
876
+ "[useGlideTable] enableRowSpan is on; virtualization is disabled to preserve cell merges."
1061
877
  );
1062
878
  }
1063
879
  }, [enableVirtualization, enableRowSpan]);
@@ -1083,6 +899,7 @@ function DataTable({
1083
899
  toggleField,
1084
900
  childField,
1085
901
  flattenField,
902
+ qtyField,
1086
903
  expandedRows,
1087
904
  onExpandedRowsChange: enableExpand ? handleExpandedRowsChange : void 0,
1088
905
  preventExpand
@@ -1147,10 +964,21 @@ function DataTable({
1147
964
  handleCellMouseDown,
1148
965
  handleCellMouseEnter,
1149
966
  handleFillHandleMouseDown
1150
- } = useCellSelection({ data: tableData, rows, onDataChange });
1151
- const { editingCell, draftValue, setDraftValue, startEdit, commitEdit, cancelEdit } = useCellEdit(
1152
- { data: tableData, rows, onDataChange }
1153
- );
967
+ } = useCellSelection({
968
+ data: tableData,
969
+ rows,
970
+ enabled: enableCellSelection,
971
+ onDataChange,
972
+ onBatchChange
973
+ });
974
+ const {
975
+ editingCell,
976
+ draftValue,
977
+ setDraftValue,
978
+ startEdit,
979
+ commitEdit,
980
+ cancelEdit
981
+ } = useCellEdit({ data: tableData, rows, onDataChange, onCellChange });
1154
982
  const handleCellMouseDownWithCommit = useCallback3(
1155
983
  (rowIndex, colIndex) => {
1156
984
  const isSameEditingCell = editingCell?.rowIndex === rowIndex && editingCell?.colIndex === colIndex;
@@ -1161,10 +989,10 @@ function DataTable({
1161
989
  },
1162
990
  [commitEdit, editingCell, handleCellMouseDown]
1163
991
  );
1164
- const clearHover = () => {
992
+ const clearHover = useCallback3(() => {
1165
993
  setHoveredRowIndex(null);
1166
994
  setHoveredGroupKey(null);
1167
- };
995
+ }, []);
1168
996
  const handleRowHover = useCallback3(
1169
997
  (rowIndex, rowData) => {
1170
998
  setHoveredRowIndex(rowIndex);
@@ -1214,6 +1042,7 @@ function DataTable({
1214
1042
  getRowClassName
1215
1043
  },
1216
1044
  cellSelection: {
1045
+ enableCellSelection,
1217
1046
  activeSelectionBounds,
1218
1047
  dragState,
1219
1048
  onCellMouseDown: handleCellMouseDownWithCommit,
@@ -1233,7 +1062,9 @@ function DataTable({
1233
1062
  toggleField,
1234
1063
  expandedRows,
1235
1064
  preventExpand,
1236
- onToggleExpand: handleToggleExpand
1065
+ onToggleExpand: handleToggleExpand,
1066
+ expandRowLabel: labels.expandRow,
1067
+ collapseRowLabel: labels.collapseRow
1237
1068
  }
1238
1069
  };
1239
1070
  }, [
@@ -1248,6 +1079,7 @@ function DataTable({
1248
1079
  selectOnRowClick,
1249
1080
  onRowClick,
1250
1081
  getRowClassName,
1082
+ enableCellSelection,
1251
1083
  activeSelectionBounds,
1252
1084
  dragState,
1253
1085
  handleCellMouseDownWithCommit,
@@ -1263,404 +1095,60 @@ function DataTable({
1263
1095
  toggleField,
1264
1096
  expandedRows,
1265
1097
  preventExpand,
1266
- handleToggleExpand
1098
+ handleToggleExpand,
1099
+ labels.expandRow,
1100
+ labels.collapseRow
1267
1101
  ]);
1268
- if (isPending) {
1269
- return /* @__PURE__ */ jsx5("div", { className: cn("DataTableJSX", "DataTableJSX--pending", className), children: /* @__PURE__ */ jsx5("span", { className: "data-table-loading-text", children: "\uB85C\uB529 \uC911..." }) });
1270
- }
1271
- return /* @__PURE__ */ jsxs4("div", { className: cn("DataTableJSX", className), children: [
1272
- /* @__PURE__ */ jsx5(
1273
- DataTableToolbar,
1274
- {
1275
- filteredCount: filteredCount ?? tableData.length,
1276
- totalCount,
1277
- summary,
1278
- selectedCount,
1279
- selectionLabel,
1280
- toolbar
1281
- }
1282
- ),
1283
- /* @__PURE__ */ jsx5("div", { ref: scrollRef, className: "data-table-scroll", children: /* @__PURE__ */ jsxs4(
1284
- "table",
1285
- {
1286
- className: "data-table",
1287
- onDragStart: (event) => event.preventDefault(),
1288
- children: [
1289
- /* @__PURE__ */ jsx5("thead", { className: "data-table-head", children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsx5("tr", { className: "data-table-head-row", children: headerGroup.headers.map((header) => {
1290
- const align = header.column.columnDef.meta?.align ?? "center";
1291
- const headerClassName = header.column.columnDef.meta?.headerClassName;
1292
- return /* @__PURE__ */ jsx5(
1293
- "th",
1294
- {
1295
- style: { width: header.getSize() !== 150 ? header.getSize() : void 0 },
1296
- className: cn(
1297
- "data-table-head-cell",
1298
- CELL_ALIGN_CLASS[align],
1299
- headerClassName
1300
- ),
1301
- children: header.isPlaceholder ? null : flexRender2(header.column.columnDef.header, header.getContext())
1302
- },
1303
- header.id
1304
- );
1305
- }) }, headerGroup.id)) }),
1306
- /* @__PURE__ */ jsx5(DataTableContextProvider, { value: rowContextValue, children: /* @__PURE__ */ jsx5("tbody", { onMouseLeave: clearHover, className: "data-table-body", children: rows.length === 0 ? /* @__PURE__ */ jsx5("tr", { children: /* @__PURE__ */ jsx5("td", { colSpan: columnCount, className: "data-table-empty-cell", children: emptyText }) }) : shouldVirtualize ? /* @__PURE__ */ jsxs4(Fragment2, { children: [
1307
- paddingTop > 0 && /* @__PURE__ */ jsx5("tr", { "aria-hidden": true, className: "data-table-virtual-spacer", children: /* @__PURE__ */ jsx5(
1308
- "td",
1309
- {
1310
- colSpan: columnCount,
1311
- style: { height: paddingTop },
1312
- className: "data-table-virtual-spacer-cell"
1313
- }
1314
- ) }),
1315
- virtualRows.map((virtualRow) => {
1316
- const row = rows[virtualRow.index];
1317
- if (!row) return null;
1318
- return /* @__PURE__ */ jsx5(
1319
- DataTableRow,
1320
- {
1321
- row,
1322
- virtualIndex: virtualRow.index,
1323
- measureElement: rowVirtualizer.measureElement,
1324
- onToggleSelect: () => handleToggleSelect(row)
1325
- },
1326
- row.id
1327
- );
1328
- }),
1329
- paddingBottom > 0 && /* @__PURE__ */ jsx5("tr", { "aria-hidden": true, className: "data-table-virtual-spacer", children: /* @__PURE__ */ jsx5(
1330
- "td",
1331
- {
1332
- colSpan: columnCount,
1333
- style: { height: paddingBottom },
1334
- className: "data-table-virtual-spacer-cell"
1335
- }
1336
- ) })
1337
- ] }) : rows.map((row) => /* @__PURE__ */ jsx5(
1338
- DataTableRow,
1339
- {
1340
- row,
1341
- onToggleSelect: () => handleToggleSelect(row)
1342
- },
1343
- row.id
1344
- )) }) })
1345
- ]
1346
- }
1347
- ) })
1348
- ] });
1349
- }
1350
-
1351
- // src/components/ui/table/components/Table/Table.tsx
1352
- import { useCallback as useCallback4, useMemo as useMemo3, useState as useState4 } from "react";
1353
-
1354
- // src/components/ui/table/components/Table/buildColumnDef.tsx
1355
- import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1356
- function SortableHeader({
1357
- label,
1358
- field,
1359
- sort,
1360
- onSort
1361
- }) {
1362
- const isActive = sort?.field === field;
1363
- const Icon = isActive ? sort.direction === "asc" ? ArrowUp : ArrowDown : ArrowUpDown;
1364
- return /* @__PURE__ */ jsxs5(
1365
- "button",
1366
- {
1367
- type: "button",
1368
- className: cn("SortableHeaderJSX", isActive ? "is-active" : "is-inactive"),
1369
- onClick: () => onSort(field),
1370
- children: [
1371
- /* @__PURE__ */ jsx6("span", { children: label }),
1372
- /* @__PURE__ */ jsx6(Icon, { className: "sortable-header-icon" })
1373
- ]
1374
- }
1375
- );
1376
- }
1377
- function buildColumnDef(props, sort, onSort) {
1378
- const {
1379
- field,
1380
- virtual = false,
1381
- children,
1382
- sortable = false,
1383
- width,
1384
- align,
1385
- rowSpan,
1386
- rowSpanKey,
1387
- editable,
1388
- editType,
1389
- className,
1390
- headerClassName,
1391
- render
1392
- } = props;
1393
1102
  return {
1394
- id: field,
1395
- ...!virtual ? { accessorKey: field } : {},
1396
- size: width ?? 150,
1397
- header: sortable ? () => /* @__PURE__ */ jsx6(SortableHeader, { label: children, field, sort, onSort }) : (
1398
- // eslint-disable-next-line @typescript-eslint/promise-function-async
1399
- () => children
1400
- ),
1401
- ...render ? {
1402
- // eslint-disable-next-line @typescript-eslint/promise-function-async
1403
- cell: ({ row, getValue }) => render(
1404
- getValue(),
1405
- row,
1406
- row.index
1407
- )
1408
- } : {},
1409
- meta: {
1410
- align,
1411
- rowSpan,
1412
- rowSpanKey,
1413
- editable,
1414
- editType,
1415
- className,
1416
- headerClassName
1417
- }
1418
- };
1419
- }
1420
-
1421
- // src/components/ui/table/components/Table/parseTableChildren.ts
1422
- import { Children } from "react";
1423
-
1424
- // src/components/ui/table/components/Table/tableChildTypes.ts
1425
- import { isValidElement } from "react";
1426
- var TABLE_HEADER_DISPLAY_NAME = "Table.Header";
1427
- var TABLE_BODY_DISPLAY_NAME = "Table.Body";
1428
- var TABLE_COLUMN_DISPLAY_NAME = "Table.Column";
1429
- var TABLE_PAGINATION_DISPLAY_NAME = "Table.Pagination";
1430
- function getComponentDisplayName(type) {
1431
- if (typeof type === "function" || typeof type === "object" && type !== null) {
1432
- return type.displayName;
1433
- }
1434
- return void 0;
1435
- }
1436
- function isTableHeaderElement(child) {
1437
- return isValidElement(child) && getComponentDisplayName(child.type) === TABLE_HEADER_DISPLAY_NAME;
1438
- }
1439
- function isTableBodyElement(child) {
1440
- return isValidElement(child) && getComponentDisplayName(child.type) === TABLE_BODY_DISPLAY_NAME;
1441
- }
1442
- function isTableColumnElement(child) {
1443
- return isValidElement(child) && getComponentDisplayName(child.type) === TABLE_COLUMN_DISPLAY_NAME;
1444
- }
1445
- function isTablePaginationElement(child) {
1446
- return isValidElement(child) && getComponentDisplayName(child.type) === TABLE_PAGINATION_DISPLAY_NAME;
1447
- }
1448
-
1449
- // src/components/ui/table/components/Table/parseTableChildren.ts
1450
- function parseTableChildren(children) {
1451
- const slots = {
1452
- header: null,
1453
- body: null,
1454
- pagination: null
1103
+ table,
1104
+ tableData,
1105
+ rows,
1106
+ columnCount,
1107
+ selectedCount,
1108
+ labels,
1109
+ emptyText: labels.empty,
1110
+ loadingText: labels.loading,
1111
+ selectionLabel: labels.selection,
1112
+ enableCellSelection,
1113
+ shouldVirtualize,
1114
+ scrollRef,
1115
+ rowVirtualizer,
1116
+ virtualRows,
1117
+ paddingTop,
1118
+ paddingBottom,
1119
+ rowContextValue,
1120
+ handleToggleSelect,
1121
+ clearHover
1455
1122
  };
1456
- for (const child of Children.toArray(children)) {
1457
- if (isTableHeaderElement(child)) {
1458
- slots.header = child;
1459
- continue;
1460
- }
1461
- if (isTableBodyElement(child)) {
1462
- slots.body = child;
1463
- continue;
1464
- }
1465
- if (isTablePaginationElement(child)) {
1466
- slots.pagination = child;
1467
- }
1468
- }
1469
- return slots;
1470
- }
1471
- function extractColumnElements(header) {
1472
- if (!header) return [];
1473
- const { children } = header.props;
1474
- return Children.toArray(children).filter(isTableColumnElement);
1475
- }
1476
-
1477
- // src/components/ui/table/components/Table/TableBody.tsx
1478
- function TableBody() {
1479
- return null;
1480
- }
1481
- TableBody.displayName = TABLE_BODY_DISPLAY_NAME;
1482
-
1483
- // src/components/ui/table/components/Table/TableColumn.tsx
1484
- function TableColumn(props) {
1485
- void props;
1486
- return null;
1487
- }
1488
- TableColumn.displayName = TABLE_COLUMN_DISPLAY_NAME;
1489
-
1490
- // src/components/ui/table/components/Table/tableDataPipeline.ts
1491
- function sortTableData(data, sort) {
1492
- if (!sort) return data;
1493
- const { field, direction } = sort;
1494
- const multiplier = direction === "asc" ? 1 : -1;
1495
- return [...data].sort((left, right) => {
1496
- const leftValue = left[field];
1497
- const rightValue = right[field];
1498
- if ((leftValue === null || leftValue === void 0) && (rightValue === null || rightValue === void 0)) {
1499
- return 0;
1500
- }
1501
- if (leftValue === null || leftValue === void 0) return 1;
1502
- if (rightValue === null || rightValue === void 0) return -1;
1503
- if (typeof leftValue === "number" && typeof rightValue === "number") {
1504
- return (leftValue - rightValue) * multiplier;
1505
- }
1506
- return String(leftValue).localeCompare(String(rightValue), "ko") * multiplier;
1507
- });
1508
- }
1509
- function paginateTableData(data, page, pageSize) {
1510
- const safePage = Math.max(1, page);
1511
- const start = (safePage - 1) * pageSize;
1512
- return data.slice(start, start + pageSize);
1513
- }
1514
- function getTotalPages(totalCount, pageSize) {
1515
- if (pageSize <= 0) return 1;
1516
- return Math.max(1, Math.ceil(totalCount / pageSize));
1517
- }
1518
-
1519
- // src/components/ui/table/components/Table/TableHeader.tsx
1520
- function TableHeader(props) {
1521
- void props;
1522
- return null;
1523
- }
1524
- TableHeader.displayName = TABLE_HEADER_DISPLAY_NAME;
1525
-
1526
- // src/components/ui/table/components/Table/TablePagination.tsx
1527
- import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
1528
- function TablePagination({
1529
- page,
1530
- pageSize = 10,
1531
- totalCount = 0,
1532
- onChange,
1533
- className
1534
- }) {
1535
- const totalPages = getTotalPages(totalCount, pageSize);
1536
- const safePage = Math.min(Math.max(1, page), totalPages);
1537
- const canGoPrev = safePage > 1;
1538
- const canGoNext = safePage < totalPages;
1539
- return /* @__PURE__ */ jsxs6("div", { className: cn("TablePaginationJSX", className), children: [
1540
- /* @__PURE__ */ jsx7(
1541
- "button",
1542
- {
1543
- type: "button",
1544
- className: "pagination-button",
1545
- disabled: !canGoPrev,
1546
- onClick: () => onChange(safePage - 1),
1547
- "aria-label": "\uC774\uC804 \uD398\uC774\uC9C0",
1548
- children: /* @__PURE__ */ jsx7(ChevronLeft, { className: "pagination-button-icon" })
1549
- }
1550
- ),
1551
- /* @__PURE__ */ jsxs6("span", { className: "pagination-label", children: [
1552
- safePage,
1553
- " / ",
1554
- totalPages
1555
- ] }),
1556
- /* @__PURE__ */ jsx7(
1557
- "button",
1558
- {
1559
- type: "button",
1560
- className: "pagination-button",
1561
- disabled: !canGoNext,
1562
- onClick: () => onChange(safePage + 1),
1563
- "aria-label": "\uB2E4\uC74C \uD398\uC774\uC9C0",
1564
- children: /* @__PURE__ */ jsx7(ChevronRight, { className: "pagination-button-icon" })
1565
- }
1566
- )
1567
- ] });
1568
- }
1569
- TablePagination.displayName = TABLE_PAGINATION_DISPLAY_NAME;
1570
-
1571
- // src/components/ui/table/components/Table/Table.tsx
1572
- import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
1573
- function TableRoot({
1574
- data,
1575
- children,
1576
- className,
1577
- totalCount,
1578
- filteredCount,
1579
- ...dataTableProps
1580
- }) {
1581
- const { header, pagination: paginationElement } = useMemo3(
1582
- () => parseTableChildren(children),
1583
- [children]
1584
- );
1585
- const [sort, setSort] = useState4(null);
1586
- const handleSort = useCallback4((field) => {
1587
- setSort((previous) => {
1588
- if (previous?.field !== field) {
1589
- return { field, direction: "asc" };
1590
- }
1591
- if (previous.direction === "asc") {
1592
- return { field, direction: "desc" };
1593
- }
1594
- return null;
1595
- });
1596
- }, []);
1597
- const columns = useMemo3(() => {
1598
- return extractColumnElements(header).map(
1599
- (columnElement) => buildColumnDef(columnElement.props, sort, handleSort)
1600
- );
1601
- }, [header, sort, handleSort]);
1602
- const paginationProps = paginationElement?.props;
1603
- const pageSize = paginationProps?.pageSize ?? 10;
1604
- const page = paginationProps?.page ?? 1;
1605
- const resolvedTotalCount = paginationProps?.totalCount ?? totalCount ?? data.length;
1606
- const tableData = useMemo3(() => {
1607
- const sortedData = sortTableData(data, sort);
1608
- if (!paginationProps) return sortedData;
1609
- return paginateTableData(sortedData, page, pageSize);
1610
- }, [data, sort, paginationProps, page, pageSize]);
1611
- if (columns.length === 0) {
1612
- console.warn("[Table] Table.Header \uC548\uC5D0 Table.Column\uC744 \uD558\uB098 \uC774\uC0C1 \uC120\uC5B8\uD574 \uC8FC\uC138\uC694.");
1613
- }
1614
- return /* @__PURE__ */ jsxs7("div", { className: "TableJSX", children: [
1615
- /* @__PURE__ */ jsx8(
1616
- DataTable,
1617
- {
1618
- ...dataTableProps,
1619
- data: tableData,
1620
- columns,
1621
- totalCount: paginationProps ? resolvedTotalCount : totalCount,
1622
- filteredCount: filteredCount ?? data.length,
1623
- className: cn(className, paginationProps && "DataTableJSX--with-pagination")
1624
- }
1625
- ),
1626
- paginationProps && /* @__PURE__ */ jsx8(
1627
- TablePagination,
1628
- {
1629
- page,
1630
- pageSize,
1631
- totalCount: resolvedTotalCount,
1632
- onChange: paginationProps.onChange,
1633
- className: paginationProps.className
1634
- }
1635
- )
1636
- ] });
1637
- }
1638
- function createTable() {
1639
- function Column(props) {
1640
- void props;
1641
- return null;
1642
- }
1643
- Column.displayName = TABLE_COLUMN_DISPLAY_NAME;
1644
- return Object.assign(
1645
- function BoundTable(props) {
1646
- return /* @__PURE__ */ jsx8(TableRoot, { ...props });
1647
- },
1648
- {
1649
- Header: TableHeader,
1650
- Column,
1651
- Body: TableBody,
1652
- Pagination: TablePagination
1653
- }
1654
- );
1655
1123
  }
1656
- var Table = Object.assign(TableRoot, {
1657
- Header: TableHeader,
1658
- Column: TableColumn,
1659
- Body: TableBody,
1660
- Pagination: TablePagination
1661
- });
1662
1124
  export {
1663
- DataTable,
1664
- Table,
1665
- createTable
1125
+ CELL_SELECTION_EDGES_CLASS,
1126
+ DEFAULT_DATA_TABLE_LABELS,
1127
+ DEFAULT_TREE_CHILDREN_FIELD,
1128
+ DEFAULT_TREE_ID_FIELD,
1129
+ DEFAULT_TREE_PARENT_ID_FIELD,
1130
+ DEFAULT_TREE_QTY_FIELD,
1131
+ applyCellEdit,
1132
+ applyFillData,
1133
+ applySelectionUpdater,
1134
+ buildColumnRowSpanMap,
1135
+ canExpandRow,
1136
+ collectFillChanges,
1137
+ collectRowSpanColumns,
1138
+ getCellEditDraftValue,
1139
+ getCellSelectionEdgeStyle,
1140
+ getColumnEditType,
1141
+ getRowIndexInMergedCell,
1142
+ hasCellSelectionEdges,
1143
+ isCellInSelection,
1144
+ isColumnEditable,
1145
+ parseCellEditValue,
1146
+ resolveDataTableLabels,
1147
+ resolveRowSelection,
1148
+ resolveRowSpanAt,
1149
+ toggleExpandedRowId,
1150
+ useCellEdit,
1151
+ useCellSelection,
1152
+ useConvertTreeData,
1153
+ useGlideTable
1666
1154
  };