@youp-grid/react 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/YoupGrid.js +165 -8
- package/dist/styles.css +36 -5
- package/dist/types.d.ts +1 -0
- package/package.json +2 -2
package/dist/YoupGrid.js
CHANGED
|
@@ -9,6 +9,9 @@ const DENSITY_ROW_HEIGHTS = {
|
|
|
9
9
|
comfortable: 46,
|
|
10
10
|
};
|
|
11
11
|
const SELECTION_COLUMN_WIDTH = 44;
|
|
12
|
+
const AUTOSIZE_CELL_EXTRA_WIDTH = 8;
|
|
13
|
+
const AUTOSIZE_CELL_BORDER_THRESHOLD = 6;
|
|
14
|
+
let autosizeMeasureCanvas;
|
|
12
15
|
export function YoupGrid(props) {
|
|
13
16
|
const controller = useYoupGrid(props);
|
|
14
17
|
const rowModel = controller.rowModel;
|
|
@@ -32,6 +35,7 @@ export function YoupGrid(props) {
|
|
|
32
35
|
const [columnChooserOpen, setColumnChooserOpen] = useState(false);
|
|
33
36
|
const [columnMenuOpenId, setColumnMenuOpenId] = useState();
|
|
34
37
|
const showRowSelectionColumn = props.showRowSelectionColumn ?? false;
|
|
38
|
+
const pinRowSelectionColumn = props.pinRowSelectionColumn ?? false;
|
|
35
39
|
const gridEditable = (props.editable ?? true) && !props.readOnly;
|
|
36
40
|
const displayRows = rowModel.displayRows;
|
|
37
41
|
const virtualRange = useMemo(() => {
|
|
@@ -75,9 +79,9 @@ export function YoupGrid(props) {
|
|
|
75
79
|
const someVisibleRowsSelected = selectedVisibleRowCount > 0 && !allVisibleRowsSelected;
|
|
76
80
|
const columnLayouts = useMemo(() => {
|
|
77
81
|
return getColumnLayouts(rowModel.visibleColumns, {
|
|
78
|
-
leftOffset: showRowSelectionColumn ? SELECTION_COLUMN_WIDTH : 0,
|
|
82
|
+
leftOffset: showRowSelectionColumn && pinRowSelectionColumn ? SELECTION_COLUMN_WIDTH : 0,
|
|
79
83
|
});
|
|
80
|
-
}, [rowModel.visibleColumns, showRowSelectionColumn]);
|
|
84
|
+
}, [pinRowSelectionColumn, rowModel.visibleColumns, showRowSelectionColumn]);
|
|
81
85
|
const visibleColumns = useMemo(() => columnLayouts.map((layout) => layout.column), [columnLayouts]);
|
|
82
86
|
const visibleRowIndexById = useMemo(() => {
|
|
83
87
|
return new Map(rowModel.visibleRows.map((row, index) => [row.id, index]));
|
|
@@ -313,6 +317,7 @@ export function YoupGrid(props) {
|
|
|
313
317
|
"youp-grid",
|
|
314
318
|
`youp-grid--density-${density}`,
|
|
315
319
|
!gridEditable ? "youp-grid--read-only" : "",
|
|
320
|
+
pinRowSelectionColumn ? "youp-grid--selection-column-pinned" : "",
|
|
316
321
|
props.className,
|
|
317
322
|
].filter(Boolean).join(" "),
|
|
318
323
|
style: gridStyle,
|
|
@@ -403,6 +408,14 @@ export function YoupGrid(props) {
|
|
|
403
408
|
}
|
|
404
409
|
},
|
|
405
410
|
resizeColumn: (width) => controller.setColumnWidth(layout.column.id, width),
|
|
411
|
+
autoSizeColumn: (event) => {
|
|
412
|
+
autoSizeColumnToFit({
|
|
413
|
+
event,
|
|
414
|
+
column: layout.column,
|
|
415
|
+
rows: rowModel.visibleRows,
|
|
416
|
+
resizeColumn: (width) => controller.setColumnWidth(layout.column.id, width),
|
|
417
|
+
});
|
|
418
|
+
},
|
|
406
419
|
showMenu: props.showColumnMenu ?? true,
|
|
407
420
|
menuOpen: columnMenuOpenId === layout.column.id,
|
|
408
421
|
toggleMenu: () => {
|
|
@@ -496,6 +509,14 @@ export function YoupGrid(props) {
|
|
|
496
509
|
},
|
|
497
510
|
});
|
|
498
511
|
},
|
|
512
|
+
autoSizeColumn: (event, column) => {
|
|
513
|
+
autoSizeColumnToFit({
|
|
514
|
+
event,
|
|
515
|
+
column,
|
|
516
|
+
rows: rowModel.visibleRows,
|
|
517
|
+
resizeColumn: (width) => controller.setColumnWidth(column.id, width),
|
|
518
|
+
});
|
|
519
|
+
},
|
|
499
520
|
applyCellValue,
|
|
500
521
|
startEditing: startEditingCell,
|
|
501
522
|
updateEditingDraft: (draftValue) => {
|
|
@@ -677,6 +698,7 @@ function renderHeaderCell(context) {
|
|
|
677
698
|
role: "columnheader",
|
|
678
699
|
style: getCellStyle(context.layout),
|
|
679
700
|
"aria-sort": context.sorted === "desc" ? "descending" : context.sorted === "asc" ? "ascending" : "none",
|
|
701
|
+
"data-youp-column-id": context.layout.column.id,
|
|
680
702
|
}, createElement("div", { className: "youp-grid__header-main" }, createElement("button", {
|
|
681
703
|
className: "youp-grid__sort-button",
|
|
682
704
|
type: "button",
|
|
@@ -736,6 +758,7 @@ function renderHeaderCell(context) {
|
|
|
736
758
|
resizeColumn: context.resizeColumn,
|
|
737
759
|
});
|
|
738
760
|
},
|
|
761
|
+
onDoubleClick: context.autoSizeColumn,
|
|
739
762
|
}));
|
|
740
763
|
}
|
|
741
764
|
function renderColumnMenu(context) {
|
|
@@ -886,6 +909,7 @@ function renderRow(context) {
|
|
|
886
909
|
meta,
|
|
887
910
|
setFocusedCell: context.setFocusedCell,
|
|
888
911
|
startFillHandle: context.startFillHandle,
|
|
912
|
+
autoSizeColumn: context.autoSizeColumn,
|
|
889
913
|
applyCellValue: context.applyCellValue,
|
|
890
914
|
startEditing: context.startEditing,
|
|
891
915
|
updateEditingDraft: context.updateEditingDraft,
|
|
@@ -935,6 +959,7 @@ function renderCell(context) {
|
|
|
935
959
|
const column = context.layout.column;
|
|
936
960
|
const value = column.accessor(context.row.original);
|
|
937
961
|
const editable = context.editable;
|
|
962
|
+
const cellAlign = getColumnAlign(column);
|
|
938
963
|
const cellContext = {
|
|
939
964
|
row: context.row,
|
|
940
965
|
column,
|
|
@@ -965,6 +990,7 @@ function renderCell(context) {
|
|
|
965
990
|
key: column.id,
|
|
966
991
|
className: getCellClassName([
|
|
967
992
|
"youp-grid__cell",
|
|
993
|
+
`youp-grid__cell--align-${cellAlign}`,
|
|
968
994
|
context.focused ? "youp-grid__cell--focused" : "",
|
|
969
995
|
context.selected ? "youp-grid__cell--range-selected" : "",
|
|
970
996
|
context.fillTargeted ? "youp-grid__cell--fill-target" : "",
|
|
@@ -985,7 +1011,11 @@ function renderCell(context) {
|
|
|
985
1011
|
event.currentTarget.focus({ preventScroll: true });
|
|
986
1012
|
context.setFocusedCell({ rowIndex: context.rowIndex, columnIndex: context.columnIndex }, event.shiftKey);
|
|
987
1013
|
},
|
|
988
|
-
onDoubleClick: () => {
|
|
1014
|
+
onDoubleClick: (event) => {
|
|
1015
|
+
if (isCellRightBorderDoubleClick(event)) {
|
|
1016
|
+
context.autoSizeColumn(event, column);
|
|
1017
|
+
return;
|
|
1018
|
+
}
|
|
989
1019
|
if (editable) {
|
|
990
1020
|
if (column.editor === "checkbox") {
|
|
991
1021
|
context.applyCellValue(cellState, !Boolean(value));
|
|
@@ -1013,6 +1043,18 @@ function renderCell(context) {
|
|
|
1013
1043
|
})
|
|
1014
1044
|
: undefined);
|
|
1015
1045
|
}
|
|
1046
|
+
function getColumnAlign(column) {
|
|
1047
|
+
if (column.align) {
|
|
1048
|
+
return column.align;
|
|
1049
|
+
}
|
|
1050
|
+
if (column.editor === "number") {
|
|
1051
|
+
return "right";
|
|
1052
|
+
}
|
|
1053
|
+
if (column.editor === "checkbox") {
|
|
1054
|
+
return "center";
|
|
1055
|
+
}
|
|
1056
|
+
return "left";
|
|
1057
|
+
}
|
|
1016
1058
|
function renderDefaultCellContent(context) {
|
|
1017
1059
|
if (context.cell.column.editor === "checkbox") {
|
|
1018
1060
|
return createElement("input", {
|
|
@@ -1338,6 +1380,100 @@ function startColumnResize(context) {
|
|
|
1338
1380
|
document.addEventListener("mousemove", handleMouseMove);
|
|
1339
1381
|
document.addEventListener("mouseup", handleMouseUp);
|
|
1340
1382
|
}
|
|
1383
|
+
function autoSizeColumnToFit(context) {
|
|
1384
|
+
context.event.preventDefault();
|
|
1385
|
+
context.event.stopPropagation();
|
|
1386
|
+
context.resizeColumn(getAutoSizeColumnWidth({
|
|
1387
|
+
anchor: context.event.currentTarget,
|
|
1388
|
+
column: context.column,
|
|
1389
|
+
rows: context.rows,
|
|
1390
|
+
}));
|
|
1391
|
+
}
|
|
1392
|
+
function getAutoSizeColumnWidth(context) {
|
|
1393
|
+
const metrics = getAutoSizeMetrics(context.anchor, context.column.id);
|
|
1394
|
+
const minWidth = context.column.minWidth ?? 64;
|
|
1395
|
+
const maxWidth = context.column.maxWidth ?? Number.MAX_SAFE_INTEGER;
|
|
1396
|
+
let width = measureAutoSizeText(context.column.headerName, metrics.headerFont) +
|
|
1397
|
+
metrics.headerHorizontalPadding +
|
|
1398
|
+
metrics.headerControlWidth +
|
|
1399
|
+
AUTOSIZE_CELL_EXTRA_WIDTH;
|
|
1400
|
+
for (const row of context.rows) {
|
|
1401
|
+
const text = getAutoSizeCellText(context.column, row.original);
|
|
1402
|
+
width = Math.max(width, measureAutoSizeText(text, metrics.cellFont) + metrics.cellHorizontalPadding + AUTOSIZE_CELL_EXTRA_WIDTH);
|
|
1403
|
+
}
|
|
1404
|
+
return Math.ceil(clamp(width, minWidth, maxWidth));
|
|
1405
|
+
}
|
|
1406
|
+
function getAutoSizeMetrics(anchor, columnId) {
|
|
1407
|
+
const anchorCell = anchor.closest(".youp-grid__cell");
|
|
1408
|
+
const root = anchor.closest(".youp-grid");
|
|
1409
|
+
const headerCell = anchorCell?.getAttribute("role") === "columnheader"
|
|
1410
|
+
? anchorCell
|
|
1411
|
+
: findColumnElement(root, "columnheader", columnId);
|
|
1412
|
+
const bodyCell = anchorCell?.getAttribute("role") === "gridcell"
|
|
1413
|
+
? anchorCell
|
|
1414
|
+
: findColumnElement(root, "gridcell", columnId);
|
|
1415
|
+
const headerCellStyle = headerCell ? window.getComputedStyle(headerCell) : undefined;
|
|
1416
|
+
const bodyCellStyle = bodyCell ? window.getComputedStyle(bodyCell) : headerCellStyle;
|
|
1417
|
+
const headerMain = headerCell?.querySelector(".youp-grid__header-main");
|
|
1418
|
+
const headerMainStyle = headerMain ? window.getComputedStyle(headerMain) : undefined;
|
|
1419
|
+
const menuButton = headerCell?.querySelector(".youp-grid__column-menu-button");
|
|
1420
|
+
const headerHorizontalPadding = headerCellStyle
|
|
1421
|
+
? getPixelValue(headerCellStyle.paddingLeft) + getPixelValue(headerCellStyle.paddingRight)
|
|
1422
|
+
: 24;
|
|
1423
|
+
const cellHorizontalPadding = bodyCellStyle
|
|
1424
|
+
? getPixelValue(bodyCellStyle.paddingLeft) + getPixelValue(bodyCellStyle.paddingRight)
|
|
1425
|
+
: headerHorizontalPadding;
|
|
1426
|
+
const headerControlWidth = menuButton
|
|
1427
|
+
? menuButton.offsetWidth + getPixelValue(headerMainStyle?.columnGap ?? headerMainStyle?.gap ?? "0")
|
|
1428
|
+
: 0;
|
|
1429
|
+
return {
|
|
1430
|
+
headerFont: headerCellStyle ? getFontValue(headerCellStyle) : "13px sans-serif",
|
|
1431
|
+
cellFont: bodyCellStyle ? getFontValue(bodyCellStyle) : "13px sans-serif",
|
|
1432
|
+
headerHorizontalPadding,
|
|
1433
|
+
cellHorizontalPadding,
|
|
1434
|
+
headerControlWidth,
|
|
1435
|
+
};
|
|
1436
|
+
}
|
|
1437
|
+
function findColumnElement(root, role, columnId) {
|
|
1438
|
+
if (!root) {
|
|
1439
|
+
return undefined;
|
|
1440
|
+
}
|
|
1441
|
+
return Array.from(root.querySelectorAll(`[role='${role}'][data-youp-column-id]`))
|
|
1442
|
+
.find((element) => element.dataset.youpColumnId === columnId);
|
|
1443
|
+
}
|
|
1444
|
+
function isCellRightBorderDoubleClick(event) {
|
|
1445
|
+
const rect = event.currentTarget.getBoundingClientRect();
|
|
1446
|
+
return Math.abs(rect.right - event.clientX) <= AUTOSIZE_CELL_BORDER_THRESHOLD;
|
|
1447
|
+
}
|
|
1448
|
+
function getAutoSizeCellText(column, row) {
|
|
1449
|
+
const text = formatCellValue(column, row, column.accessor(row));
|
|
1450
|
+
return text.length === 0 && column.placeholder ? column.placeholder : text;
|
|
1451
|
+
}
|
|
1452
|
+
function measureAutoSizeText(text, font) {
|
|
1453
|
+
if (typeof document === "undefined") {
|
|
1454
|
+
return text.length * 8;
|
|
1455
|
+
}
|
|
1456
|
+
autosizeMeasureCanvas ?? (autosizeMeasureCanvas = document.createElement("canvas"));
|
|
1457
|
+
const context = autosizeMeasureCanvas.getContext("2d");
|
|
1458
|
+
if (!context) {
|
|
1459
|
+
return text.length * 8;
|
|
1460
|
+
}
|
|
1461
|
+
context.font = font;
|
|
1462
|
+
return context.measureText(text).width;
|
|
1463
|
+
}
|
|
1464
|
+
function getFontValue(style) {
|
|
1465
|
+
return style.font || [
|
|
1466
|
+
style.fontStyle,
|
|
1467
|
+
style.fontVariant,
|
|
1468
|
+
style.fontWeight,
|
|
1469
|
+
`${style.fontSize}/${style.lineHeight}`,
|
|
1470
|
+
style.fontFamily,
|
|
1471
|
+
].join(" ");
|
|
1472
|
+
}
|
|
1473
|
+
function getPixelValue(value) {
|
|
1474
|
+
const parsed = Number.parseFloat(value);
|
|
1475
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
1476
|
+
}
|
|
1341
1477
|
function handleCellKeyDown(context) {
|
|
1342
1478
|
if (context.rowCount === 0 || context.columnCount === 0) {
|
|
1343
1479
|
return;
|
|
@@ -1420,10 +1556,15 @@ function handleCellKeyDown(context) {
|
|
|
1420
1556
|
}
|
|
1421
1557
|
return;
|
|
1422
1558
|
}
|
|
1423
|
-
if (
|
|
1559
|
+
if (isTextEditingKey(context.event)) {
|
|
1424
1560
|
if (context.cell.editable && context.cell.column.editor !== "checkbox") {
|
|
1425
|
-
context.event
|
|
1426
|
-
|
|
1561
|
+
if (canUseKeyAsInitialDraft(context.event)) {
|
|
1562
|
+
context.event.preventDefault();
|
|
1563
|
+
context.startEditing(createEditingCell(context.cell, context.event.key));
|
|
1564
|
+
}
|
|
1565
|
+
else {
|
|
1566
|
+
context.startEditing(createEditingCell(context.cell, ""));
|
|
1567
|
+
}
|
|
1427
1568
|
}
|
|
1428
1569
|
return;
|
|
1429
1570
|
}
|
|
@@ -1888,8 +2029,24 @@ function getCellTitle(meta, disabledReason, editable) {
|
|
|
1888
2029
|
}
|
|
1889
2030
|
return undefined;
|
|
1890
2031
|
}
|
|
1891
|
-
function
|
|
1892
|
-
|
|
2032
|
+
function isTextEditingKey(event) {
|
|
2033
|
+
if (event.metaKey || event.ctrlKey || event.altKey) {
|
|
2034
|
+
return false;
|
|
2035
|
+
}
|
|
2036
|
+
return event.key.length === 1 || isCompositionEditingKey(event);
|
|
2037
|
+
}
|
|
2038
|
+
function canUseKeyAsInitialDraft(event) {
|
|
2039
|
+
return event.key.length === 1 && isAsciiPrintableKey(event.key) && !isCompositionEditingKey(event);
|
|
2040
|
+
}
|
|
2041
|
+
function isCompositionEditingKey(event) {
|
|
2042
|
+
return (event.nativeEvent.isComposing ||
|
|
2043
|
+
event.key === "Process" ||
|
|
2044
|
+
event.key === "Dead" ||
|
|
2045
|
+
event.key === "Unidentified" ||
|
|
2046
|
+
event.keyCode === 229);
|
|
2047
|
+
}
|
|
2048
|
+
function isAsciiPrintableKey(key) {
|
|
2049
|
+
return key >= " " && key <= "~";
|
|
1893
2050
|
}
|
|
1894
2051
|
function isUndoShortcut(event) {
|
|
1895
2052
|
return (event.metaKey || event.ctrlKey) && !event.altKey && !event.shiftKey && event.key.toLowerCase() === "z";
|
package/dist/styles.css
CHANGED
|
@@ -164,11 +164,15 @@
|
|
|
164
164
|
--youp-grid-header-scroll-left: 0px;
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
-
.youp-grid__header .youp-grid__cell--header:not(.youp-grid__cell--pinned-left):not(.youp-grid__cell--pinned-right)
|
|
168
|
-
.youp-grid__header .youp-grid__cell--header-group:not(.youp-grid__cell--pinned-left):not(.youp-grid__cell--pinned-right)
|
|
167
|
+
.youp-grid__header .youp-grid__cell--header:not(.youp-grid__cell--pinned-left):not(.youp-grid__cell--pinned-right),
|
|
168
|
+
.youp-grid__header .youp-grid__cell--header-group:not(.youp-grid__cell--pinned-left):not(.youp-grid__cell--pinned-right) {
|
|
169
169
|
transform: translateX(calc(-1 * var(--youp-grid-header-scroll-left)));
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
+
.youp-grid--selection-column-pinned .youp-grid__header .youp-grid__selection-cell {
|
|
173
|
+
transform: none;
|
|
174
|
+
}
|
|
175
|
+
|
|
172
176
|
.youp-grid__row--header {
|
|
173
177
|
background: var(--youp-grid-header);
|
|
174
178
|
}
|
|
@@ -212,9 +216,6 @@
|
|
|
212
216
|
}
|
|
213
217
|
|
|
214
218
|
.youp-grid__selection-cell {
|
|
215
|
-
position: sticky;
|
|
216
|
-
left: 0;
|
|
217
|
-
z-index: 3;
|
|
218
219
|
display: grid;
|
|
219
220
|
place-items: center;
|
|
220
221
|
min-width: 44px;
|
|
@@ -222,6 +223,12 @@
|
|
|
222
223
|
background: #fff;
|
|
223
224
|
}
|
|
224
225
|
|
|
226
|
+
.youp-grid--selection-column-pinned .youp-grid__selection-cell {
|
|
227
|
+
position: sticky;
|
|
228
|
+
left: 0;
|
|
229
|
+
z-index: 3;
|
|
230
|
+
}
|
|
231
|
+
|
|
225
232
|
.youp-grid__cell.youp-grid__selection-cell {
|
|
226
233
|
min-width: 44px;
|
|
227
234
|
}
|
|
@@ -286,6 +293,18 @@
|
|
|
286
293
|
white-space: nowrap;
|
|
287
294
|
}
|
|
288
295
|
|
|
296
|
+
.youp-grid__cell--align-left {
|
|
297
|
+
text-align: left;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
.youp-grid__cell--align-center {
|
|
301
|
+
text-align: center;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
.youp-grid__cell--align-right {
|
|
305
|
+
text-align: right;
|
|
306
|
+
}
|
|
307
|
+
|
|
289
308
|
.youp-grid--read-only .youp-grid__cell {
|
|
290
309
|
cursor: default;
|
|
291
310
|
}
|
|
@@ -408,6 +427,18 @@
|
|
|
408
427
|
outline: none;
|
|
409
428
|
}
|
|
410
429
|
|
|
430
|
+
.youp-grid__cell--align-left .youp-grid__cell-editor {
|
|
431
|
+
text-align: left;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
.youp-grid__cell--align-center .youp-grid__cell-editor {
|
|
435
|
+
text-align: center;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
.youp-grid__cell--align-right .youp-grid__cell-editor {
|
|
439
|
+
text-align: right;
|
|
440
|
+
}
|
|
441
|
+
|
|
411
442
|
.youp-grid__cell-editor--select {
|
|
412
443
|
padding-right: 24px;
|
|
413
444
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -118,6 +118,7 @@ export type YoupGridProps<TRow> = YoupGridOptions<TRow> & {
|
|
|
118
118
|
showAggregationFooter?: boolean;
|
|
119
119
|
showPagination?: boolean;
|
|
120
120
|
showRowSelectionColumn?: boolean;
|
|
121
|
+
pinRowSelectionColumn?: boolean;
|
|
121
122
|
csvFileName?: string;
|
|
122
123
|
density?: YoupGridDensity;
|
|
123
124
|
defaultDensity?: YoupGridDensity;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@youp-grid/react",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "React adapter for Youp Grid.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"build": "tsc -p tsconfig.build.json && cp src/styles.css dist/styles.css"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@youp-grid/core": "0.2.
|
|
31
|
+
"@youp-grid/core": "0.2.2"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
34
|
"react": ">=18.2.0"
|