apex-grid 3.4.0 → 3.6.0
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/CHANGELOG.md +439 -0
- package/LICENSE.md +125 -0
- package/README.md +107 -14
- package/components/cell.d.ts +30 -4
- package/components/cell.js +199 -53
- package/components/cell.js.map +1 -1
- package/components/filter-row.d.ts +2 -0
- package/components/filter-row.js +82 -28
- package/components/filter-row.js.map +1 -1
- package/components/grid.d.ts +257 -20
- package/components/grid.js +463 -99
- package/components/grid.js.map +1 -1
- package/components/group-header-row.js +28 -25
- package/components/group-header-row.js.map +1 -1
- package/components/header-row.d.ts +7 -5
- package/components/header-row.js +19 -9
- package/components/header-row.js.map +1 -1
- package/components/header.js +36 -22
- package/components/header.js.map +1 -1
- package/components/row.d.ts +19 -3
- package/components/row.js +96 -22
- package/components/row.js.map +1 -1
- package/components/toolbar.js +2 -1
- package/components/toolbar.js.map +1 -1
- package/components/virtualizer.d.ts +45 -1
- package/components/virtualizer.js +184 -3
- package/components/virtualizer.js.map +1 -1
- package/controllers/dom.d.ts +4 -4
- package/controllers/dom.js +40 -22
- package/controllers/dom.js.map +1 -1
- package/controllers/editing.d.ts +104 -37
- package/controllers/editing.js +230 -78
- package/controllers/editing.js.map +1 -1
- package/controllers/expansion.d.ts +14 -5
- package/controllers/expansion.js +24 -1
- package/controllers/expansion.js.map +1 -1
- package/controllers/filter.d.ts +10 -2
- package/controllers/filter.js +62 -17
- package/controllers/filter.js.map +1 -1
- package/controllers/history.d.ts +45 -8
- package/controllers/history.js +58 -20
- package/controllers/history.js.map +1 -1
- package/controllers/navigation.d.ts +68 -13
- package/controllers/navigation.js +196 -51
- package/controllers/navigation.js.map +1 -1
- package/controllers/pagination.d.ts +6 -0
- package/controllers/pagination.js +10 -2
- package/controllers/pagination.js.map +1 -1
- package/controllers/reorder.js +42 -24
- package/controllers/reorder.js.map +1 -1
- package/controllers/resize.d.ts +17 -2
- package/controllers/resize.js +16 -6
- package/controllers/resize.js.map +1 -1
- package/controllers/row-pin.d.ts +20 -2
- package/controllers/row-pin.js +16 -9
- package/controllers/row-pin.js.map +1 -1
- package/controllers/row-reorder.d.ts +31 -11
- package/controllers/row-reorder.js +117 -37
- package/controllers/row-reorder.js.map +1 -1
- package/controllers/selection.d.ts +11 -4
- package/controllers/selection.js +26 -11
- package/controllers/selection.js.map +1 -1
- package/controllers/sort.d.ts +22 -2
- package/controllers/sort.js +29 -23
- package/controllers/sort.js.map +1 -1
- package/controllers/state.d.ts +65 -10
- package/controllers/state.js +86 -6
- package/controllers/state.js.map +1 -1
- package/controllers/tree.d.ts +15 -10
- package/controllers/tree.js +0 -0
- package/controllers/tree.js.map +1 -1
- package/custom-elements.json +3589 -452
- package/docs/assets/hierarchy.js +1 -1
- package/docs/assets/highlight.css +15 -8
- package/docs/assets/navigation.js +1 -1
- package/docs/assets/search.js +1 -1
- package/docs/classes/ApexGrid.html +660 -0
- package/docs/classes/ApexGridPaginator.html +36 -0
- package/docs/classes/ApexGridToolbar.html +67 -0
- package/docs/functions/localize.html +2 -2
- package/docs/functions/setup.html +1 -2
- package/docs/hierarchy.html +1 -1
- package/docs/index.html +105 -15
- package/docs/interfaces/ApexCellValidationFailedEvent.html +3 -2
- package/docs/interfaces/ApexCellValueChangedEvent.html +4 -2
- package/docs/interfaces/ApexCellValueChangingEvent.html +3 -2
- package/docs/interfaces/ApexColumnMovedEvent.html +2 -2
- package/docs/interfaces/ApexColumnMovingEvent.html +1 -1
- package/docs/interfaces/ApexDetailContext.html +2 -2
- package/docs/interfaces/ApexGridEventMap.html +9 -6
- package/docs/interfaces/ApexRowEditEndedEvent.html +2 -1
- package/docs/interfaces/ApexRowEditStartedEvent.html +2 -1
- package/docs/interfaces/ApexRowMovingEvent.html +9 -3
- package/docs/interfaces/ApexRowPinningEvent.html +1 -1
- package/docs/interfaces/ApexTreeRowExpandedEvent.html +4 -1
- package/docs/interfaces/ApexTreeRowExpandingEvent.html +4 -1
- package/docs/interfaces/BaseApexCellContext.html +1 -1
- package/docs/interfaces/BaseApexEditorContext.html +1 -1
- package/docs/interfaces/BaseColumnConfiguration.html +3 -3
- package/docs/interfaces/BaseFilterExpression.html +2 -2
- package/docs/interfaces/CSVExportOptions.html +13 -5
- package/docs/interfaces/DataPipelineConfiguration.html +2 -2
- package/docs/interfaces/EditingHistoryConfiguration.html +1 -1
- package/docs/interfaces/ExportFormat.html +2 -2
- package/docs/interfaces/ExportOptions.html +5 -3
- package/docs/interfaces/GridExpansionConfiguration.html +6 -2
- package/docs/interfaces/GridRowPinningConfiguration.html +1 -1
- package/docs/interfaces/GridRowReorderingConfiguration.html +2 -2
- package/docs/interfaces/PaginationConfiguration.html +1 -1
- package/docs/interfaces/PaginationState.html +1 -1
- package/docs/interfaces/SetStateResult.html +3 -2
- package/docs/interfaces/ValidatorContext.html +7 -2
- package/docs/media/_token-values.scss +118 -0
- package/docs/media/package.json +5 -5
- package/docs/media/state-persistence.html +0 -10
- package/docs/modules.html +1 -1
- package/docs/types/DataPipelineParams.html +2 -2
- package/docs/types/EditMode.html +2 -2
- package/docs/types/ExportSource.html +6 -4
- package/docs/types/GridLocaleText.html +1 -1
- package/docs/types/OperandKeys.html +9 -0
- package/docs/types/PaginationMode.html +1 -1
- package/docs/variables/EN_LOCALE.html +3 -3
- package/docs/variables/esLocale.html +1 -1
- package/i18n/en.d.ts +19 -0
- package/i18n/en.js +19 -0
- package/i18n/en.js.map +1 -1
- package/i18n/es.js +19 -0
- package/i18n/es.js.map +1 -1
- package/index.d.ts +2 -0
- package/index.js +2 -0
- package/index.js.map +1 -1
- package/internal/column-types.d.ts +27 -1
- package/internal/column-types.js +75 -49
- package/internal/column-types.js.map +1 -1
- package/internal/constants.d.ts +1 -2
- package/internal/constants.js +0 -4
- package/internal/constants.js.map +1 -1
- package/internal/document-styles.d.ts +30 -0
- package/internal/document-styles.js +48 -0
- package/internal/document-styles.js.map +1 -0
- package/internal/export.d.ts +39 -7
- package/internal/export.js +35 -34
- package/internal/export.js.map +1 -1
- package/internal/feature-module.d.ts +82 -3
- package/internal/feature-module.js +11 -0
- package/internal/feature-module.js.map +1 -1
- package/internal/index.d.ts +6 -4
- package/internal/index.js +5 -3
- package/internal/index.js.map +1 -1
- package/internal/normalize-case.d.ts +8 -1
- package/internal/normalize-case.js +3 -2
- package/internal/normalize-case.js.map +1 -1
- package/internal/state-snapshot.d.ts +60 -8
- package/internal/state-snapshot.js +87 -19
- package/internal/state-snapshot.js.map +1 -1
- package/internal/types.d.ts +17 -2
- package/internal/types.js.map +1 -1
- package/internal/utils.d.ts +48 -6
- package/internal/utils.js +35 -21
- package/internal/utils.js.map +1 -1
- package/internal/validators.js +1 -0
- package/internal/validators.js.map +1 -1
- package/operations/filter/operands/number.js +9 -6
- package/operations/filter/operands/number.js.map +1 -1
- package/operations/filter/operands/string.js +2 -3
- package/operations/filter/operands/string.js.map +1 -1
- package/operations/filter/types.d.ts +13 -1
- package/operations/filter/types.js.map +1 -1
- package/operations/filter.d.ts +6 -0
- package/operations/filter.js +23 -7
- package/operations/filter.js.map +1 -1
- package/operations/quick-filter.js +2 -5
- package/operations/quick-filter.js.map +1 -1
- package/operations/sort.d.ts +21 -2
- package/operations/sort.js +41 -14
- package/operations/sort.js.map +1 -1
- package/package.json +8 -4
- package/setup.d.ts +23 -11
- package/setup.js +19 -21
- package/setup.js.map +1 -1
- package/styles/_common.css.js +1 -1
- package/styles/_common.css.js.map +1 -1
- package/styles/_token-values.css.d.ts +1 -0
- package/styles/_token-values.css.js +3 -0
- package/styles/_token-values.css.js.map +1 -0
- package/styles/_tokens.css.js +1 -1
- package/styles/_tokens.css.js.map +1 -1
- package/styles/body-cell/body-cell.css.js +1 -1
- package/styles/body-cell/body-cell.css.js.map +1 -1
- package/styles/body-cell/cell-renderers.css.js +1 -1
- package/styles/body-cell/cell-renderers.css.js.map +1 -1
- package/styles/body-row/body-row.css.js +1 -1
- package/styles/body-row/body-row.css.js.map +1 -1
- package/styles/document-tokens.css.d.ts +1 -0
- package/styles/document-tokens.css.js +3 -0
- package/styles/document-tokens.css.js.map +1 -0
- package/styles/filter-row/filter-row.css.js +1 -1
- package/styles/filter-row/filter-row.css.js.map +1 -1
- package/styles/grid/_grid.base.css.js +1 -1
- package/styles/grid/_grid.base.css.js.map +1 -1
- package/styles/grid/grid.css.js +1 -1
- package/styles/grid/grid.css.js.map +1 -1
- package/styles/group-header-row/group-header-row.css.js +1 -1
- package/styles/group-header-row/group-header-row.css.js.map +1 -1
- package/styles/header-cell/header-cell.css.js +1 -1
- package/styles/header-cell/header-cell.css.js.map +1 -1
- package/styles/header-row/header-row.base.css.js +1 -1
- package/styles/header-row/header-row.base.css.js.map +1 -1
- package/styles/paginator/paginator.css.js +1 -1
- package/styles/paginator/paginator.css.js.map +1 -1
- package/styles/toolbar/toolbar.css.js +1 -1
- package/styles/toolbar/toolbar.css.js.map +1 -1
- package/tokens.css +78 -0
- package/LICENSE +0 -80
- package/docs/media/LICENSE +0 -80
- package/docs/media/_tokens.scss +0 -193
package/controllers/editing.js
CHANGED
|
@@ -5,9 +5,13 @@ export const DEFAULT_EDITING_CONFIG = Object.freeze({
|
|
|
5
5
|
mode: 'cell',
|
|
6
6
|
trigger: 'doubleClick',
|
|
7
7
|
});
|
|
8
|
+
const NO_DRAFT = Symbol('no-draft');
|
|
8
9
|
export class EditingController {
|
|
10
|
+
#effects;
|
|
9
11
|
#invalid;
|
|
10
12
|
#validationVersion;
|
|
13
|
+
#draft;
|
|
14
|
+
#draftRejected;
|
|
11
15
|
get validationVersion() {
|
|
12
16
|
return this.#validationVersion;
|
|
13
17
|
}
|
|
@@ -17,11 +21,46 @@ export class EditingController {
|
|
|
17
21
|
this.activeCell = null;
|
|
18
22
|
this.activeRow = null;
|
|
19
23
|
this.pending = new Map();
|
|
20
|
-
this.#
|
|
24
|
+
this.#effects = new Map();
|
|
25
|
+
this.#invalid = new WeakMap();
|
|
21
26
|
this.#validationVersion = 0;
|
|
27
|
+
this.#draft = NO_DRAFT;
|
|
28
|
+
this.#draftRejected = false;
|
|
22
29
|
this.host.addController(this);
|
|
23
30
|
}
|
|
24
31
|
hostConnected() { }
|
|
32
|
+
hostUpdated() {
|
|
33
|
+
const data = this.activeRow?.data ?? this.activeCell?.data;
|
|
34
|
+
if (!data)
|
|
35
|
+
return;
|
|
36
|
+
const rowIndex = this.#indexOf(data);
|
|
37
|
+
if (rowIndex < 0 && !this.#inView(data)) {
|
|
38
|
+
if (this.activeRow)
|
|
39
|
+
this.cancelRow();
|
|
40
|
+
else
|
|
41
|
+
this.cancelCell();
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (this.activeRow)
|
|
45
|
+
this.activeRow.rowIndex = rowIndex;
|
|
46
|
+
if (this.activeCell)
|
|
47
|
+
this.activeCell.rowIndex = rowIndex;
|
|
48
|
+
}
|
|
49
|
+
#indexOf(data) {
|
|
50
|
+
return this.host.pageItems.indexOf(data);
|
|
51
|
+
}
|
|
52
|
+
#inView(data) {
|
|
53
|
+
return this.host.dataView.includes(data) || this.#isPinned(data);
|
|
54
|
+
}
|
|
55
|
+
#isPinned(data) {
|
|
56
|
+
if (!this.host.rowPinning?.enabled)
|
|
57
|
+
return false;
|
|
58
|
+
const { top, bottom } = this.host.pinnedRows;
|
|
59
|
+
return top.includes(data) || bottom.includes(data);
|
|
60
|
+
}
|
|
61
|
+
#isHidden(data) {
|
|
62
|
+
return this.#indexOf(data) < 0 && !this.#isPinned(data);
|
|
63
|
+
}
|
|
25
64
|
get enabled() {
|
|
26
65
|
return Boolean(this.host.editing?.enabled);
|
|
27
66
|
}
|
|
@@ -34,36 +73,32 @@ export class EditingController {
|
|
|
34
73
|
isEditable(column) {
|
|
35
74
|
return Boolean(this.enabled && column.editable && !column.hidden);
|
|
36
75
|
}
|
|
37
|
-
isCellEditing(
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
isRowEditing(rowIndex) {
|
|
41
|
-
return this.activeRow?.rowIndex === rowIndex;
|
|
76
|
+
isCellEditing(data, columnKey) {
|
|
77
|
+
const active = this.activeCell;
|
|
78
|
+
return active !== null && active.data === data && active.columnKey === columnKey;
|
|
42
79
|
}
|
|
43
80
|
async editCell(rowIndex, columnKey) {
|
|
44
|
-
|
|
81
|
+
const data = this.host.pageItems[rowIndex];
|
|
82
|
+
return data ? this.editRecord(data, columnKey) : false;
|
|
83
|
+
}
|
|
84
|
+
async editRecord(data, columnKey) {
|
|
85
|
+
if (!this.enabled || !this.#isRecord(data))
|
|
45
86
|
return false;
|
|
46
87
|
const column = this.host.getColumn(columnKey);
|
|
47
88
|
if (!column || !this.isEditable(column))
|
|
48
89
|
return false;
|
|
49
|
-
|
|
50
|
-
if (!data)
|
|
90
|
+
if (this.mode === 'row' && !(await this.#openRow(data)))
|
|
51
91
|
return false;
|
|
52
|
-
if (this.
|
|
53
|
-
if (!this.
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
else if (this.activeRow.rowIndex !== rowIndex) {
|
|
57
|
-
const committed = await this.commitRow();
|
|
58
|
-
if (!committed)
|
|
92
|
+
if (this.activeCell && !this.isCellEditing(data, columnKey)) {
|
|
93
|
+
if (this.#draftRejected || !(await this.commitCell())) {
|
|
94
|
+
if (!this.#isHidden(this.activeCell.data))
|
|
59
95
|
return false;
|
|
60
|
-
|
|
96
|
+
this.cancelCell();
|
|
61
97
|
}
|
|
62
98
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
this.activeCell = { rowIndex, columnKey, data };
|
|
99
|
+
if (!this.isCellEditing(data, columnKey))
|
|
100
|
+
this.#resetDraft();
|
|
101
|
+
this.activeCell = { rowIndex: this.#indexOf(data), columnKey, data };
|
|
67
102
|
this.host.requestUpdate();
|
|
68
103
|
return true;
|
|
69
104
|
}
|
|
@@ -71,17 +106,25 @@ export class EditingController {
|
|
|
71
106
|
if (!this.enabled || this.mode !== 'row')
|
|
72
107
|
return false;
|
|
73
108
|
const data = this.host.pageItems[rowIndex];
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
109
|
+
return data && this.#isRecord(data) ? this.#openRow(data) : false;
|
|
110
|
+
}
|
|
111
|
+
#isRecord(data) {
|
|
112
|
+
const state = this.host
|
|
113
|
+
.stateController;
|
|
114
|
+
return state?.isDataRow(data) ?? true;
|
|
115
|
+
}
|
|
116
|
+
async #openRow(data) {
|
|
117
|
+
if (this.activeRow?.data === data)
|
|
118
|
+
return true;
|
|
119
|
+
if (this.activeRow && !(await this.commitRow())) {
|
|
120
|
+
if (!this.#isHidden(this.activeRow.data))
|
|
79
121
|
return false;
|
|
122
|
+
this.cancelRow();
|
|
80
123
|
}
|
|
81
|
-
|
|
82
|
-
return true;
|
|
124
|
+
const rowIndex = this.#indexOf(data);
|
|
83
125
|
this.activeRow = { rowIndex, data };
|
|
84
126
|
this.pending.clear();
|
|
127
|
+
this.#effects.clear();
|
|
85
128
|
this.host.requestUpdate();
|
|
86
129
|
this.host.emitEvent('rowEditStarted', { detail: { rowIndex } });
|
|
87
130
|
return true;
|
|
@@ -103,12 +146,9 @@ export class EditingController {
|
|
|
103
146
|
return 'invalid';
|
|
104
147
|
}
|
|
105
148
|
}
|
|
106
|
-
|
|
107
|
-
detail: { key: columnKey, rowIndex, data, oldValue, newValue: value },
|
|
108
|
-
cancelable: true,
|
|
109
|
-
});
|
|
110
|
-
if (!proceed)
|
|
149
|
+
if (options?.gate !== false && !this.#gate(rowIndex, columnKey, data, value)) {
|
|
111
150
|
return 'cancelled';
|
|
151
|
+
}
|
|
112
152
|
record[columnKey] = value;
|
|
113
153
|
this.clearCellErrors(data, columnKey);
|
|
114
154
|
this.history?.record({ record: data, key: columnKey, rowIndex, oldValue, newValue: value });
|
|
@@ -117,16 +157,53 @@ export class EditingController {
|
|
|
117
157
|
});
|
|
118
158
|
return 'applied';
|
|
119
159
|
}
|
|
120
|
-
|
|
160
|
+
#gate(rowIndex, columnKey, data, value) {
|
|
161
|
+
return this.host.emitEvent('cellValueChanging', {
|
|
162
|
+
detail: {
|
|
163
|
+
key: columnKey,
|
|
164
|
+
rowIndex,
|
|
165
|
+
data,
|
|
166
|
+
oldValue: data[columnKey],
|
|
167
|
+
newValue: value,
|
|
168
|
+
},
|
|
169
|
+
cancelable: true,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
validateCell(rowIndex, columnKey, data, value, row = data) {
|
|
121
173
|
const column = this.host.getColumn(columnKey);
|
|
122
174
|
if (!column?.validators?.length)
|
|
123
175
|
return [];
|
|
124
176
|
return runValidators(column.validators, value, {
|
|
125
177
|
column,
|
|
126
|
-
data,
|
|
178
|
+
data: row,
|
|
127
179
|
rowIndex,
|
|
128
180
|
});
|
|
129
181
|
}
|
|
182
|
+
stagedValues(data) {
|
|
183
|
+
return this.activeRow?.data === data ? this.pending : null;
|
|
184
|
+
}
|
|
185
|
+
stagedEffect(data, columnKey) {
|
|
186
|
+
return this.activeRow?.data === data ? this.#effects.get(columnKey) : undefined;
|
|
187
|
+
}
|
|
188
|
+
#run(effect) {
|
|
189
|
+
effect.apply();
|
|
190
|
+
this.history?.push(effect);
|
|
191
|
+
}
|
|
192
|
+
#stage(data, columnKey, value, effect) {
|
|
193
|
+
if (effect)
|
|
194
|
+
this.#effects.set(columnKey, effect);
|
|
195
|
+
else if (effect === undefined)
|
|
196
|
+
this.#effects.delete(columnKey);
|
|
197
|
+
if (Object.is(value, data[columnKey])) {
|
|
198
|
+
if (this.pending.delete(columnKey))
|
|
199
|
+
this.#validationVersion += 1;
|
|
200
|
+
this.clearCellErrors(data, columnKey);
|
|
201
|
+
}
|
|
202
|
+
else if (!this.pending.has(columnKey) || !Object.is(this.pending.get(columnKey), value)) {
|
|
203
|
+
this.pending.set(columnKey, value);
|
|
204
|
+
this.#validationVersion += 1;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
130
207
|
getCellErrors(data, columnKey) {
|
|
131
208
|
return this.#invalid.get(data)?.get(columnKey) ?? null;
|
|
132
209
|
}
|
|
@@ -154,22 +231,59 @@ export class EditingController {
|
|
|
154
231
|
perColumn.set(columnKey, errors);
|
|
155
232
|
this.#validationVersion += 1;
|
|
156
233
|
}
|
|
157
|
-
|
|
234
|
+
setDraft(value) {
|
|
235
|
+
if (!this.activeCell)
|
|
236
|
+
return;
|
|
237
|
+
this.#draft = value;
|
|
238
|
+
this.#draftRejected = false;
|
|
239
|
+
}
|
|
240
|
+
heldDraft(data, columnKey) {
|
|
241
|
+
return this.#draft === NO_DRAFT || !this.isCellEditing(data, columnKey)
|
|
242
|
+
? null
|
|
243
|
+
: { value: this.#draft };
|
|
244
|
+
}
|
|
245
|
+
#resetDraft() {
|
|
246
|
+
this.#draft = NO_DRAFT;
|
|
247
|
+
this.#draftRejected = false;
|
|
248
|
+
}
|
|
249
|
+
#endCellEdit() {
|
|
250
|
+
this.activeCell = null;
|
|
251
|
+
this.#resetDraft();
|
|
252
|
+
}
|
|
253
|
+
async commitCell(...args) {
|
|
158
254
|
const active = this.activeCell;
|
|
159
255
|
if (!active)
|
|
160
256
|
return false;
|
|
161
257
|
const { rowIndex, columnKey, data } = active;
|
|
162
|
-
const
|
|
163
|
-
const
|
|
258
|
+
const staged = this.stagedValues(data);
|
|
259
|
+
const current = staged?.has(columnKey)
|
|
260
|
+
? staged.get(columnKey)
|
|
261
|
+
: data[columnKey];
|
|
262
|
+
const draft = this.#draft;
|
|
263
|
+
const candidate = args.length > 0 ? args[0] : draft === NO_DRAFT ? current : draft;
|
|
264
|
+
const effect = args[1];
|
|
164
265
|
if (this.mode === 'cell') {
|
|
165
|
-
|
|
266
|
+
let result;
|
|
267
|
+
if (effect)
|
|
268
|
+
this.history?.beginBatch();
|
|
269
|
+
try {
|
|
270
|
+
result = this.applyCellEdit(rowIndex, columnKey, data, candidate);
|
|
271
|
+
if (effect && (result === 'applied' || result === 'unchanged'))
|
|
272
|
+
this.#run(effect);
|
|
273
|
+
}
|
|
274
|
+
finally {
|
|
275
|
+
if (effect)
|
|
276
|
+
this.history?.endBatch();
|
|
277
|
+
}
|
|
166
278
|
if (result === 'cancelled')
|
|
167
279
|
return false;
|
|
168
280
|
if (result === 'invalid') {
|
|
281
|
+
if (args.length === 0)
|
|
282
|
+
this.#draftRejected = true;
|
|
169
283
|
this.host.requestUpdate();
|
|
170
284
|
return false;
|
|
171
285
|
}
|
|
172
|
-
this
|
|
286
|
+
this.#endCellEdit();
|
|
173
287
|
if (result === 'applied') {
|
|
174
288
|
this.host.requestUpdate(PIPELINE);
|
|
175
289
|
await this.host.updateComplete;
|
|
@@ -179,23 +293,25 @@ export class EditingController {
|
|
|
179
293
|
}
|
|
180
294
|
return true;
|
|
181
295
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
}
|
|
185
|
-
this.activeCell = null;
|
|
296
|
+
this.#stage(data, columnKey, candidate, args.length > 0 ? effect : null);
|
|
297
|
+
this.#endCellEdit();
|
|
186
298
|
this.host.requestUpdate();
|
|
187
299
|
return true;
|
|
188
300
|
}
|
|
189
|
-
async commitImmediate(
|
|
190
|
-
if (!this.enabled)
|
|
301
|
+
async commitImmediate(data, columnKey, value) {
|
|
302
|
+
if (!this.enabled || !this.#isRecord(data))
|
|
191
303
|
return false;
|
|
192
304
|
const column = this.host.getColumn(columnKey);
|
|
193
305
|
if (!column || !this.isEditable(column))
|
|
194
306
|
return false;
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
307
|
+
if (this.mode === 'row') {
|
|
308
|
+
if (!(await this.#openRow(data)))
|
|
309
|
+
return false;
|
|
310
|
+
this.#stage(data, columnKey, value);
|
|
311
|
+
this.host.requestUpdate();
|
|
312
|
+
return true;
|
|
313
|
+
}
|
|
314
|
+
const result = this.applyCellEdit(this.#indexOf(data), columnKey, data, value);
|
|
199
315
|
if (result === 'cancelled')
|
|
200
316
|
return false;
|
|
201
317
|
if (result === 'invalid') {
|
|
@@ -212,7 +328,7 @@ export class EditingController {
|
|
|
212
328
|
if (!this.activeCell)
|
|
213
329
|
return;
|
|
214
330
|
const { data, columnKey } = this.activeCell;
|
|
215
|
-
this
|
|
331
|
+
this.#endCellEdit();
|
|
216
332
|
this.clearCellErrors(data, columnKey);
|
|
217
333
|
this.host.requestUpdate();
|
|
218
334
|
}
|
|
@@ -220,63 +336,99 @@ export class EditingController {
|
|
|
220
336
|
const active = this.activeRow;
|
|
221
337
|
if (!active)
|
|
222
338
|
return false;
|
|
223
|
-
const {
|
|
224
|
-
if (this.activeCell?.
|
|
339
|
+
const { data } = active;
|
|
340
|
+
if (this.activeCell?.data === data) {
|
|
225
341
|
await this.commitCell();
|
|
226
342
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
if (
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
hasInvalid = true;
|
|
343
|
+
const rowIndex = active.rowIndex;
|
|
344
|
+
const record = data;
|
|
345
|
+
for (const [columnKey, effect] of this.#effects) {
|
|
346
|
+
if (!effect.stagedValue)
|
|
347
|
+
continue;
|
|
348
|
+
const value = effect.stagedValue(this.pending);
|
|
349
|
+
if (this.pending.has(columnKey) || !Object.is(value, record[columnKey])) {
|
|
350
|
+
this.pending.set(columnKey, value);
|
|
236
351
|
}
|
|
237
352
|
}
|
|
238
|
-
|
|
353
|
+
const changes = [...this.pending].filter(([columnKey, candidate]) => !Object.is(candidate, record[columnKey]));
|
|
354
|
+
if (this.pending.size > 0 && !this.#validateRow(rowIndex, data)) {
|
|
239
355
|
this.host.requestUpdate();
|
|
240
356
|
return false;
|
|
241
357
|
}
|
|
358
|
+
for (const [columnKey, candidate] of changes) {
|
|
359
|
+
if (!this.#gate(rowIndex, columnKey, data, candidate))
|
|
360
|
+
return false;
|
|
361
|
+
}
|
|
242
362
|
this.history?.beginBatch();
|
|
243
363
|
try {
|
|
244
|
-
for (const [columnKey, candidate] of
|
|
245
|
-
|
|
246
|
-
'cancelled') {
|
|
247
|
-
return false;
|
|
248
|
-
}
|
|
364
|
+
for (const [columnKey, candidate] of changes) {
|
|
365
|
+
this.applyCellEdit(rowIndex, columnKey, data, candidate, { validate: false, gate: false });
|
|
249
366
|
}
|
|
367
|
+
for (const effect of this.#effects.values())
|
|
368
|
+
this.#run(effect);
|
|
250
369
|
}
|
|
251
370
|
finally {
|
|
252
371
|
this.history?.endBatch();
|
|
253
372
|
}
|
|
373
|
+
if (this.pending.size > 0)
|
|
374
|
+
this.#validationVersion += 1;
|
|
254
375
|
this.pending.clear();
|
|
376
|
+
this.#effects.clear();
|
|
255
377
|
this.activeRow = null;
|
|
256
378
|
this.host.requestUpdate(PIPELINE);
|
|
257
379
|
await this.host.updateComplete;
|
|
258
380
|
this.host.emitEvent('rowEditEnded', { detail: { rowIndex, committed: true } });
|
|
259
381
|
return true;
|
|
260
382
|
}
|
|
383
|
+
#validateRow(rowIndex, data) {
|
|
384
|
+
const row = Object.assign(Object.create(Object.getPrototypeOf(data)), data);
|
|
385
|
+
for (const [columnKey, value] of this.pending) {
|
|
386
|
+
row[columnKey] = value;
|
|
387
|
+
}
|
|
388
|
+
let valid = true;
|
|
389
|
+
for (const column of this.host.columns) {
|
|
390
|
+
if (!this.isEditable(column) || !column.validators?.length)
|
|
391
|
+
continue;
|
|
392
|
+
const columnKey = column.key;
|
|
393
|
+
const value = row[columnKey];
|
|
394
|
+
const errors = this.#validateStaged(rowIndex, columnKey, data, value, row);
|
|
395
|
+
if (errors.length === 0) {
|
|
396
|
+
this.clearCellErrors(data, columnKey);
|
|
397
|
+
continue;
|
|
398
|
+
}
|
|
399
|
+
if (!this.pending.has(columnKey) &&
|
|
400
|
+
this.validateCell(rowIndex, columnKey, data, value).length > 0) {
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
valid = false;
|
|
404
|
+
this.#setCellErrors(data, columnKey, errors);
|
|
405
|
+
this.host.emitEvent('cellValidationFailed', {
|
|
406
|
+
detail: { key: columnKey, rowIndex, data, value, errors },
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
return valid;
|
|
410
|
+
}
|
|
411
|
+
#validateStaged(rowIndex, columnKey, data, value, row) {
|
|
412
|
+
try {
|
|
413
|
+
return this.validateCell(rowIndex, columnKey, data, value, row);
|
|
414
|
+
}
|
|
415
|
+
catch {
|
|
416
|
+
return this.validateCell(rowIndex, columnKey, data, value);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
261
419
|
cancelRow() {
|
|
262
420
|
if (!this.activeRow)
|
|
263
421
|
return;
|
|
264
422
|
const { rowIndex, data } = this.activeRow;
|
|
265
|
-
this
|
|
423
|
+
this.#endCellEdit();
|
|
266
424
|
this.activeRow = null;
|
|
425
|
+
if (this.pending.size > 0)
|
|
426
|
+
this.#validationVersion += 1;
|
|
267
427
|
this.pending.clear();
|
|
428
|
+
this.#effects.clear();
|
|
268
429
|
this.clearRecordErrors(data);
|
|
269
430
|
this.host.requestUpdate();
|
|
270
431
|
this.host.emitEvent('rowEditEnded', { detail: { rowIndex, committed: false } });
|
|
271
432
|
}
|
|
272
|
-
getValue(rowIndex, columnKey) {
|
|
273
|
-
if (this.mode === 'row' &&
|
|
274
|
-
this.activeRow?.rowIndex === rowIndex &&
|
|
275
|
-
this.pending.has(columnKey)) {
|
|
276
|
-
return this.pending.get(columnKey);
|
|
277
|
-
}
|
|
278
|
-
const data = this.host.pageItems[rowIndex];
|
|
279
|
-
return data ? data[columnKey] : undefined;
|
|
280
|
-
}
|
|
281
433
|
}
|
|
282
434
|
//# sourceMappingURL=editing.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editing.js","sourceRoot":"","sources":["../../src/controllers/editing.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController } from 'lit';\nimport { PIPELINE } from '../internal/constants.js';\nimport type {\n ColumnConfiguration,\n EditMode,\n EditTrigger,\n GridHost,\n Keys,\n Validator,\n ValidatorContext,\n} from '../internal/types.js';\nimport { runValidators } from '../internal/validators.js';\nimport type { HistoryController } from './history.js';\n\n/**\n * The default editing configuration used when the grid has none set.\n */\nexport const DEFAULT_EDITING_CONFIG = Object.freeze({\n enabled: false,\n mode: 'cell' as EditMode,\n trigger: 'doubleClick' as EditTrigger,\n});\n\ninterface ActiveCell<T> {\n rowIndex: number;\n columnKey: Keys<T>;\n /**\n * Live reference to the underlying record (preserved through the pipeline so\n * the source array can be mutated on commit).\n */\n data: T;\n}\n\n/**\n * Outcome of a single committed cell edit routed through\n * {@link EditingController.applyCellEdit}.\n *\n * - `'unchanged'` - the candidate equalled the current value; nothing happened.\n * - `'invalid'` - a column validator rejected the candidate; the value was not\n * written and `cellValidationFailed` fired.\n * - `'cancelled'` - a `cellValueChanging` listener called `preventDefault()`.\n * - `'applied'` - the value was written and `cellValueChanged` fired.\n */\nexport type CellEditResult = 'unchanged' | 'invalid' | 'cancelled' | 'applied';\n\n/**\n * Options for {@link EditingController.applyCellEdit}.\n */\nexport interface ApplyCellEditOptions {\n /**\n * Run the column's declarative validators before writing. Defaults to `true`.\n * Set to `false` for writes that must not be re-validated (e.g. reverting a\n * previously valid value during undo/redo).\n */\n validate?: boolean;\n}\n\n/**\n * Reactive controller backing inline cell + row editing.\n *\n * @remarks\n * Holds the currently active cell / row, pending values for row-mode edits,\n * and is responsible for emitting the cancellable `cellValueChanging` event\n * and follow-up `cellValueChanged` event. The actual data mutation writes\n * through to {@link ApexGrid.data} so changes survive pipeline runs and\n * propagate to consumers that own the source array.\n */\nexport class EditingController<T extends object> implements ReactiveController {\n /** The cell currently in edit mode, or `null`. */\n public activeCell: ActiveCell<T> | null = null;\n\n /** The row currently in edit mode (row mode only), or `null`. */\n public activeRow: { rowIndex: number; data: T } | null = null;\n\n /**\n * Pending values keyed by column for the currently editing row. Populated in\n * row mode as the user edits individual cells; flushed on\n * {@link commitRow}.\n */\n public pending: Map<Keys<T>, unknown> = new Map();\n\n /**\n * Per-record validation errors, keyed by the live data reference and then by\n * column. Keyed by reference (not row index) so an invalid marker tracks its\n * row across pipeline runs (sort / filter / paginate).\n */\n #invalid: Map<T, Map<Keys<T>, string[]>> = new Map();\n\n #validationVersion = 0;\n\n /**\n * Monotonic token bumped whenever the validation-error set changes. Forwarded\n * down to each cell as a reactive property so a validation-only change\n * re-renders the affected cells (toggling `aria-invalid` and the error node)\n * without re-running the data pipeline. Stays `0` until the first failure.\n */\n public get validationVersion(): number {\n return this.#validationVersion;\n }\n\n constructor(\n protected host: GridHost<T>,\n protected history?: HistoryController<T>\n ) {\n this.host.addController(this);\n }\n\n public hostConnected() {}\n\n /**\n * Whether editing is enabled at the grid level.\n */\n public get enabled(): boolean {\n return Boolean(this.host.editing?.enabled);\n }\n\n /**\n * The resolved edit mode (`'cell'` if unset).\n */\n public get mode(): EditMode {\n return this.host.editing?.mode ?? DEFAULT_EDITING_CONFIG.mode;\n }\n\n /**\n * The resolved edit trigger (`'doubleClick'` if unset).\n */\n public get trigger(): EditTrigger {\n return this.host.editing?.trigger ?? DEFAULT_EDITING_CONFIG.trigger;\n }\n\n /**\n * Whether the given column can be edited.\n */\n public isEditable(column: ColumnConfiguration<T>): boolean {\n return Boolean(this.enabled && column.editable && !column.hidden);\n }\n\n /**\n * Whether the cell `(rowIndex, columnKey)` is currently in edit mode.\n */\n public isCellEditing(rowIndex: number, columnKey: Keys<T>): boolean {\n return this.activeCell?.rowIndex === rowIndex && this.activeCell?.columnKey === columnKey;\n }\n\n /**\n * Whether the given row is currently in edit mode (row mode).\n */\n public isRowEditing(rowIndex: number): boolean {\n return this.activeRow?.rowIndex === rowIndex;\n }\n\n /**\n * Begins editing the cell at `(rowIndex, columnKey)`. Auto-commits any cell\n * already in edit mode (in cell mode); in row mode it switches the active\n * cell within the same row and rejects cross-row moves.\n *\n * @returns `true` if edit started, `false` if rejected (column not editable\n * or row-mode constraint violated).\n */\n public async editCell(rowIndex: number, columnKey: Keys<T>): Promise<boolean> {\n if (!this.enabled) return false;\n const column = this.host.getColumn(columnKey);\n if (!column || !this.isEditable(column)) return false;\n const data = this.host.pageItems[rowIndex] as T | undefined;\n if (!data) return false;\n\n if (this.mode === 'row') {\n if (!this.activeRow) {\n await this.editRow(rowIndex);\n } else if (this.activeRow.rowIndex !== rowIndex) {\n // Switching rows in row mode — commit pending edits in the previous row\n // before starting elsewhere.\n const committed = await this.commitRow();\n if (!committed) return false;\n await this.editRow(rowIndex);\n }\n } else if (this.activeCell && !this.isCellEditing(rowIndex, columnKey)) {\n // Cell mode — commit any in-flight cell before switching.\n await this.commitCell();\n }\n\n this.activeCell = { rowIndex, columnKey, data };\n this.host.requestUpdate();\n return true;\n }\n\n /**\n * Begins editing the given row in row mode. Emits `rowEditStarted` on\n * success. No-op in cell mode.\n */\n public async editRow(rowIndex: number): Promise<boolean> {\n if (!this.enabled || this.mode !== 'row') return false;\n const data = this.host.pageItems[rowIndex] as T | undefined;\n if (!data) return false;\n if (this.activeRow && this.activeRow.rowIndex !== rowIndex) {\n const committed = await this.commitRow();\n if (!committed) return false;\n }\n if (this.activeRow?.rowIndex === rowIndex) return true;\n this.activeRow = { rowIndex, data };\n this.pending.clear();\n this.host.requestUpdate();\n this.host.emitEvent('rowEditStarted', { detail: { rowIndex } });\n return true;\n }\n\n /**\n * The single choke point for committing a cell value to the backing record.\n * Short-circuits no-op writes, runs the cancellable `cellValueChanging` gate,\n * writes the value through to {@link ApexGrid.data}, and emits\n * `cellValueChanged`. Returns the {@link CellEditResult} so callers can manage\n * their own UI state (active cell) and batch the render.\n *\n * @remarks\n * Does **not** request a render — callers refresh (once per edit, or once per\n * batch) so row-mode and bulk edits coalesce into a single pipeline pass.\n * Every committed edit (single-cell, row-mode, and enterprise paste/fill)\n * funnels through here so cross-cutting concerns (validation, undo/redo) have\n * one place to hook the old/new values and the write.\n */\n public applyCellEdit(\n rowIndex: number,\n columnKey: Keys<T>,\n data: T,\n value: unknown,\n options?: ApplyCellEditOptions\n ): CellEditResult {\n const record = data as Record<string, unknown>;\n const oldValue = record[columnKey as string];\n if (Object.is(value, oldValue)) {\n // Re-entering the original value clears any stale invalid marker.\n this.clearCellErrors(data, columnKey);\n return 'unchanged';\n }\n\n if (options?.validate !== false) {\n const errors = this.validateCell(rowIndex, columnKey, data, value);\n if (errors.length > 0) {\n this.#setCellErrors(data, columnKey, errors);\n this.host.emitEvent('cellValidationFailed', {\n detail: { key: columnKey, rowIndex, data, value, errors },\n });\n return 'invalid';\n }\n }\n\n const proceed = this.host.emitEvent('cellValueChanging', {\n detail: { key: columnKey, rowIndex, data, oldValue, newValue: value },\n cancelable: true,\n });\n if (!proceed) return 'cancelled';\n\n record[columnKey as string] = value;\n this.clearCellErrors(data, columnKey);\n this.history?.record({ record: data, key: columnKey, rowIndex, oldValue, newValue: value });\n this.host.emitEvent('cellValueChanged', {\n detail: { key: columnKey, rowIndex, data, value },\n });\n return 'applied';\n }\n\n /**\n * Runs the column's declarative validators against a candidate value and\n * returns the collected error messages (empty when the value passes or the\n * column has no validators).\n */\n public validateCell(rowIndex: number, columnKey: Keys<T>, data: T, value: unknown): string[] {\n const column = this.host.getColumn(columnKey);\n if (!column?.validators?.length) return [];\n // `ColumnConfiguration<T>` is a distributive conditional, so `validators`\n // and `column` widen to a per-key union here; collapse to the base form for\n // the runner (the runtime shapes are identical).\n return runValidators(column.validators as Validator<T>[], value, {\n column,\n data,\n rowIndex,\n } as ValidatorContext<T>);\n }\n\n /**\n * The current validation errors for `(data, columnKey)`, or `null` when the\n * cell is valid. Read by {@link ApexGridCell} to drive `aria-invalid` and the\n * inline error node.\n */\n public getCellErrors(data: T, columnKey: Keys<T>): readonly string[] | null {\n return this.#invalid.get(data)?.get(columnKey) ?? null;\n }\n\n /**\n * Clears any validation error recorded for `(data, columnKey)`.\n */\n public clearCellErrors(data: T, columnKey: Keys<T>): void {\n const perColumn = this.#invalid.get(data);\n if (!perColumn) return;\n if (perColumn.delete(columnKey)) {\n if (perColumn.size === 0) this.#invalid.delete(data);\n this.#validationVersion += 1;\n }\n }\n\n /**\n * Clears every validation error recorded for a record (all columns).\n */\n public clearRecordErrors(data: T): void {\n if (this.#invalid.delete(data)) {\n this.#validationVersion += 1;\n }\n }\n\n #setCellErrors(data: T, columnKey: Keys<T>, errors: string[]): void {\n let perColumn = this.#invalid.get(data);\n if (!perColumn) {\n perColumn = new Map();\n this.#invalid.set(data, perColumn);\n }\n perColumn.set(columnKey, errors);\n this.#validationVersion += 1;\n }\n\n /**\n * Commits a candidate value for the currently editing cell. In cell mode the\n * value is written through to {@link ApexGrid.data}; in row mode it is staged\n * in {@link pending} until {@link commitRow} is called.\n *\n * @param value - The candidate value.\n * @returns `true` if accepted (or staged), `false` if rejected by\n * `cellValueChanging.preventDefault()`.\n */\n public async commitCell(value?: unknown): Promise<boolean> {\n const active = this.activeCell;\n if (!active) return false;\n const { rowIndex, columnKey, data } = active;\n const oldValue = (data as Record<string, unknown>)[columnKey as string];\n const candidate = value === undefined ? oldValue : value;\n\n if (this.mode === 'cell') {\n const result = this.applyCellEdit(rowIndex, columnKey, data, candidate);\n if (result === 'cancelled') return false;\n // A failed validation keeps the editor open so the user can correct the\n // value; re-render to surface `aria-invalid` + the error node.\n if (result === 'invalid') {\n this.host.requestUpdate();\n return false;\n }\n // Both 'applied' and 'unchanged' close the editor; only an applied write\n // needs the data pipeline to re-run.\n this.activeCell = null;\n if (result === 'applied') {\n this.host.requestUpdate(PIPELINE);\n await this.host.updateComplete;\n } else {\n this.host.requestUpdate();\n }\n return true;\n }\n\n // Row mode — stage and exit cell edit (row stays open).\n if (!Object.is(candidate, oldValue)) {\n this.pending.set(columnKey, candidate);\n }\n this.activeCell = null;\n this.host.requestUpdate();\n return true;\n }\n\n /**\n * Writes `value` directly to the cell at `(rowIndex, columnKey)` without\n * entering edit mode. Used by interactive display widgets (e.g. the boolean\n * checkbox) that handle their own input. Goes through the same\n * `cellValueChanging` / `cellValueChanged` event path as a normal commit.\n *\n * @returns `true` if the value was applied, `false` if rejected by\n * `cellValueChanging.preventDefault()` or the column is not editable.\n */\n public async commitImmediate(\n rowIndex: number,\n columnKey: Keys<T>,\n value: unknown\n ): Promise<boolean> {\n if (!this.enabled) return false;\n const column = this.host.getColumn(columnKey);\n if (!column || !this.isEditable(column)) return false;\n const data = this.host.pageItems[rowIndex] as T | undefined;\n if (!data) return false;\n\n const result = this.applyCellEdit(rowIndex, columnKey, data, value);\n if (result === 'cancelled') return false;\n if (result === 'invalid') {\n this.host.requestUpdate();\n return false;\n }\n if (result === 'applied') {\n this.host.requestUpdate(PIPELINE);\n await this.host.updateComplete;\n }\n return true;\n }\n\n /**\n * Discards the current cell edit without writing. In row mode the row edit\n * stays open.\n */\n public cancelCell(): void {\n if (!this.activeCell) return;\n const { data, columnKey } = this.activeCell;\n this.activeCell = null;\n // Abandoning the edit discards any validation error raised for the cell.\n this.clearCellErrors(data, columnKey);\n this.host.requestUpdate();\n }\n\n /**\n * Commits all pending edits for the currently editing row. Emits\n * `cellValueChanging` for every changed cell and `rowEditEnded` at the end.\n *\n * @returns `true` if the row was applied, `false` if any cell change was\n * cancelled (the row remains in edit mode in that case).\n */\n public async commitRow(): Promise<boolean> {\n const active = this.activeRow;\n if (!active) return false;\n const { rowIndex, data } = active;\n\n // Make sure any open cell editor flushes its pending value first.\n if (this.activeCell?.rowIndex === rowIndex) {\n await this.commitCell();\n }\n\n // Pre-validate every pending cell so a single failure aborts the whole row\n // commit without a partial write. Each failing cell is marked invalid and\n // the row stays in edit mode.\n let hasInvalid = false;\n for (const [columnKey, candidate] of this.pending) {\n const errors = this.validateCell(rowIndex, columnKey, data, candidate);\n if (errors.length > 0) {\n this.#setCellErrors(data, columnKey, errors);\n this.host.emitEvent('cellValidationFailed', {\n detail: { key: columnKey, rowIndex, data, value: candidate, errors },\n });\n hasInvalid = true;\n }\n }\n if (hasInvalid) {\n this.host.requestUpdate();\n return false;\n }\n\n // Coalesce the row's writes into one undo step.\n this.history?.beginBatch();\n try {\n for (const [columnKey, candidate] of this.pending) {\n // Validation already ran above; a cancelled cell aborts the whole row\n // commit, leaving it in edit mode.\n if (\n this.applyCellEdit(rowIndex, columnKey, data, candidate, { validate: false }) ===\n 'cancelled'\n ) {\n return false;\n }\n }\n } finally {\n this.history?.endBatch();\n }\n\n this.pending.clear();\n this.activeRow = null;\n this.host.requestUpdate(PIPELINE);\n await this.host.updateComplete;\n this.host.emitEvent('rowEditEnded', { detail: { rowIndex, committed: true } });\n return true;\n }\n\n /**\n * Discards every pending edit for the active row and exits row edit mode.\n * Emits `rowEditEnded` with `committed: false`.\n */\n public cancelRow(): void {\n if (!this.activeRow) return;\n const { rowIndex, data } = this.activeRow;\n this.activeCell = null;\n this.activeRow = null;\n this.pending.clear();\n // Abandoning the row discards every validation error raised for it.\n this.clearRecordErrors(data);\n this.host.requestUpdate();\n this.host.emitEvent('rowEditEnded', { detail: { rowIndex, committed: false } });\n }\n\n /**\n * Returns the current pending or committed value for `(rowIndex, columnKey)`.\n * Cells in row mode read this so unstaged-but-pending values are reflected\n * during the edit.\n */\n public getValue(rowIndex: number, columnKey: Keys<T>): unknown {\n if (\n this.mode === 'row' &&\n this.activeRow?.rowIndex === rowIndex &&\n this.pending.has(columnKey)\n ) {\n return this.pending.get(columnKey);\n }\n const data = this.host.pageItems[rowIndex] as T | undefined;\n return data ? (data as Record<string, unknown>)[columnKey as string] : undefined;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"editing.js","sourceRoot":"","sources":["../../src/controllers/editing.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController } from 'lit';\nimport { PIPELINE } from '../internal/constants.js';\nimport type {\n ColumnConfiguration,\n EditMode,\n EditTrigger,\n GridHost,\n Keys,\n Validator,\n ValidatorContext,\n} from '../internal/types.js';\nimport { runValidators } from '../internal/validators.js';\nimport type { EditCommand, HistoryController } from './history.js';\n\n/**\n * The default editing configuration used when the grid has none set.\n */\nexport const DEFAULT_EDITING_CONFIG = Object.freeze({\n enabled: false,\n mode: 'cell' as EditMode,\n trigger: 'doubleClick' as EditTrigger,\n});\n\n/** {@link EditingController} draft sentinel: the open editor has no typed value yet. */\nconst NO_DRAFT = Symbol('no-draft');\n\ninterface ActiveCell<T> {\n /**\n * The record's view index (matches {@link ApexGrid.pageItems}), refreshed\n * after every grid update; `-1` for a pinned record or one on another page.\n */\n rowIndex: number;\n columnKey: Keys<T>;\n /**\n * Live reference to the underlying record (preserved through the pipeline so\n * the source array can be mutated on commit). The edit is bound to this\n * record, never to the view index, so a sort, filter, page or data change\n * cannot move the editor onto another record.\n */\n data: T;\n}\n\n/**\n * Outcome of a single committed cell edit routed through\n * {@link EditingController.applyCellEdit}.\n *\n * - `'unchanged'` - the candidate equalled the current value; nothing happened.\n * - `'invalid'` - a column validator rejected the candidate; the value was not\n * written and `cellValidationFailed` fired.\n * - `'cancelled'` - a `cellValueChanging` listener called `preventDefault()`.\n * - `'applied'` - the value was written and `cellValueChanged` fired.\n */\nexport type CellEditResult = 'unchanged' | 'invalid' | 'cancelled' | 'applied';\n\n/**\n * Options for {@link EditingController.applyCellEdit}.\n */\nexport interface ApplyCellEditOptions {\n /**\n * Run the column's declarative validators before writing. Defaults to `true`.\n * Set to `false` for writes that must not be re-validated (e.g. reverting a\n * previously valid value during undo/redo).\n */\n validate?: boolean;\n /**\n * Emit the cancellable `cellValueChanging` before writing. Defaults to\n * `true`. Set to `false` when the caller already ran the gate for this\n * write (a row commit gates every cell before writing any).\n */\n gate?: boolean;\n}\n\n/**\n * Reactive controller backing inline cell + row editing.\n *\n * @remarks\n * Holds the currently active cell / row, pending values for row-mode edits,\n * and is responsible for emitting the cancellable `cellValueChanging` event\n * and follow-up `cellValueChanged` event. The actual data mutation writes\n * through to {@link ApexGrid.data} so changes survive pipeline runs and\n * propagate to consumers that own the source array.\n */\nexport class EditingController<T extends object> implements ReactiveController {\n /** The cell currently in edit mode, or `null`. */\n public activeCell: ActiveCell<T> | null = null;\n\n /**\n * The row currently in edit mode (row mode only), or `null`. Bound to its\n * record like {@link activeCell}.\n */\n public activeRow: { rowIndex: number; data: T } | null = null;\n\n /**\n * Pending values keyed by column for the currently editing row. Populated in\n * row mode as the user edits individual cells; flushed on\n * {@link commitRow}. Holds only values that differ from the record.\n */\n public pending: Map<Keys<T>, unknown> = new Map();\n\n /**\n * Commands staged with the row edit, keyed by column (see\n * {@link commitCell}): run when the row commits, dropped when it cancels.\n */\n #effects: Map<Keys<T>, EditCommand> = new Map();\n\n /**\n * Per-record validation errors, keyed by the live data reference and then by\n * column. Keyed by reference (not row index) so an invalid marker tracks its\n * row across pipeline runs (sort / filter / paginate). Weak, so the markers\n * of records the app replaced are released with them.\n */\n #invalid: WeakMap<T, Map<Keys<T>, string[]>> = new WeakMap();\n\n #validationVersion = 0;\n\n /**\n * The open editor's uncommitted value, or {@link NO_DRAFT}. Held here rather\n * than in the cell so a re-render of the editing cell cannot reset it and a\n * bare {@link commitCell} (from `grid.commitEdit()`, a cell switch or a row\n * commit) writes what the user typed.\n */\n #draft: unknown = NO_DRAFT;\n\n /** Whether {@link #draft} failed validation and has not changed since. */\n #draftRejected = false;\n\n /**\n * Monotonic token bumped whenever the validation-error set or the staged\n * row-mode values change. Forwarded down to each cell as a reactive property\n * so such a change re-renders the affected cells (toggling `aria-invalid`\n * and the error node, showing a staged value) without re-running the data\n * pipeline. Stays `0` until the first failure or staged value.\n */\n public get validationVersion(): number {\n return this.#validationVersion;\n }\n\n constructor(\n protected host: GridHost<T>,\n protected history?: HistoryController<T>\n ) {\n this.host.addController(this);\n }\n\n public hostConnected() {}\n\n /**\n * Keeps an open edit bound to its record after the view changed: refreshes\n * the reported view index, and cancels the edit when the record left the\n * view (removed, filtered out, replaced by a copy), so no hidden editor can\n * commit later. A record on another page or in a pinned band stays open.\n * Runs only while an edit is open.\n */\n public hostUpdated(): void {\n const data = this.activeRow?.data ?? this.activeCell?.data;\n if (!data) return;\n const rowIndex = this.#indexOf(data);\n if (rowIndex < 0 && !this.#inView(data)) {\n if (this.activeRow) this.cancelRow();\n else this.cancelCell();\n return;\n }\n if (this.activeRow) this.activeRow.rowIndex = rowIndex;\n if (this.activeCell) this.activeCell.rowIndex = rowIndex;\n }\n\n /** The record's view index (matches {@link ApexGrid.pageItems}), or `-1`. */\n #indexOf(data: T): number {\n return this.host.pageItems.indexOf(data);\n }\n\n /** Whether the record is still in the processed view or a pinned band. */\n #inView(data: T): boolean {\n return this.host.dataView.includes(data) || this.#isPinned(data);\n }\n\n #isPinned(data: T): boolean {\n if (!this.host.rowPinning?.enabled) return false;\n const { top, bottom } = this.host.pinnedRows;\n return top.includes(data) || bottom.includes(data);\n }\n\n /**\n * Whether the record of an open edit is out of sight: on another page, so\n * neither a body row nor a pinned row renders its editor.\n */\n #isHidden(data: T): boolean {\n return this.#indexOf(data) < 0 && !this.#isPinned(data);\n }\n\n /**\n * Whether editing is enabled at the grid level.\n */\n public get enabled(): boolean {\n return Boolean(this.host.editing?.enabled);\n }\n\n /**\n * The resolved edit mode (`'cell'` if unset).\n */\n public get mode(): EditMode {\n return this.host.editing?.mode ?? DEFAULT_EDITING_CONFIG.mode;\n }\n\n /**\n * The resolved edit trigger (`'doubleClick'` if unset).\n */\n public get trigger(): EditTrigger {\n return this.host.editing?.trigger ?? DEFAULT_EDITING_CONFIG.trigger;\n }\n\n /**\n * Whether the given column can be edited.\n */\n public isEditable(column: ColumnConfiguration<T>): boolean {\n return Boolean(this.enabled && column.editable && !column.hidden);\n }\n\n /**\n * Whether the cell `(data, columnKey)` is currently in edit mode.\n */\n public isCellEditing(data: T, columnKey: Keys<T>): boolean {\n const active = this.activeCell;\n return active !== null && active.data === data && active.columnKey === columnKey;\n }\n\n /**\n * Begins editing the cell at `(rowIndex, columnKey)`, where `rowIndex` is\n * the view index (matches {@link ApexGrid.pageItems}). See\n * {@link editRecord}.\n */\n public async editCell(rowIndex: number, columnKey: Keys<T>): Promise<boolean> {\n const data = this.host.pageItems[rowIndex] as T | undefined;\n return data ? this.editRecord(data, columnKey) : false;\n }\n\n /**\n * Begins editing the `columnKey` cell of the record `data`, a body or a\n * pinned row. Auto-commits any cell already in edit mode (in cell mode); in\n * row mode it stages that cell and commits the row first on a cross-row\n * move.\n *\n * @returns `true` if edit started, `false` if rejected (column not editable,\n * `data` a row a feature synthesized, the in-flight cell's commit was\n * rejected, or the previous row could not be committed). A rejected commit\n * keeps the in-flight editor open, unless its record is on another page:\n * an edit the user cannot see or correct is cancelled instead, so it cannot\n * block every other edit.\n */\n public async editRecord(data: T, columnKey: Keys<T>): Promise<boolean> {\n if (!this.enabled || !this.#isRecord(data)) return false;\n const column = this.host.getColumn(columnKey);\n if (!column || !this.isEditable(column)) return false;\n // Row mode: switching rows commits the pending edits of the previous row\n // before starting elsewhere.\n if (this.mode === 'row' && !(await this.#openRow(data))) return false;\n if (this.activeCell && !this.isCellEditing(data, columnKey)) {\n // Commit (cell mode) or stage (row mode) the in-flight cell, draft\n // included, before switching. A rejected commit keeps that editor open\n // with its error instead of abandoning it over still-valid data. A\n // draft that already failed validation (the focus loss of the same\n // click) is not validated a second time.\n if (this.#draftRejected || !(await this.commitCell())) {\n if (!this.#isHidden(this.activeCell.data)) return false;\n this.cancelCell();\n }\n }\n\n if (!this.isCellEditing(data, columnKey)) this.#resetDraft();\n this.activeCell = { rowIndex: this.#indexOf(data), columnKey, data };\n this.host.requestUpdate();\n return true;\n }\n\n /**\n * Begins editing the given row in row mode. Emits `rowEditStarted` on\n * success. No-op in cell mode.\n */\n public async editRow(rowIndex: number): Promise<boolean> {\n if (!this.enabled || this.mode !== 'row') return false;\n const data = this.host.pageItems[rowIndex] as T | undefined;\n return data && this.#isRecord(data) ? this.#openRow(data) : false;\n }\n\n /**\n * Whether `data` is a record, not a row a feature synthesized (a group\n * header, a total, a row a server has not sent yet; see\n * `StateController.isDataRow`). Always `true` for the community grid.\n */\n #isRecord(data: T): boolean {\n const state = (this.host as unknown as { stateController?: { isDataRow(row: T): boolean } })\n .stateController;\n return state?.isDataRow(data) ?? true;\n }\n\n /** Opens `data` for a row edit, committing a different open row first. */\n async #openRow(data: T): Promise<boolean> {\n if (this.activeRow?.data === data) return true;\n if (this.activeRow && !(await this.commitRow())) {\n // A rejected row on another page cannot be corrected there: cancel it\n // rather than block every other edit.\n if (!this.#isHidden(this.activeRow.data)) return false;\n this.cancelRow();\n }\n const rowIndex = this.#indexOf(data);\n this.activeRow = { rowIndex, data };\n this.pending.clear();\n this.#effects.clear();\n this.host.requestUpdate();\n this.host.emitEvent('rowEditStarted', { detail: { rowIndex } });\n return true;\n }\n\n /**\n * The single choke point for committing a cell value to the backing record.\n * Short-circuits no-op writes, runs the cancellable `cellValueChanging` gate,\n * writes the value through to {@link ApexGrid.data}, and emits\n * `cellValueChanged`. Returns the {@link CellEditResult} so callers can manage\n * their own UI state (active cell) and batch the render.\n *\n * @remarks\n * Does **not** request a render — callers refresh (once per edit, or once per\n * batch) so row-mode and bulk edits coalesce into a single pipeline pass.\n * Every committed edit (single-cell, row-mode, and enterprise paste/fill)\n * funnels through here so cross-cutting concerns (validation, undo/redo) have\n * one place to hook the old/new values and the write.\n */\n public applyCellEdit(\n rowIndex: number,\n columnKey: Keys<T>,\n data: T,\n value: unknown,\n options?: ApplyCellEditOptions\n ): CellEditResult {\n const record = data as Record<string, unknown>;\n const oldValue = record[columnKey as string];\n if (Object.is(value, oldValue)) {\n // Re-entering the original value clears any stale invalid marker.\n this.clearCellErrors(data, columnKey);\n return 'unchanged';\n }\n\n if (options?.validate !== false) {\n const errors = this.validateCell(rowIndex, columnKey, data, value);\n if (errors.length > 0) {\n this.#setCellErrors(data, columnKey, errors);\n this.host.emitEvent('cellValidationFailed', {\n detail: { key: columnKey, rowIndex, data, value, errors },\n });\n return 'invalid';\n }\n }\n\n if (options?.gate !== false && !this.#gate(rowIndex, columnKey, data, value)) {\n return 'cancelled';\n }\n\n record[columnKey as string] = value;\n this.clearCellErrors(data, columnKey);\n this.history?.record({ record: data, key: columnKey, rowIndex, oldValue, newValue: value });\n this.host.emitEvent('cellValueChanged', {\n detail: { key: columnKey, rowIndex, data, value },\n });\n return 'applied';\n }\n\n /** Emits the cancellable `cellValueChanging`; `false` when a listener vetoed it. */\n #gate(rowIndex: number, columnKey: Keys<T>, data: T, value: unknown): boolean {\n return this.host.emitEvent('cellValueChanging', {\n detail: {\n key: columnKey,\n rowIndex,\n data,\n oldValue: (data as Record<string, unknown>)[columnKey as string],\n newValue: value,\n },\n cancelable: true,\n });\n }\n\n /**\n * Runs the column's declarative validators against a candidate value and\n * returns the collected error messages (empty when the value passes or the\n * column has no validators).\n *\n * @param row - What validators see as `ctx.data`: the record itself, or in\n * a row commit the staged row (the record with the staged values applied).\n */\n public validateCell(\n rowIndex: number,\n columnKey: Keys<T>,\n data: T,\n value: unknown,\n row: T = data\n ): string[] {\n const column = this.host.getColumn(columnKey);\n if (!column?.validators?.length) return [];\n // `ColumnConfiguration<T>` is a distributive conditional, so `validators`\n // and `column` widen to a per-key union here; collapse to the base form for\n // the runner (the runtime shapes are identical).\n return runValidators(column.validators as Validator<T>[], value, {\n column,\n data: row,\n rowIndex,\n } as ValidatorContext<T>);\n }\n\n /**\n * The staged row-mode values of `data` keyed by column, or `null` when\n * `data` is not the row in edit. Cells read it to show staged values.\n */\n public stagedValues(data: T): ReadonlyMap<Keys<T>, unknown> | null {\n return this.activeRow?.data === data ? this.pending : null;\n }\n\n /** The command staged with the row edit of `data` for `columnKey`, if any. */\n public stagedEffect(data: T, columnKey: Keys<T>): EditCommand | undefined {\n return this.activeRow?.data === data ? this.#effects.get(columnKey) : undefined;\n }\n\n /** Runs a command riding with an accepted edit and records it for undo. */\n #run(effect: EditCommand): void {\n effect.apply();\n this.history?.push(effect);\n }\n\n /**\n * Stages `value` for the active row's `columnKey`. A value equal to the\n * record's is unstaged (and its stale error cleared), so re-entering the\n * original undoes a staged edit. `effect` replaces the command staged for\n * the column; `undefined` drops it and `null` keeps it.\n */\n #stage(data: T, columnKey: Keys<T>, value: unknown, effect?: EditCommand | null): void {\n if (effect) this.#effects.set(columnKey, effect);\n else if (effect === undefined) this.#effects.delete(columnKey);\n if (Object.is(value, (data as Record<string, unknown>)[columnKey as string])) {\n if (this.pending.delete(columnKey)) this.#validationVersion += 1;\n this.clearCellErrors(data, columnKey);\n } else if (!this.pending.has(columnKey) || !Object.is(this.pending.get(columnKey), value)) {\n this.pending.set(columnKey, value);\n this.#validationVersion += 1;\n }\n }\n\n /**\n * The current validation errors for `(data, columnKey)`, or `null` when the\n * cell is valid. Read by {@link ApexGridCell} to drive `aria-invalid` and the\n * inline error node.\n */\n public getCellErrors(data: T, columnKey: Keys<T>): readonly string[] | null {\n return this.#invalid.get(data)?.get(columnKey) ?? null;\n }\n\n /**\n * Clears any validation error recorded for `(data, columnKey)`.\n */\n public clearCellErrors(data: T, columnKey: Keys<T>): void {\n const perColumn = this.#invalid.get(data);\n if (!perColumn) return;\n if (perColumn.delete(columnKey)) {\n if (perColumn.size === 0) this.#invalid.delete(data);\n this.#validationVersion += 1;\n }\n }\n\n /**\n * Clears every validation error recorded for a record (all columns).\n */\n public clearRecordErrors(data: T): void {\n if (this.#invalid.delete(data)) {\n this.#validationVersion += 1;\n }\n }\n\n #setCellErrors(data: T, columnKey: Keys<T>, errors: string[]): void {\n let perColumn = this.#invalid.get(data);\n if (!perColumn) {\n perColumn = new Map();\n this.#invalid.set(data, perColumn);\n }\n perColumn.set(columnKey, errors);\n this.#validationVersion += 1;\n }\n\n /**\n * Records the open editor's current, uncommitted value. A later\n * {@link commitCell} without an argument commits it. No-op while no cell is\n * in edit mode.\n */\n public setDraft(value: unknown): void {\n if (!this.activeCell) return;\n this.#draft = value;\n this.#draftRejected = false;\n }\n\n /**\n * The draft held for the open editor of `(data, columnKey)`, or `null` when\n * that cell is not in edit or nothing was typed. An editor rendered again\n * for an edit already open (its record paged or scrolled back into view)\n * resumes from it, so it shows what a bare {@link commitCell} commits.\n */\n public heldDraft(data: T, columnKey: Keys<T>): { value: unknown } | null {\n return this.#draft === NO_DRAFT || !this.isCellEditing(data, columnKey)\n ? null\n : { value: this.#draft };\n }\n\n #resetDraft(): void {\n this.#draft = NO_DRAFT;\n this.#draftRejected = false;\n }\n\n #endCellEdit(): void {\n this.activeCell = null;\n this.#resetDraft();\n }\n\n /**\n * Commits a candidate value for the currently editing cell. In cell mode the\n * value is written through to {@link ApexGrid.data}; in row mode it is staged\n * in {@link pending} until {@link commitRow} is called.\n *\n * @param args - The candidate value, committed as given (`undefined`\n * included). Called with no argument, it commits the open editor's draft\n * (see {@link setDraft}), or keeps the current value when nothing was typed.\n * An optional command rides with the value: it runs once the value is\n * accepted (or, in row mode, when the row commits), joins the same undo\n * step, and is dropped when the edit is rejected or the row cancelled.\n * @returns `true` if accepted (or staged), `false` if rejected by\n * `cellValueChanging.preventDefault()` or a validator.\n */\n public async commitCell(...args: [value?: unknown, effect?: EditCommand]): Promise<boolean> {\n const active = this.activeCell;\n if (!active) return false;\n const { rowIndex, columnKey, data } = active;\n // The value the editor opened on: in row mode a staged value, so an\n // untouched editor keeps it staged.\n const staged = this.stagedValues(data);\n const current = staged?.has(columnKey)\n ? staged.get(columnKey)\n : (data as Record<string, unknown>)[columnKey as string];\n const draft = this.#draft;\n const candidate = args.length > 0 ? args[0] : draft === NO_DRAFT ? current : draft;\n\n const effect = args[1];\n if (this.mode === 'cell') {\n let result: CellEditResult;\n // The value and its command undo as one step.\n if (effect) this.history?.beginBatch();\n try {\n result = this.applyCellEdit(rowIndex, columnKey, data, candidate);\n if (effect && (result === 'applied' || result === 'unchanged')) this.#run(effect);\n } finally {\n if (effect) this.history?.endBatch();\n }\n if (result === 'cancelled') return false;\n // A failed validation keeps the editor open so the user can correct the\n // value; re-render to surface `aria-invalid` + the error node.\n if (result === 'invalid') {\n if (args.length === 0) this.#draftRejected = true;\n this.host.requestUpdate();\n return false;\n }\n // Both 'applied' and 'unchanged' close the editor; only an applied write\n // needs the data pipeline to re-run.\n this.#endCellEdit();\n if (result === 'applied') {\n this.host.requestUpdate(PIPELINE);\n await this.host.updateComplete;\n } else {\n this.host.requestUpdate();\n }\n return true;\n }\n\n // Row mode: stage and exit cell edit (row stays open). A bare commit\n // keeps the command staged for the cell.\n this.#stage(data, columnKey, candidate, args.length > 0 ? effect : null);\n this.#endCellEdit();\n this.host.requestUpdate();\n return true;\n }\n\n /**\n * Writes `value` directly to the `columnKey` cell of the record `data` (a\n * body or a pinned row) without entering edit mode. Used by interactive\n * display widgets (e.g. the boolean checkbox) that handle their own input.\n * Goes through the same `cellValueChanging` / `cellValueChanged` event path\n * as a normal commit. In row mode the value joins the row's staged values\n * instead (opening the row edit first), so it commits or cancels with the\n * rest of the row.\n *\n * @returns `true` if the value was applied (or staged), `false` if rejected\n * by `cellValueChanging.preventDefault()`, a validator, a previous row that\n * could not be committed, the column is not editable, or `data` is a row a\n * feature synthesized (as in {@link editRecord}).\n */\n public async commitImmediate(data: T, columnKey: Keys<T>, value: unknown): Promise<boolean> {\n if (!this.enabled || !this.#isRecord(data)) return false;\n const column = this.host.getColumn(columnKey);\n if (!column || !this.isEditable(column)) return false;\n\n if (this.mode === 'row') {\n if (!(await this.#openRow(data))) return false;\n this.#stage(data, columnKey, value);\n this.host.requestUpdate();\n return true;\n }\n\n const result = this.applyCellEdit(this.#indexOf(data), columnKey, data, value);\n if (result === 'cancelled') return false;\n if (result === 'invalid') {\n this.host.requestUpdate();\n return false;\n }\n if (result === 'applied') {\n this.host.requestUpdate(PIPELINE);\n await this.host.updateComplete;\n }\n return true;\n }\n\n /**\n * Discards the current cell edit without writing. In row mode the row edit\n * stays open.\n */\n public cancelCell(): void {\n if (!this.activeCell) return;\n const { data, columnKey } = this.activeCell;\n this.#endCellEdit();\n // Abandoning the edit discards any validation error raised for the cell.\n this.clearCellErrors(data, columnKey);\n this.host.requestUpdate();\n }\n\n /**\n * Commits all pending edits for the currently editing row. Emits\n * `cellValueChanging` for every changed cell and `rowEditEnded` at the end.\n *\n * @remarks\n * Validators see the staged row as `ctx.data`, and once any value is staged\n * the other editable cells of the row are validated too, so a cross-field\n * rule judges the row being saved. Every cell passes its `cellValueChanging`\n * gate before any is written: an invalid or cancelled cell aborts the whole\n * row.\n *\n * @returns `true` if the row was applied, `false` if any cell failed\n * validation or its change was cancelled (the row remains in edit mode).\n */\n public async commitRow(): Promise<boolean> {\n const active = this.activeRow;\n if (!active) return false;\n const { data } = active;\n\n // Make sure any open cell editor flushes its pending value first.\n if (this.activeCell?.data === data) {\n await this.commitCell();\n }\n const rowIndex = active.rowIndex;\n const record = data as Record<string, unknown>;\n // A staged command may compute its value from cells staged after it.\n for (const [columnKey, effect] of this.#effects) {\n if (!effect.stagedValue) continue;\n const value = effect.stagedValue(this.pending);\n if (this.pending.has(columnKey) || !Object.is(value, record[columnKey as string])) {\n this.pending.set(columnKey, value);\n }\n }\n const changes = [...this.pending].filter(\n ([columnKey, candidate]) => !Object.is(candidate, record[columnKey as string])\n );\n\n if (this.pending.size > 0 && !this.#validateRow(rowIndex, data)) {\n this.host.requestUpdate();\n return false;\n }\n for (const [columnKey, candidate] of changes) {\n if (!this.#gate(rowIndex, columnKey, data, candidate)) return false;\n }\n\n // Coalesce the row's writes into one undo step. Validation and the gate\n // already ran above for every cell.\n this.history?.beginBatch();\n try {\n for (const [columnKey, candidate] of changes) {\n this.applyCellEdit(rowIndex, columnKey, data, candidate, { validate: false, gate: false });\n }\n for (const effect of this.#effects.values()) this.#run(effect);\n } finally {\n this.history?.endBatch();\n }\n\n // Staged values were showing in the row's cells, and a cell whose record\n // value ended where it started gets no new value binding: re-render them.\n if (this.pending.size > 0) this.#validationVersion += 1;\n this.pending.clear();\n this.#effects.clear();\n this.activeRow = null;\n this.host.requestUpdate(PIPELINE);\n await this.host.updateComplete;\n this.host.emitEvent('rowEditEnded', { detail: { rowIndex, committed: true } });\n return true;\n }\n\n /**\n * Validates the staged row, marking each failing cell (and clearing the\n * marker of each passing one). `false` when any cell failed. A staged cell\n * is judged on its staged value; another editable cell fails only when the\n * staged values made it invalid (a cross-field rule), so an untouched value\n * that was already invalid does not block the row.\n */\n #validateRow(rowIndex: number, data: T): boolean {\n // The record with the staged values applied, keeping its prototype so\n // validators reading accessors or methods still work.\n const row = Object.assign(Object.create(Object.getPrototypeOf(data)), data) as T;\n for (const [columnKey, value] of this.pending) {\n (row as Record<string, unknown>)[columnKey as string] = value;\n }\n let valid = true;\n for (const column of this.host.columns) {\n if (!this.isEditable(column) || !column.validators?.length) continue;\n const columnKey = column.key;\n const value = (row as Record<string, unknown>)[columnKey as string];\n const errors = this.#validateStaged(rowIndex, columnKey, data, value, row);\n if (errors.length === 0) {\n this.clearCellErrors(data, columnKey);\n continue;\n }\n if (\n !this.pending.has(columnKey) &&\n this.validateCell(rowIndex, columnKey, data, value).length > 0\n ) {\n continue;\n }\n valid = false;\n this.#setCellErrors(data, columnKey, errors);\n this.host.emitEvent('cellValidationFailed', {\n detail: { key: columnKey, rowIndex, data, value, errors },\n });\n }\n return valid;\n }\n\n /**\n * Validates a cell against the staged row. A validator that throws on the\n * copy (one reading private class fields of the record, say) is run again\n * against the live record, as before staged rows existed; a throw there\n * propagates.\n */\n #validateStaged(rowIndex: number, columnKey: Keys<T>, data: T, value: unknown, row: T): string[] {\n try {\n return this.validateCell(rowIndex, columnKey, data, value, row);\n } catch {\n return this.validateCell(rowIndex, columnKey, data, value);\n }\n }\n\n /**\n * Discards every pending edit for the active row and exits row edit mode.\n * Emits `rowEditEnded` with `committed: false`.\n */\n public cancelRow(): void {\n if (!this.activeRow) return;\n const { rowIndex, data } = this.activeRow;\n this.#endCellEdit();\n this.activeRow = null;\n // Staged values were showing in the row's cells: re-render them.\n if (this.pending.size > 0) this.#validationVersion += 1;\n this.pending.clear();\n this.#effects.clear();\n // Abandoning the row discards every validation error raised for it.\n this.clearRecordErrors(data);\n this.host.requestUpdate();\n this.host.emitEvent('rowEditEnded', { detail: { rowIndex, committed: false } });\n }\n}\n"]}
|