primeng 16.6.0 → 16.7.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 (175) hide show
  1. package/animate/animate.d.ts +3 -2
  2. package/animateonscroll/animateonscroll.d.ts +73 -0
  3. package/animateonscroll/index.d.ts +5 -0
  4. package/animateonscroll/public_api.d.ts +1 -0
  5. package/api/primengconfig.d.ts +1 -0
  6. package/autocomplete/autocomplete.d.ts +177 -54
  7. package/autocomplete/autocomplete.interface.d.ts +30 -0
  8. package/cascadeselect/cascadeselect.d.ts +188 -68
  9. package/cascadeselect/cascadeselect.interface.d.ts +19 -0
  10. package/checkbox/checkbox.d.ts +1 -4
  11. package/chips/chips.d.ts +21 -5
  12. package/colorpicker/colorpicker.d.ts +5 -5
  13. package/contextmenu/contextmenu.d.ts +1 -0
  14. package/dialog/dialog.d.ts +1 -2
  15. package/dom/domhandler.d.ts +4 -1
  16. package/dropdown/dropdown.d.ts +115 -37
  17. package/esm2022/accordion/accordion.mjs +11 -7
  18. package/esm2022/animate/animate.mjs +4 -1
  19. package/esm2022/animateonscroll/animateonscroll.mjs +185 -0
  20. package/esm2022/animateonscroll/primeng-animateonscroll.mjs +5 -0
  21. package/esm2022/animateonscroll/public_api.mjs +2 -0
  22. package/esm2022/api/primengconfig.mjs +2 -1
  23. package/esm2022/autocomplete/autocomplete.interface.mjs +1 -1
  24. package/esm2022/autocomplete/autocomplete.mjs +893 -617
  25. package/esm2022/carousel/carousel.mjs +5 -1
  26. package/esm2022/cascadeselect/cascadeselect.interface.mjs +1 -1
  27. package/esm2022/cascadeselect/cascadeselect.mjs +921 -482
  28. package/esm2022/checkbox/checkbox.mjs +90 -73
  29. package/esm2022/chips/chips.mjs +197 -53
  30. package/esm2022/colorpicker/colorpicker.mjs +56 -37
  31. package/esm2022/contextmenu/contextmenu.mjs +10 -1
  32. package/esm2022/dialog/dialog.mjs +6 -11
  33. package/esm2022/dom/domhandler.mjs +26 -8
  34. package/esm2022/dropdown/dropdown.mjs +707 -588
  35. package/esm2022/inputmask/inputmask.mjs +22 -9
  36. package/esm2022/inputnumber/inputnumber.mjs +142 -83
  37. package/esm2022/inputswitch/inputswitch.mjs +55 -49
  38. package/esm2022/knob/knob.mjs +92 -5
  39. package/esm2022/listbox/listbox.interface.mjs +1 -1
  40. package/esm2022/listbox/listbox.mjs +996 -454
  41. package/esm2022/multiselect/multiselect.mjs +1022 -604
  42. package/esm2022/overlaypanel/overlaypanel.mjs +2 -2
  43. package/esm2022/paginator/paginator.mjs +2 -2
  44. package/esm2022/password/password.mjs +29 -28
  45. package/esm2022/radiobutton/radiobutton.mjs +46 -33
  46. package/esm2022/rating/rating.mjs +172 -80
  47. package/esm2022/selectbutton/selectbutton.mjs +105 -34
  48. package/esm2022/slider/slider.mjs +151 -66
  49. package/esm2022/table/table.mjs +3 -3
  50. package/esm2022/togglebutton/togglebutton.mjs +47 -10
  51. package/esm2022/tristatecheckbox/tristatecheckbox.mjs +53 -35
  52. package/fesm2022/primeng-accordion.mjs +10 -6
  53. package/fesm2022/primeng-accordion.mjs.map +1 -1
  54. package/fesm2022/primeng-animate.mjs +3 -0
  55. package/fesm2022/primeng-animate.mjs.map +1 -1
  56. package/fesm2022/primeng-animateonscroll.mjs +190 -0
  57. package/fesm2022/primeng-animateonscroll.mjs.map +1 -0
  58. package/fesm2022/primeng-api.mjs +1 -0
  59. package/fesm2022/primeng-api.mjs.map +1 -1
  60. package/fesm2022/primeng-autocomplete.mjs +893 -617
  61. package/fesm2022/primeng-autocomplete.mjs.map +1 -1
  62. package/fesm2022/primeng-carousel.mjs +4 -0
  63. package/fesm2022/primeng-carousel.mjs.map +1 -1
  64. package/fesm2022/primeng-cascadeselect.mjs +920 -481
  65. package/fesm2022/primeng-cascadeselect.mjs.map +1 -1
  66. package/fesm2022/primeng-checkbox.mjs +89 -72
  67. package/fesm2022/primeng-checkbox.mjs.map +1 -1
  68. package/fesm2022/primeng-chips.mjs +195 -51
  69. package/fesm2022/primeng-chips.mjs.map +1 -1
  70. package/fesm2022/primeng-colorpicker.mjs +55 -36
  71. package/fesm2022/primeng-colorpicker.mjs.map +1 -1
  72. package/fesm2022/primeng-contextmenu.mjs +9 -0
  73. package/fesm2022/primeng-contextmenu.mjs.map +1 -1
  74. package/fesm2022/primeng-dialog.mjs +5 -10
  75. package/fesm2022/primeng-dialog.mjs.map +1 -1
  76. package/fesm2022/primeng-dom.mjs +25 -7
  77. package/fesm2022/primeng-dom.mjs.map +1 -1
  78. package/fesm2022/primeng-dropdown.mjs +707 -588
  79. package/fesm2022/primeng-dropdown.mjs.map +1 -1
  80. package/fesm2022/primeng-inputmask.mjs +20 -7
  81. package/fesm2022/primeng-inputmask.mjs.map +1 -1
  82. package/fesm2022/primeng-inputnumber.mjs +140 -81
  83. package/fesm2022/primeng-inputnumber.mjs.map +1 -1
  84. package/fesm2022/primeng-inputswitch.mjs +55 -49
  85. package/fesm2022/primeng-inputswitch.mjs.map +1 -1
  86. package/fesm2022/primeng-knob.mjs +92 -5
  87. package/fesm2022/primeng-knob.mjs.map +1 -1
  88. package/fesm2022/primeng-listbox.mjs +995 -453
  89. package/fesm2022/primeng-listbox.mjs.map +1 -1
  90. package/fesm2022/primeng-multiselect.mjs +1021 -603
  91. package/fesm2022/primeng-multiselect.mjs.map +1 -1
  92. package/fesm2022/primeng-overlaypanel.mjs +1 -1
  93. package/fesm2022/primeng-overlaypanel.mjs.map +1 -1
  94. package/fesm2022/primeng-paginator.mjs +1 -1
  95. package/fesm2022/primeng-paginator.mjs.map +1 -1
  96. package/fesm2022/primeng-password.mjs +27 -26
  97. package/fesm2022/primeng-password.mjs.map +1 -1
  98. package/fesm2022/primeng-radiobutton.mjs +46 -33
  99. package/fesm2022/primeng-radiobutton.mjs.map +1 -1
  100. package/fesm2022/primeng-rating.mjs +171 -79
  101. package/fesm2022/primeng-rating.mjs.map +1 -1
  102. package/fesm2022/primeng-selectbutton.mjs +104 -33
  103. package/fesm2022/primeng-selectbutton.mjs.map +1 -1
  104. package/fesm2022/primeng-slider.mjs +150 -65
  105. package/fesm2022/primeng-slider.mjs.map +1 -1
  106. package/fesm2022/primeng-table.mjs +2 -2
  107. package/fesm2022/primeng-table.mjs.map +1 -1
  108. package/fesm2022/primeng-togglebutton.mjs +46 -9
  109. package/fesm2022/primeng-togglebutton.mjs.map +1 -1
  110. package/fesm2022/primeng-tristatecheckbox.mjs +53 -35
  111. package/fesm2022/primeng-tristatecheckbox.mjs.map +1 -1
  112. package/inputmask/inputmask.d.ts +6 -1
  113. package/inputnumber/inputnumber.d.ts +6 -1
  114. package/inputswitch/inputswitch.d.ts +6 -9
  115. package/knob/knob.d.ts +20 -3
  116. package/listbox/listbox.d.ts +208 -39
  117. package/listbox/listbox.interface.d.ts +15 -0
  118. package/multiselect/multiselect.d.ts +171 -60
  119. package/package.json +126 -120
  120. package/password/password.d.ts +3 -4
  121. package/radiobutton/radiobutton.d.ts +1 -2
  122. package/rating/rating.d.ts +29 -7
  123. package/resources/components/dropdown/dropdown.css +16 -2
  124. package/resources/themes/arya-blue/theme.css +106 -84
  125. package/resources/themes/arya-green/theme.css +106 -84
  126. package/resources/themes/arya-orange/theme.css +106 -84
  127. package/resources/themes/arya-purple/theme.css +106 -84
  128. package/resources/themes/bootstrap4-dark-blue/theme.css +110 -88
  129. package/resources/themes/bootstrap4-dark-purple/theme.css +110 -88
  130. package/resources/themes/bootstrap4-light-blue/theme.css +110 -88
  131. package/resources/themes/bootstrap4-light-purple/theme.css +110 -88
  132. package/resources/themes/fluent-light/theme.css +103 -81
  133. package/resources/themes/lara-dark-blue/theme.css +106 -84
  134. package/resources/themes/lara-dark-indigo/theme.css +106 -84
  135. package/resources/themes/lara-dark-purple/theme.css +106 -84
  136. package/resources/themes/lara-dark-teal/theme.css +106 -84
  137. package/resources/themes/lara-light-blue/theme.css +109 -87
  138. package/resources/themes/lara-light-indigo/theme.css +109 -87
  139. package/resources/themes/lara-light-purple/theme.css +109 -87
  140. package/resources/themes/lara-light-teal/theme.css +109 -87
  141. package/resources/themes/luna-amber/theme.css +110 -88
  142. package/resources/themes/luna-blue/theme.css +110 -88
  143. package/resources/themes/luna-green/theme.css +110 -88
  144. package/resources/themes/luna-pink/theme.css +110 -88
  145. package/resources/themes/md-dark-deeppurple/theme.css +117 -95
  146. package/resources/themes/md-dark-indigo/theme.css +117 -95
  147. package/resources/themes/md-light-deeppurple/theme.css +117 -95
  148. package/resources/themes/md-light-indigo/theme.css +117 -95
  149. package/resources/themes/mdc-dark-deeppurple/theme.css +117 -95
  150. package/resources/themes/mdc-dark-indigo/theme.css +117 -95
  151. package/resources/themes/mdc-light-deeppurple/theme.css +117 -95
  152. package/resources/themes/mdc-light-indigo/theme.css +117 -95
  153. package/resources/themes/mira/theme.css +107 -85
  154. package/resources/themes/nano/theme.css +109 -87
  155. package/resources/themes/nova/theme.css +110 -88
  156. package/resources/themes/nova-accent/theme.css +109 -87
  157. package/resources/themes/nova-alt/theme.css +110 -88
  158. package/resources/themes/rhea/theme.css +109 -87
  159. package/resources/themes/saga-blue/theme.css +106 -84
  160. package/resources/themes/saga-green/theme.css +106 -84
  161. package/resources/themes/saga-orange/theme.css +106 -84
  162. package/resources/themes/saga-purple/theme.css +106 -84
  163. package/resources/themes/soho-dark/theme.css +109 -87
  164. package/resources/themes/soho-light/theme.css +109 -87
  165. package/resources/themes/tailwind-light/theme.css +110 -88
  166. package/resources/themes/vela-blue/theme.css +106 -84
  167. package/resources/themes/vela-green/theme.css +106 -84
  168. package/resources/themes/vela-orange/theme.css +106 -84
  169. package/resources/themes/vela-purple/theme.css +106 -84
  170. package/resources/themes/viva-dark/theme.css +109 -87
  171. package/resources/themes/viva-light/theme.css +109 -87
  172. package/selectbutton/selectbutton.d.ts +15 -3
  173. package/slider/slider.d.ts +12 -6
  174. package/togglebutton/togglebutton.d.ts +7 -1
  175. package/tristatecheckbox/tristatecheckbox.d.ts +8 -4
@@ -1,7 +1,7 @@
1
1
  import * as i1 from '@angular/common';
2
2
  import { CommonModule } from '@angular/common';
3
3
  import * as i0 from '@angular/core';
4
- import { forwardRef, EventEmitter, Component, Input, Output, ChangeDetectionStrategy, ViewEncapsulation, ViewChild, ContentChildren, NgModule } from '@angular/core';
4
+ import { forwardRef, EventEmitter, Component, Input, Output, signal, computed, effect, ChangeDetectionStrategy, ViewEncapsulation, ViewChild, ContentChildren, NgModule } from '@angular/core';
5
5
  import { NG_VALUE_ACCESSOR } from '@angular/forms';
6
6
  import * as i3 from 'primeng/api';
7
7
  import { TranslationKeys, PrimeTemplate, SharedModule } from 'primeng/api';
@@ -16,7 +16,7 @@ import * as i6 from 'primeng/scroller';
16
16
  import { ScrollerModule } from 'primeng/scroller';
17
17
  import * as i5 from 'primeng/tooltip';
18
18
  import { TooltipModule } from 'primeng/tooltip';
19
- import { ObjectUtils, UniqueComponentId } from 'primeng/utils';
19
+ import { UniqueComponentId, ObjectUtils } from 'primeng/utils';
20
20
  import { TimesIcon } from 'primeng/icons/times';
21
21
  import { ChevronDownIcon } from 'primeng/icons/chevrondown';
22
22
  import { SearchIcon } from 'primeng/icons/search';
@@ -27,31 +27,43 @@ const DROPDOWN_VALUE_ACCESSOR = {
27
27
  multi: true
28
28
  };
29
29
  class DropdownItem {
30
+ id;
30
31
  option;
31
32
  selected;
33
+ focused;
32
34
  label;
33
35
  disabled;
34
36
  visible;
35
37
  itemSize;
38
+ ariaPosInset;
39
+ ariaSetSize;
36
40
  template;
37
41
  onClick = new EventEmitter();
42
+ onMouseEnter = new EventEmitter();
43
+ ngOnInit() { }
38
44
  onOptionClick(event) {
39
- this.onClick.emit({
40
- originalEvent: event,
41
- option: this.option
42
- });
45
+ this.onClick.emit(event);
46
+ }
47
+ onOptionMouseEnter(event) {
48
+ this.onMouseEnter.emit(event);
43
49
  }
44
50
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: DropdownItem, deps: [], target: i0.ɵɵFactoryTarget.Component });
45
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.0.2", type: DropdownItem, selector: "p-dropdownItem", inputs: { option: "option", selected: "selected", label: "label", disabled: "disabled", visible: "visible", itemSize: "itemSize", template: "template" }, outputs: { onClick: "onClick" }, host: { classAttribute: "p-element" }, ngImport: i0, template: `
51
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.0.2", type: DropdownItem, selector: "p-dropdownItem", inputs: { id: "id", option: "option", selected: "selected", focused: "focused", label: "label", disabled: "disabled", visible: "visible", itemSize: "itemSize", ariaPosInset: "ariaPosInset", ariaSetSize: "ariaSetSize", template: "template" }, outputs: { onClick: "onClick", onMouseEnter: "onMouseEnter" }, host: { classAttribute: "p-element" }, ngImport: i0, template: `
46
52
  <li
53
+ [id]="id"
47
54
  (click)="onOptionClick($event)"
55
+ (mouseenter)="onOptionMouseEnter($event)"
48
56
  role="option"
49
57
  pRipple
50
58
  [attr.aria-label]="label"
59
+ [attr.aria-setsize]="ariaSetSize"
60
+ [attr.aria-posinset]="ariaPosInset"
51
61
  [attr.aria-selected]="selected"
62
+ [attr.data-p-focused]="focused"
63
+ [attr.data-p-highlight]="selected"
64
+ [attr.data-p-disabled]="disabled"
52
65
  [ngStyle]="{ height: itemSize + 'px' }"
53
- [id]="selected ? 'p-highlighted-option' : ''"
54
- [ngClass]="{ 'p-dropdown-item': true, 'p-highlight': selected, 'p-disabled': disabled }"
66
+ [ngClass]="{ 'p-dropdown-item': true, 'p-highlight': selected, 'p-disabled': disabled, 'p-focus': focused }"
55
67
  >
56
68
  <span *ngIf="!template">{{ label ?? 'empty' }}</span>
57
69
  <ng-container *ngTemplateOutlet="template; context: { $implicit: option }"></ng-container>
@@ -64,14 +76,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
64
76
  selector: 'p-dropdownItem',
65
77
  template: `
66
78
  <li
79
+ [id]="id"
67
80
  (click)="onOptionClick($event)"
81
+ (mouseenter)="onOptionMouseEnter($event)"
68
82
  role="option"
69
83
  pRipple
70
84
  [attr.aria-label]="label"
85
+ [attr.aria-setsize]="ariaSetSize"
86
+ [attr.aria-posinset]="ariaPosInset"
71
87
  [attr.aria-selected]="selected"
88
+ [attr.data-p-focused]="focused"
89
+ [attr.data-p-highlight]="selected"
90
+ [attr.data-p-disabled]="disabled"
72
91
  [ngStyle]="{ height: itemSize + 'px' }"
73
- [id]="selected ? 'p-highlighted-option' : ''"
74
- [ngClass]="{ 'p-dropdown-item': true, 'p-highlight': selected, 'p-disabled': disabled }"
92
+ [ngClass]="{ 'p-dropdown-item': true, 'p-highlight': selected, 'p-disabled': disabled, 'p-focus': focused }"
75
93
  >
76
94
  <span *ngIf="!template">{{ label ?? 'empty' }}</span>
77
95
  <ng-container *ngTemplateOutlet="template; context: { $implicit: option }"></ng-container>
@@ -81,10 +99,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
81
99
  class: 'p-element'
82
100
  }
83
101
  }]
84
- }], propDecorators: { option: [{
102
+ }], propDecorators: { id: [{
103
+ type: Input
104
+ }], option: [{
85
105
  type: Input
86
106
  }], selected: [{
87
107
  type: Input
108
+ }], focused: [{
109
+ type: Input
88
110
  }], label: [{
89
111
  type: Input
90
112
  }], disabled: [{
@@ -93,10 +115,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
93
115
  type: Input
94
116
  }], itemSize: [{
95
117
  type: Input
118
+ }], ariaPosInset: [{
119
+ type: Input
120
+ }], ariaSetSize: [{
121
+ type: Input
96
122
  }], template: [{
97
123
  type: Input
98
124
  }], onClick: [{
99
125
  type: Output
126
+ }], onMouseEnter: [{
127
+ type: Output
100
128
  }] } });
101
129
  /**
102
130
  * Dropdown also known as Select, is used to choose an item from a collection of options.
@@ -109,6 +137,11 @@ class Dropdown {
109
137
  zone;
110
138
  filterService;
111
139
  config;
140
+ /**
141
+ * Unique identifier of the component
142
+ * @group Props
143
+ */
144
+ id;
112
145
  /**
113
146
  * Height of the viewport in pixels, a scrollbar is defined if height of list exceeds this value.
114
147
  * @group Props
@@ -168,7 +201,7 @@ class Dropdown {
168
201
  * Index of the element in tabbing order.
169
202
  * @group Props
170
203
  */
171
- tabindex;
204
+ tabindex = 0;
172
205
  /**
173
206
  * Default text to display when no option is selected.
174
207
  * @group Props
@@ -199,6 +232,11 @@ class Dropdown {
199
232
  * @group Props
200
233
  */
201
234
  filterBy;
235
+ /**
236
+ * Fields used when filtering the options, defaults to optionLabel.
237
+ * @group Props
238
+ */
239
+ filterFields;
202
240
  /**
203
241
  * When present, it specifies that the component should automatically get focus on load.
204
242
  * @group Props
@@ -233,7 +271,7 @@ class Dropdown {
233
271
  * Name of the label field of an option group.
234
272
  * @group Props
235
273
  */
236
- optionGroupLabel;
274
+ optionGroupLabel = 'label';
237
275
  /**
238
276
  * Name of the options field of an option group.
239
277
  * @group Props
@@ -334,6 +372,21 @@ class Dropdown {
334
372
  * @group Props
335
373
  */
336
374
  tooltipStyleClass;
375
+ /**
376
+ * Fields used when filtering the options, defaults to optionLabel.
377
+ * @group Props
378
+ */
379
+ focusOnHover = false;
380
+ /**
381
+ * Determines if the option will be selected on focus.
382
+ * @group Props
383
+ */
384
+ selectOnFocus = false;
385
+ /**
386
+ * Whether to focus on the first visible or selected element when the overlay panel is shown.
387
+ * @group Props
388
+ */
389
+ autoOptionFocus = true;
337
390
  /**
338
391
  * Applies focus to the filter element when the overlay is shown.
339
392
  * @group Props
@@ -427,32 +480,21 @@ class Dropdown {
427
480
  * @group Props
428
481
  */
429
482
  get filterValue() {
430
- return this._filterValue;
483
+ return this._filterValue();
431
484
  }
432
485
  set filterValue(val) {
433
- this._filterValue = val;
434
- this.activateFilter();
486
+ this._filterValue.set(val);
435
487
  }
436
488
  /**
437
489
  * An array of objects to display as the available options.
438
490
  * @group Props
439
491
  */
440
492
  get options() {
441
- return this._options;
493
+ const options = this._options();
494
+ return options;
442
495
  }
443
496
  set options(val) {
444
- this._options = val;
445
- this.optionsToDisplay = this._options;
446
- this.updateSelectedOption(this.value);
447
- this.selectedOption = this.findOption(this.value, this.optionsToDisplay);
448
- if (!this.selectedOption && ObjectUtils.isNotEmpty(this.value) && !this.editable) {
449
- this.value = null;
450
- this.onModelChange(this.value);
451
- }
452
- this.optionsChanged = true;
453
- if (this._filterValue && this._filterValue.length) {
454
- this.activateFilter();
455
- }
497
+ this._options.set(val);
456
498
  }
457
499
  /**
458
500
  * Callback to invoke when value of dropdown changes.
@@ -510,11 +552,12 @@ class Dropdown {
510
552
  onLazyLoad = new EventEmitter();
511
553
  containerViewChild;
512
554
  filterViewChild;
513
- accessibleViewChild;
555
+ focusInputViewChild;
514
556
  editableInputViewChild;
515
557
  itemsViewChild;
516
558
  scroller;
517
559
  overlayViewChild;
560
+ firstHiddenFocusableElementOnOverlay;
518
561
  templates;
519
562
  _disabled;
520
563
  itemsWrapper;
@@ -531,12 +574,11 @@ class Dropdown {
531
574
  clearIconTemplate;
532
575
  filterIconTemplate;
533
576
  filterOptions;
534
- selectedOption;
535
- _options;
577
+ _options = signal(null);
578
+ modelValue = signal(null);
536
579
  value;
537
580
  onModelChange = () => { };
538
581
  onModelTouched = () => { };
539
- optionsToDisplay;
540
582
  hover;
541
583
  focused;
542
584
  overlayVisible;
@@ -545,16 +587,83 @@ class Dropdown {
545
587
  dimensionsUpdated;
546
588
  hoveredItem;
547
589
  selectedOptionUpdated;
548
- _filterValue;
590
+ _filterValue = signal(null);
549
591
  searchValue;
550
592
  searchIndex;
551
593
  searchTimeout;
552
594
  previousSearchChar;
553
595
  currentSearchChar;
554
596
  preventModelTouched;
555
- id = UniqueComponentId();
597
+ focusedOptionIndex = signal(-1);
556
598
  labelId;
557
599
  listId;
600
+ get emptyMessageLabel() {
601
+ return this.emptyMessage || this.config.getTranslation(TranslationKeys.EMPTY_MESSAGE);
602
+ }
603
+ get emptyFilterMessageLabel() {
604
+ return this.emptyFilterMessage || this.config.getTranslation(TranslationKeys.EMPTY_FILTER_MESSAGE);
605
+ }
606
+ get filled() {
607
+ if (typeof this.modelValue() === 'string')
608
+ return !!this.modelValue();
609
+ return this.modelValue() || this.modelValue() != null || this.modelValue() != undefined;
610
+ }
611
+ get isVisibleClearIcon() {
612
+ return this.modelValue() != null && this.modelValue() !== '' && this.showClear && !this.disabled;
613
+ }
614
+ get containerClass() {
615
+ return {
616
+ 'p-dropdown p-component p-inputwrapper': true,
617
+ 'p-disabled': this.disabled,
618
+ 'p-dropdown-clearable': this.showClear && !this.disabled,
619
+ 'p-focus': this.focused,
620
+ 'p-inputwrapper-filled': this.modelValue(),
621
+ 'p-inputwrapper-focus': this.focused || this.overlayVisible
622
+ };
623
+ }
624
+ get inputClass() {
625
+ return {
626
+ 'p-dropdown-label p-inputtext': true,
627
+ 'p-placeholder': this.placeholder && this.label() === this.placeholder,
628
+ 'p-dropdown-label-empty': !this.editable && !this.selectedItemTemplate && (this.label() === 'p-emptylabel' || this.label().length === 0)
629
+ };
630
+ }
631
+ get panelClass() {
632
+ return {
633
+ 'p-dropdown-panel p-component': true,
634
+ 'p-input-filled': this.config.inputStyle === 'filled',
635
+ 'p-ripple-disabled': this.config.ripple === false
636
+ };
637
+ }
638
+ visibleOptions = computed(() => {
639
+ const options = this.group ? this.flatOptions(this.options) : this.options || [];
640
+ if (this._filterValue()) {
641
+ const filteredOptions = this.filterService.filter(options, this.searchFields(), this._filterValue(), this.filterMatchMode, this.filterLocale);
642
+ if (this.group) {
643
+ const optionGroups = this.options || [];
644
+ const filtered = [];
645
+ optionGroups.forEach((group) => {
646
+ const groupChildren = this.getOptionGroupChildren(group);
647
+ const filteredItems = groupChildren.filter((item) => filteredOptions.includes(item));
648
+ if (filteredItems.length > 0)
649
+ filtered.push({ ...group, [typeof this.optionGroupChildren === 'string' ? this.optionGroupChildren : 'items']: [...filteredItems] });
650
+ });
651
+ return this.flatOptions(filtered);
652
+ }
653
+ return filteredOptions;
654
+ }
655
+ return options;
656
+ });
657
+ label = computed(() => {
658
+ let selectedOptionIndex;
659
+ if (this.autoDisplayFirst) {
660
+ selectedOptionIndex = this.findFirstOptionIndex();
661
+ }
662
+ if (!this.autoDisplayFirst) {
663
+ selectedOptionIndex = this.findSelectedOptionIndex();
664
+ }
665
+ return this.modelValue() ? this.getOptionLabel(this.modelValue()) : selectedOptionIndex !== -1 ? this.getOptionLabel(this.visibleOptions()[selectedOptionIndex]) : this.placeholder || 'p-emptylabel';
666
+ });
558
667
  constructor(el, renderer, cd, zone, filterService, config) {
559
668
  this.el = el;
560
669
  this.renderer = renderer;
@@ -562,6 +671,41 @@ class Dropdown {
562
671
  this.zone = zone;
563
672
  this.filterService = filterService;
564
673
  this.config = config;
674
+ effect(() => {
675
+ const modelValue = this.modelValue();
676
+ if (modelValue && this.editable) {
677
+ this.updateEditableLabel();
678
+ }
679
+ });
680
+ }
681
+ ngOnInit() {
682
+ this.id = this.id || UniqueComponentId();
683
+ this.autoUpdateModel();
684
+ if (this.filterBy) {
685
+ this.filterOptions = {
686
+ filter: (value) => this.onFilterInputChange(value),
687
+ reset: () => this.resetFilter()
688
+ };
689
+ }
690
+ }
691
+ ngAfterViewChecked() {
692
+ if (this.optionsChanged && this.overlayVisible) {
693
+ this.optionsChanged = false;
694
+ this.zone.runOutsideAngular(() => {
695
+ setTimeout(() => {
696
+ if (this.overlayViewChild) {
697
+ this.overlayViewChild.alignOverlay();
698
+ }
699
+ }, 1);
700
+ });
701
+ }
702
+ if (this.selectedOptionUpdated && this.itemsWrapper) {
703
+ let selectedItem = DomHandler.findSingle(this.overlayViewChild?.overlayViewChild?.nativeElement, 'li.p-highlight');
704
+ if (selectedItem) {
705
+ DomHandler.scrollInView(this.itemsWrapper, selectedItem);
706
+ }
707
+ this.selectedOptionUpdated = false;
708
+ }
565
709
  }
566
710
  ngAfterContentInit() {
567
711
  this.templates.forEach((item) => {
@@ -608,48 +752,60 @@ class Dropdown {
608
752
  }
609
753
  });
610
754
  }
611
- ngOnInit() {
612
- this.optionsToDisplay = this.options;
613
- this.updateSelectedOption(null);
614
- this.labelId = this.id + '_label';
615
- this.listId = this.id + '_list';
616
- if (this.filterBy) {
617
- this.filterOptions = {
618
- filter: (value) => this.onFilterInputChange(value),
619
- reset: () => this.resetFilter()
620
- };
755
+ flatOptions(options) {
756
+ return (options || []).reduce((result, option, index) => {
757
+ result.push({ optionGroup: option, group: true, index });
758
+ const optionGroupChildren = this.getOptionGroupChildren(option);
759
+ optionGroupChildren && optionGroupChildren.forEach((o) => result.push(o));
760
+ return result;
761
+ }, []);
762
+ }
763
+ autoUpdateModel() {
764
+ if (this.selectOnFocus && this.autoOptionFocus && !this.hasSelectedOption()) {
765
+ this.focusedOptionIndex.set(this.findFirstFocusedOptionIndex());
766
+ this.onOptionSelect(null, this.visibleOptions()[this.focusedOptionIndex()], false);
621
767
  }
622
- }
623
- ngAfterViewInit() {
624
- if (this.editable) {
625
- this.updateEditableLabel();
768
+ if (this.autoDisplayFirst && !this.modelValue()) {
769
+ const ind = this.findFirstOptionIndex();
770
+ this.onOptionSelect(null, this.visibleOptions()[ind], false);
626
771
  }
627
772
  }
628
- get label() {
629
- if (typeof this.selectedOption === 'number') {
630
- this.selectedOption = this.selectedOption.toString();
631
- }
632
- return this.selectedOption ? this.getOptionLabel(this.selectedOption) : null;
773
+ onOptionSelect(event, option, isHide = true) {
774
+ const value = this.getOptionValue(option);
775
+ this.updateModel(value, event);
776
+ this.focusedOptionIndex.set(this.findSelectedOptionIndex());
777
+ isHide && this.hide(true);
633
778
  }
634
- get emptyMessageLabel() {
635
- return this.emptyMessage || this.config.getTranslation(TranslationKeys.EMPTY_MESSAGE);
779
+ onOptionMouseEnter(event, index) {
780
+ if (this.focusOnHover) {
781
+ this.changeFocusedOptionIndex(event, index);
782
+ }
636
783
  }
637
- get emptyFilterMessageLabel() {
638
- return this.emptyFilterMessage || this.config.getTranslation(TranslationKeys.EMPTY_FILTER_MESSAGE);
784
+ updateModel(value, event) {
785
+ this.onModelChange(value);
786
+ this.modelValue.set(value);
787
+ this.selectedOptionUpdated = true;
788
+ this.onChange.emit({
789
+ originalEvent: event,
790
+ value: value
791
+ });
639
792
  }
640
- get filled() {
641
- if (typeof this.value === 'string')
642
- return !!this.value;
643
- return this.value || this.value != null || this.value != undefined;
793
+ isSelected(option) {
794
+ return this.isValidOption(option) && ObjectUtils.equals(this.modelValue(), this.getOptionValue(option), this.equalityKey());
644
795
  }
645
- get isVisibleClearIcon() {
646
- return this.value != null && this.value !== '' && this.showClear && !this.disabled;
796
+ ngAfterViewInit() {
797
+ if (this.editable) {
798
+ this.updateEditableLabel();
799
+ }
647
800
  }
648
801
  updateEditableLabel() {
649
- if (this.editableInputViewChild && this.editableInputViewChild.nativeElement) {
650
- this.editableInputViewChild.nativeElement.value = this.selectedOption ? this.getOptionLabel(this.selectedOption) : this.value || '';
802
+ if (this.editableInputViewChild) {
803
+ this.editableInputViewChild.nativeElement.value = this.getOptionLabel(this.modelValue()) === undefined ? this.editableInputViewChild.nativeElement.value : this.getOptionLabel(this.modelValue());
651
804
  }
652
805
  }
806
+ getOptionIndex(index, scrollerOptions) {
807
+ return this.virtualScrollerDisabled ? index : scrollerOptions && scrollerOptions.getItemOptions(index)['index'];
808
+ }
653
809
  getOptionLabel(option) {
654
810
  return this.optionLabel ? ObjectUtils.resolveFieldData(option, this.optionLabel) : option && option.label !== undefined ? option.label : option;
655
811
  }
@@ -665,53 +821,23 @@ class Dropdown {
665
821
  getOptionGroupChildren(optionGroup) {
666
822
  return this.optionGroupChildren ? ObjectUtils.resolveFieldData(optionGroup, this.optionGroupChildren) : optionGroup.items;
667
823
  }
668
- onItemClick(event) {
669
- const option = event.option;
670
- if (!this.isOptionDisabled(option)) {
671
- this.selectItem(event.originalEvent, option);
672
- this.accessibleViewChild?.nativeElement.focus({ preventScroll: true });
673
- }
674
- setTimeout(() => {
675
- this.hide();
676
- }, 1);
677
- }
678
- selectItem(event, option) {
679
- if (this.selectedOption != option) {
680
- this.selectedOption = option;
681
- this.value = this.getOptionValue(option);
682
- this.onModelChange(this.value);
683
- this.updateEditableLabel();
684
- this.onChange.emit({
685
- originalEvent: event,
686
- value: this.value
687
- });
688
- }
824
+ getAriaPosInset(index) {
825
+ return ((this.optionGroupLabel
826
+ ? index -
827
+ this.visibleOptions()
828
+ .slice(0, index)
829
+ .filter((option) => this.isOptionGroup(option)).length
830
+ : index) + 1);
689
831
  }
690
- ngAfterViewChecked() {
691
- if (this.optionsChanged && this.overlayVisible) {
692
- this.optionsChanged = false;
693
- this.zone.runOutsideAngular(() => {
694
- setTimeout(() => {
695
- if (this.overlayViewChild) {
696
- this.overlayViewChild.alignOverlay();
697
- }
698
- }, 1);
699
- });
700
- }
701
- if (this.selectedOptionUpdated && this.itemsWrapper) {
702
- let selectedItem = DomHandler.findSingle(this.overlayViewChild?.overlayViewChild?.nativeElement, 'li.p-highlight');
703
- if (selectedItem) {
704
- DomHandler.scrollInView(this.itemsWrapper, selectedItem);
705
- }
706
- this.selectedOptionUpdated = false;
707
- }
832
+ get ariaSetSize() {
833
+ return this.visibleOptions().filter((option) => !this.isOptionGroup(option)).length;
708
834
  }
709
835
  writeValue(value) {
710
836
  if (this.filter) {
711
837
  this.resetFilter();
712
838
  }
713
- this.value = value;
714
- this.updateSelectedOption(value);
839
+ this.value = this.modelValue();
840
+ this.updateModel(this.value);
715
841
  this.updateEditableLabel();
716
842
  this.cd.markForCheck();
717
843
  }
@@ -720,25 +846,10 @@ class Dropdown {
720
846
  * @group Method
721
847
  */
722
848
  resetFilter() {
723
- this._filterValue = null;
849
+ this._filterValue.set(null);
724
850
  if (this.filterViewChild && this.filterViewChild.nativeElement) {
725
851
  this.filterViewChild.nativeElement.value = '';
726
852
  }
727
- this.optionsToDisplay = this.options;
728
- }
729
- updateSelectedOption(val) {
730
- this.selectedOption = this.findOption(val, this.optionsToDisplay);
731
- if (this.autoDisplayFirst && !this.placeholder && !this.selectedOption && this.optionsToDisplay && this.optionsToDisplay.length && !this.editable) {
732
- if (this.group) {
733
- this.selectedOption = this.getOptionGroupChildren(this.optionsToDisplay[0])[0];
734
- }
735
- else {
736
- this.selectedOption = this.optionsToDisplay[0];
737
- }
738
- this.value = this.getOptionValue(this.selectedOption);
739
- this.onModelChange(this.value);
740
- }
741
- this.selectedOptionUpdated = true;
742
853
  }
743
854
  registerOnChange(fn) {
744
855
  this.onModelChange = fn;
@@ -750,48 +861,42 @@ class Dropdown {
750
861
  this.disabled = val;
751
862
  this.cd.markForCheck();
752
863
  }
753
- onMouseclick(event) {
754
- if (this.disabled || this.readonly || this.isInputClick(event)) {
864
+ onContainerClick(event) {
865
+ if (this.disabled || this.readonly) {
866
+ return;
867
+ }
868
+ this.focusInputViewChild?.nativeElement.focus({ preventScroll: true });
869
+ if (event.target.tagName === 'INPUT' || event.target.getAttribute('data-pc-section') === 'clearicon' || event.target.closest('[data-pc-section="clearicon"]')) {
755
870
  return;
756
871
  }
872
+ else if (!this.overlayViewChild || !this.overlayViewChild.el.nativeElement.contains(event.target)) {
873
+ this.overlayVisible ? this.hide(true) : this.show(true);
874
+ }
757
875
  this.onClick.emit(event);
758
- this.accessibleViewChild?.nativeElement.focus({ preventScroll: true });
759
- if (this.overlayVisible)
760
- this.hide();
761
- else
762
- this.show();
763
876
  this.cd.detectChanges();
764
877
  }
765
- isInputClick(event) {
766
- const target = event.target;
767
- return (DomHandler.hasClass(target, 'p-dropdown-clear-icon') ||
768
- target.closest('.p-dropdown-clear-icon') !== null ||
769
- target.isSameNode(this.accessibleViewChild?.nativeElement) ||
770
- (this.editableInputViewChild && target.isSameNode(this.editableInputViewChild.nativeElement)));
771
- }
772
878
  isEmpty() {
773
- return !this.optionsToDisplay || (this.optionsToDisplay && this.optionsToDisplay.length === 0);
879
+ return !this._options() || (this._options() && this._options().length === 0);
774
880
  }
775
- onEditableInputFocus(event) {
776
- this.focused = true;
777
- this.hide();
778
- this.onFocus.emit(event);
779
- }
780
- onEditableInputChange(event) {
781
- this.value = event.target.value;
782
- this.updateSelectedOption(this.value);
783
- this.onModelChange(this.value);
784
- this.onChange.emit({
785
- originalEvent: event,
786
- value: this.value
787
- });
881
+ onEditableInput(event) {
882
+ const value = event.target.value;
883
+ this.searchValue = '';
884
+ const matched = this.searchOptions(event, value);
885
+ !matched && this.focusedOptionIndex.set(-1);
886
+ this.onModelChange(value);
887
+ this.updateModel(value, event);
788
888
  }
789
889
  /**
790
890
  * Displays the panel.
791
891
  * @group Method
792
892
  */
793
- show() {
893
+ show(isFocus) {
794
894
  this.overlayVisible = true;
895
+ const focusedOptionIndex = this.focusedOptionIndex() !== -1 ? this.focusedOptionIndex() : this.autoOptionFocus ? this.findFirstFocusedOptionIndex() : -1;
896
+ this.focusedOptionIndex.set(focusedOptionIndex);
897
+ if (isFocus) {
898
+ DomHandler.focus(this.focusInputViewChild?.nativeElement);
899
+ }
795
900
  this.cd.markForCheck();
796
901
  }
797
902
  onOverlayAnimationStart(event) {
@@ -800,9 +905,9 @@ class Dropdown {
800
905
  this.virtualScroll && this.scroller?.setContentEl(this.itemsViewChild?.nativeElement);
801
906
  if (this.options && this.options.length) {
802
907
  if (this.virtualScroll) {
803
- const selectedIndex = this.selectedOption ? this.findOptionIndex(this.getOptionValue(this.selectedOption), this.optionsToDisplay) : -1;
908
+ const selectedIndex = this.modelValue() ? this.focusedOptionIndex() : -1;
804
909
  if (selectedIndex !== -1) {
805
- this.scroller?.scrollToIndex(selectedIndex);
910
+ this.scroller?.scrollToIndex(0);
806
911
  }
807
912
  }
808
913
  else {
@@ -830,15 +935,24 @@ class Dropdown {
830
935
  * Hides the panel.
831
936
  * @group Method
832
937
  */
833
- hide() {
938
+ hide(isFocus) {
834
939
  this.overlayVisible = false;
940
+ this.focusedOptionIndex.set(-1);
835
941
  if (this.filter && this.resetFilterOnHide) {
836
942
  this.resetFilter();
837
943
  }
944
+ isFocus && DomHandler.focus(this.focusInputViewChild?.nativeElement);
838
945
  this.cd.markForCheck();
839
946
  }
840
947
  onInputFocus(event) {
948
+ if (this.disabled) {
949
+ // For ScreenReaders
950
+ return;
951
+ }
841
952
  this.focused = true;
953
+ const focusedOptionIndex = this.focusedOptionIndex() !== -1 ? this.focusedOptionIndex() : this.overlayVisible && this.autoOptionFocus ? this.findFirstFocusedOptionIndex() : -1;
954
+ this.focusedOptionIndex.set(focusedOptionIndex);
955
+ this.overlayVisible && this.scrollInView(this.focusedOptionIndex());
842
956
  this.onFocus.emit(event);
843
957
  }
844
958
  onInputBlur(event) {
@@ -849,331 +963,337 @@ class Dropdown {
849
963
  }
850
964
  this.preventModelTouched = false;
851
965
  }
852
- findPrevEnabledOption(index) {
853
- let prevEnabledOption;
854
- if (this.optionsToDisplay && this.optionsToDisplay.length) {
855
- for (let i = index - 1; 0 <= i; i--) {
856
- let option = this.optionsToDisplay[i];
857
- if (this.isOptionDisabled(option)) {
858
- continue;
859
- }
860
- else {
861
- prevEnabledOption = option;
862
- break;
863
- }
864
- }
865
- if (!prevEnabledOption) {
866
- for (let i = this.optionsToDisplay.length - 1; i >= index; i--) {
867
- let option = this.optionsToDisplay[i];
868
- if (this.isOptionDisabled(option)) {
869
- continue;
870
- }
871
- else {
872
- prevEnabledOption = option;
873
- break;
874
- }
875
- }
876
- }
877
- }
878
- return prevEnabledOption;
879
- }
880
- findNextEnabledOption(index) {
881
- let nextEnabledOption;
882
- if (this.optionsToDisplay && this.optionsToDisplay.length) {
883
- for (let i = index + 1; i < this.optionsToDisplay.length; i++) {
884
- let option = this.optionsToDisplay[i];
885
- if (this.isOptionDisabled(option)) {
886
- continue;
887
- }
888
- else {
889
- nextEnabledOption = option;
890
- break;
891
- }
892
- }
893
- if (!nextEnabledOption) {
894
- for (let i = 0; i < index; i++) {
895
- let option = this.optionsToDisplay[i];
896
- if (this.isOptionDisabled(option)) {
897
- continue;
898
- }
899
- else {
900
- nextEnabledOption = option;
901
- break;
902
- }
903
- }
904
- }
905
- }
906
- return nextEnabledOption;
907
- }
908
- onKeydown(event, search) {
909
- if (this.readonly || !this.optionsToDisplay || this.optionsToDisplay.length === null) {
966
+ onKeyDown(event, search) {
967
+ if (this.disabled || this.readonly) {
910
968
  return;
911
969
  }
912
- switch (event.which) {
970
+ switch (event.code) {
913
971
  //down
914
- case 40:
915
- if (!this.overlayVisible && event.altKey) {
916
- this.show();
917
- }
918
- else {
919
- if (this.group) {
920
- let selectedItemIndex = this.selectedOption ? this.findOptionGroupIndex(this.getOptionValue(this.selectedOption), this.optionsToDisplay) : -1;
921
- if (selectedItemIndex !== -1) {
922
- let nextItemIndex = selectedItemIndex.itemIndex + 1;
923
- if (nextItemIndex < this.getOptionGroupChildren(this.optionsToDisplay[selectedItemIndex.groupIndex]).length) {
924
- this.selectItem(event, this.getOptionGroupChildren(this.optionsToDisplay[selectedItemIndex.groupIndex])[nextItemIndex]);
925
- this.selectedOptionUpdated = true;
926
- }
927
- else if (this.optionsToDisplay[selectedItemIndex.groupIndex + 1]) {
928
- this.selectItem(event, this.getOptionGroupChildren(this.optionsToDisplay[selectedItemIndex.groupIndex + 1])[0]);
929
- this.selectedOptionUpdated = true;
930
- }
931
- }
932
- else {
933
- if (this.optionsToDisplay && this.optionsToDisplay.length > 0) {
934
- this.selectItem(event, this.getOptionGroupChildren(this.optionsToDisplay[0])[0]);
935
- }
936
- }
937
- }
938
- else {
939
- let selectedItemIndex = this.selectedOption ? this.findOptionIndex(this.getOptionValue(this.selectedOption), this.optionsToDisplay) : -1;
940
- let nextEnabledOption = this.findNextEnabledOption(selectedItemIndex);
941
- if (nextEnabledOption) {
942
- this.selectItem(event, nextEnabledOption);
943
- this.selectedOptionUpdated = true;
944
- }
945
- }
946
- }
947
- event.preventDefault();
972
+ case 'ArrowDown':
973
+ this.onArrowDownKey(event);
948
974
  break;
949
975
  //up
950
- case 38:
951
- if (this.group) {
952
- let selectedItemIndex = this.selectedOption ? this.findOptionGroupIndex(this.getOptionValue(this.selectedOption), this.optionsToDisplay) : -1;
953
- if (selectedItemIndex !== -1) {
954
- let prevItemIndex = selectedItemIndex.itemIndex - 1;
955
- if (prevItemIndex >= 0) {
956
- this.selectItem(event, this.getOptionGroupChildren(this.optionsToDisplay[selectedItemIndex.groupIndex])[prevItemIndex]);
957
- this.selectedOptionUpdated = true;
958
- }
959
- else if (prevItemIndex < 0) {
960
- let prevGroup = this.optionsToDisplay[selectedItemIndex.groupIndex - 1];
961
- if (prevGroup) {
962
- this.selectItem(event, this.getOptionGroupChildren(prevGroup)[this.getOptionGroupChildren(prevGroup).length - 1]);
963
- this.selectedOptionUpdated = true;
964
- }
965
- }
966
- }
967
- }
968
- else {
969
- let selectedItemIndex = this.selectedOption ? this.findOptionIndex(this.getOptionValue(this.selectedOption), this.optionsToDisplay) : -1;
970
- let prevEnabledOption = this.findPrevEnabledOption(selectedItemIndex);
971
- if (prevEnabledOption) {
972
- this.selectItem(event, prevEnabledOption);
973
- this.selectedOptionUpdated = true;
974
- }
975
- }
976
- event.preventDefault();
976
+ case 'ArrowUp':
977
+ this.onArrowUpKey(event, this.editable);
978
+ break;
979
+ case 'ArrowLeft':
980
+ case 'ArrowRight':
981
+ this.onArrowLeftKey(event, this.editable);
982
+ break;
983
+ case 'Delete':
984
+ this.onDeleteKey(event);
985
+ break;
986
+ case 'Home':
987
+ this.onHomeKey(event, this.editable);
988
+ break;
989
+ case 'End':
990
+ this.onEndKey(event, this.editable);
991
+ break;
992
+ case 'PageDown':
993
+ this.onPageDownKey(event);
994
+ break;
995
+ case 'PageUp':
996
+ this.onPageUpKey(event);
977
997
  break;
978
998
  //space
979
- case 32:
980
- if (search) {
981
- if (!this.overlayVisible) {
982
- this.show();
983
- }
984
- else {
985
- this.hide();
986
- }
987
- event.preventDefault();
988
- }
999
+ case 'Space':
1000
+ this.onSpaceKey(event, search);
989
1001
  break;
990
1002
  //enter
991
- case 13:
992
- if (this.overlayVisible && (!this.filter || (this.optionsToDisplay && this.optionsToDisplay.length > 0))) {
993
- this.hide();
994
- }
995
- else if (!this.overlayVisible) {
996
- this.show();
997
- }
998
- event.preventDefault();
1003
+ case 'Enter':
1004
+ case 'NumpadEnter':
1005
+ this.onEnterKey(event);
999
1006
  break;
1000
1007
  //escape and tab
1001
- case 27:
1002
- case 9:
1003
- this.hide();
1004
- event.preventDefault();
1008
+ case 'Escape':
1009
+ this.onEscapeKey(event);
1010
+ break;
1011
+ case 'Tab':
1012
+ this.onTabKey(event);
1013
+ break;
1014
+ case 'Backspace':
1015
+ this.onBackspaceKey(event, this.editable);
1016
+ break;
1017
+ case 'ShiftLeft':
1018
+ case 'ShiftRight':
1019
+ //NOOP
1005
1020
  break;
1006
- //search item based on keyboard input
1007
1021
  default:
1008
- if (search && !event.metaKey && event.which !== 17) {
1009
- this.search(event);
1022
+ if (!event.metaKey && ObjectUtils.isPrintableCharacter(event.key)) {
1023
+ !this.overlayVisible && this.show();
1024
+ !this.editable && this.searchOptions(event, event.key);
1010
1025
  }
1011
1026
  break;
1012
1027
  }
1013
1028
  }
1014
- search(event) {
1015
- if (this.searchTimeout) {
1016
- clearTimeout(this.searchTimeout);
1017
- }
1018
- const char = event.key;
1019
- this.previousSearchChar = this.currentSearchChar;
1020
- this.currentSearchChar = char;
1021
- if (this.previousSearchChar === this.currentSearchChar)
1022
- this.searchValue = this.currentSearchChar;
1023
- else
1024
- this.searchValue = this.searchValue ? this.searchValue + char : char;
1025
- let newOption;
1026
- if (this.group) {
1027
- let searchIndex = this.selectedOption ? this.findOptionGroupIndex(this.getOptionValue(this.selectedOption), this.optionsToDisplay) : { groupIndex: 0, itemIndex: 0 };
1028
- newOption = this.searchOptionWithinGroup(searchIndex);
1029
- }
1030
- else {
1031
- let searchIndex = this.selectedOption ? this.findOptionIndex(this.getOptionValue(this.selectedOption), this.optionsToDisplay) : -1;
1032
- newOption = this.searchOption(++searchIndex);
1033
- }
1034
- if (newOption && !this.isOptionDisabled(newOption)) {
1035
- this.selectItem(event, newOption);
1036
- this.selectedOptionUpdated = true;
1029
+ onFilterKeyDown(event) {
1030
+ switch (event.code) {
1031
+ case 'ArrowDown':
1032
+ this.onArrowDownKey(event);
1033
+ break;
1034
+ case 'ArrowUp':
1035
+ this.onArrowUpKey(event, true);
1036
+ break;
1037
+ case 'ArrowLeft':
1038
+ case 'ArrowRight':
1039
+ this.onArrowLeftKey(event, true);
1040
+ break;
1041
+ case 'Home':
1042
+ this.onHomeKey(event, true);
1043
+ break;
1044
+ case 'End':
1045
+ this.onEndKey(event, true);
1046
+ break;
1047
+ case 'Enter':
1048
+ this.onEnterKey(event);
1049
+ break;
1050
+ case 'Escape':
1051
+ this.onEscapeKey(event);
1052
+ break;
1053
+ case 'Tab':
1054
+ this.onTabKey(event, true);
1055
+ break;
1056
+ default:
1057
+ break;
1037
1058
  }
1038
- this.searchTimeout = setTimeout(() => {
1039
- this.searchValue = null;
1040
- }, 250);
1041
- }
1042
- searchOption(index) {
1043
- let option;
1044
- if (this.searchValue) {
1045
- option = this.searchOptionInRange(index, this.optionsToDisplay.length);
1046
- if (!option) {
1047
- option = this.searchOptionInRange(0, index);
1059
+ }
1060
+ onFilterBlur(event) {
1061
+ this.focusedOptionIndex.set(-1);
1062
+ }
1063
+ onArrowDownKey(event) {
1064
+ const optionIndex = this.focusedOptionIndex() !== -1 ? this.findNextOptionIndex(this.focusedOptionIndex()) : this.findFirstFocusedOptionIndex();
1065
+ this.changeFocusedOptionIndex(event, optionIndex);
1066
+ !this.overlayVisible && this.show();
1067
+ event.preventDefault();
1068
+ }
1069
+ changeFocusedOptionIndex(event, index) {
1070
+ if (this.focusedOptionIndex() !== index) {
1071
+ this.focusedOptionIndex.set(index);
1072
+ this.scrollInView();
1073
+ if (this.selectOnFocus) {
1074
+ const option = this.visibleOptions()[index];
1075
+ this.onOptionSelect(event, option, false);
1048
1076
  }
1049
1077
  }
1050
- return option;
1051
- }
1052
- searchOptionInRange(start, end) {
1053
- for (let i = start; i < end; i++) {
1054
- let opt = this.optionsToDisplay[i];
1055
- if (this.getOptionLabel(opt)
1056
- .toLocaleLowerCase(this.filterLocale)
1057
- .startsWith(this.searchValue.toLocaleLowerCase(this.filterLocale)) &&
1058
- !this.isOptionDisabled(opt)) {
1059
- return opt;
1078
+ }
1079
+ get virtualScrollerDisabled() {
1080
+ return !this.virtualScroll;
1081
+ }
1082
+ scrollInView(index = -1) {
1083
+ const id = index !== -1 ? `${this.id}_${index}` : this.focusedOptionId;
1084
+ if (this.itemsViewChild && this.itemsViewChild.nativeElement) {
1085
+ const element = DomHandler.findSingle(this.itemsViewChild.nativeElement, `li[id="${id}"]`);
1086
+ if (element) {
1087
+ element.scrollIntoView && element.scrollIntoView({ block: 'nearest', inline: 'start' });
1060
1088
  }
1061
- }
1062
- return null;
1063
- }
1064
- searchOptionWithinGroup(index) {
1065
- let option;
1066
- if (this.searchValue) {
1067
- if (this.optionsToDisplay) {
1068
- for (let i = index.groupIndex; i < this.optionsToDisplay.length; i++) {
1069
- for (let j = index.groupIndex === i ? index.itemIndex + 1 : 0; j < this.getOptionGroupChildren(this.optionsToDisplay[i]).length; j++) {
1070
- let opt = this.getOptionGroupChildren(this.optionsToDisplay[i])[j];
1071
- if (this.getOptionLabel(opt)
1072
- .toLocaleLowerCase(this.filterLocale)
1073
- .startsWith(this.searchValue.toLocaleLowerCase(this.filterLocale)) &&
1074
- !this.isOptionDisabled(opt)) {
1075
- return opt;
1076
- }
1077
- }
1078
- }
1079
- if (!option) {
1080
- for (let i = 0; i <= index.groupIndex; i++) {
1081
- for (let j = 0; j < (index.groupIndex === i ? index.itemIndex : this.getOptionGroupChildren(this.optionsToDisplay[i]).length); j++) {
1082
- let opt = this.getOptionGroupChildren(this.optionsToDisplay[i])[j];
1083
- if (this.getOptionLabel(opt)
1084
- .toLocaleLowerCase(this.filterLocale)
1085
- .startsWith(this.searchValue.toLocaleLowerCase(this.filterLocale)) &&
1086
- !this.isOptionDisabled(opt)) {
1087
- return opt;
1088
- }
1089
- }
1090
- }
1091
- }
1089
+ else if (!this.virtualScrollerDisabled) {
1090
+ setTimeout(() => {
1091
+ this.virtualScroll && this.scroller?.scrollToIndex(index !== -1 ? index : this.focusedOptionIndex());
1092
+ }, 0);
1092
1093
  }
1093
1094
  }
1094
- return null;
1095
- }
1096
- findOptionIndex(val, opts) {
1097
- let index = -1;
1098
- if (opts) {
1099
- for (let i = 0; i < opts.length; i++) {
1100
- if ((val == null && this.getOptionValue(opts[i]) == null) || ObjectUtils.equals(val, this.getOptionValue(opts[i]), this.dataKey)) {
1101
- index = i;
1102
- break;
1103
- }
1095
+ }
1096
+ get focusedOptionId() {
1097
+ return this.focusedOptionIndex() !== -1 ? `${this.id}_${this.focusedOptionIndex()}` : null;
1098
+ }
1099
+ hasSelectedOption() {
1100
+ return ObjectUtils.isNotEmpty(this.modelValue());
1101
+ }
1102
+ isValidSelectedOption(option) {
1103
+ return this.isValidOption(option) && this.isSelected(option);
1104
+ }
1105
+ equalityKey() {
1106
+ return this.optionValue ? null : this.dataKey;
1107
+ }
1108
+ findFirstFocusedOptionIndex() {
1109
+ const selectedIndex = this.findSelectedOptionIndex();
1110
+ return selectedIndex < 0 ? this.findFirstOptionIndex() : selectedIndex;
1111
+ }
1112
+ findFirstOptionIndex() {
1113
+ return this.visibleOptions().findIndex((option) => this.isValidOption(option));
1114
+ }
1115
+ findSelectedOptionIndex() {
1116
+ return this.hasSelectedOption() ? this.visibleOptions().findIndex((option) => this.isValidSelectedOption(option)) : -1;
1117
+ }
1118
+ findNextOptionIndex(index) {
1119
+ const matchedOptionIndex = index < this.visibleOptions().length - 1
1120
+ ? this.visibleOptions()
1121
+ .slice(index + 1)
1122
+ .findIndex((option) => this.isValidOption(option))
1123
+ : -1;
1124
+ return matchedOptionIndex > -1 ? matchedOptionIndex + index + 1 : index;
1125
+ }
1126
+ findPrevOptionIndex(index) {
1127
+ const matchedOptionIndex = index > 0 ? ObjectUtils.findLastIndex(this.visibleOptions().slice(0, index), (option) => this.isValidOption(option)) : -1;
1128
+ return matchedOptionIndex > -1 ? matchedOptionIndex : index;
1129
+ }
1130
+ findLastOptionIndex() {
1131
+ return ObjectUtils.findLastIndex(this.visibleOptions(), (option) => this.isValidOption(option));
1132
+ }
1133
+ findLastFocusedOptionIndex() {
1134
+ const selectedIndex = this.findSelectedOptionIndex();
1135
+ return selectedIndex < 0 ? this.findLastOptionIndex() : selectedIndex;
1136
+ }
1137
+ isValidOption(option) {
1138
+ return option && !(this.isOptionDisabled(option) || this.isOptionGroup(option));
1139
+ }
1140
+ isOptionGroup(option) {
1141
+ return this.optionGroupLabel && option.optionGroup && option.group;
1142
+ }
1143
+ onArrowUpKey(event, pressedInInputText = false) {
1144
+ if (event.altKey && !pressedInInputText) {
1145
+ if (this.focusedOptionIndex() !== -1) {
1146
+ const option = this.visibleOptions()[this.focusedOptionIndex()];
1147
+ this.onOptionSelect(event, option);
1104
1148
  }
1149
+ this.overlayVisible && this.hide();
1150
+ event.preventDefault();
1105
1151
  }
1106
- return index;
1107
- }
1108
- findOptionGroupIndex(val, opts) {
1109
- let groupIndex, itemIndex;
1110
- if (opts) {
1111
- for (let i = 0; i < opts.length; i++) {
1112
- groupIndex = i;
1113
- itemIndex = this.findOptionIndex(val, this.getOptionGroupChildren(opts[i]));
1114
- if (itemIndex !== -1) {
1115
- break;
1116
- }
1117
- }
1152
+ else {
1153
+ const optionIndex = this.focusedOptionIndex() !== -1 ? this.findPrevOptionIndex(this.focusedOptionIndex()) : this.findLastFocusedOptionIndex();
1154
+ this.changeFocusedOptionIndex(event, optionIndex);
1155
+ !this.overlayVisible && this.show();
1156
+ event.preventDefault();
1118
1157
  }
1119
- if (itemIndex !== -1) {
1120
- return { groupIndex: groupIndex, itemIndex: itemIndex };
1158
+ }
1159
+ onArrowLeftKey(event, pressedInInputText = false) {
1160
+ pressedInInputText && this.focusedOptionIndex.set(-1);
1161
+ }
1162
+ onDeleteKey(event) {
1163
+ if (this.showClear) {
1164
+ this.clear(event);
1165
+ event.preventDefault();
1166
+ }
1167
+ }
1168
+ onHomeKey(event, pressedInInputText = false) {
1169
+ if (pressedInInputText) {
1170
+ event.currentTarget.setSelectionRange(0, 0);
1171
+ this.focusedOptionIndex.set(-1);
1121
1172
  }
1122
1173
  else {
1123
- return -1;
1174
+ this.changeFocusedOptionIndex(event, this.findFirstOptionIndex());
1175
+ !this.overlayVisible && this.show();
1124
1176
  }
1125
- }
1126
- findOption(val, opts, inGroup) {
1127
- if (this.group && !inGroup) {
1128
- let opt;
1129
- if (opts && opts.length) {
1130
- for (let optgroup of opts) {
1131
- opt = this.findOption(val, this.getOptionGroupChildren(optgroup), true);
1132
- if (opt) {
1133
- break;
1134
- }
1135
- }
1136
- }
1137
- return opt;
1177
+ event.preventDefault();
1178
+ }
1179
+ onEndKey(event, pressedInInputText = false) {
1180
+ if (pressedInInputText) {
1181
+ const target = event.currentTarget;
1182
+ const len = target.value.length;
1183
+ target.setSelectionRange(len, len);
1184
+ this.focusedOptionIndex.set(-1);
1138
1185
  }
1139
1186
  else {
1140
- let index = this.findOptionIndex(val, opts);
1141
- return index != -1 ? opts[index] : null;
1187
+ this.changeFocusedOptionIndex(event, this.findLastOptionIndex());
1188
+ !this.overlayVisible && this.show();
1142
1189
  }
1190
+ event.preventDefault();
1143
1191
  }
1144
- onFilterInputChange(event) {
1145
- let inputValue = event.target.value?.trim();
1146
- if (inputValue && inputValue.length) {
1147
- this._filterValue = inputValue;
1148
- this.activateFilter();
1192
+ onPageDownKey(event) {
1193
+ this.scrollInView(this.visibleOptions().length - 1);
1194
+ event.preventDefault();
1195
+ }
1196
+ onPageUpKey(event) {
1197
+ this.scrollInView(0);
1198
+ event.preventDefault();
1199
+ }
1200
+ onSpaceKey(event, pressedInInputText = false) {
1201
+ !pressedInInputText && this.onEnterKey(event);
1202
+ }
1203
+ onEnterKey(event) {
1204
+ if (!this.overlayVisible) {
1205
+ this.onArrowDownKey(event);
1149
1206
  }
1150
1207
  else {
1151
- this._filterValue = null;
1152
- this.optionsToDisplay = this.options;
1208
+ if (this.focusedOptionIndex() !== -1) {
1209
+ const option = this.visibleOptions()[this.focusedOptionIndex()];
1210
+ this.onOptionSelect(event, option);
1211
+ }
1212
+ this.hide();
1153
1213
  }
1154
- this.virtualScroll && this.scroller?.scrollToIndex(0);
1155
- this.optionsChanged = true;
1156
- this.onFilter.emit({ originalEvent: event, filter: this._filterValue });
1214
+ event.preventDefault();
1157
1215
  }
1158
- activateFilter() {
1159
- let searchFields = (this.filterBy || this.optionLabel || 'label').split(',');
1160
- if (this.options && this.options.length) {
1161
- if (this.group) {
1162
- let filteredGroups = [];
1163
- for (let optgroup of this.options) {
1164
- let filteredSubOptions = this.filterService.filter(this.getOptionGroupChildren(optgroup), searchFields, this.filterValue, this.filterMatchMode, this.filterLocale);
1165
- if (filteredSubOptions && filteredSubOptions.length) {
1166
- filteredGroups.push({ ...optgroup, ...{ [this.optionGroupChildren]: filteredSubOptions } });
1167
- }
1168
- }
1169
- this.optionsToDisplay = filteredGroups;
1216
+ onEscapeKey(event) {
1217
+ this.overlayVisible && this.hide(true);
1218
+ event.preventDefault();
1219
+ }
1220
+ onTabKey(event, pressedInInputText = false) {
1221
+ if (!pressedInInputText) {
1222
+ if (this.overlayVisible && this.hasFocusableElements()) {
1223
+ DomHandler.focus(this.firstHiddenFocusableElementOnOverlay.nativeElement);
1224
+ event.preventDefault();
1170
1225
  }
1171
1226
  else {
1172
- this.optionsToDisplay = this.filterService.filter(this.options, searchFields, this.filterValue, this.filterMatchMode, this.filterLocale);
1227
+ if (this.focusedOptionIndex() !== -1) {
1228
+ const option = this.visibleOptions()[this.focusedOptionIndex()];
1229
+ this.onOptionSelect(event, option);
1230
+ }
1231
+ this.overlayVisible && this.hide(this.filter);
1173
1232
  }
1174
- this.optionsChanged = true;
1175
1233
  }
1176
1234
  }
1235
+ onFirstHiddenFocus(event) {
1236
+ const focusableEl = event.relatedTarget === this.focusInputViewChild.nativeElement ? DomHandler.getFirstFocusableElement(this.overlayViewChild.el.nativeElement, ':not(.p-hidden-focusable)') : this.focusInputViewChild.nativeElement;
1237
+ DomHandler.focus(focusableEl);
1238
+ }
1239
+ hasFocusableElements() {
1240
+ return DomHandler.getFocusableElements(this.overlayViewChild.overlayViewChild.nativeElement, ':not(.p-hidden-focusable)').length > 0;
1241
+ }
1242
+ onBackspaceKey(event, pressedInInputText = false) {
1243
+ if (pressedInInputText) {
1244
+ !this.overlayVisible && this.show();
1245
+ }
1246
+ }
1247
+ searchFields() {
1248
+ return this.filterFields || [this.optionLabel];
1249
+ }
1250
+ searchOptions(event, char) {
1251
+ this.searchValue = (this.searchValue || '') + char;
1252
+ let optionIndex = -1;
1253
+ let matched = false;
1254
+ if (this.focusedOptionIndex() !== -1) {
1255
+ optionIndex = this.visibleOptions()
1256
+ .slice(this.focusedOptionIndex())
1257
+ .findIndex((option) => this.isOptionMatched(option));
1258
+ optionIndex =
1259
+ optionIndex === -1
1260
+ ? this.visibleOptions()
1261
+ .slice(0, this.focusedOptionIndex())
1262
+ .findIndex((option) => this.isOptionMatched(option))
1263
+ : optionIndex + this.focusedOptionIndex();
1264
+ }
1265
+ else {
1266
+ optionIndex = this.visibleOptions().findIndex((option) => this.isOptionMatched(option));
1267
+ }
1268
+ if (optionIndex !== -1) {
1269
+ matched = true;
1270
+ }
1271
+ if (optionIndex === -1 && this.focusedOptionIndex() === -1) {
1272
+ optionIndex = this.findFirstFocusedOptionIndex();
1273
+ }
1274
+ if (optionIndex !== -1) {
1275
+ this.changeFocusedOptionIndex(event, optionIndex);
1276
+ }
1277
+ if (this.searchTimeout) {
1278
+ clearTimeout(this.searchTimeout);
1279
+ }
1280
+ this.searchTimeout = setTimeout(() => {
1281
+ this.searchValue = '';
1282
+ this.searchTimeout = null;
1283
+ }, 500);
1284
+ return matched;
1285
+ }
1286
+ isOptionMatched(option) {
1287
+ return this.isValidOption(option) && this.getOptionLabel(option).toLocaleLowerCase(this.filterLocale).startsWith(this.searchValue.toLocaleLowerCase(this.filterLocale));
1288
+ }
1289
+ onFilterInputChange(event) {
1290
+ let value = event.target.value?.trim();
1291
+ this._filterValue.set(value);
1292
+ this.focusedOptionIndex.set(-1);
1293
+ this.onFilter.emit({ originalEvent: event, filter: this._filterValue() });
1294
+ !this.virtualScrollerDisabled && this.scroller.scrollToIndex(0);
1295
+ this.cd.markForCheck();
1296
+ }
1177
1297
  applyFocus() {
1178
1298
  if (this.editable)
1179
1299
  DomHandler.findSingle(this.el.nativeElement, '.p-dropdown-label.p-inputtext').focus();
@@ -1188,84 +1308,64 @@ class Dropdown {
1188
1308
  this.applyFocus();
1189
1309
  }
1190
1310
  clear(event) {
1191
- this.value = null;
1192
- this.onModelChange(this.value);
1193
- this.onChange.emit({
1194
- originalEvent: event,
1195
- value: this.value
1196
- });
1197
- this.updateSelectedOption(this.value);
1311
+ this.updateModel(event, null);
1198
1312
  this.updateEditableLabel();
1199
1313
  this.onClear.emit(event);
1200
1314
  }
1201
1315
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: Dropdown, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }, { token: i0.NgZone }, { token: i3.FilterService }, { token: i3.PrimeNGConfig }], target: i0.ɵɵFactoryTarget.Component });
1202
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.0.2", type: Dropdown, selector: "p-dropdown", inputs: { scrollHeight: "scrollHeight", filter: "filter", name: "name", style: "style", panelStyle: "panelStyle", styleClass: "styleClass", panelStyleClass: "panelStyleClass", readonly: "readonly", required: "required", editable: "editable", appendTo: "appendTo", tabindex: "tabindex", placeholder: "placeholder", filterPlaceholder: "filterPlaceholder", filterLocale: "filterLocale", inputId: "inputId", dataKey: "dataKey", filterBy: "filterBy", autofocus: "autofocus", resetFilterOnHide: "resetFilterOnHide", dropdownIcon: "dropdownIcon", optionLabel: "optionLabel", optionValue: "optionValue", optionDisabled: "optionDisabled", optionGroupLabel: "optionGroupLabel", optionGroupChildren: "optionGroupChildren", autoDisplayFirst: "autoDisplayFirst", group: "group", showClear: "showClear", emptyFilterMessage: "emptyFilterMessage", emptyMessage: "emptyMessage", lazy: "lazy", virtualScroll: "virtualScroll", virtualScrollItemSize: "virtualScrollItemSize", virtualScrollOptions: "virtualScrollOptions", overlayOptions: "overlayOptions", ariaFilterLabel: "ariaFilterLabel", ariaLabel: "ariaLabel", ariaLabelledBy: "ariaLabelledBy", filterMatchMode: "filterMatchMode", maxlength: "maxlength", tooltip: "tooltip", tooltipPosition: "tooltipPosition", tooltipPositionStyle: "tooltipPositionStyle", tooltipStyleClass: "tooltipStyleClass", autofocusFilter: "autofocusFilter", disabled: "disabled", itemSize: "itemSize", autoZIndex: "autoZIndex", baseZIndex: "baseZIndex", showTransitionOptions: "showTransitionOptions", hideTransitionOptions: "hideTransitionOptions", filterValue: "filterValue", options: "options" }, outputs: { onChange: "onChange", onFilter: "onFilter", onFocus: "onFocus", onBlur: "onBlur", onClick: "onClick", onShow: "onShow", onHide: "onHide", onClear: "onClear", onLazyLoad: "onLazyLoad" }, host: { properties: { "class.p-inputwrapper-filled": "filled", "class.p-inputwrapper-focus": "focused || overlayVisible" }, classAttribute: "p-element p-inputwrapper" }, providers: [DROPDOWN_VALUE_ACCESSOR], queries: [{ propertyName: "templates", predicate: PrimeTemplate }], viewQueries: [{ propertyName: "containerViewChild", first: true, predicate: ["container"], descendants: true }, { propertyName: "filterViewChild", first: true, predicate: ["filter"], descendants: true }, { propertyName: "accessibleViewChild", first: true, predicate: ["in"], descendants: true }, { propertyName: "editableInputViewChild", first: true, predicate: ["editableInput"], descendants: true }, { propertyName: "itemsViewChild", first: true, predicate: ["items"], descendants: true }, { propertyName: "scroller", first: true, predicate: ["scroller"], descendants: true }, { propertyName: "overlayViewChild", first: true, predicate: ["overlay"], descendants: true }], ngImport: i0, template: `
1203
- <div
1204
- #container
1205
- [ngClass]="{ 'p-dropdown p-component': true, 'p-disabled': disabled, 'p-dropdown-open': overlayVisible, 'p-focus': focused, 'p-dropdown-clearable': showClear && !disabled }"
1206
- (click)="onMouseclick($event)"
1207
- [ngStyle]="style"
1208
- [class]="styleClass"
1209
- >
1210
- <div class="p-hidden-accessible">
1211
- <input
1212
- #in
1213
- [attr.id]="inputId"
1214
- type="text"
1215
- readonly
1216
- (focus)="onInputFocus($event)"
1217
- aria-haspopup="listbox"
1218
- [attr.placeholder]="placeholder"
1219
- aria-haspopup="listbox"
1220
- [attr.aria-label]="ariaLabel"
1221
- [attr.aria-expanded]="false"
1222
- [attr.aria-labelledby]="ariaLabelledBy"
1223
- (blur)="onInputBlur($event)"
1224
- (keydown)="onKeydown($event, true)"
1225
- [disabled]="disabled"
1226
- [attr.tabindex]="tabindex"
1227
- pAutoFocus
1228
- [autofocus]="autofocus"
1229
- [attr.aria-activedescendant]="overlayVisible ? labelId : null"
1230
- role="combobox"
1231
- />
1232
- </div>
1316
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.0.2", type: Dropdown, selector: "p-dropdown", inputs: { id: "id", scrollHeight: "scrollHeight", filter: "filter", name: "name", style: "style", panelStyle: "panelStyle", styleClass: "styleClass", panelStyleClass: "panelStyleClass", readonly: "readonly", required: "required", editable: "editable", appendTo: "appendTo", tabindex: "tabindex", placeholder: "placeholder", filterPlaceholder: "filterPlaceholder", filterLocale: "filterLocale", inputId: "inputId", dataKey: "dataKey", filterBy: "filterBy", filterFields: "filterFields", autofocus: "autofocus", resetFilterOnHide: "resetFilterOnHide", dropdownIcon: "dropdownIcon", optionLabel: "optionLabel", optionValue: "optionValue", optionDisabled: "optionDisabled", optionGroupLabel: "optionGroupLabel", optionGroupChildren: "optionGroupChildren", autoDisplayFirst: "autoDisplayFirst", group: "group", showClear: "showClear", emptyFilterMessage: "emptyFilterMessage", emptyMessage: "emptyMessage", lazy: "lazy", virtualScroll: "virtualScroll", virtualScrollItemSize: "virtualScrollItemSize", virtualScrollOptions: "virtualScrollOptions", overlayOptions: "overlayOptions", ariaFilterLabel: "ariaFilterLabel", ariaLabel: "ariaLabel", ariaLabelledBy: "ariaLabelledBy", filterMatchMode: "filterMatchMode", maxlength: "maxlength", tooltip: "tooltip", tooltipPosition: "tooltipPosition", tooltipPositionStyle: "tooltipPositionStyle", tooltipStyleClass: "tooltipStyleClass", focusOnHover: "focusOnHover", selectOnFocus: "selectOnFocus", autoOptionFocus: "autoOptionFocus", autofocusFilter: "autofocusFilter", disabled: "disabled", itemSize: "itemSize", autoZIndex: "autoZIndex", baseZIndex: "baseZIndex", showTransitionOptions: "showTransitionOptions", hideTransitionOptions: "hideTransitionOptions", filterValue: "filterValue", options: "options" }, outputs: { onChange: "onChange", onFilter: "onFilter", onFocus: "onFocus", onBlur: "onBlur", onClick: "onClick", onShow: "onShow", onHide: "onHide", onClear: "onClear", onLazyLoad: "onLazyLoad" }, host: { properties: { "class.p-inputwrapper-filled": "filled", "class.p-inputwrapper-focus": "focused || overlayVisible" }, classAttribute: "p-element p-inputwrapper" }, providers: [DROPDOWN_VALUE_ACCESSOR], queries: [{ propertyName: "templates", predicate: PrimeTemplate }], viewQueries: [{ propertyName: "containerViewChild", first: true, predicate: ["container"], descendants: true }, { propertyName: "filterViewChild", first: true, predicate: ["filter"], descendants: true }, { propertyName: "focusInputViewChild", first: true, predicate: ["focusInput"], descendants: true }, { propertyName: "editableInputViewChild", first: true, predicate: ["editableInput"], descendants: true }, { propertyName: "itemsViewChild", first: true, predicate: ["items"], descendants: true }, { propertyName: "scroller", first: true, predicate: ["scroller"], descendants: true }, { propertyName: "overlayViewChild", first: true, predicate: ["overlay"], descendants: true }, { propertyName: "firstHiddenFocusableElementOnOverlay", first: true, predicate: ["firstHiddenFocusableElementOnOverlay"], descendants: true }], ngImport: i0, template: `
1317
+ <div #container [attr.id]="id" [ngClass]="containerClass" (click)="onContainerClick($event)" [ngStyle]="style" [class]="styleClass">
1233
1318
  <span
1234
- [attr.id]="labelId"
1235
- [ngClass]="{ 'p-dropdown-label p-inputtext': true, 'p-dropdown-label-empty': label == null || label.length === 0 }"
1236
- *ngIf="!editable && label != null"
1319
+ #focusInput
1320
+ [ngClass]="inputClass"
1321
+ *ngIf="!editable"
1237
1322
  [pTooltip]="tooltip"
1238
1323
  [tooltipPosition]="tooltipPosition"
1239
1324
  [positionStyle]="tooltipPositionStyle"
1240
1325
  [tooltipStyleClass]="tooltipStyleClass"
1326
+ [attr.aria-disabled]="disabled"
1327
+ [attr.id]="inputId"
1328
+ role="combobox"
1329
+ [attr.aria-label]="ariaLabel"
1330
+ [attr.aria-labelledby]="ariaLabelledBy"
1331
+ [attr.aria-haspopup]="'listbox'"
1332
+ [attr.aria-expanded]="overlayVisible"
1333
+ [attr.aria-controls]="id + '_list'"
1334
+ [attr.tabindex]="!disabled ? tabindex : -1"
1335
+ pAutoFocus
1336
+ [autofocus]="autofocus"
1337
+ [attr.aria-activedescendant]="focused ? focusedOptionId : undefined"
1338
+ (focus)="onInputFocus($event)"
1339
+ (blur)="onInputBlur($event)"
1340
+ (keydown)="onKeyDown($event)"
1241
1341
  >
1242
- <ng-container *ngIf="!selectedItemTemplate">{{ label || 'empty' }}</ng-container>
1243
- <ng-container *ngTemplateOutlet="selectedItemTemplate; context: { $implicit: selectedOption }"></ng-container>
1342
+ <ng-container *ngIf="!selectedItemTemplate">{{ label() === 'p-emptylabel' ? '&nbsp;' : label() || 'empty' }}</ng-container>
1343
+ <ng-container *ngTemplateOutlet="selectedItemTemplate; context: { $implicit: modelValue() }"></ng-container>
1344
+ <span *ngIf="!editable && !label() && placeholder">{{ placeholder || 'empty' }}</span>
1244
1345
  </span>
1245
- <span [ngClass]="{ 'p-dropdown-label p-inputtext p-placeholder': true, 'p-dropdown-label-empty': placeholder == null || placeholder.length === 0 }" *ngIf="!editable && label == null">{{ placeholder || 'empty' }}</span>
1246
1346
  <input
1347
+ *ngIf="editable"
1247
1348
  #editableInput
1248
1349
  type="text"
1249
1350
  [attr.maxlength]="maxlength"
1250
- class="p-dropdown-label p-inputtext"
1251
- *ngIf="editable"
1351
+ [ngClass]="inputClass"
1252
1352
  [disabled]="disabled"
1253
- [attr.placeholder]="placeholder"
1254
1353
  aria-haspopup="listbox"
1354
+ [attr.placeholder]="placeholder"
1255
1355
  [attr.aria-expanded]="overlayVisible"
1256
- (input)="onEditableInputChange($event)"
1257
- (focus)="onEditableInputFocus($event)"
1356
+ (input)="onEditableInput($event)"
1357
+ (keydown)="onKeyDown($event)"
1358
+ (focus)="onInputFocus($event)"
1258
1359
  (blur)="onInputBlur($event)"
1259
1360
  />
1260
-
1261
1361
  <ng-container *ngIf="isVisibleClearIcon">
1262
- <TimesIcon [styleClass]="'p-dropdown-clear-icon'" (click)="clear($event)" *ngIf="!clearIconTemplate" />
1263
- <span class="p-dropdown-clear-icon" (click)="clear($event)" *ngIf="clearIconTemplate">
1362
+ <TimesIcon [styleClass]="'p-dropdown-clear-icon'" (click)="clear($event)" *ngIf="!clearIconTemplate" [attr.data-pc-section]="'clearicon'" />
1363
+ <span class="p-dropdown-clear-icon" (click)="clear($event)" *ngIf="clearIconTemplate" [attr.data-pc-section]="'clearicon'">
1264
1364
  <ng-template *ngTemplateOutlet="clearIconTemplate"></ng-template>
1265
1365
  </span>
1266
1366
  </ng-container>
1267
1367
 
1268
- <div class="p-dropdown-trigger" role="button" aria-label="dropdown trigger" aria-haspopup="listbox" [attr.aria-expanded]="overlayVisible">
1368
+ <div class="p-dropdown-trigger" role="button" aria-label="dropdown trigger" aria-haspopup="listbox" [attr.aria-expanded]="overlayVisible" [attr.data-pc-section]="'trigger'">
1269
1369
  <ng-container *ngIf="!dropdownIconTemplate">
1270
1370
  <span class="p-dropdown-trigger-icon" *ngIf="dropdownIcon" [ngClass]="dropdownIcon"></span>
1271
1371
  <ChevronDownIcon *ngIf="!dropdownIcon" [styleClass]="'p-dropdown-trigger-icon'" />
@@ -1290,6 +1390,15 @@ class Dropdown {
1290
1390
  >
1291
1391
  <ng-template pTemplate="content">
1292
1392
  <div [ngClass]="'p-dropdown-panel p-component'" [ngStyle]="panelStyle" [class]="panelStyleClass">
1393
+ <span
1394
+ #firstHiddenFocusableElementOnOverlay
1395
+ role="presentation"
1396
+ [attr.aria-hidden]="true"
1397
+ class="p-hidden-accessible p-hidden-focusable"
1398
+ [attr.tabindex]="0"
1399
+ (focus)="onFirstHiddenFocus($event)"
1400
+ [attr.data-p-hidden-focusable]="true"
1401
+ ></span>
1293
1402
  <ng-container *ngTemplateOutlet="headerTemplate"></ng-container>
1294
1403
  <div class="p-dropdown-header" *ngIf="filter" (click)="$event.stopPropagation()">
1295
1404
  <ng-container *ngIf="filterTemplate; else builtInFilterElement">
@@ -1301,14 +1410,15 @@ class Dropdown {
1301
1410
  #filter
1302
1411
  type="text"
1303
1412
  autocomplete="off"
1304
- [value]="filterValue || ''"
1413
+ [value]="_filterValue() || ''"
1305
1414
  class="p-dropdown-filter p-inputtext p-component"
1306
1415
  [attr.placeholder]="filterPlaceholder"
1307
- (keydown.enter)="$event.preventDefault()"
1308
- (keydown)="onKeydown($event, false)"
1416
+ [attr.aria-owns]="id + '_list'"
1309
1417
  (input)="onFilterInputChange($event)"
1310
1418
  [attr.aria-label]="ariaFilterLabel"
1311
- [attr.aria-activedescendant]="overlayVisible ? 'p-highlighted-option' : labelId"
1419
+ [attr.aria-activedescendant]="focusedOptionId"
1420
+ (keydown)="onFilterKeyDown($event)"
1421
+ (blur)="onFilterBlur($event)"
1312
1422
  />
1313
1423
  <SearchIcon *ngIf="!filterIconTemplate" [styleClass]="'p-dropdown-filter-icon'" />
1314
1424
  <span *ngIf="filterIconTemplate" class="p-dropdown-filter-icon">
@@ -1321,7 +1431,7 @@ class Dropdown {
1321
1431
  <p-scroller
1322
1432
  *ngIf="virtualScroll"
1323
1433
  #scroller
1324
- [items]="optionsToDisplay"
1434
+ [items]="visibleOptions()"
1325
1435
  [style]="{ height: scrollHeight }"
1326
1436
  [itemSize]="virtualScrollItemSize || _itemSize"
1327
1437
  [autoSize]="true"
@@ -1339,35 +1449,35 @@ class Dropdown {
1339
1449
  </ng-container>
1340
1450
  </p-scroller>
1341
1451
  <ng-container *ngIf="!virtualScroll">
1342
- <ng-container *ngTemplateOutlet="buildInItems; context: { $implicit: optionsToDisplay, options: {} }"></ng-container>
1452
+ <ng-container *ngTemplateOutlet="buildInItems; context: { $implicit: visibleOptions(), options: {} }"></ng-container>
1343
1453
  </ng-container>
1344
1454
 
1345
1455
  <ng-template #buildInItems let-items let-scrollerOptions="options">
1346
- <ul #items [attr.id]="listId" class="p-dropdown-items" [ngClass]="scrollerOptions.contentStyleClass" [style]="scrollerOptions.contentStyle" role="listbox">
1347
- <ng-container *ngIf="group">
1348
- <ng-template ngFor let-optgroup [ngForOf]="items">
1349
- <li class="p-dropdown-item-group" [ngStyle]="{ height: scrollerOptions.itemSize + 'px' }">
1350
- <span *ngIf="!groupTemplate">{{ getOptionGroupLabel(optgroup) || 'empty' }}</span>
1351
- <ng-container *ngTemplateOutlet="groupTemplate; context: { $implicit: optgroup }"></ng-container>
1456
+ <ul #items [attr.id]="id + '_list'" class="p-dropdown-items" [ngClass]="scrollerOptions.contentStyleClass" [style]="scrollerOptions.contentStyle" role="listbox">
1457
+ <ng-template ngFor let-option [ngForOf]="items" let-i="index">
1458
+ <ng-container *ngIf="option.group">
1459
+ <li class="p-dropdown-item-group" [attr.id]="id + '_' + getOptionIndex(i, scrollerOptions)" [ngStyle]="{ height: scrollerOptions.itemSize + 'px' }" role="option">
1460
+ <span *ngIf="!groupTemplate">{{ getOptionGroupLabel(option.optionGroup) }}</span>
1461
+ <ng-container *ngTemplateOutlet="groupTemplate; context: { $implicit: option.optionGroup }"></ng-container>
1352
1462
  </li>
1353
- <ng-container *ngTemplateOutlet="itemslist; context: { $implicit: getOptionGroupChildren(optgroup), selectedOption: selectedOption }"></ng-container>
1354
- </ng-template>
1355
- </ng-container>
1356
- <ng-container *ngIf="!group">
1357
- <ng-container *ngTemplateOutlet="itemslist; context: { $implicit: items, selectedOption: selectedOption }"></ng-container>
1358
- </ng-container>
1359
- <ng-template #itemslist let-options let-selectedOption="selectedOption">
1360
- <ng-template ngFor let-option let-i="index" [ngForOf]="options">
1463
+ </ng-container>
1464
+ <ng-container *ngIf="!option.group">
1361
1465
  <p-dropdownItem
1466
+ [id]="id + '_' + getOptionIndex(i, scrollerOptions)"
1362
1467
  [option]="option"
1363
- [selected]="selectedOption == option"
1468
+ [selected]="isSelected(option)"
1364
1469
  [label]="getOptionLabel(option)"
1365
1470
  [disabled]="isOptionDisabled(option)"
1366
- (onClick)="onItemClick($event)"
1367
1471
  [template]="itemTemplate"
1472
+ [focused]="focusedOptionIndex() === getOptionIndex(i, scrollerOptions)"
1473
+ [ariaPosInset]="getAriaPosInset(getOptionIndex(i, scrollerOptions))"
1474
+ [ariaSetSize]="ariaSetSize"
1475
+ (onClick)="onOptionSelect($event, option)"
1476
+ (onMouseEnter)="onOptionMouseEnter($event, getOptionIndex(i, scrollerOptions))"
1368
1477
  ></p-dropdownItem>
1369
- </ng-template>
1478
+ </ng-container>
1370
1479
  </ng-template>
1480
+
1371
1481
  <li *ngIf="filterValue && isEmpty()" class="p-dropdown-empty-message" [ngStyle]="{ height: scrollerOptions.itemSize + 'px' }">
1372
1482
  <ng-container *ngIf="!emptyFilterTemplate && !emptyTemplate; else emptyFilter">
1373
1483
  {{ emptyFilterMessageLabel }}
@@ -1388,77 +1498,63 @@ class Dropdown {
1388
1498
  </ng-template>
1389
1499
  </p-overlay>
1390
1500
  </div>
1391
- `, isInline: true, styles: ["@layer primeng{.p-dropdown{display:inline-flex;cursor:pointer;position:relative;-webkit-user-select:none;user-select:none}.p-dropdown-clear-icon{position:absolute;top:50%;margin-top:-.5rem}.p-dropdown-trigger{display:flex;align-items:center;justify-content:center;flex-shrink:0}.p-dropdown-label{display:block;white-space:nowrap;overflow:hidden;flex:1 1 auto;width:1%;text-overflow:ellipsis;cursor:pointer}.p-dropdown-label-empty{overflow:hidden;visibility:hidden}input.p-dropdown-label{cursor:default}.p-dropdown-items-wrapper{overflow:auto}.p-dropdown-item{cursor:pointer;font-weight:400;white-space:nowrap;position:relative;overflow:hidden}.p-dropdown-items{margin:0;padding:0;list-style-type:none}.p-dropdown-filter{width:100%}.p-dropdown-filter-container{position:relative}.p-dropdown-filter-icon{position:absolute;top:50%;margin-top:-.5rem}.p-fluid .p-dropdown{display:flex}.p-fluid .p-dropdown .p-dropdown-label{width:1%}}\n"], dependencies: [{ kind: "directive", type: i0.forwardRef(function () { return i1.NgClass; }), selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i0.forwardRef(function () { return i1.NgForOf; }), selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i0.forwardRef(function () { return i1.NgIf; }), selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i0.forwardRef(function () { return i1.NgTemplateOutlet; }), selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i0.forwardRef(function () { return i1.NgStyle; }), selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: i0.forwardRef(function () { return i4.Overlay; }), selector: "p-overlay", inputs: ["visible", "mode", "style", "styleClass", "contentStyle", "contentStyleClass", "target", "appendTo", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "listener", "responsive", "options"], outputs: ["visibleChange", "onBeforeShow", "onShow", "onBeforeHide", "onHide", "onAnimationStart", "onAnimationDone"] }, { kind: "directive", type: i0.forwardRef(function () { return i3.PrimeTemplate; }), selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "directive", type: i0.forwardRef(function () { return i5.Tooltip; }), selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "component", type: i0.forwardRef(function () { return i6.Scroller; }), selector: "p-scroller", inputs: ["id", "style", "styleClass", "tabindex", "items", "itemSize", "scrollHeight", "scrollWidth", "orientation", "step", "delay", "resizeDelay", "appendOnly", "inline", "lazy", "disabled", "loaderDisabled", "columns", "showSpacer", "showLoader", "numToleratedItems", "loading", "autoSize", "trackBy", "options"], outputs: ["onLazyLoad", "onScroll", "onScrollIndexChange"] }, { kind: "directive", type: i0.forwardRef(function () { return i7.AutoFocus; }), selector: "[pAutoFocus]", inputs: ["autofocus"] }, { kind: "component", type: i0.forwardRef(function () { return TimesIcon; }), selector: "TimesIcon" }, { kind: "component", type: i0.forwardRef(function () { return ChevronDownIcon; }), selector: "ChevronDownIcon" }, { kind: "component", type: i0.forwardRef(function () { return SearchIcon; }), selector: "SearchIcon" }, { kind: "component", type: i0.forwardRef(function () { return DropdownItem; }), selector: "p-dropdownItem", inputs: ["option", "selected", "label", "disabled", "visible", "itemSize", "template"], outputs: ["onClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1501
+ `, isInline: true, styles: ["@layer primeng{.p-dropdown{display:inline-flex;cursor:pointer;position:relative;-webkit-user-select:none;user-select:none}.p-dropdown-clear-icon{position:absolute;top:50%;margin-top:-.5rem}.p-dropdown-trigger{display:flex;align-items:center;justify-content:center;flex-shrink:0}.p-dropdown-label{display:block;white-space:nowrap;overflow:hidden;flex:1 1 auto;width:1%;text-overflow:ellipsis;cursor:pointer}.p-dropdown-label-empty{overflow:hidden;opacity:0}input.p-dropdown-label{cursor:default}.p-dropdown .p-dropdown-panel{min-width:100%}.p-dropdown-panel{position:absolute;top:0;left:0}.p-dropdown-items-wrapper{overflow:auto}.p-dropdown-item{cursor:pointer;font-weight:400;white-space:nowrap;position:relative;overflow:hidden}.p-dropdown-item-group{cursor:auto}.p-dropdown-items{margin:0;padding:0;list-style-type:none}.p-dropdown-filter{width:100%}.p-dropdown-filter-container{position:relative}.p-dropdown-filter-icon{position:absolute;top:50%;margin-top:-.5rem}.p-fluid .p-dropdown{display:flex}.p-fluid .p-dropdown .p-dropdown-label{width:1%}}\n"], dependencies: [{ kind: "directive", type: i0.forwardRef(function () { return i1.NgClass; }), selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i0.forwardRef(function () { return i1.NgForOf; }), selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i0.forwardRef(function () { return i1.NgIf; }), selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i0.forwardRef(function () { return i1.NgTemplateOutlet; }), selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i0.forwardRef(function () { return i1.NgStyle; }), selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: i0.forwardRef(function () { return i4.Overlay; }), selector: "p-overlay", inputs: ["visible", "mode", "style", "styleClass", "contentStyle", "contentStyleClass", "target", "appendTo", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "listener", "responsive", "options"], outputs: ["visibleChange", "onBeforeShow", "onShow", "onBeforeHide", "onHide", "onAnimationStart", "onAnimationDone"] }, { kind: "directive", type: i0.forwardRef(function () { return i3.PrimeTemplate; }), selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "directive", type: i0.forwardRef(function () { return i5.Tooltip; }), selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "component", type: i0.forwardRef(function () { return i6.Scroller; }), selector: "p-scroller", inputs: ["id", "style", "styleClass", "tabindex", "items", "itemSize", "scrollHeight", "scrollWidth", "orientation", "step", "delay", "resizeDelay", "appendOnly", "inline", "lazy", "disabled", "loaderDisabled", "columns", "showSpacer", "showLoader", "numToleratedItems", "loading", "autoSize", "trackBy", "options"], outputs: ["onLazyLoad", "onScroll", "onScrollIndexChange"] }, { kind: "directive", type: i0.forwardRef(function () { return i7.AutoFocus; }), selector: "[pAutoFocus]", inputs: ["autofocus"] }, { kind: "component", type: i0.forwardRef(function () { return TimesIcon; }), selector: "TimesIcon" }, { kind: "component", type: i0.forwardRef(function () { return ChevronDownIcon; }), selector: "ChevronDownIcon" }, { kind: "component", type: i0.forwardRef(function () { return SearchIcon; }), selector: "SearchIcon" }, { kind: "component", type: i0.forwardRef(function () { return DropdownItem; }), selector: "p-dropdownItem", inputs: ["id", "option", "selected", "focused", "label", "disabled", "visible", "itemSize", "ariaPosInset", "ariaSetSize", "template"], outputs: ["onClick", "onMouseEnter"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1392
1502
  }
1393
1503
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: Dropdown, decorators: [{
1394
1504
  type: Component,
1395
1505
  args: [{ selector: 'p-dropdown', template: `
1396
- <div
1397
- #container
1398
- [ngClass]="{ 'p-dropdown p-component': true, 'p-disabled': disabled, 'p-dropdown-open': overlayVisible, 'p-focus': focused, 'p-dropdown-clearable': showClear && !disabled }"
1399
- (click)="onMouseclick($event)"
1400
- [ngStyle]="style"
1401
- [class]="styleClass"
1402
- >
1403
- <div class="p-hidden-accessible">
1404
- <input
1405
- #in
1406
- [attr.id]="inputId"
1407
- type="text"
1408
- readonly
1409
- (focus)="onInputFocus($event)"
1410
- aria-haspopup="listbox"
1411
- [attr.placeholder]="placeholder"
1412
- aria-haspopup="listbox"
1413
- [attr.aria-label]="ariaLabel"
1414
- [attr.aria-expanded]="false"
1415
- [attr.aria-labelledby]="ariaLabelledBy"
1416
- (blur)="onInputBlur($event)"
1417
- (keydown)="onKeydown($event, true)"
1418
- [disabled]="disabled"
1419
- [attr.tabindex]="tabindex"
1420
- pAutoFocus
1421
- [autofocus]="autofocus"
1422
- [attr.aria-activedescendant]="overlayVisible ? labelId : null"
1423
- role="combobox"
1424
- />
1425
- </div>
1506
+ <div #container [attr.id]="id" [ngClass]="containerClass" (click)="onContainerClick($event)" [ngStyle]="style" [class]="styleClass">
1426
1507
  <span
1427
- [attr.id]="labelId"
1428
- [ngClass]="{ 'p-dropdown-label p-inputtext': true, 'p-dropdown-label-empty': label == null || label.length === 0 }"
1429
- *ngIf="!editable && label != null"
1508
+ #focusInput
1509
+ [ngClass]="inputClass"
1510
+ *ngIf="!editable"
1430
1511
  [pTooltip]="tooltip"
1431
1512
  [tooltipPosition]="tooltipPosition"
1432
1513
  [positionStyle]="tooltipPositionStyle"
1433
1514
  [tooltipStyleClass]="tooltipStyleClass"
1515
+ [attr.aria-disabled]="disabled"
1516
+ [attr.id]="inputId"
1517
+ role="combobox"
1518
+ [attr.aria-label]="ariaLabel"
1519
+ [attr.aria-labelledby]="ariaLabelledBy"
1520
+ [attr.aria-haspopup]="'listbox'"
1521
+ [attr.aria-expanded]="overlayVisible"
1522
+ [attr.aria-controls]="id + '_list'"
1523
+ [attr.tabindex]="!disabled ? tabindex : -1"
1524
+ pAutoFocus
1525
+ [autofocus]="autofocus"
1526
+ [attr.aria-activedescendant]="focused ? focusedOptionId : undefined"
1527
+ (focus)="onInputFocus($event)"
1528
+ (blur)="onInputBlur($event)"
1529
+ (keydown)="onKeyDown($event)"
1434
1530
  >
1435
- <ng-container *ngIf="!selectedItemTemplate">{{ label || 'empty' }}</ng-container>
1436
- <ng-container *ngTemplateOutlet="selectedItemTemplate; context: { $implicit: selectedOption }"></ng-container>
1531
+ <ng-container *ngIf="!selectedItemTemplate">{{ label() === 'p-emptylabel' ? '&nbsp;' : label() || 'empty' }}</ng-container>
1532
+ <ng-container *ngTemplateOutlet="selectedItemTemplate; context: { $implicit: modelValue() }"></ng-container>
1533
+ <span *ngIf="!editable && !label() && placeholder">{{ placeholder || 'empty' }}</span>
1437
1534
  </span>
1438
- <span [ngClass]="{ 'p-dropdown-label p-inputtext p-placeholder': true, 'p-dropdown-label-empty': placeholder == null || placeholder.length === 0 }" *ngIf="!editable && label == null">{{ placeholder || 'empty' }}</span>
1439
1535
  <input
1536
+ *ngIf="editable"
1440
1537
  #editableInput
1441
1538
  type="text"
1442
1539
  [attr.maxlength]="maxlength"
1443
- class="p-dropdown-label p-inputtext"
1444
- *ngIf="editable"
1540
+ [ngClass]="inputClass"
1445
1541
  [disabled]="disabled"
1446
- [attr.placeholder]="placeholder"
1447
1542
  aria-haspopup="listbox"
1543
+ [attr.placeholder]="placeholder"
1448
1544
  [attr.aria-expanded]="overlayVisible"
1449
- (input)="onEditableInputChange($event)"
1450
- (focus)="onEditableInputFocus($event)"
1545
+ (input)="onEditableInput($event)"
1546
+ (keydown)="onKeyDown($event)"
1547
+ (focus)="onInputFocus($event)"
1451
1548
  (blur)="onInputBlur($event)"
1452
1549
  />
1453
-
1454
1550
  <ng-container *ngIf="isVisibleClearIcon">
1455
- <TimesIcon [styleClass]="'p-dropdown-clear-icon'" (click)="clear($event)" *ngIf="!clearIconTemplate" />
1456
- <span class="p-dropdown-clear-icon" (click)="clear($event)" *ngIf="clearIconTemplate">
1551
+ <TimesIcon [styleClass]="'p-dropdown-clear-icon'" (click)="clear($event)" *ngIf="!clearIconTemplate" [attr.data-pc-section]="'clearicon'" />
1552
+ <span class="p-dropdown-clear-icon" (click)="clear($event)" *ngIf="clearIconTemplate" [attr.data-pc-section]="'clearicon'">
1457
1553
  <ng-template *ngTemplateOutlet="clearIconTemplate"></ng-template>
1458
1554
  </span>
1459
1555
  </ng-container>
1460
1556
 
1461
- <div class="p-dropdown-trigger" role="button" aria-label="dropdown trigger" aria-haspopup="listbox" [attr.aria-expanded]="overlayVisible">
1557
+ <div class="p-dropdown-trigger" role="button" aria-label="dropdown trigger" aria-haspopup="listbox" [attr.aria-expanded]="overlayVisible" [attr.data-pc-section]="'trigger'">
1462
1558
  <ng-container *ngIf="!dropdownIconTemplate">
1463
1559
  <span class="p-dropdown-trigger-icon" *ngIf="dropdownIcon" [ngClass]="dropdownIcon"></span>
1464
1560
  <ChevronDownIcon *ngIf="!dropdownIcon" [styleClass]="'p-dropdown-trigger-icon'" />
@@ -1483,6 +1579,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
1483
1579
  >
1484
1580
  <ng-template pTemplate="content">
1485
1581
  <div [ngClass]="'p-dropdown-panel p-component'" [ngStyle]="panelStyle" [class]="panelStyleClass">
1582
+ <span
1583
+ #firstHiddenFocusableElementOnOverlay
1584
+ role="presentation"
1585
+ [attr.aria-hidden]="true"
1586
+ class="p-hidden-accessible p-hidden-focusable"
1587
+ [attr.tabindex]="0"
1588
+ (focus)="onFirstHiddenFocus($event)"
1589
+ [attr.data-p-hidden-focusable]="true"
1590
+ ></span>
1486
1591
  <ng-container *ngTemplateOutlet="headerTemplate"></ng-container>
1487
1592
  <div class="p-dropdown-header" *ngIf="filter" (click)="$event.stopPropagation()">
1488
1593
  <ng-container *ngIf="filterTemplate; else builtInFilterElement">
@@ -1494,14 +1599,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
1494
1599
  #filter
1495
1600
  type="text"
1496
1601
  autocomplete="off"
1497
- [value]="filterValue || ''"
1602
+ [value]="_filterValue() || ''"
1498
1603
  class="p-dropdown-filter p-inputtext p-component"
1499
1604
  [attr.placeholder]="filterPlaceholder"
1500
- (keydown.enter)="$event.preventDefault()"
1501
- (keydown)="onKeydown($event, false)"
1605
+ [attr.aria-owns]="id + '_list'"
1502
1606
  (input)="onFilterInputChange($event)"
1503
1607
  [attr.aria-label]="ariaFilterLabel"
1504
- [attr.aria-activedescendant]="overlayVisible ? 'p-highlighted-option' : labelId"
1608
+ [attr.aria-activedescendant]="focusedOptionId"
1609
+ (keydown)="onFilterKeyDown($event)"
1610
+ (blur)="onFilterBlur($event)"
1505
1611
  />
1506
1612
  <SearchIcon *ngIf="!filterIconTemplate" [styleClass]="'p-dropdown-filter-icon'" />
1507
1613
  <span *ngIf="filterIconTemplate" class="p-dropdown-filter-icon">
@@ -1514,7 +1620,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
1514
1620
  <p-scroller
1515
1621
  *ngIf="virtualScroll"
1516
1622
  #scroller
1517
- [items]="optionsToDisplay"
1623
+ [items]="visibleOptions()"
1518
1624
  [style]="{ height: scrollHeight }"
1519
1625
  [itemSize]="virtualScrollItemSize || _itemSize"
1520
1626
  [autoSize]="true"
@@ -1532,35 +1638,35 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
1532
1638
  </ng-container>
1533
1639
  </p-scroller>
1534
1640
  <ng-container *ngIf="!virtualScroll">
1535
- <ng-container *ngTemplateOutlet="buildInItems; context: { $implicit: optionsToDisplay, options: {} }"></ng-container>
1641
+ <ng-container *ngTemplateOutlet="buildInItems; context: { $implicit: visibleOptions(), options: {} }"></ng-container>
1536
1642
  </ng-container>
1537
1643
 
1538
1644
  <ng-template #buildInItems let-items let-scrollerOptions="options">
1539
- <ul #items [attr.id]="listId" class="p-dropdown-items" [ngClass]="scrollerOptions.contentStyleClass" [style]="scrollerOptions.contentStyle" role="listbox">
1540
- <ng-container *ngIf="group">
1541
- <ng-template ngFor let-optgroup [ngForOf]="items">
1542
- <li class="p-dropdown-item-group" [ngStyle]="{ height: scrollerOptions.itemSize + 'px' }">
1543
- <span *ngIf="!groupTemplate">{{ getOptionGroupLabel(optgroup) || 'empty' }}</span>
1544
- <ng-container *ngTemplateOutlet="groupTemplate; context: { $implicit: optgroup }"></ng-container>
1645
+ <ul #items [attr.id]="id + '_list'" class="p-dropdown-items" [ngClass]="scrollerOptions.contentStyleClass" [style]="scrollerOptions.contentStyle" role="listbox">
1646
+ <ng-template ngFor let-option [ngForOf]="items" let-i="index">
1647
+ <ng-container *ngIf="option.group">
1648
+ <li class="p-dropdown-item-group" [attr.id]="id + '_' + getOptionIndex(i, scrollerOptions)" [ngStyle]="{ height: scrollerOptions.itemSize + 'px' }" role="option">
1649
+ <span *ngIf="!groupTemplate">{{ getOptionGroupLabel(option.optionGroup) }}</span>
1650
+ <ng-container *ngTemplateOutlet="groupTemplate; context: { $implicit: option.optionGroup }"></ng-container>
1545
1651
  </li>
1546
- <ng-container *ngTemplateOutlet="itemslist; context: { $implicit: getOptionGroupChildren(optgroup), selectedOption: selectedOption }"></ng-container>
1547
- </ng-template>
1548
- </ng-container>
1549
- <ng-container *ngIf="!group">
1550
- <ng-container *ngTemplateOutlet="itemslist; context: { $implicit: items, selectedOption: selectedOption }"></ng-container>
1551
- </ng-container>
1552
- <ng-template #itemslist let-options let-selectedOption="selectedOption">
1553
- <ng-template ngFor let-option let-i="index" [ngForOf]="options">
1652
+ </ng-container>
1653
+ <ng-container *ngIf="!option.group">
1554
1654
  <p-dropdownItem
1655
+ [id]="id + '_' + getOptionIndex(i, scrollerOptions)"
1555
1656
  [option]="option"
1556
- [selected]="selectedOption == option"
1657
+ [selected]="isSelected(option)"
1557
1658
  [label]="getOptionLabel(option)"
1558
1659
  [disabled]="isOptionDisabled(option)"
1559
- (onClick)="onItemClick($event)"
1560
1660
  [template]="itemTemplate"
1661
+ [focused]="focusedOptionIndex() === getOptionIndex(i, scrollerOptions)"
1662
+ [ariaPosInset]="getAriaPosInset(getOptionIndex(i, scrollerOptions))"
1663
+ [ariaSetSize]="ariaSetSize"
1664
+ (onClick)="onOptionSelect($event, option)"
1665
+ (onMouseEnter)="onOptionMouseEnter($event, getOptionIndex(i, scrollerOptions))"
1561
1666
  ></p-dropdownItem>
1562
- </ng-template>
1667
+ </ng-container>
1563
1668
  </ng-template>
1669
+
1564
1670
  <li *ngIf="filterValue && isEmpty()" class="p-dropdown-empty-message" [ngStyle]="{ height: scrollerOptions.itemSize + 'px' }">
1565
1671
  <ng-container *ngIf="!emptyFilterTemplate && !emptyTemplate; else emptyFilter">
1566
1672
  {{ emptyFilterMessageLabel }}
@@ -1585,8 +1691,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
1585
1691
  class: 'p-element p-inputwrapper',
1586
1692
  '[class.p-inputwrapper-filled]': 'filled',
1587
1693
  '[class.p-inputwrapper-focus]': 'focused || overlayVisible'
1588
- }, providers: [DROPDOWN_VALUE_ACCESSOR], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, styles: ["@layer primeng{.p-dropdown{display:inline-flex;cursor:pointer;position:relative;-webkit-user-select:none;user-select:none}.p-dropdown-clear-icon{position:absolute;top:50%;margin-top:-.5rem}.p-dropdown-trigger{display:flex;align-items:center;justify-content:center;flex-shrink:0}.p-dropdown-label{display:block;white-space:nowrap;overflow:hidden;flex:1 1 auto;width:1%;text-overflow:ellipsis;cursor:pointer}.p-dropdown-label-empty{overflow:hidden;visibility:hidden}input.p-dropdown-label{cursor:default}.p-dropdown-items-wrapper{overflow:auto}.p-dropdown-item{cursor:pointer;font-weight:400;white-space:nowrap;position:relative;overflow:hidden}.p-dropdown-items{margin:0;padding:0;list-style-type:none}.p-dropdown-filter{width:100%}.p-dropdown-filter-container{position:relative}.p-dropdown-filter-icon{position:absolute;top:50%;margin-top:-.5rem}.p-fluid .p-dropdown{display:flex}.p-fluid .p-dropdown .p-dropdown-label{width:1%}}\n"] }]
1589
- }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.ChangeDetectorRef }, { type: i0.NgZone }, { type: i3.FilterService }, { type: i3.PrimeNGConfig }]; }, propDecorators: { scrollHeight: [{
1694
+ }, providers: [DROPDOWN_VALUE_ACCESSOR], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, styles: ["@layer primeng{.p-dropdown{display:inline-flex;cursor:pointer;position:relative;-webkit-user-select:none;user-select:none}.p-dropdown-clear-icon{position:absolute;top:50%;margin-top:-.5rem}.p-dropdown-trigger{display:flex;align-items:center;justify-content:center;flex-shrink:0}.p-dropdown-label{display:block;white-space:nowrap;overflow:hidden;flex:1 1 auto;width:1%;text-overflow:ellipsis;cursor:pointer}.p-dropdown-label-empty{overflow:hidden;opacity:0}input.p-dropdown-label{cursor:default}.p-dropdown .p-dropdown-panel{min-width:100%}.p-dropdown-panel{position:absolute;top:0;left:0}.p-dropdown-items-wrapper{overflow:auto}.p-dropdown-item{cursor:pointer;font-weight:400;white-space:nowrap;position:relative;overflow:hidden}.p-dropdown-item-group{cursor:auto}.p-dropdown-items{margin:0;padding:0;list-style-type:none}.p-dropdown-filter{width:100%}.p-dropdown-filter-container{position:relative}.p-dropdown-filter-icon{position:absolute;top:50%;margin-top:-.5rem}.p-fluid .p-dropdown{display:flex}.p-fluid .p-dropdown .p-dropdown-label{width:1%}}\n"] }]
1695
+ }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.ChangeDetectorRef }, { type: i0.NgZone }, { type: i3.FilterService }, { type: i3.PrimeNGConfig }]; }, propDecorators: { id: [{
1696
+ type: Input
1697
+ }], scrollHeight: [{
1590
1698
  type: Input
1591
1699
  }], filter: [{
1592
1700
  type: Input
@@ -1622,6 +1730,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
1622
1730
  type: Input
1623
1731
  }], filterBy: [{
1624
1732
  type: Input
1733
+ }], filterFields: [{
1734
+ type: Input
1625
1735
  }], autofocus: [{
1626
1736
  type: Input
1627
1737
  }], resetFilterOnHide: [{
@@ -1676,6 +1786,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
1676
1786
  type: Input
1677
1787
  }], tooltipStyleClass: [{
1678
1788
  type: Input
1789
+ }], focusOnHover: [{
1790
+ type: Input
1791
+ }], selectOnFocus: [{
1792
+ type: Input
1793
+ }], autoOptionFocus: [{
1794
+ type: Input
1679
1795
  }], autofocusFilter: [{
1680
1796
  type: Input
1681
1797
  }], disabled: [{
@@ -1718,9 +1834,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
1718
1834
  }], filterViewChild: [{
1719
1835
  type: ViewChild,
1720
1836
  args: ['filter']
1721
- }], accessibleViewChild: [{
1837
+ }], focusInputViewChild: [{
1722
1838
  type: ViewChild,
1723
- args: ['in']
1839
+ args: ['focusInput']
1724
1840
  }], editableInputViewChild: [{
1725
1841
  type: ViewChild,
1726
1842
  args: ['editableInput']
@@ -1733,6 +1849,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
1733
1849
  }], overlayViewChild: [{
1734
1850
  type: ViewChild,
1735
1851
  args: ['overlay']
1852
+ }], firstHiddenFocusableElementOnOverlay: [{
1853
+ type: ViewChild,
1854
+ args: ['firstHiddenFocusableElementOnOverlay']
1736
1855
  }], templates: [{
1737
1856
  type: ContentChildren,
1738
1857
  args: [PrimeTemplate]