react-glide-table 1.1.4 → 1.1.5
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/LICENSE +21 -0
- package/dist/compound.cjs +144 -48
- package/dist/compound.js +145 -49
- package/dist/core.cjs +122 -43
- package/dist/core.d.cts +24 -3
- package/dist/core.d.ts +24 -3
- package/dist/core.js +120 -43
- package/dist/index.cjs +148 -48
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +147 -49
- package/package.json +1 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 송찬영
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/compound.cjs
CHANGED
|
@@ -128,10 +128,36 @@ function getCellSelectionBounds(start, end) {
|
|
|
128
128
|
endCol: Math.max(start.col, end.col)
|
|
129
129
|
};
|
|
130
130
|
}
|
|
131
|
+
function measureMergedSpanRowHeights(rowIndex, rowSpan, cellElement) {
|
|
132
|
+
if (rowSpan <= 1) return void 0;
|
|
133
|
+
const tbody = cellElement?.closest("tbody") ?? (typeof document !== "undefined" ? document.querySelector("tbody.data-table-body") : null);
|
|
134
|
+
if (!tbody) return void 0;
|
|
135
|
+
const rows = tbody.querySelectorAll(":scope > tr");
|
|
136
|
+
if (rows.length < rowIndex + rowSpan) return void 0;
|
|
137
|
+
const heights = [];
|
|
138
|
+
for (let i = 0; i < rowSpan; i++) {
|
|
139
|
+
const row = rows[rowIndex + i];
|
|
140
|
+
const height = row?.getBoundingClientRect().height ?? 0;
|
|
141
|
+
if (height <= 0) return void 0;
|
|
142
|
+
heights.push(height);
|
|
143
|
+
}
|
|
144
|
+
return heights;
|
|
145
|
+
}
|
|
131
146
|
function getRowIndexInMergedCell(clientY, cellElement, rowIndex, rowSpan) {
|
|
132
147
|
if (rowSpan <= 1) return rowIndex;
|
|
133
148
|
const rect = cellElement.getBoundingClientRect();
|
|
134
149
|
const relativeY = clientY - rect.top;
|
|
150
|
+
const heights = measureMergedSpanRowHeights(rowIndex, rowSpan, cellElement);
|
|
151
|
+
if (heights && heights.length === rowSpan) {
|
|
152
|
+
let accrued = 0;
|
|
153
|
+
for (let i = 0; i < rowSpan; i++) {
|
|
154
|
+
accrued += heights[i];
|
|
155
|
+
if (relativeY < accrued) {
|
|
156
|
+
return rowIndex + i;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return rowIndex + rowSpan - 1;
|
|
160
|
+
}
|
|
135
161
|
const rowHeight = rect.height / rowSpan;
|
|
136
162
|
const offset = Math.min(
|
|
137
163
|
Math.max(Math.floor(relativeY / rowHeight), 0),
|
|
@@ -153,7 +179,35 @@ function getActiveSelectionBounds(dragState, selectionBounds) {
|
|
|
153
179
|
var SELECTION_EDGE_WIDTH_PX = 2;
|
|
154
180
|
var SELECTION_EDGE_COLOR = "var(--color-brand-primary)";
|
|
155
181
|
var CELL_SELECTION_EDGES_CLASS = "cell-selection-edges";
|
|
156
|
-
function
|
|
182
|
+
function rowRangeToHeightRatios(rowIndex, span, fromRow, toRowExclusive, rowHeights) {
|
|
183
|
+
const clampedFrom = Math.max(fromRow, rowIndex);
|
|
184
|
+
const clampedTo = Math.min(toRowExclusive, rowIndex + span);
|
|
185
|
+
if (clampedTo <= clampedFrom) {
|
|
186
|
+
return { offsetRatio: 0, lengthRatio: 0 };
|
|
187
|
+
}
|
|
188
|
+
if (!rowHeights || rowHeights.length !== span) {
|
|
189
|
+
return {
|
|
190
|
+
offsetRatio: (clampedFrom - rowIndex) / span,
|
|
191
|
+
lengthRatio: (clampedTo - clampedFrom) / span
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
const total = rowHeights.reduce((sum, height) => sum + height, 0) || 1;
|
|
195
|
+
let offsetPx = 0;
|
|
196
|
+
for (let i = 0; i < clampedFrom - rowIndex; i++) {
|
|
197
|
+
offsetPx += rowHeights[i] ?? 0;
|
|
198
|
+
}
|
|
199
|
+
let lengthPx = 0;
|
|
200
|
+
for (let i = clampedFrom - rowIndex; i < clampedTo - rowIndex; i++) {
|
|
201
|
+
lengthPx += rowHeights[i] ?? 0;
|
|
202
|
+
}
|
|
203
|
+
return {
|
|
204
|
+
offsetRatio: offsetPx / total,
|
|
205
|
+
lengthRatio: lengthPx / total,
|
|
206
|
+
offsetPx,
|
|
207
|
+
lengthPx
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
function getMergedCellStepEdges(rowIndex, colIndex, bounds, rowSpan, isVisuallySelectedAt, rowHeights) {
|
|
157
211
|
const cellEndRow = rowIndex + rowSpan - 1;
|
|
158
212
|
const span = cellEndRow - rowIndex + 1;
|
|
159
213
|
if (span <= 1) return [];
|
|
@@ -172,20 +226,30 @@ function getMergedCellStepEdges(rowIndex, colIndex, bounds, rowSpan, isVisuallyS
|
|
|
172
226
|
continue;
|
|
173
227
|
}
|
|
174
228
|
if (runStart !== null) {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
229
|
+
const ratios = rowRangeToHeightRatios(
|
|
230
|
+
rowIndex,
|
|
231
|
+
span,
|
|
232
|
+
runStart,
|
|
233
|
+
row,
|
|
234
|
+
rowHeights
|
|
235
|
+
);
|
|
236
|
+
if (ratios.lengthRatio > 0) {
|
|
237
|
+
edges.push({ side, ...ratios });
|
|
238
|
+
}
|
|
180
239
|
runStart = null;
|
|
181
240
|
}
|
|
182
241
|
}
|
|
183
242
|
if (runStart !== null) {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
243
|
+
const ratios = rowRangeToHeightRatios(
|
|
244
|
+
rowIndex,
|
|
245
|
+
span,
|
|
246
|
+
runStart,
|
|
247
|
+
toRowExclusive,
|
|
248
|
+
rowHeights
|
|
249
|
+
);
|
|
250
|
+
if (ratios.lengthRatio > 0) {
|
|
251
|
+
edges.push({ side, ...ratios });
|
|
252
|
+
}
|
|
189
253
|
}
|
|
190
254
|
};
|
|
191
255
|
const collectSide = (side, neighborCol) => {
|
|
@@ -214,14 +278,17 @@ function getMergedCellStepEdges(rowIndex, colIndex, bounds, rowSpan, isVisuallyS
|
|
|
214
278
|
}
|
|
215
279
|
return edges;
|
|
216
280
|
}
|
|
217
|
-
function
|
|
281
|
+
function buildPartialEdgeGradient(edge) {
|
|
282
|
+
const usePx = edge.offsetPx != null && edge.lengthPx != null;
|
|
218
283
|
const startPct = edge.offsetRatio * 100;
|
|
219
|
-
const endPct = (edge.offsetRatio + edge.
|
|
220
|
-
const
|
|
221
|
-
const
|
|
222
|
-
const
|
|
223
|
-
const
|
|
224
|
-
const
|
|
284
|
+
const endPct = (edge.offsetRatio + edge.lengthRatio) * 100;
|
|
285
|
+
const startPx = edge.offsetPx ?? 0;
|
|
286
|
+
const endPx = (edge.offsetPx ?? 0) + (edge.lengthPx ?? 0);
|
|
287
|
+
const overlapPx = SELECTION_EDGE_WIDTH_PX;
|
|
288
|
+
const isTopProtrusion = (usePx ? startPx === 0 : edge.offsetRatio === 0) && edge.lengthRatio < 1;
|
|
289
|
+
const isBottomProtrusion = usePx ? startPx > 0 : edge.offsetRatio > 0;
|
|
290
|
+
const startStop = usePx ? isBottomProtrusion ? `${Math.max(0, startPx - overlapPx)}px` : `${startPx}px` : isBottomProtrusion ? `calc(${startPct}% - ${overlapPx}px)` : `${startPct}%`;
|
|
291
|
+
const endStop = usePx ? isTopProtrusion ? `${endPx + overlapPx}px` : `${endPx}px` : isTopProtrusion ? `calc(${endPct}% + ${overlapPx}px)` : `${endPct}%`;
|
|
225
292
|
const xPos = edge.side === "left" ? "0" : "100%";
|
|
226
293
|
const layers = [
|
|
227
294
|
{
|
|
@@ -231,7 +298,7 @@ function buildPartialVerticalGradient(edge) {
|
|
|
231
298
|
}
|
|
232
299
|
];
|
|
233
300
|
if (isTopProtrusion || isBottomProtrusion) {
|
|
234
|
-
const capTop = isTopProtrusion ? `calc(${endPct}% - ${SELECTION_EDGE_WIDTH_PX}px)` : `calc(${startPct}% - ${SELECTION_EDGE_WIDTH_PX}px)`;
|
|
301
|
+
const capTop = usePx ? isTopProtrusion ? `${Math.max(0, endPx - SELECTION_EDGE_WIDTH_PX)}px` : `${Math.max(0, startPx - SELECTION_EDGE_WIDTH_PX)}px` : isTopProtrusion ? `calc(${endPct}% - ${SELECTION_EDGE_WIDTH_PX}px)` : `calc(${startPct}% - ${SELECTION_EDGE_WIDTH_PX}px)`;
|
|
235
302
|
layers.push({
|
|
236
303
|
image: `linear-gradient(${SELECTION_EDGE_COLOR}, ${SELECTION_EDGE_COLOR})`,
|
|
237
304
|
size: `${SELECTION_EDGE_WIDTH_PX}px ${SELECTION_EDGE_WIDTH_PX}px`,
|
|
@@ -240,7 +307,7 @@ function buildPartialVerticalGradient(edge) {
|
|
|
240
307
|
}
|
|
241
308
|
return layers;
|
|
242
309
|
}
|
|
243
|
-
function getCellSelectionEdgeStyle(rowIndex, colIndex, bounds, rowSpan = 1, isVisuallySelectedAt) {
|
|
310
|
+
function getCellSelectionEdgeStyle(rowIndex, colIndex, bounds, rowSpan = 1, isVisuallySelectedAt, rowHeights) {
|
|
244
311
|
if (!isCellInSelection(rowIndex, colIndex, bounds, rowSpan) || !bounds)
|
|
245
312
|
return void 0;
|
|
246
313
|
const cellEndRow = rowIndex + rowSpan - 1;
|
|
@@ -249,39 +316,47 @@ function getCellSelectionEdgeStyle(rowIndex, colIndex, bounds, rowSpan = 1, isVi
|
|
|
249
316
|
const isLeftEdge = colIndex === bounds.startCol;
|
|
250
317
|
const isRightEdge = colIndex === bounds.endCol;
|
|
251
318
|
const selectionContinuesBelow = cellEndRow < bounds.endRow;
|
|
252
|
-
const shadows = [];
|
|
253
|
-
if (isTopEdge) {
|
|
254
|
-
shadows.push(
|
|
255
|
-
`inset 0 ${SELECTION_EDGE_WIDTH_PX}px 0 0 ${SELECTION_EDGE_COLOR}`
|
|
256
|
-
);
|
|
257
|
-
}
|
|
258
|
-
if (isBottomEdge) {
|
|
259
|
-
shadows.push(
|
|
260
|
-
`inset 0 -${SELECTION_EDGE_WIDTH_PX}px 0 0 ${SELECTION_EDGE_COLOR}`
|
|
261
|
-
);
|
|
262
|
-
}
|
|
263
|
-
if (isLeftEdge) {
|
|
264
|
-
shadows.push(
|
|
265
|
-
`inset ${SELECTION_EDGE_WIDTH_PX}px 0 0 0 ${SELECTION_EDGE_COLOR}`
|
|
266
|
-
);
|
|
267
|
-
}
|
|
268
|
-
if (isRightEdge) {
|
|
269
|
-
shadows.push(
|
|
270
|
-
`inset -${SELECTION_EDGE_WIDTH_PX}px 0 0 0 ${SELECTION_EDGE_COLOR}`
|
|
271
|
-
);
|
|
272
|
-
}
|
|
273
319
|
const stepEdges = getMergedCellStepEdges(
|
|
274
320
|
rowIndex,
|
|
275
321
|
colIndex,
|
|
276
322
|
bounds,
|
|
277
323
|
rowSpan,
|
|
278
|
-
isVisuallySelectedAt
|
|
324
|
+
isVisuallySelectedAt,
|
|
325
|
+
rowHeights
|
|
279
326
|
);
|
|
327
|
+
const shadows = [];
|
|
328
|
+
const hasFullPerimeter = isTopEdge && isBottomEdge && isLeftEdge && isRightEdge && stepEdges.length === 0;
|
|
329
|
+
if (hasFullPerimeter) {
|
|
330
|
+
shadows.push(
|
|
331
|
+
`inset 0 0 0 ${SELECTION_EDGE_WIDTH_PX}px ${SELECTION_EDGE_COLOR}`
|
|
332
|
+
);
|
|
333
|
+
} else {
|
|
334
|
+
if (isTopEdge) {
|
|
335
|
+
shadows.push(
|
|
336
|
+
`inset 0 ${SELECTION_EDGE_WIDTH_PX}px 0 0 ${SELECTION_EDGE_COLOR}`
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
if (isBottomEdge) {
|
|
340
|
+
shadows.push(
|
|
341
|
+
`inset 0 -${SELECTION_EDGE_WIDTH_PX}px 0 0 ${SELECTION_EDGE_COLOR}`
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
if (isLeftEdge) {
|
|
345
|
+
shadows.push(
|
|
346
|
+
`inset ${SELECTION_EDGE_WIDTH_PX}px 0 0 0 ${SELECTION_EDGE_COLOR}`
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
if (isRightEdge) {
|
|
350
|
+
shadows.push(
|
|
351
|
+
`inset -${SELECTION_EDGE_WIDTH_PX}px 0 0 0 ${SELECTION_EDGE_COLOR}`
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
280
355
|
const gradients = [];
|
|
281
356
|
const sizes = [];
|
|
282
357
|
const positions = [];
|
|
283
358
|
for (const edge of stepEdges) {
|
|
284
|
-
for (const partial of
|
|
359
|
+
for (const partial of buildPartialEdgeGradient(edge)) {
|
|
285
360
|
gradients.push(partial.image);
|
|
286
361
|
sizes.push(partial.size);
|
|
287
362
|
positions.push(partial.position);
|
|
@@ -853,9 +928,10 @@ function DataTableRow({
|
|
|
853
928
|
}
|
|
854
929
|
}
|
|
855
930
|
const isEditing = editingCell?.rowIndex === rowIndex && editingCell?.colIndex === cellIndex;
|
|
856
|
-
const showCellHover = isRowSpanColumn ? isGroupHovered : isRowHovered;
|
|
857
|
-
const showCellSelected = isRowSpanColumn ? isGroupSelected : isRowSelected;
|
|
858
931
|
const cellRowSpan = rowSpanInfo?.rowSpan ?? 1;
|
|
932
|
+
const isMergedCellHovered = hoveredRowIndex !== null && hoveredRowIndex >= rowIndex && hoveredRowIndex <= rowIndex + cellRowSpan - 1;
|
|
933
|
+
const showCellHover = isRowSpanColumn ? isMergedCellHovered : isRowHovered;
|
|
934
|
+
const showCellSelected = isRowSpanColumn ? isGroupSelected : isRowSelected;
|
|
859
935
|
const isMerged = cellRowSpan > 1;
|
|
860
936
|
const showMergedRightEdge = isMerged && (cellIndex === visibleCells.length - 1 || resolveRowSpanAt(
|
|
861
937
|
columnRowSpanMap.get(columnIdsByIndex[cellIndex + 1]),
|
|
@@ -868,12 +944,14 @@ function DataTableRow({
|
|
|
868
944
|
cellRowSpan
|
|
869
945
|
);
|
|
870
946
|
const isBottomRightCell = !isEditing && activeSelectionBounds && !dragState.isSelecting && activeSelectionBounds.endRow >= rowIndex && activeSelectionBounds.endRow <= rowIndex + cellRowSpan - 1 && cellIndex === activeSelectionBounds.endCol;
|
|
947
|
+
const spanRowHeights = enableCellSelection && activeSelectionBounds && isCellDragSelected && cellRowSpan > 1 ? measureMergedSpanRowHeights(rowIndex, cellRowSpan) : void 0;
|
|
871
948
|
const selectionEdgeStyle = getCellSelectionEdgeStyle(
|
|
872
949
|
rowIndex,
|
|
873
950
|
cellIndex,
|
|
874
951
|
activeSelectionBounds,
|
|
875
952
|
cellRowSpan,
|
|
876
|
-
isVisuallySelectedAt
|
|
953
|
+
isVisuallySelectedAt,
|
|
954
|
+
spanRowHeights
|
|
877
955
|
);
|
|
878
956
|
const resolveCellRowIndex = (clientY, element) => getRowIndexInMergedCell(clientY, element, rowIndex, cellRowSpan);
|
|
879
957
|
const hasSelectionEdges = hasCellSelectionEdges(selectionEdgeStyle);
|
|
@@ -883,6 +961,7 @@ function DataTableRow({
|
|
|
883
961
|
rowSpan: rowSpanInfo && rowSpanInfo.rowSpan > 1 ? rowSpanInfo.rowSpan : void 0,
|
|
884
962
|
"data-merged": isMerged && cellIndex > 0 ? "" : void 0,
|
|
885
963
|
"data-merged-edge-right": showMergedRightEdge ? "" : void 0,
|
|
964
|
+
"data-merged-row-first": isMerged && cellIndex === 0 && showMergedRightEdge ? "" : void 0,
|
|
886
965
|
"data-group-selected": enableRowSpan && showCellSelected ? "" : void 0,
|
|
887
966
|
"data-group-hovered": enableRowSpan && showCellHover && !showCellSelected ? "" : void 0,
|
|
888
967
|
"data-selection-fill": isCellDragSelected ? "" : void 0,
|
|
@@ -927,7 +1006,8 @@ function DataTableRow({
|
|
|
927
1006
|
"data-table-cell",
|
|
928
1007
|
CELL_ALIGN_CLASS[align],
|
|
929
1008
|
cellClassName,
|
|
930
|
-
isMerged &&
|
|
1009
|
+
isMerged && "is-merged",
|
|
1010
|
+
isMerged && cellIndex === 0 && showMergedRightEdge && "is-merged-row-first",
|
|
931
1011
|
showMergedRightEdge && "is-merged-edge-right",
|
|
932
1012
|
enableRowSpan && showCellSelected && "is-group-selected",
|
|
933
1013
|
enableRowSpan && showCellHover && !showCellSelected && "is-group-hovered",
|
|
@@ -2036,10 +2116,26 @@ function parseTableChildren(children) {
|
|
|
2036
2116
|
}
|
|
2037
2117
|
return slots;
|
|
2038
2118
|
}
|
|
2119
|
+
function flattenColumnElements(children) {
|
|
2120
|
+
const result = [];
|
|
2121
|
+
for (const child of import_react9.Children.toArray(children)) {
|
|
2122
|
+
if (isTableColumnElement(child)) {
|
|
2123
|
+
result.push(child);
|
|
2124
|
+
continue;
|
|
2125
|
+
}
|
|
2126
|
+
if ((0, import_react9.isValidElement)(child)) {
|
|
2127
|
+
const nested = child.props.children;
|
|
2128
|
+
if (nested != null) {
|
|
2129
|
+
result.push(...flattenColumnElements(nested));
|
|
2130
|
+
}
|
|
2131
|
+
}
|
|
2132
|
+
}
|
|
2133
|
+
return result;
|
|
2134
|
+
}
|
|
2039
2135
|
function extractColumnElements(header) {
|
|
2040
2136
|
if (!header) return [];
|
|
2041
2137
|
const { children } = header.props;
|
|
2042
|
-
return
|
|
2138
|
+
return flattenColumnElements(children);
|
|
2043
2139
|
}
|
|
2044
2140
|
|
|
2045
2141
|
// src/components/ui/table/components/Table/TableBody.tsx
|
package/dist/compound.js
CHANGED
|
@@ -100,10 +100,36 @@ function getCellSelectionBounds(start, end) {
|
|
|
100
100
|
endCol: Math.max(start.col, end.col)
|
|
101
101
|
};
|
|
102
102
|
}
|
|
103
|
+
function measureMergedSpanRowHeights(rowIndex, rowSpan, cellElement) {
|
|
104
|
+
if (rowSpan <= 1) return void 0;
|
|
105
|
+
const tbody = cellElement?.closest("tbody") ?? (typeof document !== "undefined" ? document.querySelector("tbody.data-table-body") : null);
|
|
106
|
+
if (!tbody) return void 0;
|
|
107
|
+
const rows = tbody.querySelectorAll(":scope > tr");
|
|
108
|
+
if (rows.length < rowIndex + rowSpan) return void 0;
|
|
109
|
+
const heights = [];
|
|
110
|
+
for (let i = 0; i < rowSpan; i++) {
|
|
111
|
+
const row = rows[rowIndex + i];
|
|
112
|
+
const height = row?.getBoundingClientRect().height ?? 0;
|
|
113
|
+
if (height <= 0) return void 0;
|
|
114
|
+
heights.push(height);
|
|
115
|
+
}
|
|
116
|
+
return heights;
|
|
117
|
+
}
|
|
103
118
|
function getRowIndexInMergedCell(clientY, cellElement, rowIndex, rowSpan) {
|
|
104
119
|
if (rowSpan <= 1) return rowIndex;
|
|
105
120
|
const rect = cellElement.getBoundingClientRect();
|
|
106
121
|
const relativeY = clientY - rect.top;
|
|
122
|
+
const heights = measureMergedSpanRowHeights(rowIndex, rowSpan, cellElement);
|
|
123
|
+
if (heights && heights.length === rowSpan) {
|
|
124
|
+
let accrued = 0;
|
|
125
|
+
for (let i = 0; i < rowSpan; i++) {
|
|
126
|
+
accrued += heights[i];
|
|
127
|
+
if (relativeY < accrued) {
|
|
128
|
+
return rowIndex + i;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return rowIndex + rowSpan - 1;
|
|
132
|
+
}
|
|
107
133
|
const rowHeight = rect.height / rowSpan;
|
|
108
134
|
const offset = Math.min(
|
|
109
135
|
Math.max(Math.floor(relativeY / rowHeight), 0),
|
|
@@ -125,7 +151,35 @@ function getActiveSelectionBounds(dragState, selectionBounds) {
|
|
|
125
151
|
var SELECTION_EDGE_WIDTH_PX = 2;
|
|
126
152
|
var SELECTION_EDGE_COLOR = "var(--color-brand-primary)";
|
|
127
153
|
var CELL_SELECTION_EDGES_CLASS = "cell-selection-edges";
|
|
128
|
-
function
|
|
154
|
+
function rowRangeToHeightRatios(rowIndex, span, fromRow, toRowExclusive, rowHeights) {
|
|
155
|
+
const clampedFrom = Math.max(fromRow, rowIndex);
|
|
156
|
+
const clampedTo = Math.min(toRowExclusive, rowIndex + span);
|
|
157
|
+
if (clampedTo <= clampedFrom) {
|
|
158
|
+
return { offsetRatio: 0, lengthRatio: 0 };
|
|
159
|
+
}
|
|
160
|
+
if (!rowHeights || rowHeights.length !== span) {
|
|
161
|
+
return {
|
|
162
|
+
offsetRatio: (clampedFrom - rowIndex) / span,
|
|
163
|
+
lengthRatio: (clampedTo - clampedFrom) / span
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
const total = rowHeights.reduce((sum, height) => sum + height, 0) || 1;
|
|
167
|
+
let offsetPx = 0;
|
|
168
|
+
for (let i = 0; i < clampedFrom - rowIndex; i++) {
|
|
169
|
+
offsetPx += rowHeights[i] ?? 0;
|
|
170
|
+
}
|
|
171
|
+
let lengthPx = 0;
|
|
172
|
+
for (let i = clampedFrom - rowIndex; i < clampedTo - rowIndex; i++) {
|
|
173
|
+
lengthPx += rowHeights[i] ?? 0;
|
|
174
|
+
}
|
|
175
|
+
return {
|
|
176
|
+
offsetRatio: offsetPx / total,
|
|
177
|
+
lengthRatio: lengthPx / total,
|
|
178
|
+
offsetPx,
|
|
179
|
+
lengthPx
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
function getMergedCellStepEdges(rowIndex, colIndex, bounds, rowSpan, isVisuallySelectedAt, rowHeights) {
|
|
129
183
|
const cellEndRow = rowIndex + rowSpan - 1;
|
|
130
184
|
const span = cellEndRow - rowIndex + 1;
|
|
131
185
|
if (span <= 1) return [];
|
|
@@ -144,20 +198,30 @@ function getMergedCellStepEdges(rowIndex, colIndex, bounds, rowSpan, isVisuallyS
|
|
|
144
198
|
continue;
|
|
145
199
|
}
|
|
146
200
|
if (runStart !== null) {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
201
|
+
const ratios = rowRangeToHeightRatios(
|
|
202
|
+
rowIndex,
|
|
203
|
+
span,
|
|
204
|
+
runStart,
|
|
205
|
+
row,
|
|
206
|
+
rowHeights
|
|
207
|
+
);
|
|
208
|
+
if (ratios.lengthRatio > 0) {
|
|
209
|
+
edges.push({ side, ...ratios });
|
|
210
|
+
}
|
|
152
211
|
runStart = null;
|
|
153
212
|
}
|
|
154
213
|
}
|
|
155
214
|
if (runStart !== null) {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
215
|
+
const ratios = rowRangeToHeightRatios(
|
|
216
|
+
rowIndex,
|
|
217
|
+
span,
|
|
218
|
+
runStart,
|
|
219
|
+
toRowExclusive,
|
|
220
|
+
rowHeights
|
|
221
|
+
);
|
|
222
|
+
if (ratios.lengthRatio > 0) {
|
|
223
|
+
edges.push({ side, ...ratios });
|
|
224
|
+
}
|
|
161
225
|
}
|
|
162
226
|
};
|
|
163
227
|
const collectSide = (side, neighborCol) => {
|
|
@@ -186,14 +250,17 @@ function getMergedCellStepEdges(rowIndex, colIndex, bounds, rowSpan, isVisuallyS
|
|
|
186
250
|
}
|
|
187
251
|
return edges;
|
|
188
252
|
}
|
|
189
|
-
function
|
|
253
|
+
function buildPartialEdgeGradient(edge) {
|
|
254
|
+
const usePx = edge.offsetPx != null && edge.lengthPx != null;
|
|
190
255
|
const startPct = edge.offsetRatio * 100;
|
|
191
|
-
const endPct = (edge.offsetRatio + edge.
|
|
192
|
-
const
|
|
193
|
-
const
|
|
194
|
-
const
|
|
195
|
-
const
|
|
196
|
-
const
|
|
256
|
+
const endPct = (edge.offsetRatio + edge.lengthRatio) * 100;
|
|
257
|
+
const startPx = edge.offsetPx ?? 0;
|
|
258
|
+
const endPx = (edge.offsetPx ?? 0) + (edge.lengthPx ?? 0);
|
|
259
|
+
const overlapPx = SELECTION_EDGE_WIDTH_PX;
|
|
260
|
+
const isTopProtrusion = (usePx ? startPx === 0 : edge.offsetRatio === 0) && edge.lengthRatio < 1;
|
|
261
|
+
const isBottomProtrusion = usePx ? startPx > 0 : edge.offsetRatio > 0;
|
|
262
|
+
const startStop = usePx ? isBottomProtrusion ? `${Math.max(0, startPx - overlapPx)}px` : `${startPx}px` : isBottomProtrusion ? `calc(${startPct}% - ${overlapPx}px)` : `${startPct}%`;
|
|
263
|
+
const endStop = usePx ? isTopProtrusion ? `${endPx + overlapPx}px` : `${endPx}px` : isTopProtrusion ? `calc(${endPct}% + ${overlapPx}px)` : `${endPct}%`;
|
|
197
264
|
const xPos = edge.side === "left" ? "0" : "100%";
|
|
198
265
|
const layers = [
|
|
199
266
|
{
|
|
@@ -203,7 +270,7 @@ function buildPartialVerticalGradient(edge) {
|
|
|
203
270
|
}
|
|
204
271
|
];
|
|
205
272
|
if (isTopProtrusion || isBottomProtrusion) {
|
|
206
|
-
const capTop = isTopProtrusion ? `calc(${endPct}% - ${SELECTION_EDGE_WIDTH_PX}px)` : `calc(${startPct}% - ${SELECTION_EDGE_WIDTH_PX}px)`;
|
|
273
|
+
const capTop = usePx ? isTopProtrusion ? `${Math.max(0, endPx - SELECTION_EDGE_WIDTH_PX)}px` : `${Math.max(0, startPx - SELECTION_EDGE_WIDTH_PX)}px` : isTopProtrusion ? `calc(${endPct}% - ${SELECTION_EDGE_WIDTH_PX}px)` : `calc(${startPct}% - ${SELECTION_EDGE_WIDTH_PX}px)`;
|
|
207
274
|
layers.push({
|
|
208
275
|
image: `linear-gradient(${SELECTION_EDGE_COLOR}, ${SELECTION_EDGE_COLOR})`,
|
|
209
276
|
size: `${SELECTION_EDGE_WIDTH_PX}px ${SELECTION_EDGE_WIDTH_PX}px`,
|
|
@@ -212,7 +279,7 @@ function buildPartialVerticalGradient(edge) {
|
|
|
212
279
|
}
|
|
213
280
|
return layers;
|
|
214
281
|
}
|
|
215
|
-
function getCellSelectionEdgeStyle(rowIndex, colIndex, bounds, rowSpan = 1, isVisuallySelectedAt) {
|
|
282
|
+
function getCellSelectionEdgeStyle(rowIndex, colIndex, bounds, rowSpan = 1, isVisuallySelectedAt, rowHeights) {
|
|
216
283
|
if (!isCellInSelection(rowIndex, colIndex, bounds, rowSpan) || !bounds)
|
|
217
284
|
return void 0;
|
|
218
285
|
const cellEndRow = rowIndex + rowSpan - 1;
|
|
@@ -221,39 +288,47 @@ function getCellSelectionEdgeStyle(rowIndex, colIndex, bounds, rowSpan = 1, isVi
|
|
|
221
288
|
const isLeftEdge = colIndex === bounds.startCol;
|
|
222
289
|
const isRightEdge = colIndex === bounds.endCol;
|
|
223
290
|
const selectionContinuesBelow = cellEndRow < bounds.endRow;
|
|
224
|
-
const shadows = [];
|
|
225
|
-
if (isTopEdge) {
|
|
226
|
-
shadows.push(
|
|
227
|
-
`inset 0 ${SELECTION_EDGE_WIDTH_PX}px 0 0 ${SELECTION_EDGE_COLOR}`
|
|
228
|
-
);
|
|
229
|
-
}
|
|
230
|
-
if (isBottomEdge) {
|
|
231
|
-
shadows.push(
|
|
232
|
-
`inset 0 -${SELECTION_EDGE_WIDTH_PX}px 0 0 ${SELECTION_EDGE_COLOR}`
|
|
233
|
-
);
|
|
234
|
-
}
|
|
235
|
-
if (isLeftEdge) {
|
|
236
|
-
shadows.push(
|
|
237
|
-
`inset ${SELECTION_EDGE_WIDTH_PX}px 0 0 0 ${SELECTION_EDGE_COLOR}`
|
|
238
|
-
);
|
|
239
|
-
}
|
|
240
|
-
if (isRightEdge) {
|
|
241
|
-
shadows.push(
|
|
242
|
-
`inset -${SELECTION_EDGE_WIDTH_PX}px 0 0 0 ${SELECTION_EDGE_COLOR}`
|
|
243
|
-
);
|
|
244
|
-
}
|
|
245
291
|
const stepEdges = getMergedCellStepEdges(
|
|
246
292
|
rowIndex,
|
|
247
293
|
colIndex,
|
|
248
294
|
bounds,
|
|
249
295
|
rowSpan,
|
|
250
|
-
isVisuallySelectedAt
|
|
296
|
+
isVisuallySelectedAt,
|
|
297
|
+
rowHeights
|
|
251
298
|
);
|
|
299
|
+
const shadows = [];
|
|
300
|
+
const hasFullPerimeter = isTopEdge && isBottomEdge && isLeftEdge && isRightEdge && stepEdges.length === 0;
|
|
301
|
+
if (hasFullPerimeter) {
|
|
302
|
+
shadows.push(
|
|
303
|
+
`inset 0 0 0 ${SELECTION_EDGE_WIDTH_PX}px ${SELECTION_EDGE_COLOR}`
|
|
304
|
+
);
|
|
305
|
+
} else {
|
|
306
|
+
if (isTopEdge) {
|
|
307
|
+
shadows.push(
|
|
308
|
+
`inset 0 ${SELECTION_EDGE_WIDTH_PX}px 0 0 ${SELECTION_EDGE_COLOR}`
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
if (isBottomEdge) {
|
|
312
|
+
shadows.push(
|
|
313
|
+
`inset 0 -${SELECTION_EDGE_WIDTH_PX}px 0 0 ${SELECTION_EDGE_COLOR}`
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
if (isLeftEdge) {
|
|
317
|
+
shadows.push(
|
|
318
|
+
`inset ${SELECTION_EDGE_WIDTH_PX}px 0 0 0 ${SELECTION_EDGE_COLOR}`
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
if (isRightEdge) {
|
|
322
|
+
shadows.push(
|
|
323
|
+
`inset -${SELECTION_EDGE_WIDTH_PX}px 0 0 0 ${SELECTION_EDGE_COLOR}`
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
252
327
|
const gradients = [];
|
|
253
328
|
const sizes = [];
|
|
254
329
|
const positions = [];
|
|
255
330
|
for (const edge of stepEdges) {
|
|
256
|
-
for (const partial of
|
|
331
|
+
for (const partial of buildPartialEdgeGradient(edge)) {
|
|
257
332
|
gradients.push(partial.image);
|
|
258
333
|
sizes.push(partial.size);
|
|
259
334
|
positions.push(partial.position);
|
|
@@ -825,9 +900,10 @@ function DataTableRow({
|
|
|
825
900
|
}
|
|
826
901
|
}
|
|
827
902
|
const isEditing = editingCell?.rowIndex === rowIndex && editingCell?.colIndex === cellIndex;
|
|
828
|
-
const showCellHover = isRowSpanColumn ? isGroupHovered : isRowHovered;
|
|
829
|
-
const showCellSelected = isRowSpanColumn ? isGroupSelected : isRowSelected;
|
|
830
903
|
const cellRowSpan = rowSpanInfo?.rowSpan ?? 1;
|
|
904
|
+
const isMergedCellHovered = hoveredRowIndex !== null && hoveredRowIndex >= rowIndex && hoveredRowIndex <= rowIndex + cellRowSpan - 1;
|
|
905
|
+
const showCellHover = isRowSpanColumn ? isMergedCellHovered : isRowHovered;
|
|
906
|
+
const showCellSelected = isRowSpanColumn ? isGroupSelected : isRowSelected;
|
|
831
907
|
const isMerged = cellRowSpan > 1;
|
|
832
908
|
const showMergedRightEdge = isMerged && (cellIndex === visibleCells.length - 1 || resolveRowSpanAt(
|
|
833
909
|
columnRowSpanMap.get(columnIdsByIndex[cellIndex + 1]),
|
|
@@ -840,12 +916,14 @@ function DataTableRow({
|
|
|
840
916
|
cellRowSpan
|
|
841
917
|
);
|
|
842
918
|
const isBottomRightCell = !isEditing && activeSelectionBounds && !dragState.isSelecting && activeSelectionBounds.endRow >= rowIndex && activeSelectionBounds.endRow <= rowIndex + cellRowSpan - 1 && cellIndex === activeSelectionBounds.endCol;
|
|
919
|
+
const spanRowHeights = enableCellSelection && activeSelectionBounds && isCellDragSelected && cellRowSpan > 1 ? measureMergedSpanRowHeights(rowIndex, cellRowSpan) : void 0;
|
|
843
920
|
const selectionEdgeStyle = getCellSelectionEdgeStyle(
|
|
844
921
|
rowIndex,
|
|
845
922
|
cellIndex,
|
|
846
923
|
activeSelectionBounds,
|
|
847
924
|
cellRowSpan,
|
|
848
|
-
isVisuallySelectedAt
|
|
925
|
+
isVisuallySelectedAt,
|
|
926
|
+
spanRowHeights
|
|
849
927
|
);
|
|
850
928
|
const resolveCellRowIndex = (clientY, element) => getRowIndexInMergedCell(clientY, element, rowIndex, cellRowSpan);
|
|
851
929
|
const hasSelectionEdges = hasCellSelectionEdges(selectionEdgeStyle);
|
|
@@ -855,6 +933,7 @@ function DataTableRow({
|
|
|
855
933
|
rowSpan: rowSpanInfo && rowSpanInfo.rowSpan > 1 ? rowSpanInfo.rowSpan : void 0,
|
|
856
934
|
"data-merged": isMerged && cellIndex > 0 ? "" : void 0,
|
|
857
935
|
"data-merged-edge-right": showMergedRightEdge ? "" : void 0,
|
|
936
|
+
"data-merged-row-first": isMerged && cellIndex === 0 && showMergedRightEdge ? "" : void 0,
|
|
858
937
|
"data-group-selected": enableRowSpan && showCellSelected ? "" : void 0,
|
|
859
938
|
"data-group-hovered": enableRowSpan && showCellHover && !showCellSelected ? "" : void 0,
|
|
860
939
|
"data-selection-fill": isCellDragSelected ? "" : void 0,
|
|
@@ -899,7 +978,8 @@ function DataTableRow({
|
|
|
899
978
|
"data-table-cell",
|
|
900
979
|
CELL_ALIGN_CLASS[align],
|
|
901
980
|
cellClassName,
|
|
902
|
-
isMerged &&
|
|
981
|
+
isMerged && "is-merged",
|
|
982
|
+
isMerged && cellIndex === 0 && showMergedRightEdge && "is-merged-row-first",
|
|
903
983
|
showMergedRightEdge && "is-merged-edge-right",
|
|
904
984
|
enableRowSpan && showCellSelected && "is-group-selected",
|
|
905
985
|
enableRowSpan && showCellHover && !showCellSelected && "is-group-hovered",
|
|
@@ -1970,7 +2050,7 @@ function buildColumnDef(props, sort, onSort) {
|
|
|
1970
2050
|
}
|
|
1971
2051
|
|
|
1972
2052
|
// src/components/ui/table/components/Table/parseTableChildren.ts
|
|
1973
|
-
import { Children } from "react";
|
|
2053
|
+
import { Children, isValidElement as isValidElement2 } from "react";
|
|
1974
2054
|
|
|
1975
2055
|
// src/components/ui/table/components/Table/tableChildTypes.ts
|
|
1976
2056
|
import { isValidElement } from "react";
|
|
@@ -2019,10 +2099,26 @@ function parseTableChildren(children) {
|
|
|
2019
2099
|
}
|
|
2020
2100
|
return slots;
|
|
2021
2101
|
}
|
|
2102
|
+
function flattenColumnElements(children) {
|
|
2103
|
+
const result = [];
|
|
2104
|
+
for (const child of Children.toArray(children)) {
|
|
2105
|
+
if (isTableColumnElement(child)) {
|
|
2106
|
+
result.push(child);
|
|
2107
|
+
continue;
|
|
2108
|
+
}
|
|
2109
|
+
if (isValidElement2(child)) {
|
|
2110
|
+
const nested = child.props.children;
|
|
2111
|
+
if (nested != null) {
|
|
2112
|
+
result.push(...flattenColumnElements(nested));
|
|
2113
|
+
}
|
|
2114
|
+
}
|
|
2115
|
+
}
|
|
2116
|
+
return result;
|
|
2117
|
+
}
|
|
2022
2118
|
function extractColumnElements(header) {
|
|
2023
2119
|
if (!header) return [];
|
|
2024
2120
|
const { children } = header.props;
|
|
2025
|
-
return
|
|
2121
|
+
return flattenColumnElements(children);
|
|
2026
2122
|
}
|
|
2027
2123
|
|
|
2028
2124
|
// src/components/ui/table/components/Table/TableBody.tsx
|