@angular/cdk-experimental 20.2.0-next.2 → 20.2.0-rc.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.
Files changed (80) hide show
  1. package/accordion/index.d.ts +3 -3
  2. package/{accordion.d-CC6dGMlv.d.ts → accordion.d.d.ts} +7 -5
  3. package/{expansion.d-Zkcf-XJU.d.ts → expansion.d.d.ts} +3 -3
  4. package/fesm2022/accordion.mjs +17 -17
  5. package/fesm2022/accordion.mjs.map +1 -1
  6. package/fesm2022/{accordion-D9JoxtzT.mjs → accordion2.mjs} +8 -6
  7. package/fesm2022/accordion2.mjs.map +1 -0
  8. package/fesm2022/cdk-experimental.mjs +1 -1
  9. package/fesm2022/cdk-experimental.mjs.map +1 -1
  10. package/fesm2022/column-resize.mjs +54 -54
  11. package/fesm2022/column-resize.mjs.map +1 -1
  12. package/fesm2022/combobox.mjs +10 -10
  13. package/fesm2022/combobox.mjs.map +1 -1
  14. package/fesm2022/deferred-content.mjs +6 -6
  15. package/fesm2022/deferred-content.mjs.map +1 -1
  16. package/fesm2022/{expansion-C9iQLHOG.mjs → expansion.mjs} +2 -2
  17. package/fesm2022/expansion.mjs.map +1 -0
  18. package/fesm2022/{list-focus-Czul8jzR.mjs → list-navigation.mjs} +67 -62
  19. package/fesm2022/list-navigation.mjs.map +1 -0
  20. package/fesm2022/list.mjs +355 -0
  21. package/fesm2022/list.mjs.map +1 -0
  22. package/fesm2022/listbox.mjs +10 -11
  23. package/fesm2022/listbox.mjs.map +1 -1
  24. package/fesm2022/option.mjs +231 -0
  25. package/fesm2022/option.mjs.map +1 -0
  26. package/fesm2022/{polyfill-CXksG4af.mjs → polyfill.mjs} +2 -2
  27. package/fesm2022/polyfill.mjs.map +1 -0
  28. package/fesm2022/popover-edit.mjs +44 -44
  29. package/fesm2022/popover-edit.mjs.map +1 -1
  30. package/fesm2022/radio-group.mjs +44 -11
  31. package/fesm2022/radio-group.mjs.map +1 -1
  32. package/fesm2022/radio-group2.mjs +143 -0
  33. package/fesm2022/radio-group2.mjs.map +1 -0
  34. package/fesm2022/scrolling.mjs +7 -7
  35. package/fesm2022/scrolling.mjs.map +1 -1
  36. package/fesm2022/selection.mjs +19 -19
  37. package/fesm2022/selection.mjs.map +1 -1
  38. package/fesm2022/table-scroll-container.mjs +7 -7
  39. package/fesm2022/table-scroll-container.mjs.map +1 -1
  40. package/fesm2022/tabs.mjs +20 -20
  41. package/fesm2022/tabs.mjs.map +1 -1
  42. package/fesm2022/{tabs-hMdwtXv2.mjs → tabs2.mjs} +34 -70
  43. package/fesm2022/tabs2.mjs.map +1 -0
  44. package/fesm2022/toolbar.mjs +168 -0
  45. package/fesm2022/toolbar.mjs.map +1 -0
  46. package/fesm2022/toolbar2.mjs +224 -0
  47. package/fesm2022/toolbar2.mjs.map +1 -0
  48. package/fesm2022/tree.mjs +140 -219
  49. package/fesm2022/tree.mjs.map +1 -1
  50. package/fesm2022/ui-patterns.mjs +8 -8
  51. package/fesm2022/ui-patterns.mjs.map +1 -1
  52. package/list.d.d.ts +207 -0
  53. package/listbox/index.d.ts +3 -4
  54. package/{listbox.d-Ckp1is82.d.ts → listbox.d.d.ts} +9 -62
  55. package/package.json +6 -2
  56. package/{pointer-event-manager.d-BqSm9Jh5.d.ts → pointer-event-manager.d.d.ts} +12 -8
  57. package/radio-group/index.d.ts +15 -7
  58. package/radio-group.d.d.ts +80 -0
  59. package/tabs/index.d.ts +4 -4
  60. package/{tabs.d-Db8oTrMB.d.ts → tabs.d.d.ts} +15 -30
  61. package/toolbar/index.d.ts +89 -0
  62. package/toolbar.d.d.ts +136 -0
  63. package/tree/index.d.ts +28 -63
  64. package/ui-patterns/index.d.ts +8 -8
  65. package/fesm2022/accordion-D9JoxtzT.mjs.map +0 -1
  66. package/fesm2022/expansion-C9iQLHOG.mjs.map +0 -1
  67. package/fesm2022/list-focus-Czul8jzR.mjs.map +0 -1
  68. package/fesm2022/list-selection-C41ApAbt.mjs +0 -136
  69. package/fesm2022/list-selection-C41ApAbt.mjs.map +0 -1
  70. package/fesm2022/list-typeahead-DIIbNJrP.mjs +0 -64
  71. package/fesm2022/list-typeahead-DIIbNJrP.mjs.map +0 -1
  72. package/fesm2022/option-CgeKz9_Q.mjs +0 -321
  73. package/fesm2022/option-CgeKz9_Q.mjs.map +0 -1
  74. package/fesm2022/polyfill-CXksG4af.mjs.map +0 -1
  75. package/fesm2022/radio-button-92xc4w-A.mjs +0 -203
  76. package/fesm2022/radio-button-92xc4w-A.mjs.map +0 -1
  77. package/fesm2022/tabs-hMdwtXv2.mjs.map +0 -1
  78. package/list-selection.d-fbAPr_N_.d.ts +0 -69
  79. package/list-typeahead.d-ljh3nJ9y.d.ts +0 -48
  80. package/radio-group.d-CFC0aKQM.d.ts +0 -114
package/fesm2022/tree.mjs CHANGED
@@ -4,16 +4,17 @@ import { _IdGenerator } from '@angular/cdk/a11y';
4
4
  import { Directionality } from '@angular/cdk/bidi';
5
5
  import * as i1 from '@angular/cdk-experimental/deferred-content';
6
6
  import { DeferredContentAware, DeferredContent } from '@angular/cdk-experimental/deferred-content';
7
- import { M as Modifier, L as ListFocus, a as ListNavigation, K as KeyboardEventManager, P as PointerEventManager } from './list-focus-Czul8jzR.mjs';
8
- import { L as ListSelection } from './list-selection-C41ApAbt.mjs';
9
- import { L as ListTypeahead } from './list-typeahead-DIIbNJrP.mjs';
10
- import { E as ExpansionControl, L as ListExpansion } from './expansion-C9iQLHOG.mjs';
7
+ import { List } from './list.mjs';
8
+ import { ExpansionControl, ListExpansion } from './expansion.mjs';
9
+ import { Modifier, KeyboardEventManager, PointerEventManager } from './list-navigation.mjs';
11
10
 
12
11
  /**
13
12
  * Represents an item in a Tree.
14
13
  */
15
14
  class TreeItemPattern {
16
15
  inputs;
16
+ /** The position of this item among its siblings. */
17
+ index = computed(() => this.tree().visibleItems().indexOf(this));
17
18
  /** The unique identifier used by the expansion behavior. */
18
19
  expansionId;
19
20
  /** Controls expansion for child items. */
@@ -33,9 +34,9 @@ class TreeItemPattern {
33
34
  /** The position of this item among its siblings (1-based). */
34
35
  posinset = computed(() => this.parent().children().indexOf(this) + 1);
35
36
  /** Whether the item is active. */
36
- active = computed(() => this.tree().focusManager.activeItem() === this);
37
+ active = computed(() => this.tree().activeItem() === this);
37
38
  /** The tabindex of the item. */
38
- tabindex = computed(() => this.tree().focusManager.getItemTabindex(this));
39
+ tabindex = computed(() => this.tree().listBehavior.getItemTabindex(this));
39
40
  /** Whether the item is selected. */
40
41
  selected = computed(() => {
41
42
  if (this.tree().nav()) {
@@ -81,14 +82,8 @@ class TreeItemPattern {
81
82
  /** Controls the state and interactions of a tree view. */
82
83
  class TreePattern {
83
84
  inputs;
84
- /** Controls focus for the all visible tree items. */
85
- focusManager;
86
- /** Controls navigation for all visible tree items. */
87
- navigationManager;
88
- /** Controls selection for all visible tree items. */
89
- selectionManager;
90
- /** Controls typeahead for all visible tree items. */
91
- typeaheadManager;
85
+ /** The list behavior for the tree. */
86
+ listBehavior;
92
87
  /** Controls expansion for direct children of the tree root (top-level items). */
93
88
  expansionManager;
94
89
  /** The root level is 0. */
@@ -96,11 +91,9 @@ class TreePattern {
96
91
  /** The root is always expanded. */
97
92
  expanded = () => true;
98
93
  /** The tabindex of the tree. */
99
- tabindex = computed(() => this.focusManager.getListTabindex());
94
+ tabindex = computed(() => this.listBehavior.tabindex());
100
95
  /** The id of the current active item. */
101
- activedescendant = computed(() => this.focusManager.getActiveDescendant());
102
- /** Whether the tree is performing a range selection. */
103
- inSelection = signal(false);
96
+ activedescendant = computed(() => this.listBehavior.activedescendant());
104
97
  /** The direct children of the root (top-level tree items). */
105
98
  children = computed(() => this.inputs.allItems().filter(item => item.level() === this.level() + 1));
106
99
  /** All currently visible tree items. An item is visible if their parent is expanded. */
@@ -136,67 +129,62 @@ class TreePattern {
136
129
  return this.inputs.textDirection() === 'rtl' ? 'ArrowLeft' : 'ArrowRight';
137
130
  });
138
131
  /** Represents the space key. Does nothing when the user is actively using typeahead. */
139
- dynamicSpaceKey = computed(() => (this.typeaheadManager.isTyping() ? '' : ' '));
132
+ dynamicSpaceKey = computed(() => (this.listBehavior.isTyping() ? '' : ' '));
140
133
  /** Regular expression to match characters for typeahead. */
141
134
  typeaheadRegexp = /^.$/;
142
- /** Uncommitted tree item for selecting a range of tree items. */
143
- anchorItem = signal(undefined);
144
- /**
145
- * Uncommitted tree item index for selecting a range of tree items.
146
- *
147
- * The index is computed in case the tree item position is changed caused by tree expansions.
148
- */
149
- anchorIndex = computed(() => this.anchorItem() ? this.visibleItems().indexOf(this.anchorItem()) : -1);
150
135
  /** The keydown event manager for the tree. */
151
136
  keydown = computed(() => {
152
137
  const manager = new KeyboardEventManager();
138
+ const list = this.listBehavior;
153
139
  if (!this.followFocus()) {
154
140
  manager
155
- .on(this.prevKey, () => this.prev())
156
- .on(this.nextKey, () => this.next())
157
- .on('Home', () => this.first())
158
- .on('End', () => this.last())
159
- .on(this.typeaheadRegexp, e => this.search(e.key));
141
+ .on(this.prevKey, () => list.prev())
142
+ .on(this.nextKey, () => list.next())
143
+ .on('Home', () => list.first())
144
+ .on('End', () => list.last())
145
+ .on(this.typeaheadRegexp, e => list.search(e.key));
160
146
  }
161
147
  if (this.followFocus()) {
162
148
  manager
163
- .on(this.prevKey, () => this.prev({ selectOne: true }))
164
- .on(this.nextKey, () => this.next({ selectOne: true }))
165
- .on('Home', () => this.first({ selectOne: true }))
166
- .on('End', () => this.last({ selectOne: true }))
167
- .on(this.typeaheadRegexp, e => this.search(e.key, { selectOne: true }));
149
+ .on(this.prevKey, () => list.prev({ selectOne: true }))
150
+ .on(this.nextKey, () => list.next({ selectOne: true }))
151
+ .on('Home', () => list.first({ selectOne: true }))
152
+ .on('End', () => list.last({ selectOne: true }))
153
+ .on(this.typeaheadRegexp, e => list.search(e.key, { selectOne: true }));
168
154
  }
169
155
  if (this.inputs.multi()) {
170
156
  manager
171
- .on(Modifier.Any, 'Shift', () => this.anchorItem.set(this.focusManager.activeItem()))
172
- .on(Modifier.Shift, this.prevKey, () => this.prev({ selectRange: true }))
173
- .on(Modifier.Shift, this.nextKey, () => this.next({ selectRange: true }))
174
- .on([Modifier.Ctrl | Modifier.Shift, Modifier.Meta | Modifier.Shift], 'Home', () => this.first({ selectRange: true, anchor: false }))
175
- .on([Modifier.Ctrl | Modifier.Shift, Modifier.Meta | Modifier.Shift], 'End', () => this.last({ selectRange: true, anchor: false }))
176
- .on(Modifier.Shift, 'Enter', () => this._updateSelection({ selectRange: true, anchor: false }))
177
- .on(Modifier.Shift, this.dynamicSpaceKey, () => this._updateSelection({ selectRange: true, anchor: false }));
157
+ // TODO: Tracking the anchor by index can break if the
158
+ // tree is expanded or collapsed causing the index to change.
159
+ .on(Modifier.Any, 'Shift', () => list.anchor(this.listBehavior.activeIndex()))
160
+ .on(Modifier.Shift, this.prevKey, () => list.prev({ selectRange: true }))
161
+ .on(Modifier.Shift, this.nextKey, () => list.next({ selectRange: true }))
162
+ .on([Modifier.Ctrl | Modifier.Shift, Modifier.Meta | Modifier.Shift], 'Home', () => list.first({ selectRange: true, anchor: false }))
163
+ .on([Modifier.Ctrl | Modifier.Shift, Modifier.Meta | Modifier.Shift], 'End', () => list.last({ selectRange: true, anchor: false }))
164
+ .on(Modifier.Shift, 'Enter', () => list.updateSelection({ selectRange: true, anchor: false }))
165
+ .on(Modifier.Shift, this.dynamicSpaceKey, () => list.updateSelection({ selectRange: true, anchor: false }));
178
166
  }
179
167
  if (!this.followFocus() && this.inputs.multi()) {
180
168
  manager
181
- .on(this.dynamicSpaceKey, () => this.selectionManager.toggle())
182
- .on('Enter', () => this.selectionManager.toggle())
183
- .on([Modifier.Ctrl, Modifier.Meta], 'A', () => this.selectionManager.toggleAll());
169
+ .on(this.dynamicSpaceKey, () => list.toggle())
170
+ .on('Enter', () => list.toggle())
171
+ .on([Modifier.Ctrl, Modifier.Meta], 'A', () => list.toggleAll());
184
172
  }
185
173
  if (!this.followFocus() && !this.inputs.multi()) {
186
- manager.on(this.dynamicSpaceKey, () => this.selectionManager.toggleOne());
187
- manager.on('Enter', () => this.selectionManager.toggleOne());
174
+ manager.on(this.dynamicSpaceKey, () => list.toggleOne());
175
+ manager.on('Enter', () => list.toggleOne());
188
176
  }
189
177
  if (this.inputs.multi() && this.followFocus()) {
190
178
  manager
191
- .on([Modifier.Ctrl, Modifier.Meta], this.prevKey, () => this.prev())
192
- .on([Modifier.Ctrl, Modifier.Meta], this.nextKey, () => this.next())
193
- .on([Modifier.Ctrl, Modifier.Meta], ' ', () => this.selectionManager.toggle())
194
- .on([Modifier.Ctrl, Modifier.Meta], 'Enter', () => this.selectionManager.toggle())
195
- .on([Modifier.Ctrl, Modifier.Meta], 'Home', () => this.first())
196
- .on([Modifier.Ctrl, Modifier.Meta], 'End', () => this.last())
179
+ .on([Modifier.Ctrl, Modifier.Meta], this.prevKey, () => list.prev())
180
+ .on([Modifier.Ctrl, Modifier.Meta], this.nextKey, () => list.next())
181
+ .on([Modifier.Ctrl, Modifier.Meta], ' ', () => list.toggle())
182
+ .on([Modifier.Ctrl, Modifier.Meta], 'Enter', () => list.toggle())
183
+ .on([Modifier.Ctrl, Modifier.Meta], 'Home', () => list.first())
184
+ .on([Modifier.Ctrl, Modifier.Meta], 'End', () => list.last())
197
185
  .on([Modifier.Ctrl, Modifier.Meta], 'A', () => {
198
- this.selectionManager.toggleAll();
199
- this.selectionManager.select(); // Ensure the currect item remains selected.
186
+ list.toggleAll();
187
+ list.select(); // Ensure the currect item remains selected.
200
188
  });
201
189
  }
202
190
  manager
@@ -234,34 +222,19 @@ class TreePattern {
234
222
  this.allItems = inputs.allItems;
235
223
  this.focusMode = inputs.focusMode;
236
224
  this.disabled = inputs.disabled;
237
- this.activeIndex = inputs.activeIndex;
225
+ this.activeItem = inputs.activeItem;
238
226
  this.skipDisabled = inputs.skipDisabled;
239
227
  this.wrap = inputs.wrap;
240
228
  this.orientation = inputs.orientation;
241
229
  this.textDirection = inputs.textDirection;
242
230
  this.multi = computed(() => (this.nav() ? false : this.inputs.multi()));
243
- this.value = inputs.value;
244
231
  this.selectionMode = inputs.selectionMode;
245
232
  this.typeaheadDelay = inputs.typeaheadDelay;
246
- this.focusManager = new ListFocus({
247
- ...inputs,
248
- items: this.visibleItems,
249
- });
250
- this.navigationManager = new ListNavigation({
251
- ...inputs,
252
- wrap: computed(() => this.inputs.wrap() && !this.inSelection()),
253
- items: this.visibleItems,
254
- focusManager: this.focusManager,
255
- });
256
- this.selectionManager = new ListSelection({
257
- ...inputs,
258
- items: this.visibleItems,
259
- focusManager: this.focusManager,
260
- });
261
- this.typeaheadManager = new ListTypeahead({
233
+ this.value = inputs.value;
234
+ this.listBehavior = new List({
262
235
  ...inputs,
263
236
  items: this.visibleItems,
264
- focusManager: this.focusManager,
237
+ multi: this.multi,
265
238
  });
266
239
  this.expansionManager = new ListExpansion({
267
240
  multiExpandable: () => true,
@@ -278,22 +251,22 @@ class TreePattern {
278
251
  * Otherwise, sets focus to the first focusable tree item.
279
252
  */
280
253
  setDefaultState() {
281
- let firstItemIndex;
282
- for (const [index, item] of this.allItems().entries()) {
254
+ let firstItem;
255
+ for (const item of this.allItems()) {
283
256
  if (!item.visible())
284
257
  continue;
285
- if (!this.focusManager.isFocusable(item))
258
+ if (!this.listBehavior.isFocusable(item))
286
259
  continue;
287
- if (firstItemIndex === undefined) {
288
- firstItemIndex = index;
260
+ if (firstItem === undefined) {
261
+ firstItem = item;
289
262
  }
290
263
  if (item.selected()) {
291
- this.activeIndex.set(index);
264
+ this.activeItem.set(item);
292
265
  return;
293
266
  }
294
267
  }
295
- if (firstItemIndex !== undefined) {
296
- this.activeIndex.set(firstItemIndex);
268
+ if (firstItem !== undefined) {
269
+ this.activeItem.set(firstItem);
297
270
  }
298
271
  }
299
272
  /** Handles keydown events on the tree. */
@@ -308,36 +281,18 @@ class TreePattern {
308
281
  this.pointerdown().handle(event);
309
282
  }
310
283
  }
311
- /** Navigates to the first visible tree item in the tree. */
312
- first(opts) {
313
- this._navigate(opts, () => this.navigationManager.first());
314
- }
315
- /** Navigates to the last visible tree item in the tree. */
316
- last(opts) {
317
- this._navigate(opts, () => this.navigationManager.last());
318
- }
319
- /** Navigates to the next visible tree item in the tree. */
320
- next(opts) {
321
- this._navigate(opts, () => this.navigationManager.next());
322
- }
323
- /** Navigates to the previous visible tree item in the tree. */
324
- prev(opts) {
325
- this._navigate(opts, () => this.navigationManager.prev());
326
- }
327
284
  /** Navigates to the given tree item in the tree. */
328
- goto(event, opts) {
329
- const item = this._getItem(event);
330
- this._navigate(opts, () => this.navigationManager.goto(item));
285
+ goto(e, opts) {
286
+ const item = this._getItem(e);
287
+ if (!item)
288
+ return;
289
+ this.listBehavior.goto(item, opts);
331
290
  this.toggleExpansion(item);
332
291
  }
333
- /** Handles typeahead search navigation for the tree. */
334
- search(char, opts) {
335
- this._navigate(opts, () => this.typeaheadManager.search(char));
336
- }
337
292
  /** Toggles to expand or collapse a tree item. */
338
293
  toggleExpansion(item) {
339
- item ??= this.focusManager.activeItem();
340
- if (!item || !this.focusManager.isFocusable(item))
294
+ item ??= this.activeItem();
295
+ if (!item || !this.listBehavior.isFocusable(item))
341
296
  return;
342
297
  if (!item.expandable())
343
298
  return;
@@ -350,67 +305,40 @@ class TreePattern {
350
305
  }
351
306
  /** Expands a tree item. */
352
307
  expand(item) {
353
- item ??= this.focusManager.activeItem();
354
- if (!item || !this.focusManager.isFocusable(item))
308
+ item ??= this.activeItem();
309
+ if (!item || !this.listBehavior.isFocusable(item))
355
310
  return;
356
311
  if (item.expandable() && !item.expanded()) {
357
312
  item.expansion.open();
358
313
  }
359
314
  else if (item.expanded() && item.children().length > 0) {
360
315
  const firstChild = item.children()[0];
361
- if (this.focusManager.isFocusable(firstChild)) {
362
- this.navigationManager.goto(firstChild);
316
+ if (this.listBehavior.isFocusable(firstChild)) {
317
+ this.listBehavior.goto(firstChild);
363
318
  }
364
319
  }
365
320
  }
366
321
  /** Expands all sibling tree items including itself. */
367
322
  expandSiblings(item) {
368
- item ??= this.focusManager.activeItem();
369
- const siblings = item.parent()?.children();
323
+ item ??= this.activeItem();
324
+ const siblings = item?.parent()?.children();
370
325
  siblings?.forEach(item => this.expand(item));
371
326
  }
372
327
  /** Collapses a tree item. */
373
328
  collapse(item) {
374
- item ??= this.focusManager.activeItem();
375
- if (!item || !this.focusManager.isFocusable(item))
329
+ item ??= this.activeItem();
330
+ if (!item || !this.listBehavior.isFocusable(item))
376
331
  return;
377
332
  if (item.expandable() && item.expanded()) {
378
333
  item.expansion.close();
379
334
  }
380
335
  else if (item.parent() && item.parent() !== this) {
381
336
  const parentItem = item.parent();
382
- if (parentItem instanceof TreeItemPattern && this.focusManager.isFocusable(parentItem)) {
383
- this.navigationManager.goto(parentItem);
337
+ if (parentItem instanceof TreeItemPattern && this.listBehavior.isFocusable(parentItem)) {
338
+ this.listBehavior.goto(parentItem);
384
339
  }
385
340
  }
386
341
  }
387
- /** Safely performs a navigation operation. */
388
- _navigate(opts = {}, operation) {
389
- if (opts?.selectRange) {
390
- this.inSelection.set(true);
391
- this.selectionManager.rangeStartIndex.set(this.anchorIndex());
392
- }
393
- const moved = operation();
394
- if (moved) {
395
- this._updateSelection(opts);
396
- }
397
- this.inSelection.set(false);
398
- }
399
- /** Handles updating selection for the tree. */
400
- _updateSelection(opts = { anchor: true }) {
401
- if (opts.toggle) {
402
- this.selectionManager.toggle();
403
- }
404
- if (opts.selectOne) {
405
- this.selectionManager.selectOne();
406
- }
407
- if (opts.selectRange) {
408
- this.selectionManager.selectRange();
409
- }
410
- if (!opts.anchor) {
411
- this.anchorItem.set(this.visibleItems()[this.selectionManager.rangeStartIndex()]);
412
- }
413
- }
414
342
  /** Retrieves the TreeItemPattern associated with a DOM event, if any. */
415
343
  _getItem(event) {
416
344
  if (!(event.target instanceof HTMLElement)) {
@@ -453,8 +381,6 @@ function sortDirectives(a, b) {
453
381
  class CdkTree {
454
382
  /** All CdkTreeItem instances within this tree. */
455
383
  _unorderedItems = signal(new Set(), ...(ngDevMode ? [{ debugName: "_unorderedItems" }] : []));
456
- /** All CdkGroup instances within this tree. */
457
- unorderedGroups = signal(new Set(), ...(ngDevMode ? [{ debugName: "unorderedGroups" }] : []));
458
384
  /** Orientation of the tree. */
459
385
  orientation = input('vertical', ...(ngDevMode ? [{ debugName: "orientation" }] : []));
460
386
  /** Whether multi-selection is allowed. */
@@ -483,7 +409,7 @@ class CdkTree {
483
409
  pattern = new TreePattern({
484
410
  ...this,
485
411
  allItems: computed(() => [...this._unorderedItems()].sort(sortDirectives).map(item => item.pattern)),
486
- activeIndex: signal(0),
412
+ activeItem: signal(undefined),
487
413
  });
488
414
  /** Whether the tree has received focus yet. */
489
415
  _hasFocused = signal(false, ...(ngDevMode ? [{ debugName: "_hasFocused" }] : []));
@@ -498,29 +424,17 @@ class CdkTree {
498
424
  this._hasFocused.set(true);
499
425
  }
500
426
  register(child) {
501
- if (child instanceof CdkTreeItemGroup) {
502
- this.unorderedGroups().add(child);
503
- this.unorderedGroups.set(new Set(this.unorderedGroups()));
504
- }
505
- if (child instanceof CdkTreeItem) {
506
- this._unorderedItems().add(child);
507
- this._unorderedItems.set(new Set(this._unorderedItems()));
508
- }
427
+ this._unorderedItems().add(child);
428
+ this._unorderedItems.set(new Set(this._unorderedItems()));
509
429
  }
510
- deregister(child) {
511
- if (child instanceof CdkTreeItemGroup) {
512
- this.unorderedGroups().delete(child);
513
- this.unorderedGroups.set(new Set(this.unorderedGroups()));
514
- }
515
- if (child instanceof CdkTreeItem) {
516
- this._unorderedItems().delete(child);
517
- this._unorderedItems.set(new Set(this._unorderedItems()));
518
- }
430
+ unregister(child) {
431
+ this._unorderedItems().delete(child);
432
+ this._unorderedItems.set(new Set(this._unorderedItems()));
519
433
  }
520
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.1", ngImport: i0, type: CdkTree, deps: [], target: i0.ɵɵFactoryTarget.Directive });
521
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.2.0-next.1", type: CdkTree, isStandalone: true, selector: "[cdkTree]", inputs: { orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, multi: { classPropertyName: "multi", publicName: "multi", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, selectionMode: { classPropertyName: "selectionMode", publicName: "selectionMode", isSignal: true, isRequired: false, transformFunction: null }, focusMode: { classPropertyName: "focusMode", publicName: "focusMode", isSignal: true, isRequired: false, transformFunction: null }, wrap: { classPropertyName: "wrap", publicName: "wrap", isSignal: true, isRequired: false, transformFunction: null }, skipDisabled: { classPropertyName: "skipDisabled", publicName: "skipDisabled", isSignal: true, isRequired: false, transformFunction: null }, typeaheadDelay: { classPropertyName: "typeaheadDelay", publicName: "typeaheadDelay", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, nav: { classPropertyName: "nav", publicName: "nav", isSignal: true, isRequired: false, transformFunction: null }, currentType: { classPropertyName: "currentType", publicName: "currentType", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, host: { attributes: { "role": "tree" }, listeners: { "keydown": "pattern.onKeydown($event)", "pointerdown": "pattern.onPointerdown($event)", "focusin": "onFocus()" }, properties: { "attr.aria-orientation": "pattern.orientation()", "attr.aria-multiselectable": "pattern.multi()", "attr.aria-disabled": "pattern.disabled()", "attr.aria-activedescendant": "pattern.activedescendant()", "tabindex": "pattern.tabindex()" }, classAttribute: "cdk-tree" }, exportAs: ["cdkTree"], ngImport: i0 });
434
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-rc.1", ngImport: i0, type: CdkTree, deps: [], target: i0.ɵɵFactoryTarget.Directive });
435
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.2.0-rc.1", type: CdkTree, isStandalone: true, selector: "[cdkTree]", inputs: { orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, multi: { classPropertyName: "multi", publicName: "multi", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, selectionMode: { classPropertyName: "selectionMode", publicName: "selectionMode", isSignal: true, isRequired: false, transformFunction: null }, focusMode: { classPropertyName: "focusMode", publicName: "focusMode", isSignal: true, isRequired: false, transformFunction: null }, wrap: { classPropertyName: "wrap", publicName: "wrap", isSignal: true, isRequired: false, transformFunction: null }, skipDisabled: { classPropertyName: "skipDisabled", publicName: "skipDisabled", isSignal: true, isRequired: false, transformFunction: null }, typeaheadDelay: { classPropertyName: "typeaheadDelay", publicName: "typeaheadDelay", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, nav: { classPropertyName: "nav", publicName: "nav", isSignal: true, isRequired: false, transformFunction: null }, currentType: { classPropertyName: "currentType", publicName: "currentType", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, host: { attributes: { "role": "tree" }, listeners: { "keydown": "pattern.onKeydown($event)", "pointerdown": "pattern.onPointerdown($event)", "focusin": "onFocus()" }, properties: { "attr.aria-orientation": "pattern.orientation()", "attr.aria-multiselectable": "pattern.multi()", "attr.aria-disabled": "pattern.disabled()", "attr.aria-activedescendant": "pattern.activedescendant()", "tabindex": "pattern.tabindex()" }, classAttribute: "cdk-tree" }, exportAs: ["cdkTree"], ngImport: i0 });
522
436
  }
523
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.1", ngImport: i0, type: CdkTree, decorators: [{
437
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-rc.1", ngImport: i0, type: CdkTree, decorators: [{
524
438
  type: Directive,
525
439
  args: [{
526
440
  selector: '[cdkTree]',
@@ -547,63 +461,72 @@ class CdkTreeItem {
547
461
  _elementRef = inject(ElementRef);
548
462
  /** A unique identifier for the tree item. */
549
463
  _id = inject(_IdGenerator).getId('cdk-tree-item-');
550
- /** The top level CdkTree. */
551
- _tree = inject((CdkTree));
552
- /** The parent CdkTreeItem. */
553
- _treeItem = inject((CdkTreeItem), { optional: true, skipSelf: true });
554
- /** The parent CdkGroup, if any. */
555
- _parentGroup = inject((CdkTreeItemGroup), { optional: true });
556
- /** The top level TreePattern. */
557
- _treePattern = computed(() => this._tree.pattern, ...(ngDevMode ? [{ debugName: "_treePattern" }] : []));
558
- /** The parent TreeItemPattern. */
559
- _parentPattern = computed(() => this._treeItem?.pattern ?? this._treePattern(), ...(ngDevMode ? [{ debugName: "_parentPattern" }] : []));
464
+ /** The owned tree item group. */
465
+ _group = signal(undefined, ...(ngDevMode ? [{ debugName: "_group" }] : []));
466
+ /** The id of the owned group. */
467
+ ownsId = computed(() => this._group()?.id, ...(ngDevMode ? [{ debugName: "ownsId" }] : []));
560
468
  /** The host native element. */
561
469
  element = computed(() => this._elementRef.nativeElement, ...(ngDevMode ? [{ debugName: "element" }] : []));
562
470
  /** The value of the tree item. */
563
471
  value = input.required(...(ngDevMode ? [{ debugName: "value" }] : []));
472
+ /** The parent tree root or tree item group. */
473
+ parent = input.required(...(ngDevMode ? [{ debugName: "parent" }] : []));
564
474
  /** Whether the tree item is disabled. */
565
475
  disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
566
476
  /** Optional label for typeahead. Defaults to the element's textContent. */
567
477
  label = input(...(ngDevMode ? [undefined, { debugName: "label" }] : []));
568
478
  /** Search term for typeahead. */
569
479
  searchTerm = computed(() => this.label() ?? this.element().textContent, ...(ngDevMode ? [{ debugName: "searchTerm" }] : []));
570
- /** Manual group assignment. */
571
- group = signal(undefined, ...(ngDevMode ? [{ debugName: "group" }] : []));
480
+ /** The tree root. */
481
+ tree = computed(() => {
482
+ if (this.parent() instanceof CdkTree) {
483
+ return this.parent();
484
+ }
485
+ return this.parent().ownedBy().tree();
486
+ }, ...(ngDevMode ? [{ debugName: "tree" }] : []));
572
487
  /** The UI pattern for this item. */
573
- pattern = new TreeItemPattern({
574
- ...this,
575
- id: () => this._id,
576
- tree: this._treePattern,
577
- parent: this._parentPattern,
578
- children: computed(() => this.group()
579
- ?.children()
580
- .map(item => item.pattern) ?? []),
581
- hasChildren: computed(() => !!this.group()),
582
- });
488
+ pattern;
583
489
  constructor() {
584
- afterRenderEffect(() => {
585
- const group = [...this._tree.unorderedGroups()].find(group => group.value() === this.value());
586
- if (group) {
587
- this.group.set(group);
588
- }
589
- });
590
490
  // Updates the visibility of the owned group.
591
491
  afterRenderEffect(() => {
592
- this.group()?.visible.set(this.pattern.expanded());
492
+ this._group()?.visible.set(this.pattern.expanded());
593
493
  });
594
494
  }
595
495
  ngOnInit() {
596
- this._tree.register(this);
597
- this._parentGroup?.register(this);
496
+ this.parent().register(this);
497
+ this.tree().register(this);
498
+ const treePattern = computed(() => this.tree().pattern, ...(ngDevMode ? [{ debugName: "treePattern" }] : []));
499
+ const parentPattern = computed(() => {
500
+ if (this.parent() instanceof CdkTree) {
501
+ return treePattern();
502
+ }
503
+ return this.parent().ownedBy().pattern;
504
+ }, ...(ngDevMode ? [{ debugName: "parentPattern" }] : []));
505
+ this.pattern = new TreeItemPattern({
506
+ ...this,
507
+ id: () => this._id,
508
+ tree: treePattern,
509
+ parent: parentPattern,
510
+ children: computed(() => this._group()
511
+ ?.children()
512
+ .map(item => item.pattern) ?? []),
513
+ hasChildren: computed(() => !!this._group()),
514
+ });
598
515
  }
599
516
  ngOnDestroy() {
600
- this._tree.deregister(this);
601
- this._parentGroup?.deregister(this);
517
+ this.parent().unregister(this);
518
+ this.tree().unregister(this);
519
+ }
520
+ register(group) {
521
+ this._group.set(group);
602
522
  }
603
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.1", ngImport: i0, type: CdkTreeItem, deps: [], target: i0.ɵɵFactoryTarget.Directive });
604
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.2.0-next.1", type: CdkTreeItem, isStandalone: true, selector: "[cdkTreeItem]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "treeitem" }, properties: { "class.cdk-active": "pattern.active()", "id": "pattern.id()", "attr.aria-expanded": "pattern.expandable() ? pattern.expanded() : null", "attr.aria-selected": "pattern.selected()", "attr.aria-current": "pattern.current()", "attr.aria-disabled": "pattern.disabled()", "attr.aria-level": "pattern.level()", "attr.aria-owns": "group()?.id", "attr.aria-setsize": "pattern.setsize()", "attr.aria-posinset": "pattern.posinset()", "attr.tabindex": "pattern.tabindex()", "attr.inert": "pattern.visible() ? null : true" }, classAttribute: "cdk-treeitem" }, exportAs: ["cdkTreeItem"], ngImport: i0 });
523
+ unregister() {
524
+ this._group.set(undefined);
525
+ }
526
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-rc.1", ngImport: i0, type: CdkTreeItem, deps: [], target: i0.ɵɵFactoryTarget.Directive });
527
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.2.0-rc.1", type: CdkTreeItem, isStandalone: true, selector: "[cdkTreeItem]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null }, parent: { classPropertyName: "parent", publicName: "parent", isSignal: true, isRequired: true, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "treeitem" }, properties: { "class.cdk-active": "pattern.active()", "id": "pattern.id()", "attr.aria-expanded": "pattern.expandable() ? pattern.expanded() : null", "attr.aria-selected": "pattern.selected()", "attr.aria-current": "pattern.current()", "attr.aria-disabled": "pattern.disabled()", "attr.aria-level": "pattern.level()", "attr.aria-owns": "ownsId()", "attr.aria-setsize": "pattern.setsize()", "attr.aria-posinset": "pattern.posinset()", "attr.tabindex": "pattern.tabindex()", "attr.inert": "pattern.visible() ? null : true" }, classAttribute: "cdk-treeitem" }, exportAs: ["cdkTreeItem"], ngImport: i0 });
605
528
  }
606
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.1", ngImport: i0, type: CdkTreeItem, decorators: [{
529
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-rc.1", ngImport: i0, type: CdkTreeItem, decorators: [{
607
530
  type: Directive,
608
531
  args: [{
609
532
  selector: '[cdkTreeItem]',
@@ -618,7 +541,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.1",
618
541
  '[attr.aria-current]': 'pattern.current()',
619
542
  '[attr.aria-disabled]': 'pattern.disabled()',
620
543
  '[attr.aria-level]': 'pattern.level()',
621
- '[attr.aria-owns]': 'group()?.id',
544
+ '[attr.aria-owns]': 'ownsId()',
622
545
  '[attr.aria-setsize]': 'pattern.setsize()',
623
546
  '[attr.aria-posinset]': 'pattern.posinset()',
624
547
  '[attr.tabindex]': 'pattern.tabindex()',
@@ -634,8 +557,6 @@ class CdkTreeItemGroup {
634
557
  _elementRef = inject(ElementRef);
635
558
  /** The DeferredContentAware host directive. */
636
559
  _deferredContentAware = inject(DeferredContentAware);
637
- /** The top level CdkTree. */
638
- _tree = inject((CdkTree));
639
560
  /** All groupable items that are descendants of the group. */
640
561
  _unorderedItems = signal(new Set(), ...(ngDevMode ? [{ debugName: "_unorderedItems" }] : []));
641
562
  /** The host native element. */
@@ -646,8 +567,8 @@ class CdkTreeItemGroup {
646
567
  visible = signal(true, ...(ngDevMode ? [{ debugName: "visible" }] : []));
647
568
  /** Child items within this group. */
648
569
  children = computed(() => [...this._unorderedItems()].sort(sortDirectives), ...(ngDevMode ? [{ debugName: "children" }] : []));
649
- /** Identifier for matching the group owner. */
650
- value = input.required(...(ngDevMode ? [{ debugName: "value" }] : []));
570
+ /** Tree item that owns the group. */
571
+ ownedBy = input.required(...(ngDevMode ? [{ debugName: "ownedBy" }] : []));
651
572
  constructor() {
652
573
  // Connect the group's hidden state to the DeferredContentAware's visibility.
653
574
  afterRenderEffect(() => {
@@ -655,23 +576,23 @@ class CdkTreeItemGroup {
655
576
  });
656
577
  }
657
578
  ngOnInit() {
658
- this._tree.register(this);
579
+ this.ownedBy().register(this);
659
580
  }
660
581
  ngOnDestroy() {
661
- this._tree.deregister(this);
582
+ this.ownedBy().unregister();
662
583
  }
663
584
  register(child) {
664
585
  this._unorderedItems().add(child);
665
586
  this._unorderedItems.set(new Set(this._unorderedItems()));
666
587
  }
667
- deregister(child) {
588
+ unregister(child) {
668
589
  this._unorderedItems().delete(child);
669
590
  this._unorderedItems.set(new Set(this._unorderedItems()));
670
591
  }
671
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.1", ngImport: i0, type: CdkTreeItemGroup, deps: [], target: i0.ɵɵFactoryTarget.Directive });
672
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.2.0-next.1", type: CdkTreeItemGroup, isStandalone: true, selector: "[cdkTreeItemGroup]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null } }, host: { attributes: { "role": "group" }, properties: { "id": "id", "attr.inert": "visible() ? null : true" }, classAttribute: "cdk-treeitem-group" }, exportAs: ["cdkTreeItemGroup"], hostDirectives: [{ directive: i1.DeferredContentAware, inputs: ["preserveContent", "preserveContent"] }], ngImport: i0 });
592
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-rc.1", ngImport: i0, type: CdkTreeItemGroup, deps: [], target: i0.ɵɵFactoryTarget.Directive });
593
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.2.0-rc.1", type: CdkTreeItemGroup, isStandalone: true, selector: "[cdkTreeItemGroup]", inputs: { ownedBy: { classPropertyName: "ownedBy", publicName: "ownedBy", isSignal: true, isRequired: true, transformFunction: null } }, host: { attributes: { "role": "group" }, properties: { "id": "id", "attr.inert": "visible() ? null : true" }, classAttribute: "cdk-treeitem-group" }, exportAs: ["cdkTreeItemGroup"], hostDirectives: [{ directive: i1.DeferredContentAware, inputs: ["preserveContent", "preserveContent"] }], ngImport: i0 });
673
594
  }
674
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.1", ngImport: i0, type: CdkTreeItemGroup, decorators: [{
595
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-rc.1", ngImport: i0, type: CdkTreeItemGroup, decorators: [{
675
596
  type: Directive,
676
597
  args: [{
677
598
  selector: '[cdkTreeItemGroup]',
@@ -695,10 +616,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.1",
695
616
  * for a `CdkTreeItemGroup`. This content can be lazily loaded.
696
617
  */
697
618
  class CdkTreeItemGroupContent {
698
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.1", ngImport: i0, type: CdkTreeItemGroupContent, deps: [], target: i0.ɵɵFactoryTarget.Directive });
699
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-next.1", type: CdkTreeItemGroupContent, isStandalone: true, selector: "ng-template[cdkTreeItemGroupContent]", hostDirectives: [{ directive: i1.DeferredContent }], ngImport: i0 });
619
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-rc.1", ngImport: i0, type: CdkTreeItemGroupContent, deps: [], target: i0.ɵɵFactoryTarget.Directive });
620
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0-rc.1", type: CdkTreeItemGroupContent, isStandalone: true, selector: "ng-template[cdkTreeItemGroupContent]", hostDirectives: [{ directive: i1.DeferredContent }], ngImport: i0 });
700
621
  }
701
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.1", ngImport: i0, type: CdkTreeItemGroupContent, decorators: [{
622
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-rc.1", ngImport: i0, type: CdkTreeItemGroupContent, decorators: [{
702
623
  type: Directive,
703
624
  args: [{
704
625
  selector: 'ng-template[cdkTreeItemGroupContent]',