@vuu-ui/vuu-data-editing 4.0.0-alpha.20 → 4.0.0-alpha.22
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/README.md +364 -1
- package/package.json +7 -7
- package/src/EditSession.js +32 -12
- package/src/useEditableTable.js +2 -0
- package/types/DataEditingProvider.d.ts +1 -1
- package/types/EditButtons.d.ts +1 -1
- package/types/EditModeProvider.d.ts +1 -1
- package/types/EditSession.d.ts +3 -0
- package/types/UndoCellRenderer.d.ts +1 -1
- package/types/edit-field/EditField.d.ts +1 -1
- package/types/edit-utils.d.ts +1 -1
- package/types/index.d.ts +1 -1
- package/types/useEditableTable.d.ts +2 -0
- package/types/src/DataEditingProvider.d.ts +0 -8
- package/types/src/EditButtons.d.ts +0 -14
- package/types/src/EditModeProvider.d.ts +0 -13
- package/types/src/EditSession.d.ts +0 -86
- package/types/src/UndoCellRenderer.d.ts +0 -12
- package/types/src/edit-utils.d.ts +0 -5
- package/types/src/editActionRowClassNameGenerator.d.ts +0 -3
- package/types/src/index.d.ts +0 -10
- package/types/src/useCellEdited.d.ts +0 -2
- package/types/src/useEditableTable.d.ts +0 -44
package/README.md
CHANGED
|
@@ -2,4 +2,367 @@
|
|
|
2
2
|
|
|
3
3
|
Shared data editing APIs, state management, and React components for VUU UI.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
This package coordinates edit-session state with editable data sources (both in-memory and remote Vuu session tables) and provides React hooks and UI controls for table editing.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Table of Contents
|
|
10
|
+
|
|
11
|
+
- [Overview & Architecture](#overview--architecture)
|
|
12
|
+
- [EditSession](#editsession)
|
|
13
|
+
- [Lifecycle State Machine](#lifecycle-state-machine)
|
|
14
|
+
- [Transition Queue](#transition-queue)
|
|
15
|
+
- [EditState & Counters](#editstate--counters)
|
|
16
|
+
- [Internal Edit Tracking](#internal-edit-tracking)
|
|
17
|
+
- [Editing Operations & Flows](#editing-operations--flows)
|
|
18
|
+
- [Cell Editing (`commit` / `cancel`)](#cell-editing-commit--cancel)
|
|
19
|
+
- [New Row Flow (`addNewRow` / `addRow`)](#new-row-flow-addnewrow--addrow)
|
|
20
|
+
- [Row Deletions (`deleteSelectedRows`)](#row-deletions-deleteselectedrows)
|
|
21
|
+
- [Undo Flow (`undoRowChange`)](#undo-flow-undorowchange)
|
|
22
|
+
- [Session Completion (`end`) & Stale Handling](#session-completion-end--stale-handling)
|
|
23
|
+
- [Direct Editing (`DirectEditSession`)](#direct-editing-directeditsession)
|
|
24
|
+
- [React Hooks & Context](#react-hooks--context)
|
|
25
|
+
- [`useEditableTable`](#useeditabletable)
|
|
26
|
+
- [`DataEditingProvider` & `useEditSession`](#dataeditingprovider--useeditsession)
|
|
27
|
+
- [`useCellEdited`](#usecellEdited)
|
|
28
|
+
- [`useEditMode` & `EditModeProvider`](#useeditmode--editmodeprovider)
|
|
29
|
+
- [UI Components & Helpers](#ui-components--helpers)
|
|
30
|
+
- [`EditButtons`](#editbuttons)
|
|
31
|
+
- [`UndoCellRenderer`](#undocellrenderer)
|
|
32
|
+
- [`editActionRowClassNameGenerator`](#editactionrowclassnamegenerator)
|
|
33
|
+
- [`isRowSelectable` / `isEditRowReadOnly`](#isrowselectable--iseditrowreadonly)
|
|
34
|
+
- [Standard Integration Pattern](#standard-integration-pattern)
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Overview & Architecture
|
|
39
|
+
|
|
40
|
+
VUU editing operates primarily through **staged edit sessions**:
|
|
41
|
+
1. When entering edit mode, a server-side (or mock) **session table** is created as a sandbox copy of the source table.
|
|
42
|
+
2. User edits (cell edits, row insertions, soft deletes) are applied to the session table and tracked locally by `EditSession`.
|
|
43
|
+
3. When saved, changes are committed from the session table to the source table. When cancelled, the session table is discarded without affecting the source table.
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
Source DataSource ──begin()──> Session Table Created ──> Live Session DataSource
|
|
47
|
+
│ │
|
|
48
|
+
│ Edits & Deletes
|
|
49
|
+
│ │
|
|
50
|
+
└──────────────end(save=true/false)──────────────────────┘
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
For backends that do not use session tables and accept cell edits directly against the live table, `DirectEditSession` is used instead.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## EditSession
|
|
58
|
+
|
|
59
|
+
`EditSession` is the core stateful orchestrator class extending `EventEmitter`. It tracks:
|
|
60
|
+
- Local cell edits per row and column
|
|
61
|
+
- Added row keys
|
|
62
|
+
- Edit, invalid, delete, and add counts
|
|
63
|
+
- Edit session lifecycle state
|
|
64
|
+
|
|
65
|
+
### Lifecycle State Machine
|
|
66
|
+
|
|
67
|
+
`EditSession.lifecycle` is a discriminated union on `status`:
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
type EditLifecycle =
|
|
71
|
+
| { status: "idle" }
|
|
72
|
+
| { status: "starting" }
|
|
73
|
+
| { status: "active"; sessionDataSource: DataSource }
|
|
74
|
+
| { status: "ending"; sessionDataSource: DataSource }
|
|
75
|
+
| { status: "error"; operation: "begin" | "end"; error: Error; sessionDataSource?: DataSource };
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
idle ──begin()──> starting ──> active ──end()──> ending ──> idle
|
|
80
|
+
│ │
|
|
81
|
+
└── error { op: "begin" } └── error { op: "end" }
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
- `inEditMode`: Getter returning `true` when status is `"active"`, `"ending"`, or `error { operation: "end" }`.
|
|
85
|
+
- `dataSource`: Getter returning `#sessionDataSource` when active/ending, falling back to `#sourceTableDataSource`.
|
|
86
|
+
|
|
87
|
+
### Transition Queue
|
|
88
|
+
|
|
89
|
+
All `begin()` and `end()` calls are serialized through `#transitionQueue` (a chained Promise). This prevents overlapping transitions, race conditions, and corrupted lifecycle states when rapid toggles occur.
|
|
90
|
+
|
|
91
|
+
### EditState & Counters
|
|
92
|
+
|
|
93
|
+
`editSession.editState` is a derived property reflecting the overall dirtiness and validity of the session:
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
type EditState = "clean" | "dirty" | "invalid" | "stale";
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Priority order (highest to lowest):
|
|
100
|
+
1. **`"invalid"`**: When `invalidCount > 0` (validation failure in at least one cell).
|
|
101
|
+
2. **`"stale"`**: When a save was rejected by the server due to concurrent updates (`StaleUpdateError`).
|
|
102
|
+
3. **`"dirty"`**: When `editCount > 0 || deleteCount > 0 || addCount > 0`.
|
|
103
|
+
4. **`"clean"`**: When no edits, deletes, or added rows exist.
|
|
104
|
+
|
|
105
|
+
Driven by four independent counters:
|
|
106
|
+
- `editCount`: Number of valid cell edits differing from their original values.
|
|
107
|
+
- `invalidCount`: Number of cell edits with validation errors.
|
|
108
|
+
- `deleteCount`: Number of rows marked for deletion.
|
|
109
|
+
- `addCount`: Number of newly inserted rows currently in the session.
|
|
110
|
+
|
|
111
|
+
All counter setters enforce non-negative values via `Math.max(0, val)`.
|
|
112
|
+
|
|
113
|
+
### Internal Edit Tracking
|
|
114
|
+
|
|
115
|
+
`EditSession` manages four primary collections:
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
#rowEdits = new Map<string, RowEditDetails>(); // rowKey => { cellEdits: Map<column, CellEdit> }
|
|
119
|
+
#addedRowKeys = new Set<string>(); // Set of added row keys
|
|
120
|
+
#cellCommitRevisions = new Map<string, Map<string, number>>(); // (key, col) => revision
|
|
121
|
+
#transitionQueue = Promise.resolve(); // Serialized transition queue
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
`CellEdit` holds:
|
|
125
|
+
```typescript
|
|
126
|
+
type CellEdit = {
|
|
127
|
+
originalValue: EditSessionValue;
|
|
128
|
+
editedValue: EditSessionValue;
|
|
129
|
+
isValid: boolean;
|
|
130
|
+
};
|
|
131
|
+
```
|
|
132
|
+
A cell is considered edited only when `originalValue !== editedValue && isValid === true`. If edited back to the original value, the entry is automatically pruned.
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Editing Operations & Flows
|
|
137
|
+
|
|
138
|
+
### Cell Editing (`commit` / `cancel`)
|
|
139
|
+
|
|
140
|
+
- **`commit(key, columnName, originalValue, typedValue, isValid, options)`**:
|
|
141
|
+
- Increments cell revision to guard against out-of-order RPC responses.
|
|
142
|
+
- Updates `#rowEdits`, adjusting `editCount` and `invalidCount`.
|
|
143
|
+
- Dispatches `editCell` RPC to the active DataSource if `syncToDataSource !== false`.
|
|
144
|
+
- Emits `"cellEditChanged"` and `"editState"`.
|
|
145
|
+
- **`cancel(key, columnName, restoredValue)`**:
|
|
146
|
+
- Discards an in-progress invalid edit, restoring the cell to its original valid state. Uncommitted typed values are discarded client-side without sending an RPC.
|
|
147
|
+
|
|
148
|
+
### New Row Flow (`addNewRow` / `addRow`)
|
|
149
|
+
|
|
150
|
+
1. **Configure**: `editSession.configureNewRow(columns, requiredColumns)` defines the expected column inputs.
|
|
151
|
+
2. **Draft**: `editSession.setNewRowValue(column, value)` updates `#newRowState.values`.
|
|
152
|
+
3. **Submit**: `editSession.addNewRow()` validates required columns and delegates to `addRow()`.
|
|
153
|
+
4. **`addRow(rowData)`**:
|
|
154
|
+
- Calls `dataSource.addRow(rowData)` with `#rowDefaults` merged in.
|
|
155
|
+
- On success, extracts the row key directly from the response map (`response.data.key`) and records it in `#addedRowKeys`.
|
|
156
|
+
- Increments `addCount`.
|
|
157
|
+
- Resets new-row form draft and increments `draftRevision`.
|
|
158
|
+
|
|
159
|
+
### Row Deletions (`deleteSelectedRows`)
|
|
160
|
+
|
|
161
|
+
- Captures `selectedRowsCount` before deleting.
|
|
162
|
+
- Exits early if `selectedRowsCount === 0`.
|
|
163
|
+
- Calls `dataSource.deleteSelectedRows(deleteMode)`.
|
|
164
|
+
- On success:
|
|
165
|
+
- Increments `deleteCount` by `selectedRowsCount`.
|
|
166
|
+
- **Clears selection**: Dispatches `dataSource.select({ type: "DESELECT_ALL" })` so deleted rows are immediately deselected, preventing accidental double-deletion and disabling the Delete button.
|
|
167
|
+
|
|
168
|
+
### Undo Flow (`undoRowChange`)
|
|
169
|
+
|
|
170
|
+
Invoked when the user clicks the Undo button on a row (`UndoCellRenderer`):
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
editSession.undoRowChange(key, action);
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
1. **Reverts cell edits**: Clears recorded cell edits for `key`, restores previous values, and adjusts `editCount` / `invalidCount`.
|
|
177
|
+
2. **Reverts deletions**: If `action === "deleteRow"`, decrements `deleteCount`.
|
|
178
|
+
3. **Reverts insertions**: If the row was an inserted row:
|
|
179
|
+
- `action === "addRow"` OR
|
|
180
|
+
- Row key exists in private `#addedRowKeys`
|
|
181
|
+
- Decrements `addCount` and removes `key` from `#addedRowKeys`.
|
|
182
|
+
|
|
183
|
+
> **Robust Add-Delete-Undo**: Even if a row was added, then soft-deleted (`action` became `"deleteRow"`), and the server purges the row on undo without returning any special flag, `EditSession` identifies the row via `#addedRowKeys` and decrements **both** `deleteCount` and `addCount`, returning `editState` cleanly to `"clean"`.
|
|
184
|
+
|
|
185
|
+
### Session Completion (`end`) & Stale Handling
|
|
186
|
+
|
|
187
|
+
- **`end(saveChanges = false, force = false)`**:
|
|
188
|
+
- Transitions lifecycle to `"ending"`.
|
|
189
|
+
- Calls `dataSource.endEditSession(saveChanges, force)`.
|
|
190
|
+
- On success: clears all edits, resets counters, unsubscribes session DataSource, transitions to `"idle"`.
|
|
191
|
+
- **Stale Updates (`StaleUpdateError`)**: If the server rejects the commit due to concurrent edits, lifecycle transitions to `error { operation: "end" }` and `editState` becomes `"stale"`. The user can force-save with `end(true, true)`.
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## Direct Editing (`DirectEditSession`)
|
|
196
|
+
|
|
197
|
+
Implements `TableEditSession` for tables that support in-place cell editing without a session table or lifecycle state machine:
|
|
198
|
+
- Does not create session tables or track `editCount`.
|
|
199
|
+
- Each `commit()` forwards directly to `dataSource.editCell()`.
|
|
200
|
+
- `inEditMode` is always `false`.
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## React Hooks & Context
|
|
205
|
+
|
|
206
|
+
### `useEditableTable`
|
|
207
|
+
|
|
208
|
+
The primary orchestrator hook for table components:
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
const {
|
|
212
|
+
canCancel, // boolean: safe to show/enable Cancel button
|
|
213
|
+
canSave, // boolean: active, dirty/stale, invalidCount === 0
|
|
214
|
+
dataSource, // Active DataSource (session DS in edit mode, else source DS)
|
|
215
|
+
sourceDataSource, // Always the source DataSource
|
|
216
|
+
sessionDataSource, // Session DataSource (when active)
|
|
217
|
+
editSession, // EditSession instance
|
|
218
|
+
lifecycle, // Current EditLifecycle
|
|
219
|
+
hasSelection, // boolean: whether rows are selected (controls Delete button)
|
|
220
|
+
isEditMode, // boolean: current edit mode flag
|
|
221
|
+
isEditSessionReady, // boolean: gates rendering the editable Table
|
|
222
|
+
isRowSelectable, // (dataRow) => boolean: blocks selection of soft-deleted rows
|
|
223
|
+
rowClassNameGenerators, // [vuu-edit-actions] in edit mode, else undefined
|
|
224
|
+
onCancel, // async handler: ends session and calls props.onCancel
|
|
225
|
+
onDelete, // async handler: deletes selected rows
|
|
226
|
+
onSave, // async handler: ends session (with optional force) and calls props.onSave
|
|
227
|
+
onUndoRowChange, // (key, action) => void
|
|
228
|
+
} = useEditableTable(props);
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### `DataEditingProvider` & `useEditSession`
|
|
232
|
+
|
|
233
|
+
Distributes `EditSession` through React Context to descendant cells and controls:
|
|
234
|
+
|
|
235
|
+
```tsx
|
|
236
|
+
<DataEditingProvider editSession={editSession}>
|
|
237
|
+
{/* Table and EditButtons subtree */}
|
|
238
|
+
</DataEditingProvider>
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
- `useEditSession()`: Returns `EditSession | undefined`.
|
|
242
|
+
- `useEditSession(true)`: Returns `EditSession`, throws if unmounted.
|
|
243
|
+
- `useTableEditSession()`: Returns generic `TableEditSession` (works with both `EditSession` and `DirectEditSession`).
|
|
244
|
+
|
|
245
|
+
### `useCellEdited`
|
|
246
|
+
|
|
247
|
+
Uses `useSyncExternalStore` for zero-lag cell edit detection. Returns `true` if `(rowKey, columnName)` has an uncommitted edit:
|
|
248
|
+
|
|
249
|
+
```typescript
|
|
250
|
+
const isEdited = useCellEdited(editSession, rowKey, columnName);
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### `useEditMode` & `EditModeProvider`
|
|
254
|
+
|
|
255
|
+
Optional context for coordinating a boolean edit/view mode toggle across independent toolbar and table components:
|
|
256
|
+
|
|
257
|
+
```tsx
|
|
258
|
+
const { isEditMode, setEditMode } = useEditMode();
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## UI Components & Helpers
|
|
264
|
+
|
|
265
|
+
### `EditButtons`
|
|
266
|
+
|
|
267
|
+
Pre-built action buttons wired to `EditSession`:
|
|
268
|
+
- **Delete**: Enabled only when `hasSelection === true`.
|
|
269
|
+
- **Save**: Enabled when `canSave === true`. Displays `"Save (force)"` when `editState === "stale"`.
|
|
270
|
+
- **Cancel**: Enabled when `canCancel === true`.
|
|
271
|
+
|
|
272
|
+
```tsx
|
|
273
|
+
<EditButtons
|
|
274
|
+
canCancel={canCancel}
|
|
275
|
+
canSave={canSave}
|
|
276
|
+
editSession={editSession}
|
|
277
|
+
hasSelection={hasSelection}
|
|
278
|
+
onCancel={onCancel}
|
|
279
|
+
onDelete={onDelete}
|
|
280
|
+
onSave={onSave}
|
|
281
|
+
/>
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### `UndoCellRenderer`
|
|
285
|
+
|
|
286
|
+
Registered as `"vuu.undo-cell"`. Renders an Undo button in the row's action column:
|
|
287
|
+
- Dispatches `editSession.undoRowChange(key, action)` on click.
|
|
288
|
+
- Tooltip dynamically reflects action: `"Undo insert row"`, `"Undo delete row"`, or `"Undo row edits"`.
|
|
289
|
+
|
|
290
|
+
### `editActionRowClassNameGenerator`
|
|
291
|
+
|
|
292
|
+
Registered as `"vuu-edit-actions"`. Applies row CSS classes based on `dataRow.vuuAction`:
|
|
293
|
+
- `"addRow"` → `.vuuTableRow-inserted`
|
|
294
|
+
- `"deleteRow"` → `.vuuTableRow-deleted`
|
|
295
|
+
|
|
296
|
+
### `isRowSelectable` / `isEditRowReadOnly`
|
|
297
|
+
|
|
298
|
+
- `isEditRowReadOnly(dataRow)`: Returns `true` if `dataRow.vuuAction === "deleteRow"`.
|
|
299
|
+
- `isRowSelectable`: Exported from `useEditableTable` as `(dataRow) => !isEditRowReadOnly(dataRow)`. Pass to `<Table isRowSelectable={isRowSelectable} />` to prevent users from selecting soft-deleted rows.
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
## Standard Integration Pattern
|
|
304
|
+
|
|
305
|
+
```tsx
|
|
306
|
+
import React, { useCallback, useState } from "react";
|
|
307
|
+
import { Table } from "@vuu-ui/vuu-table";
|
|
308
|
+
import {
|
|
309
|
+
DataEditingProvider,
|
|
310
|
+
EditButtons,
|
|
311
|
+
useEditableTable,
|
|
312
|
+
} from "@vuu-ui/vuu-data-editing";
|
|
313
|
+
|
|
314
|
+
export const EditableTableFeature = ({ sourceDataSource, tableConfig }) => {
|
|
315
|
+
const [isEditMode, setIsEditMode] = useState(false);
|
|
316
|
+
|
|
317
|
+
const {
|
|
318
|
+
canCancel,
|
|
319
|
+
canSave,
|
|
320
|
+
dataSource,
|
|
321
|
+
editSession,
|
|
322
|
+
hasSelection,
|
|
323
|
+
isEditSessionReady,
|
|
324
|
+
isRowSelectable,
|
|
325
|
+
onCancel,
|
|
326
|
+
onDelete,
|
|
327
|
+
onSave,
|
|
328
|
+
rowClassNameGenerators,
|
|
329
|
+
} = useEditableTable({
|
|
330
|
+
dataSource: sourceDataSource,
|
|
331
|
+
isEditMode,
|
|
332
|
+
onCancel: () => setIsEditMode(false),
|
|
333
|
+
onSave: () => setIsEditMode(false),
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
return (
|
|
337
|
+
<DataEditingProvider editSession={editSession}>
|
|
338
|
+
<div className="table-container">
|
|
339
|
+
{(!isEditMode || isEditSessionReady) && (
|
|
340
|
+
<Table
|
|
341
|
+
config={tableConfig}
|
|
342
|
+
dataSource={dataSource}
|
|
343
|
+
isRowSelectable={isRowSelectable}
|
|
344
|
+
rowClassNameGenerators={rowClassNameGenerators}
|
|
345
|
+
/>
|
|
346
|
+
)}
|
|
347
|
+
</div>
|
|
348
|
+
|
|
349
|
+
<div className="toolbar">
|
|
350
|
+
{!isEditMode ? (
|
|
351
|
+
<button onClick={() => setIsEditMode(true)}>Edit</button>
|
|
352
|
+
) : (
|
|
353
|
+
<EditButtons
|
|
354
|
+
canCancel={canCancel}
|
|
355
|
+
canSave={canSave}
|
|
356
|
+
editSession={editSession}
|
|
357
|
+
hasSelection={hasSelection}
|
|
358
|
+
onCancel={onCancel}
|
|
359
|
+
onDelete={onDelete}
|
|
360
|
+
onSave={onSave}
|
|
361
|
+
/>
|
|
362
|
+
)}
|
|
363
|
+
</div>
|
|
364
|
+
</DataEditingProvider>
|
|
365
|
+
);
|
|
366
|
+
};
|
|
367
|
+
```
|
|
368
|
+
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "4.0.0-alpha.
|
|
2
|
+
"version": "4.0.0-alpha.22",
|
|
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": "4.0.0-alpha.
|
|
16
|
-
"@vuu-ui/vuu-utils": "4.0.0-alpha.
|
|
14
|
+
"@salt-ds/core": "1.72.0",
|
|
15
|
+
"@vuu-ui/vuu-ui-controls": "4.0.0-alpha.22",
|
|
16
|
+
"@vuu-ui/vuu-utils": "4.0.0-alpha.22"
|
|
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.22",
|
|
20
|
+
"@vuu-ui/vuu-protocol-types": "4.0.0-alpha.22",
|
|
21
|
+
"@vuu-ui/vuu-table-types": "4.0.0-alpha.22"
|
|
22
22
|
},
|
|
23
23
|
"peerDependencies": {
|
|
24
24
|
"react": "^19.2.3"
|
package/src/EditSession.js
CHANGED
|
@@ -16,6 +16,7 @@ class SupersededEditError extends Error {
|
|
|
16
16
|
class EditSession extends EventEmitter {
|
|
17
17
|
static newRowKey = "__vuu_new_row__";
|
|
18
18
|
#rowEdits = new Map();
|
|
19
|
+
#addedRowKeys = new Set();
|
|
19
20
|
#editCount = 0;
|
|
20
21
|
#deleteCount = 0;
|
|
21
22
|
#addCount = 0;
|
|
@@ -88,19 +89,21 @@ class EditSession extends EventEmitter {
|
|
|
88
89
|
}
|
|
89
90
|
}
|
|
90
91
|
#setDeleteCount(val) {
|
|
91
|
-
|
|
92
|
+
const newCount = Math.max(0, val);
|
|
93
|
+
if (newCount !== this.#deleteCount) {
|
|
92
94
|
const oldState = this.editState;
|
|
93
95
|
const oldCount = this.#deleteCount;
|
|
94
|
-
this.#deleteCount =
|
|
95
|
-
this.#emitEditStateChange(oldState, 0 === oldCount || 0 ===
|
|
96
|
+
this.#deleteCount = newCount;
|
|
97
|
+
this.#emitEditStateChange(oldState, 0 === oldCount || 0 === newCount);
|
|
96
98
|
}
|
|
97
99
|
}
|
|
98
100
|
#setAddCount(val) {
|
|
99
|
-
|
|
101
|
+
const newCount = Math.max(0, val);
|
|
102
|
+
if (newCount !== this.#addCount) {
|
|
100
103
|
const oldState = this.editState;
|
|
101
104
|
const oldCount = this.#addCount;
|
|
102
|
-
this.#addCount =
|
|
103
|
-
this.#emitEditStateChange(oldState, 0 === oldCount || 0 ===
|
|
105
|
+
this.#addCount = newCount;
|
|
106
|
+
this.#emitEditStateChange(oldState, 0 === oldCount || 0 === newCount);
|
|
104
107
|
}
|
|
105
108
|
}
|
|
106
109
|
#setStale(isStale) {
|
|
@@ -234,10 +237,17 @@ class EditSession extends EventEmitter {
|
|
|
234
237
|
const deleteSelectedRows = this.dataSource?.deleteSelectedRows;
|
|
235
238
|
if (void 0 === deleteSelectedRows) throw Error("[EditSession] datasource does not support deleting rows");
|
|
236
239
|
const selectedRowsCount = this.dataSource?.selectedRowsCount ?? 0;
|
|
240
|
+
if (0 === selectedRowsCount) return {
|
|
241
|
+
data: void 0,
|
|
242
|
+
type: "SUCCESS_RESULT"
|
|
243
|
+
};
|
|
237
244
|
const response = await deleteSelectedRows.call(this.dataSource, this.#deleteMode);
|
|
238
245
|
if (void 0 === response) throw Error("[EditSession] datasource returned no response when deleting rows");
|
|
239
246
|
if (isRpcError(response)) return response;
|
|
240
247
|
if (selectedRowsCount > 0) this.#setDeleteCount(this.#deleteCount + selectedRowsCount);
|
|
248
|
+
await this.dataSource?.select?.({
|
|
249
|
+
type: "DESELECT_ALL"
|
|
250
|
+
});
|
|
241
251
|
return response;
|
|
242
252
|
}
|
|
243
253
|
async addRow(rowData = {}) {
|
|
@@ -248,7 +258,11 @@ class EditSession extends EventEmitter {
|
|
|
248
258
|
...rowData
|
|
249
259
|
});
|
|
250
260
|
if (void 0 === response) throw Error("[EditSession] datasource returned no response when adding row");
|
|
251
|
-
if (!isRpcError(response))
|
|
261
|
+
if (!isRpcError(response)) {
|
|
262
|
+
const key = response.data?.key;
|
|
263
|
+
if (null != key) this.#addedRowKeys.add(String(key));
|
|
264
|
+
this.#setAddCount(this.#addCount + 1);
|
|
265
|
+
}
|
|
252
266
|
return response;
|
|
253
267
|
}
|
|
254
268
|
hasRowChanges(key) {
|
|
@@ -287,9 +301,12 @@ class EditSession extends EventEmitter {
|
|
|
287
301
|
this.#invalidCount -= removedInvalidCount;
|
|
288
302
|
for (const columnName of changedColumns)this.emit("cellEditChanged", key, columnName);
|
|
289
303
|
}
|
|
290
|
-
if ("deleteRow" === action) this.#deleteCount
|
|
291
|
-
const wasInsertedRow = "addRow" === action ||
|
|
292
|
-
if (wasInsertedRow)
|
|
304
|
+
if ("deleteRow" === action) this.#deleteCount = Math.max(0, this.#deleteCount - 1);
|
|
305
|
+
const wasInsertedRow = "addRow" === action || this.#addedRowKeys.has(key);
|
|
306
|
+
if (wasInsertedRow) {
|
|
307
|
+
this.#addedRowKeys.delete(key);
|
|
308
|
+
this.#addCount = Math.max(0, this.#addCount - 1);
|
|
309
|
+
}
|
|
293
310
|
this.#emitEditStateChange(oldState);
|
|
294
311
|
return response;
|
|
295
312
|
}
|
|
@@ -304,6 +321,7 @@ class EditSession extends EventEmitter {
|
|
|
304
321
|
columnName
|
|
305
322
|
]));
|
|
306
323
|
this.#rowEdits.clear();
|
|
324
|
+
this.#addedRowKeys.clear();
|
|
307
325
|
this.#cellCommitRevisions.clear();
|
|
308
326
|
this.#editCount = 0;
|
|
309
327
|
this.#deleteCount = 0;
|
|
@@ -402,8 +420,10 @@ class EditSession extends EventEmitter {
|
|
|
402
420
|
sessionDataSource
|
|
403
421
|
});
|
|
404
422
|
try {
|
|
405
|
-
|
|
406
|
-
|
|
423
|
+
if ("unsubscribed" !== sessionDataSource.status || saveChanges) {
|
|
424
|
+
const response = await this.dataSource?.endEditSession?.(saveChanges, force);
|
|
425
|
+
if (isRpcError(response)) throw new Error(response.errorMessage);
|
|
426
|
+
}
|
|
407
427
|
this.#clearEdits();
|
|
408
428
|
this.#sessionDataSource = void 0;
|
|
409
429
|
this.#setLifecycle({
|
package/src/useEditableTable.js
CHANGED
|
@@ -2,6 +2,7 @@ import { useData, useLayoutEffectSkipFirst } from "@vuu-ui/vuu-utils";
|
|
|
2
2
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
3
3
|
import { EditSession } from "./EditSession.js";
|
|
4
4
|
import { EDIT_ACTION_ROW_CLASS_NAME_GENERATOR } from "./editActionRowClassNameGenerator.js";
|
|
5
|
+
import { isEditRowReadOnly } from "./edit-utils.js";
|
|
5
6
|
const EDIT_ACTION_ROW_CLASS_NAME_GENERATORS = [
|
|
6
7
|
EDIT_ACTION_ROW_CLASS_NAME_GENERATOR
|
|
7
8
|
];
|
|
@@ -148,6 +149,7 @@ const useEditableTable = ({ columns, dataSource: dataSourceProp, deleteMode = "s
|
|
|
148
149
|
onDelete: handleDelete,
|
|
149
150
|
onSave: handleSave,
|
|
150
151
|
onUndoRowChange: handleUndoRowChange,
|
|
152
|
+
isRowSelectable: isEditMode ? (dataRow)=>!isEditRowReadOnly(dataRow) : void 0,
|
|
151
153
|
rowClassNameGenerators: isEditMode ? EDIT_ACTION_ROW_CLASS_NAME_GENERATORS : void 0,
|
|
152
154
|
sessionDataSource,
|
|
153
155
|
sourceDataSource
|
|
@@ -4,7 +4,7 @@ import type { TableEditSession } from "./TableEditSession";
|
|
|
4
4
|
export declare const DataEditingProvider: ({ children, editSession, }: {
|
|
5
5
|
children: ReactNode;
|
|
6
6
|
editSession: TableEditSession;
|
|
7
|
-
}) => import("react").JSX.Element;
|
|
7
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
8
8
|
/**
|
|
9
9
|
* Returns the EditSession provided by an enclosing DataEditingProvider. If the
|
|
10
10
|
* provider holds some other TableEditSession (e.g. DirectEditSession), there is
|
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: _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-runtime").JSX.Element;
|
|
@@ -10,5 +10,5 @@ export interface EditModeContextProps {
|
|
|
10
10
|
export declare const EditModeProvider: ({ children, isEditMode: isEditModeProp, }: {
|
|
11
11
|
children: ReactNode;
|
|
12
12
|
isEditMode?: boolean;
|
|
13
|
-
}) => import("react").JSX.Element;
|
|
13
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
14
14
|
export declare const useEditMode: () => EditModeContextProps;
|
package/types/EditSession.d.ts
CHANGED
|
@@ -21,6 +21,9 @@ export type EditSessionConstructorProps = {
|
|
|
21
21
|
/** Default column values merged into every addRow call for absent columns. Pass a stable reference. */
|
|
22
22
|
rowDefaults?: RowDefaultDataItemValues;
|
|
23
23
|
};
|
|
24
|
+
export type AddRowResultData = {
|
|
25
|
+
key?: string | number;
|
|
26
|
+
};
|
|
24
27
|
export type NewRowState = {
|
|
25
28
|
columns: readonly string[];
|
|
26
29
|
requiredColumns?: readonly string[];
|
|
@@ -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").JSX.Element | null;
|
|
12
|
+
export declare const UndoCellRenderer: ({ column, dataRow, }: TableCellRendererProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -18,4 +18,4 @@ export interface DropdownEditFieldProps extends EditFieldProps {
|
|
|
18
18
|
optionMap: OptionMap;
|
|
19
19
|
table: VuuTable;
|
|
20
20
|
}
|
|
21
|
-
export declare const EditField: ({ dataRow, deferNewRow, label, name, readOnly, required, type, ...options }: EditFieldProps | DropdownEditFieldProps) => import("react").JSX.Element;
|
|
21
|
+
export declare const EditField: ({ dataRow, deferNewRow, label, name, readOnly, required, type, ...options }: EditFieldProps | DropdownEditFieldProps) => import("react/jsx-runtime").JSX.Element;
|
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").JSX.Element | undefined;
|
|
5
|
+
export declare const getVuuEditMessage: (dataRow: DataRow, column: RuntimeColumnDescriptor, originalValue: string) => string | import("react/jsx-runtime").JSX.Element | undefined;
|
package/types/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export { EditButtons, type EditButtonProps } from "./EditButtons";
|
|
|
8
8
|
export { EditField, type DropdownEditFieldProps, type EditFieldProps, type EditFieldType, type TextFieldType, } from "./edit-field/EditField";
|
|
9
9
|
export { useEditField, type EditFieldHookProps, } from "./edit-field/useEditField";
|
|
10
10
|
export { EditModeProvider, useEditMode, type EditModeContextProps, } from "./EditModeProvider";
|
|
11
|
-
export { EditError, EditSession, SupersededEditError, type EditActionType, type EditCommitOptions, type EditLifecycle, type EditSessionConstructorProps, type EditSessionValue, type NewRowState, type EditState, type RowDefaultDataItemValues, } from "./EditSession";
|
|
11
|
+
export { EditError, EditSession, SupersededEditError, type AddRowResultData, type EditActionType, type EditCommitOptions, type EditLifecycle, type EditSessionConstructorProps, type EditSessionValue, type NewRowState, type EditState, type RowDefaultDataItemValues, } from "./EditSession";
|
|
12
12
|
export { StaleUpdateError } from "@vuu-ui/vuu-utils";
|
|
13
13
|
export { lookupOptionsFromRows, useLookupValues, type LookupOption, type LookupValuedHookProps, type OptionMap, } from "./lookup-values/useLookupValues";
|
|
14
14
|
export { useEditable, type EditableHookProps } from "./useEditable";
|
|
@@ -1,5 +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 type { DataRow } from "@vuu-ui/vuu-table-types";
|
|
3
4
|
import { EditSession, type EditActionType, type EditLifecycle, type EditSessionApi, type RowDefaultDataItemValues } from "./EditSession";
|
|
4
5
|
export type EditMode = "edit" | "view";
|
|
5
6
|
export interface EditableTableHookProps {
|
|
@@ -38,6 +39,7 @@ export declare const useEditableTable: ({ columns, dataSource: dataSourceProp, d
|
|
|
38
39
|
onDelete: () => Promise<void>;
|
|
39
40
|
onSave: (force?: boolean) => Promise<void>;
|
|
40
41
|
onUndoRowChange: (key: string, action: EditActionType) => undefined;
|
|
42
|
+
isRowSelectable: ((dataRow: DataRow) => boolean) | undefined;
|
|
41
43
|
rowClassNameGenerators: string[] | undefined;
|
|
42
44
|
sessionDataSource: import("@vuu-ui/vuu-data-types").DataSourceBase<import("@vuu-ui/vuu-data-types").DataSourceRowWithBigint> | undefined;
|
|
43
45
|
sourceDataSource: DataSource;
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { type ReactNode } from "react";
|
|
2
|
-
import type { EditSession } from "./EditSession";
|
|
3
|
-
export declare const DataEditingProvider: ({ children, editSession, }: {
|
|
4
|
-
children: ReactNode;
|
|
5
|
-
editSession: EditSession;
|
|
6
|
-
}) => import("react").JSX.Element;
|
|
7
|
-
export declare function useEditSession(throwIfUnavailable?: false): EditSession | undefined;
|
|
8
|
-
export declare function useEditSession(throwIfUnavailable: true): EditSession;
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { EditSession } from "./EditSession";
|
|
2
|
-
export interface EditButtonProps {
|
|
3
|
-
canCancel: boolean;
|
|
4
|
-
canSave: boolean;
|
|
5
|
-
editSession?: EditSession;
|
|
6
|
-
hasSelection?: boolean;
|
|
7
|
-
onCancel?: () => void;
|
|
8
|
-
onDelete?: () => void;
|
|
9
|
-
onSave: (force?: boolean) => void;
|
|
10
|
-
saveLabel?: string;
|
|
11
|
-
confirmSave?: () => boolean | Promise<boolean>;
|
|
12
|
-
confirmCancel?: () => boolean | Promise<boolean>;
|
|
13
|
-
}
|
|
14
|
-
export declare const EditButtons: ({ canCancel, canSave, confirmCancel, confirmSave, editSession, hasSelection, onCancel, onDelete, onSave, saveLabel, }: EditButtonProps) => import("react").JSX.Element;
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { ReactNode } from "react";
|
|
2
|
-
export interface EditModeContextProps {
|
|
3
|
-
isEditMode: boolean;
|
|
4
|
-
setEditMode: (inEditMode: boolean) => void;
|
|
5
|
-
}
|
|
6
|
-
/**
|
|
7
|
-
* Implemented as a standalone Provider so that EditMode cna be implemented
|
|
8
|
-
* at higher level than individual edit controls.
|
|
9
|
-
*/
|
|
10
|
-
export declare const EditModeProvider: ({ children }: {
|
|
11
|
-
children: ReactNode;
|
|
12
|
-
}) => import("react").JSX.Element;
|
|
13
|
-
export declare const useEditMode: () => EditModeContextProps;
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import type { CopyOption, DataSource, DeleteRowMode, SessionType } from "@vuu-ui/vuu-data-types";
|
|
2
|
-
import type { RpcResult, VuuRowDataItemType } from "@vuu-ui/vuu-protocol-types";
|
|
3
|
-
import { EventEmitter } from "@vuu-ui/vuu-utils";
|
|
4
|
-
export type EditState = "clean" | "dirty" | "invalid" | "stale";
|
|
5
|
-
export type EditActionType = "deleteRow" | "addRow" | "editCell";
|
|
6
|
-
/** Column name to default value mapping applied to every addRow call when a column is absent from the row data. */
|
|
7
|
-
export type RowDefaultDataItemValues = Record<string, VuuRowDataItemType>;
|
|
8
|
-
export type EditSessionApi = "createSessionDataSource" | "beginEditSession";
|
|
9
|
-
export type EditSessionConstructorProps = {
|
|
10
|
-
dataSource: DataSource;
|
|
11
|
-
/** @default "soft" */
|
|
12
|
-
deleteMode?: DeleteRowMode;
|
|
13
|
-
/** @default "createSessionDataSource" */
|
|
14
|
-
editSessionApi?: EditSessionApi;
|
|
15
|
-
/** Default column values merged into every addRow call for absent columns. Pass a stable reference. */
|
|
16
|
-
rowDefaults?: RowDefaultDataItemValues;
|
|
17
|
-
};
|
|
18
|
-
export type NewRowState = {
|
|
19
|
-
columns: readonly string[];
|
|
20
|
-
requiredColumns?: readonly string[];
|
|
21
|
-
draftRevision: number;
|
|
22
|
-
errors: Readonly<Record<string, string>>;
|
|
23
|
-
submitting: boolean;
|
|
24
|
-
values: Readonly<Record<string, VuuRowDataItemType>>;
|
|
25
|
-
};
|
|
26
|
-
export type EditLifecycle = {
|
|
27
|
-
status: "idle";
|
|
28
|
-
} | {
|
|
29
|
-
status: "starting";
|
|
30
|
-
} | {
|
|
31
|
-
status: "active";
|
|
32
|
-
sessionDataSource: DataSource;
|
|
33
|
-
} | {
|
|
34
|
-
status: "ending";
|
|
35
|
-
sessionDataSource: DataSource;
|
|
36
|
-
} | {
|
|
37
|
-
status: "error";
|
|
38
|
-
operation: "begin" | "end";
|
|
39
|
-
error: Error;
|
|
40
|
-
sessionDataSource?: DataSource;
|
|
41
|
-
};
|
|
42
|
-
export declare class EditError extends Error {
|
|
43
|
-
}
|
|
44
|
-
export declare class SupersededEditError extends Error {
|
|
45
|
-
}
|
|
46
|
-
type EditSessionEvents = {
|
|
47
|
-
cellEditChanged: (key: string, columnName: string) => void;
|
|
48
|
-
editState: (editState: EditState) => void;
|
|
49
|
-
lifecycle: (lifecycle: EditLifecycle) => void;
|
|
50
|
-
newRow: (newRowState: NewRowState) => void;
|
|
51
|
-
};
|
|
52
|
-
export declare class EditSession extends EventEmitter<EditSessionEvents> {
|
|
53
|
-
#private;
|
|
54
|
-
static readonly newRowKey = "__vuu_new_row__";
|
|
55
|
-
constructor({ dataSource, deleteMode, editSessionApi, rowDefaults, }: EditSessionConstructorProps);
|
|
56
|
-
get editCount(): number;
|
|
57
|
-
get invalidCount(): number;
|
|
58
|
-
get deleteCount(): number;
|
|
59
|
-
get addCount(): number;
|
|
60
|
-
get editState(): EditState;
|
|
61
|
-
get newRowState(): NewRowState;
|
|
62
|
-
isNewRow(key: string): key is "__vuu_new_row__";
|
|
63
|
-
isNewRowFinalColumn(columnName: string): boolean;
|
|
64
|
-
isNewRowComplete(): boolean;
|
|
65
|
-
configureNewRow(columns: readonly string[], requiredColumns?: readonly string[]): void;
|
|
66
|
-
setNewRowValue(column: string, value: VuuRowDataItemType): void;
|
|
67
|
-
addNewRow(): Promise<RpcResult>;
|
|
68
|
-
deleteSelectedRows(): Promise<RpcResult>;
|
|
69
|
-
addRow(rowData?: Record<string, VuuRowDataItemType>): Promise<RpcResult>;
|
|
70
|
-
hasRowChanges(key: string): boolean;
|
|
71
|
-
isCellEdited(key: string, columnName: string): boolean;
|
|
72
|
-
undoRowChange(key: string, action: EditActionType): Promise<RpcResult | undefined>;
|
|
73
|
-
begin(copyOption?: CopyOption, sessionType?: SessionType): Promise<DataSource>;
|
|
74
|
-
/**
|
|
75
|
-
* Safe to call repeatedly - schema of a remote session table typically arrives
|
|
76
|
-
* after begin() resolves, so callers re-invoke this once 'subscribed' fires.
|
|
77
|
-
*/
|
|
78
|
-
reconcileWithSessionSchema(): void;
|
|
79
|
-
get dataSource(): import("@vuu-ui/vuu-data-types").DataSourceBase<import("@vuu-ui/vuu-data-types").DataSourceRowWithBigint> | undefined;
|
|
80
|
-
get sessionDataSource(): DataSource | undefined;
|
|
81
|
-
end(saveChanges?: boolean, force?: boolean): Promise<void>;
|
|
82
|
-
get lifecycle(): EditLifecycle;
|
|
83
|
-
get inEditMode(): boolean;
|
|
84
|
-
commit(key: string, columnName: string, originalValue: VuuRowDataItemType, typedValue: string | number | boolean, isValid: boolean): Promise<RpcResult>;
|
|
85
|
-
}
|
|
86
|
-
export {};
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { TableCellRendererProps } from "@vuu-ui/vuu-table-types";
|
|
2
|
-
export declare const UNDO_CELL_RENDERER = "vuu.undo-cell";
|
|
3
|
-
export interface UndoCellRendererComponentProps {
|
|
4
|
-
icon?: string;
|
|
5
|
-
text?: string | false;
|
|
6
|
-
}
|
|
7
|
-
export declare const getUndoButtonContent: (componentProps?: UndoCellRendererComponentProps) => {
|
|
8
|
-
icon: string | undefined;
|
|
9
|
-
text: string | undefined;
|
|
10
|
-
};
|
|
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").JSX.Element | null;
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import type { DataRow, RuntimeColumnDescriptor } from "@vuu-ui/vuu-table-types";
|
|
2
|
-
export { isInlineEditingSession } from "@vuu-ui/vuu-utils";
|
|
3
|
-
export declare const isEditRowReadOnly: (dataRow: DataRow) => boolean;
|
|
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").JSX.Element | undefined;
|
package/types/src/index.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export { DataEditingProvider, useEditSession } from "./DataEditingProvider";
|
|
2
|
-
export { useCellEdited } from "./useCellEdited";
|
|
3
|
-
export { getVuuEditMessage, isInlineEditingSession, isEditRowReadOnly, withDataRowEditErrors, } from "./edit-utils";
|
|
4
|
-
export { EditButtons, type EditButtonProps } from "./EditButtons";
|
|
5
|
-
export { EditModeProvider, useEditMode, type EditModeContextProps, } from "./EditModeProvider";
|
|
6
|
-
export { EditError, EditSession, SupersededEditError, type EditActionType, type EditLifecycle, type EditSessionConstructorProps, type NewRowState, type EditState, type RowDefaultDataItemValues, } from "./EditSession";
|
|
7
|
-
export { StaleUpdateError } from "@vuu-ui/vuu-utils";
|
|
8
|
-
export { EDIT_ACTION_ROW_CLASS_NAME_GENERATOR, editActionRowClassNameGenerator, } from "./editActionRowClassNameGenerator";
|
|
9
|
-
export { getUndoButtonContent, getUndoTooltipContent, UNDO_CELL_RENDERER, UndoCellRenderer, type UndoCellRendererComponentProps, } from "./UndoCellRenderer";
|
|
10
|
-
export { useEditableTable, type EditableTableHookProps, type EditMode, } from "./useEditableTable";
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import type { CopyOption, DataSource, DeleteRowMode } from "@vuu-ui/vuu-data-types";
|
|
2
|
-
import type { VuuTable } from "@vuu-ui/vuu-protocol-types";
|
|
3
|
-
import { EditSession, type EditActionType, type EditLifecycle, type EditSessionApi, type RowDefaultDataItemValues } from "./EditSession";
|
|
4
|
-
export type EditMode = "edit" | "view";
|
|
5
|
-
export interface EditableTableHookProps {
|
|
6
|
-
/**
|
|
7
|
-
* columns to be included in subscription. If not provided,
|
|
8
|
-
* default will be '*'. Ignored if dataSource prop present.
|
|
9
|
-
*/
|
|
10
|
-
columns?: string[];
|
|
11
|
-
dataSource?: DataSource;
|
|
12
|
-
addRowsCount?: number;
|
|
13
|
-
deleteMode?: DeleteRowMode;
|
|
14
|
-
editSessionApi?: EditSessionApi;
|
|
15
|
-
copyOption?: CopyOption;
|
|
16
|
-
isEditMode: boolean;
|
|
17
|
-
onCancel: () => void;
|
|
18
|
-
onSave: () => void;
|
|
19
|
-
/** Default column values applied to every addRow call. Pass a stable reference — a new object triggers EditSession recreation. */
|
|
20
|
-
rowDefaults?: RowDefaultDataItemValues;
|
|
21
|
-
/**
|
|
22
|
-
* If dataSource not provided, new DataSource
|
|
23
|
-
* will be created using table and columns
|
|
24
|
-
*/
|
|
25
|
-
table?: VuuTable;
|
|
26
|
-
}
|
|
27
|
-
export declare const useEditableTable: ({ columns, dataSource: dataSourceProp, deleteMode, editSessionApi, copyOption, isEditMode, onCancel, onSave, rowDefaults, table, }: EditableTableHookProps) => {
|
|
28
|
-
canCancel: boolean;
|
|
29
|
-
canSave: boolean;
|
|
30
|
-
columnsDiverge: boolean;
|
|
31
|
-
dataSource: DataSource;
|
|
32
|
-
editSchema: import("@vuu-ui/vuu-data-types").TableSchema | undefined;
|
|
33
|
-
editSession: EditSession;
|
|
34
|
-
lifecycle: EditLifecycle;
|
|
35
|
-
hasSelection: boolean;
|
|
36
|
-
isEditSessionReady: boolean;
|
|
37
|
-
onCancel: () => Promise<void>;
|
|
38
|
-
onDelete: () => Promise<void>;
|
|
39
|
-
onSave: (force?: boolean) => Promise<void>;
|
|
40
|
-
onUndoRowChange: (key: string, action: EditActionType) => undefined;
|
|
41
|
-
rowClassNameGenerators: string[] | undefined;
|
|
42
|
-
sessionDataSource: import("@vuu-ui/vuu-data-types").DataSourceBase<import("@vuu-ui/vuu-data-types").DataSourceRowWithBigint> | undefined;
|
|
43
|
-
sourceDataSource: DataSource;
|
|
44
|
-
};
|