@angular/cdk-experimental 21.0.0-next.9 → 21.0.0-rc.1

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.
@@ -11,1142 +11,1206 @@ import { TemplatePortal } from '@angular/cdk/portal';
11
11
  import { FocusTrapFactory, InteractivityChecker, FocusTrap } from '@angular/cdk/a11y';
12
12
  import { ScrollDispatcher, ViewportRuler } from '@angular/cdk/scrolling';
13
13
 
14
- /** Selector for finding table cells. */
15
14
  const CELL_SELECTOR = '.cdk-cell, .mat-cell, td';
16
- /** Selector for finding editable table cells. */
17
15
  const EDITABLE_CELL_SELECTOR = '.cdk-popover-edit-cell, .mat-popover-edit-cell';
18
- /** Selector for finding table rows. */
19
16
  const ROW_SELECTOR = '.cdk-row, .mat-row, tr';
20
- /** Selector for finding the table element. */
21
17
  const TABLE_SELECTOR = 'table, cdk-table, mat-table';
22
- /** CSS class added to the edit lens pane. */
23
18
  const EDIT_PANE_CLASS = 'cdk-edit-pane';
24
- /** Selector for finding the edit lens pane. */
25
19
  const EDIT_PANE_SELECTOR = `.${EDIT_PANE_CLASS}, .mat-edit-pane`;
26
- /** Selector for table rows that should be skipped when moving focus. */
27
20
  const SKIP_ROW_FOCUS_SELECTOR = '.cdk-popover-edit-skip-focus, .mat-popover-edit-skip-focus';
28
21
 
29
- /** The delay applied to mouse events before hiding or showing hover content. */
30
22
  const MOUSE_EVENT_DELAY_MS = 40;
31
- /** The delay for reacting to focus/blur changes. */
32
23
  const FOCUS_DELAY = 0;
33
- /**
34
- * The possible states for hover content:
35
- * OFF - Not rendered.
36
- * FOCUSABLE - Rendered in the dom and styled for its contents to be focusable but invisible.
37
- * ON - Rendered and fully visible.
38
- */
39
24
  var HoverContentState;
40
25
  (function (HoverContentState) {
41
- HoverContentState[HoverContentState["OFF"] = 0] = "OFF";
42
- HoverContentState[HoverContentState["FOCUSABLE"] = 1] = "FOCUSABLE";
43
- HoverContentState[HoverContentState["ON"] = 2] = "ON";
26
+ HoverContentState[HoverContentState["OFF"] = 0] = "OFF";
27
+ HoverContentState[HoverContentState["FOCUSABLE"] = 1] = "FOCUSABLE";
28
+ HoverContentState[HoverContentState["ON"] = 2] = "ON";
44
29
  })(HoverContentState || (HoverContentState = {}));
45
- // Note: this class is generic, rather than referencing EditRef directly, in order to avoid
46
- // circular imports. If we were to reference it here, importing the registry into the
47
- // class that is registering itself will introduce a circular import.
48
- /**
49
- * Service for sharing delegated events and state for triggering table edits.
50
- */
51
30
  class EditEventDispatcher {
52
- _ngZone = inject(NgZone);
53
- /** A subject that indicates which table cell is currently editing (unless it is disabled). */
54
- editing = new Subject();
55
- /** A subject that indicates which table row is currently hovered. */
56
- hovering = new Subject();
57
- /** A subject that indicates which table row currently contains focus. */
58
- focused = new Subject();
59
- /** A subject that indicates all elements in the table matching ROW_SELECTOR. */
60
- allRows = new Subject();
61
- /** A subject that emits mouse move events from the table indicating the targeted row. */
62
- mouseMove = new Subject();
63
- // TODO: Use WeakSet once IE11 support is dropped.
64
- /**
65
- * Tracks the currently disabled editable cells - edit calls will be ignored
66
- * for these cells.
67
- */
68
- disabledCells = new WeakMap();
69
- /** The EditRef for the currently active edit lens (if any). */
70
- get editRef() {
71
- return this._editRef;
72
- }
73
- _editRef = null;
74
- // Optimization: Precompute common pipeable operators used per row/cell.
75
- _distinctUntilChanged = distinctUntilChanged();
76
- _startWithNull = startWith(null);
77
- _distinctShare = pipe(this._distinctUntilChanged, shareReplay(1));
78
- _startWithNullDistinct = pipe(this._startWithNull, this._distinctUntilChanged);
79
- editingAndEnabled = this.editing.pipe(filter(cell => cell == null || !this.disabledCells.has(cell)), shareReplay(1));
80
- /** An observable that emits the row containing focus or an active edit. */
81
- editingOrFocused = combineLatest([
82
- this.editingAndEnabled.pipe(map(cell => closest(cell, ROW_SELECTOR)), this._startWithNull),
83
- this.focused.pipe(this._startWithNull),
84
- ]).pipe(map(([editingRow, focusedRow]) => focusedRow || editingRow), this._distinctUntilChanged, auditTime(FOCUS_DELAY), // Use audit to skip over blur events to the next focused element.
85
- this._distinctUntilChanged, shareReplay(1));
86
- /** Tracks rows that contain hover content with a reference count. */
87
- _rowsWithHoverContent = new WeakMap();
88
- /** The table cell that has an active edit lens (or null). */
89
- _currentlyEditing = null;
90
- /** The combined set of row hover content states organized by row. */
91
- _hoveredContentStateDistinct = combineLatest([
92
- this._getFirstRowWithHoverContent(),
93
- this._getLastRowWithHoverContent(),
94
- this.editingOrFocused,
95
- this.hovering.pipe(distinctUntilChanged(), audit(row => this.mouseMove.pipe(filter(mouseMoveRow => row === mouseMoveRow), this._startWithNull, debounceTime(MOUSE_EVENT_DELAY_MS))), this._startWithNullDistinct),
96
- ]).pipe(skip(1), // Skip the initial emission of [null, null, null, null].
97
- map(computeHoverContentState), distinctUntilChanged(areMapEntriesEqual),
98
- // Optimization: Enter the zone before shareReplay so that we trigger a single
99
- // ApplicationRef.tick for all row updates.
100
- this._enterZone(), shareReplay(1));
101
- _editingAndEnabledDistinct = this.editingAndEnabled.pipe(distinctUntilChanged(), this._enterZone(), shareReplay(1));
102
- // Optimization: Share row events observable with subsequent callers.
103
- // At startup, calls will be sequential by row.
104
- _lastSeenRow = null;
105
- _lastSeenRowHoverOrFocus = null;
106
- constructor() {
107
- this._editingAndEnabledDistinct.subscribe(cell => {
108
- this._currentlyEditing = cell;
109
- });
110
- }
111
- /**
112
- * Gets an Observable that emits true when the specified element's cell
113
- * is editing and false when not.
114
- */
115
- editingCell(element) {
116
- let cell = null;
117
- return this._editingAndEnabledDistinct.pipe(map(editCell => editCell === (cell || (cell = closest(element, CELL_SELECTOR)))), this._distinctUntilChanged);
118
- }
119
- /**
120
- * Stops editing for the specified cell. If the specified cell is not the current
121
- * edit cell, does nothing.
122
- */
123
- doneEditingCell(element) {
124
- const cell = closest(element, CELL_SELECTOR);
125
- if (this._currentlyEditing === cell) {
126
- this.editing.next(null);
127
- }
128
- }
129
- /** Sets the currently active EditRef. */
130
- setActiveEditRef(ref) {
131
- this._editRef = ref;
132
- }
133
- /** Unset the currently active EditRef, if the specified editRef is active. */
134
- unsetActiveEditRef(ref) {
135
- if (this._editRef !== ref) {
136
- return;
137
- }
138
- this._editRef = null;
139
- }
140
- /** Adds the specified table row to be tracked for first/last row comparisons. */
141
- registerRowWithHoverContent(row) {
142
- this._rowsWithHoverContent.set(row, (this._rowsWithHoverContent.get(row) || 0) + 1);
143
- }
144
- /**
145
- * Reference decrements and ultimately removes the specified table row from first/last row
146
- * comparisons.
147
- */
148
- deregisterRowWithHoverContent(row) {
149
- const refCount = this._rowsWithHoverContent.get(row) || 0;
150
- if (refCount <= 1) {
151
- this._rowsWithHoverContent.delete(row);
31
+ _ngZone = inject(NgZone);
32
+ editing = new Subject();
33
+ hovering = new Subject();
34
+ focused = new Subject();
35
+ allRows = new Subject();
36
+ mouseMove = new Subject();
37
+ disabledCells = new WeakMap();
38
+ get editRef() {
39
+ return this._editRef;
40
+ }
41
+ _editRef = null;
42
+ _distinctUntilChanged = distinctUntilChanged();
43
+ _startWithNull = startWith(null);
44
+ _distinctShare = pipe(this._distinctUntilChanged, shareReplay(1));
45
+ _startWithNullDistinct = pipe(this._startWithNull, this._distinctUntilChanged);
46
+ editingAndEnabled = this.editing.pipe(filter(cell => cell == null || !this.disabledCells.has(cell)), shareReplay(1));
47
+ editingOrFocused = combineLatest([this.editingAndEnabled.pipe(map(cell => closest(cell, ROW_SELECTOR)), this._startWithNull), this.focused.pipe(this._startWithNull)]).pipe(map(([editingRow, focusedRow]) => focusedRow || editingRow), this._distinctUntilChanged, auditTime(FOCUS_DELAY), this._distinctUntilChanged, shareReplay(1));
48
+ _rowsWithHoverContent = new WeakMap();
49
+ _currentlyEditing = null;
50
+ _hoveredContentStateDistinct = combineLatest([this._getFirstRowWithHoverContent(), this._getLastRowWithHoverContent(), this.editingOrFocused, this.hovering.pipe(distinctUntilChanged(), audit(row => this.mouseMove.pipe(filter(mouseMoveRow => row === mouseMoveRow), this._startWithNull, debounceTime(MOUSE_EVENT_DELAY_MS))), this._startWithNullDistinct)]).pipe(skip(1), map(computeHoverContentState), distinctUntilChanged(areMapEntriesEqual), this._enterZone(), shareReplay(1));
51
+ _editingAndEnabledDistinct = this.editingAndEnabled.pipe(distinctUntilChanged(), this._enterZone(), shareReplay(1));
52
+ _lastSeenRow = null;
53
+ _lastSeenRowHoverOrFocus = null;
54
+ constructor() {
55
+ this._editingAndEnabledDistinct.subscribe(cell => {
56
+ this._currentlyEditing = cell;
57
+ });
58
+ }
59
+ editingCell(element) {
60
+ let cell = null;
61
+ return this._editingAndEnabledDistinct.pipe(map(editCell => editCell === (cell || (cell = closest(element, CELL_SELECTOR)))), this._distinctUntilChanged);
62
+ }
63
+ doneEditingCell(element) {
64
+ const cell = closest(element, CELL_SELECTOR);
65
+ if (this._currentlyEditing === cell) {
66
+ this.editing.next(null);
67
+ }
68
+ }
69
+ setActiveEditRef(ref) {
70
+ this._editRef = ref;
71
+ }
72
+ unsetActiveEditRef(ref) {
73
+ if (this._editRef !== ref) {
74
+ return;
75
+ }
76
+ this._editRef = null;
77
+ }
78
+ registerRowWithHoverContent(row) {
79
+ this._rowsWithHoverContent.set(row, (this._rowsWithHoverContent.get(row) || 0) + 1);
80
+ }
81
+ deregisterRowWithHoverContent(row) {
82
+ const refCount = this._rowsWithHoverContent.get(row) || 0;
83
+ if (refCount <= 1) {
84
+ this._rowsWithHoverContent.delete(row);
85
+ } else {
86
+ this._rowsWithHoverContent.set(row, refCount - 1);
87
+ }
88
+ }
89
+ hoverOrFocusOnRow(row) {
90
+ if (row !== this._lastSeenRow) {
91
+ this._lastSeenRow = row;
92
+ this._lastSeenRowHoverOrFocus = this._hoveredContentStateDistinct.pipe(map(state => state.get(row) || HoverContentState.OFF), this._distinctShare);
93
+ }
94
+ return this._lastSeenRowHoverOrFocus;
95
+ }
96
+ _enterZone() {
97
+ return source => new Observable(observer => source.subscribe({
98
+ next: value => this._ngZone.run(() => observer.next(value)),
99
+ error: err => observer.error(err),
100
+ complete: () => observer.complete()
101
+ }));
102
+ }
103
+ _getFirstRowWithHoverContent() {
104
+ return this._mapAllRowsToSingleRow(rows => {
105
+ for (let i = 0, row; row = rows[i]; i++) {
106
+ if (this._rowsWithHoverContent.has(row)) {
107
+ return row;
152
108
  }
153
- else {
154
- this._rowsWithHoverContent.set(row, refCount - 1);
155
- }
156
- }
157
- /**
158
- * Gets an Observable that emits true when the specified element's row
159
- * contains the focused element or is being hovered over and false when not.
160
- * Hovering is defined as when the mouse has momentarily stopped moving over the cell.
161
- */
162
- hoverOrFocusOnRow(row) {
163
- if (row !== this._lastSeenRow) {
164
- this._lastSeenRow = row;
165
- this._lastSeenRowHoverOrFocus = this._hoveredContentStateDistinct.pipe(map(state => state.get(row) || HoverContentState.OFF), this._distinctShare);
109
+ }
110
+ return null;
111
+ });
112
+ }
113
+ _getLastRowWithHoverContent() {
114
+ return this._mapAllRowsToSingleRow(rows => {
115
+ for (let i = rows.length - 1, row; row = rows[i]; i--) {
116
+ if (this._rowsWithHoverContent.has(row)) {
117
+ return row;
166
118
  }
167
- return this._lastSeenRowHoverOrFocus;
168
- }
169
- /**
170
- * RxJS operator that enters the Angular zone, used to reduce boilerplate in
171
- * re-entering the zone for stream pipelines.
172
- */
173
- _enterZone() {
174
- return (source) => new Observable(observer => source.subscribe({
175
- next: value => this._ngZone.run(() => observer.next(value)),
176
- error: err => observer.error(err),
177
- complete: () => observer.complete(),
178
- }));
179
- }
180
- _getFirstRowWithHoverContent() {
181
- return this._mapAllRowsToSingleRow(rows => {
182
- for (let i = 0, row; (row = rows[i]); i++) {
183
- if (this._rowsWithHoverContent.has(row)) {
184
- return row;
185
- }
186
- }
187
- return null;
188
- });
189
- }
190
- _getLastRowWithHoverContent() {
191
- return this._mapAllRowsToSingleRow(rows => {
192
- for (let i = rows.length - 1, row; (row = rows[i]); i--) {
193
- if (this._rowsWithHoverContent.has(row)) {
194
- return row;
195
- }
196
- }
197
- return null;
198
- });
199
- }
200
- _mapAllRowsToSingleRow(mapper) {
201
- return this.allRows.pipe(map(mapper), this._startWithNullDistinct);
202
- }
203
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: EditEventDispatcher, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
204
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: EditEventDispatcher });
119
+ }
120
+ return null;
121
+ });
122
+ }
123
+ _mapAllRowsToSingleRow(mapper) {
124
+ return this.allRows.pipe(map(mapper), this._startWithNullDistinct);
125
+ }
126
+ static ɵfac = i0.ɵɵngDeclareFactory({
127
+ minVersion: "12.0.0",
128
+ version: "20.2.0-next.2",
129
+ ngImport: i0,
130
+ type: EditEventDispatcher,
131
+ deps: [],
132
+ target: i0.ɵɵFactoryTarget.Injectable
133
+ });
134
+ static ɵprov = i0.ɵɵngDeclareInjectable({
135
+ minVersion: "12.0.0",
136
+ version: "20.2.0-next.2",
137
+ ngImport: i0,
138
+ type: EditEventDispatcher
139
+ });
205
140
  }
206
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: EditEventDispatcher, decorators: [{
207
- type: Injectable
208
- }], ctorParameters: () => [] });
209
- function computeHoverContentState([firstRow, lastRow, activeRow, hoverRow,]) {
210
- const hoverContentState = new Map();
211
- // Add focusable rows.
212
- for (const focussableRow of [
213
- firstRow,
214
- lastRow,
215
- activeRow && activeRow.previousElementSibling,
216
- activeRow && activeRow.nextElementSibling,
217
- ]) {
218
- if (focussableRow) {
219
- hoverContentState.set(focussableRow, HoverContentState.FOCUSABLE);
220
- }
221
- }
222
- // Add/overwrite with fully visible rows.
223
- for (const onRow of [activeRow, hoverRow]) {
224
- if (onRow) {
225
- hoverContentState.set(onRow, HoverContentState.ON);
226
- }
227
- }
228
- return hoverContentState;
141
+ i0.ɵɵngDeclareClassMetadata({
142
+ minVersion: "12.0.0",
143
+ version: "20.2.0-next.2",
144
+ ngImport: i0,
145
+ type: EditEventDispatcher,
146
+ decorators: [{
147
+ type: Injectable
148
+ }],
149
+ ctorParameters: () => []
150
+ });
151
+ function computeHoverContentState([firstRow, lastRow, activeRow, hoverRow]) {
152
+ const hoverContentState = new Map();
153
+ for (const focussableRow of [firstRow, lastRow, activeRow && activeRow.previousElementSibling, activeRow && activeRow.nextElementSibling]) {
154
+ if (focussableRow) {
155
+ hoverContentState.set(focussableRow, HoverContentState.FOCUSABLE);
156
+ }
157
+ }
158
+ for (const onRow of [activeRow, hoverRow]) {
159
+ if (onRow) {
160
+ hoverContentState.set(onRow, HoverContentState.ON);
161
+ }
162
+ }
163
+ return hoverContentState;
229
164
  }
230
165
  function areMapEntriesEqual(a, b) {
231
- if (a.size !== b.size) {
232
- return false;
233
- }
234
- // TODO: use Map.prototype.entries once we're off IE11.
235
- for (const aKey of Array.from(a.keys())) {
236
- if (b.get(aKey) !== a.get(aKey)) {
237
- return false;
238
- }
166
+ if (a.size !== b.size) {
167
+ return false;
168
+ }
169
+ for (const aKey of Array.from(a.keys())) {
170
+ if (b.get(aKey) !== a.get(aKey)) {
171
+ return false;
239
172
  }
240
- return true;
173
+ }
174
+ return true;
241
175
  }
242
176
 
243
- /**
244
- * Used for communication between the form within the edit lens and the
245
- * table that launched it. Provided by CdkEditControl within the lens.
246
- */
247
177
  class EditRef {
248
- _form = inject(ControlContainer, { self: true });
249
- _editEventDispatcher = inject(EditEventDispatcher);
250
- /** Emits the final value of this edit instance before closing. */
251
- _finalValueSubject = new Subject();
252
- finalValue = this._finalValueSubject;
253
- /** Emits when the user tabs out of this edit lens before closing. */
254
- _blurredSubject = new Subject();
255
- blurred = this._blurredSubject;
256
- /** The value to set the form back to on revert. */
257
- _revertFormValue;
258
- _injector = inject(Injector);
259
- constructor() {
260
- this._editEventDispatcher.setActiveEditRef(this);
261
- }
262
- /**
263
- * Called by the host directive's OnInit hook. Reads the initial state of the
264
- * form and overrides it with persisted state from previous openings, if
265
- * applicable.
266
- */
267
- init(previousFormValue) {
268
- // Wait for the next render before caching the initial value.
269
- // This ensures that all form controls have been initialized.
270
- afterNextRender(() => {
271
- this.updateRevertValue();
272
- if (previousFormValue) {
273
- this.reset(previousFormValue);
274
- }
275
- }, { injector: this._injector });
276
- }
277
- ngOnDestroy() {
278
- this._editEventDispatcher.unsetActiveEditRef(this);
279
- this._finalValueSubject.next(this._form.value);
280
- this._finalValueSubject.complete();
281
- }
282
- /** Whether the attached form is in a valid state. */
283
- isValid() {
284
- return this._form.valid;
285
- }
286
- /** Set the form's current value as what it will be set to on revert/reset. */
287
- updateRevertValue() {
288
- this._revertFormValue = this._form.value;
289
- }
290
- /** Tells the table to close the edit popup. */
291
- close() {
292
- this._editEventDispatcher.editing.next(null);
293
- }
294
- /** Notifies the active edit that the user has moved focus out of the lens. */
295
- blur() {
296
- this._blurredSubject.next();
297
- }
298
- /**
299
- * Resets the form value to the specified value or the previously set
300
- * revert value.
301
- */
302
- reset(value) {
303
- this._form.reset(value || this._revertFormValue);
304
- }
305
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: EditRef, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
306
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: EditRef });
178
+ _form = inject(ControlContainer, {
179
+ self: true
180
+ });
181
+ _editEventDispatcher = inject(EditEventDispatcher);
182
+ _finalValueSubject = new Subject();
183
+ finalValue = this._finalValueSubject;
184
+ _blurredSubject = new Subject();
185
+ blurred = this._blurredSubject;
186
+ _revertFormValue;
187
+ _injector = inject(Injector);
188
+ constructor() {
189
+ this._editEventDispatcher.setActiveEditRef(this);
190
+ }
191
+ init(previousFormValue) {
192
+ afterNextRender(() => {
193
+ this.updateRevertValue();
194
+ if (previousFormValue) {
195
+ this.reset(previousFormValue);
196
+ }
197
+ }, {
198
+ injector: this._injector
199
+ });
200
+ }
201
+ ngOnDestroy() {
202
+ this._editEventDispatcher.unsetActiveEditRef(this);
203
+ this._finalValueSubject.next(this._form.value);
204
+ this._finalValueSubject.complete();
205
+ }
206
+ isValid() {
207
+ return this._form.valid;
208
+ }
209
+ updateRevertValue() {
210
+ this._revertFormValue = this._form.value;
211
+ }
212
+ close() {
213
+ this._editEventDispatcher.editing.next(null);
214
+ }
215
+ blur() {
216
+ this._blurredSubject.next();
217
+ }
218
+ reset(value) {
219
+ this._form.reset(value || this._revertFormValue);
220
+ }
221
+ static ɵfac = i0.ɵɵngDeclareFactory({
222
+ minVersion: "12.0.0",
223
+ version: "20.2.0-next.2",
224
+ ngImport: i0,
225
+ type: EditRef,
226
+ deps: [],
227
+ target: i0.ɵɵFactoryTarget.Injectable
228
+ });
229
+ static ɵprov = i0.ɵɵngDeclareInjectable({
230
+ minVersion: "12.0.0",
231
+ version: "20.2.0-next.2",
232
+ ngImport: i0,
233
+ type: EditRef
234
+ });
307
235
  }
308
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: EditRef, decorators: [{
309
- type: Injectable
310
- }], ctorParameters: () => [] });
236
+ i0.ɵɵngDeclareClassMetadata({
237
+ minVersion: "12.0.0",
238
+ version: "20.2.0-next.2",
239
+ ngImport: i0,
240
+ type: EditRef,
241
+ decorators: [{
242
+ type: Injectable
243
+ }],
244
+ ctorParameters: () => []
245
+ });
311
246
 
312
- /**
313
- * Service responsible for moving cell focus around in response to keyboard events.
314
- * May be overridden to customize the keyboard behavior of popover edit.
315
- */
316
247
  class FocusDispatcher {
317
- directionality = inject(Directionality);
318
- /** Observes keydown events triggered from the table. */
319
- keyObserver;
320
- constructor() {
321
- this.keyObserver = { next: event => this.handleKeyboardEvent(event) };
322
- }
323
- /**
324
- * Moves focus to earlier or later cells (in dom order) by offset cells relative to
325
- * currentCell.
326
- */
327
- moveFocusHorizontally(currentCell, offset) {
328
- const cells = Array.from(closest(currentCell, TABLE_SELECTOR).querySelectorAll(EDITABLE_CELL_SELECTOR));
329
- const currentIndex = cells.indexOf(currentCell);
330
- const newIndex = currentIndex + offset;
331
- if (cells[newIndex]) {
332
- cells[newIndex].focus();
333
- }
334
- }
335
- /** Moves focus to up or down by row by offset cells relative to currentCell. */
336
- moveFocusVertically(currentCell, offset) {
337
- const currentRow = closest(currentCell, ROW_SELECTOR);
338
- const rows = Array.from(closest(currentRow, TABLE_SELECTOR).querySelectorAll(ROW_SELECTOR));
339
- const currentRowIndex = rows.indexOf(currentRow);
340
- const currentIndexWithinRow = Array.from(currentRow.querySelectorAll(EDITABLE_CELL_SELECTOR)).indexOf(currentCell);
341
- let newRowIndex = currentRowIndex + offset;
342
- while (rows[newRowIndex]?.matches(SKIP_ROW_FOCUS_SELECTOR)) {
343
- newRowIndex = newRowIndex + (offset > 0 ? 1 : -1);
344
- }
345
- if (rows[newRowIndex]) {
346
- const rowToFocus = Array.from(rows[newRowIndex].querySelectorAll(EDITABLE_CELL_SELECTOR));
347
- if (rowToFocus[currentIndexWithinRow]) {
348
- rowToFocus[currentIndexWithinRow].focus();
349
- }
350
- }
351
- }
352
- /** Translates arrow keydown events into focus move operations. */
353
- handleKeyboardEvent(event) {
354
- const cell = closest(event.target, EDITABLE_CELL_SELECTOR);
355
- if (!cell) {
356
- return;
357
- }
358
- switch (event.keyCode) {
359
- case UP_ARROW:
360
- this.moveFocusVertically(cell, -1);
361
- break;
362
- case DOWN_ARROW:
363
- this.moveFocusVertically(cell, 1);
364
- break;
365
- case LEFT_ARROW:
366
- this.moveFocusHorizontally(cell, this.directionality.value === 'ltr' ? -1 : 1);
367
- break;
368
- case RIGHT_ARROW:
369
- this.moveFocusHorizontally(cell, this.directionality.value === 'ltr' ? 1 : -1);
370
- break;
371
- default:
372
- // If the keyboard event is not handled, return now so that we don't `preventDefault`.
373
- return;
374
- }
375
- event.preventDefault();
376
- }
377
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: FocusDispatcher, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
378
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: FocusDispatcher, providedIn: 'root' });
248
+ directionality = inject(Directionality);
249
+ keyObserver;
250
+ constructor() {
251
+ this.keyObserver = {
252
+ next: event => this.handleKeyboardEvent(event)
253
+ };
254
+ }
255
+ moveFocusHorizontally(currentCell, offset) {
256
+ const cells = Array.from(closest(currentCell, TABLE_SELECTOR).querySelectorAll(EDITABLE_CELL_SELECTOR));
257
+ const currentIndex = cells.indexOf(currentCell);
258
+ const newIndex = currentIndex + offset;
259
+ if (cells[newIndex]) {
260
+ cells[newIndex].focus();
261
+ }
262
+ }
263
+ moveFocusVertically(currentCell, offset) {
264
+ const currentRow = closest(currentCell, ROW_SELECTOR);
265
+ const rows = Array.from(closest(currentRow, TABLE_SELECTOR).querySelectorAll(ROW_SELECTOR));
266
+ const currentRowIndex = rows.indexOf(currentRow);
267
+ const currentIndexWithinRow = Array.from(currentRow.querySelectorAll(EDITABLE_CELL_SELECTOR)).indexOf(currentCell);
268
+ let newRowIndex = currentRowIndex + offset;
269
+ while (rows[newRowIndex]?.matches(SKIP_ROW_FOCUS_SELECTOR)) {
270
+ newRowIndex = newRowIndex + (offset > 0 ? 1 : -1);
271
+ }
272
+ if (rows[newRowIndex]) {
273
+ const rowToFocus = Array.from(rows[newRowIndex].querySelectorAll(EDITABLE_CELL_SELECTOR));
274
+ if (rowToFocus[currentIndexWithinRow]) {
275
+ rowToFocus[currentIndexWithinRow].focus();
276
+ }
277
+ }
278
+ }
279
+ handleKeyboardEvent(event) {
280
+ const cell = closest(event.target, EDITABLE_CELL_SELECTOR);
281
+ if (!cell) {
282
+ return;
283
+ }
284
+ switch (event.keyCode) {
285
+ case UP_ARROW:
286
+ this.moveFocusVertically(cell, -1);
287
+ break;
288
+ case DOWN_ARROW:
289
+ this.moveFocusVertically(cell, 1);
290
+ break;
291
+ case LEFT_ARROW:
292
+ this.moveFocusHorizontally(cell, this.directionality.value === 'ltr' ? -1 : 1);
293
+ break;
294
+ case RIGHT_ARROW:
295
+ this.moveFocusHorizontally(cell, this.directionality.value === 'ltr' ? 1 : -1);
296
+ break;
297
+ default:
298
+ return;
299
+ }
300
+ event.preventDefault();
301
+ }
302
+ static ɵfac = i0.ɵɵngDeclareFactory({
303
+ minVersion: "12.0.0",
304
+ version: "20.2.0-next.2",
305
+ ngImport: i0,
306
+ type: FocusDispatcher,
307
+ deps: [],
308
+ target: i0.ɵɵFactoryTarget.Injectable
309
+ });
310
+ static ɵprov = i0.ɵɵngDeclareInjectable({
311
+ minVersion: "12.0.0",
312
+ version: "20.2.0-next.2",
313
+ ngImport: i0,
314
+ type: FocusDispatcher,
315
+ providedIn: 'root'
316
+ });
379
317
  }
380
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: FocusDispatcher, decorators: [{
381
- type: Injectable,
382
- args: [{ providedIn: 'root' }]
383
- }], ctorParameters: () => [] });
318
+ i0.ɵɵngDeclareClassMetadata({
319
+ minVersion: "12.0.0",
320
+ version: "20.2.0-next.2",
321
+ ngImport: i0,
322
+ type: FocusDispatcher,
323
+ decorators: [{
324
+ type: Injectable,
325
+ args: [{
326
+ providedIn: 'root'
327
+ }]
328
+ }],
329
+ ctorParameters: () => []
330
+ });
384
331
 
385
- /**
386
- * A convenience class for preserving unsaved form state while an edit lens is closed.
387
- *
388
- * Example usage:
389
- * class MyComponent {
390
- * readonly nameEditValues = new FormValueContainer&lt;Item, {name: string}&gt;();
391
- * }
392
- *
393
- * &lt;form cdkEditControl [(cdkEditControlPreservedFormValue)]="nameEditValues.for(item).value"&gt;
394
- */
395
332
  class FormValueContainer {
396
- _formValues = new WeakMap();
397
- for(key) {
398
- const _formValues = this._formValues;
399
- let entry = _formValues.get(key);
400
- if (!entry) {
401
- // Expose entry as an object so that we can [(two-way)] bind to its value member
402
- entry = {};
403
- _formValues.set(key, entry);
404
- }
405
- return entry;
406
- }
333
+ _formValues = new WeakMap();
334
+ for(key) {
335
+ const _formValues = this._formValues;
336
+ let entry = _formValues.get(key);
337
+ if (!entry) {
338
+ entry = {};
339
+ _formValues.set(key, entry);
340
+ }
341
+ return entry;
342
+ }
407
343
  }
408
344
 
409
- /**
410
- * A directive that attaches to a form within the edit lens.
411
- * It coordinates the form state with the table-wide edit system and handles
412
- * closing the edit lens when the form is submitted or the user clicks
413
- * out.
414
- */
415
345
  class CdkEditControl {
416
- elementRef = inject(ElementRef);
417
- editRef = inject(EditRef);
418
- destroyed = new Subject();
419
- /**
420
- * Specifies what should happen when the user clicks outside of the edit lens.
421
- * The default behavior is to close the lens without submitting the form.
422
- */
423
- clickOutBehavior = 'close';
424
- /**
425
- * A two-way binding for storing unsubmitted form state. If not provided
426
- * then form state will be discarded on close. The PeristBy directive is offered
427
- * as a convenient shortcut for these bindings.
428
- */
429
- preservedFormValue;
430
- preservedFormValueChange = new EventEmitter();
431
- /**
432
- * Determines whether the lens will close on form submit if the form is not in a valid
433
- * state. By default the lens will remain open.
434
- */
435
- ignoreSubmitUnlessValid = true;
436
- ngOnInit() {
437
- this.editRef.init(this.preservedFormValue);
438
- this.editRef.finalValue.subscribe(this.preservedFormValueChange);
439
- this.editRef.blurred.subscribe(() => this._handleBlur());
440
- }
441
- ngOnDestroy() {
442
- this.destroyed.next();
443
- this.destroyed.complete();
444
- }
445
- /**
446
- * Called when the form submits. If ignoreSubmitUnlessValid is true, checks
447
- * the form for validity before proceeding.
448
- * Updates the revert state with the latest submitted value then closes the edit.
449
- */
450
- handleFormSubmit() {
451
- if (this.ignoreSubmitUnlessValid && !this.editRef.isValid()) {
452
- return;
453
- }
454
- this.editRef.updateRevertValue();
346
+ elementRef = inject(ElementRef);
347
+ editRef = inject(EditRef);
348
+ destroyed = new Subject();
349
+ clickOutBehavior = 'close';
350
+ preservedFormValue;
351
+ preservedFormValueChange = new EventEmitter();
352
+ ignoreSubmitUnlessValid = true;
353
+ ngOnInit() {
354
+ this.editRef.init(this.preservedFormValue);
355
+ this.editRef.finalValue.subscribe(this.preservedFormValueChange);
356
+ this.editRef.blurred.subscribe(() => this._handleBlur());
357
+ }
358
+ ngOnDestroy() {
359
+ this.destroyed.next();
360
+ this.destroyed.complete();
361
+ }
362
+ handleFormSubmit() {
363
+ if (this.ignoreSubmitUnlessValid && !this.editRef.isValid()) {
364
+ return;
365
+ }
366
+ this.editRef.updateRevertValue();
367
+ this.editRef.close();
368
+ }
369
+ close() {
370
+ this.editRef.close();
371
+ }
372
+ handlePossibleClickOut(evt) {
373
+ if (closest(evt.target, EDIT_PANE_SELECTOR)) {
374
+ return;
375
+ }
376
+ switch (this.clickOutBehavior) {
377
+ case 'submit':
378
+ this._triggerFormSubmit();
455
379
  this.editRef.close();
456
- }
457
- /** Called on Escape keyup. Closes the edit. */
458
- close() {
459
- // todo - allow this behavior to be customized as well, such as calling
460
- // reset before close
380
+ break;
381
+ case 'close':
461
382
  this.editRef.close();
462
- }
463
- /**
464
- * Called on click anywhere in the document.
465
- * If the click was outside of the lens, trigger the specified click out behavior.
466
- */
467
- handlePossibleClickOut(evt) {
468
- if (closest(evt.target, EDIT_PANE_SELECTOR)) {
469
- return;
470
- }
471
- switch (this.clickOutBehavior) {
472
- case 'submit':
473
- // Manually cause the form to submit before closing.
474
- this._triggerFormSubmit();
475
- this.editRef.close();
476
- break;
477
- case 'close':
478
- this.editRef.close();
479
- break;
480
- }
481
- }
482
- _handleKeydown(event) {
483
- if (event.key === 'Escape' && !hasModifierKey(event)) {
484
- this.close();
485
- event.preventDefault();
486
- }
487
- }
488
- /** Triggers submit on tab out if clickOutBehavior is 'submit'. */
489
- _handleBlur() {
490
- if (this.clickOutBehavior === 'submit') {
491
- // Manually cause the form to submit before closing.
492
- this._triggerFormSubmit();
493
- }
494
- }
495
- _triggerFormSubmit() {
496
- this.elementRef.nativeElement.dispatchEvent(new Event('submit'));
497
- }
498
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: CdkEditControl, deps: [], target: i0.ɵɵFactoryTarget.Directive });
499
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: CdkEditControl, isStandalone: true, selector: "form[cdkEditControl]", inputs: { clickOutBehavior: ["cdkEditControlClickOutBehavior", "clickOutBehavior"], preservedFormValue: ["cdkEditControlPreservedFormValue", "preservedFormValue"], ignoreSubmitUnlessValid: ["cdkEditControlIgnoreSubmitUnlessValid", "ignoreSubmitUnlessValid"] }, outputs: { preservedFormValueChange: "cdkEditControlPreservedFormValueChange" }, host: { listeners: { "ngSubmit": "handleFormSubmit()", "document:click": "handlePossibleClickOut($event)", "keydown": "_handleKeydown($event)" } }, providers: [EditRef], ngImport: i0 });
383
+ break;
384
+ }
385
+ }
386
+ _handleKeydown(event) {
387
+ if (event.key === 'Escape' && !hasModifierKey(event)) {
388
+ this.close();
389
+ event.preventDefault();
390
+ }
391
+ }
392
+ _handleBlur() {
393
+ if (this.clickOutBehavior === 'submit') {
394
+ this._triggerFormSubmit();
395
+ }
396
+ }
397
+ _triggerFormSubmit() {
398
+ this.elementRef.nativeElement.dispatchEvent(new Event('submit'));
399
+ }
400
+ static ɵfac = i0.ɵɵngDeclareFactory({
401
+ minVersion: "12.0.0",
402
+ version: "20.2.0-next.2",
403
+ ngImport: i0,
404
+ type: CdkEditControl,
405
+ deps: [],
406
+ target: i0.ɵɵFactoryTarget.Directive
407
+ });
408
+ static ɵdir = i0.ɵɵngDeclareDirective({
409
+ minVersion: "14.0.0",
410
+ version: "20.2.0-next.2",
411
+ type: CdkEditControl,
412
+ isStandalone: true,
413
+ selector: "form[cdkEditControl]",
414
+ inputs: {
415
+ clickOutBehavior: ["cdkEditControlClickOutBehavior", "clickOutBehavior"],
416
+ preservedFormValue: ["cdkEditControlPreservedFormValue", "preservedFormValue"],
417
+ ignoreSubmitUnlessValid: ["cdkEditControlIgnoreSubmitUnlessValid", "ignoreSubmitUnlessValid"]
418
+ },
419
+ outputs: {
420
+ preservedFormValueChange: "cdkEditControlPreservedFormValueChange"
421
+ },
422
+ host: {
423
+ listeners: {
424
+ "ngSubmit": "handleFormSubmit()",
425
+ "document:click": "handlePossibleClickOut($event)",
426
+ "keydown": "_handleKeydown($event)"
427
+ }
428
+ },
429
+ providers: [EditRef],
430
+ ngImport: i0
431
+ });
500
432
  }
501
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: CdkEditControl, decorators: [{
502
- type: Directive,
503
- args: [{
504
- selector: 'form[cdkEditControl]',
505
- inputs: [
506
- { name: 'clickOutBehavior', alias: 'cdkEditControlClickOutBehavior' },
507
- { name: 'preservedFormValue', alias: 'cdkEditControlPreservedFormValue' },
508
- { name: 'ignoreSubmitUnlessValid', alias: 'cdkEditControlIgnoreSubmitUnlessValid' },
509
- ],
510
- outputs: ['preservedFormValueChange: cdkEditControlPreservedFormValueChange'],
511
- providers: [EditRef],
512
- host: {
513
- '(ngSubmit)': 'handleFormSubmit()',
514
- '(document:click)': 'handlePossibleClickOut($event)',
515
- '(keydown)': '_handleKeydown($event)',
516
- },
517
- }]
518
- }] });
519
- /** Reverts the form to its initial or previously submitted state on click. */
433
+ i0.ɵɵngDeclareClassMetadata({
434
+ minVersion: "12.0.0",
435
+ version: "20.2.0-next.2",
436
+ ngImport: i0,
437
+ type: CdkEditControl,
438
+ decorators: [{
439
+ type: Directive,
440
+ args: [{
441
+ selector: 'form[cdkEditControl]',
442
+ inputs: [{
443
+ name: 'clickOutBehavior',
444
+ alias: 'cdkEditControlClickOutBehavior'
445
+ }, {
446
+ name: 'preservedFormValue',
447
+ alias: 'cdkEditControlPreservedFormValue'
448
+ }, {
449
+ name: 'ignoreSubmitUnlessValid',
450
+ alias: 'cdkEditControlIgnoreSubmitUnlessValid'
451
+ }],
452
+ outputs: ['preservedFormValueChange: cdkEditControlPreservedFormValueChange'],
453
+ providers: [EditRef],
454
+ host: {
455
+ '(ngSubmit)': 'handleFormSubmit()',
456
+ '(document:click)': 'handlePossibleClickOut($event)',
457
+ '(keydown)': '_handleKeydown($event)'
458
+ }
459
+ }]
460
+ }]
461
+ });
520
462
  class CdkEditRevert {
521
- editRef = inject(EditRef);
522
- /** Type of the button. Defaults to `button` to avoid accident form submits. */
523
- type = 'button';
524
- revertEdit() {
525
- this.editRef.reset();
526
- }
527
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: CdkEditRevert, deps: [], target: i0.ɵɵFactoryTarget.Directive });
528
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: CdkEditRevert, isStandalone: true, selector: "button[cdkEditRevert]", inputs: { type: "type" }, host: { attributes: { "type": "button" }, listeners: { "click": "revertEdit()" } }, ngImport: i0 });
463
+ editRef = inject(EditRef);
464
+ type = 'button';
465
+ revertEdit() {
466
+ this.editRef.reset();
467
+ }
468
+ static ɵfac = i0.ɵɵngDeclareFactory({
469
+ minVersion: "12.0.0",
470
+ version: "20.2.0-next.2",
471
+ ngImport: i0,
472
+ type: CdkEditRevert,
473
+ deps: [],
474
+ target: i0.ɵɵFactoryTarget.Directive
475
+ });
476
+ static ɵdir = i0.ɵɵngDeclareDirective({
477
+ minVersion: "14.0.0",
478
+ version: "20.2.0-next.2",
479
+ type: CdkEditRevert,
480
+ isStandalone: true,
481
+ selector: "button[cdkEditRevert]",
482
+ inputs: {
483
+ type: "type"
484
+ },
485
+ host: {
486
+ attributes: {
487
+ "type": "button"
488
+ },
489
+ listeners: {
490
+ "click": "revertEdit()"
491
+ }
492
+ },
493
+ ngImport: i0
494
+ });
529
495
  }
530
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: CdkEditRevert, decorators: [{
531
- type: Directive,
532
- args: [{
533
- selector: 'button[cdkEditRevert]',
534
- host: {
535
- 'type': 'button',
536
- '(click)': 'revertEdit()',
537
- },
538
- }]
539
- }], propDecorators: { type: [{
540
- type: Input
541
- }] } });
542
- /** Closes the lens on click. */
496
+ i0.ɵɵngDeclareClassMetadata({
497
+ minVersion: "12.0.0",
498
+ version: "20.2.0-next.2",
499
+ ngImport: i0,
500
+ type: CdkEditRevert,
501
+ decorators: [{
502
+ type: Directive,
503
+ args: [{
504
+ selector: 'button[cdkEditRevert]',
505
+ host: {
506
+ 'type': 'button',
507
+ '(click)': 'revertEdit()'
508
+ }
509
+ }]
510
+ }],
511
+ propDecorators: {
512
+ type: [{
513
+ type: Input
514
+ }]
515
+ }
516
+ });
543
517
  class CdkEditClose {
544
- elementRef = inject(ElementRef);
545
- editRef = inject(EditRef);
546
- constructor() {
547
- const nativeElement = this.elementRef.nativeElement;
548
- // Prevent accidental form submits.
549
- if (nativeElement.nodeName === 'BUTTON' && !nativeElement.getAttribute('type')) {
550
- nativeElement.setAttribute('type', 'button');
551
- }
552
- }
553
- closeEdit() {
554
- // Note that we use `click` here, rather than a keyboard event, because some screen readers
555
- // will emit a fake click event instead of an enter keyboard event on buttons. For the keyboard
556
- // events we use `keydown`, rather than `keyup`, because we use `keydown` to open the overlay
557
- // as well. If we were to use `keyup`, the user could end up opening and closing within
558
- // the same event sequence if focus was moved quickly.
559
- this.editRef.close();
560
- }
561
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: CdkEditClose, deps: [], target: i0.ɵɵFactoryTarget.Directive });
562
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: CdkEditClose, isStandalone: true, selector: "[cdkEditClose]", host: { listeners: { "click": "closeEdit()", "keydown.enter": "closeEdit()", "keydown.space": "closeEdit()" } }, ngImport: i0 });
518
+ elementRef = inject(ElementRef);
519
+ editRef = inject(EditRef);
520
+ constructor() {
521
+ const nativeElement = this.elementRef.nativeElement;
522
+ if (nativeElement.nodeName === 'BUTTON' && !nativeElement.getAttribute('type')) {
523
+ nativeElement.setAttribute('type', 'button');
524
+ }
525
+ }
526
+ closeEdit() {
527
+ this.editRef.close();
528
+ }
529
+ static ɵfac = i0.ɵɵngDeclareFactory({
530
+ minVersion: "12.0.0",
531
+ version: "20.2.0-next.2",
532
+ ngImport: i0,
533
+ type: CdkEditClose,
534
+ deps: [],
535
+ target: i0.ɵɵFactoryTarget.Directive
536
+ });
537
+ static ɵdir = i0.ɵɵngDeclareDirective({
538
+ minVersion: "14.0.0",
539
+ version: "20.2.0-next.2",
540
+ type: CdkEditClose,
541
+ isStandalone: true,
542
+ selector: "[cdkEditClose]",
543
+ host: {
544
+ listeners: {
545
+ "click": "closeEdit()",
546
+ "keydown.enter": "closeEdit()",
547
+ "keydown.space": "closeEdit()"
548
+ }
549
+ },
550
+ ngImport: i0
551
+ });
563
552
  }
564
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: CdkEditClose, decorators: [{
565
- type: Directive,
566
- args: [{
567
- selector: '[cdkEditClose]',
568
- host: {
569
- '(click)': 'closeEdit()',
570
- '(keydown.enter)': 'closeEdit()',
571
- '(keydown.space)': 'closeEdit()',
572
- },
573
- }]
574
- }], ctorParameters: () => [] });
553
+ i0.ɵɵngDeclareClassMetadata({
554
+ minVersion: "12.0.0",
555
+ version: "20.2.0-next.2",
556
+ ngImport: i0,
557
+ type: CdkEditClose,
558
+ decorators: [{
559
+ type: Directive,
560
+ args: [{
561
+ selector: '[cdkEditClose]',
562
+ host: {
563
+ '(click)': 'closeEdit()',
564
+ '(keydown.enter)': 'closeEdit()',
565
+ '(keydown.space)': 'closeEdit()'
566
+ }
567
+ }]
568
+ }],
569
+ ctorParameters: () => []
570
+ });
575
571
 
576
- /**
577
- * Optimization
578
- * Collects multiple Injectables into a singleton shared across the table. By reducing the
579
- * number of services injected into each CdkPopoverEdit, this saves about 0.023ms of cpu time
580
- * and 56 bytes of memory per instance.
581
- */
582
572
  class EditServices {
583
- directionality = inject(Directionality);
584
- editEventDispatcher = inject(EditEventDispatcher);
585
- focusDispatcher = inject(FocusDispatcher);
586
- focusTrapFactory = inject(FocusTrapFactory);
587
- ngZone = inject(NgZone);
588
- scrollDispatcher = inject(ScrollDispatcher);
589
- viewportRuler = inject(ViewportRuler);
590
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: EditServices, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
591
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: EditServices });
573
+ directionality = inject(Directionality);
574
+ editEventDispatcher = inject(EditEventDispatcher);
575
+ focusDispatcher = inject(FocusDispatcher);
576
+ focusTrapFactory = inject(FocusTrapFactory);
577
+ ngZone = inject(NgZone);
578
+ scrollDispatcher = inject(ScrollDispatcher);
579
+ viewportRuler = inject(ViewportRuler);
580
+ static ɵfac = i0.ɵɵngDeclareFactory({
581
+ minVersion: "12.0.0",
582
+ version: "20.2.0-next.2",
583
+ ngImport: i0,
584
+ type: EditServices,
585
+ deps: [],
586
+ target: i0.ɵɵFactoryTarget.Injectable
587
+ });
588
+ static ɵprov = i0.ɵɵngDeclareInjectable({
589
+ minVersion: "12.0.0",
590
+ version: "20.2.0-next.2",
591
+ ngImport: i0,
592
+ type: EditServices
593
+ });
592
594
  }
593
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: EditServices, decorators: [{
594
- type: Injectable
595
- }] });
595
+ i0.ɵɵngDeclareClassMetadata({
596
+ minVersion: "12.0.0",
597
+ version: "20.2.0-next.2",
598
+ ngImport: i0,
599
+ type: EditServices,
600
+ decorators: [{
601
+ type: Injectable
602
+ }]
603
+ });
596
604
 
597
- /** Value indicating whether focus left the target area before or after the enclosed elements. */
598
605
  var FocusEscapeNotifierDirection;
599
606
  (function (FocusEscapeNotifierDirection) {
600
- FocusEscapeNotifierDirection[FocusEscapeNotifierDirection["START"] = 0] = "START";
601
- FocusEscapeNotifierDirection[FocusEscapeNotifierDirection["END"] = 1] = "END";
607
+ FocusEscapeNotifierDirection[FocusEscapeNotifierDirection["START"] = 0] = "START";
608
+ FocusEscapeNotifierDirection[FocusEscapeNotifierDirection["END"] = 1] = "END";
602
609
  })(FocusEscapeNotifierDirection || (FocusEscapeNotifierDirection = {}));
603
- /**
604
- * Like FocusTrap, but rather than trapping focus within a dom region, notifies subscribers when
605
- * focus leaves the region.
606
- */
607
610
  class FocusEscapeNotifier extends FocusTrap {
608
- _escapeSubject = new Subject();
609
- constructor(element, checker, ngZone, document) {
610
- super(element, checker, ngZone, document, true /* deferAnchors */);
611
- // The focus trap adds "anchors" at the beginning and end of a trapped region that redirect
612
- // focus. We override that redirect behavior here with simply emitting on a stream.
613
- this.startAnchorListener = () => {
614
- this._escapeSubject.next(FocusEscapeNotifierDirection.START);
615
- return true;
616
- };
617
- this.endAnchorListener = () => {
618
- this._escapeSubject.next(FocusEscapeNotifierDirection.END);
619
- return true;
620
- };
621
- this.attachAnchors();
622
- }
623
- escapes() {
624
- return this._escapeSubject;
625
- }
611
+ _escapeSubject = new Subject();
612
+ constructor(element, checker, ngZone, document) {
613
+ super(element, checker, ngZone, document, true);
614
+ this.startAnchorListener = () => {
615
+ this._escapeSubject.next(FocusEscapeNotifierDirection.START);
616
+ return true;
617
+ };
618
+ this.endAnchorListener = () => {
619
+ this._escapeSubject.next(FocusEscapeNotifierDirection.END);
620
+ return true;
621
+ };
622
+ this.attachAnchors();
623
+ }
624
+ escapes() {
625
+ return this._escapeSubject;
626
+ }
626
627
  }
627
- /** Factory that allows easy instantiation of focus escape notifiers. */
628
628
  class FocusEscapeNotifierFactory {
629
- _checker = inject(InteractivityChecker);
630
- _ngZone = inject(NgZone);
631
- _document = inject(DOCUMENT);
632
- /**
633
- * Creates a focus escape notifier region around the given element.
634
- * @param element The element around which focus will be monitored.
635
- * @returns The created focus escape notifier instance.
636
- */
637
- create(element) {
638
- return new FocusEscapeNotifier(element, this._checker, this._ngZone, this._document);
639
- }
640
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: FocusEscapeNotifierFactory, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
641
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: FocusEscapeNotifierFactory, providedIn: 'root' });
629
+ _checker = inject(InteractivityChecker);
630
+ _ngZone = inject(NgZone);
631
+ _document = inject(DOCUMENT);
632
+ create(element) {
633
+ return new FocusEscapeNotifier(element, this._checker, this._ngZone, this._document);
634
+ }
635
+ static ɵfac = i0.ɵɵngDeclareFactory({
636
+ minVersion: "12.0.0",
637
+ version: "20.2.0-next.2",
638
+ ngImport: i0,
639
+ type: FocusEscapeNotifierFactory,
640
+ deps: [],
641
+ target: i0.ɵɵFactoryTarget.Injectable
642
+ });
643
+ static ɵprov = i0.ɵɵngDeclareInjectable({
644
+ minVersion: "12.0.0",
645
+ version: "20.2.0-next.2",
646
+ ngImport: i0,
647
+ type: FocusEscapeNotifierFactory,
648
+ providedIn: 'root'
649
+ });
642
650
  }
643
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: FocusEscapeNotifierFactory, decorators: [{
644
- type: Injectable,
645
- args: [{ providedIn: 'root' }]
646
- }] });
651
+ i0.ɵɵngDeclareClassMetadata({
652
+ minVersion: "12.0.0",
653
+ version: "20.2.0-next.2",
654
+ ngImport: i0,
655
+ type: FocusEscapeNotifierFactory,
656
+ decorators: [{
657
+ type: Injectable,
658
+ args: [{
659
+ providedIn: 'root'
660
+ }]
661
+ }]
662
+ });
647
663
 
648
- /** Used for rate-limiting mousemove events. */
649
664
  const MOUSE_MOVE_THROTTLE_TIME_MS = 10;
650
665
  function hasRowElement(nl) {
651
- for (let i = 0; i < nl.length; i++) {
652
- const el = nl[i];
653
- if (!(el instanceof HTMLElement)) {
654
- continue;
655
- }
656
- if (el.matches(ROW_SELECTOR)) {
657
- return true;
658
- }
666
+ for (let i = 0; i < nl.length; i++) {
667
+ const el = nl[i];
668
+ if (!(el instanceof HTMLElement)) {
669
+ continue;
659
670
  }
660
- return false;
671
+ if (el.matches(ROW_SELECTOR)) {
672
+ return true;
673
+ }
674
+ }
675
+ return false;
661
676
  }
662
677
  function isRowMutation(mutation) {
663
- return hasRowElement(mutation.addedNodes) || hasRowElement(mutation.removedNodes);
678
+ return hasRowElement(mutation.addedNodes) || hasRowElement(mutation.removedNodes);
664
679
  }
665
- /**
666
- * A directive that must be attached to enable editability on a table.
667
- * It is responsible for setting up delegated event handlers and providing the
668
- * EditEventDispatcher service for use by the other edit directives.
669
- */
670
680
  class CdkEditable {
671
- elementRef = inject(ElementRef);
672
- editEventDispatcher = inject(EditEventDispatcher);
673
- focusDispatcher = inject(FocusDispatcher);
674
- ngZone = inject(NgZone);
675
- _renderer = inject(Renderer2);
676
- destroyed = new Subject();
677
- _rowsRendered = new Subject();
678
- _rowMutationObserver = globalThis.MutationObserver
679
- ? new globalThis.MutationObserver(mutations => {
680
- if (mutations.some(isRowMutation)) {
681
- this._rowsRendered.next();
682
- }
683
- })
684
- : null;
685
- constructor() {
686
- // TODO: consider a design where instead of polling for row changes we just use
687
- // afterRenderEffect + a signal of the rows.
688
- afterNextRender(() => {
689
- this._rowsRendered.next();
690
- this._rowMutationObserver?.observe(this.elementRef.nativeElement, {
691
- childList: true,
692
- subtree: true,
693
- });
694
- });
695
- }
696
- ngAfterViewInit() {
697
- this._listenForTableEvents();
698
- }
699
- ngOnDestroy() {
700
- this.destroyed.next();
701
- this.destroyed.complete();
702
- this._rowMutationObserver?.disconnect();
703
- }
704
- _observableFromEvent(element, name, options) {
705
- return new Observable(subscriber => {
706
- const handler = (event) => subscriber.next(event);
707
- const cleanup = this._renderer.listen(element, name, handler, options);
708
- return () => {
709
- cleanup();
710
- subscriber.complete();
711
- };
712
- });
713
- }
714
- _listenForTableEvents() {
715
- const element = this.elementRef.nativeElement;
716
- const toClosest = (selector) => map((event) => closest(event.target, selector));
717
- this.ngZone.runOutsideAngular(() => {
718
- // Track mouse movement over the table to hide/show hover content.
719
- this._observableFromEvent(element, 'mouseover')
720
- .pipe(toClosest(ROW_SELECTOR), takeUntil(this.destroyed))
721
- .subscribe(this.editEventDispatcher.hovering);
722
- this._observableFromEvent(element, 'mouseleave')
723
- .pipe(mapTo(null), takeUntil(this.destroyed))
724
- .subscribe(this.editEventDispatcher.hovering);
725
- this._observableFromEvent(element, 'mousemove')
726
- .pipe(throttleTime(MOUSE_MOVE_THROTTLE_TIME_MS), toClosest(ROW_SELECTOR), takeUntil(this.destroyed))
727
- .subscribe(this.editEventDispatcher.mouseMove);
728
- // Track focus within the table to hide/show/make focusable hover content.
729
- this._observableFromEvent(element, 'focus', { capture: true })
730
- .pipe(toClosest(ROW_SELECTOR), share(), takeUntil(this.destroyed))
731
- .subscribe(this.editEventDispatcher.focused);
732
- merge(this._observableFromEvent(element, 'blur', { capture: true }), this._observableFromEvent(element, 'keydown').pipe(filter(event => event.key === 'Escape')))
733
- .pipe(mapTo(null), share(), takeUntil(this.destroyed))
734
- .subscribe(this.editEventDispatcher.focused);
735
- // Keep track of rows within the table. This is used to know which rows with hover content
736
- // are first or last in the table. They are kept focusable in case focus enters from above
737
- // or below the table.
738
- this._rowsRendered
739
- .pipe(
740
- // Avoid some timing inconsistencies since Angular v19.
741
- // TODO: see if we can remove this now that we're using MutationObserver.
742
- debounceTime(0),
743
- // Optimization: ignore dom changes while focus is within the table as we already
744
- // ensure that rows above and below the focused/active row are tabbable.
745
- withLatestFrom(this.editEventDispatcher.editingOrFocused), filter(([_, activeRow]) => activeRow == null), map(() => element.querySelectorAll(ROW_SELECTOR)), share(), takeUntil(this.destroyed))
746
- .subscribe(this.editEventDispatcher.allRows);
747
- this._observableFromEvent(element, 'keydown')
748
- .pipe(filter(event => event.key === 'Enter'), toClosest(CELL_SELECTOR), takeUntil(this.destroyed))
749
- .subscribe(this.editEventDispatcher.editing);
750
- // Keydown must be used here or else key auto-repeat does not work properly on some platforms.
751
- this._observableFromEvent(element, 'keydown')
752
- .pipe(takeUntil(this.destroyed))
753
- .subscribe(this.focusDispatcher.keyObserver);
754
- });
755
- }
756
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: CdkEditable, deps: [], target: i0.ɵɵFactoryTarget.Directive });
757
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: CdkEditable, isStandalone: true, selector: "table[editable], cdk-table[editable], mat-table[editable]", providers: [EditEventDispatcher, EditServices], ngImport: i0 });
681
+ elementRef = inject(ElementRef);
682
+ editEventDispatcher = inject(EditEventDispatcher);
683
+ focusDispatcher = inject(FocusDispatcher);
684
+ ngZone = inject(NgZone);
685
+ _renderer = inject(Renderer2);
686
+ destroyed = new Subject();
687
+ _rowsRendered = new Subject();
688
+ _rowMutationObserver = globalThis.MutationObserver ? new globalThis.MutationObserver(mutations => {
689
+ if (mutations.some(isRowMutation)) {
690
+ this._rowsRendered.next();
691
+ }
692
+ }) : null;
693
+ constructor() {
694
+ afterNextRender(() => {
695
+ this._rowsRendered.next();
696
+ this._rowMutationObserver?.observe(this.elementRef.nativeElement, {
697
+ childList: true,
698
+ subtree: true
699
+ });
700
+ });
701
+ }
702
+ ngAfterViewInit() {
703
+ this._listenForTableEvents();
704
+ }
705
+ ngOnDestroy() {
706
+ this.destroyed.next();
707
+ this.destroyed.complete();
708
+ this._rowMutationObserver?.disconnect();
709
+ }
710
+ _observableFromEvent(element, name, options) {
711
+ return new Observable(subscriber => {
712
+ const handler = event => subscriber.next(event);
713
+ const cleanup = this._renderer.listen(element, name, handler, options);
714
+ return () => {
715
+ cleanup();
716
+ subscriber.complete();
717
+ };
718
+ });
719
+ }
720
+ _listenForTableEvents() {
721
+ const element = this.elementRef.nativeElement;
722
+ const toClosest = selector => map(event => closest(event.target, selector));
723
+ this.ngZone.runOutsideAngular(() => {
724
+ this._observableFromEvent(element, 'mouseover').pipe(toClosest(ROW_SELECTOR), takeUntil(this.destroyed)).subscribe(this.editEventDispatcher.hovering);
725
+ this._observableFromEvent(element, 'mouseleave').pipe(mapTo(null), takeUntil(this.destroyed)).subscribe(this.editEventDispatcher.hovering);
726
+ this._observableFromEvent(element, 'mousemove').pipe(throttleTime(MOUSE_MOVE_THROTTLE_TIME_MS), toClosest(ROW_SELECTOR), takeUntil(this.destroyed)).subscribe(this.editEventDispatcher.mouseMove);
727
+ this._observableFromEvent(element, 'focus', {
728
+ capture: true
729
+ }).pipe(toClosest(ROW_SELECTOR), share(), takeUntil(this.destroyed)).subscribe(this.editEventDispatcher.focused);
730
+ merge(this._observableFromEvent(element, 'blur', {
731
+ capture: true
732
+ }), this._observableFromEvent(element, 'keydown').pipe(filter(event => event.key === 'Escape'))).pipe(mapTo(null), share(), takeUntil(this.destroyed)).subscribe(this.editEventDispatcher.focused);
733
+ this._rowsRendered.pipe(debounceTime(0), withLatestFrom(this.editEventDispatcher.editingOrFocused), filter(([_, activeRow]) => activeRow == null), map(() => element.querySelectorAll(ROW_SELECTOR)), share(), takeUntil(this.destroyed)).subscribe(this.editEventDispatcher.allRows);
734
+ this._observableFromEvent(element, 'keydown').pipe(filter(event => event.key === 'Enter'), toClosest(CELL_SELECTOR), takeUntil(this.destroyed)).subscribe(this.editEventDispatcher.editing);
735
+ this._observableFromEvent(element, 'keydown').pipe(takeUntil(this.destroyed)).subscribe(this.focusDispatcher.keyObserver);
736
+ });
737
+ }
738
+ static ɵfac = i0.ɵɵngDeclareFactory({
739
+ minVersion: "12.0.0",
740
+ version: "20.2.0-next.2",
741
+ ngImport: i0,
742
+ type: CdkEditable,
743
+ deps: [],
744
+ target: i0.ɵɵFactoryTarget.Directive
745
+ });
746
+ static ɵdir = i0.ɵɵngDeclareDirective({
747
+ minVersion: "14.0.0",
748
+ version: "20.2.0-next.2",
749
+ type: CdkEditable,
750
+ isStandalone: true,
751
+ selector: "table[editable], cdk-table[editable], mat-table[editable]",
752
+ providers: [EditEventDispatcher, EditServices],
753
+ ngImport: i0
754
+ });
758
755
  }
759
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: CdkEditable, decorators: [{
760
- type: Directive,
761
- args: [{
762
- selector: 'table[editable], cdk-table[editable], mat-table[editable]',
763
- providers: [EditEventDispatcher, EditServices],
764
- }]
765
- }], ctorParameters: () => [] });
756
+ i0.ɵɵngDeclareClassMetadata({
757
+ minVersion: "12.0.0",
758
+ version: "20.2.0-next.2",
759
+ ngImport: i0,
760
+ type: CdkEditable,
761
+ decorators: [{
762
+ type: Directive,
763
+ args: [{
764
+ selector: 'table[editable], cdk-table[editable], mat-table[editable]',
765
+ providers: [EditEventDispatcher, EditServices]
766
+ }]
767
+ }],
768
+ ctorParameters: () => []
769
+ });
766
770
  const POPOVER_EDIT_HOST_BINDINGS = {
767
- '[attr.tabindex]': 'disabled ? null : 0',
768
- 'class': 'cdk-popover-edit-cell',
769
- '[attr.aria-haspopup]': '!disabled',
771
+ '[attr.tabindex]': 'disabled ? null : 0',
772
+ 'class': 'cdk-popover-edit-cell',
773
+ '[attr.aria-haspopup]': '!disabled'
770
774
  };
771
- const POPOVER_EDIT_INPUTS = [
772
- { name: 'template', alias: 'cdkPopoverEdit' },
773
- { name: 'context', alias: 'cdkPopoverEditContext' },
774
- { name: 'colspan', alias: 'cdkPopoverEditColspan' },
775
- { name: 'disabled', alias: 'cdkPopoverEditDisabled' },
776
- { name: 'ariaLabel', alias: 'cdkPopoverEditAriaLabel' },
777
- ];
778
- /**
779
- * Attaches an ng-template to a cell and shows it when instructed to by the
780
- * EditEventDispatcher service.
781
- * Makes the cell focusable.
782
- */
775
+ const POPOVER_EDIT_INPUTS = [{
776
+ name: 'template',
777
+ alias: 'cdkPopoverEdit'
778
+ }, {
779
+ name: 'context',
780
+ alias: 'cdkPopoverEditContext'
781
+ }, {
782
+ name: 'colspan',
783
+ alias: 'cdkPopoverEditColspan'
784
+ }, {
785
+ name: 'disabled',
786
+ alias: 'cdkPopoverEditDisabled'
787
+ }, {
788
+ name: 'ariaLabel',
789
+ alias: 'cdkPopoverEditAriaLabel'
790
+ }];
783
791
  class CdkPopoverEdit {
784
- services = inject(EditServices);
785
- elementRef = inject(ElementRef);
786
- viewContainerRef = inject(ViewContainerRef);
787
- _injector = inject(Injector);
788
- /** The edit lens template shown over the cell on edit. */
789
- template = null;
790
- /**
791
- * Implicit context to pass along to the template. Can be omitted if the template
792
- * is defined within the cell.
793
- */
794
- context;
795
- /** Aria label to set on the popover dialog element. */
796
- ariaLabel;
797
- /**
798
- * Specifies that the popup should cover additional table cells before and/or after
799
- * this one.
800
- */
801
- get colspan() {
802
- return this._colspan;
803
- }
804
- set colspan(value) {
805
- this._colspan = value;
806
- // Recompute positioning when the colspan changes.
807
- if (this.overlayRef) {
808
- this.overlayRef.updatePositionStrategy(this._getPositionStrategy());
809
- if (this.overlayRef.hasAttached()) {
810
- this._updateOverlaySize();
811
- }
812
- }
813
- }
814
- _colspan = {};
815
- /** Whether popover edit is disabled for this cell. */
816
- get disabled() {
817
- return this._disabled;
818
- }
819
- set disabled(value) {
820
- this._disabled = value;
821
- if (value) {
822
- this.services.editEventDispatcher.doneEditingCell(this.elementRef.nativeElement);
823
- this.services.editEventDispatcher.disabledCells.set(this.elementRef.nativeElement, true);
824
- }
825
- else {
826
- this.services.editEventDispatcher.disabledCells.delete(this.elementRef.nativeElement);
827
- }
828
- }
829
- _disabled = false;
830
- focusTrap;
831
- overlayRef;
832
- destroyed = new Subject();
833
- ngAfterViewInit() {
834
- this._startListeningToEditEvents();
835
- }
836
- ngOnDestroy() {
837
- this.destroyed.next();
838
- this.destroyed.complete();
839
- if (this.focusTrap) {
840
- this.focusTrap.destroy();
841
- this.focusTrap = undefined;
842
- }
843
- if (this.overlayRef) {
844
- this.overlayRef.dispose();
845
- }
846
- }
847
- initFocusTrap() {
848
- this.focusTrap = this.services.focusTrapFactory.create(this.overlayRef.overlayElement);
849
- }
850
- closeEditOverlay() {
851
- this.services.editEventDispatcher.doneEditingCell(this.elementRef.nativeElement);
852
- }
853
- panelClass() {
854
- return EDIT_PANE_CLASS;
855
- }
856
- _startListeningToEditEvents() {
857
- this.services.editEventDispatcher
858
- .editingCell(this.elementRef.nativeElement)
859
- .pipe(takeUntil(this.destroyed))
860
- .subscribe(open => {
861
- if (open && this.template) {
862
- if (!this.overlayRef) {
863
- this._createEditOverlay();
864
- }
865
- this._showEditOverlay();
866
- }
867
- else if (this.overlayRef) {
868
- this._maybeReturnFocusToCell();
869
- this.overlayRef.detach();
870
- }
871
- });
872
- }
873
- _createEditOverlay() {
874
- this.overlayRef = createOverlayRef(this._injector, {
875
- disposeOnNavigation: true,
876
- panelClass: this.panelClass(),
877
- positionStrategy: this._getPositionStrategy(),
878
- scrollStrategy: createRepositionScrollStrategy(this._injector),
879
- direction: this.services.directionality,
880
- });
881
- this.initFocusTrap();
882
- this.overlayRef.overlayElement.setAttribute('role', 'dialog');
883
- if (this.ariaLabel) {
884
- this.overlayRef.overlayElement.setAttribute('aria-label', this.ariaLabel);
885
- }
886
- this.overlayRef.detachments().subscribe(() => this.closeEditOverlay());
887
- }
888
- _showEditOverlay() {
889
- this.overlayRef.attach(new TemplatePortal(this.template, this.viewContainerRef, { $implicit: this.context }));
890
- // We have to defer trapping focus, because doing so too early can cause the form inside
891
- // the overlay to be submitted immediately if it was opened on an Enter keydown event.
892
- this.services.ngZone.runOutsideAngular(() => {
893
- setTimeout(() => {
894
- this.focusTrap.focusInitialElement();
895
- });
896
- });
897
- // Update the size of the popup initially and on subsequent changes to
898
- // scroll position and viewport size.
899
- merge(this.services.scrollDispatcher.scrolled(), this.services.viewportRuler.change())
900
- .pipe(startWith(null), takeUntil(merge(this.overlayRef.detachments(), this.destroyed)))
901
- .subscribe(() => {
902
- this._updateOverlaySize();
903
- });
904
- }
905
- _getOverlayCells() {
906
- const cell = closest(this.elementRef.nativeElement, CELL_SELECTOR);
907
- if (!this._colspan.before && !this._colspan.after) {
908
- return [cell];
909
- }
910
- const row = closest(this.elementRef.nativeElement, ROW_SELECTOR);
911
- const rowCells = Array.from(row.querySelectorAll(CELL_SELECTOR));
912
- const ownIndex = rowCells.indexOf(cell);
913
- return rowCells.slice(ownIndex - (this._colspan.before || 0), ownIndex + (this._colspan.after || 0) + 1);
914
- }
915
- _getPositionStrategy() {
916
- const cells = this._getOverlayCells();
917
- return createFlexibleConnectedPositionStrategy(this._injector, cells[0])
918
- .withGrowAfterOpen()
919
- .withPush()
920
- .withViewportMargin(16)
921
- .withPositions([
922
- {
923
- originX: 'start',
924
- originY: 'top',
925
- overlayX: 'start',
926
- overlayY: 'top',
927
- },
928
- ]);
929
- }
930
- _updateOverlaySize() {
931
- this.overlayRef.updateSize(this._sizeConfigForCells(this._getOverlayCells()));
932
- }
933
- _maybeReturnFocusToCell() {
934
- if (closest(document.activeElement, EDIT_PANE_SELECTOR) === this.overlayRef.overlayElement) {
935
- this.elementRef.nativeElement.focus();
936
- }
937
- }
938
- _sizeConfigForCells(cells) {
939
- if (cells.length === 0) {
940
- return {};
792
+ services = inject(EditServices);
793
+ elementRef = inject(ElementRef);
794
+ viewContainerRef = inject(ViewContainerRef);
795
+ _injector = inject(Injector);
796
+ template = null;
797
+ context;
798
+ ariaLabel;
799
+ get colspan() {
800
+ return this._colspan;
801
+ }
802
+ set colspan(value) {
803
+ this._colspan = value;
804
+ if (this.overlayRef) {
805
+ this.overlayRef.updatePositionStrategy(this._getPositionStrategy());
806
+ if (this.overlayRef.hasAttached()) {
807
+ this._updateOverlaySize();
808
+ }
809
+ }
810
+ }
811
+ _colspan = {};
812
+ get disabled() {
813
+ return this._disabled;
814
+ }
815
+ set disabled(value) {
816
+ this._disabled = value;
817
+ if (value) {
818
+ this.services.editEventDispatcher.doneEditingCell(this.elementRef.nativeElement);
819
+ this.services.editEventDispatcher.disabledCells.set(this.elementRef.nativeElement, true);
820
+ } else {
821
+ this.services.editEventDispatcher.disabledCells.delete(this.elementRef.nativeElement);
822
+ }
823
+ }
824
+ _disabled = false;
825
+ focusTrap;
826
+ overlayRef;
827
+ destroyed = new Subject();
828
+ ngAfterViewInit() {
829
+ this._startListeningToEditEvents();
830
+ }
831
+ ngOnDestroy() {
832
+ this.destroyed.next();
833
+ this.destroyed.complete();
834
+ if (this.focusTrap) {
835
+ this.focusTrap.destroy();
836
+ this.focusTrap = undefined;
837
+ }
838
+ if (this.overlayRef) {
839
+ this.overlayRef.dispose();
840
+ }
841
+ }
842
+ initFocusTrap() {
843
+ this.focusTrap = this.services.focusTrapFactory.create(this.overlayRef.overlayElement);
844
+ }
845
+ closeEditOverlay() {
846
+ this.services.editEventDispatcher.doneEditingCell(this.elementRef.nativeElement);
847
+ }
848
+ panelClass() {
849
+ return EDIT_PANE_CLASS;
850
+ }
851
+ _startListeningToEditEvents() {
852
+ this.services.editEventDispatcher.editingCell(this.elementRef.nativeElement).pipe(takeUntil(this.destroyed)).subscribe(open => {
853
+ if (open && this.template) {
854
+ if (!this.overlayRef) {
855
+ this._createEditOverlay();
941
856
  }
942
- if (cells.length === 1) {
943
- return { width: cells[0].getBoundingClientRect().width };
944
- }
945
- let firstCell, lastCell;
946
- if (this.services.directionality.value === 'ltr') {
947
- firstCell = cells[0];
948
- lastCell = cells[cells.length - 1];
949
- }
950
- else {
951
- lastCell = cells[0];
952
- firstCell = cells[cells.length - 1];
953
- }
954
- return { width: lastCell.getBoundingClientRect().right - firstCell.getBoundingClientRect().left };
955
- }
956
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: CdkPopoverEdit, deps: [], target: i0.ɵɵFactoryTarget.Directive });
957
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: CdkPopoverEdit, isStandalone: true, selector: "[cdkPopoverEdit]:not([cdkPopoverEditTabOut])", inputs: { template: ["cdkPopoverEdit", "template"], context: ["cdkPopoverEditContext", "context"], colspan: ["cdkPopoverEditColspan", "colspan"], disabled: ["cdkPopoverEditDisabled", "disabled"], ariaLabel: ["cdkPopoverEditAriaLabel", "ariaLabel"] }, host: { properties: { "attr.tabindex": "disabled ? null : 0", "attr.aria-haspopup": "!disabled" }, classAttribute: "cdk-popover-edit-cell" }, ngImport: i0 });
857
+ this._showEditOverlay();
858
+ } else if (this.overlayRef) {
859
+ this._maybeReturnFocusToCell();
860
+ this.overlayRef.detach();
861
+ }
862
+ });
863
+ }
864
+ _createEditOverlay() {
865
+ this.overlayRef = createOverlayRef(this._injector, {
866
+ disposeOnNavigation: true,
867
+ panelClass: this.panelClass(),
868
+ positionStrategy: this._getPositionStrategy(),
869
+ scrollStrategy: createRepositionScrollStrategy(this._injector),
870
+ direction: this.services.directionality
871
+ });
872
+ this.initFocusTrap();
873
+ this.overlayRef.overlayElement.setAttribute('role', 'dialog');
874
+ if (this.ariaLabel) {
875
+ this.overlayRef.overlayElement.setAttribute('aria-label', this.ariaLabel);
876
+ }
877
+ this.overlayRef.detachments().subscribe(() => this.closeEditOverlay());
878
+ }
879
+ _showEditOverlay() {
880
+ this.overlayRef.attach(new TemplatePortal(this.template, this.viewContainerRef, {
881
+ $implicit: this.context
882
+ }));
883
+ this.services.ngZone.runOutsideAngular(() => {
884
+ setTimeout(() => {
885
+ this.focusTrap.focusInitialElement();
886
+ });
887
+ });
888
+ merge(this.services.scrollDispatcher.scrolled(), this.services.viewportRuler.change()).pipe(startWith(null), takeUntil(merge(this.overlayRef.detachments(), this.destroyed))).subscribe(() => {
889
+ this._updateOverlaySize();
890
+ });
891
+ }
892
+ _getOverlayCells() {
893
+ const cell = closest(this.elementRef.nativeElement, CELL_SELECTOR);
894
+ if (!this._colspan.before && !this._colspan.after) {
895
+ return [cell];
896
+ }
897
+ const row = closest(this.elementRef.nativeElement, ROW_SELECTOR);
898
+ const rowCells = Array.from(row.querySelectorAll(CELL_SELECTOR));
899
+ const ownIndex = rowCells.indexOf(cell);
900
+ return rowCells.slice(ownIndex - (this._colspan.before || 0), ownIndex + (this._colspan.after || 0) + 1);
901
+ }
902
+ _getPositionStrategy() {
903
+ const cells = this._getOverlayCells();
904
+ return createFlexibleConnectedPositionStrategy(this._injector, cells[0]).withGrowAfterOpen().withPush().withViewportMargin(16).withPositions([{
905
+ originX: 'start',
906
+ originY: 'top',
907
+ overlayX: 'start',
908
+ overlayY: 'top'
909
+ }]);
910
+ }
911
+ _updateOverlaySize() {
912
+ this.overlayRef.updateSize(this._sizeConfigForCells(this._getOverlayCells()));
913
+ }
914
+ _maybeReturnFocusToCell() {
915
+ if (closest(document.activeElement, EDIT_PANE_SELECTOR) === this.overlayRef.overlayElement) {
916
+ this.elementRef.nativeElement.focus();
917
+ }
918
+ }
919
+ _sizeConfigForCells(cells) {
920
+ if (cells.length === 0) {
921
+ return {};
922
+ }
923
+ if (cells.length === 1) {
924
+ return {
925
+ width: cells[0].getBoundingClientRect().width
926
+ };
927
+ }
928
+ let firstCell, lastCell;
929
+ if (this.services.directionality.value === 'ltr') {
930
+ firstCell = cells[0];
931
+ lastCell = cells[cells.length - 1];
932
+ } else {
933
+ lastCell = cells[0];
934
+ firstCell = cells[cells.length - 1];
935
+ }
936
+ return {
937
+ width: lastCell.getBoundingClientRect().right - firstCell.getBoundingClientRect().left
938
+ };
939
+ }
940
+ static ɵfac = i0.ɵɵngDeclareFactory({
941
+ minVersion: "12.0.0",
942
+ version: "20.2.0-next.2",
943
+ ngImport: i0,
944
+ type: CdkPopoverEdit,
945
+ deps: [],
946
+ target: i0.ɵɵFactoryTarget.Directive
947
+ });
948
+ static ɵdir = i0.ɵɵngDeclareDirective({
949
+ minVersion: "14.0.0",
950
+ version: "20.2.0-next.2",
951
+ type: CdkPopoverEdit,
952
+ isStandalone: true,
953
+ selector: "[cdkPopoverEdit]:not([cdkPopoverEditTabOut])",
954
+ inputs: {
955
+ template: ["cdkPopoverEdit", "template"],
956
+ context: ["cdkPopoverEditContext", "context"],
957
+ colspan: ["cdkPopoverEditColspan", "colspan"],
958
+ disabled: ["cdkPopoverEditDisabled", "disabled"],
959
+ ariaLabel: ["cdkPopoverEditAriaLabel", "ariaLabel"]
960
+ },
961
+ host: {
962
+ properties: {
963
+ "attr.tabindex": "disabled ? null : 0",
964
+ "attr.aria-haspopup": "!disabled"
965
+ },
966
+ classAttribute: "cdk-popover-edit-cell"
967
+ },
968
+ ngImport: i0
969
+ });
958
970
  }
959
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: CdkPopoverEdit, decorators: [{
960
- type: Directive,
961
- args: [{
962
- selector: '[cdkPopoverEdit]:not([cdkPopoverEditTabOut])',
963
- host: POPOVER_EDIT_HOST_BINDINGS,
964
- inputs: POPOVER_EDIT_INPUTS,
965
- }]
966
- }] });
967
- /**
968
- * Attaches an ng-template to a cell and shows it when instructed to by the
969
- * EditEventDispatcher service.
970
- * Makes the cell focusable.
971
- */
971
+ i0.ɵɵngDeclareClassMetadata({
972
+ minVersion: "12.0.0",
973
+ version: "20.2.0-next.2",
974
+ ngImport: i0,
975
+ type: CdkPopoverEdit,
976
+ decorators: [{
977
+ type: Directive,
978
+ args: [{
979
+ selector: '[cdkPopoverEdit]:not([cdkPopoverEditTabOut])',
980
+ host: POPOVER_EDIT_HOST_BINDINGS,
981
+ inputs: POPOVER_EDIT_INPUTS
982
+ }]
983
+ }]
984
+ });
972
985
  class CdkPopoverEditTabOut extends CdkPopoverEdit {
973
- focusEscapeNotifierFactory = inject(FocusEscapeNotifierFactory);
974
- focusTrap = undefined;
975
- initFocusTrap() {
976
- this.focusTrap = this.focusEscapeNotifierFactory.create(this.overlayRef.overlayElement);
977
- this.focusTrap
978
- .escapes()
979
- .pipe(takeUntil(this.destroyed))
980
- .subscribe(direction => {
981
- this.services.editEventDispatcher.editRef?.blur();
982
- this.services.focusDispatcher.moveFocusHorizontally(closest(this.elementRef.nativeElement, CELL_SELECTOR), direction === FocusEscapeNotifierDirection.START ? -1 : 1);
983
- this.closeEditOverlay();
984
- });
985
- }
986
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: CdkPopoverEditTabOut, deps: null, target: i0.ɵɵFactoryTarget.Directive });
987
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: CdkPopoverEditTabOut, isStandalone: true, selector: "[cdkPopoverEdit][cdkPopoverEditTabOut]", inputs: { template: ["cdkPopoverEdit", "template"], context: ["cdkPopoverEditContext", "context"], colspan: ["cdkPopoverEditColspan", "colspan"], disabled: ["cdkPopoverEditDisabled", "disabled"], ariaLabel: ["cdkPopoverEditAriaLabel", "ariaLabel"] }, host: { properties: { "attr.tabindex": "disabled ? null : 0", "attr.aria-haspopup": "!disabled" }, classAttribute: "cdk-popover-edit-cell" }, usesInheritance: true, ngImport: i0 });
986
+ focusEscapeNotifierFactory = inject(FocusEscapeNotifierFactory);
987
+ focusTrap = undefined;
988
+ initFocusTrap() {
989
+ this.focusTrap = this.focusEscapeNotifierFactory.create(this.overlayRef.overlayElement);
990
+ this.focusTrap.escapes().pipe(takeUntil(this.destroyed)).subscribe(direction => {
991
+ this.services.editEventDispatcher.editRef?.blur();
992
+ this.services.focusDispatcher.moveFocusHorizontally(closest(this.elementRef.nativeElement, CELL_SELECTOR), direction === FocusEscapeNotifierDirection.START ? -1 : 1);
993
+ this.closeEditOverlay();
994
+ });
995
+ }
996
+ static ɵfac = i0.ɵɵngDeclareFactory({
997
+ minVersion: "12.0.0",
998
+ version: "20.2.0-next.2",
999
+ ngImport: i0,
1000
+ type: CdkPopoverEditTabOut,
1001
+ deps: null,
1002
+ target: i0.ɵɵFactoryTarget.Directive
1003
+ });
1004
+ static ɵdir = i0.ɵɵngDeclareDirective({
1005
+ minVersion: "14.0.0",
1006
+ version: "20.2.0-next.2",
1007
+ type: CdkPopoverEditTabOut,
1008
+ isStandalone: true,
1009
+ selector: "[cdkPopoverEdit][cdkPopoverEditTabOut]",
1010
+ inputs: {
1011
+ template: ["cdkPopoverEdit", "template"],
1012
+ context: ["cdkPopoverEditContext", "context"],
1013
+ colspan: ["cdkPopoverEditColspan", "colspan"],
1014
+ disabled: ["cdkPopoverEditDisabled", "disabled"],
1015
+ ariaLabel: ["cdkPopoverEditAriaLabel", "ariaLabel"]
1016
+ },
1017
+ host: {
1018
+ properties: {
1019
+ "attr.tabindex": "disabled ? null : 0",
1020
+ "attr.aria-haspopup": "!disabled"
1021
+ },
1022
+ classAttribute: "cdk-popover-edit-cell"
1023
+ },
1024
+ usesInheritance: true,
1025
+ ngImport: i0
1026
+ });
988
1027
  }
989
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: CdkPopoverEditTabOut, decorators: [{
990
- type: Directive,
991
- args: [{
992
- selector: '[cdkPopoverEdit][cdkPopoverEditTabOut]',
993
- host: POPOVER_EDIT_HOST_BINDINGS,
994
- inputs: POPOVER_EDIT_INPUTS,
995
- }]
996
- }] });
997
- /**
998
- * A structural directive that shows its contents when the table row containing
999
- * it is hovered or when an element in the row has focus.
1000
- */
1028
+ i0.ɵɵngDeclareClassMetadata({
1029
+ minVersion: "12.0.0",
1030
+ version: "20.2.0-next.2",
1031
+ ngImport: i0,
1032
+ type: CdkPopoverEditTabOut,
1033
+ decorators: [{
1034
+ type: Directive,
1035
+ args: [{
1036
+ selector: '[cdkPopoverEdit][cdkPopoverEditTabOut]',
1037
+ host: POPOVER_EDIT_HOST_BINDINGS,
1038
+ inputs: POPOVER_EDIT_INPUTS
1039
+ }]
1040
+ }]
1041
+ });
1001
1042
  class CdkRowHoverContent {
1002
- services = inject(EditServices);
1003
- elementRef = inject(ElementRef);
1004
- templateRef = inject(TemplateRef);
1005
- viewContainerRef = inject(ViewContainerRef);
1006
- destroyed = new Subject();
1007
- viewRef = null;
1008
- _row;
1009
- ngAfterViewInit() {
1010
- this._row = closest(this.elementRef.nativeElement, ROW_SELECTOR);
1011
- this.services.editEventDispatcher.registerRowWithHoverContent(this._row);
1012
- this._listenForHoverAndFocusEvents();
1013
- }
1014
- ngOnDestroy() {
1015
- this.destroyed.next();
1016
- this.destroyed.complete();
1017
- if (this.viewRef) {
1018
- this.viewRef.destroy();
1043
+ services = inject(EditServices);
1044
+ elementRef = inject(ElementRef);
1045
+ templateRef = inject(TemplateRef);
1046
+ viewContainerRef = inject(ViewContainerRef);
1047
+ destroyed = new Subject();
1048
+ viewRef = null;
1049
+ _row;
1050
+ ngAfterViewInit() {
1051
+ this._row = closest(this.elementRef.nativeElement, ROW_SELECTOR);
1052
+ this.services.editEventDispatcher.registerRowWithHoverContent(this._row);
1053
+ this._listenForHoverAndFocusEvents();
1054
+ }
1055
+ ngOnDestroy() {
1056
+ this.destroyed.next();
1057
+ this.destroyed.complete();
1058
+ if (this.viewRef) {
1059
+ this.viewRef.destroy();
1060
+ }
1061
+ if (this._row) {
1062
+ this.services.editEventDispatcher.deregisterRowWithHoverContent(this._row);
1063
+ }
1064
+ }
1065
+ initElement(_) {}
1066
+ makeElementHiddenButFocusable(element) {
1067
+ element.style.opacity = '0';
1068
+ }
1069
+ makeElementVisible(element) {
1070
+ element.style.opacity = '';
1071
+ }
1072
+ _listenForHoverAndFocusEvents() {
1073
+ this.services.editEventDispatcher.hoverOrFocusOnRow(this._row).pipe(takeUntil(this.destroyed)).subscribe(eventState => {
1074
+ if (eventState === HoverContentState.ON || eventState === HoverContentState.FOCUSABLE) {
1075
+ if (!this.viewRef) {
1076
+ this.viewRef = this.viewContainerRef.createEmbeddedView(this.templateRef, {});
1077
+ this.initElement(this.viewRef.rootNodes[0]);
1078
+ this.viewRef.markForCheck();
1079
+ } else if (this.viewContainerRef.indexOf(this.viewRef) === -1) {
1080
+ this.viewContainerRef.insert(this.viewRef);
1081
+ this.viewRef.markForCheck();
1019
1082
  }
1020
- if (this._row) {
1021
- this.services.editEventDispatcher.deregisterRowWithHoverContent(this._row);
1083
+ if (eventState === HoverContentState.ON) {
1084
+ this.makeElementVisible(this.viewRef.rootNodes[0]);
1085
+ } else {
1086
+ this.makeElementHiddenButFocusable(this.viewRef.rootNodes[0]);
1022
1087
  }
1023
- }
1024
- /**
1025
- * Called immediately after the hover content is created and added to the dom.
1026
- * In the CDK version, this is a noop but subclasses such as MatRowHoverContent use this
1027
- * to prepare/style the inserted element.
1028
- */
1029
- initElement(_) { }
1030
- /**
1031
- * Called when the hover content needs to be focusable to preserve a reasonable tab ordering
1032
- * but should not yet be shown.
1033
- */
1034
- makeElementHiddenButFocusable(element) {
1035
- element.style.opacity = '0';
1036
- }
1037
- /**
1038
- * Called when the hover content needs to be focusable to preserve a reasonable tab ordering
1039
- * but should not yet be shown.
1040
- */
1041
- makeElementVisible(element) {
1042
- element.style.opacity = '';
1043
- }
1044
- _listenForHoverAndFocusEvents() {
1045
- this.services.editEventDispatcher
1046
- .hoverOrFocusOnRow(this._row)
1047
- .pipe(takeUntil(this.destroyed))
1048
- .subscribe(eventState => {
1049
- // When in FOCUSABLE state, add the hover content to the dom but make it transparent so
1050
- // that it is in the tab order relative to the currently focused row.
1051
- if (eventState === HoverContentState.ON || eventState === HoverContentState.FOCUSABLE) {
1052
- if (!this.viewRef) {
1053
- this.viewRef = this.viewContainerRef.createEmbeddedView(this.templateRef, {});
1054
- this.initElement(this.viewRef.rootNodes[0]);
1055
- this.viewRef.markForCheck();
1056
- }
1057
- else if (this.viewContainerRef.indexOf(this.viewRef) === -1) {
1058
- this.viewContainerRef.insert(this.viewRef);
1059
- this.viewRef.markForCheck();
1060
- }
1061
- if (eventState === HoverContentState.ON) {
1062
- this.makeElementVisible(this.viewRef.rootNodes[0]);
1063
- }
1064
- else {
1065
- this.makeElementHiddenButFocusable(this.viewRef.rootNodes[0]);
1066
- }
1067
- }
1068
- else if (this.viewRef) {
1069
- this.viewContainerRef.detach(this.viewContainerRef.indexOf(this.viewRef));
1070
- }
1071
- });
1072
- }
1073
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: CdkRowHoverContent, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1074
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: CdkRowHoverContent, isStandalone: true, selector: "[cdkRowHoverContent]", ngImport: i0 });
1088
+ } else if (this.viewRef) {
1089
+ this.viewContainerRef.detach(this.viewContainerRef.indexOf(this.viewRef));
1090
+ }
1091
+ });
1092
+ }
1093
+ static ɵfac = i0.ɵɵngDeclareFactory({
1094
+ minVersion: "12.0.0",
1095
+ version: "20.2.0-next.2",
1096
+ ngImport: i0,
1097
+ type: CdkRowHoverContent,
1098
+ deps: [],
1099
+ target: i0.ɵɵFactoryTarget.Directive
1100
+ });
1101
+ static ɵdir = i0.ɵɵngDeclareDirective({
1102
+ minVersion: "14.0.0",
1103
+ version: "20.2.0-next.2",
1104
+ type: CdkRowHoverContent,
1105
+ isStandalone: true,
1106
+ selector: "[cdkRowHoverContent]",
1107
+ ngImport: i0
1108
+ });
1075
1109
  }
1076
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: CdkRowHoverContent, decorators: [{
1077
- type: Directive,
1078
- args: [{
1079
- selector: '[cdkRowHoverContent]',
1080
- }]
1081
- }] });
1082
- /**
1083
- * Opens the closest edit popover to this element, whether it's associated with this exact
1084
- * element or an ancestor element.
1085
- */
1110
+ i0.ɵɵngDeclareClassMetadata({
1111
+ minVersion: "12.0.0",
1112
+ version: "20.2.0-next.2",
1113
+ ngImport: i0,
1114
+ type: CdkRowHoverContent,
1115
+ decorators: [{
1116
+ type: Directive,
1117
+ args: [{
1118
+ selector: '[cdkRowHoverContent]'
1119
+ }]
1120
+ }]
1121
+ });
1086
1122
  class CdkEditOpen {
1087
- elementRef = inject(ElementRef);
1088
- editEventDispatcher = inject(EditEventDispatcher);
1089
- constructor() {
1090
- const elementRef = this.elementRef;
1091
- const nativeElement = elementRef.nativeElement;
1092
- // Prevent accidental form submits.
1093
- if (nativeElement.nodeName === 'BUTTON' && !nativeElement.getAttribute('type')) {
1094
- nativeElement.setAttribute('type', 'button');
1095
- }
1096
- }
1097
- openEdit(evt) {
1098
- this.editEventDispatcher.editing.next(closest(this.elementRef.nativeElement, CELL_SELECTOR));
1099
- evt.stopPropagation();
1100
- }
1101
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: CdkEditOpen, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1102
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.2", type: CdkEditOpen, isStandalone: true, selector: "[cdkEditOpen]", host: { listeners: { "click": "openEdit($event)" } }, ngImport: i0 });
1123
+ elementRef = inject(ElementRef);
1124
+ editEventDispatcher = inject(EditEventDispatcher);
1125
+ constructor() {
1126
+ const elementRef = this.elementRef;
1127
+ const nativeElement = elementRef.nativeElement;
1128
+ if (nativeElement.nodeName === 'BUTTON' && !nativeElement.getAttribute('type')) {
1129
+ nativeElement.setAttribute('type', 'button');
1130
+ }
1131
+ }
1132
+ openEdit(evt) {
1133
+ this.editEventDispatcher.editing.next(closest(this.elementRef.nativeElement, CELL_SELECTOR));
1134
+ evt.stopPropagation();
1135
+ }
1136
+ static ɵfac = i0.ɵɵngDeclareFactory({
1137
+ minVersion: "12.0.0",
1138
+ version: "20.2.0-next.2",
1139
+ ngImport: i0,
1140
+ type: CdkEditOpen,
1141
+ deps: [],
1142
+ target: i0.ɵɵFactoryTarget.Directive
1143
+ });
1144
+ static ɵdir = i0.ɵɵngDeclareDirective({
1145
+ minVersion: "14.0.0",
1146
+ version: "20.2.0-next.2",
1147
+ type: CdkEditOpen,
1148
+ isStandalone: true,
1149
+ selector: "[cdkEditOpen]",
1150
+ host: {
1151
+ listeners: {
1152
+ "click": "openEdit($event)"
1153
+ }
1154
+ },
1155
+ ngImport: i0
1156
+ });
1103
1157
  }
1104
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: CdkEditOpen, decorators: [{
1105
- type: Directive,
1106
- args: [{
1107
- selector: '[cdkEditOpen]',
1108
- host: {
1109
- '(click)': 'openEdit($event)',
1110
- },
1111
- }]
1112
- }], ctorParameters: () => [] });
1158
+ i0.ɵɵngDeclareClassMetadata({
1159
+ minVersion: "12.0.0",
1160
+ version: "20.2.0-next.2",
1161
+ ngImport: i0,
1162
+ type: CdkEditOpen,
1163
+ decorators: [{
1164
+ type: Directive,
1165
+ args: [{
1166
+ selector: '[cdkEditOpen]',
1167
+ host: {
1168
+ '(click)': 'openEdit($event)'
1169
+ }
1170
+ }]
1171
+ }],
1172
+ ctorParameters: () => []
1173
+ });
1113
1174
 
1114
- const EXPORTED_DECLARATIONS = [
1115
- CdkPopoverEdit,
1116
- CdkPopoverEditTabOut,
1117
- CdkRowHoverContent,
1118
- CdkEditControl,
1119
- CdkEditRevert,
1120
- CdkEditClose,
1121
- CdkEditable,
1122
- CdkEditOpen,
1123
- ];
1175
+ const EXPORTED_DECLARATIONS = [CdkPopoverEdit, CdkPopoverEditTabOut, CdkRowHoverContent, CdkEditControl, CdkEditRevert, CdkEditClose, CdkEditable, CdkEditOpen];
1124
1176
  class CdkPopoverEditModule {
1125
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: CdkPopoverEditModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1126
- static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.2.0-next.2", ngImport: i0, type: CdkPopoverEditModule, imports: [OverlayModule, CdkPopoverEdit,
1127
- CdkPopoverEditTabOut,
1128
- CdkRowHoverContent,
1129
- CdkEditControl,
1130
- CdkEditRevert,
1131
- CdkEditClose,
1132
- CdkEditable,
1133
- CdkEditOpen], exports: [CdkPopoverEdit,
1134
- CdkPopoverEditTabOut,
1135
- CdkRowHoverContent,
1136
- CdkEditControl,
1137
- CdkEditRevert,
1138
- CdkEditClose,
1139
- CdkEditable,
1140
- CdkEditOpen] });
1141
- static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: CdkPopoverEditModule, imports: [OverlayModule] });
1177
+ static ɵfac = i0.ɵɵngDeclareFactory({
1178
+ minVersion: "12.0.0",
1179
+ version: "20.2.0-next.2",
1180
+ ngImport: i0,
1181
+ type: CdkPopoverEditModule,
1182
+ deps: [],
1183
+ target: i0.ɵɵFactoryTarget.NgModule
1184
+ });
1185
+ static ɵmod = i0.ɵɵngDeclareNgModule({
1186
+ minVersion: "14.0.0",
1187
+ version: "20.2.0-next.2",
1188
+ ngImport: i0,
1189
+ type: CdkPopoverEditModule,
1190
+ imports: [OverlayModule, CdkPopoverEdit, CdkPopoverEditTabOut, CdkRowHoverContent, CdkEditControl, CdkEditRevert, CdkEditClose, CdkEditable, CdkEditOpen],
1191
+ exports: [CdkPopoverEdit, CdkPopoverEditTabOut, CdkRowHoverContent, CdkEditControl, CdkEditRevert, CdkEditClose, CdkEditable, CdkEditOpen]
1192
+ });
1193
+ static ɵinj = i0.ɵɵngDeclareInjector({
1194
+ minVersion: "12.0.0",
1195
+ version: "20.2.0-next.2",
1196
+ ngImport: i0,
1197
+ type: CdkPopoverEditModule,
1198
+ imports: [OverlayModule]
1199
+ });
1142
1200
  }
1143
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.2", ngImport: i0, type: CdkPopoverEditModule, decorators: [{
1144
- type: NgModule,
1145
- args: [{
1146
- imports: [OverlayModule, ...EXPORTED_DECLARATIONS],
1147
- exports: EXPORTED_DECLARATIONS,
1148
- }]
1149
- }] });
1201
+ i0.ɵɵngDeclareClassMetadata({
1202
+ minVersion: "12.0.0",
1203
+ version: "20.2.0-next.2",
1204
+ ngImport: i0,
1205
+ type: CdkPopoverEditModule,
1206
+ decorators: [{
1207
+ type: NgModule,
1208
+ args: [{
1209
+ imports: [OverlayModule, ...EXPORTED_DECLARATIONS],
1210
+ exports: EXPORTED_DECLARATIONS
1211
+ }]
1212
+ }]
1213
+ });
1150
1214
 
1151
1215
  export { CdkEditClose, CdkEditControl, CdkEditOpen, CdkEditRevert, CdkEditable, CdkPopoverEdit, CdkPopoverEditModule, CdkPopoverEditTabOut, CdkRowHoverContent, EditEventDispatcher, EditRef, FocusDispatcher, FormValueContainer, HoverContentState, CELL_SELECTOR as _CELL_SELECTOR, closest as _closest };
1152
1216
  //# sourceMappingURL=popover-edit.mjs.map