@youp-grid/react 0.2.1 → 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 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;
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):not(.youp-grid__selection-cell),
168
- .youp-grid__header .youp-grid__cell--header-group:not(.youp-grid__cell--pinned-left):not(.youp-grid__cell--pinned-right):not(.youp-grid__selection-cell) {
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.1",
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.1"
31
+ "@youp-grid/core": "0.2.2"
32
32
  },
33
33
  "peerDependencies": {
34
34
  "react": ">=18.2.0"