@vuu-ui/vuu-data-editing 3.3.17 → 4.0.0-alpha.10
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 +7 -7
- package/src/EditButtons.js +2 -2
- package/src/EditSession.js +13 -4
- package/src/edit-field/EditField.js +75 -0
- package/src/edit-field/useEditField.js +203 -0
- package/src/index.js +7 -4
- package/src/useEditable.js +52 -0
- package/types/DataEditingProvider.d.ts +1 -1
- package/types/EditButtons.d.ts +1 -1
- package/types/EditModeProvider.d.ts +2 -2
- package/types/EditSession.d.ts +8 -1
- package/types/UndoCellRenderer.d.ts +1 -1
- package/types/edit-utils.d.ts +1 -1
- package/types/editActionRowClassNameGenerator.d.ts +1 -1
- package/types/index.d.ts +11 -8
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "
|
|
2
|
+
"version": "4.0.0-alpha.10",
|
|
3
3
|
"description": "Shared data editing APIs and React components for VUU UI",
|
|
4
4
|
"main": "./src/index.js",
|
|
5
5
|
"author": "heswell",
|
|
@@ -11,14 +11,14 @@
|
|
|
11
11
|
"type-defs": "node ../../scripts/build-type-defs.mjs"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@salt-ds/core": "1.
|
|
15
|
-
"@vuu-ui/vuu-ui-controls": "
|
|
16
|
-
"@vuu-ui/vuu-utils": "
|
|
14
|
+
"@salt-ds/core": "1.67.0",
|
|
15
|
+
"@vuu-ui/vuu-ui-controls": "4.0.0-alpha.10",
|
|
16
|
+
"@vuu-ui/vuu-utils": "4.0.0-alpha.10"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
|
-
"@vuu-ui/vuu-data-types": "
|
|
20
|
-
"@vuu-ui/vuu-protocol-types": "
|
|
21
|
-
"@vuu-ui/vuu-table-types": "
|
|
19
|
+
"@vuu-ui/vuu-data-types": "4.0.0-alpha.10",
|
|
20
|
+
"@vuu-ui/vuu-protocol-types": "4.0.0-alpha.10",
|
|
21
|
+
"@vuu-ui/vuu-table-types": "4.0.0-alpha.10"
|
|
22
22
|
},
|
|
23
23
|
"peerDependencies": {
|
|
24
24
|
"react": "^19.2.3"
|
package/src/EditButtons.js
CHANGED
|
@@ -2,7 +2,7 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { Button } from "@salt-ds/core";
|
|
3
3
|
import { useCallback } from "react";
|
|
4
4
|
import { useEditState } from "./useEditState.js";
|
|
5
|
-
const EditButtons = ({ canCancel, canSave, confirmCancel, confirmSave, editSession, hasSelection = false, onCancel, onDelete, onSave, saveLabel = "Save" })=>{
|
|
5
|
+
const EditButtons = ({ canCancel, canSave: _canSave, confirmCancel, confirmSave, editSession, hasSelection = false, onCancel, onDelete, onSave, saveLabel = "Save" })=>{
|
|
6
6
|
const editState = useEditState(editSession);
|
|
7
7
|
const isDirty = editSession?.isDirty ?? false;
|
|
8
8
|
const handleSave = useCallback(async ()=>{
|
|
@@ -36,7 +36,7 @@ const EditButtons = ({ canCancel, canSave, confirmCancel, confirmSave, editSessi
|
|
|
36
36
|
children: "Delete"
|
|
37
37
|
}),
|
|
38
38
|
/*#__PURE__*/ jsx(Button, {
|
|
39
|
-
disabled: !canSave,
|
|
39
|
+
disabled: !editSession?.canSave,
|
|
40
40
|
onClick: handleSave,
|
|
41
41
|
sentiment: "accented",
|
|
42
42
|
children: "stale" === editState ? `${saveLabel} (force)` : saveLabel
|
package/src/EditSession.js
CHANGED
|
@@ -69,6 +69,12 @@ class EditSession extends EventEmitter {
|
|
|
69
69
|
get isDirty() {
|
|
70
70
|
return "clean" !== this.editState;
|
|
71
71
|
}
|
|
72
|
+
get canCancel() {
|
|
73
|
+
return "active" === this.lifecycle.status || "error" === this.lifecycle.status && "end" === this.lifecycle.operation;
|
|
74
|
+
}
|
|
75
|
+
get canSave() {
|
|
76
|
+
return this.canCancel && ("dirty" === this.editState || "stale" === this.editState) && 0 === this.invalidCount;
|
|
77
|
+
}
|
|
72
78
|
#emitEditStateChange(oldState, force = false) {
|
|
73
79
|
const newState = this.editState;
|
|
74
80
|
if (force || newState !== oldState) this.emit("editState", newState);
|
|
@@ -396,7 +402,8 @@ class EditSession extends EventEmitter {
|
|
|
396
402
|
sessionDataSource
|
|
397
403
|
});
|
|
398
404
|
try {
|
|
399
|
-
await this.dataSource?.endEditSession?.(saveChanges, force);
|
|
405
|
+
const response = await this.dataSource?.endEditSession?.(saveChanges, force);
|
|
406
|
+
if (isRpcError(response)) throw new Error(response.errorMessage);
|
|
400
407
|
this.#clearEdits();
|
|
401
408
|
this.#sessionDataSource = void 0;
|
|
402
409
|
this.#setLifecycle({
|
|
@@ -471,15 +478,17 @@ class EditSession extends EventEmitter {
|
|
|
471
478
|
#isLatestCellCommit(key, columnName, revision) {
|
|
472
479
|
return this.#cellCommitRevisions.get(key)?.get(columnName) === revision;
|
|
473
480
|
}
|
|
474
|
-
async commit(key, columnName, originalValue, typedValue, isValid) {
|
|
481
|
+
async commit(key, columnName, originalValue, typedValue, isValid, { dataSourceValue, syncToDataSource = true } = {}) {
|
|
475
482
|
if ("active" !== this.#lifecycle.status && !("error" === this.#lifecycle.status && "end" === this.#lifecycle.operation)) throw new Error("No edit session in progress");
|
|
476
483
|
const revision = this.#setCellCommitRevision(key, columnName);
|
|
477
484
|
const rowEditDetails = this.#getOrCreateRowEdits(key);
|
|
478
485
|
const { cellEdits } = rowEditDetails;
|
|
479
486
|
if (isValid) {
|
|
480
487
|
const cellEdit = this.#storeCellEdit(key, cellEdits, columnName, originalValue, typedValue, isValid);
|
|
481
|
-
if (this.dataSource?.editCell) {
|
|
482
|
-
const
|
|
488
|
+
if (syncToDataSource && this.dataSource?.editCell) {
|
|
489
|
+
const valueForDataSource = dataSourceValue ?? typedValue;
|
|
490
|
+
if ("object" == typeof valueForDataSource && null !== valueForDataSource) throw new Error("Custom edit values require a scalar dataSourceValue.");
|
|
491
|
+
const response = await this.dataSource.editCell(key, columnName, valueForDataSource);
|
|
483
492
|
if (!this.inEditMode) return {
|
|
484
493
|
data: void 0,
|
|
485
494
|
type: "SUCCESS_RESULT"
|
|
@@ -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";
|
|
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,11 +1,14 @@
|
|
|
1
|
+
export { StaleUpdateError } from "@vuu-ui/vuu-utils";
|
|
1
2
|
export { DataEditingProvider, useEditSession } from "./DataEditingProvider.js";
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
3
|
+
export { EditField } from "./edit-field/EditField.js";
|
|
4
|
+
export { useEditField } from "./edit-field/useEditField.js";
|
|
4
5
|
export { getVuuEditMessage, isEditRowReadOnly, isInlineEditingSession, withDataRowEditErrors } from "./edit-utils.js";
|
|
6
|
+
export { EDIT_ACTION_ROW_CLASS_NAME_GENERATOR, editActionRowClassNameGenerator } from "./editActionRowClassNameGenerator.js";
|
|
5
7
|
export { EditButtons } from "./EditButtons.js";
|
|
6
8
|
export { EditModeProvider, useEditMode } from "./EditModeProvider.js";
|
|
7
9
|
export { EditError, EditSession, SupersededEditError } from "./EditSession.js";
|
|
8
|
-
export { StaleUpdateError } from "@vuu-ui/vuu-utils";
|
|
9
|
-
export { EDIT_ACTION_ROW_CLASS_NAME_GENERATOR, editActionRowClassNameGenerator } from "./editActionRowClassNameGenerator.js";
|
|
10
10
|
export { UNDO_CELL_RENDERER, UndoCellRenderer, getUndoButtonContent, getUndoTooltipContent } from "./UndoCellRenderer.js";
|
|
11
|
+
export { useCellEdited } from "./useCellEdited.js";
|
|
12
|
+
export { useEditable } from "./useEditable.js";
|
|
11
13
|
export { useEditableTable } from "./useEditableTable.js";
|
|
14
|
+
export { useEditState } from "./useEditState.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 };
|
|
@@ -3,6 +3,6 @@ import type { EditSession } from "./EditSession";
|
|
|
3
3
|
export declare const DataEditingProvider: ({ children, editSession, }: {
|
|
4
4
|
children: ReactNode;
|
|
5
5
|
editSession: EditSession;
|
|
6
|
-
}) => import("react
|
|
6
|
+
}) => import("react").JSX.Element;
|
|
7
7
|
export declare function useEditSession(throwIfUnavailable?: false): EditSession | undefined;
|
|
8
8
|
export declare function useEditSession(throwIfUnavailable: true): EditSession;
|
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
|
|
14
|
+
export declare const EditButtons: ({ canCancel, canSave: _canSave, confirmCancel, confirmSave, editSession, hasSelection, onCancel, onDelete, onSave, saveLabel, }: EditButtonProps) => import("react").JSX.Element;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ReactNode } from "react";
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
2
|
export interface EditModeContextProps {
|
|
3
3
|
isEditMode: boolean;
|
|
4
4
|
setEditMode: (inEditMode: boolean) => void;
|
|
@@ -9,5 +9,5 @@ export interface EditModeContextProps {
|
|
|
9
9
|
*/
|
|
10
10
|
export declare const EditModeProvider: ({ children }: {
|
|
11
11
|
children: ReactNode;
|
|
12
|
-
}) => import("react
|
|
12
|
+
}) => import("react").JSX.Element;
|
|
13
13
|
export declare const useEditMode: () => EditModeContextProps;
|
package/types/EditSession.d.ts
CHANGED
|
@@ -3,6 +3,11 @@ 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
5
|
export type EditActionType = "deleteRow" | "addRow" | "editCell";
|
|
6
|
+
export type EditSessionValue = VuuRowDataItemType | object;
|
|
7
|
+
export type EditCommitOptions = {
|
|
8
|
+
dataSourceValue?: VuuRowDataItemType;
|
|
9
|
+
syncToDataSource?: boolean;
|
|
10
|
+
};
|
|
6
11
|
/** Column name to default value mapping applied to every addRow call when a column is absent from the row data. */
|
|
7
12
|
export type RowDefaultDataItemValues = Record<string, VuuRowDataItemType>;
|
|
8
13
|
export type EditSessionApi = "createSessionDataSource" | "beginEditSession";
|
|
@@ -59,6 +64,8 @@ export declare class EditSession extends EventEmitter<EditSessionEvents> {
|
|
|
59
64
|
get addCount(): number;
|
|
60
65
|
get editState(): EditState;
|
|
61
66
|
get isDirty(): boolean;
|
|
67
|
+
get canCancel(): boolean;
|
|
68
|
+
get canSave(): boolean;
|
|
62
69
|
get newRowState(): NewRowState;
|
|
63
70
|
isNewRow(key: string): key is "__vuu_new_row__";
|
|
64
71
|
isNewRowFinalColumn(columnName: string): boolean;
|
|
@@ -82,6 +89,6 @@ export declare class EditSession extends EventEmitter<EditSessionEvents> {
|
|
|
82
89
|
end(saveChanges?: boolean, force?: boolean): Promise<void>;
|
|
83
90
|
get lifecycle(): EditLifecycle;
|
|
84
91
|
get inEditMode(): boolean;
|
|
85
|
-
commit(key: string, columnName: string, originalValue:
|
|
92
|
+
commit(key: string, columnName: string, originalValue: EditSessionValue, typedValue: EditSessionValue, isValid: boolean, { dataSourceValue, syncToDataSource }?: EditCommitOptions): Promise<RpcResult>;
|
|
86
93
|
}
|
|
87
94
|
export {};
|
|
@@ -9,4 +9,4 @@ export declare const getUndoButtonContent: (componentProps?: UndoCellRendererCom
|
|
|
9
9
|
text: string | undefined;
|
|
10
10
|
};
|
|
11
11
|
export declare const getUndoTooltipContent: (action: unknown) => "Undo delete row" | "Undo insert row" | "Undo row edits" | undefined;
|
|
12
|
-
export declare const UndoCellRenderer: ({ column, dataRow, }: TableCellRendererProps) => import("react
|
|
12
|
+
export declare const UndoCellRenderer: ({ column, dataRow, }: TableCellRendererProps) => import("react").JSX.Element | null;
|
package/types/edit-utils.d.ts
CHANGED
|
@@ -2,4 +2,4 @@ import type { DataRow, RuntimeColumnDescriptor } from "@vuu-ui/vuu-table-types";
|
|
|
2
2
|
export { isInlineEditingSession } from "@vuu-ui/vuu-utils";
|
|
3
3
|
export declare const isEditRowReadOnly: (dataRow: DataRow) => boolean;
|
|
4
4
|
export declare const withDataRowEditErrors: <T extends DataRow>(dataRow: T, errors: Record<string, string>) => T;
|
|
5
|
-
export declare const getVuuEditMessage: (dataRow: DataRow, column: RuntimeColumnDescriptor, originalValue: string) => string | import("react
|
|
5
|
+
export declare const getVuuEditMessage: (dataRow: DataRow, column: RuntimeColumnDescriptor, originalValue: string) => string | import("react").JSX.Element | undefined;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { DataRow } from "@vuu-ui/vuu-table-types";
|
|
2
2
|
export declare const EDIT_ACTION_ROW_CLASS_NAME_GENERATOR = "vuu-edit-actions";
|
|
3
|
-
export declare const editActionRowClassNameGenerator: (dataRow: DataRow) => "vuuTableRow-
|
|
3
|
+
export declare const editActionRowClassNameGenerator: (dataRow: DataRow) => "vuuTableRow-deleted" | "vuuTableRow-inserted" | undefined;
|
package/types/index.d.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
export { StaleUpdateError } from "@vuu-ui/vuu-utils";
|
|
1
2
|
export { DataEditingProvider, useEditSession } from "./DataEditingProvider";
|
|
3
|
+
export { EditField } from './edit-field/EditField';
|
|
4
|
+
export { useEditField } from './edit-field/useEditField';
|
|
5
|
+
export { getVuuEditMessage, isEditRowReadOnly, isInlineEditingSession, withDataRowEditErrors } from "./edit-utils";
|
|
6
|
+
export { EDIT_ACTION_ROW_CLASS_NAME_GENERATOR, editActionRowClassNameGenerator } from "./editActionRowClassNameGenerator";
|
|
7
|
+
export { EditButtons, type EditButtonProps } from "./EditButtons";
|
|
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";
|
|
2
11
|
export { useCellEdited } from "./useCellEdited";
|
|
12
|
+
export { useEditable } from './useEditable';
|
|
13
|
+
export { useEditableTable, type EditableTableHookProps, type EditMode } from "./useEditableTable";
|
|
3
14
|
export { useEditState } from "./useEditState";
|
|
4
|
-
export { getVuuEditMessage, isInlineEditingSession, isEditRowReadOnly, withDataRowEditErrors, } from "./edit-utils";
|
|
5
|
-
export { EditButtons, type EditButtonProps } from "./EditButtons";
|
|
6
|
-
export { EditModeProvider, useEditMode, type EditModeContextProps, } from "./EditModeProvider";
|
|
7
|
-
export { EditError, EditSession, SupersededEditError, type EditActionType, type EditLifecycle, type EditSessionConstructorProps, type NewRowState, type EditState, type RowDefaultDataItemValues, } from "./EditSession";
|
|
8
|
-
export { StaleUpdateError } from "@vuu-ui/vuu-utils";
|
|
9
|
-
export { EDIT_ACTION_ROW_CLASS_NAME_GENERATOR, editActionRowClassNameGenerator, } from "./editActionRowClassNameGenerator";
|
|
10
|
-
export { getUndoButtonContent, getUndoTooltipContent, UNDO_CELL_RENDERER, UndoCellRenderer, type UndoCellRendererComponentProps, } from "./UndoCellRenderer";
|
|
11
|
-
export { useEditableTable, type EditableTableHookProps, type EditMode, } from "./useEditableTable";
|