@vuu-ui/vuu-data-editing 4.0.0-alpha.1 → 4.0.0-alpha.3
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/package.json +6 -6
- package/src/EditButtons.js +2 -2
- package/src/EditSession.js +84 -82
- package/src/UndoCellRenderer.js +1 -1
- package/src/edit-field/EditField.js +75 -0
- package/src/edit-field/useEditField.js +203 -0
- package/src/index.js +6 -3
- package/src/useEditable.js +52 -0
- package/src/useEditableTable.js +1 -1
- package/types/EditButtons.d.ts +1 -1
- package/types/EditModeProvider.d.ts +1 -1
- package/types/EditSession.d.ts +14 -11
- package/types/edit-field/EditField.d.ts +12 -0
- package/types/edit-field/useEditField.d.ts +24 -0
- package/types/index.d.ts +11 -8
- package/types/useEditState.d.ts +2 -0
- package/types/useEditable.d.ts +13 -0
- package/types/useEditableTable.d.ts +2 -2
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "4.0.0-alpha.
|
|
2
|
+
"version": "4.0.0-alpha.3",
|
|
3
3
|
"description": "Shared data editing APIs and React components for VUU UI",
|
|
4
4
|
"main": "./src/index.js",
|
|
5
5
|
"author": "heswell",
|
|
@@ -12,13 +12,13 @@
|
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@salt-ds/core": "1.67.0",
|
|
15
|
-
"@vuu-ui/vuu-ui-controls": "4.0.0-alpha.
|
|
16
|
-
"@vuu-ui/vuu-utils": "4.0.0-alpha.
|
|
15
|
+
"@vuu-ui/vuu-ui-controls": "4.0.0-alpha.3",
|
|
16
|
+
"@vuu-ui/vuu-utils": "4.0.0-alpha.3"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
|
-
"@vuu-ui/vuu-data-types": "4.0.0-alpha.
|
|
20
|
-
"@vuu-ui/vuu-protocol-types": "4.0.0-alpha.
|
|
21
|
-
"@vuu-ui/vuu-table-types": "4.0.0-alpha.
|
|
19
|
+
"@vuu-ui/vuu-data-types": "4.0.0-alpha.3",
|
|
20
|
+
"@vuu-ui/vuu-protocol-types": "4.0.0-alpha.3",
|
|
21
|
+
"@vuu-ui/vuu-table-types": "4.0.0-alpha.3"
|
|
22
22
|
},
|
|
23
23
|
"peerDependencies": {
|
|
24
24
|
"react": "^19.2.3"
|
package/src/EditButtons.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Button } from "@salt-ds/core";
|
|
3
3
|
import { useCallback, useEffect, useState } from "react";
|
|
4
|
-
const EditButtons = ({ canCancel, canSave, confirmCancel, confirmSave, editSession, hasSelection = false, onCancel, onDelete, onSave, saveLabel = "Save" })=>{
|
|
4
|
+
const EditButtons = ({ canCancel, canSave: _canSave, confirmCancel, confirmSave, editSession, hasSelection = false, onCancel, onDelete, onSave, saveLabel = "Save" })=>{
|
|
5
5
|
const [editState, setEditState] = useState(()=>editSession?.editState ?? "clean");
|
|
6
6
|
const handleSave = useCallback(async ()=>{
|
|
7
7
|
if (confirmSave) {
|
|
@@ -42,7 +42,7 @@ const EditButtons = ({ canCancel, canSave, confirmCancel, confirmSave, editSessi
|
|
|
42
42
|
children: "Delete"
|
|
43
43
|
}),
|
|
44
44
|
/*#__PURE__*/ jsx(Button, {
|
|
45
|
-
disabled: !canSave,
|
|
45
|
+
disabled: !editSession?.canSave,
|
|
46
46
|
onClick: handleSave,
|
|
47
47
|
sentiment: "accented",
|
|
48
48
|
children: "stale" === editState ? `${saveLabel} (force)` : saveLabel
|
package/src/EditSession.js
CHANGED
|
@@ -16,9 +16,6 @@ class SupersededEditError extends Error {
|
|
|
16
16
|
class EditSession extends EventEmitter {
|
|
17
17
|
static newRowKey = "__vuu_new_row__";
|
|
18
18
|
#rowEdits = new Map();
|
|
19
|
-
#deletedRows = new Set();
|
|
20
|
-
#deleteRevision = 0;
|
|
21
|
-
#rowDeleteRevisions = new Map();
|
|
22
19
|
#editCount = 0;
|
|
23
20
|
#deleteCount = 0;
|
|
24
21
|
#addCount = 0;
|
|
@@ -48,47 +45,33 @@ class EditSession extends EventEmitter {
|
|
|
48
45
|
this.#sourceTableDataSource = dataSource;
|
|
49
46
|
this.#deleteMode = deleteMode;
|
|
50
47
|
this.#editSessionApi = editSessionApi;
|
|
51
|
-
this.#rowDefaults =
|
|
48
|
+
this.#rowDefaults = {
|
|
49
|
+
...rowDefaults
|
|
50
|
+
};
|
|
52
51
|
}
|
|
53
52
|
get editCount() {
|
|
54
53
|
return this.#editCount;
|
|
55
54
|
}
|
|
56
|
-
set editCount(val) {
|
|
57
|
-
this.#setEditCounts(val, this.#invalidCount);
|
|
58
|
-
}
|
|
59
55
|
get invalidCount() {
|
|
60
56
|
return this.#invalidCount;
|
|
61
57
|
}
|
|
62
|
-
set invalidCount(val) {
|
|
63
|
-
this.#setEditCounts(this.#editCount, val);
|
|
64
|
-
}
|
|
65
58
|
get deleteCount() {
|
|
66
59
|
return this.#deleteCount;
|
|
67
60
|
}
|
|
68
|
-
set deleteCount(val) {
|
|
69
|
-
if (val !== this.#deleteCount) {
|
|
70
|
-
const oldState = this.editState;
|
|
71
|
-
const oldCount = this.#deleteCount;
|
|
72
|
-
this.#deleteCount = val;
|
|
73
|
-
this.#emitEditStateChange(oldState, 0 === oldCount || 0 === val);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
61
|
get addCount() {
|
|
77
62
|
return this.#addCount;
|
|
78
63
|
}
|
|
79
|
-
set addCount(val) {
|
|
80
|
-
if (val !== this.#addCount) {
|
|
81
|
-
const oldState = this.editState;
|
|
82
|
-
const oldCount = this.#addCount;
|
|
83
|
-
this.#addCount = val;
|
|
84
|
-
this.#emitEditStateChange(oldState, 0 === oldCount || 0 === val);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
64
|
get editState() {
|
|
88
65
|
if (this.#invalidCount > 0) return "invalid";
|
|
89
66
|
if (this.#isStale) return "stale";
|
|
90
67
|
return 0 === this.#editCount && 0 === this.#deleteCount && 0 === this.#addCount ? "clean" : "dirty";
|
|
91
68
|
}
|
|
69
|
+
get canCancel() {
|
|
70
|
+
return "active" === this.lifecycle.status || "error" === this.lifecycle.status && "end" === this.lifecycle.operation;
|
|
71
|
+
}
|
|
72
|
+
get canSave() {
|
|
73
|
+
return this.canCancel && ("dirty" === this.editState || "stale" === this.editState) && 0 === this.invalidCount;
|
|
74
|
+
}
|
|
92
75
|
#emitEditStateChange(oldState, force = false) {
|
|
93
76
|
const newState = this.editState;
|
|
94
77
|
if (force || newState !== oldState) this.emit("editState", newState);
|
|
@@ -101,6 +84,22 @@ class EditSession extends EventEmitter {
|
|
|
101
84
|
this.#emitEditStateChange(oldState);
|
|
102
85
|
}
|
|
103
86
|
}
|
|
87
|
+
#setDeleteCount(val) {
|
|
88
|
+
if (val !== this.#deleteCount) {
|
|
89
|
+
const oldState = this.editState;
|
|
90
|
+
const oldCount = this.#deleteCount;
|
|
91
|
+
this.#deleteCount = val;
|
|
92
|
+
this.#emitEditStateChange(oldState, 0 === oldCount || 0 === val);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
#setAddCount(val) {
|
|
96
|
+
if (val !== this.#addCount) {
|
|
97
|
+
const oldState = this.editState;
|
|
98
|
+
const oldCount = this.#addCount;
|
|
99
|
+
this.#addCount = val;
|
|
100
|
+
this.#emitEditStateChange(oldState, 0 === oldCount || 0 === val);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
104
103
|
#setStale(isStale) {
|
|
105
104
|
if (isStale !== this.#isStale) {
|
|
106
105
|
const oldState = this.editState;
|
|
@@ -108,13 +107,6 @@ class EditSession extends EventEmitter {
|
|
|
108
107
|
this.#emitEditStateChange(oldState);
|
|
109
108
|
}
|
|
110
109
|
}
|
|
111
|
-
#refreshEditCounts() {
|
|
112
|
-
let editCount = 0;
|
|
113
|
-
let invalidCount = 0;
|
|
114
|
-
for (const { cellEdits } of this.#rowEdits.values())for (const cellEdit of cellEdits.values())if (cellEdit.isValid) editCount++;
|
|
115
|
-
else invalidCount++;
|
|
116
|
-
this.#setEditCounts(editCount, invalidCount);
|
|
117
|
-
}
|
|
118
110
|
get newRowState() {
|
|
119
111
|
return this.#newRowState;
|
|
120
112
|
}
|
|
@@ -236,20 +228,14 @@ class EditSession extends EventEmitter {
|
|
|
236
228
|
this.emit("newRow", newRowState);
|
|
237
229
|
}
|
|
238
230
|
async deleteSelectedRows() {
|
|
239
|
-
const
|
|
240
|
-
if (
|
|
241
|
-
const
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
this.#deletedRows.add(key);
|
|
248
|
-
newCount++;
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
if (newCount > 0) this.deleteCount = this.#deleteCount + newCount;
|
|
252
|
-
}
|
|
231
|
+
const deleteSelectedRows = this.dataSource?.deleteSelectedRows;
|
|
232
|
+
if (void 0 === deleteSelectedRows) throw Error("[EditSession] datasource does not support deleting rows");
|
|
233
|
+
const selectedRowsCount = this.dataSource?.selectedRowsCount ?? 0;
|
|
234
|
+
const response = await deleteSelectedRows.call(this.dataSource, this.#deleteMode);
|
|
235
|
+
if (void 0 === response) throw Error("[EditSession] datasource returned no response when deleting rows");
|
|
236
|
+
if (isRpcError(response)) return response;
|
|
237
|
+
if (selectedRowsCount > 0) this.#setDeleteCount(this.#deleteCount + selectedRowsCount);
|
|
238
|
+
return response;
|
|
253
239
|
}
|
|
254
240
|
async addRow(rowData = {}) {
|
|
255
241
|
const addRow = this.dataSource?.addRow;
|
|
@@ -259,54 +245,50 @@ class EditSession extends EventEmitter {
|
|
|
259
245
|
...rowData
|
|
260
246
|
});
|
|
261
247
|
if (void 0 === response) throw Error("[EditSession] datasource returned no response when adding row");
|
|
262
|
-
if (!isRpcError(response)) this
|
|
248
|
+
if (!isRpcError(response)) this.#setAddCount(this.#addCount + 1);
|
|
263
249
|
return response;
|
|
264
250
|
}
|
|
265
|
-
restoreRows(keys) {
|
|
266
|
-
for (const key of keys)if (this.#deletedRows.has(key)) {
|
|
267
|
-
this.#deletedRows.delete(key);
|
|
268
|
-
this.#rowDeleteRevisions.delete(key);
|
|
269
|
-
this.deleteCount = this.#deleteCount - 1;
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
251
|
hasRowChanges(key) {
|
|
273
|
-
return this.#rowEdits.has(key)
|
|
252
|
+
return this.#rowEdits.has(key);
|
|
274
253
|
}
|
|
275
254
|
isCellEdited(key, columnName) {
|
|
276
255
|
const cellEdit = this.#rowEdits.get(key)?.cellEdits.get(columnName);
|
|
277
256
|
return cellEdit?.isValid === true && cellEdit.originalValue !== cellEdit.editedValue;
|
|
278
257
|
}
|
|
279
|
-
async undoRowChange(key) {
|
|
258
|
+
async undoRowChange(key, action) {
|
|
280
259
|
if (!this.inEditMode) return;
|
|
281
260
|
const undoRevision = this.#commitRevision;
|
|
282
|
-
const deleteRevisionAtRequest = this.#rowDeleteRevisions.get(key);
|
|
283
261
|
const rowEditsAtRequest = this.#rowEdits.get(key);
|
|
284
262
|
const columnsAtRequest = new Set(rowEditsAtRequest?.cellEdits.keys());
|
|
285
|
-
const wasDeleted = this.#deletedRows.has(key);
|
|
286
263
|
const response = await this.dataSource?.undoRowChange?.(key);
|
|
287
|
-
if (
|
|
264
|
+
if (void 0 === response) return;
|
|
265
|
+
if (isRpcError(response)) return response;
|
|
266
|
+
const oldState = this.editState;
|
|
288
267
|
const rowEdits = this.#rowEdits.get(key);
|
|
289
268
|
if (rowEdits) {
|
|
290
269
|
const changedColumns = [];
|
|
270
|
+
let removedValidCount = 0;
|
|
271
|
+
let removedInvalidCount = 0;
|
|
291
272
|
for (const columnName of columnsAtRequest){
|
|
292
273
|
const latestRevision = this.#cellCommitRevisions.get(key)?.get(columnName) ?? 0;
|
|
293
|
-
if (
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
274
|
+
if (latestRevision > undoRevision) continue;
|
|
275
|
+
const existing = rowEdits.cellEdits.get(columnName);
|
|
276
|
+
if (existing) if (existing.isValid) removedValidCount++;
|
|
277
|
+
else removedInvalidCount++;
|
|
278
|
+
if (this.isCellEdited(key, columnName)) changedColumns.push(columnName);
|
|
279
|
+
rowEdits.cellEdits.delete(columnName);
|
|
280
|
+
this.#setCellCommitRevision(key, columnName);
|
|
298
281
|
}
|
|
299
282
|
if (0 === rowEdits.cellEdits.size) this.#rowEdits.delete(key);
|
|
300
|
-
this.#
|
|
283
|
+
this.#editCount -= removedValidCount;
|
|
284
|
+
this.#invalidCount -= removedInvalidCount;
|
|
301
285
|
for (const columnName of changedColumns)this.emit("cellEditChanged", key, columnName);
|
|
302
286
|
}
|
|
303
|
-
if (
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
const wasInsertedRow = response?.data?.wasInsertedRow === true;
|
|
309
|
-
if (wasInsertedRow) this.addCount = this.#addCount - 1;
|
|
287
|
+
if ("deleteRow" === action) this.#deleteCount--;
|
|
288
|
+
const wasInsertedRow = "addRow" === action || response?.data?.wasInsertedRow === true;
|
|
289
|
+
if (wasInsertedRow) this.#addCount--;
|
|
290
|
+
this.#emitEditStateChange(oldState);
|
|
291
|
+
return response;
|
|
310
292
|
}
|
|
311
293
|
#clearEdits() {
|
|
312
294
|
const oldState = this.editState;
|
|
@@ -319,8 +301,6 @@ class EditSession extends EventEmitter {
|
|
|
319
301
|
columnName
|
|
320
302
|
]));
|
|
321
303
|
this.#rowEdits.clear();
|
|
322
|
-
this.#deletedRows.clear();
|
|
323
|
-
this.#rowDeleteRevisions.clear();
|
|
324
304
|
this.#cellCommitRevisions.clear();
|
|
325
305
|
this.#editCount = 0;
|
|
326
306
|
this.#deleteCount = 0;
|
|
@@ -419,7 +399,8 @@ class EditSession extends EventEmitter {
|
|
|
419
399
|
sessionDataSource
|
|
420
400
|
});
|
|
421
401
|
try {
|
|
422
|
-
await this.dataSource?.endEditSession?.(saveChanges, force);
|
|
402
|
+
const response = await this.dataSource?.endEditSession?.(saveChanges, force);
|
|
403
|
+
if (isRpcError(response)) throw new Error(response.errorMessage);
|
|
423
404
|
this.#clearEdits();
|
|
424
405
|
this.#sessionDataSource = void 0;
|
|
425
406
|
this.#setLifecycle({
|
|
@@ -463,9 +444,24 @@ class EditSession extends EventEmitter {
|
|
|
463
444
|
editedValue,
|
|
464
445
|
isValid
|
|
465
446
|
};
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
447
|
+
let prevValidCount = 0;
|
|
448
|
+
let prevInvalidCount = 0;
|
|
449
|
+
if (existingCellEdit) if (existingCellEdit.isValid) prevValidCount = 1;
|
|
450
|
+
else prevInvalidCount = 1;
|
|
451
|
+
let nextValidCount = 0;
|
|
452
|
+
let nextInvalidCount = 0;
|
|
453
|
+
const isRevertedToOriginal = isValid && cellEdit.originalValue === editedValue;
|
|
454
|
+
if (isRevertedToOriginal) {
|
|
455
|
+
cellEdits.delete(column);
|
|
456
|
+
if (0 === cellEdits.size) this.#rowEdits.delete(key);
|
|
457
|
+
} else {
|
|
458
|
+
cellEdits.set(column, cellEdit);
|
|
459
|
+
if (isValid) nextValidCount = 1;
|
|
460
|
+
else nextInvalidCount = 1;
|
|
461
|
+
}
|
|
462
|
+
const editCountDiff = nextValidCount - prevValidCount;
|
|
463
|
+
const invalidCountDiff = nextInvalidCount - prevInvalidCount;
|
|
464
|
+
if (0 !== editCountDiff || 0 !== invalidCountDiff) this.#setEditCounts(this.#editCount + editCountDiff, this.#invalidCount + invalidCountDiff);
|
|
469
465
|
if (wasEdited !== this.isCellEdited(key, column)) this.emit("cellEditChanged", key, column);
|
|
470
466
|
return cellEdit;
|
|
471
467
|
}
|
|
@@ -479,15 +475,21 @@ class EditSession extends EventEmitter {
|
|
|
479
475
|
#isLatestCellCommit(key, columnName, revision) {
|
|
480
476
|
return this.#cellCommitRevisions.get(key)?.get(columnName) === revision;
|
|
481
477
|
}
|
|
482
|
-
async commit(key, columnName, originalValue, typedValue, isValid) {
|
|
478
|
+
async commit(key, columnName, originalValue, typedValue, isValid, { dataSourceValue, syncToDataSource = true } = {}) {
|
|
483
479
|
if ("active" !== this.#lifecycle.status && !("error" === this.#lifecycle.status && "end" === this.#lifecycle.operation)) throw new Error("No edit session in progress");
|
|
484
480
|
const revision = this.#setCellCommitRevision(key, columnName);
|
|
485
481
|
const rowEditDetails = this.#getOrCreateRowEdits(key);
|
|
486
482
|
const { cellEdits } = rowEditDetails;
|
|
487
483
|
if (isValid) {
|
|
488
484
|
const cellEdit = this.#storeCellEdit(key, cellEdits, columnName, originalValue, typedValue, isValid);
|
|
489
|
-
if (this.dataSource?.editCell) {
|
|
490
|
-
const
|
|
485
|
+
if (syncToDataSource && this.dataSource?.editCell) {
|
|
486
|
+
const valueForDataSource = dataSourceValue ?? typedValue;
|
|
487
|
+
if ("object" == typeof valueForDataSource && null !== valueForDataSource) throw new Error("Custom edit values require a scalar dataSourceValue.");
|
|
488
|
+
const response = await this.dataSource.editCell(key, columnName, valueForDataSource);
|
|
489
|
+
if (!this.inEditMode) return {
|
|
490
|
+
data: void 0,
|
|
491
|
+
type: "SUCCESS_RESULT"
|
|
492
|
+
};
|
|
491
493
|
if (!this.#isLatestCellCommit(key, columnName, revision)) throw new SupersededEditError(`Edit response superseded for ${key}:${columnName}`);
|
|
492
494
|
const currentCellEdits = this.#getOrCreateRowEdits(key).cellEdits;
|
|
493
495
|
if (isRpcError(response)) this.#storeCellEdit(key, currentCellEdits, columnName, cellEdit.originalValue, typedValue, false);
|
package/src/UndoCellRenderer.js
CHANGED
|
@@ -20,7 +20,7 @@ const UndoCellRenderer = ({ column, dataRow })=>{
|
|
|
20
20
|
children: /*#__PURE__*/ jsxs(Button, {
|
|
21
21
|
appearance: "transparent",
|
|
22
22
|
"aria-label": tooltipContent,
|
|
23
|
-
onClick: ()=>editSession?.undoRowChange(dataRow.key),
|
|
23
|
+
onClick: ()=>editSession?.undoRowChange(dataRow.key, dataRow.vuuAction),
|
|
24
24
|
style: {
|
|
25
25
|
height: "100%",
|
|
26
26
|
width: "100%"
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Checkbox, FormField, FormFieldLabel, Input } from "@salt-ds/core";
|
|
3
|
+
import { useCallback } from "react";
|
|
4
|
+
import { useEditField } from "./useEditField.js";
|
|
5
|
+
import { useEditSession } from "../DataEditingProvider.js";
|
|
6
|
+
import { dataDescriptorTypeToVuuRowDataItemType } from "@vuu-ui/vuu-utils/src/data-utils";
|
|
7
|
+
import { useEditMode } from "../EditModeProvider.js";
|
|
8
|
+
const EditField = ({ dataRow, label, name, readOnly = false, required, type })=>{
|
|
9
|
+
const editSession = useEditSession();
|
|
10
|
+
const { isEditMode } = useEditMode();
|
|
11
|
+
const onEdit = useCallback(async (editState, editPhase)=>{
|
|
12
|
+
const { isValid = true, previousValue = "", value } = editState;
|
|
13
|
+
if ("commit" === editPhase && editSession) {
|
|
14
|
+
if (editSession.isNewRow(dataRow.key)) {
|
|
15
|
+
const isEmptyValue = "string" == typeof value && "" === value.trim();
|
|
16
|
+
if (!isValid && !isEmptyValue) return {
|
|
17
|
+
errorMessage: "Invalid value",
|
|
18
|
+
type: "ERROR_RESULT"
|
|
19
|
+
};
|
|
20
|
+
editSession.setNewRowValue(name, value);
|
|
21
|
+
if (editSession.isNewRowFinalColumn(name) || editSession.isNewRowComplete()) return editSession.addNewRow();
|
|
22
|
+
return {
|
|
23
|
+
data: void 0,
|
|
24
|
+
type: "SUCCESS_RESULT"
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
return editSession.commit(dataRow.key, name, previousValue, value, isValid);
|
|
28
|
+
}
|
|
29
|
+
}, [
|
|
30
|
+
dataRow,
|
|
31
|
+
editSession,
|
|
32
|
+
name
|
|
33
|
+
]);
|
|
34
|
+
const onCommit = useCallback(()=>{
|
|
35
|
+
console.log("onCommit");
|
|
36
|
+
}, []);
|
|
37
|
+
const necessity = required ? "asterisk" : void 0;
|
|
38
|
+
const dataValue = dataRow?.[name] ?? "";
|
|
39
|
+
const column = {
|
|
40
|
+
label,
|
|
41
|
+
name,
|
|
42
|
+
serverDataType: "string"
|
|
43
|
+
};
|
|
44
|
+
const { editing, inputProps, warningMessage, previousValue = "", ...editProps } = useEditField({
|
|
45
|
+
column,
|
|
46
|
+
textType: "checkbox" !== type ? type : void 0,
|
|
47
|
+
onEdit,
|
|
48
|
+
type: dataDescriptorTypeToVuuRowDataItemType(column),
|
|
49
|
+
value: dataValue
|
|
50
|
+
});
|
|
51
|
+
return /*#__PURE__*/ jsxs(FormField, {
|
|
52
|
+
"data-field": name,
|
|
53
|
+
necessity: necessity,
|
|
54
|
+
children: [
|
|
55
|
+
/*#__PURE__*/ jsx(FormFieldLabel, {
|
|
56
|
+
children: label
|
|
57
|
+
}),
|
|
58
|
+
false === isEditMode ? /*#__PURE__*/ jsx(Input, {
|
|
59
|
+
bordered: true,
|
|
60
|
+
inputProps: {
|
|
61
|
+
readOnly: true
|
|
62
|
+
},
|
|
63
|
+
value: String(dataValue)
|
|
64
|
+
}) : "checkbox" === type ? /*#__PURE__*/ jsx(Checkbox, {
|
|
65
|
+
checked: Boolean(dataValue),
|
|
66
|
+
onChange: onCommit
|
|
67
|
+
}) : /*#__PURE__*/ jsx(Input, {
|
|
68
|
+
...editProps,
|
|
69
|
+
bordered: true,
|
|
70
|
+
readOnly: readOnly
|
|
71
|
+
})
|
|
72
|
+
]
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
export { EditField };
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { DataValidationError, dispatchCustomEvent, getTypedValue, isRpcError, isRpcSuccess } from "@vuu-ui/vuu-utils";
|
|
2
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
3
|
+
const stringValueOf = (value)=>value?.toString() ?? "";
|
|
4
|
+
const useEditField = ({ column, value, onEdit, textType, type = "string" })=>{
|
|
5
|
+
const [editState, setEditState] = useState({
|
|
6
|
+
editing: false,
|
|
7
|
+
value: stringValueOf(value)
|
|
8
|
+
});
|
|
9
|
+
const initialValueRef = useRef(value?.toString() ?? "");
|
|
10
|
+
const isDirtyRef = useRef(false);
|
|
11
|
+
useEffect(()=>{
|
|
12
|
+
const nextValue = stringValueOf(value);
|
|
13
|
+
if (initialValueRef.current !== nextValue) {
|
|
14
|
+
initialValueRef.current = nextValue;
|
|
15
|
+
isDirtyRef.current = false;
|
|
16
|
+
setEditState((editState)=>({
|
|
17
|
+
...editState,
|
|
18
|
+
message: void 0,
|
|
19
|
+
value: nextValue
|
|
20
|
+
}));
|
|
21
|
+
}
|
|
22
|
+
}, [
|
|
23
|
+
value
|
|
24
|
+
]);
|
|
25
|
+
const commit = useCallback(async ()=>{
|
|
26
|
+
const { value } = editState;
|
|
27
|
+
const result = column.clientSideEditValidationCheck?.(value, "*");
|
|
28
|
+
if (result?.ok === false) setEditState((state)=>({
|
|
29
|
+
...state,
|
|
30
|
+
message: result?.messages?.join(",")
|
|
31
|
+
}));
|
|
32
|
+
else {
|
|
33
|
+
const { current: initialValue } = initialValueRef;
|
|
34
|
+
const previousValue = getTypedValue(initialValue, type);
|
|
35
|
+
try {
|
|
36
|
+
const typedValue = getTypedValue(value, type, true);
|
|
37
|
+
const response = await onEdit?.({
|
|
38
|
+
editType: "commit",
|
|
39
|
+
isValid: true,
|
|
40
|
+
previousValue,
|
|
41
|
+
value: typedValue
|
|
42
|
+
}, "commit");
|
|
43
|
+
if (isRpcSuccess(response)) {
|
|
44
|
+
isDirtyRef.current = false;
|
|
45
|
+
setEditState(({ previousValue, value })=>({
|
|
46
|
+
editing: false,
|
|
47
|
+
previousValue: previousValue === value ? void 0 : void 0 === previousValue ? initialValue : previousValue,
|
|
48
|
+
value
|
|
49
|
+
}));
|
|
50
|
+
} else if (isRpcError(response)) {
|
|
51
|
+
setEditState((state)=>({
|
|
52
|
+
...state,
|
|
53
|
+
message: response.errorMessage
|
|
54
|
+
}));
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
initialValueRef.current = value;
|
|
58
|
+
return true;
|
|
59
|
+
} catch (e) {
|
|
60
|
+
if (e instanceof DataValidationError) {
|
|
61
|
+
const { actualType, expectedType, message } = e;
|
|
62
|
+
if (column) {
|
|
63
|
+
const { name, label = name } = column;
|
|
64
|
+
const message = `${label} is a ${expectedType} value, data entered is ${actualType} `;
|
|
65
|
+
setEditState((state)=>({
|
|
66
|
+
...state,
|
|
67
|
+
message
|
|
68
|
+
}));
|
|
69
|
+
onEdit?.({
|
|
70
|
+
editType: "commit",
|
|
71
|
+
isValid: false,
|
|
72
|
+
previousValue,
|
|
73
|
+
value
|
|
74
|
+
}, "commit");
|
|
75
|
+
} else setEditState((state)=>({
|
|
76
|
+
...state,
|
|
77
|
+
message
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return false;
|
|
83
|
+
}, [
|
|
84
|
+
column,
|
|
85
|
+
editState,
|
|
86
|
+
onEdit,
|
|
87
|
+
type
|
|
88
|
+
]);
|
|
89
|
+
const toggleActivation = useCallback(async (input, cancel = false)=>{
|
|
90
|
+
if (editState.editing) if (isDirtyRef.current) if (cancel) {
|
|
91
|
+
const { value: previousValue } = editState;
|
|
92
|
+
isDirtyRef.current = false;
|
|
93
|
+
setEditState({
|
|
94
|
+
editing: false,
|
|
95
|
+
value: initialValueRef.current,
|
|
96
|
+
message: void 0
|
|
97
|
+
});
|
|
98
|
+
onEdit?.({
|
|
99
|
+
editType: "cancel",
|
|
100
|
+
isValid: true,
|
|
101
|
+
previousValue,
|
|
102
|
+
value: getTypedValue(initialValueRef.current, type, true)
|
|
103
|
+
}, "commit");
|
|
104
|
+
} else {
|
|
105
|
+
const commitSuccessful = await commit();
|
|
106
|
+
if (commitSuccessful) {
|
|
107
|
+
setEditState((editState)=>({
|
|
108
|
+
...editState,
|
|
109
|
+
editing: false
|
|
110
|
+
}));
|
|
111
|
+
dispatchCustomEvent(input, "vuu-commit");
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
else setEditState((editState)=>({
|
|
115
|
+
...editState,
|
|
116
|
+
editing: false
|
|
117
|
+
}));
|
|
118
|
+
else if (!cancel) {
|
|
119
|
+
setEditState((editState)=>({
|
|
120
|
+
...editState,
|
|
121
|
+
editing: true
|
|
122
|
+
}));
|
|
123
|
+
input.select();
|
|
124
|
+
}
|
|
125
|
+
}, [
|
|
126
|
+
commit,
|
|
127
|
+
editState,
|
|
128
|
+
onEdit,
|
|
129
|
+
type
|
|
130
|
+
]);
|
|
131
|
+
const handleKeyDown = useCallback(async (evt)=>{
|
|
132
|
+
const { key, target } = evt;
|
|
133
|
+
const input = target;
|
|
134
|
+
if ("Enter" === key) toggleActivation(input);
|
|
135
|
+
else if ("ArrowRight" === key || "ArrowLeft" === key || "ArrowUp" === key || "ArrowDown" === key) {
|
|
136
|
+
if (editState.editing) evt.stopPropagation();
|
|
137
|
+
} else if ("Escape" === evt.key) toggleActivation(input, true);
|
|
138
|
+
}, [
|
|
139
|
+
editState,
|
|
140
|
+
toggleActivation
|
|
141
|
+
]);
|
|
142
|
+
const handleFocus = useCallback((e)=>{
|
|
143
|
+
const input = e.target;
|
|
144
|
+
const source = e.relatedTarget;
|
|
145
|
+
if (source?.classList.contains("vuuTableCell") && source.contains(input)) toggleActivation(input);
|
|
146
|
+
}, [
|
|
147
|
+
toggleActivation
|
|
148
|
+
]);
|
|
149
|
+
const handleBlur = useCallback(async ()=>{
|
|
150
|
+
if (editState.editing) {
|
|
151
|
+
if (isDirtyRef.current) {
|
|
152
|
+
const commitSuccessful = await commit();
|
|
153
|
+
console.log({
|
|
154
|
+
commitSuccessful
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
setEditState((editState)=>({
|
|
158
|
+
...editState,
|
|
159
|
+
editing: false
|
|
160
|
+
}));
|
|
161
|
+
}
|
|
162
|
+
}, [
|
|
163
|
+
commit,
|
|
164
|
+
editState
|
|
165
|
+
]);
|
|
166
|
+
const handleChange = useCallback((evt)=>{
|
|
167
|
+
const { value } = evt.target;
|
|
168
|
+
isDirtyRef.current = value !== initialValueRef.current;
|
|
169
|
+
const result = column.clientSideEditValidationCheck?.(value, "change");
|
|
170
|
+
setEditState({
|
|
171
|
+
editing: true,
|
|
172
|
+
value
|
|
173
|
+
});
|
|
174
|
+
onEdit?.({
|
|
175
|
+
editType: "change",
|
|
176
|
+
isValid: result?.ok !== false,
|
|
177
|
+
previousValue: initialValueRef.current,
|
|
178
|
+
value
|
|
179
|
+
}, "change");
|
|
180
|
+
if (result?.ok === false) setEditState({
|
|
181
|
+
editing: true,
|
|
182
|
+
value,
|
|
183
|
+
message: result.messages?.join(",")
|
|
184
|
+
});
|
|
185
|
+
}, [
|
|
186
|
+
column,
|
|
187
|
+
onEdit
|
|
188
|
+
]);
|
|
189
|
+
return {
|
|
190
|
+
editing: editState.editing,
|
|
191
|
+
inputProps: {
|
|
192
|
+
onBlur: handleBlur,
|
|
193
|
+
onFocus: handleFocus,
|
|
194
|
+
type: textType
|
|
195
|
+
},
|
|
196
|
+
onChange: handleChange,
|
|
197
|
+
onKeyDown: handleKeyDown,
|
|
198
|
+
previousValue: editState.previousValue,
|
|
199
|
+
value: editState.value,
|
|
200
|
+
warningMessage: editState.message
|
|
201
|
+
};
|
|
202
|
+
};
|
|
203
|
+
export { useEditField };
|
package/src/index.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
export { StaleUpdateError } from "@vuu-ui/vuu-utils";
|
|
1
2
|
export { DataEditingProvider, useEditSession } from "./DataEditingProvider.js";
|
|
2
|
-
export { useCellEdited } from "./useCellEdited.js";
|
|
3
3
|
export { getVuuEditMessage, isEditRowReadOnly, isInlineEditingSession, withDataRowEditErrors } from "./edit-utils.js";
|
|
4
|
+
export { EDIT_ACTION_ROW_CLASS_NAME_GENERATOR, editActionRowClassNameGenerator } from "./editActionRowClassNameGenerator.js";
|
|
4
5
|
export { EditButtons } from "./EditButtons.js";
|
|
6
|
+
export { EditField } from "./edit-field/EditField.js";
|
|
7
|
+
export { useEditField } from "./edit-field/useEditField.js";
|
|
5
8
|
export { EditModeProvider, useEditMode } from "./EditModeProvider.js";
|
|
6
9
|
export { EditError, EditSession, SupersededEditError } from "./EditSession.js";
|
|
7
|
-
export { StaleUpdateError } from "@vuu-ui/vuu-utils";
|
|
8
|
-
export { EDIT_ACTION_ROW_CLASS_NAME_GENERATOR, editActionRowClassNameGenerator } from "./editActionRowClassNameGenerator.js";
|
|
9
10
|
export { UNDO_CELL_RENDERER, UndoCellRenderer, getUndoButtonContent, getUndoTooltipContent } from "./UndoCellRenderer.js";
|
|
11
|
+
export { useCellEdited } from "./useCellEdited.js";
|
|
12
|
+
export { useEditable } from "./useEditable.js";
|
|
10
13
|
export { useEditableTable } from "./useEditableTable.js";
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { EditSession, useEditMode } from "./index.js";
|
|
2
|
+
import { useCallback, useEffect, useMemo } from "react";
|
|
3
|
+
const useEditable = ({ copyOption = "Selected", dataSource, onCancel, onSave })=>{
|
|
4
|
+
const { isEditMode } = useEditMode();
|
|
5
|
+
const editSession = useMemo(()=>new EditSession({
|
|
6
|
+
dataSource
|
|
7
|
+
}), [
|
|
8
|
+
dataSource
|
|
9
|
+
]);
|
|
10
|
+
const handleCancel = useCallback(async ()=>{
|
|
11
|
+
try {
|
|
12
|
+
await editSession.end();
|
|
13
|
+
onCancel();
|
|
14
|
+
} catch (error) {
|
|
15
|
+
console.error("[useEditableTable] cancel edit session failed", error);
|
|
16
|
+
}
|
|
17
|
+
}, [
|
|
18
|
+
editSession,
|
|
19
|
+
onCancel
|
|
20
|
+
]);
|
|
21
|
+
const handleSave = useCallback(async (force = false)=>{
|
|
22
|
+
try {
|
|
23
|
+
await editSession.end(true, force);
|
|
24
|
+
onSave();
|
|
25
|
+
} catch (error) {
|
|
26
|
+
console.error("[useEditableTable] save edit session failed", error);
|
|
27
|
+
}
|
|
28
|
+
}, [
|
|
29
|
+
editSession,
|
|
30
|
+
onSave
|
|
31
|
+
]);
|
|
32
|
+
useEffect(()=>{
|
|
33
|
+
const transition = isEditMode ? editSession.begin(copyOption) : editSession.end();
|
|
34
|
+
transition.catch((error)=>{
|
|
35
|
+
if (isEditMode) {
|
|
36
|
+
console.error("[useEditableTable] begin edit session failed", error);
|
|
37
|
+
handleCancel();
|
|
38
|
+
} else console.error("[useEditableTable] end edit session failed", error);
|
|
39
|
+
});
|
|
40
|
+
}, [
|
|
41
|
+
copyOption,
|
|
42
|
+
editSession,
|
|
43
|
+
isEditMode,
|
|
44
|
+
handleCancel
|
|
45
|
+
]);
|
|
46
|
+
return {
|
|
47
|
+
editSession,
|
|
48
|
+
onCancel: handleCancel,
|
|
49
|
+
onSave: handleSave
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
export { useEditable };
|
package/src/useEditableTable.js
CHANGED
|
@@ -74,7 +74,7 @@ const useEditableTable = ({ columns, dataSource: dataSourceProp, deleteMode = "s
|
|
|
74
74
|
}, [
|
|
75
75
|
editSession
|
|
76
76
|
]);
|
|
77
|
-
const handleUndoRowChange = useCallback((key)=>void editSession.undoRowChange(key), [
|
|
77
|
+
const handleUndoRowChange = useCallback((key, action)=>void editSession.undoRowChange(key, action), [
|
|
78
78
|
editSession
|
|
79
79
|
]);
|
|
80
80
|
useEffect(()=>{
|
package/types/EditButtons.d.ts
CHANGED
|
@@ -11,4 +11,4 @@ export interface EditButtonProps {
|
|
|
11
11
|
confirmSave?: () => boolean | Promise<boolean>;
|
|
12
12
|
confirmCancel?: () => boolean | Promise<boolean>;
|
|
13
13
|
}
|
|
14
|
-
export declare const EditButtons: ({ canCancel, canSave, confirmCancel, confirmSave, editSession, hasSelection, onCancel, onDelete, onSave, saveLabel, }: EditButtonProps) => import("react").JSX.Element;
|
|
14
|
+
export declare const EditButtons: ({ canCancel, canSave: _canSave, confirmCancel, confirmSave, editSession, hasSelection, onCancel, onDelete, onSave, saveLabel, }: EditButtonProps) => import("react").JSX.Element;
|
package/types/EditSession.d.ts
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
|
-
import type { CopyOption, DataSource, DeleteRowMode,
|
|
1
|
+
import type { CopyOption, DataSource, DeleteRowMode, SessionType } from "@vuu-ui/vuu-data-types";
|
|
2
2
|
import type { RpcResult, VuuRowDataItemType } from "@vuu-ui/vuu-protocol-types";
|
|
3
3
|
import { EventEmitter } from "@vuu-ui/vuu-utils";
|
|
4
4
|
export type EditState = "clean" | "dirty" | "invalid" | "stale";
|
|
5
|
+
export type EditActionType = "deleteRow" | "addRow" | "editCell";
|
|
6
|
+
export type EditSessionValue = VuuRowDataItemType | object;
|
|
7
|
+
export type EditCommitOptions = {
|
|
8
|
+
dataSourceValue?: VuuRowDataItemType;
|
|
9
|
+
syncToDataSource?: boolean;
|
|
10
|
+
};
|
|
5
11
|
/** Column name to default value mapping applied to every addRow call when a column is absent from the row data. */
|
|
6
12
|
export type RowDefaultDataItemValues = Record<string, VuuRowDataItemType>;
|
|
7
13
|
export type EditSessionApi = "createSessionDataSource" | "beginEditSession";
|
|
8
14
|
export type EditSessionConstructorProps = {
|
|
9
|
-
dataSource:
|
|
15
|
+
dataSource: DataSource;
|
|
10
16
|
/** @default "soft" */
|
|
11
17
|
deleteMode?: DeleteRowMode;
|
|
12
18
|
/** @default "createSessionDataSource" */
|
|
@@ -53,14 +59,12 @@ export declare class EditSession extends EventEmitter<EditSessionEvents> {
|
|
|
53
59
|
static readonly newRowKey = "__vuu_new_row__";
|
|
54
60
|
constructor({ dataSource, deleteMode, editSessionApi, rowDefaults, }: EditSessionConstructorProps);
|
|
55
61
|
get editCount(): number;
|
|
56
|
-
set editCount(val: number);
|
|
57
62
|
get invalidCount(): number;
|
|
58
|
-
set invalidCount(val: number);
|
|
59
63
|
get deleteCount(): number;
|
|
60
|
-
set deleteCount(val: number);
|
|
61
64
|
get addCount(): number;
|
|
62
|
-
set addCount(val: number);
|
|
63
65
|
get editState(): EditState;
|
|
66
|
+
get canCancel(): boolean;
|
|
67
|
+
get canSave(): boolean;
|
|
64
68
|
get newRowState(): NewRowState;
|
|
65
69
|
isNewRow(key: string): key is "__vuu_new_row__";
|
|
66
70
|
isNewRowFinalColumn(columnName: string): boolean;
|
|
@@ -68,23 +72,22 @@ export declare class EditSession extends EventEmitter<EditSessionEvents> {
|
|
|
68
72
|
configureNewRow(columns: readonly string[], requiredColumns?: readonly string[]): void;
|
|
69
73
|
setNewRowValue(column: string, value: VuuRowDataItemType): void;
|
|
70
74
|
addNewRow(): Promise<RpcResult>;
|
|
71
|
-
deleteSelectedRows(): Promise<
|
|
75
|
+
deleteSelectedRows(): Promise<RpcResult>;
|
|
72
76
|
addRow(rowData?: Record<string, VuuRowDataItemType>): Promise<RpcResult>;
|
|
73
|
-
restoreRows(keys: string[]): void;
|
|
74
77
|
hasRowChanges(key: string): boolean;
|
|
75
78
|
isCellEdited(key: string, columnName: string): boolean;
|
|
76
|
-
undoRowChange(key: string): Promise<
|
|
79
|
+
undoRowChange(key: string, action: EditActionType): Promise<RpcResult | undefined>;
|
|
77
80
|
begin(copyOption?: CopyOption, sessionType?: SessionType): Promise<DataSource>;
|
|
78
81
|
/**
|
|
79
82
|
* Safe to call repeatedly - schema of a remote session table typically arrives
|
|
80
83
|
* after begin() resolves, so callers re-invoke this once 'subscribed' fires.
|
|
81
84
|
*/
|
|
82
85
|
reconcileWithSessionSchema(): void;
|
|
83
|
-
get dataSource():
|
|
86
|
+
get dataSource(): import("@vuu-ui/vuu-data-types").DataSourceBase<import("@vuu-ui/vuu-data-types").DataSourceRowWithBigint> | undefined;
|
|
84
87
|
get sessionDataSource(): DataSource | undefined;
|
|
85
88
|
end(saveChanges?: boolean, force?: boolean): Promise<void>;
|
|
86
89
|
get lifecycle(): EditLifecycle;
|
|
87
90
|
get inEditMode(): boolean;
|
|
88
|
-
commit(key: string, columnName: string, originalValue:
|
|
91
|
+
commit(key: string, columnName: string, originalValue: EditSessionValue, typedValue: EditSessionValue, isValid: boolean, { dataSourceValue, syncToDataSource }?: EditCommitOptions): Promise<RpcResult>;
|
|
89
92
|
}
|
|
90
93
|
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { DataRow } from "@vuu-ui/vuu-table-types";
|
|
2
|
+
export type TextFieldType = "email" | "password";
|
|
3
|
+
export type EditFieldType = "checkbox" | TextFieldType;
|
|
4
|
+
export interface EditFieldProps {
|
|
5
|
+
dataRow: DataRow;
|
|
6
|
+
label: string;
|
|
7
|
+
name: string;
|
|
8
|
+
readOnly?: boolean;
|
|
9
|
+
required?: boolean;
|
|
10
|
+
type?: EditFieldType;
|
|
11
|
+
}
|
|
12
|
+
export declare const EditField: ({ dataRow, label, name, readOnly, required, type, }: EditFieldProps) => import("react").JSX.Element;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { VuuRowDataItemType } from "@vuu-ui/vuu-protocol-types";
|
|
2
|
+
import type { RuntimeColumnDescriptor, TableCellEditHandler } from "@vuu-ui/vuu-table-types";
|
|
3
|
+
import { type ChangeEventHandler, type FocusEventHandler, type KeyboardEvent } from "react";
|
|
4
|
+
import type { TextFieldType } from "./EditField";
|
|
5
|
+
export interface EditFieldHookProps<T extends VuuRowDataItemType = VuuRowDataItemType> {
|
|
6
|
+
column: Pick<RuntimeColumnDescriptor, "clientSideEditValidationCheck" | "label" | "name">;
|
|
7
|
+
value?: T;
|
|
8
|
+
onEdit?: TableCellEditHandler;
|
|
9
|
+
textType?: TextFieldType;
|
|
10
|
+
type?: "string" | "number" | "boolean";
|
|
11
|
+
}
|
|
12
|
+
export declare const useEditField: <T extends string | number | boolean = string>({ column, value, onEdit, textType, type, }: EditFieldHookProps<T>) => {
|
|
13
|
+
editing: boolean;
|
|
14
|
+
inputProps: {
|
|
15
|
+
onBlur: FocusEventHandler<HTMLElement>;
|
|
16
|
+
onFocus: FocusEventHandler<HTMLElement>;
|
|
17
|
+
type: TextFieldType | undefined;
|
|
18
|
+
};
|
|
19
|
+
onChange: ChangeEventHandler;
|
|
20
|
+
onKeyDown: (evt: KeyboardEvent<HTMLElement>) => Promise<void>;
|
|
21
|
+
previousValue: string | undefined;
|
|
22
|
+
value: string;
|
|
23
|
+
warningMessage: string | undefined;
|
|
24
|
+
};
|
package/types/index.d.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
export { StaleUpdateError } from "@vuu-ui/vuu-utils";
|
|
1
2
|
export { DataEditingProvider, useEditSession } from "./DataEditingProvider";
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
3
|
+
export { getVuuEditMessage, isEditRowReadOnly, isInlineEditingSession, withDataRowEditErrors } from "./edit-utils";
|
|
4
|
+
export { EDIT_ACTION_ROW_CLASS_NAME_GENERATOR, editActionRowClassNameGenerator } from "./editActionRowClassNameGenerator";
|
|
4
5
|
export { EditButtons, type EditButtonProps } from "./EditButtons";
|
|
5
|
-
export {
|
|
6
|
-
export {
|
|
7
|
-
export {
|
|
8
|
-
export {
|
|
9
|
-
export { getUndoButtonContent, getUndoTooltipContent, UNDO_CELL_RENDERER, UndoCellRenderer, type UndoCellRendererComponentProps
|
|
10
|
-
export {
|
|
6
|
+
export { EditField } from './edit-field/EditField';
|
|
7
|
+
export { useEditField } from './edit-field/useEditField';
|
|
8
|
+
export { EditModeProvider, useEditMode, type EditModeContextProps } from "./EditModeProvider";
|
|
9
|
+
export { EditError, EditSession, SupersededEditError, type EditActionType, type EditLifecycle, type EditSessionConstructorProps, type EditState, type NewRowState, type RowDefaultDataItemValues } from "./EditSession";
|
|
10
|
+
export { getUndoButtonContent, getUndoTooltipContent, UNDO_CELL_RENDERER, UndoCellRenderer, type UndoCellRendererComponentProps } from "./UndoCellRenderer";
|
|
11
|
+
export { useCellEdited } from "./useCellEdited";
|
|
12
|
+
export { useEditable } from './useEditable';
|
|
13
|
+
export { useEditableTable, type EditableTableHookProps, type EditMode } from "./useEditableTable";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CopyOption, DataSource } from "@vuu-ui/vuu-data-types";
|
|
2
|
+
import { EditSession } from ".";
|
|
3
|
+
export interface EditableHookProps {
|
|
4
|
+
copyOption?: CopyOption;
|
|
5
|
+
dataSource: DataSource;
|
|
6
|
+
onCancel: () => void;
|
|
7
|
+
onSave: () => void;
|
|
8
|
+
}
|
|
9
|
+
export declare const useEditable: ({ copyOption, dataSource, onCancel, onSave }: EditableHookProps) => {
|
|
10
|
+
editSession: EditSession;
|
|
11
|
+
onCancel: () => Promise<void>;
|
|
12
|
+
onSave: (force?: boolean) => Promise<void>;
|
|
13
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CopyOption, DataSource, DeleteRowMode } from "@vuu-ui/vuu-data-types";
|
|
2
2
|
import type { VuuTable } from "@vuu-ui/vuu-protocol-types";
|
|
3
|
-
import { EditSession, type EditLifecycle, type EditSessionApi, type RowDefaultDataItemValues } from "./EditSession";
|
|
3
|
+
import { EditSession, type EditActionType, type EditLifecycle, type EditSessionApi, type RowDefaultDataItemValues } from "./EditSession";
|
|
4
4
|
export type EditMode = "edit" | "view";
|
|
5
5
|
export interface EditableTableHookProps {
|
|
6
6
|
/**
|
|
@@ -37,7 +37,7 @@ export declare const useEditableTable: ({ columns, dataSource: dataSourceProp, d
|
|
|
37
37
|
onCancel: () => Promise<void>;
|
|
38
38
|
onDelete: () => Promise<void>;
|
|
39
39
|
onSave: (force?: boolean) => Promise<void>;
|
|
40
|
-
onUndoRowChange: (key: string) => undefined;
|
|
40
|
+
onUndoRowChange: (key: string, action: EditActionType) => undefined;
|
|
41
41
|
rowClassNameGenerators: string[] | undefined;
|
|
42
42
|
sessionDataSource: import("@vuu-ui/vuu-data-types").DataSourceBase<import("@vuu-ui/vuu-data-types").DataSourceRowWithBigint> | undefined;
|
|
43
43
|
sourceDataSource: DataSource;
|