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/components/cell.js
CHANGED
|
@@ -11,7 +11,7 @@ import { property, query } from 'lit/decorators.js';
|
|
|
11
11
|
import { gridStateContext } from '../controllers/state.js';
|
|
12
12
|
import { getColumnTypeRenderer } from '../internal/column-types.js';
|
|
13
13
|
import { registerComponent } from '../internal/register.js';
|
|
14
|
-
import { GRID_CELL_TAG } from '../internal/tags.js';
|
|
14
|
+
import { GRID_CELL_TAG, GRID_ROW_TAG } from '../internal/tags.js';
|
|
15
15
|
import { styles } from '../styles/body-cell/body-cell.css.js';
|
|
16
16
|
function isErrorLike(value) {
|
|
17
17
|
return (typeof value === 'object' &&
|
|
@@ -19,16 +19,64 @@ function isErrorLike(value) {
|
|
|
19
19
|
typeof value.code === 'string' &&
|
|
20
20
|
value.code.startsWith('#'));
|
|
21
21
|
}
|
|
22
|
+
function renderedRows(body) {
|
|
23
|
+
if (!body)
|
|
24
|
+
return [];
|
|
25
|
+
return Array.from(body.children).filter((element) => element.localName === GRID_ROW_TAG);
|
|
26
|
+
}
|
|
27
|
+
function tabTarget(count, from, keys, key, step, isFullWidth) {
|
|
28
|
+
const column = keys[keys.indexOf(key) + step];
|
|
29
|
+
if (column !== undefined)
|
|
30
|
+
return { row: from, column };
|
|
31
|
+
const wrapColumn = keys[step > 0 ? 0 : keys.length - 1];
|
|
32
|
+
for (let index = from + step; index >= 0 && index < count; index += step) {
|
|
33
|
+
if (!isFullWidth(index))
|
|
34
|
+
return { row: index, column: wrapColumn };
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
function nearestCellRow(count, start, step, isFullWidth) {
|
|
39
|
+
const origin = Math.min(Math.max(start, 0), count - 1);
|
|
40
|
+
for (let distance = 0; distance < count; distance++) {
|
|
41
|
+
for (const index of [origin + distance * step, origin - distance * step]) {
|
|
42
|
+
if (index >= 0 && index < count && !isFullWidth(index))
|
|
43
|
+
return index;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return -1;
|
|
47
|
+
}
|
|
48
|
+
function findRenderedCell(body, node) {
|
|
49
|
+
return renderedRows(body)
|
|
50
|
+
.find((row) => row.index === node.row)
|
|
51
|
+
?.cells.find((cell) => cell.column.key === node.column);
|
|
52
|
+
}
|
|
53
|
+
function scrollRowIntoRange(scroller, body, index) {
|
|
54
|
+
const rows = renderedRows(body).sort((a, b) => a.index - b.index);
|
|
55
|
+
const first = rows.at(0);
|
|
56
|
+
const last = rows.at(-1);
|
|
57
|
+
if (!first || !last)
|
|
58
|
+
return;
|
|
59
|
+
const top = first.getBoundingClientRect().top;
|
|
60
|
+
const height = (last.getBoundingClientRect().bottom - top) / (last.index - first.index + 1);
|
|
61
|
+
const view = scroller.getBoundingClientRect();
|
|
62
|
+
const rowCentre = top + (index - first.index + 0.5) * height;
|
|
63
|
+
scroller.scrollTop += rowCentre - (view.top + scroller.clientHeight / 2);
|
|
64
|
+
}
|
|
22
65
|
class ApexGridCell extends LitElement {
|
|
23
66
|
constructor() {
|
|
24
67
|
super(...arguments);
|
|
25
68
|
this.active = false;
|
|
26
69
|
this.editing = false;
|
|
27
70
|
this.colindex = 0;
|
|
71
|
+
this.rowIndex = -1;
|
|
28
72
|
this.decorationVersion = 0;
|
|
73
|
+
this.dataVersion = 0;
|
|
29
74
|
this.validationVersion = 0;
|
|
30
75
|
this.#decoratedKeys = [];
|
|
31
76
|
this.#errors = null;
|
|
77
|
+
this.#staged = false;
|
|
78
|
+
this.#resumed = null;
|
|
79
|
+
this.#reconnected = false;
|
|
32
80
|
this.#handleClick = (event) => {
|
|
33
81
|
if (this.isEditing) {
|
|
34
82
|
event.stopPropagation();
|
|
@@ -56,9 +104,7 @@ class ApexGridCell extends LitElement {
|
|
|
56
104
|
this.#startEdit();
|
|
57
105
|
};
|
|
58
106
|
this.#refocusAfterEdit = false;
|
|
59
|
-
this.#
|
|
60
|
-
return this.editingController.commitCell(value ?? this.#pendingValue);
|
|
61
|
-
};
|
|
107
|
+
this.#commit = () => this.editingController.commitCell();
|
|
62
108
|
this.#cancel = () => {
|
|
63
109
|
this.editingController.cancelCell();
|
|
64
110
|
};
|
|
@@ -68,7 +114,7 @@ class ApexGridCell extends LitElement {
|
|
|
68
114
|
case 'Enter':
|
|
69
115
|
event.preventDefault();
|
|
70
116
|
this.#refocusAfterEdit = true;
|
|
71
|
-
this.#
|
|
117
|
+
this.#commit();
|
|
72
118
|
return;
|
|
73
119
|
case 'Escape':
|
|
74
120
|
event.preventDefault();
|
|
@@ -76,24 +122,12 @@ class ApexGridCell extends LitElement {
|
|
|
76
122
|
this.#cancel();
|
|
77
123
|
return;
|
|
78
124
|
case 'Tab':
|
|
79
|
-
event
|
|
80
|
-
this.#refocusAfterEdit = true;
|
|
81
|
-
this.#commitWith();
|
|
125
|
+
this.#commitAndTab(event);
|
|
82
126
|
return;
|
|
83
127
|
default:
|
|
84
128
|
return;
|
|
85
129
|
}
|
|
86
130
|
};
|
|
87
|
-
this.#handleBlur = () => {
|
|
88
|
-
if (!this.isEditing)
|
|
89
|
-
return;
|
|
90
|
-
if (this.editingController.mode === 'cell') {
|
|
91
|
-
this.#commitWith();
|
|
92
|
-
}
|
|
93
|
-
else {
|
|
94
|
-
this.editingController.commitCell(this.#pendingValue);
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
131
|
this.#handleCellKeydown = (event) => {
|
|
98
132
|
if (!this.isEditing)
|
|
99
133
|
return;
|
|
@@ -103,11 +137,8 @@ class ApexGridCell extends LitElement {
|
|
|
103
137
|
this.#cancel();
|
|
104
138
|
return;
|
|
105
139
|
}
|
|
106
|
-
if (event.key === 'Tab')
|
|
107
|
-
event
|
|
108
|
-
this.#refocusAfterEdit = true;
|
|
109
|
-
this.#commitWith();
|
|
110
|
-
}
|
|
140
|
+
if (event.key === 'Tab')
|
|
141
|
+
this.#commitAndTab(event);
|
|
111
142
|
};
|
|
112
143
|
this.#handleCellFocusOut = (event) => {
|
|
113
144
|
if (!this.isEditing)
|
|
@@ -115,26 +146,23 @@ class ApexGridCell extends LitElement {
|
|
|
115
146
|
const next = event.relatedTarget;
|
|
116
147
|
if (next && (this.contains(next) || this.shadowRoot?.contains(next)))
|
|
117
148
|
return;
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}
|
|
121
|
-
else {
|
|
122
|
-
this.editingController.commitCell(this.#pendingValue);
|
|
123
|
-
}
|
|
149
|
+
this.#refocusAfterEdit = false;
|
|
150
|
+
this.#commit();
|
|
124
151
|
};
|
|
125
152
|
this.#handleTextInput = (event) => {
|
|
126
153
|
const target = event.target;
|
|
127
|
-
if (this
|
|
154
|
+
if (this.#isNumeric) {
|
|
128
155
|
const numeric = target.valueAsNumber;
|
|
129
|
-
this
|
|
156
|
+
this.editingController.setDraft(target.value === '' || Number.isNaN(numeric) ? null : numeric);
|
|
130
157
|
return;
|
|
131
158
|
}
|
|
132
|
-
this
|
|
159
|
+
this.editingController.setDraft(target.value);
|
|
133
160
|
};
|
|
134
|
-
this.#handleCheckboxChange = (event) => {
|
|
161
|
+
this.#handleCheckboxChange = async (event) => {
|
|
135
162
|
const target = event.target;
|
|
136
|
-
|
|
137
|
-
|
|
163
|
+
if (!(await this.editingController.commitCell(target.checked))) {
|
|
164
|
+
target.checked = !target.checked;
|
|
165
|
+
}
|
|
138
166
|
};
|
|
139
167
|
}
|
|
140
168
|
static get tagName() {
|
|
@@ -152,7 +180,7 @@ class ApexGridCell extends LitElement {
|
|
|
152
180
|
value: this.value,
|
|
153
181
|
};
|
|
154
182
|
if (this.isEditable) {
|
|
155
|
-
ctx.commit = (next) => this.editingController.commitImmediate(this.row.
|
|
183
|
+
ctx.commit = (next) => this.editingController.commitImmediate(this.row.data, this.column.key, next);
|
|
156
184
|
}
|
|
157
185
|
return ctx;
|
|
158
186
|
}
|
|
@@ -167,10 +195,18 @@ class ApexGridCell extends LitElement {
|
|
|
167
195
|
return false;
|
|
168
196
|
return this.editingController.isEditable(this.column);
|
|
169
197
|
}
|
|
198
|
+
get #inPinnedBand() {
|
|
199
|
+
const pin = this.state.rowPin;
|
|
200
|
+
return pin.hasPinnedRows && pin.enabled && pin.isPinned(this.row.data);
|
|
201
|
+
}
|
|
170
202
|
#decoratedKeys;
|
|
171
203
|
static #ERROR_ID = 'apex-cell-error';
|
|
172
204
|
#errors;
|
|
205
|
+
#staged;
|
|
206
|
+
#resumed;
|
|
207
|
+
#reconnected;
|
|
173
208
|
connectedCallback() {
|
|
209
|
+
this.#reconnected = this.hasUpdated && !this.isUpdatePending;
|
|
174
210
|
super.connectedCallback();
|
|
175
211
|
this.setAttribute('role', 'gridcell');
|
|
176
212
|
this.addEventListener('click', this.#handleClick);
|
|
@@ -185,7 +221,29 @@ class ApexGridCell extends LitElement {
|
|
|
185
221
|
this.removeEventListener('focusout', this.#handleCellFocusOut);
|
|
186
222
|
super.disconnectedCallback();
|
|
187
223
|
}
|
|
188
|
-
|
|
224
|
+
shouldUpdate(changed) {
|
|
225
|
+
const reconnected = this.#reconnected;
|
|
226
|
+
this.#reconnected = false;
|
|
227
|
+
if (!this.hasUpdated || (!changed.size && !reconnected))
|
|
228
|
+
return true;
|
|
229
|
+
const tree = this.state?.tree;
|
|
230
|
+
const readsRow = this.column.cellTemplate || (tree?.enabled && tree.isGroupColumn(this.column.key));
|
|
231
|
+
for (const key of changed.keys()) {
|
|
232
|
+
const token = key === 'rowIndex' || key === 'dataVersion';
|
|
233
|
+
if (key !== 'decorationVersion' && (readsRow || !token))
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
236
|
+
if (changed.has('decorationVersion') || changed.has('rowIndex'))
|
|
237
|
+
this.#applyDecoration();
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
willUpdate(changed) {
|
|
241
|
+
this.#applyStaged();
|
|
242
|
+
if (changed.has('editing')) {
|
|
243
|
+
this.#resumed = this.editing
|
|
244
|
+
? this.editingController.heldDraft(this.row.data, this.column.key)
|
|
245
|
+
: null;
|
|
246
|
+
}
|
|
189
247
|
if (this.colindex > 0) {
|
|
190
248
|
this.setAttribute('aria-colindex', String(this.colindex));
|
|
191
249
|
}
|
|
@@ -210,6 +268,20 @@ class ApexGridCell extends LitElement {
|
|
|
210
268
|
this.#applyValidation();
|
|
211
269
|
this.#applyDecoration();
|
|
212
270
|
}
|
|
271
|
+
#applyStaged() {
|
|
272
|
+
const staged = this.state?.editing?.activeRow
|
|
273
|
+
? this.editingController.stagedValues(this.row.data)
|
|
274
|
+
: null;
|
|
275
|
+
const key = this.column.key;
|
|
276
|
+
if (staged?.has(key)) {
|
|
277
|
+
this.value = staged.get(key);
|
|
278
|
+
this.#staged = true;
|
|
279
|
+
}
|
|
280
|
+
else if (this.#staged) {
|
|
281
|
+
this.#staged = false;
|
|
282
|
+
this.value = this.row.data[key];
|
|
283
|
+
}
|
|
284
|
+
}
|
|
213
285
|
#applyValidation() {
|
|
214
286
|
const errors = this.state && this.row?.data
|
|
215
287
|
? (this.editingController?.getCellErrors(this.row.data, this.column.key) ?? null)
|
|
@@ -242,7 +314,7 @@ class ApexGridCell extends LitElement {
|
|
|
242
314
|
const decoration = this.state && this.row
|
|
243
315
|
? this.state.decorateCell({
|
|
244
316
|
row: this.row.data,
|
|
245
|
-
rowIndex: this.
|
|
317
|
+
rowIndex: this.#inPinnedBand ? -1 : this.rowIndex,
|
|
246
318
|
column: this.column,
|
|
247
319
|
value: this.value,
|
|
248
320
|
})
|
|
@@ -266,6 +338,8 @@ class ApexGridCell extends LitElement {
|
|
|
266
338
|
}
|
|
267
339
|
updated(changed) {
|
|
268
340
|
if (this.isEditing) {
|
|
341
|
+
if (!changed.has('editing'))
|
|
342
|
+
return;
|
|
269
343
|
const editor = this.editorElement;
|
|
270
344
|
editor?.focus();
|
|
271
345
|
if (editor instanceof HTMLInputElement) {
|
|
@@ -285,22 +359,94 @@ class ApexGridCell extends LitElement {
|
|
|
285
359
|
#startEdit() {
|
|
286
360
|
if (!this.row)
|
|
287
361
|
return;
|
|
288
|
-
this.editingController.
|
|
362
|
+
this.editingController.editRecord(this.row.data, this.column.key);
|
|
289
363
|
}
|
|
290
|
-
#pendingValue;
|
|
291
364
|
#refocusAfterEdit;
|
|
292
|
-
#
|
|
365
|
+
#commit;
|
|
293
366
|
#cancel;
|
|
367
|
+
#commitAndTab(event) {
|
|
368
|
+
event.preventDefault();
|
|
369
|
+
if (this.#inPinnedBand) {
|
|
370
|
+
this.#refocusAfterEdit = true;
|
|
371
|
+
void this.#commit();
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
const step = event.shiftKey ? -1 : 1;
|
|
375
|
+
const host = this.state.host;
|
|
376
|
+
const body = this.row.parentElement;
|
|
377
|
+
const record = this.row.data;
|
|
378
|
+
const origin = this.row.index;
|
|
379
|
+
const key = this.column.key;
|
|
380
|
+
const columns = this.row.columns;
|
|
381
|
+
const keys = this.row.cells.map((cell) => cell.column.key);
|
|
382
|
+
const settle = async () => {
|
|
383
|
+
await host.updateComplete;
|
|
384
|
+
await body?.updateComplete;
|
|
385
|
+
await Promise.all(renderedRows(body).map((row) => row.updateComplete));
|
|
386
|
+
};
|
|
387
|
+
void this.#commit().then(async (committed) => {
|
|
388
|
+
if (!committed)
|
|
389
|
+
return;
|
|
390
|
+
await settle();
|
|
391
|
+
const items = host.pageItems;
|
|
392
|
+
const isFullWidth = (index) => items[index] == null ||
|
|
393
|
+
this.state.presentRow(items[index], { columns, rowIndex: index }) !== null;
|
|
394
|
+
const from = items.indexOf(record);
|
|
395
|
+
let target;
|
|
396
|
+
if (from >= 0) {
|
|
397
|
+
target = tabTarget(items.length, from, keys, key, step, isFullWidth) ?? {
|
|
398
|
+
row: from,
|
|
399
|
+
column: key,
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
else {
|
|
403
|
+
const row = nearestCellRow(items.length, origin, step, isFullWidth);
|
|
404
|
+
target = row < 0 ? null : { row, column: key };
|
|
405
|
+
}
|
|
406
|
+
if (!target) {
|
|
407
|
+
body?.focus({ preventScroll: true });
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
this.state.active = target;
|
|
411
|
+
await settle();
|
|
412
|
+
let cell = findRenderedCell(body, target);
|
|
413
|
+
for (let attempt = 0; !cell && attempt < 3; attempt++) {
|
|
414
|
+
scrollRowIntoRange(host, body, target.row);
|
|
415
|
+
await new Promise(requestAnimationFrame);
|
|
416
|
+
await new Promise(requestAnimationFrame);
|
|
417
|
+
await settle();
|
|
418
|
+
cell = findRenderedCell(body, target);
|
|
419
|
+
}
|
|
420
|
+
if (!cell) {
|
|
421
|
+
body?.focus({ preventScroll: true });
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
cell.focus({ preventScroll: true });
|
|
425
|
+
cell.scrollIntoView({ block: 'nearest', inline: 'nearest' });
|
|
426
|
+
await new Promise(requestAnimationFrame);
|
|
427
|
+
await new Promise(requestAnimationFrame);
|
|
428
|
+
const active = this.state.active;
|
|
429
|
+
const dropped = !document.activeElement || document.activeElement === document.body;
|
|
430
|
+
if (dropped && active.row === target.row && active.column === target.column) {
|
|
431
|
+
findRenderedCell(body, target)?.focus({ preventScroll: true });
|
|
432
|
+
}
|
|
433
|
+
});
|
|
434
|
+
}
|
|
294
435
|
#handleKeydown;
|
|
295
|
-
#handleBlur;
|
|
296
436
|
#handleCellKeydown;
|
|
297
437
|
#handleCellFocusOut;
|
|
438
|
+
get #isNumeric() {
|
|
439
|
+
const type = this.column.type;
|
|
440
|
+
return type === 'number' || type === 'currency';
|
|
441
|
+
}
|
|
298
442
|
#handleTextInput;
|
|
299
443
|
#handleCheckboxChange;
|
|
444
|
+
get #editorValue() {
|
|
445
|
+
return this.#resumed ? this.#resumed.value : this.value;
|
|
446
|
+
}
|
|
300
447
|
renderDefaultEditor() {
|
|
301
|
-
const value = this
|
|
448
|
+
const value = this.#editorValue;
|
|
302
449
|
if (this.column.type === 'boolean') {
|
|
303
|
-
this.#pendingValue = Boolean(value);
|
|
304
450
|
return html `<input
|
|
305
451
|
type="checkbox"
|
|
306
452
|
part="editor"
|
|
@@ -308,11 +454,9 @@ class ApexGridCell extends LitElement {
|
|
|
308
454
|
?checked=${Boolean(value)}
|
|
309
455
|
@change=${this.#handleCheckboxChange}
|
|
310
456
|
@keydown=${this.#handleKeydown}
|
|
311
|
-
@blur=${this.#handleBlur}
|
|
312
457
|
/>`;
|
|
313
458
|
}
|
|
314
|
-
if (this
|
|
315
|
-
this.#pendingValue = value;
|
|
459
|
+
if (this.#isNumeric) {
|
|
316
460
|
return html `<input
|
|
317
461
|
type="number"
|
|
318
462
|
part="editor"
|
|
@@ -320,10 +464,8 @@ class ApexGridCell extends LitElement {
|
|
|
320
464
|
.value=${value == null ? '' : String(value)}
|
|
321
465
|
@input=${this.#handleTextInput}
|
|
322
466
|
@keydown=${this.#handleKeydown}
|
|
323
|
-
@blur=${this.#handleBlur}
|
|
324
467
|
/>`;
|
|
325
468
|
}
|
|
326
|
-
this.#pendingValue = value;
|
|
327
469
|
return html `<input
|
|
328
470
|
type="text"
|
|
329
471
|
part="editor"
|
|
@@ -331,7 +473,6 @@ class ApexGridCell extends LitElement {
|
|
|
331
473
|
.value=${value == null ? '' : String(value)}
|
|
332
474
|
@input=${this.#handleTextInput}
|
|
333
475
|
@keydown=${this.#handleKeydown}
|
|
334
|
-
@blur=${this.#handleBlur}
|
|
335
476
|
/>`;
|
|
336
477
|
}
|
|
337
478
|
renderEditor() {
|
|
@@ -340,17 +481,16 @@ class ApexGridCell extends LitElement {
|
|
|
340
481
|
parent: this,
|
|
341
482
|
row: this.row,
|
|
342
483
|
column: this.column,
|
|
343
|
-
value: this
|
|
484
|
+
value: this.#editorValue,
|
|
344
485
|
commit: (next) => this.editingController.commitCell(next),
|
|
345
486
|
cancel: () => this.editingController.cancelCell(),
|
|
487
|
+
setDraft: (next) => this.editingController.setDraft(next),
|
|
346
488
|
};
|
|
347
489
|
if (template) {
|
|
348
|
-
this.#pendingValue = this.value;
|
|
349
490
|
return template(ctx);
|
|
350
491
|
}
|
|
351
492
|
const typeRenderer = getColumnTypeRenderer(this.column.type);
|
|
352
493
|
if (typeRenderer?.editor) {
|
|
353
|
-
this.#pendingValue = this.value;
|
|
354
494
|
return typeRenderer.editor(ctx);
|
|
355
495
|
}
|
|
356
496
|
return this.renderDefaultEditor();
|
|
@@ -470,9 +610,15 @@ __decorate([
|
|
|
470
610
|
__decorate([
|
|
471
611
|
property({ attribute: false, type: Number })
|
|
472
612
|
], ApexGridCell.prototype, "colindex", void 0);
|
|
613
|
+
__decorate([
|
|
614
|
+
property({ attribute: false })
|
|
615
|
+
], ApexGridCell.prototype, "rowIndex", void 0);
|
|
473
616
|
__decorate([
|
|
474
617
|
property({ attribute: false, type: Number })
|
|
475
618
|
], ApexGridCell.prototype, "decorationVersion", void 0);
|
|
619
|
+
__decorate([
|
|
620
|
+
property({ attribute: false })
|
|
621
|
+
], ApexGridCell.prototype, "dataVersion", void 0);
|
|
476
622
|
__decorate([
|
|
477
623
|
property({ attribute: false, type: Number })
|
|
478
624
|
], ApexGridCell.prototype, "validationVersion", void 0);
|
package/components/cell.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cell.js","sourceRoot":"","sources":["../../src/components/cell.ts"],"names":[],"mappings":"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","sourcesContent":["import { consume } from '@lit/context';\nimport { html, LitElement, type PropertyValues } from 'lit';\nimport { property, query } from 'lit/decorators.js';\nimport { gridStateContext, type StateController } from '../controllers/state.js';\nimport { getColumnTypeRenderer } from '../internal/column-types.js';\nimport { registerComponent } from '../internal/register.js';\nimport { GRID_CELL_TAG } from '../internal/tags.js';\nimport type {\n ApexCellContext,\n ApexEditorContext,\n ColumnConfiguration,\n PropertyType,\n} from '../internal/types.js';\nimport { styles } from '../styles/body-cell/body-cell.css.js';\nimport type ApexGridRow from './row.js';\n\n/**\n * A spreadsheet-style error value (e.g. the enterprise formula engine's\n * `#VALUE!` / `#DIV/0!`). Duck-typed so core carries no dependency on the\n * enterprise layer: any value that is an object carrying a `#...` string `code`\n * is rendered as that code, even in a typed (currency / number) column whose\n * numeric renderer would otherwise coerce it to `NaN` and show nothing.\n */\nfunction isErrorLike(value: unknown): value is { code: string } {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as { code?: unknown }).code === 'string' &&\n (value as { code: string }).code.startsWith('#')\n );\n}\n\n/**\n * Component representing a DOM cell of the Apex grid.\n *\n * @csspart cell - The cell host element.\n * @csspart editor - The editor wrapper rendered while the cell is in edit mode.\n */\nexport default class ApexGridCell<T extends object> extends LitElement {\n public static get tagName() {\n return GRID_CELL_TAG;\n }\n\n public static override styles = styles;\n\n public static register(): void {\n registerComponent(ApexGridCell);\n }\n\n /**\n * The value which will be rendered by the component.\n */\n @property({ attribute: false })\n public value!: PropertyType<T>;\n\n /**\n * A reference to the column configuration object.\n */\n @property({ attribute: false })\n public column!: ColumnConfiguration<T>;\n\n /**\n * Indicates whether this is the active cell in the grid.\n *\n */\n @property({ type: Boolean, reflect: true })\n public active = false;\n\n /**\n * Whether the cell is currently in edit mode. Set by the parent row from the\n * editing controller's state so cells re-render on edit state changes.\n */\n @property({ type: Boolean, reflect: true })\n public editing = false;\n\n @consume({ context: gridStateContext, subscribe: true })\n @property({ attribute: false })\n public state!: StateController<T>;\n\n /**\n * The parent row component holding this cell.\n */\n public row!: ApexGridRow<T>;\n\n @query('input, [data-apex-editor]')\n protected editorElement!: HTMLElement | null;\n\n protected get context(): ApexCellContext<T> {\n const ctx = {\n parent: this,\n row: this.row,\n column: this.column,\n value: this.value,\n } as unknown as {\n parent: ApexGridCell<T>;\n row: ApexGridRow<T>;\n column: ColumnConfiguration<T>;\n value: PropertyType<T>;\n commit?: (value: unknown) => Promise<boolean>;\n };\n // Only expose `commit` when the column is editable — non-editable\n // interactive widgets should render as read-only.\n if (this.isEditable) {\n ctx.commit = (next: unknown) =>\n this.editingController.commitImmediate(this.row.index, this.column.key, next);\n }\n return ctx as unknown as ApexCellContext<T>;\n }\n\n protected get editingController() {\n return this.state.editing;\n }\n\n protected get isEditing(): boolean {\n return this.editing;\n }\n\n protected get isEditable(): boolean {\n if (!this.editingController) return false;\n return this.editingController.isEditable(this.column);\n }\n\n /**\n * 1-based column index used to populate `aria-colindex`. Accounts for the\n * auto-rendered selection + expansion columns ahead of the data columns.\n */\n @property({ attribute: false, type: Number })\n public colindex = 0;\n\n /**\n * Reactive token forwarded from {@link StateController.decorationVersion}.\n * Changing it re-runs {@link willUpdate} so module-driven cell decoration is\n * re-evaluated when it changes (e.g. while dragging a selection range). Stays\n * `0` for the community grid, so cells are never re-decorated there.\n */\n @property({ attribute: false, type: Number })\n public decorationVersion = 0;\n\n /**\n * Reactive token forwarded from {@link EditingController.validationVersion}.\n * Changing it re-runs {@link willUpdate} so the cell re-reads its validation\n * errors and toggles `aria-invalid` / the inline error node. Stays `0` until\n * the first validation failure.\n */\n @property({ attribute: false, type: Number })\n public validationVersion = 0;\n\n /** Decoration attribute keys applied on the previous update, for cleanup. */\n #decoratedKeys: string[] = [];\n\n /** DOM id of the inline error node, referenced by `aria-errormessage`. */\n static readonly #ERROR_ID = 'apex-cell-error';\n\n /** Validation errors resolved in {@link willUpdate}, consumed in render. */\n #errors: readonly string[] | null = null;\n\n public override connectedCallback(): void {\n super.connectedCallback();\n this.setAttribute('role', 'gridcell');\n this.addEventListener('click', this.#handleClick);\n this.addEventListener('dblclick', this.#handleDoubleClick);\n this.addEventListener('keydown', this.#handleCellKeydown);\n this.addEventListener('focusout', this.#handleCellFocusOut);\n }\n\n public override disconnectedCallback(): void {\n this.removeEventListener('click', this.#handleClick);\n this.removeEventListener('dblclick', this.#handleDoubleClick);\n this.removeEventListener('keydown', this.#handleCellKeydown);\n this.removeEventListener('focusout', this.#handleCellFocusOut);\n super.disconnectedCallback();\n }\n\n protected override willUpdate() {\n if (this.colindex > 0) {\n this.setAttribute('aria-colindex', String(this.colindex));\n } else {\n this.removeAttribute('aria-colindex');\n }\n // Roving tabindex: the active cell is the grid body's single tab stop, so\n // real focus (not just `aria-current`) tracks keyboard navigation and\n // screen readers follow arrow-key movement cell to cell.\n this.tabIndex = this.active ? 0 : -1;\n if (this.active) {\n this.setAttribute('aria-current', 'true');\n } else {\n this.removeAttribute('aria-current');\n }\n // Reflect tree-expanded state on the group cell so the SCSS chevron\n // rotation triggers from this attribute (cheaper than per-render style\n // mutations and keeps the SVG transform purely declarative).\n const tree = this.state?.tree;\n const isGroup = tree?.enabled && this.row?.data && tree.isGroupColumn(this.column.key);\n if (isGroup && tree.isExpanded(this.row.data)) {\n this.setAttribute('data-tree-expanded', '');\n } else {\n this.removeAttribute('data-tree-expanded');\n }\n\n this.#applyValidation();\n this.#applyDecoration();\n }\n\n /**\n * Reflects the cell's validation state from the editing controller: stores the\n * current error messages for {@link render} and toggles `aria-invalid` +\n * `aria-errormessage` + `data-invalid` on the host. Inert for cells whose\n * column has no validators (the lookup returns `null`).\n */\n #applyValidation(): void {\n const errors =\n this.state && this.row?.data\n ? (this.editingController?.getCellErrors(this.row.data, this.column.key) ?? null)\n : null;\n this.#errors = errors && errors.length > 0 ? errors : null;\n\n if (this.#errors) {\n this.setAttribute('aria-invalid', 'true');\n this.setAttribute('aria-errormessage', ApexGridCell.#ERROR_ID);\n this.setAttribute('data-invalid', '');\n this.setAttribute('title', this.#errors.join('; '));\n } else {\n this.removeAttribute('aria-invalid');\n this.removeAttribute('aria-errormessage');\n this.removeAttribute('data-invalid');\n this.removeAttribute('title');\n }\n }\n\n /**\n * The inline error node surfaced when the cell is invalid. `role=\"alert\"`\n * announces the message when it appears, covering the cross-shadow gap where\n * an `aria-errormessage` IDREF on the host can't reach this node.\n */\n protected renderError() {\n if (!this.#errors) return null;\n return html`<span\n part=\"cell-error\"\n id=${ApexGridCell.#ERROR_ID}\n role=\"alert\"\n >${this.#errors.join('; ')}</span\n >`;\n }\n\n /**\n * Reflects module-contributed decoration attributes (see {@link CellDecorator})\n * onto the cell host, reconciling against the previous update so attributes\n * that are no longer present are removed. Inert for the community grid:\n * `state.decorateCell` returns `null` with no modules, so nothing is set.\n */\n #applyDecoration(): void {\n const decoration =\n this.state && this.row\n ? this.state.decorateCell({\n row: this.row.data,\n rowIndex: this.row.index,\n column: this.column,\n value: this.value as unknown,\n })\n : null;\n const next = decoration?.attributes ?? {};\n\n // Remove anything we set last time that's gone (or explicitly cleared).\n for (const key of this.#decoratedKeys) {\n if (next[key] == null) this.removeAttribute(key);\n }\n\n const applied: string[] = [];\n for (const [key, value] of Object.entries(next)) {\n if (value == null) {\n this.removeAttribute(key);\n } else {\n this.setAttribute(key, value);\n applied.push(key);\n }\n }\n this.#decoratedKeys = applied;\n }\n\n protected override updated(changed: PropertyValues<this>) {\n if (this.isEditing) {\n const editor = this.editorElement;\n editor?.focus();\n if (editor instanceof HTMLInputElement) {\n if (editor.type === 'text' || editor.type === 'number') {\n editor.select();\n }\n }\n return;\n }\n // A keyboard-committed (or cancelled) edit removes the focused editor from\n // the DOM; hand focus back to the cell host so grid navigation continues\n // from where the user was. Pointer-driven exits (blur / outside click)\n // never set the flag, so they don't steal focus from the click target.\n if (changed.get('editing') === true && this.#refocusAfterEdit) {\n this.#refocusAfterEdit = false;\n this.focus();\n }\n }\n\n #handleClick = (event: MouseEvent) => {\n if (this.isEditing) {\n // Don't let clicks inside the editor bubble into navigation / outside-click commits.\n event.stopPropagation();\n return;\n }\n if (!this.isEditable) return;\n // Boolean cells handle interaction in their display widget — clicking the\n // checkbox commits inline via `ctx.commit`. We never enter edit mode for\n // booleans, which avoids the visual reflow between display/editor markup\n // and lets a single click toggle the value.\n if (this.column.type === 'boolean') return;\n if (this.editingController.trigger !== 'click') return;\n this.#startEdit();\n };\n\n #handleDoubleClick = (event: MouseEvent) => {\n if (this.isEditing) {\n event.stopPropagation();\n return;\n }\n if (!this.isEditable) return;\n if (this.column.type === 'boolean') return;\n if (this.editingController.trigger !== 'doubleClick') return;\n this.#startEdit();\n };\n\n #startEdit() {\n if (!this.row) return;\n this.editingController.editCell(this.row.index, this.column.key);\n }\n\n #pendingValue: unknown;\n\n /** Set by keyboard-driven commit/cancel so `updated` refocuses the cell host. */\n #refocusAfterEdit = false;\n\n #commitWith = async (value?: unknown): Promise<boolean> => {\n return this.editingController.commitCell(value ?? this.#pendingValue);\n };\n\n #cancel = () => {\n this.editingController.cancelCell();\n };\n\n #handleKeydown = (event: KeyboardEvent) => {\n event.stopPropagation();\n switch (event.key) {\n case 'Enter':\n event.preventDefault();\n this.#refocusAfterEdit = true;\n this.#commitWith();\n return;\n case 'Escape':\n event.preventDefault();\n this.#refocusAfterEdit = true;\n this.#cancel();\n return;\n case 'Tab':\n // Commit first; navigation moves to the next/prev cell. Editing of the\n // landed cell stays manual (Enter to re-edit) for predictability.\n event.preventDefault();\n this.#refocusAfterEdit = true;\n this.#commitWith();\n return;\n default:\n return;\n }\n };\n\n #handleBlur = () => {\n if (!this.isEditing) return;\n if (this.editingController.mode === 'cell') {\n this.#commitWith();\n } else {\n // Row mode — stash the value and exit the cell editor; the row stays open.\n this.editingController.commitCell(this.#pendingValue);\n }\n };\n\n /**\n * Cell-level keydown that catches keys bubbling out of registry-built\n * editors (the default editor stops propagation on its own input).\n *\n * - Escape always cancels the edit.\n * - Tab commits (or closes when there's no draft — `commitCell()` with\n * `undefined` value is treated as \"no change\" by the controller).\n *\n * Per-editor `keydown` handlers that need to consume Enter (e.g. the\n * built-in `<select>` editor) still get the first crack — they call\n * `event.stopPropagation()` and we never see those keys here.\n */\n #handleCellKeydown = (event: KeyboardEvent) => {\n if (!this.isEditing) return;\n if (event.key === 'Escape') {\n event.preventDefault();\n this.#refocusAfterEdit = true;\n this.#cancel();\n return;\n }\n if (event.key === 'Tab') {\n event.preventDefault();\n this.#refocusAfterEdit = true;\n this.#commitWith();\n }\n };\n\n /**\n * Cell-level focus-out: commits the active edit when focus truly leaves\n * the cell (clicking another cell, tabbing past the editor, blurring to\n * the document body). The default editor's input also has `@blur` which\n * commits first; by that time `isEditing` is false and this is a no-op.\n *\n * For built-in registry editors `commitCell()` with no explicit value\n * resolves to the current data value — same shape as \"no change\", so\n * losing focus without picking discards the open editor without writing\n * spurious data.\n */\n #handleCellFocusOut = (event: FocusEvent) => {\n if (!this.isEditing) return;\n const next = event.relatedTarget as Node | null;\n if (next && (this.contains(next) || this.shadowRoot?.contains(next))) return;\n if (this.editingController.mode === 'cell') {\n this.#commitWith();\n } else {\n this.editingController.commitCell(this.#pendingValue);\n }\n };\n\n #handleTextInput = (event: Event) => {\n const target = event.target as HTMLInputElement;\n if (this.column.type === 'number') {\n // An empty (or non-parseable) number field clears the value to null rather\n // than committing NaN, which would render as the text \"NaN\".\n const numeric = target.valueAsNumber;\n this.#pendingValue = target.value === '' || Number.isNaN(numeric) ? null : numeric;\n return;\n }\n this.#pendingValue = target.value;\n };\n\n #handleCheckboxChange = (event: Event) => {\n const target = event.target as HTMLInputElement;\n this.#pendingValue = target.checked;\n // Booleans commit immediately — toggling is the whole interaction.\n this.#commitWith(target.checked);\n };\n\n protected renderDefaultEditor() {\n const value = this.value as unknown;\n if (this.column.type === 'boolean') {\n this.#pendingValue = Boolean(value);\n return html`<input\n type=\"checkbox\"\n part=\"editor\"\n data-apex-editor\n ?checked=${Boolean(value)}\n @change=${this.#handleCheckboxChange}\n @keydown=${this.#handleKeydown}\n @blur=${this.#handleBlur}\n />`;\n }\n if (this.column.type === 'number') {\n this.#pendingValue = value;\n return html`<input\n type=\"number\"\n part=\"editor\"\n data-apex-editor\n .value=${value == null ? '' : String(value)}\n @input=${this.#handleTextInput}\n @keydown=${this.#handleKeydown}\n @blur=${this.#handleBlur}\n />`;\n }\n this.#pendingValue = value;\n return html`<input\n type=\"text\"\n part=\"editor\"\n data-apex-editor\n .value=${value == null ? '' : String(value)}\n @input=${this.#handleTextInput}\n @keydown=${this.#handleKeydown}\n @blur=${this.#handleBlur}\n />`;\n }\n\n protected renderEditor() {\n const template = this.column.editorTemplate;\n const ctx = {\n parent: this,\n row: this.row,\n column: this.column,\n value: this.value,\n commit: (next: unknown) => this.editingController.commitCell(next),\n cancel: () => this.editingController.cancelCell(),\n };\n if (template) {\n // For custom editors we don't know the draft shape; reset pending so\n // cell-level commit doesn't write a stale value from a previous edit.\n this.#pendingValue = this.value;\n return template(ctx as unknown as ApexEditorContext<T> as never);\n }\n const typeRenderer = getColumnTypeRenderer<T>(this.column.type);\n if (typeRenderer?.editor) {\n this.#pendingValue = this.value;\n return typeRenderer.editor(ctx as never);\n }\n return this.renderDefaultEditor();\n }\n\n /**\n * Renders the tree affordance — depth-based indent + a chevron toggle (or\n * leaf spacer) — that prefixes the group cell when {@link ApexGrid.tree}\n * is enabled. Returns `nothing` for every other cell.\n */\n protected renderTreeAffordance() {\n const tree = this.state?.tree;\n if (!tree?.enabled) return null;\n if (!this.row?.data) return null;\n if (!tree.isGroupColumn(this.column.key)) return null;\n\n const data = this.row.data;\n const meta = tree.getMeta(data);\n if (!meta) return null;\n\n const indent = meta.depth * tree.childIndent;\n const expanded = tree.isExpanded(data);\n const handleClick = (event: MouseEvent) => {\n event.stopPropagation();\n if (!meta.hasChildren) return;\n void tree.toggleRow(data);\n };\n\n const chevron = meta.hasChildren\n ? html`<button\n type=\"button\"\n part=\"tree-toggle\"\n aria-label=${\n expanded ? this.state.localize('row.collapse') : this.state.localize('row.expand')\n }\n aria-expanded=${expanded ? 'true' : 'false'}\n @click=${handleClick}\n >\n <svg\n part=\"tree-chevron\"\n viewBox=\"0 0 24 24\"\n aria-hidden=\"true\"\n width=\"14\"\n height=\"14\"\n >\n <path\n d=\"M9 6l6 6-6 6\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </button>`\n : html`<span part=\"tree-spacer\" aria-hidden=\"true\"></span>`;\n\n return html`<span\n part=\"tree-indent\"\n aria-hidden=\"true\"\n style=${`inline-size: ${indent}px`}\n ></span>${chevron}`;\n }\n\n /**\n * Resolves the value to display for the cell. Synthesized tree parents\n * (those that appear only as a path segment with no backing data) render\n * their last path segment in the group column and nothing elsewhere.\n */\n protected resolveDisplayValue(): unknown {\n const tree = this.state?.tree;\n if (tree?.enabled && this.row?.data && tree.isSynthesized(this.row.data)) {\n return tree.isGroupColumn(this.column.key) ? tree.getLabel(this.row.data) : '';\n }\n return this.value;\n }\n\n protected renderCellBody() {\n if (this.column.cellTemplate) {\n return this.column.cellTemplate(this.context as ApexCellContext<T> as never);\n }\n // A formula error is a first-class cell value: render its code as text so it\n // stays visible in typed columns (a currency/number renderer would coerce it\n // to NaN and show an empty cell).\n const value = this.resolveDisplayValue();\n if (isErrorLike(value)) {\n return html`${value.code}`;\n }\n const typeRenderer = getColumnTypeRenderer<T>(this.column.type);\n if (typeRenderer?.display) {\n // Synthesized parents have no real backing data — route them through\n // a plain text render instead of the typed renderer.\n const tree = this.state?.tree;\n if (tree?.enabled && this.row?.data && tree.isSynthesized(this.row.data)) {\n return html`${this.resolveDisplayValue()}`;\n }\n return typeRenderer.display(this.context as never);\n }\n return html`${this.resolveDisplayValue()}`;\n }\n\n protected override render() {\n const error = this.renderError();\n if (this.isEditing) {\n return html`${this.renderEditor()}${error}`;\n }\n const affordance = this.renderTreeAffordance();\n if (affordance) {\n return html`${affordance}<span part=\"tree-cell-content\"\n >${this.renderCellBody()}</span\n >${error}`;\n }\n return html`${this.renderCellBody()}${error}`;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n [ApexGridCell.tagName]: ApexGridCell<object>;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"cell.js","sourceRoot":"","sources":["../../src/components/cell.ts"],"names":[],"mappings":"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","sourcesContent":["import { consume } from '@lit/context';\nimport { html, LitElement, type PropertyValues } from 'lit';\nimport { property, query } from 'lit/decorators.js';\nimport { gridStateContext, type StateController } from '../controllers/state.js';\nimport { getColumnTypeRenderer } from '../internal/column-types.js';\nimport { registerComponent } from '../internal/register.js';\nimport { GRID_CELL_TAG, GRID_ROW_TAG } from '../internal/tags.js';\nimport type {\n ActiveNode,\n ApexCellContext,\n ApexEditorContext,\n ColumnConfiguration,\n PropertyType,\n} from '../internal/types.js';\nimport { styles } from '../styles/body-cell/body-cell.css.js';\nimport type ApexGridRow from './row.js';\n\n/**\n * A spreadsheet-style error value (e.g. the enterprise formula engine's\n * `#VALUE!` / `#DIV/0!`). Duck-typed so core carries no dependency on the\n * enterprise layer: any value that is an object carrying a `#...` string `code`\n * is rendered as that code, even in a typed (currency / number) column whose\n * numeric renderer would otherwise coerce it to `NaN` and show nothing.\n */\nfunction isErrorLike(value: unknown): value is { code: string } {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as { code?: unknown }).code === 'string' &&\n (value as { code: string }).code.startsWith('#')\n );\n}\n\n/** The body rows rendered under `body` (the rows' shared parent). */\nfunction renderedRows<T extends object>(body: Element | null): ApexGridRow<T>[] {\n if (!body) return [];\n return Array.from(body.children).filter(\n (element) => element.localName === GRID_ROW_TAG\n ) as unknown as ApexGridRow<T>[];\n}\n\n/**\n * The cell Tab moves to from column `key` of view row `from`: the neighbouring\n * column (`keys`) of that row or, past the row edge, the first (or last) column\n * of the nearest row in that direction that renders cells, skipping full-width\n * rows. `null` at the edge of the grid's `count` view rows.\n */\nfunction tabTarget<T extends object>(\n count: number,\n from: number,\n keys: ColumnConfiguration<T>['key'][],\n key: ColumnConfiguration<T>['key'],\n step: 1 | -1,\n isFullWidth: (index: number) => boolean\n): ActiveNode<T> | null {\n const column = keys[keys.indexOf(key) + step];\n if (column !== undefined) return { row: from, column };\n const wrapColumn = keys[step > 0 ? 0 : keys.length - 1];\n for (let index = from + step; index >= 0 && index < count; index += step) {\n if (!isFullWidth(index)) return { row: index, column: wrapColumn };\n }\n return null;\n}\n\n/**\n * The view row nearest `start` (clamped to the `count` rows) that renders\n * cells, looking in the `step` direction first. `-1` when none does.\n */\nfunction nearestCellRow(\n count: number,\n start: number,\n step: 1 | -1,\n isFullWidth: (index: number) => boolean\n): number {\n const origin = Math.min(Math.max(start, 0), count - 1);\n for (let distance = 0; distance < count; distance++) {\n for (const index of [origin + distance * step, origin - distance * step]) {\n if (index >= 0 && index < count && !isFullWidth(index)) return index;\n }\n }\n return -1;\n}\n\n/** The rendered cell for `node` under `body`, if its row is rendered. */\nfunction findRenderedCell<T extends object>(body: Element | null, node: ActiveNode<T>) {\n return renderedRows<T>(body)\n .find((row) => row.index === node.row)\n ?.cells.find((cell) => cell.column.key === node.column);\n}\n\n/**\n * Scrolls `scroller` (the grid host, which owns the body's scrolling) so view\n * row `index`, outside the rows rendered under `body`, lands about mid-view,\n * placing it from the rendered rows' positions and average height. The\n * virtualizer then renders it on the scroll and the landed cell is aligned\n * exactly. (The virtualizer's own `element(index).scrollIntoView()` pin does\n * not work with the grid host as the scroller: it jumps to the end of the\n * range and renders no rows.)\n */\nfunction scrollRowIntoRange(scroller: HTMLElement, body: Element | null, index: number) {\n const rows = renderedRows(body).sort((a, b) => a.index - b.index);\n const first = rows.at(0);\n const last = rows.at(-1);\n if (!first || !last) return;\n const top = first.getBoundingClientRect().top;\n const height = (last.getBoundingClientRect().bottom - top) / (last.index - first.index + 1);\n const view = scroller.getBoundingClientRect();\n const rowCentre = top + (index - first.index + 0.5) * height;\n scroller.scrollTop += rowCentre - (view.top + scroller.clientHeight / 2);\n}\n\n/**\n * Component representing a DOM cell of the Apex grid.\n *\n * @csspart cell - The cell host element.\n * @csspart editor - The editor wrapper rendered while the cell is in edit mode.\n */\nexport default class ApexGridCell<T extends object> extends LitElement {\n public static get tagName() {\n return GRID_CELL_TAG;\n }\n\n public static override styles = styles;\n\n public static register(): void {\n registerComponent(ApexGridCell);\n }\n\n /**\n * The value which will be rendered by the component.\n */\n @property({ attribute: false })\n public value!: PropertyType<T>;\n\n /**\n * A reference to the column configuration object.\n */\n @property({ attribute: false })\n public column!: ColumnConfiguration<T>;\n\n /**\n * Indicates whether this is the active cell in the grid.\n *\n */\n @property({ type: Boolean, reflect: true })\n public active = false;\n\n /**\n * Whether the cell is currently in edit mode. Set by the parent row from the\n * editing controller's state so cells re-render on edit state changes.\n */\n @property({ type: Boolean, reflect: true })\n public editing = false;\n\n @consume({ context: gridStateContext, subscribe: true })\n @property({ attribute: false })\n public state!: StateController<T>;\n\n /**\n * The parent row component holding this cell.\n */\n public row!: ApexGridRow<T>;\n\n @query('input, [data-apex-editor]')\n protected editorElement!: HTMLElement | null;\n\n protected get context(): ApexCellContext<T> {\n const ctx = {\n parent: this,\n row: this.row,\n column: this.column,\n value: this.value,\n } as unknown as {\n parent: ApexGridCell<T>;\n row: ApexGridRow<T>;\n column: ColumnConfiguration<T>;\n value: PropertyType<T>;\n commit?: (value: unknown) => Promise<boolean>;\n };\n // Only expose `commit` when the column is editable — non-editable\n // interactive widgets should render as read-only.\n if (this.isEditable) {\n ctx.commit = (next: unknown) =>\n this.editingController.commitImmediate(this.row.data, this.column.key, next);\n }\n return ctx as unknown as ApexCellContext<T>;\n }\n\n protected get editingController() {\n return this.state.editing;\n }\n\n protected get isEditing(): boolean {\n return this.editing;\n }\n\n protected get isEditable(): boolean {\n if (!this.editingController) return false;\n return this.editingController.isEditable(this.column);\n }\n\n /** Whether the cell's row renders in a pinned band rather than the body. */\n get #inPinnedBand(): boolean {\n const pin = this.state.rowPin;\n return pin.hasPinnedRows && pin.enabled && pin.isPinned(this.row.data);\n }\n\n /**\n * 1-based column index used to populate `aria-colindex`. Accounts for the\n * auto-rendered selection + expansion columns ahead of the data columns.\n */\n @property({ attribute: false, type: Number })\n public colindex = 0;\n\n /**\n * The parent row's view index, set by the row. Changing it re-decorates the\n * cell (decoration such as a range selection is positional), so a row that\n * moves with the same data (sort, filter, an expand above it) never keeps a\n * stale highlight.\n *\n * @internal\n */\n @property({ attribute: false })\n public rowIndex = -1;\n\n /**\n * Reactive token forwarded from {@link StateController.decorationVersion}.\n * Changing it re-applies module-driven cell decoration (e.g. while dragging a\n * selection range) without re-rendering the cell content. Stays `0` for the\n * community grid, so cells are never re-decorated there.\n */\n @property({ attribute: false, type: Number })\n public decorationVersion = 0;\n\n /**\n * Reactive token forwarded from {@link StateController.dataVersion}, bumped\n * once per pipeline run. Re-renders only a cell that reads its row beyond\n * its own value (see {@link shouldUpdate}).\n *\n * @internal\n */\n @property({ attribute: false })\n public dataVersion = 0;\n\n /**\n * Reactive token forwarded from {@link EditingController.validationVersion}.\n * Changing it re-runs {@link willUpdate} so the cell re-reads its validation\n * errors and toggles `aria-invalid` / the inline error node. Stays `0` until\n * the first validation failure.\n */\n @property({ attribute: false, type: Number })\n public validationVersion = 0;\n\n /** Decoration attribute keys applied on the previous update, for cleanup. */\n #decoratedKeys: string[] = [];\n\n /** DOM id of the inline error node, referenced by `aria-errormessage`. */\n static readonly #ERROR_ID = 'apex-cell-error';\n\n /** Validation errors resolved in {@link willUpdate}, consumed in render. */\n #errors: readonly string[] | null = null;\n\n /** Whether {@link value} currently shows a staged row-mode value. */\n #staged = false;\n\n /**\n * The held draft the editor resumed from when it opened on an edit already\n * in progress (see {@link #editorValue}), or `null`.\n */\n #resumed: { value: unknown } | null = null;\n\n /** Set by a reconnect, whose context re-request is a bare requestUpdate(). */\n #reconnected = false;\n\n public override connectedCallback(): void {\n // A moved row reconnects its cells; the state context consumer then\n // requests an update with nothing changed, which needs no render.\n this.#reconnected = this.hasUpdated && !this.isUpdatePending;\n super.connectedCallback();\n this.setAttribute('role', 'gridcell');\n this.addEventListener('click', this.#handleClick);\n this.addEventListener('dblclick', this.#handleDoubleClick);\n this.addEventListener('keydown', this.#handleCellKeydown);\n this.addEventListener('focusout', this.#handleCellFocusOut);\n }\n\n public override disconnectedCallback(): void {\n this.removeEventListener('click', this.#handleClick);\n this.removeEventListener('dblclick', this.#handleDoubleClick);\n this.removeEventListener('keydown', this.#handleCellKeydown);\n this.removeEventListener('focusout', this.#handleCellFocusOut);\n super.disconnectedCallback();\n }\n\n /**\n * Skips the render when only positional or decoration tokens changed: the\n * decoration is host attributes, so it is reconciled here and the cell\n * template (type renderers, user templates) is not re-run. A cell that reads\n * its row beyond {@link value} (a `cellTemplate`, which may read other fields\n * or the row index, or the tree group cell, whose chevron shows the row's\n * expansion) still renders when the row index or the data token moves.\n */\n protected override shouldUpdate(changed: PropertyValues<this>): boolean {\n const reconnected = this.#reconnected;\n this.#reconnected = false;\n // A bare requestUpdate() (empty map) renders, as Lit callers expect.\n if (!this.hasUpdated || (!changed.size && !reconnected)) return true;\n const tree = this.state?.tree;\n const readsRow =\n this.column.cellTemplate || (tree?.enabled && tree.isGroupColumn(this.column.key));\n for (const key of changed.keys()) {\n const token = key === 'rowIndex' || key === 'dataVersion';\n if (key !== 'decorationVersion' && (readsRow || !token)) return true;\n }\n if (changed.has('decorationVersion') || changed.has('rowIndex')) this.#applyDecoration();\n return false;\n }\n\n protected override willUpdate(changed: PropertyValues<this>) {\n this.#applyStaged();\n if (changed.has('editing')) {\n this.#resumed = this.editing\n ? this.editingController.heldDraft(this.row.data, this.column.key)\n : null;\n }\n if (this.colindex > 0) {\n this.setAttribute('aria-colindex', String(this.colindex));\n } else {\n this.removeAttribute('aria-colindex');\n }\n // Roving tabindex: the active cell is the grid body's single tab stop, so\n // real focus (not just `aria-current`) tracks keyboard navigation and\n // screen readers follow arrow-key movement cell to cell.\n this.tabIndex = this.active ? 0 : -1;\n if (this.active) {\n this.setAttribute('aria-current', 'true');\n } else {\n this.removeAttribute('aria-current');\n }\n // Reflect tree-expanded state on the group cell so the SCSS chevron\n // rotation triggers from this attribute (cheaper than per-render style\n // mutations and keeps the SVG transform purely declarative).\n const tree = this.state?.tree;\n const isGroup = tree?.enabled && this.row?.data && tree.isGroupColumn(this.column.key);\n if (isGroup && tree.isExpanded(this.row.data)) {\n this.setAttribute('data-tree-expanded', '');\n } else {\n this.removeAttribute('data-tree-expanded');\n }\n\n this.#applyValidation();\n this.#applyDecoration();\n }\n\n /**\n * Row mode: while the row is in edit, shows the cell's staged value in\n * place of the record's (display and a re-opened editor alike), and the\n * record's again once the row commits or cancels. One property read for\n * cells of rows not in edit.\n */\n #applyStaged(): void {\n const staged = this.state?.editing?.activeRow\n ? this.editingController.stagedValues(this.row.data)\n : null;\n const key = this.column.key;\n if (staged?.has(key)) {\n this.value = staged.get(key) as PropertyType<T>;\n this.#staged = true;\n } else if (this.#staged) {\n this.#staged = false;\n this.value = this.row.data[key] as PropertyType<T>;\n }\n }\n\n /**\n * Reflects the cell's validation state from the editing controller: stores the\n * current error messages for {@link render} and toggles `aria-invalid` +\n * `aria-errormessage` + `data-invalid` on the host. Inert for cells whose\n * column has no validators (the lookup returns `null`).\n */\n #applyValidation(): void {\n const errors =\n this.state && this.row?.data\n ? (this.editingController?.getCellErrors(this.row.data, this.column.key) ?? null)\n : null;\n this.#errors = errors && errors.length > 0 ? errors : null;\n\n if (this.#errors) {\n this.setAttribute('aria-invalid', 'true');\n this.setAttribute('aria-errormessage', ApexGridCell.#ERROR_ID);\n this.setAttribute('data-invalid', '');\n this.setAttribute('title', this.#errors.join('; '));\n } else {\n this.removeAttribute('aria-invalid');\n this.removeAttribute('aria-errormessage');\n this.removeAttribute('data-invalid');\n this.removeAttribute('title');\n }\n }\n\n /**\n * The inline error node surfaced when the cell is invalid. `role=\"alert\"`\n * announces the message when it appears, covering the cross-shadow gap where\n * an `aria-errormessage` IDREF on the host can't reach this node.\n */\n protected renderError() {\n if (!this.#errors) return null;\n return html`<span\n part=\"cell-error\"\n id=${ApexGridCell.#ERROR_ID}\n role=\"alert\"\n >${this.#errors.join('; ')}</span\n >`;\n }\n\n /**\n * Reflects module-contributed decoration attributes (see {@link CellDecorator})\n * onto the cell host, reconciling against the previous update so attributes\n * that are no longer present are removed. Inert for the community grid:\n * `state.decorateCell` returns `null` with no modules, so nothing is set.\n */\n #applyDecoration(): void {\n const decoration =\n this.state && this.row\n ? this.state.decorateCell({\n row: this.row.data,\n // A pinned row is outside the body view (`pageItems`), so its\n // band-local index must not match a body row's.\n rowIndex: this.#inPinnedBand ? -1 : this.rowIndex,\n column: this.column,\n value: this.value as unknown,\n })\n : null;\n const next = decoration?.attributes ?? {};\n\n // Remove anything we set last time that's gone (or explicitly cleared).\n for (const key of this.#decoratedKeys) {\n if (next[key] == null) this.removeAttribute(key);\n }\n\n const applied: string[] = [];\n for (const [key, value] of Object.entries(next)) {\n if (value == null) {\n this.removeAttribute(key);\n } else {\n this.setAttribute(key, value);\n applied.push(key);\n }\n }\n this.#decoratedKeys = applied;\n }\n\n protected override updated(changed: PropertyValues<this>) {\n if (this.isEditing) {\n // Focus and select only on entering edit mode: a mid-edit re-render\n // (validation, decoration) must keep the caret and the user's focus.\n if (!changed.has('editing')) return;\n const editor = this.editorElement;\n editor?.focus();\n if (editor instanceof HTMLInputElement) {\n if (editor.type === 'text' || editor.type === 'number') {\n editor.select();\n }\n }\n return;\n }\n // A keyboard-committed (or cancelled) edit removes the focused editor from\n // the DOM; hand focus back to the cell host so grid navigation continues\n // from where the user was. Pointer-driven exits (blur / outside click)\n // never set the flag, so they don't steal focus from the click target.\n if (changed.get('editing') === true && this.#refocusAfterEdit) {\n this.#refocusAfterEdit = false;\n this.focus();\n }\n }\n\n #handleClick = (event: MouseEvent) => {\n if (this.isEditing) {\n // Don't let clicks inside the editor bubble into navigation / outside-click commits.\n event.stopPropagation();\n return;\n }\n if (!this.isEditable) return;\n // Boolean cells handle interaction in their display widget — clicking the\n // checkbox commits inline via `ctx.commit`. We never enter edit mode for\n // booleans, which avoids the visual reflow between display/editor markup\n // and lets a single click toggle the value.\n if (this.column.type === 'boolean') return;\n if (this.editingController.trigger !== 'click') return;\n this.#startEdit();\n };\n\n #handleDoubleClick = (event: MouseEvent) => {\n if (this.isEditing) {\n event.stopPropagation();\n return;\n }\n if (!this.isEditable) return;\n if (this.column.type === 'boolean') return;\n if (this.editingController.trigger !== 'doubleClick') return;\n this.#startEdit();\n };\n\n #startEdit() {\n if (!this.row) return;\n // By record, so a pinned row edits its own record, not the body row at\n // its band-local index.\n this.editingController.editRecord(this.row.data, this.column.key);\n }\n\n /** Set by keyboard-driven commit/cancel so `updated` refocuses the cell host. */\n #refocusAfterEdit = false;\n\n /** Commits the open editor's draft (held by the editing controller). */\n #commit = (): Promise<boolean> => this.editingController.commitCell();\n\n #cancel = () => {\n this.editingController.cancelCell();\n };\n\n /**\n * Tab while editing: commits the draft and, once the commit is accepted,\n * moves the active cell and focus to the next cell (Shift+Tab: the previous\n * one), wrapping across rows, and scrolls it into view. The landed cell\n * stays closed (Enter or F2 opens it); a rejected commit keeps the editor\n * open. With no cell to land on (grid edge, only full-width rows such as\n * group headers beyond), focus stays on the edited record's cell.\n *\n * The target is resolved after the commit settles, from the edited record's\n * position in {@link ApexGrid.pageItems}: a commit can re-sort or regroup\n * the rows (the edited value is a sort or group key), so the record may now\n * sit at another index, outside the rows the virtualizer renders; the target\n * row is scrolled into view before it is focused. When the commit removed\n * the record from the view (filtered out, moved into a collapsed group, or\n * replaced by a listener writing a new object), focus stays in the grid on\n * the cell nearest the edited position.\n */\n #commitAndTab(event: KeyboardEvent): void {\n event.preventDefault();\n if (this.#inPinnedBand) {\n // Pinned rows sit outside the body's keyboard model: commit and keep\n // focus on this cell.\n this.#refocusAfterEdit = true;\n void this.#commit();\n return;\n }\n const step = event.shiftKey ? -1 : 1;\n const host = this.state.host;\n const body = this.row.parentElement as\n | (HTMLElement & { updateComplete?: Promise<unknown> })\n | null;\n const record = this.row.data;\n const origin = this.row.index;\n const key = this.column.key;\n const columns = this.row.columns;\n const keys = this.row.cells.map((cell) => cell.column.key);\n // The grid, then the rows' container (the virtualizer re-renders its rows\n // in its own update), then the rows themselves (a row that now holds a\n // full-width record drops its cells in its own update).\n const settle = async () => {\n await host.updateComplete;\n await body?.updateComplete;\n await Promise.all(renderedRows<T>(body).map((row) => row.updateComplete));\n };\n void this.#commit().then(async (committed) => {\n if (!committed) return;\n await settle();\n const items = host.pageItems;\n const isFullWidth = (index: number) =>\n items[index] == null ||\n this.state.presentRow(items[index], { columns, rowIndex: index }) !== null;\n const from = items.indexOf(record);\n let target: ActiveNode<T> | null;\n if (from >= 0) {\n target = tabTarget(items.length, from, keys, key, step, isFullWidth) ?? {\n row: from,\n column: key,\n };\n } else {\n const row = nearestCellRow(items.length, origin, step, isFullWidth);\n target = row < 0 ? null : { row, column: key };\n }\n if (!target) {\n body?.focus({ preventScroll: true });\n return;\n }\n this.state.active = target;\n await settle();\n let cell = findRenderedCell(body, target);\n // The target row is outside the rendered range: scroll towards it and\n // let the virtualizer render (two frames), re-aiming from the newly\n // rendered rows when the estimate fell short.\n for (let attempt = 0; !cell && attempt < 3; attempt++) {\n scrollRowIntoRange(host as unknown as HTMLElement, body, target.row);\n await new Promise(requestAnimationFrame);\n await new Promise(requestAnimationFrame);\n await settle();\n cell = findRenderedCell(body, target);\n }\n if (!cell) {\n body?.focus({ preventScroll: true });\n return;\n }\n cell.focus({ preventScroll: true });\n cell.scrollIntoView({ block: 'nearest', inline: 'nearest' });\n // The virtualizer's own layout pass, a frame or two later, can move or\n // re-create the landed row (an items change from the commit, such as a\n // quick filter dropping the record), which drops focus to the document.\n // Land again while the active cell is still the target.\n await new Promise(requestAnimationFrame);\n await new Promise(requestAnimationFrame);\n const active = this.state.active;\n const dropped = !document.activeElement || document.activeElement === document.body;\n if (dropped && active.row === target.row && active.column === target.column) {\n findRenderedCell(body, target)?.focus({ preventScroll: true });\n }\n });\n }\n\n #handleKeydown = (event: KeyboardEvent) => {\n event.stopPropagation();\n switch (event.key) {\n case 'Enter':\n event.preventDefault();\n this.#refocusAfterEdit = true;\n this.#commit();\n return;\n case 'Escape':\n event.preventDefault();\n this.#refocusAfterEdit = true;\n this.#cancel();\n return;\n case 'Tab':\n this.#commitAndTab(event);\n return;\n default:\n return;\n }\n };\n\n /**\n * Cell-level keydown that catches keys bubbling out of registry-built\n * editors (the default editor stops propagation on its own input).\n *\n * - Escape always cancels the edit.\n * - Tab commits the draft (or just closes when nothing was typed) and\n * moves to the next cell.\n *\n * Per-editor `keydown` handlers that need to consume Enter (e.g. the\n * built-in `<select>` editor) still get the first crack — they call\n * `event.stopPropagation()` and we never see those keys here.\n */\n #handleCellKeydown = (event: KeyboardEvent) => {\n if (!this.isEditing) return;\n if (event.key === 'Escape') {\n event.preventDefault();\n this.#refocusAfterEdit = true;\n this.#cancel();\n return;\n }\n if (event.key === 'Tab') this.#commitAndTab(event);\n };\n\n /**\n * Cell-level focus-out, the single focus-loss commit path: commits the\n * editor's draft when focus truly leaves the cell (clicking another cell or\n * a control outside the grid, blurring to the document body). In row mode\n * the value is staged and the row stays open.\n *\n * With no draft (nothing typed or picked) `commitCell()` resolves to the\n * current data value, so losing focus closes the editor without writing.\n * A failed validation keeps the editor open with its error.\n */\n #handleCellFocusOut = (event: FocusEvent) => {\n if (!this.isEditing) return;\n const next = event.relatedTarget as Node | null;\n if (next && (this.contains(next) || this.shadowRoot?.contains(next))) return;\n // A pointer exit never hands focus back to the cell, even after an\n // earlier keyboard commit that failed validation set the flag.\n this.#refocusAfterEdit = false;\n this.#commit();\n };\n\n /** Number and currency columns share the built-in number editor. */\n get #isNumeric(): boolean {\n const type = this.column.type;\n return type === 'number' || type === 'currency';\n }\n\n #handleTextInput = (event: Event) => {\n const target = event.target as HTMLInputElement;\n if (this.#isNumeric) {\n // An empty (or non-parseable) number field clears the value to null rather\n // than committing NaN, which would render as the text \"NaN\".\n const numeric = target.valueAsNumber;\n this.editingController.setDraft(\n target.value === '' || Number.isNaN(numeric) ? null : numeric\n );\n return;\n }\n this.editingController.setDraft(target.value);\n };\n\n #handleCheckboxChange = async (event: Event) => {\n const target = event.target as HTMLInputElement;\n // Booleans commit immediately: toggling is the whole interaction. A\n // rejected toggle flips back so the box never shows an unsaved state.\n if (!(await this.editingController.commitCell(target.checked))) {\n target.checked = !target.checked;\n }\n };\n\n /**\n * The value the editor shows: the cell value, or the held draft when the\n * editor opened on an edit already in progress (its record paged or\n * scrolled back into view), so what it shows is what a commit writes. Read\n * once on opening, so a later re-render never rewrites what the user is\n * typing.\n */\n get #editorValue(): unknown {\n return this.#resumed ? this.#resumed.value : this.value;\n }\n\n protected renderDefaultEditor() {\n const value = this.#editorValue;\n if (this.column.type === 'boolean') {\n return html`<input\n type=\"checkbox\"\n part=\"editor\"\n data-apex-editor\n ?checked=${Boolean(value)}\n @change=${this.#handleCheckboxChange}\n @keydown=${this.#handleKeydown}\n />`;\n }\n if (this.#isNumeric) {\n return html`<input\n type=\"number\"\n part=\"editor\"\n data-apex-editor\n .value=${value == null ? '' : String(value)}\n @input=${this.#handleTextInput}\n @keydown=${this.#handleKeydown}\n />`;\n }\n return html`<input\n type=\"text\"\n part=\"editor\"\n data-apex-editor\n .value=${value == null ? '' : String(value)}\n @input=${this.#handleTextInput}\n @keydown=${this.#handleKeydown}\n />`;\n }\n\n protected renderEditor() {\n const template = this.column.editorTemplate;\n const ctx = {\n parent: this,\n row: this.row,\n column: this.column,\n value: this.#editorValue,\n commit: (next: unknown) => this.editingController.commitCell(next),\n cancel: () => this.editingController.cancelCell(),\n setDraft: (next: unknown) => this.editingController.setDraft(next),\n };\n if (template) {\n return template(ctx as unknown as ApexEditorContext<T> as never);\n }\n const typeRenderer = getColumnTypeRenderer<T>(this.column.type);\n if (typeRenderer?.editor) {\n return typeRenderer.editor(ctx as never);\n }\n return this.renderDefaultEditor();\n }\n\n /**\n * Renders the tree affordance — depth-based indent + a chevron toggle (or\n * leaf spacer) — that prefixes the group cell when {@link ApexGrid.tree}\n * is enabled. Returns `nothing` for every other cell.\n */\n protected renderTreeAffordance() {\n const tree = this.state?.tree;\n if (!tree?.enabled) return null;\n if (!this.row?.data) return null;\n if (!tree.isGroupColumn(this.column.key)) return null;\n\n const data = this.row.data;\n const meta = tree.getMeta(data);\n if (!meta) return null;\n\n const indent = meta.depth * tree.childIndent;\n const expanded = tree.isExpanded(data);\n const handleClick = (event: MouseEvent) => {\n event.stopPropagation();\n if (!meta.hasChildren) return;\n void tree.toggleRow(data);\n };\n\n const chevron = meta.hasChildren\n ? html`<button\n type=\"button\"\n part=\"tree-toggle\"\n aria-label=${\n expanded ? this.state.localize('row.collapse') : this.state.localize('row.expand')\n }\n aria-expanded=${expanded ? 'true' : 'false'}\n @click=${handleClick}\n >\n <svg\n part=\"tree-chevron\"\n viewBox=\"0 0 24 24\"\n aria-hidden=\"true\"\n width=\"14\"\n height=\"14\"\n >\n <path\n d=\"M9 6l6 6-6 6\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </button>`\n : html`<span part=\"tree-spacer\" aria-hidden=\"true\"></span>`;\n\n return html`<span\n part=\"tree-indent\"\n aria-hidden=\"true\"\n style=${`inline-size: ${indent}px`}\n ></span>${chevron}`;\n }\n\n /**\n * Resolves the value to display for the cell. Synthesized tree parents\n * (those that appear only as a path segment with no backing data) render\n * their last path segment in the group column and nothing elsewhere.\n */\n protected resolveDisplayValue(): unknown {\n const tree = this.state?.tree;\n if (tree?.enabled && this.row?.data && tree.isSynthesized(this.row.data)) {\n return tree.isGroupColumn(this.column.key) ? tree.getLabel(this.row.data) : '';\n }\n return this.value;\n }\n\n protected renderCellBody() {\n if (this.column.cellTemplate) {\n return this.column.cellTemplate(this.context as ApexCellContext<T> as never);\n }\n // A formula error is a first-class cell value: render its code as text so it\n // stays visible in typed columns (a currency/number renderer would coerce it\n // to NaN and show an empty cell).\n const value = this.resolveDisplayValue();\n if (isErrorLike(value)) {\n return html`${value.code}`;\n }\n const typeRenderer = getColumnTypeRenderer<T>(this.column.type);\n if (typeRenderer?.display) {\n // Synthesized parents have no real backing data — route them through\n // a plain text render instead of the typed renderer.\n const tree = this.state?.tree;\n if (tree?.enabled && this.row?.data && tree.isSynthesized(this.row.data)) {\n return html`${this.resolveDisplayValue()}`;\n }\n return typeRenderer.display(this.context as never);\n }\n return html`${this.resolveDisplayValue()}`;\n }\n\n protected override render() {\n const error = this.renderError();\n if (this.isEditing) {\n return html`${this.renderEditor()}${error}`;\n }\n const affordance = this.renderTreeAffordance();\n if (affordance) {\n return html`${affordance}<span part=\"tree-cell-content\"\n >${this.renderCellBody()}</span\n >${error}`;\n }\n return html`${this.renderCellBody()}${error}`;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n [ApexGridCell.tagName]: ApexGridCell<object>;\n }\n}\n"]}
|