@youp-grid/react 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/YoupGrid.js +387 -68
- package/dist/index.d.ts +1 -1
- package/dist/styles.css +121 -0
- package/dist/types.d.ts +33 -1
- package/package.json +2 -2
package/dist/YoupGrid.js
CHANGED
|
@@ -18,6 +18,7 @@ export function YoupGrid(props) {
|
|
|
18
18
|
const viewportHeight = normalizeHeight(props.height) ?? 420;
|
|
19
19
|
const loading = props.loading ?? controller.state.remoteRequest?.status === "loading";
|
|
20
20
|
const infiniteScrollLoading = props.infiniteScrollLoading ?? loading;
|
|
21
|
+
const headerRef = useRef(null);
|
|
21
22
|
const bodyRef = useRef(null);
|
|
22
23
|
const lastRowsEndReachedKeyRef = useRef();
|
|
23
24
|
const skipNextBlurCommitRef = useRef(false);
|
|
@@ -31,6 +32,7 @@ export function YoupGrid(props) {
|
|
|
31
32
|
const [columnChooserOpen, setColumnChooserOpen] = useState(false);
|
|
32
33
|
const [columnMenuOpenId, setColumnMenuOpenId] = useState();
|
|
33
34
|
const showRowSelectionColumn = props.showRowSelectionColumn ?? false;
|
|
35
|
+
const gridEditable = (props.editable ?? true) && !props.readOnly;
|
|
34
36
|
const displayRows = rowModel.displayRows;
|
|
35
37
|
const virtualRange = useMemo(() => {
|
|
36
38
|
return getVirtualRange({
|
|
@@ -108,6 +110,44 @@ export function YoupGrid(props) {
|
|
|
108
110
|
return row ? { row, displayIndex: item.index } : undefined;
|
|
109
111
|
})
|
|
110
112
|
.filter((item) => Boolean(item));
|
|
113
|
+
const getCellEditContext = (row, rowIndex, column) => {
|
|
114
|
+
return {
|
|
115
|
+
row: row.original,
|
|
116
|
+
rowNode: row,
|
|
117
|
+
rowId: row.id,
|
|
118
|
+
rowIndex,
|
|
119
|
+
column,
|
|
120
|
+
columnId: column.id,
|
|
121
|
+
value: column.accessor(row.original),
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
const canEditGridCell = (row, rowIndex, column) => {
|
|
125
|
+
if (!gridEditable || column.editable === false) {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
return props.canEditCell?.(getCellEditContext(row, rowIndex, column)) ?? true;
|
|
129
|
+
};
|
|
130
|
+
const getGridCellMeta = (row, rowIndex, column) => {
|
|
131
|
+
return (props.getCellMeta?.(getCellEditContext(row, rowIndex, column)) ??
|
|
132
|
+
props.cellMeta?.[`${row.id}:${column.id}`]);
|
|
133
|
+
};
|
|
134
|
+
const createGridCellValueChange = (cell, value) => {
|
|
135
|
+
if (!cell.editable) {
|
|
136
|
+
return undefined;
|
|
137
|
+
}
|
|
138
|
+
if (Object.is(value, cell.value)) {
|
|
139
|
+
return undefined;
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
row: cell.row.original,
|
|
143
|
+
rowId: cell.row.id,
|
|
144
|
+
rowIndex: cell.rowIndex,
|
|
145
|
+
column: cell.column,
|
|
146
|
+
columnId: cell.column.id,
|
|
147
|
+
value,
|
|
148
|
+
previousValue: cell.value,
|
|
149
|
+
};
|
|
150
|
+
};
|
|
111
151
|
useEffect(() => {
|
|
112
152
|
if (focusedRowIndex >= rowModel.visibleRows.length) {
|
|
113
153
|
setFocusedRowIndex(Math.max(0, rowModel.visibleRows.length - 1));
|
|
@@ -159,7 +199,7 @@ export function YoupGrid(props) {
|
|
|
159
199
|
if (changes.length === 0) {
|
|
160
200
|
return;
|
|
161
201
|
}
|
|
162
|
-
if (source === "edit" || source === "paste" || source === "fill") {
|
|
202
|
+
if (source === "edit" || source === "paste" || source === "fill" || source === "delete") {
|
|
163
203
|
valueHistoryRef.current = pushValueHistoryEntry(valueHistoryRef.current, {
|
|
164
204
|
changes: changes.map((change) => ({
|
|
165
205
|
rowId: change.rowId,
|
|
@@ -170,18 +210,33 @@ export function YoupGrid(props) {
|
|
|
170
210
|
})),
|
|
171
211
|
}, { maxEntries: VALUE_HISTORY_LIMIT });
|
|
172
212
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
213
|
+
const emittedChanges = changes.map((change) => ({
|
|
214
|
+
...change,
|
|
215
|
+
source,
|
|
216
|
+
}));
|
|
217
|
+
for (const change of emittedChanges) {
|
|
218
|
+
props.onCellValueChange?.(change);
|
|
219
|
+
}
|
|
220
|
+
if (source === "paste" || source === "fill") {
|
|
221
|
+
props.onCellsValueChange?.({
|
|
222
|
+
changes: emittedChanges,
|
|
223
|
+
source: source,
|
|
177
224
|
});
|
|
178
225
|
}
|
|
179
226
|
};
|
|
227
|
+
const applyCellValue = (cell, value) => {
|
|
228
|
+
const change = createGridCellValueChange(cell, value);
|
|
229
|
+
if (!change) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
applyCellValueChanges([change], "edit");
|
|
233
|
+
};
|
|
180
234
|
const applyValueHistoryEntry = (entry, source) => {
|
|
181
235
|
applyCellValueChanges(getHistoryEntryValueChanges({
|
|
182
236
|
entry,
|
|
183
237
|
rowModel,
|
|
184
238
|
source,
|
|
239
|
+
canEditCell: canEditGridCell,
|
|
185
240
|
}), source);
|
|
186
241
|
};
|
|
187
242
|
const undoCellValueChange = () => {
|
|
@@ -202,19 +257,28 @@ export function YoupGrid(props) {
|
|
|
202
257
|
applyValueHistoryEntry(result.entry, "redo");
|
|
203
258
|
return true;
|
|
204
259
|
};
|
|
205
|
-
const commitEditingValue = (cell,
|
|
206
|
-
if (
|
|
260
|
+
const commitEditingValue = (cell, reason = "enter") => {
|
|
261
|
+
if (reason === "blur" && skipNextBlurCommitRef.current) {
|
|
207
262
|
skipNextBlurCommitRef.current = false;
|
|
208
263
|
return;
|
|
209
264
|
}
|
|
210
|
-
if (
|
|
265
|
+
if (reason !== "blur") {
|
|
211
266
|
skipNextBlurCommitRef.current = true;
|
|
212
267
|
}
|
|
213
|
-
commitEditingCell({
|
|
268
|
+
const change = commitEditingCell({
|
|
214
269
|
cell,
|
|
215
270
|
rowModel,
|
|
216
|
-
|
|
271
|
+
canEditCell: canEditGridCell,
|
|
217
272
|
});
|
|
273
|
+
if (change) {
|
|
274
|
+
if (!Object.is(change.value, change.previousValue)) {
|
|
275
|
+
applyCellValueChanges([change], "edit");
|
|
276
|
+
}
|
|
277
|
+
props.onCellEditCommit?.({
|
|
278
|
+
...change,
|
|
279
|
+
reason,
|
|
280
|
+
});
|
|
281
|
+
}
|
|
218
282
|
setEditingCell(undefined);
|
|
219
283
|
};
|
|
220
284
|
const setFocusedCell = (cell, extendSelection = false, selectionAnchor) => {
|
|
@@ -245,7 +309,12 @@ export function YoupGrid(props) {
|
|
|
245
309
|
controller.setSelectedRows(currentSelectedRowIds.filter((rowId) => !visibleRowIdSet.has(rowId)));
|
|
246
310
|
};
|
|
247
311
|
return createElement("div", {
|
|
248
|
-
className: [
|
|
312
|
+
className: [
|
|
313
|
+
"youp-grid",
|
|
314
|
+
`youp-grid--density-${density}`,
|
|
315
|
+
!gridEditable ? "youp-grid--read-only" : "",
|
|
316
|
+
props.className,
|
|
317
|
+
].filter(Boolean).join(" "),
|
|
249
318
|
style: gridStyle,
|
|
250
319
|
}, renderColumnToolbar({
|
|
251
320
|
showColumnChooser: props.showColumnChooser ?? true,
|
|
@@ -268,12 +337,16 @@ export function YoupGrid(props) {
|
|
|
268
337
|
}),
|
|
269
338
|
});
|
|
270
339
|
},
|
|
340
|
+
}), renderDisabledReason({
|
|
341
|
+
enabled: !gridEditable,
|
|
342
|
+
reason: props.disabledReason,
|
|
271
343
|
}), createElement("div", {
|
|
272
344
|
className: "youp-grid__viewport",
|
|
273
345
|
role: "grid",
|
|
274
346
|
"aria-rowcount": displayRows.length,
|
|
275
347
|
"aria-colcount": rowModel.visibleColumns.length + (showRowSelectionColumn ? 1 : 0),
|
|
276
348
|
"aria-busy": loading || undefined,
|
|
349
|
+
"aria-readonly": !gridEditable || undefined,
|
|
277
350
|
onCopy: (event) => {
|
|
278
351
|
if (editingCell) {
|
|
279
352
|
return;
|
|
@@ -287,7 +360,7 @@ export function YoupGrid(props) {
|
|
|
287
360
|
});
|
|
288
361
|
},
|
|
289
362
|
onPaste: (event) => {
|
|
290
|
-
if (editingCell) {
|
|
363
|
+
if (editingCell || !gridEditable) {
|
|
291
364
|
return;
|
|
292
365
|
}
|
|
293
366
|
handleGridPaste({
|
|
@@ -296,10 +369,11 @@ export function YoupGrid(props) {
|
|
|
296
369
|
selectionRange,
|
|
297
370
|
rows: rowModel.visibleRows,
|
|
298
371
|
columns: visibleColumns,
|
|
372
|
+
canEditCell: canEditGridCell,
|
|
299
373
|
applyCellValueChanges,
|
|
300
374
|
});
|
|
301
375
|
},
|
|
302
|
-
}, createElement("div", { className: "youp-grid__header", role: "rowgroup" }, hasHeaderGroups
|
|
376
|
+
}, createElement("div", { className: "youp-grid__header", role: "rowgroup", ref: headerRef }, hasHeaderGroups
|
|
303
377
|
? createElement("div", { className: "youp-grid__row youp-grid__row--header-group", role: "row" }, showRowSelectionColumn
|
|
304
378
|
? renderSelectionHeaderGroupCell()
|
|
305
379
|
: undefined, headerGroupLayouts.map((layout) => renderHeaderGroupCell(layout)))
|
|
@@ -345,6 +419,9 @@ export function YoupGrid(props) {
|
|
|
345
419
|
ref: bodyRef,
|
|
346
420
|
style: { height: viewportHeight },
|
|
347
421
|
onScroll: (event) => {
|
|
422
|
+
if (headerRef.current) {
|
|
423
|
+
headerRef.current.style.setProperty("--youp-grid-header-scroll-left", `${event.currentTarget.scrollLeft}px`);
|
|
424
|
+
}
|
|
348
425
|
setScrollTop(event.currentTarget.scrollTop);
|
|
349
426
|
},
|
|
350
427
|
}, rowModel.visibleRows.length === 0 && !props.loading && !props.error
|
|
@@ -383,10 +460,16 @@ export function YoupGrid(props) {
|
|
|
383
460
|
selectionRange,
|
|
384
461
|
fillRange,
|
|
385
462
|
editingCell,
|
|
386
|
-
editable:
|
|
463
|
+
editable: gridEditable,
|
|
464
|
+
disabledReason: props.disabledReason,
|
|
465
|
+
canEditCell: canEditGridCell,
|
|
466
|
+
getCellMeta: getGridCellMeta,
|
|
387
467
|
setRowSelected: (selected) => controller.setRowSelected(row.id, selected),
|
|
388
468
|
setFocusedCell,
|
|
389
469
|
startFillHandle: (event) => {
|
|
470
|
+
if (!gridEditable) {
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
390
473
|
const sourceRange = normalizeCellRange(selectionRange ?? {
|
|
391
474
|
anchor: focusedCell,
|
|
392
475
|
focus: focusedCell,
|
|
@@ -403,6 +486,7 @@ export function YoupGrid(props) {
|
|
|
403
486
|
targetRange,
|
|
404
487
|
rows: rowModel.visibleRows,
|
|
405
488
|
columns: visibleColumns,
|
|
489
|
+
canEditCell: canEditGridCell,
|
|
406
490
|
applyCellValueChanges,
|
|
407
491
|
});
|
|
408
492
|
const nextSelectionRange = getFillSelectionRange(sourceRange, targetRange);
|
|
@@ -412,6 +496,7 @@ export function YoupGrid(props) {
|
|
|
412
496
|
},
|
|
413
497
|
});
|
|
414
498
|
},
|
|
499
|
+
applyCellValue,
|
|
415
500
|
startEditing: startEditingCell,
|
|
416
501
|
updateEditingDraft: (draftValue) => {
|
|
417
502
|
setEditingCell((current) => current ? { ...current, draftValue } : current);
|
|
@@ -434,6 +519,17 @@ export function YoupGrid(props) {
|
|
|
434
519
|
startEditing: startEditingCell,
|
|
435
520
|
commitEditing: commitEditingValue,
|
|
436
521
|
cancelEditing: cancelEditingCell,
|
|
522
|
+
applyCellValue,
|
|
523
|
+
deleteCellValues: () => {
|
|
524
|
+
deleteGridCellValues({
|
|
525
|
+
focusedCell,
|
|
526
|
+
selectionRange,
|
|
527
|
+
rows: rowModel.visibleRows,
|
|
528
|
+
columns: visibleColumns,
|
|
529
|
+
canEditCell: canEditGridCell,
|
|
530
|
+
applyCellValueChanges,
|
|
531
|
+
});
|
|
532
|
+
},
|
|
437
533
|
undoCellValueChange,
|
|
438
534
|
redoCellValueChange,
|
|
439
535
|
toggleSelected: () => controller.toggleRowSelected(row.id),
|
|
@@ -473,6 +569,12 @@ function renderGridOverlay(context) {
|
|
|
473
569
|
}
|
|
474
570
|
return undefined;
|
|
475
571
|
}
|
|
572
|
+
function renderDisabledReason(context) {
|
|
573
|
+
if (!context.enabled || context.reason == null) {
|
|
574
|
+
return undefined;
|
|
575
|
+
}
|
|
576
|
+
return createElement("div", { className: "youp-grid__disabled-reason", role: "status" }, context.reason);
|
|
577
|
+
}
|
|
476
578
|
function renderAggregationFooter(context) {
|
|
477
579
|
if (!context.enabled) {
|
|
478
580
|
return undefined;
|
|
@@ -761,7 +863,10 @@ function renderRow(context) {
|
|
|
761
863
|
const fillTargeted = context.fillRange
|
|
762
864
|
? isCellInNormalizedRange(context.rowIndex, columnIndex, context.fillRange)
|
|
763
865
|
: false;
|
|
866
|
+
const editable = context.canEditCell(context.row, context.rowIndex, layout.column);
|
|
867
|
+
const meta = context.getCellMeta(context.row, context.rowIndex, layout.column);
|
|
764
868
|
const showFillHandle = !context.editingCell &&
|
|
869
|
+
editable &&
|
|
765
870
|
context.rowIndex === activeRange.endRowIndex &&
|
|
766
871
|
columnIndex === activeRange.endColumnIndex;
|
|
767
872
|
return renderCell({
|
|
@@ -776,9 +881,12 @@ function renderRow(context) {
|
|
|
776
881
|
showFillHandle,
|
|
777
882
|
editing,
|
|
778
883
|
editingCell: context.editingCell,
|
|
779
|
-
editable
|
|
884
|
+
editable,
|
|
885
|
+
disabledReason: context.disabledReason,
|
|
886
|
+
meta,
|
|
780
887
|
setFocusedCell: context.setFocusedCell,
|
|
781
888
|
startFillHandle: context.startFillHandle,
|
|
889
|
+
applyCellValue: context.applyCellValue,
|
|
782
890
|
startEditing: context.startEditing,
|
|
783
891
|
updateEditingDraft: context.updateEditingDraft,
|
|
784
892
|
cancelEditing: context.cancelEditing,
|
|
@@ -826,13 +934,15 @@ function shouldIgnoreRowMouseEvent(event) {
|
|
|
826
934
|
function renderCell(context) {
|
|
827
935
|
const column = context.layout.column;
|
|
828
936
|
const value = column.accessor(context.row.original);
|
|
829
|
-
const editable = context.editable
|
|
937
|
+
const editable = context.editable;
|
|
830
938
|
const cellContext = {
|
|
831
939
|
row: context.row,
|
|
832
940
|
column,
|
|
833
941
|
value,
|
|
834
942
|
editing: context.editing,
|
|
835
943
|
focused: context.focused,
|
|
944
|
+
editable,
|
|
945
|
+
meta: context.meta,
|
|
836
946
|
};
|
|
837
947
|
const cellState = {
|
|
838
948
|
row: context.row,
|
|
@@ -841,10 +951,16 @@ function renderCell(context) {
|
|
|
841
951
|
columnIndex: context.columnIndex,
|
|
842
952
|
value,
|
|
843
953
|
editable,
|
|
954
|
+
meta: context.meta,
|
|
844
955
|
};
|
|
845
956
|
const cellContent = context.renderCell
|
|
846
957
|
? context.renderCell(cellContext)
|
|
847
|
-
:
|
|
958
|
+
: renderDefaultCellContent({
|
|
959
|
+
cell: cellState,
|
|
960
|
+
row: context.row.original,
|
|
961
|
+
disabledReason: context.disabledReason,
|
|
962
|
+
applyCellValue: context.applyCellValue,
|
|
963
|
+
});
|
|
848
964
|
return createElement("div", {
|
|
849
965
|
key: column.id,
|
|
850
966
|
className: getCellClassName([
|
|
@@ -853,10 +969,14 @@ function renderCell(context) {
|
|
|
853
969
|
context.selected ? "youp-grid__cell--range-selected" : "",
|
|
854
970
|
context.fillTargeted ? "youp-grid__cell--fill-target" : "",
|
|
855
971
|
context.editing ? "youp-grid__cell--editing" : "",
|
|
972
|
+
!editable ? "youp-grid__cell--disabled" : "",
|
|
973
|
+
context.meta ? `youp-grid__cell--status-${context.meta.status}` : "",
|
|
856
974
|
].filter(Boolean).join(" "), context.layout),
|
|
857
975
|
role: "gridcell",
|
|
858
976
|
tabIndex: context.focused && !context.editing ? 0 : -1,
|
|
977
|
+
title: getCellTitle(context.meta, context.disabledReason, editable),
|
|
859
978
|
"aria-colindex": context.columnIndex + context.ariaColumnOffset + 1,
|
|
979
|
+
"aria-readonly": !editable || undefined,
|
|
860
980
|
"data-youp-row-index": context.rowIndex,
|
|
861
981
|
"data-youp-column-index": context.columnIndex,
|
|
862
982
|
"data-youp-column-id": column.id,
|
|
@@ -867,34 +987,107 @@ function renderCell(context) {
|
|
|
867
987
|
},
|
|
868
988
|
onDoubleClick: () => {
|
|
869
989
|
if (editable) {
|
|
870
|
-
|
|
990
|
+
if (column.editor === "checkbox") {
|
|
991
|
+
context.applyCellValue(cellState, !Boolean(value));
|
|
992
|
+
}
|
|
993
|
+
else {
|
|
994
|
+
context.startEditing(createEditingCell(cellState, value));
|
|
995
|
+
}
|
|
871
996
|
}
|
|
872
997
|
},
|
|
873
998
|
onKeyDown: (event) => context.onKeyDown(event, cellState),
|
|
874
999
|
}, context.editing
|
|
875
|
-
?
|
|
876
|
-
|
|
1000
|
+
? renderCellEditor({
|
|
1001
|
+
cell: cellState,
|
|
1002
|
+
editingCell: context.editingCell,
|
|
1003
|
+
updateEditingDraft: context.updateEditingDraft,
|
|
1004
|
+
commitEditing: context.commitEditing,
|
|
1005
|
+
onKeyDown: context.onKeyDown,
|
|
1006
|
+
})
|
|
1007
|
+
: cellContent, renderCellStatus(context.meta), !context.editing && context.showFillHandle
|
|
1008
|
+
? createElement("span", {
|
|
1009
|
+
className: "youp-grid__fill-handle",
|
|
1010
|
+
role: "button",
|
|
1011
|
+
"aria-label": "Fill selection",
|
|
1012
|
+
onMouseDown: context.startFillHandle,
|
|
1013
|
+
})
|
|
1014
|
+
: undefined);
|
|
1015
|
+
}
|
|
1016
|
+
function renderDefaultCellContent(context) {
|
|
1017
|
+
if (context.cell.column.editor === "checkbox") {
|
|
1018
|
+
return createElement("input", {
|
|
1019
|
+
className: "youp-grid__cell-checkbox",
|
|
1020
|
+
type: "checkbox",
|
|
1021
|
+
checked: Boolean(context.cell.value),
|
|
1022
|
+
disabled: !context.cell.editable,
|
|
1023
|
+
title: getCellTitle(context.cell.meta, context.disabledReason, context.cell.editable),
|
|
1024
|
+
"aria-label": context.cell.column.headerName,
|
|
1025
|
+
onChange: (event) => {
|
|
1026
|
+
context.applyCellValue(context.cell, event.currentTarget.checked);
|
|
1027
|
+
},
|
|
1028
|
+
onClick: (event) => {
|
|
1029
|
+
event.stopPropagation();
|
|
1030
|
+
},
|
|
1031
|
+
onKeyDown: (event) => {
|
|
1032
|
+
event.stopPropagation();
|
|
1033
|
+
},
|
|
1034
|
+
});
|
|
1035
|
+
}
|
|
1036
|
+
const text = formatCellValue(context.cell.column, context.row, context.cell.value);
|
|
1037
|
+
const placeholder = context.cell.column.placeholder;
|
|
1038
|
+
const hasPlaceholder = text.length === 0 && Boolean(placeholder);
|
|
1039
|
+
return createElement("span", { className: hasPlaceholder ? "youp-grid__cell-placeholder" : undefined }, hasPlaceholder ? placeholder : text);
|
|
1040
|
+
}
|
|
1041
|
+
function renderCellEditor(context) {
|
|
1042
|
+
if (context.cell.column.editor === "select") {
|
|
1043
|
+
const options = normalizeEditorOptions(context.cell.column.options);
|
|
1044
|
+
return createElement("select", {
|
|
1045
|
+
className: "youp-grid__cell-editor youp-grid__cell-editor--select",
|
|
877
1046
|
value: context.editingCell?.draftValue ?? "",
|
|
878
1047
|
autoFocus: true,
|
|
1048
|
+
disabled: !context.cell.editable,
|
|
879
1049
|
onChange: (event) => {
|
|
880
1050
|
context.updateEditingDraft(event.currentTarget.value);
|
|
881
1051
|
},
|
|
882
1052
|
onBlur: (event) => {
|
|
883
|
-
context.commitEditing(createEditingCell(
|
|
1053
|
+
context.commitEditing(createEditingCell(context.cell, event.currentTarget.value), "blur");
|
|
884
1054
|
},
|
|
885
1055
|
onKeyDown: (event) => {
|
|
886
1056
|
event.stopPropagation();
|
|
887
|
-
context.onKeyDown(event,
|
|
1057
|
+
context.onKeyDown(event, context.cell);
|
|
888
1058
|
},
|
|
889
|
-
}
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
:
|
|
1059
|
+
}, context.cell.column.placeholder
|
|
1060
|
+
? createElement("option", { key: "__placeholder", value: "", disabled: true }, context.cell.column.placeholder)
|
|
1061
|
+
: undefined, options.map((option) => createElement("option", { key: option.inputValue, value: option.inputValue }, option.label)));
|
|
1062
|
+
}
|
|
1063
|
+
return createElement("input", {
|
|
1064
|
+
className: "youp-grid__cell-editor",
|
|
1065
|
+
type: context.cell.column.editor === "number" ? "number" : "text",
|
|
1066
|
+
value: context.editingCell?.draftValue ?? "",
|
|
1067
|
+
placeholder: context.cell.column.placeholder,
|
|
1068
|
+
autoFocus: true,
|
|
1069
|
+
disabled: !context.cell.editable,
|
|
1070
|
+
onChange: (event) => {
|
|
1071
|
+
context.updateEditingDraft(event.currentTarget.value);
|
|
1072
|
+
},
|
|
1073
|
+
onBlur: (event) => {
|
|
1074
|
+
context.commitEditing(createEditingCell(context.cell, event.currentTarget.value), "blur");
|
|
1075
|
+
},
|
|
1076
|
+
onKeyDown: (event) => {
|
|
1077
|
+
event.stopPropagation();
|
|
1078
|
+
context.onKeyDown(event, context.cell);
|
|
1079
|
+
},
|
|
1080
|
+
});
|
|
1081
|
+
}
|
|
1082
|
+
function renderCellStatus(meta) {
|
|
1083
|
+
if (!meta) {
|
|
1084
|
+
return undefined;
|
|
1085
|
+
}
|
|
1086
|
+
return createElement("span", {
|
|
1087
|
+
className: `youp-grid__cell-status youp-grid__cell-status--${meta.status}`,
|
|
1088
|
+
title: typeof meta.message === "string" ? meta.message : undefined,
|
|
1089
|
+
"aria-hidden": true,
|
|
1090
|
+
});
|
|
898
1091
|
}
|
|
899
1092
|
function renderColumnToolbar(context) {
|
|
900
1093
|
if (!context.showColumnChooser && !context.showCsvExport && !context.showDensityControl) {
|
|
@@ -1161,11 +1354,11 @@ function handleCellKeyDown(context) {
|
|
|
1161
1354
|
}
|
|
1162
1355
|
if (context.event.key === "Enter") {
|
|
1163
1356
|
context.event.preventDefault();
|
|
1164
|
-
context.commitEditing(editingCell);
|
|
1357
|
+
context.commitEditing(editingCell, "enter");
|
|
1165
1358
|
moveFocusedCell({
|
|
1166
1359
|
...context,
|
|
1167
1360
|
nextCell: {
|
|
1168
|
-
rowIndex: clamp(context.cell.rowIndex + 1, 0, context.rowCount - 1),
|
|
1361
|
+
rowIndex: clamp(context.cell.rowIndex + (context.event.shiftKey ? -1 : 1), 0, context.rowCount - 1),
|
|
1169
1362
|
columnIndex: context.cell.columnIndex,
|
|
1170
1363
|
},
|
|
1171
1364
|
});
|
|
@@ -1173,7 +1366,7 @@ function handleCellKeyDown(context) {
|
|
|
1173
1366
|
}
|
|
1174
1367
|
if (context.event.key === "Tab") {
|
|
1175
1368
|
context.event.preventDefault();
|
|
1176
|
-
context.commitEditing(editingCell);
|
|
1369
|
+
context.commitEditing(editingCell, "tab");
|
|
1177
1370
|
moveFocusedCell({
|
|
1178
1371
|
...context,
|
|
1179
1372
|
nextCell: getNextTabCell(context.cell, context.rowCount, context.columnCount, context.event.shiftKey),
|
|
@@ -1184,23 +1377,41 @@ function handleCellKeyDown(context) {
|
|
|
1184
1377
|
}
|
|
1185
1378
|
if (isUndoShortcut(context.event)) {
|
|
1186
1379
|
context.event.preventDefault();
|
|
1187
|
-
context.
|
|
1380
|
+
if (context.cell.editable) {
|
|
1381
|
+
context.undoCellValueChange();
|
|
1382
|
+
}
|
|
1188
1383
|
return;
|
|
1189
1384
|
}
|
|
1190
1385
|
if (isRedoShortcut(context.event)) {
|
|
1191
1386
|
context.event.preventDefault();
|
|
1192
|
-
context.
|
|
1387
|
+
if (context.cell.editable) {
|
|
1388
|
+
context.redoCellValueChange();
|
|
1389
|
+
}
|
|
1390
|
+
return;
|
|
1391
|
+
}
|
|
1392
|
+
if (context.event.key === "Delete") {
|
|
1393
|
+
context.event.preventDefault();
|
|
1394
|
+
context.deleteCellValues();
|
|
1193
1395
|
return;
|
|
1194
1396
|
}
|
|
1195
1397
|
if (context.event.key === "Enter" || context.event.key === "F2") {
|
|
1196
1398
|
if (context.cell.editable) {
|
|
1197
1399
|
context.event.preventDefault();
|
|
1198
|
-
|
|
1400
|
+
if (context.cell.column.editor === "checkbox") {
|
|
1401
|
+
context.applyCellValue(context.cell, !Boolean(context.cell.value));
|
|
1402
|
+
}
|
|
1403
|
+
else {
|
|
1404
|
+
context.startEditing(createEditingCell(context.cell, context.cell.value));
|
|
1405
|
+
}
|
|
1199
1406
|
}
|
|
1200
1407
|
return;
|
|
1201
1408
|
}
|
|
1202
1409
|
if (context.event.key === " ") {
|
|
1203
1410
|
context.event.preventDefault();
|
|
1411
|
+
if (context.cell.column.editor === "checkbox" && context.cell.editable) {
|
|
1412
|
+
context.applyCellValue(context.cell, !Boolean(context.cell.value));
|
|
1413
|
+
return;
|
|
1414
|
+
}
|
|
1204
1415
|
if (context.event.shiftKey) {
|
|
1205
1416
|
context.setFocusedCell(context.cell, true);
|
|
1206
1417
|
}
|
|
@@ -1209,10 +1420,15 @@ function handleCellKeyDown(context) {
|
|
|
1209
1420
|
}
|
|
1210
1421
|
return;
|
|
1211
1422
|
}
|
|
1212
|
-
if (
|
|
1213
|
-
if (context.cell.editable) {
|
|
1214
|
-
context.event
|
|
1215
|
-
|
|
1423
|
+
if (isTextEditingKey(context.event)) {
|
|
1424
|
+
if (context.cell.editable && context.cell.column.editor !== "checkbox") {
|
|
1425
|
+
if (canUseKeyAsInitialDraft(context.event)) {
|
|
1426
|
+
context.event.preventDefault();
|
|
1427
|
+
context.startEditing(createEditingCell(context.cell, context.event.key));
|
|
1428
|
+
}
|
|
1429
|
+
else {
|
|
1430
|
+
context.startEditing(createEditingCell(context.cell, ""));
|
|
1431
|
+
}
|
|
1216
1432
|
}
|
|
1217
1433
|
return;
|
|
1218
1434
|
}
|
|
@@ -1372,27 +1588,20 @@ function isEditingCell(editingCell, row, column) {
|
|
|
1372
1588
|
function commitEditingCell(context) {
|
|
1373
1589
|
const row = context.rowModel.visibleRows[context.cell.rowIndex];
|
|
1374
1590
|
const column = context.rowModel.visibleColumns.find((item) => item.id === context.cell.columnId);
|
|
1375
|
-
if (!row || !column) {
|
|
1376
|
-
return;
|
|
1591
|
+
if (!row || !column || !context.canEditCell(row, context.cell.rowIndex, column)) {
|
|
1592
|
+
return undefined;
|
|
1377
1593
|
}
|
|
1378
1594
|
const previousValue = column.accessor(row.original);
|
|
1379
|
-
const value = column.
|
|
1380
|
-
|
|
1381
|
-
:
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
rowIndex: context.cell.rowIndex,
|
|
1390
|
-
column,
|
|
1391
|
-
columnId: column.id,
|
|
1392
|
-
value,
|
|
1393
|
-
previousValue,
|
|
1394
|
-
},
|
|
1395
|
-
], "edit");
|
|
1595
|
+
const value = parseDraftValue(column, row.original, context.cell.draftValue);
|
|
1596
|
+
return {
|
|
1597
|
+
row: row.original,
|
|
1598
|
+
rowId: row.id,
|
|
1599
|
+
rowIndex: context.cell.rowIndex,
|
|
1600
|
+
column,
|
|
1601
|
+
columnId: column.id,
|
|
1602
|
+
value,
|
|
1603
|
+
previousValue,
|
|
1604
|
+
};
|
|
1396
1605
|
}
|
|
1397
1606
|
function handleGridCopy(context) {
|
|
1398
1607
|
const range = context.selectionRange ?? {
|
|
@@ -1433,11 +1642,11 @@ function handleGridPaste(context) {
|
|
|
1433
1642
|
})) {
|
|
1434
1643
|
const row = context.rows[cell.rowIndex];
|
|
1435
1644
|
const column = context.columns[cell.columnIndex];
|
|
1436
|
-
if (!row || !column ||
|
|
1645
|
+
if (!row || !column || !context.canEditCell(row, cell.rowIndex, column)) {
|
|
1437
1646
|
continue;
|
|
1438
1647
|
}
|
|
1439
1648
|
const previousValue = column.accessor(row.original);
|
|
1440
|
-
const value = column
|
|
1649
|
+
const value = parseDraftValue(column, row.original, cell.value);
|
|
1441
1650
|
if (Object.is(value, previousValue)) {
|
|
1442
1651
|
continue;
|
|
1443
1652
|
}
|
|
@@ -1453,6 +1662,37 @@ function handleGridPaste(context) {
|
|
|
1453
1662
|
}
|
|
1454
1663
|
context.applyCellValueChanges(changes, "paste");
|
|
1455
1664
|
}
|
|
1665
|
+
function deleteGridCellValues(context) {
|
|
1666
|
+
const range = normalizeCellRange(context.selectionRange ?? {
|
|
1667
|
+
anchor: context.focusedCell,
|
|
1668
|
+
focus: context.focusedCell,
|
|
1669
|
+
});
|
|
1670
|
+
const changes = [];
|
|
1671
|
+
for (let rowIndex = range.startRowIndex; rowIndex <= range.endRowIndex; rowIndex += 1) {
|
|
1672
|
+
for (let columnIndex = range.startColumnIndex; columnIndex <= range.endColumnIndex; columnIndex += 1) {
|
|
1673
|
+
const row = context.rows[rowIndex];
|
|
1674
|
+
const column = context.columns[columnIndex];
|
|
1675
|
+
if (!row || !column || !context.canEditCell(row, rowIndex, column)) {
|
|
1676
|
+
continue;
|
|
1677
|
+
}
|
|
1678
|
+
const previousValue = column.accessor(row.original);
|
|
1679
|
+
const value = getEmptyCellValue(column, row.original);
|
|
1680
|
+
if (Object.is(value, previousValue)) {
|
|
1681
|
+
continue;
|
|
1682
|
+
}
|
|
1683
|
+
changes.push({
|
|
1684
|
+
row: row.original,
|
|
1685
|
+
rowId: row.id,
|
|
1686
|
+
rowIndex,
|
|
1687
|
+
column,
|
|
1688
|
+
columnId: column.id,
|
|
1689
|
+
value,
|
|
1690
|
+
previousValue,
|
|
1691
|
+
});
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
context.applyCellValueChanges(changes, "delete");
|
|
1695
|
+
}
|
|
1456
1696
|
function startFillHandleDrag(context) {
|
|
1457
1697
|
context.event.preventDefault();
|
|
1458
1698
|
context.event.stopPropagation();
|
|
@@ -1499,7 +1739,7 @@ function applyFillHandleValues(context) {
|
|
|
1499
1739
|
})) {
|
|
1500
1740
|
const row = context.rows[cell.rowIndex];
|
|
1501
1741
|
const column = context.columns[cell.columnIndex];
|
|
1502
|
-
if (!row || !column ||
|
|
1742
|
+
if (!row || !column || !context.canEditCell(row, cell.rowIndex, column)) {
|
|
1503
1743
|
continue;
|
|
1504
1744
|
}
|
|
1505
1745
|
const previousValue = column.accessor(row.original);
|
|
@@ -1569,16 +1809,20 @@ function getHistoryEntryValueChanges(context) {
|
|
|
1569
1809
|
if (!row || !column) {
|
|
1570
1810
|
continue;
|
|
1571
1811
|
}
|
|
1812
|
+
const visibleRowIndex = context.rowModel.visibleRows.findIndex((item) => item.id === row.id);
|
|
1813
|
+
const rowIndex = visibleRowIndex >= 0 ? visibleRowIndex : row.index;
|
|
1814
|
+
if (!context.canEditCell(row, rowIndex, column)) {
|
|
1815
|
+
continue;
|
|
1816
|
+
}
|
|
1572
1817
|
const value = context.source === "undo" ? historyChange.previousValue : historyChange.value;
|
|
1573
1818
|
const previousValue = column.accessor(row.original);
|
|
1574
1819
|
if (Object.is(value, previousValue)) {
|
|
1575
1820
|
continue;
|
|
1576
1821
|
}
|
|
1577
|
-
const visibleRowIndex = context.rowModel.visibleRows.findIndex((item) => item.id === row.id);
|
|
1578
1822
|
changes.push({
|
|
1579
1823
|
row: row.original,
|
|
1580
1824
|
rowId: row.id,
|
|
1581
|
-
rowIndex
|
|
1825
|
+
rowIndex,
|
|
1582
1826
|
column,
|
|
1583
1827
|
columnId: column.id,
|
|
1584
1828
|
value,
|
|
@@ -1588,10 +1832,85 @@ function getHistoryEntryValueChanges(context) {
|
|
|
1588
1832
|
return changes;
|
|
1589
1833
|
}
|
|
1590
1834
|
function formatCellValue(column, row, value) {
|
|
1591
|
-
|
|
1835
|
+
if (column.valueFormatter) {
|
|
1836
|
+
return column.valueFormatter(value, row);
|
|
1837
|
+
}
|
|
1838
|
+
if (column.editor === "select") {
|
|
1839
|
+
const option = normalizeEditorOptions(column.options).find((item) => Object.is(item.value, value));
|
|
1840
|
+
if (option) {
|
|
1841
|
+
return option.label;
|
|
1842
|
+
}
|
|
1843
|
+
}
|
|
1844
|
+
return String(value ?? "");
|
|
1845
|
+
}
|
|
1846
|
+
function parseDraftValue(column, row, draftValue) {
|
|
1847
|
+
if (column.valueParser) {
|
|
1848
|
+
return column.valueParser(draftValue, row);
|
|
1849
|
+
}
|
|
1850
|
+
if (column.editor === "number") {
|
|
1851
|
+
return draftValue === "" ? undefined : Number(draftValue);
|
|
1852
|
+
}
|
|
1853
|
+
if (column.editor === "checkbox") {
|
|
1854
|
+
return draftValue === "true";
|
|
1855
|
+
}
|
|
1856
|
+
if (column.editor === "select") {
|
|
1857
|
+
const option = normalizeEditorOptions(column.options).find((item) => item.inputValue === draftValue);
|
|
1858
|
+
return option ? option.value : draftValue;
|
|
1859
|
+
}
|
|
1860
|
+
return draftValue;
|
|
1861
|
+
}
|
|
1862
|
+
function getEmptyCellValue(column, row) {
|
|
1863
|
+
if (column.valueParser) {
|
|
1864
|
+
return column.valueParser("", row);
|
|
1865
|
+
}
|
|
1866
|
+
if (column.editor === "checkbox") {
|
|
1867
|
+
return false;
|
|
1868
|
+
}
|
|
1869
|
+
if (column.editor === "number") {
|
|
1870
|
+
return undefined;
|
|
1871
|
+
}
|
|
1872
|
+
return "";
|
|
1873
|
+
}
|
|
1874
|
+
function normalizeEditorOptions(options) {
|
|
1875
|
+
return (options ?? []).map((option) => {
|
|
1876
|
+
const value = getEditorOptionValue(option);
|
|
1877
|
+
return {
|
|
1878
|
+
value,
|
|
1879
|
+
label: typeof option === "object" ? option.label : String(option),
|
|
1880
|
+
inputValue: String(value),
|
|
1881
|
+
};
|
|
1882
|
+
});
|
|
1883
|
+
}
|
|
1884
|
+
function getEditorOptionValue(option) {
|
|
1885
|
+
return typeof option === "object" ? option.value : option;
|
|
1886
|
+
}
|
|
1887
|
+
function getCellTitle(meta, disabledReason, editable) {
|
|
1888
|
+
if (typeof meta?.message === "string") {
|
|
1889
|
+
return meta.message;
|
|
1890
|
+
}
|
|
1891
|
+
if (!editable && typeof disabledReason === "string") {
|
|
1892
|
+
return disabledReason;
|
|
1893
|
+
}
|
|
1894
|
+
return undefined;
|
|
1895
|
+
}
|
|
1896
|
+
function isTextEditingKey(event) {
|
|
1897
|
+
if (event.metaKey || event.ctrlKey || event.altKey) {
|
|
1898
|
+
return false;
|
|
1899
|
+
}
|
|
1900
|
+
return event.key.length === 1 || isCompositionEditingKey(event);
|
|
1901
|
+
}
|
|
1902
|
+
function canUseKeyAsInitialDraft(event) {
|
|
1903
|
+
return event.key.length === 1 && isAsciiPrintableKey(event.key) && !isCompositionEditingKey(event);
|
|
1904
|
+
}
|
|
1905
|
+
function isCompositionEditingKey(event) {
|
|
1906
|
+
return (event.nativeEvent.isComposing ||
|
|
1907
|
+
event.key === "Process" ||
|
|
1908
|
+
event.key === "Dead" ||
|
|
1909
|
+
event.key === "Unidentified" ||
|
|
1910
|
+
event.keyCode === 229);
|
|
1592
1911
|
}
|
|
1593
|
-
function
|
|
1594
|
-
return
|
|
1912
|
+
function isAsciiPrintableKey(key) {
|
|
1913
|
+
return key >= " " && key <= "~";
|
|
1595
1914
|
}
|
|
1596
1915
|
function isUndoShortcut(event) {
|
|
1597
1916
|
return (event.metaKey || event.ctrlKey) && !event.altKey && !event.shiftKey && event.key.toLowerCase() === "z";
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { YoupGrid } from "./YoupGrid.ts";
|
|
2
2
|
export { useYoupGrid } from "./useYoupGrid.ts";
|
|
3
|
-
export type { YoupGridCellContext, YoupGridController, YoupGridDensity, YoupGridHeaderContext, YoupGridOptions, YoupGridProps, YoupGridRowEvent, YoupGridRowsEndReachedEvent, YoupGridStateChange, } from "./types.ts";
|
|
3
|
+
export type { YoupGridCanEditCellContext, YoupGridCellEditCommit, YoupGridCellEditCommitReason, YoupGridCellContext, YoupGridCellMeta, YoupGridCellMetaStatus, YoupGridCellsValueChange, YoupGridCellsValueChangeSource, YoupGridController, YoupGridDensity, YoupGridHeaderContext, YoupGridOptions, YoupGridProps, YoupGridRowEvent, YoupGridRowsEndReachedEvent, YoupGridStateChange, } from "./types.ts";
|
package/dist/styles.css
CHANGED
|
@@ -64,6 +64,15 @@
|
|
|
64
64
|
background: #fff;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
.youp-grid__disabled-reason {
|
|
68
|
+
padding: 8px 12px;
|
|
69
|
+
border-bottom: 1px solid var(--youp-grid-border);
|
|
70
|
+
color: var(--youp-grid-muted);
|
|
71
|
+
background: #f8fafc;
|
|
72
|
+
font-size: 12px;
|
|
73
|
+
font-weight: 700;
|
|
74
|
+
}
|
|
75
|
+
|
|
67
76
|
.youp-grid__density-control {
|
|
68
77
|
display: inline-flex;
|
|
69
78
|
align-items: center;
|
|
@@ -151,6 +160,15 @@
|
|
|
151
160
|
background: var(--youp-grid-row-hover);
|
|
152
161
|
}
|
|
153
162
|
|
|
163
|
+
.youp-grid__header {
|
|
164
|
+
--youp-grid-header-scroll-left: 0px;
|
|
165
|
+
}
|
|
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) {
|
|
169
|
+
transform: translateX(calc(-1 * var(--youp-grid-header-scroll-left)));
|
|
170
|
+
}
|
|
171
|
+
|
|
154
172
|
.youp-grid__row--header {
|
|
155
173
|
background: var(--youp-grid-header);
|
|
156
174
|
}
|
|
@@ -268,6 +286,10 @@
|
|
|
268
286
|
white-space: nowrap;
|
|
269
287
|
}
|
|
270
288
|
|
|
289
|
+
.youp-grid--read-only .youp-grid__cell {
|
|
290
|
+
cursor: default;
|
|
291
|
+
}
|
|
292
|
+
|
|
271
293
|
.youp-grid__cell:focus {
|
|
272
294
|
outline: none;
|
|
273
295
|
}
|
|
@@ -289,6 +311,70 @@
|
|
|
289
311
|
box-shadow: inset 0 0 0 1px #0ea5e9;
|
|
290
312
|
}
|
|
291
313
|
|
|
314
|
+
.youp-grid__cell--disabled {
|
|
315
|
+
color: var(--youp-grid-muted);
|
|
316
|
+
background: #f8fafc;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
.youp-grid__cell--status-loading {
|
|
320
|
+
background: #eff6ff;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
.youp-grid__cell--status-error {
|
|
324
|
+
background: #fef2f2;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
.youp-grid__cell--status-warning {
|
|
328
|
+
background: #fffbeb;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
.youp-grid__cell--status-success {
|
|
332
|
+
background: #f0fdf4;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
.youp-grid__cell-placeholder {
|
|
336
|
+
color: #94a3b8;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
.youp-grid__cell-checkbox {
|
|
340
|
+
width: 16px;
|
|
341
|
+
height: 16px;
|
|
342
|
+
margin: 0;
|
|
343
|
+
accent-color: #2563eb;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
.youp-grid__cell-checkbox:disabled {
|
|
347
|
+
cursor: not-allowed;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
.youp-grid__cell-status {
|
|
351
|
+
position: absolute;
|
|
352
|
+
top: 6px;
|
|
353
|
+
right: 6px;
|
|
354
|
+
z-index: 3;
|
|
355
|
+
width: 7px;
|
|
356
|
+
height: 7px;
|
|
357
|
+
border: 1px solid #fff;
|
|
358
|
+
border-radius: 999px;
|
|
359
|
+
pointer-events: none;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
.youp-grid__cell-status--loading {
|
|
363
|
+
background: #2563eb;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
.youp-grid__cell-status--error {
|
|
367
|
+
background: #dc2626;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
.youp-grid__cell-status--warning {
|
|
371
|
+
background: #d97706;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
.youp-grid__cell-status--success {
|
|
375
|
+
background: #16a34a;
|
|
376
|
+
}
|
|
377
|
+
|
|
292
378
|
.youp-grid__cell--focused.youp-grid__cell--fill-target {
|
|
293
379
|
background: #bae6fd;
|
|
294
380
|
}
|
|
@@ -322,6 +408,16 @@
|
|
|
322
408
|
outline: none;
|
|
323
409
|
}
|
|
324
410
|
|
|
411
|
+
.youp-grid__cell-editor--select {
|
|
412
|
+
padding-right: 24px;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
.youp-grid__cell-editor:disabled {
|
|
416
|
+
color: var(--youp-grid-muted);
|
|
417
|
+
cursor: not-allowed;
|
|
418
|
+
background: #f1f5f9;
|
|
419
|
+
}
|
|
420
|
+
|
|
325
421
|
.youp-grid__cell--pinned-left,
|
|
326
422
|
.youp-grid__cell--pinned-right {
|
|
327
423
|
position: sticky;
|
|
@@ -363,6 +459,31 @@
|
|
|
363
459
|
background: #e0f2fe;
|
|
364
460
|
}
|
|
365
461
|
|
|
462
|
+
.youp-grid__cell--pinned-left.youp-grid__cell--disabled,
|
|
463
|
+
.youp-grid__cell--pinned-right.youp-grid__cell--disabled {
|
|
464
|
+
background: #f8fafc;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
.youp-grid__cell--pinned-left.youp-grid__cell--status-loading,
|
|
468
|
+
.youp-grid__cell--pinned-right.youp-grid__cell--status-loading {
|
|
469
|
+
background: #eff6ff;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
.youp-grid__cell--pinned-left.youp-grid__cell--status-error,
|
|
473
|
+
.youp-grid__cell--pinned-right.youp-grid__cell--status-error {
|
|
474
|
+
background: #fef2f2;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
.youp-grid__cell--pinned-left.youp-grid__cell--status-warning,
|
|
478
|
+
.youp-grid__cell--pinned-right.youp-grid__cell--status-warning {
|
|
479
|
+
background: #fffbeb;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
.youp-grid__cell--pinned-left.youp-grid__cell--status-success,
|
|
483
|
+
.youp-grid__cell--pinned-right.youp-grid__cell--status-success {
|
|
484
|
+
background: #f0fdf4;
|
|
485
|
+
}
|
|
486
|
+
|
|
366
487
|
.youp-grid__cell--focused.youp-grid__cell--left-last {
|
|
367
488
|
box-shadow:
|
|
368
489
|
inset 0 0 0 2px #2563eb,
|
package/dist/types.d.ts
CHANGED
|
@@ -14,7 +14,30 @@ export type YoupGridCellValueChange<TRow> = {
|
|
|
14
14
|
previousValue: unknown;
|
|
15
15
|
source: YoupGridCellValueChangeSource;
|
|
16
16
|
};
|
|
17
|
-
export type YoupGridCellValueChangeSource = "edit" | "paste" | "fill" | "undo" | "redo";
|
|
17
|
+
export type YoupGridCellValueChangeSource = "edit" | "paste" | "fill" | "delete" | "undo" | "redo";
|
|
18
|
+
export type YoupGridCellEditCommitReason = "enter" | "tab" | "blur";
|
|
19
|
+
export type YoupGridCellEditCommit<TRow> = Omit<YoupGridCellValueChange<TRow>, "source"> & {
|
|
20
|
+
reason: YoupGridCellEditCommitReason;
|
|
21
|
+
};
|
|
22
|
+
export type YoupGridCellsValueChangeSource = "paste" | "fill";
|
|
23
|
+
export type YoupGridCellsValueChange<TRow> = {
|
|
24
|
+
changes: YoupGridCellValueChange<TRow>[];
|
|
25
|
+
source: YoupGridCellsValueChangeSource;
|
|
26
|
+
};
|
|
27
|
+
export type YoupGridCellMetaStatus = "loading" | "error" | "warning" | "success";
|
|
28
|
+
export type YoupGridCellMeta = {
|
|
29
|
+
status: YoupGridCellMetaStatus;
|
|
30
|
+
message?: ReactNode;
|
|
31
|
+
};
|
|
32
|
+
export type YoupGridCanEditCellContext<TRow> = {
|
|
33
|
+
row: TRow;
|
|
34
|
+
rowNode: RowNode<TRow>;
|
|
35
|
+
rowId: GridRowId;
|
|
36
|
+
rowIndex: number;
|
|
37
|
+
column: ResolvedColumnDef<TRow>;
|
|
38
|
+
columnId: string;
|
|
39
|
+
value: unknown;
|
|
40
|
+
};
|
|
18
41
|
export type YoupGridDensity = "compact" | "standard" | "comfortable";
|
|
19
42
|
export type YoupGridRowEvent<TRow> = {
|
|
20
43
|
row: TRow;
|
|
@@ -84,6 +107,9 @@ export type YoupGridProps<TRow> = YoupGridOptions<TRow> & {
|
|
|
84
107
|
style?: CSSProperties;
|
|
85
108
|
height?: number | string;
|
|
86
109
|
editable?: boolean;
|
|
110
|
+
readOnly?: boolean;
|
|
111
|
+
canEditCell?: (context: YoupGridCanEditCellContext<TRow>) => boolean;
|
|
112
|
+
disabledReason?: ReactNode;
|
|
87
113
|
showColumnChooser?: boolean;
|
|
88
114
|
showColumnMenu?: boolean;
|
|
89
115
|
showCsvExport?: boolean;
|
|
@@ -100,9 +126,13 @@ export type YoupGridProps<TRow> = YoupGridOptions<TRow> & {
|
|
|
100
126
|
loadingContent?: ReactNode;
|
|
101
127
|
error?: boolean;
|
|
102
128
|
errorContent?: ReactNode;
|
|
129
|
+
cellMeta?: Record<string, YoupGridCellMeta | undefined>;
|
|
130
|
+
getCellMeta?: (context: YoupGridCanEditCellContext<TRow>) => YoupGridCellMeta | undefined;
|
|
103
131
|
renderCell?: (context: YoupGridCellContext<TRow>) => ReactNode;
|
|
104
132
|
renderHeader?: (context: YoupGridHeaderContext<TRow>) => ReactNode;
|
|
105
133
|
onCellValueChange?: (change: YoupGridCellValueChange<TRow>) => void;
|
|
134
|
+
onCellEditCommit?: (commit: YoupGridCellEditCommit<TRow>) => void;
|
|
135
|
+
onCellsValueChange?: (change: YoupGridCellsValueChange<TRow>) => void;
|
|
106
136
|
onRowClick?: (event: YoupGridRowEvent<TRow>) => void;
|
|
107
137
|
onRowDoubleClick?: (event: YoupGridRowEvent<TRow>) => void;
|
|
108
138
|
onRowsEndReached?: (event: YoupGridRowsEndReachedEvent<TRow>) => void;
|
|
@@ -114,6 +144,8 @@ export type YoupGridCellContext<TRow> = {
|
|
|
114
144
|
value: unknown;
|
|
115
145
|
editing: boolean;
|
|
116
146
|
focused: boolean;
|
|
147
|
+
editable: boolean;
|
|
148
|
+
meta?: YoupGridCellMeta;
|
|
117
149
|
};
|
|
118
150
|
export type YoupGridHeaderContext<TRow> = {
|
|
119
151
|
column: ResolvedColumnDef<TRow>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@youp-grid/react",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
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.1
|
|
31
|
+
"@youp-grid/core": "0.2.1"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
34
|
"react": ">=18.2.0"
|