@angular/cdk-experimental 20.0.0-next.0 → 20.0.0-next.10

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 (45) hide show
  1. package/column-resize/index.d.ts +276 -289
  2. package/combobox/index.d.ts +15 -39
  3. package/deferred-content/index.d.ts +37 -0
  4. package/fesm2022/cdk-experimental.mjs +1 -1
  5. package/fesm2022/cdk-experimental.mjs.map +1 -1
  6. package/fesm2022/column-resize.mjs +139 -70
  7. package/fesm2022/column-resize.mjs.map +1 -1
  8. package/fesm2022/combobox.mjs +19 -26
  9. package/fesm2022/combobox.mjs.map +1 -1
  10. package/fesm2022/deferred-content.mjs +60 -0
  11. package/fesm2022/deferred-content.mjs.map +1 -0
  12. package/fesm2022/list-focus-Di7m_z_6.mjs +382 -0
  13. package/fesm2022/list-focus-Di7m_z_6.mjs.map +1 -0
  14. package/fesm2022/listbox.mjs +42 -21
  15. package/fesm2022/listbox.mjs.map +1 -1
  16. package/fesm2022/option-f_gNslw8.mjs +367 -0
  17. package/fesm2022/option-f_gNslw8.mjs.map +1 -0
  18. package/fesm2022/polyfill-CXksG4af.mjs +14 -0
  19. package/fesm2022/polyfill-CXksG4af.mjs.map +1 -0
  20. package/fesm2022/popover-edit.mjs +92 -81
  21. package/fesm2022/popover-edit.mjs.map +1 -1
  22. package/fesm2022/scrolling.mjs +7 -11
  23. package/fesm2022/scrolling.mjs.map +1 -1
  24. package/fesm2022/selection.mjs +19 -27
  25. package/fesm2022/selection.mjs.map +1 -1
  26. package/fesm2022/table-scroll-container.mjs +8 -13
  27. package/fesm2022/table-scroll-container.mjs.map +1 -1
  28. package/fesm2022/tabs-BunANY1M.mjs +176 -0
  29. package/fesm2022/tabs-BunANY1M.mjs.map +1 -0
  30. package/fesm2022/tabs.mjs +225 -0
  31. package/fesm2022/tabs.mjs.map +1 -0
  32. package/fesm2022/ui-patterns.mjs +12 -603
  33. package/fesm2022/ui-patterns.mjs.map +1 -1
  34. package/index.d.ts +2 -2
  35. package/list-navigation.d-DfOSxsSp.d.ts +247 -0
  36. package/listbox/index.d.ts +46 -39
  37. package/listbox.d-QWPLmxRe.d.ts +193 -0
  38. package/package.json +13 -2
  39. package/popover-edit/index.d.ts +269 -315
  40. package/scrolling/index.d.ts +34 -47
  41. package/selection/index.d.ts +119 -161
  42. package/table-scroll-container/index.d.ts +6 -14
  43. package/tabs/index.d.ts +128 -0
  44. package/tabs.d-BAo141mw.d.ts +110 -0
  45. package/ui-patterns/index.d.ts +4 -391
@@ -1,9 +1,10 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, contentChildren, computed, input, booleanAttribute, model, Directive, ElementRef } from '@angular/core';
3
- import { ListboxPattern, OptionPattern } from '@angular/cdk-experimental/ui-patterns';
2
+ import { inject, contentChildren, computed, input, booleanAttribute, model, signal, effect, Directive, ElementRef } from '@angular/core';
4
3
  import { Directionality } from '@angular/cdk/bidi';
5
4
  import { toSignal } from '@angular/core/rxjs-interop';
6
5
  import { _IdGenerator } from '@angular/cdk/a11y';
6
+ import { L as ListboxPattern, O as OptionPattern } from './option-f_gNslw8.mjs';
7
+ import './list-focus-Di7m_z_6.mjs';
7
8
 
8
9
  /**
9
10
  * A listbox container.
@@ -13,9 +14,9 @@ import { _IdGenerator } from '@angular/cdk/a11y';
13
14
  *
14
15
  * ```html
15
16
  * <ul cdkListbox>
16
- * <li cdkOption>Item 1</li>
17
- * <li cdkOption>Item 2</li>
18
- * <li cdkOption>Item 3</li>
17
+ * <li [value]="1" cdkOption>Item 1</li>
18
+ * <li [value]="2" cdkOption>Item 2</li>
19
+ * <li [value]="3" cdkOption>Item 3</li>
19
20
  * </ul>
20
21
  * ```
21
22
  */
@@ -33,7 +34,7 @@ class CdkListbox {
33
34
  /** Whether the list is vertically or horizontally oriented. */
34
35
  orientation = input('vertical');
35
36
  /** Whether multiple items in the list can be selected at once. */
36
- multiselectable = input(false, { transform: booleanAttribute });
37
+ multi = input(false, { transform: booleanAttribute });
37
38
  /** Whether focus should wrap when navigating. */
38
39
  wrap = input(true, { transform: booleanAttribute });
39
40
  /** Whether disabled items in the list should be skipped when navigating. */
@@ -46,9 +47,10 @@ class CdkListbox {
46
47
  typeaheadDelay = input(0.5); // Picked arbitrarily.
47
48
  /** Whether the listbox is disabled. */
48
49
  disabled = input(false, { transform: booleanAttribute });
49
- // TODO(wagnermaciel): Figure out how we want to expose control over the current listbox value.
50
- /** The ids of the current selected items. */
51
- selectedIds = model([]);
50
+ /** Whether the listbox is readonly. */
51
+ readonly = input(false, { transform: booleanAttribute });
52
+ /** The values of the current selected items. */
53
+ value = model([]);
52
54
  /** The current index that has been navigated to. */
53
55
  activeIndex = model(0);
54
56
  /** The Listbox UIPattern. */
@@ -57,10 +59,27 @@ class CdkListbox {
57
59
  items: this.items,
58
60
  textDirection: this.textDirection,
59
61
  });
60
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: CdkListbox, deps: [], target: i0.ɵɵFactoryTarget.Directive });
61
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "19.2.0", type: CdkListbox, isStandalone: true, selector: "[cdkListbox]", inputs: { orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, multiselectable: { classPropertyName: "multiselectable", publicName: "multiselectable", 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 }, focusMode: { classPropertyName: "focusMode", publicName: "focusMode", isSignal: true, isRequired: false, transformFunction: null }, selectionMode: { classPropertyName: "selectionMode", publicName: "selectionMode", isSignal: true, isRequired: false, transformFunction: null }, typeaheadDelay: { classPropertyName: "typeaheadDelay", publicName: "typeaheadDelay", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, selectedIds: { classPropertyName: "selectedIds", publicName: "selectedIds", isSignal: true, isRequired: false, transformFunction: null }, activeIndex: { classPropertyName: "activeIndex", publicName: "activeIndex", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedIds: "selectedIdsChange", activeIndex: "activeIndexChange" }, host: { attributes: { "role": "listbox" }, listeners: { "keydown": "pattern.onKeydown($event)", "pointerdown": "pattern.onPointerdown($event)" }, properties: { "attr.tabindex": "pattern.tabindex()", "attr.aria-disabled": "pattern.disabled()", "attr.aria-orientation": "pattern.orientation()", "attr.aria-multiselectable": "pattern.multiselectable()", "attr.aria-activedescendant": "pattern.activedescendant()" }, classAttribute: "cdk-listbox" }, queries: [{ propertyName: "_cdkOptions", predicate: CdkOption, descendants: true, isSignal: true }], exportAs: ["cdkListbox"], ngImport: i0 });
62
+ /** Whether the listbox has received focus yet. */
63
+ _hasFocused = signal(false);
64
+ /** Whether the options in the listbox have been initialized. */
65
+ _isViewInitialized = signal(false);
66
+ constructor() {
67
+ effect(() => {
68
+ if (this._isViewInitialized() && !this._hasFocused()) {
69
+ this.pattern.setDefaultState();
70
+ }
71
+ });
72
+ }
73
+ ngAfterViewInit() {
74
+ this._isViewInitialized.set(true);
75
+ }
76
+ onFocus() {
77
+ this._hasFocused.set(true);
78
+ }
79
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: CdkListbox, deps: [], target: i0.ɵɵFactoryTarget.Directive });
80
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "20.0.0-next.5", type: CdkListbox, isStandalone: true, selector: "[cdkListbox]", inputs: { orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, multi: { classPropertyName: "multi", publicName: "multi", 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 }, focusMode: { classPropertyName: "focusMode", publicName: "focusMode", isSignal: true, isRequired: false, transformFunction: null }, selectionMode: { classPropertyName: "selectionMode", publicName: "selectionMode", isSignal: true, isRequired: false, transformFunction: null }, typeaheadDelay: { classPropertyName: "typeaheadDelay", publicName: "typeaheadDelay", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, activeIndex: { classPropertyName: "activeIndex", publicName: "activeIndex", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", activeIndex: "activeIndexChange" }, host: { attributes: { "role": "listbox" }, listeners: { "keydown": "pattern.onKeydown($event)", "pointerdown": "pattern.onPointerdown($event)", "focusin": "onFocus()" }, properties: { "attr.tabindex": "pattern.tabindex()", "attr.aria-readonly": "pattern.readonly()", "attr.aria-disabled": "pattern.disabled()", "attr.aria-orientation": "pattern.orientation()", "attr.aria-multiselectable": "pattern.multi()", "attr.aria-activedescendant": "pattern.activedescendant()" }, classAttribute: "cdk-listbox" }, queries: [{ propertyName: "_cdkOptions", predicate: CdkOption, descendants: true, isSignal: true }], exportAs: ["cdkListbox"], ngImport: i0 });
62
81
  }
63
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: CdkListbox, decorators: [{
82
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: CdkListbox, decorators: [{
64
83
  type: Directive,
65
84
  args: [{
66
85
  selector: '[cdkListbox]',
@@ -69,15 +88,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.0", ngImpor
69
88
  'role': 'listbox',
70
89
  'class': 'cdk-listbox',
71
90
  '[attr.tabindex]': 'pattern.tabindex()',
91
+ '[attr.aria-readonly]': 'pattern.readonly()',
72
92
  '[attr.aria-disabled]': 'pattern.disabled()',
73
93
  '[attr.aria-orientation]': 'pattern.orientation()',
74
- '[attr.aria-multiselectable]': 'pattern.multiselectable()',
94
+ '[attr.aria-multiselectable]': 'pattern.multi()',
75
95
  '[attr.aria-activedescendant]': 'pattern.activedescendant()',
76
96
  '(keydown)': 'pattern.onKeydown($event)',
77
97
  '(pointerdown)': 'pattern.onPointerdown($event)',
98
+ '(focusin)': 'onFocus()',
78
99
  },
79
100
  }]
80
- }] });
101
+ }], ctorParameters: () => [] });
81
102
  /** A selectable option in a CdkListbox. */
82
103
  class CdkOption {
83
104
  /** A reference to the option element. */
@@ -89,6 +110,8 @@ class CdkOption {
89
110
  // TODO(wagnermaciel): https://github.com/angular/components/pull/30495#discussion_r1972601144.
90
111
  /** A unique identifier for the option. */
91
112
  id = computed(() => this._generatedId);
113
+ /** The value of the option. */
114
+ value = input.required();
92
115
  // TODO(wagnermaciel): See if we want to change how we handle this since textContent is not
93
116
  // reactive. See https://github.com/angular/components/pull/30495#discussion_r1961260216.
94
117
  /** The text used by the typeahead search. */
@@ -105,14 +128,15 @@ class CdkOption {
105
128
  pattern = new OptionPattern({
106
129
  ...this,
107
130
  id: this.id,
131
+ value: this.value,
108
132
  listbox: this.listbox,
109
133
  element: this.element,
110
134
  searchTerm: this.searchTerm,
111
135
  });
112
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: CdkOption, deps: [], target: i0.ɵɵFactoryTarget.Directive });
113
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.0", type: CdkOption, isStandalone: true, selector: "[cdkOption]", inputs: { 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": "option" }, properties: { "attr.tabindex": "pattern.tabindex()", "attr.aria-selected": "pattern.selected()", "attr.aria-disabled": "pattern.disabled()" }, classAttribute: "cdk-option" }, exportAs: ["cdkOption"], ngImport: i0 });
136
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: CdkOption, deps: [], target: i0.ɵɵFactoryTarget.Directive });
137
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.0-next.5", type: CdkOption, isStandalone: true, selector: "[cdkOption]", 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": "option" }, properties: { "class.cdk-active": "pattern.active()", "attr.tabindex": "pattern.tabindex()", "attr.aria-selected": "pattern.selected()", "attr.aria-disabled": "pattern.disabled()" }, classAttribute: "cdk-option" }, exportAs: ["cdkOption"], ngImport: i0 });
114
138
  }
115
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: CdkOption, decorators: [{
139
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0-next.5", ngImport: i0, type: CdkOption, decorators: [{
116
140
  type: Directive,
117
141
  args: [{
118
142
  selector: '[cdkOption]',
@@ -120,6 +144,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.0", ngImpor
120
144
  host: {
121
145
  'role': 'option',
122
146
  'class': 'cdk-option',
147
+ '[class.cdk-active]': 'pattern.active()',
123
148
  '[attr.tabindex]': 'pattern.tabindex()',
124
149
  '[attr.aria-selected]': 'pattern.selected()',
125
150
  '[attr.aria-disabled]': 'pattern.disabled()',
@@ -127,9 +152,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.0", ngImpor
127
152
  }]
128
153
  }] });
129
154
 
130
- /**
131
- * Generated bundle index. Do not edit.
132
- */
133
-
134
155
  export { CdkListbox, CdkOption };
135
156
  //# sourceMappingURL=listbox.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"listbox.mjs","sources":["../../../../../../src/cdk-experimental/listbox/listbox.ts","../../../../../../src/cdk-experimental/listbox/listbox_public_index.ts"],"sourcesContent":["/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {\n booleanAttribute,\n computed,\n contentChildren,\n Directive,\n ElementRef,\n inject,\n input,\n model,\n} from '@angular/core';\nimport {ListboxPattern, OptionPattern} from '@angular/cdk-experimental/ui-patterns';\nimport {Directionality} from '@angular/cdk/bidi';\nimport {toSignal} from '@angular/core/rxjs-interop';\nimport {_IdGenerator} from '@angular/cdk/a11y';\n\n/**\n * A listbox container.\n *\n * Listboxes are used to display a list of items for a user to select from. The CdkListbox is meant\n * to be used in conjunction with CdkOption as follows:\n *\n * ```html\n * <ul cdkListbox>\n * <li cdkOption>Item 1</li>\n * <li cdkOption>Item 2</li>\n * <li cdkOption>Item 3</li>\n * </ul>\n * ```\n */\n@Directive({\n selector: '[cdkListbox]',\n exportAs: 'cdkListbox',\n host: {\n 'role': 'listbox',\n 'class': 'cdk-listbox',\n '[attr.tabindex]': 'pattern.tabindex()',\n '[attr.aria-disabled]': 'pattern.disabled()',\n '[attr.aria-orientation]': 'pattern.orientation()',\n '[attr.aria-multiselectable]': 'pattern.multiselectable()',\n '[attr.aria-activedescendant]': 'pattern.activedescendant()',\n '(keydown)': 'pattern.onKeydown($event)',\n '(pointerdown)': 'pattern.onPointerdown($event)',\n },\n})\nexport class CdkListbox {\n /** The directionality (LTR / RTL) context for the application (or a subtree of it). */\n private readonly _directionality = inject(Directionality);\n\n /** The CdkOptions nested inside of the CdkListbox. */\n private readonly _cdkOptions = contentChildren(CdkOption, {descendants: true});\n\n /** A signal wrapper for directionality. */\n protected textDirection = toSignal(this._directionality.change, {\n initialValue: this._directionality.value,\n });\n\n /** The Option UIPatterns of the child CdkOptions. */\n protected items = computed(() => this._cdkOptions().map(option => option.pattern));\n\n /** Whether the list is vertically or horizontally oriented. */\n orientation = input<'vertical' | 'horizontal'>('vertical');\n\n /** Whether multiple items in the list can be selected at once. */\n multiselectable = input(false, {transform: booleanAttribute});\n\n /** Whether focus should wrap when navigating. */\n wrap = input(true, {transform: booleanAttribute});\n\n /** Whether disabled items in the list should be skipped when navigating. */\n skipDisabled = input(true, {transform: booleanAttribute});\n\n /** The focus strategy used by the list. */\n focusMode = input<'roving' | 'activedescendant'>('roving');\n\n /** The selection strategy used by the list. */\n selectionMode = input<'follow' | 'explicit'>('follow');\n\n /** The amount of time before the typeahead search is reset. */\n typeaheadDelay = input<number>(0.5); // Picked arbitrarily.\n\n /** Whether the listbox is disabled. */\n disabled = input(false, {transform: booleanAttribute});\n\n // TODO(wagnermaciel): Figure out how we want to expose control over the current listbox value.\n /** The ids of the current selected items. */\n selectedIds = model<string[]>([]);\n\n /** The current index that has been navigated to. */\n activeIndex = model<number>(0);\n\n /** The Listbox UIPattern. */\n pattern: ListboxPattern = new ListboxPattern({\n ...this,\n items: this.items,\n textDirection: this.textDirection,\n });\n}\n\n/** A selectable option in a CdkListbox. */\n@Directive({\n selector: '[cdkOption]',\n exportAs: 'cdkOption',\n host: {\n 'role': 'option',\n 'class': 'cdk-option',\n '[attr.tabindex]': 'pattern.tabindex()',\n '[attr.aria-selected]': 'pattern.selected()',\n '[attr.aria-disabled]': 'pattern.disabled()',\n },\n})\nexport class CdkOption {\n /** A reference to the option element. */\n private readonly _elementRef = inject(ElementRef);\n\n /** The parent CdkListbox. */\n private readonly _cdkListbox = inject(CdkListbox);\n\n /** A unique identifier for the option. */\n private readonly _generatedId = inject(_IdGenerator).getId('cdk-option-');\n\n // TODO(wagnermaciel): https://github.com/angular/components/pull/30495#discussion_r1972601144.\n /** A unique identifier for the option. */\n protected id = computed(() => this._generatedId);\n\n // TODO(wagnermaciel): See if we want to change how we handle this since textContent is not\n // reactive. See https://github.com/angular/components/pull/30495#discussion_r1961260216.\n /** The text used by the typeahead search. */\n protected searchTerm = computed(() => this.label() ?? this.element().textContent);\n\n /** The parent Listbox UIPattern. */\n protected listbox = computed(() => this._cdkListbox.pattern);\n\n /** A reference to the option element to be focused on navigation. */\n protected element = computed(() => this._elementRef.nativeElement);\n\n /** Whether an item is disabled. */\n disabled = input(false, {transform: booleanAttribute});\n\n /** The text used by the typeahead search. */\n label = input<string>();\n\n /** The Option UIPattern. */\n pattern = new OptionPattern({\n ...this,\n id: this.id,\n listbox: this.listbox,\n element: this.element,\n searchTerm: this.searchTerm,\n });\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"listbox.mjs","sources":["../../../../../darwin_arm64-fastbuild-ST-46c76129e412/bin/src/cdk-experimental/listbox/listbox.ts"],"sourcesContent":["/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {\n AfterViewInit,\n booleanAttribute,\n computed,\n contentChildren,\n Directive,\n effect,\n ElementRef,\n inject,\n input,\n model,\n signal,\n} from '@angular/core';\nimport {ListboxPattern, OptionPattern} from '../ui-patterns';\nimport {Directionality} from '@angular/cdk/bidi';\nimport {toSignal} from '@angular/core/rxjs-interop';\nimport {_IdGenerator} from '@angular/cdk/a11y';\n\n/**\n * A listbox container.\n *\n * Listboxes are used to display a list of items for a user to select from. The CdkListbox is meant\n * to be used in conjunction with CdkOption as follows:\n *\n * ```html\n * <ul cdkListbox>\n * <li [value]=\"1\" cdkOption>Item 1</li>\n * <li [value]=\"2\" cdkOption>Item 2</li>\n * <li [value]=\"3\" cdkOption>Item 3</li>\n * </ul>\n * ```\n */\n@Directive({\n selector: '[cdkListbox]',\n exportAs: 'cdkListbox',\n host: {\n 'role': 'listbox',\n 'class': 'cdk-listbox',\n '[attr.tabindex]': 'pattern.tabindex()',\n '[attr.aria-readonly]': 'pattern.readonly()',\n '[attr.aria-disabled]': 'pattern.disabled()',\n '[attr.aria-orientation]': 'pattern.orientation()',\n '[attr.aria-multiselectable]': 'pattern.multi()',\n '[attr.aria-activedescendant]': 'pattern.activedescendant()',\n '(keydown)': 'pattern.onKeydown($event)',\n '(pointerdown)': 'pattern.onPointerdown($event)',\n '(focusin)': 'onFocus()',\n },\n})\nexport class CdkListbox<V> implements AfterViewInit {\n /** The directionality (LTR / RTL) context for the application (or a subtree of it). */\n private readonly _directionality = inject(Directionality);\n\n /** The CdkOptions nested inside of the CdkListbox. */\n private readonly _cdkOptions = contentChildren(CdkOption, {descendants: true});\n\n /** A signal wrapper for directionality. */\n protected textDirection = toSignal(this._directionality.change, {\n initialValue: this._directionality.value,\n });\n\n /** The Option UIPatterns of the child CdkOptions. */\n protected items = computed(() => this._cdkOptions().map(option => option.pattern));\n\n /** Whether the list is vertically or horizontally oriented. */\n orientation = input<'vertical' | 'horizontal'>('vertical');\n\n /** Whether multiple items in the list can be selected at once. */\n multi = input(false, {transform: booleanAttribute});\n\n /** Whether focus should wrap when navigating. */\n wrap = input(true, {transform: booleanAttribute});\n\n /** Whether disabled items in the list should be skipped when navigating. */\n skipDisabled = input(true, {transform: booleanAttribute});\n\n /** The focus strategy used by the list. */\n focusMode = input<'roving' | 'activedescendant'>('roving');\n\n /** The selection strategy used by the list. */\n selectionMode = input<'follow' | 'explicit'>('follow');\n\n /** The amount of time before the typeahead search is reset. */\n typeaheadDelay = input<number>(0.5); // Picked arbitrarily.\n\n /** Whether the listbox is disabled. */\n disabled = input(false, {transform: booleanAttribute});\n\n /** Whether the listbox is readonly. */\n readonly = input(false, {transform: booleanAttribute});\n\n /** The values of the current selected items. */\n value = model<V[]>([]);\n\n /** The current index that has been navigated to. */\n activeIndex = model<number>(0);\n\n /** The Listbox UIPattern. */\n pattern: ListboxPattern<V> = new ListboxPattern<V>({\n ...this,\n items: this.items,\n textDirection: this.textDirection,\n });\n\n /** Whether the listbox has received focus yet. */\n private _hasFocused = signal(false);\n\n /** Whether the options in the listbox have been initialized. */\n private _isViewInitialized = signal(false);\n\n constructor() {\n effect(() => {\n if (this._isViewInitialized() && !this._hasFocused()) {\n this.pattern.setDefaultState();\n }\n });\n }\n\n ngAfterViewInit() {\n this._isViewInitialized.set(true);\n }\n\n onFocus() {\n this._hasFocused.set(true);\n }\n}\n\n/** A selectable option in a CdkListbox. */\n@Directive({\n selector: '[cdkOption]',\n exportAs: 'cdkOption',\n host: {\n 'role': 'option',\n 'class': 'cdk-option',\n '[class.cdk-active]': 'pattern.active()',\n '[attr.tabindex]': 'pattern.tabindex()',\n '[attr.aria-selected]': 'pattern.selected()',\n '[attr.aria-disabled]': 'pattern.disabled()',\n },\n})\nexport class CdkOption<V> {\n /** A reference to the option element. */\n private readonly _elementRef = inject(ElementRef);\n\n /** The parent CdkListbox. */\n private readonly _cdkListbox = inject(CdkListbox);\n\n /** A unique identifier for the option. */\n private readonly _generatedId = inject(_IdGenerator).getId('cdk-option-');\n\n // TODO(wagnermaciel): https://github.com/angular/components/pull/30495#discussion_r1972601144.\n /** A unique identifier for the option. */\n protected id = computed(() => this._generatedId);\n\n /** The value of the option. */\n protected value = input.required<V>();\n\n // TODO(wagnermaciel): See if we want to change how we handle this since textContent is not\n // reactive. See https://github.com/angular/components/pull/30495#discussion_r1961260216.\n /** The text used by the typeahead search. */\n protected searchTerm = computed(() => this.label() ?? this.element().textContent);\n\n /** The parent Listbox UIPattern. */\n protected listbox = computed(() => this._cdkListbox.pattern);\n\n /** A reference to the option element to be focused on navigation. */\n protected element = computed(() => this._elementRef.nativeElement);\n\n /** Whether an item is disabled. */\n disabled = input(false, {transform: booleanAttribute});\n\n /** The text used by the typeahead search. */\n label = input<string>();\n\n /** The Option UIPattern. */\n pattern = new OptionPattern<V>({\n ...this,\n id: this.id,\n value: this.value,\n listbox: this.listbox,\n element: this.element,\n searchTerm: this.searchTerm,\n });\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,367 @@
1
+ import { M as ModifierKey, L as ListFocus, a as ListSelection, b as ListNavigation, K as KeyboardEventManager, P as PointerEventManager } from './list-focus-Di7m_z_6.mjs';
2
+ import { computed, signal } from '@angular/core';
3
+
4
+ /** Controls typeahead for a list of items. */
5
+ class ListTypeahead {
6
+ inputs;
7
+ /** A reference to the timeout for resetting the typeahead search. */
8
+ timeout;
9
+ /** The focus controller of the parent list. */
10
+ focusManager;
11
+ /** Whether the user is actively typing a typeahead search query. */
12
+ isTyping = computed(() => this._query().length > 0);
13
+ /** Keeps track of the characters that typeahead search is being called with. */
14
+ _query = signal('');
15
+ /** The index where that the typeahead search was initiated from. */
16
+ _startIndex = signal(undefined);
17
+ constructor(inputs) {
18
+ this.inputs = inputs;
19
+ this.focusManager = inputs.focusManager;
20
+ }
21
+ /** Performs a typeahead search, appending the given character to the search string. */
22
+ search(char) {
23
+ if (char.length !== 1) {
24
+ return false;
25
+ }
26
+ if (!this.isTyping() && char === ' ') {
27
+ return false;
28
+ }
29
+ if (this._startIndex() === undefined) {
30
+ this._startIndex.set(this.focusManager.inputs.activeIndex());
31
+ }
32
+ clearTimeout(this.timeout);
33
+ this._query.update(q => q + char.toLowerCase());
34
+ const item = this._getItem();
35
+ if (item) {
36
+ this.focusManager.focus(item);
37
+ }
38
+ this.timeout = setTimeout(() => {
39
+ this._query.set('');
40
+ this._startIndex.set(undefined);
41
+ }, this.inputs.typeaheadDelay() * 1000);
42
+ return true;
43
+ }
44
+ /**
45
+ * Returns the first item whose search term matches the
46
+ * current query starting from the the current anchor index.
47
+ */
48
+ _getItem() {
49
+ let items = this.focusManager.inputs.items();
50
+ const after = items.slice(this._startIndex() + 1);
51
+ const before = items.slice(0, this._startIndex());
52
+ items = after.concat(before);
53
+ items.push(this.inputs.items()[this._startIndex()]);
54
+ const focusableItems = [];
55
+ for (const item of items) {
56
+ if (this.focusManager.isFocusable(item)) {
57
+ focusableItems.push(item);
58
+ }
59
+ }
60
+ return focusableItems.find(i => i.searchTerm().toLowerCase().startsWith(this._query()));
61
+ }
62
+ }
63
+
64
+ /** Controls the state of a listbox. */
65
+ class ListboxPattern {
66
+ inputs;
67
+ /** Controls navigation for the listbox. */
68
+ navigation;
69
+ /** Controls selection for the listbox. */
70
+ selection;
71
+ /** Controls typeahead for the listbox. */
72
+ typeahead;
73
+ /** Controls focus for the listbox. */
74
+ focusManager;
75
+ /** Whether the list is vertically or horizontally oriented. */
76
+ orientation;
77
+ /** Whether the listbox is disabled. */
78
+ disabled = computed(() => this.focusManager.isListDisabled());
79
+ /** Whether the listbox is readonly. */
80
+ readonly;
81
+ /** The tabindex of the listbox. */
82
+ tabindex = computed(() => this.focusManager.getListTabindex());
83
+ /** The id of the current active item. */
84
+ activedescendant = computed(() => this.focusManager.getActiveDescendant());
85
+ /** Whether multiple items in the list can be selected at once. */
86
+ multi;
87
+ /** The number of items in the listbox. */
88
+ setsize = computed(() => this.navigation.inputs.items().length);
89
+ /** Whether the listbox selection follows focus. */
90
+ followFocus = computed(() => this.inputs.selectionMode() === 'follow');
91
+ /** Whether the listbox should wrap. Used to disable wrapping while range selecting. */
92
+ wrap = signal(true);
93
+ /** The key used to navigate to the previous item in the list. */
94
+ prevKey = computed(() => {
95
+ if (this.inputs.orientation() === 'vertical') {
96
+ return 'ArrowUp';
97
+ }
98
+ return this.inputs.textDirection() === 'rtl' ? 'ArrowRight' : 'ArrowLeft';
99
+ });
100
+ /** The key used to navigate to the next item in the list. */
101
+ nextKey = computed(() => {
102
+ if (this.inputs.orientation() === 'vertical') {
103
+ return 'ArrowDown';
104
+ }
105
+ return this.inputs.textDirection() === 'rtl' ? 'ArrowLeft' : 'ArrowRight';
106
+ });
107
+ /** Represents the space key. Does nothing when the user is actively using typeahead. */
108
+ dynamicSpaceKey = computed(() => (this.typeahead.isTyping() ? '' : ' '));
109
+ /** The regexp used to decide if a key should trigger typeahead. */
110
+ typeaheadRegexp = /^.$/; // TODO: Ignore spaces?
111
+ /**
112
+ * The uncommitted index for selecting a range of options.
113
+ *
114
+ * NOTE: This is subtly distinct from the "rangeStartIndex" in the ListSelection behavior.
115
+ * The anchorIndex does not necessarily represent the start of a range, but represents the most
116
+ * recent index where the user showed intent to begin a range selection. Usually, this is wherever
117
+ * the user most recently pressed the "Shift" key, but if the user presses shift + space to select
118
+ * from the anchor, the user is not intending to start a new range from this index.
119
+ *
120
+ * In other words, "rangeStartIndex" is only set when a user commits to starting a range selection
121
+ * while "anchorIndex" is set whenever a user indicates they may be starting a range selection.
122
+ */
123
+ anchorIndex = signal(0);
124
+ /** The keydown event manager for the listbox. */
125
+ keydown = computed(() => {
126
+ const manager = new KeyboardEventManager();
127
+ if (this.readonly()) {
128
+ return manager
129
+ .on(this.prevKey, () => this.prev())
130
+ .on(this.nextKey, () => this.next())
131
+ .on('Home', () => this.first())
132
+ .on('End', () => this.last())
133
+ .on(this.typeaheadRegexp, e => this.search(e.key));
134
+ }
135
+ if (!this.followFocus()) {
136
+ manager
137
+ .on(this.prevKey, () => this.prev())
138
+ .on(this.nextKey, () => this.next())
139
+ .on('Home', () => this.first())
140
+ .on('End', () => this.last())
141
+ .on(this.typeaheadRegexp, e => this.search(e.key));
142
+ }
143
+ if (this.followFocus()) {
144
+ manager
145
+ .on(this.prevKey, () => this.prev({ selectOne: true }))
146
+ .on(this.nextKey, () => this.next({ selectOne: true }))
147
+ .on('Home', () => this.first({ selectOne: true }))
148
+ .on('End', () => this.last({ selectOne: true }))
149
+ .on(this.typeaheadRegexp, e => this.search(e.key, { selectOne: true }));
150
+ }
151
+ if (this.inputs.multi()) {
152
+ manager
153
+ .on(ModifierKey.Any, 'Shift', () => this.anchorIndex.set(this.inputs.activeIndex()))
154
+ .on(ModifierKey.Shift, this.prevKey, () => this.prev({ selectRange: true }))
155
+ .on(ModifierKey.Shift, this.nextKey, () => this.next({ selectRange: true }))
156
+ .on([ModifierKey.Ctrl | ModifierKey.Shift, ModifierKey.Meta | ModifierKey.Shift], 'Home', () => this.first({ selectRange: true, anchor: false }))
157
+ .on([ModifierKey.Ctrl | ModifierKey.Shift, ModifierKey.Meta | ModifierKey.Shift], 'End', () => this.last({ selectRange: true, anchor: false }))
158
+ .on(ModifierKey.Shift, 'Enter', () => this._updateSelection({ selectRange: true, anchor: false }))
159
+ .on(ModifierKey.Shift, this.dynamicSpaceKey, () => this._updateSelection({ selectRange: true, anchor: false }));
160
+ }
161
+ if (!this.followFocus() && this.inputs.multi()) {
162
+ manager
163
+ .on(this.dynamicSpaceKey, () => this.selection.toggle())
164
+ .on('Enter', () => this.selection.toggle())
165
+ .on([ModifierKey.Ctrl, ModifierKey.Meta], 'A', () => this.selection.toggleAll());
166
+ }
167
+ if (!this.followFocus() && !this.inputs.multi()) {
168
+ manager.on(this.dynamicSpaceKey, () => this.selection.toggleOne());
169
+ manager.on('Enter', () => this.selection.toggleOne());
170
+ }
171
+ if (this.inputs.multi() && this.followFocus()) {
172
+ manager
173
+ .on([ModifierKey.Ctrl, ModifierKey.Meta], this.prevKey, () => this.prev())
174
+ .on([ModifierKey.Ctrl, ModifierKey.Meta], this.nextKey, () => this.next())
175
+ .on([ModifierKey.Ctrl, ModifierKey.Meta], ' ', () => this.selection.toggle())
176
+ .on([ModifierKey.Ctrl, ModifierKey.Meta], 'Enter', () => this.selection.toggle())
177
+ .on([ModifierKey.Ctrl, ModifierKey.Meta], 'Home', () => this.first())
178
+ .on([ModifierKey.Ctrl, ModifierKey.Meta], 'End', () => this.last())
179
+ .on([ModifierKey.Ctrl, ModifierKey.Meta], 'A', () => {
180
+ this.selection.toggleAll();
181
+ this.selection.select(); // Ensure the currect option remains selected.
182
+ });
183
+ }
184
+ return manager;
185
+ });
186
+ /** The pointerdown event manager for the listbox. */
187
+ pointerdown = computed(() => {
188
+ const manager = new PointerEventManager();
189
+ if (this.readonly()) {
190
+ return manager.on(e => this.goto(e));
191
+ }
192
+ if (this.multi()) {
193
+ manager.on(ModifierKey.Shift, e => this.goto(e, { selectRange: true }));
194
+ }
195
+ if (!this.multi() && this.followFocus()) {
196
+ return manager.on(e => this.goto(e, { selectOne: true }));
197
+ }
198
+ if (!this.multi() && !this.followFocus()) {
199
+ return manager.on(e => this.goto(e, { toggle: true }));
200
+ }
201
+ if (this.multi() && this.followFocus()) {
202
+ return manager
203
+ .on(e => this.goto(e, { selectOne: true }))
204
+ .on(ModifierKey.Ctrl, e => this.goto(e, { toggle: true }));
205
+ }
206
+ if (this.multi() && !this.followFocus()) {
207
+ return manager.on(e => this.goto(e, { toggle: true }));
208
+ }
209
+ return manager;
210
+ });
211
+ constructor(inputs) {
212
+ this.inputs = inputs;
213
+ this.readonly = inputs.readonly;
214
+ this.orientation = inputs.orientation;
215
+ this.multi = inputs.multi;
216
+ this.focusManager = new ListFocus(inputs);
217
+ this.selection = new ListSelection({ ...inputs, focusManager: this.focusManager });
218
+ this.typeahead = new ListTypeahead({ ...inputs, focusManager: this.focusManager });
219
+ this.navigation = new ListNavigation({
220
+ ...inputs,
221
+ focusManager: this.focusManager,
222
+ wrap: computed(() => this.wrap() && this.inputs.wrap()),
223
+ });
224
+ }
225
+ /** Handles keydown events for the listbox. */
226
+ onKeydown(event) {
227
+ if (!this.disabled()) {
228
+ this.keydown().handle(event);
229
+ }
230
+ }
231
+ onPointerdown(event) {
232
+ if (!this.disabled()) {
233
+ this.pointerdown().handle(event);
234
+ }
235
+ }
236
+ /** Navigates to the first option in the listbox. */
237
+ first(opts) {
238
+ this._navigate(opts, () => this.navigation.first());
239
+ }
240
+ /** Navigates to the last option in the listbox. */
241
+ last(opts) {
242
+ this._navigate(opts, () => this.navigation.last());
243
+ }
244
+ /** Navigates to the next option in the listbox. */
245
+ next(opts) {
246
+ this._navigate(opts, () => this.navigation.next());
247
+ }
248
+ /** Navigates to the previous option in the listbox. */
249
+ prev(opts) {
250
+ this._navigate(opts, () => this.navigation.prev());
251
+ }
252
+ /** Navigates to the given item in the listbox. */
253
+ goto(event, opts) {
254
+ const item = this._getItem(event);
255
+ this._navigate(opts, () => this.navigation.goto(item));
256
+ }
257
+ /** Handles typeahead search navigation for the listbox. */
258
+ search(char, opts) {
259
+ this._navigate(opts, () => this.typeahead.search(char));
260
+ }
261
+ /**
262
+ * Sets the listbox to it's default initial state.
263
+ *
264
+ * Sets the active index of the listbox to the first focusable selected
265
+ * item if one exists. Otherwise, sets focus to the first focusable item.
266
+ *
267
+ * This method should be called once the listbox and it's options are properly initialized,
268
+ * meaning the ListboxPattern and OptionPatterns should have references to each other before this
269
+ * is called.
270
+ */
271
+ setDefaultState() {
272
+ let firstItem = null;
273
+ for (const item of this.inputs.items()) {
274
+ if (this.focusManager.isFocusable(item)) {
275
+ if (!firstItem) {
276
+ firstItem = item;
277
+ }
278
+ if (item.selected()) {
279
+ this.inputs.activeIndex.set(item.index());
280
+ return;
281
+ }
282
+ }
283
+ }
284
+ if (firstItem) {
285
+ this.inputs.activeIndex.set(firstItem.index());
286
+ }
287
+ }
288
+ /**
289
+ * Safely performs a navigation operation.
290
+ *
291
+ * Handles conditionally disabling wrapping for when a navigation
292
+ * operation is occurring while the user is selecting a range of options.
293
+ *
294
+ * Handles boilerplate calling of focus & selection operations. Also ensures these
295
+ * additional operations are only called if the navigation operation moved focus to a new option.
296
+ */
297
+ _navigate(opts = {}, operation) {
298
+ if (opts?.selectRange) {
299
+ this.wrap.set(false);
300
+ this.selection.rangeStartIndex.set(this.anchorIndex());
301
+ }
302
+ const moved = operation();
303
+ if (moved) {
304
+ this._updateSelection(opts);
305
+ }
306
+ this.wrap.set(true);
307
+ }
308
+ /** Handles updating selection for the listbox. */
309
+ _updateSelection(opts = { anchor: true }) {
310
+ if (opts.toggle) {
311
+ this.selection.toggle();
312
+ }
313
+ if (opts.selectOne) {
314
+ this.selection.selectOne();
315
+ }
316
+ if (opts.selectRange) {
317
+ this.selection.selectRange();
318
+ }
319
+ if (!opts.anchor) {
320
+ this.anchorIndex.set(this.selection.rangeStartIndex());
321
+ }
322
+ }
323
+ _getItem(e) {
324
+ if (!(e.target instanceof HTMLElement)) {
325
+ return;
326
+ }
327
+ const element = e.target.closest('[role="option"]');
328
+ return this.inputs.items().find(i => i.element() === element);
329
+ }
330
+ }
331
+
332
+ /** Represents an option in a listbox. */
333
+ class OptionPattern {
334
+ /** A unique identifier for the option. */
335
+ id;
336
+ /** The value of the option. */
337
+ value;
338
+ /** The position of the option in the list. */
339
+ index = computed(() => this.listbox()
340
+ ?.navigation.inputs.items()
341
+ .findIndex(i => i.id() === this.id()) ?? -1);
342
+ /** Whether the option is active. */
343
+ active = computed(() => this.listbox()?.focusManager.activeItem() === this);
344
+ /** Whether the option is selected. */
345
+ selected = computed(() => this.listbox()?.selection.inputs.value().includes(this.value()));
346
+ /** Whether the option is disabled. */
347
+ disabled;
348
+ /** The text used by the typeahead search. */
349
+ searchTerm;
350
+ /** A reference to the parent listbox. */
351
+ listbox;
352
+ /** The tabindex of the option. */
353
+ tabindex = computed(() => this.listbox()?.focusManager.getItemTabindex(this));
354
+ /** The html element that should receive focus. */
355
+ element;
356
+ constructor(args) {
357
+ this.id = args.id;
358
+ this.value = args.value;
359
+ this.listbox = args.listbox;
360
+ this.element = args.element;
361
+ this.disabled = args.disabled;
362
+ this.searchTerm = args.searchTerm;
363
+ }
364
+ }
365
+
366
+ export { ListboxPattern as L, OptionPattern as O };
367
+ //# sourceMappingURL=option-f_gNslw8.mjs.map