primeng 16.5.1 → 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 (228) 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/menuitem.d.ts +5 -1
  6. package/api/primengconfig.d.ts +1 -0
  7. package/autocomplete/autocomplete.d.ts +177 -54
  8. package/autocomplete/autocomplete.interface.d.ts +30 -0
  9. package/breadcrumb/breadcrumb.d.ts +1 -0
  10. package/cascadeselect/cascadeselect.d.ts +188 -68
  11. package/cascadeselect/cascadeselect.interface.d.ts +19 -0
  12. package/checkbox/checkbox.d.ts +1 -4
  13. package/chips/chips.d.ts +21 -5
  14. package/colorpicker/colorpicker.d.ts +5 -5
  15. package/contextmenu/contextmenu.d.ts +4 -1
  16. package/dialog/dialog.d.ts +1 -2
  17. package/dom/domhandler.d.ts +4 -1
  18. package/dropdown/dropdown.d.ts +115 -37
  19. package/esm2022/accordion/accordion.mjs +11 -7
  20. package/esm2022/animate/animate.mjs +4 -1
  21. package/esm2022/animateonscroll/animateonscroll.mjs +185 -0
  22. package/esm2022/animateonscroll/primeng-animateonscroll.mjs +5 -0
  23. package/esm2022/animateonscroll/public_api.mjs +2 -0
  24. package/esm2022/api/menuitem.mjs +1 -1
  25. package/esm2022/api/primengconfig.mjs +2 -1
  26. package/esm2022/autocomplete/autocomplete.interface.mjs +1 -1
  27. package/esm2022/autocomplete/autocomplete.mjs +893 -617
  28. package/esm2022/breadcrumb/breadcrumb.mjs +44 -17
  29. package/esm2022/button/button.mjs +2 -2
  30. package/esm2022/carousel/carousel.mjs +6 -1
  31. package/esm2022/cascadeselect/cascadeselect.interface.mjs +1 -1
  32. package/esm2022/cascadeselect/cascadeselect.mjs +921 -482
  33. package/esm2022/checkbox/checkbox.mjs +90 -73
  34. package/esm2022/chips/chips.mjs +197 -53
  35. package/esm2022/colorpicker/colorpicker.mjs +56 -37
  36. package/esm2022/contextmenu/contextmenu.mjs +177 -144
  37. package/esm2022/dialog/dialog.mjs +6 -11
  38. package/esm2022/dom/domhandler.mjs +26 -8
  39. package/esm2022/dropdown/dropdown.mjs +707 -588
  40. package/esm2022/galleria/galleria.mjs +3 -3
  41. package/esm2022/image/image.mjs +11 -4
  42. package/esm2022/inputmask/inputmask.mjs +22 -9
  43. package/esm2022/inputnumber/inputnumber.mjs +142 -83
  44. package/esm2022/inputswitch/inputswitch.mjs +55 -49
  45. package/esm2022/knob/knob.mjs +92 -5
  46. package/esm2022/listbox/listbox.interface.mjs +1 -1
  47. package/esm2022/listbox/listbox.mjs +996 -454
  48. package/esm2022/megamenu/megamenu.mjs +168 -144
  49. package/esm2022/menu/menu.mjs +146 -94
  50. package/esm2022/menubar/menubar.mjs +168 -144
  51. package/esm2022/multiselect/multiselect.mjs +1022 -603
  52. package/esm2022/overlaypanel/overlaypanel.mjs +10 -4
  53. package/esm2022/paginator/paginator.mjs +2 -2
  54. package/esm2022/panelmenu/panelmenu.mjs +135 -106
  55. package/esm2022/password/password.mjs +29 -28
  56. package/esm2022/radiobutton/radiobutton.mjs +46 -33
  57. package/esm2022/rating/rating.mjs +172 -80
  58. package/esm2022/selectbutton/selectbutton.mjs +105 -34
  59. package/esm2022/slider/slider.mjs +151 -66
  60. package/esm2022/splitbutton/splitbutton.interface.mjs +1 -1
  61. package/esm2022/splitbutton/splitbutton.mjs +70 -14
  62. package/esm2022/table/table.mjs +3 -3
  63. package/esm2022/tabmenu/tabmenu.mjs +17 -25
  64. package/esm2022/tabview/tabview.mjs +3 -3
  65. package/esm2022/tieredmenu/tieredmenu.mjs +168 -144
  66. package/esm2022/togglebutton/togglebutton.mjs +47 -10
  67. package/esm2022/treetable/treetable.mjs +1 -1
  68. package/esm2022/tristatecheckbox/tristatecheckbox.mjs +53 -35
  69. package/fesm2022/primeng-accordion.mjs +10 -6
  70. package/fesm2022/primeng-accordion.mjs.map +1 -1
  71. package/fesm2022/primeng-animate.mjs +3 -0
  72. package/fesm2022/primeng-animate.mjs.map +1 -1
  73. package/fesm2022/primeng-animateonscroll.mjs +190 -0
  74. package/fesm2022/primeng-animateonscroll.mjs.map +1 -0
  75. package/fesm2022/primeng-api.mjs +1 -0
  76. package/fesm2022/primeng-api.mjs.map +1 -1
  77. package/fesm2022/primeng-autocomplete.mjs +893 -617
  78. package/fesm2022/primeng-autocomplete.mjs.map +1 -1
  79. package/fesm2022/primeng-breadcrumb.mjs +43 -16
  80. package/fesm2022/primeng-breadcrumb.mjs.map +1 -1
  81. package/fesm2022/primeng-button.mjs +1 -1
  82. package/fesm2022/primeng-button.mjs.map +1 -1
  83. package/fesm2022/primeng-carousel.mjs +5 -0
  84. package/fesm2022/primeng-carousel.mjs.map +1 -1
  85. package/fesm2022/primeng-cascadeselect.mjs +920 -481
  86. package/fesm2022/primeng-cascadeselect.mjs.map +1 -1
  87. package/fesm2022/primeng-checkbox.mjs +89 -72
  88. package/fesm2022/primeng-checkbox.mjs.map +1 -1
  89. package/fesm2022/primeng-chips.mjs +195 -51
  90. package/fesm2022/primeng-chips.mjs.map +1 -1
  91. package/fesm2022/primeng-colorpicker.mjs +55 -36
  92. package/fesm2022/primeng-colorpicker.mjs.map +1 -1
  93. package/fesm2022/primeng-contextmenu.mjs +176 -143
  94. package/fesm2022/primeng-contextmenu.mjs.map +1 -1
  95. package/fesm2022/primeng-dialog.mjs +5 -10
  96. package/fesm2022/primeng-dialog.mjs.map +1 -1
  97. package/fesm2022/primeng-dom.mjs +25 -7
  98. package/fesm2022/primeng-dom.mjs.map +1 -1
  99. package/fesm2022/primeng-dropdown.mjs +707 -588
  100. package/fesm2022/primeng-dropdown.mjs.map +1 -1
  101. package/fesm2022/primeng-galleria.mjs +2 -2
  102. package/fesm2022/primeng-galleria.mjs.map +1 -1
  103. package/fesm2022/primeng-image.mjs +10 -3
  104. package/fesm2022/primeng-image.mjs.map +1 -1
  105. package/fesm2022/primeng-inputmask.mjs +20 -7
  106. package/fesm2022/primeng-inputmask.mjs.map +1 -1
  107. package/fesm2022/primeng-inputnumber.mjs +140 -81
  108. package/fesm2022/primeng-inputnumber.mjs.map +1 -1
  109. package/fesm2022/primeng-inputswitch.mjs +55 -49
  110. package/fesm2022/primeng-inputswitch.mjs.map +1 -1
  111. package/fesm2022/primeng-knob.mjs +92 -5
  112. package/fesm2022/primeng-knob.mjs.map +1 -1
  113. package/fesm2022/primeng-listbox.mjs +995 -453
  114. package/fesm2022/primeng-listbox.mjs.map +1 -1
  115. package/fesm2022/primeng-megamenu.mjs +167 -143
  116. package/fesm2022/primeng-megamenu.mjs.map +1 -1
  117. package/fesm2022/primeng-menu.mjs +146 -94
  118. package/fesm2022/primeng-menu.mjs.map +1 -1
  119. package/fesm2022/primeng-menubar.mjs +167 -143
  120. package/fesm2022/primeng-menubar.mjs.map +1 -1
  121. package/fesm2022/primeng-multiselect.mjs +1021 -602
  122. package/fesm2022/primeng-multiselect.mjs.map +1 -1
  123. package/fesm2022/primeng-overlaypanel.mjs +9 -3
  124. package/fesm2022/primeng-overlaypanel.mjs.map +1 -1
  125. package/fesm2022/primeng-paginator.mjs +1 -1
  126. package/fesm2022/primeng-paginator.mjs.map +1 -1
  127. package/fesm2022/primeng-panelmenu.mjs +134 -105
  128. package/fesm2022/primeng-panelmenu.mjs.map +1 -1
  129. package/fesm2022/primeng-password.mjs +27 -26
  130. package/fesm2022/primeng-password.mjs.map +1 -1
  131. package/fesm2022/primeng-radiobutton.mjs +46 -33
  132. package/fesm2022/primeng-radiobutton.mjs.map +1 -1
  133. package/fesm2022/primeng-rating.mjs +171 -79
  134. package/fesm2022/primeng-rating.mjs.map +1 -1
  135. package/fesm2022/primeng-selectbutton.mjs +104 -33
  136. package/fesm2022/primeng-selectbutton.mjs.map +1 -1
  137. package/fesm2022/primeng-slider.mjs +150 -65
  138. package/fesm2022/primeng-slider.mjs.map +1 -1
  139. package/fesm2022/primeng-splitbutton.mjs +69 -13
  140. package/fesm2022/primeng-splitbutton.mjs.map +1 -1
  141. package/fesm2022/primeng-table.mjs +2 -2
  142. package/fesm2022/primeng-table.mjs.map +1 -1
  143. package/fesm2022/primeng-tabmenu.mjs +16 -24
  144. package/fesm2022/primeng-tabmenu.mjs.map +1 -1
  145. package/fesm2022/primeng-tabview.mjs +2 -2
  146. package/fesm2022/primeng-tabview.mjs.map +1 -1
  147. package/fesm2022/primeng-tieredmenu.mjs +167 -143
  148. package/fesm2022/primeng-tieredmenu.mjs.map +1 -1
  149. package/fesm2022/primeng-togglebutton.mjs +46 -9
  150. package/fesm2022/primeng-togglebutton.mjs.map +1 -1
  151. package/fesm2022/primeng-treetable.mjs.map +1 -1
  152. package/fesm2022/primeng-tristatecheckbox.mjs +53 -35
  153. package/fesm2022/primeng-tristatecheckbox.mjs.map +1 -1
  154. package/image/image.d.ts +6 -1
  155. package/inputmask/inputmask.d.ts +6 -1
  156. package/inputnumber/inputnumber.d.ts +6 -1
  157. package/inputswitch/inputswitch.d.ts +6 -9
  158. package/knob/knob.d.ts +20 -3
  159. package/listbox/listbox.d.ts +208 -39
  160. package/listbox/listbox.interface.d.ts +15 -0
  161. package/megamenu/megamenu.d.ts +3 -1
  162. package/menu/menu.d.ts +11 -5
  163. package/menubar/menubar.d.ts +3 -1
  164. package/multiselect/multiselect.d.ts +171 -60
  165. package/overlaypanel/overlaypanel.d.ts +1 -0
  166. package/package.json +83 -77
  167. package/panelmenu/panelmenu.d.ts +5 -2
  168. package/password/password.d.ts +3 -4
  169. package/radiobutton/radiobutton.d.ts +1 -2
  170. package/rating/rating.d.ts +29 -7
  171. package/resources/components/dropdown/dropdown.css +16 -2
  172. package/resources/themes/arya-blue/theme.css +106 -84
  173. package/resources/themes/arya-green/theme.css +106 -84
  174. package/resources/themes/arya-orange/theme.css +106 -84
  175. package/resources/themes/arya-purple/theme.css +106 -84
  176. package/resources/themes/bootstrap4-dark-blue/theme.css +110 -88
  177. package/resources/themes/bootstrap4-dark-purple/theme.css +110 -88
  178. package/resources/themes/bootstrap4-light-blue/theme.css +110 -88
  179. package/resources/themes/bootstrap4-light-purple/theme.css +110 -88
  180. package/resources/themes/fluent-light/theme.css +103 -81
  181. package/resources/themes/lara-dark-blue/theme.css +106 -84
  182. package/resources/themes/lara-dark-indigo/theme.css +106 -84
  183. package/resources/themes/lara-dark-purple/theme.css +106 -84
  184. package/resources/themes/lara-dark-teal/theme.css +106 -84
  185. package/resources/themes/lara-light-blue/theme.css +109 -87
  186. package/resources/themes/lara-light-indigo/theme.css +109 -87
  187. package/resources/themes/lara-light-purple/theme.css +109 -87
  188. package/resources/themes/lara-light-teal/theme.css +109 -87
  189. package/resources/themes/luna-amber/theme.css +110 -88
  190. package/resources/themes/luna-blue/theme.css +110 -88
  191. package/resources/themes/luna-green/theme.css +110 -88
  192. package/resources/themes/luna-pink/theme.css +110 -88
  193. package/resources/themes/md-dark-deeppurple/theme.css +117 -95
  194. package/resources/themes/md-dark-indigo/theme.css +117 -95
  195. package/resources/themes/md-light-deeppurple/theme.css +117 -95
  196. package/resources/themes/md-light-indigo/theme.css +117 -95
  197. package/resources/themes/mdc-dark-deeppurple/theme.css +117 -95
  198. package/resources/themes/mdc-dark-indigo/theme.css +117 -95
  199. package/resources/themes/mdc-light-deeppurple/theme.css +117 -95
  200. package/resources/themes/mdc-light-indigo/theme.css +117 -95
  201. package/resources/themes/mira/theme.css +107 -85
  202. package/resources/themes/nano/theme.css +109 -87
  203. package/resources/themes/nova/theme.css +110 -88
  204. package/resources/themes/nova-accent/theme.css +109 -87
  205. package/resources/themes/nova-alt/theme.css +110 -88
  206. package/resources/themes/rhea/theme.css +109 -87
  207. package/resources/themes/saga-blue/theme.css +106 -84
  208. package/resources/themes/saga-green/theme.css +106 -84
  209. package/resources/themes/saga-orange/theme.css +106 -84
  210. package/resources/themes/saga-purple/theme.css +106 -84
  211. package/resources/themes/soho-dark/theme.css +109 -87
  212. package/resources/themes/soho-light/theme.css +109 -87
  213. package/resources/themes/tailwind-light/theme.css +110 -88
  214. package/resources/themes/vela-blue/theme.css +106 -84
  215. package/resources/themes/vela-green/theme.css +106 -84
  216. package/resources/themes/vela-orange/theme.css +106 -84
  217. package/resources/themes/vela-purple/theme.css +106 -84
  218. package/resources/themes/viva-dark/theme.css +109 -87
  219. package/resources/themes/viva-light/theme.css +109 -87
  220. package/selectbutton/selectbutton.d.ts +15 -3
  221. package/slider/slider.d.ts +12 -6
  222. package/splitbutton/splitbutton.d.ts +10 -1
  223. package/splitbutton/splitbutton.interface.d.ts +15 -0
  224. package/tabmenu/tabmenu.d.ts +2 -2
  225. package/tieredmenu/tieredmenu.d.ts +3 -1
  226. package/togglebutton/togglebutton.d.ts +7 -1
  227. package/treetable/treetable.d.ts +1 -1
  228. 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, ViewEncapsulation, Input, Output, ChangeDetectionStrategy, ViewChild, ContentChild, ContentChildren, NgModule } from '@angular/core';
4
+ import { forwardRef, EventEmitter, Component, ViewEncapsulation, Input, Output, signal, computed, ChangeDetectionStrategy, ViewChild, ContentChild, 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, Footer, Header, PrimeTemplate, SharedModule } from 'primeng/api';
@@ -14,7 +14,7 @@ import * as i6 from 'primeng/scroller';
14
14
  import { ScrollerModule } from 'primeng/scroller';
15
15
  import * as i5 from 'primeng/tooltip';
16
16
  import { TooltipModule } from 'primeng/tooltip';
17
- import { ObjectUtils } from 'primeng/utils';
17
+ import { ObjectUtils, UniqueComponentId } from 'primeng/utils';
18
18
  import { CheckIcon } from 'primeng/icons/check';
19
19
  import { SearchIcon } from 'primeng/icons/search';
20
20
  import { TimesCircleIcon } from 'primeng/icons/timescircle';
@@ -27,15 +27,19 @@ const MULTISELECT_VALUE_ACCESSOR = {
27
27
  multi: true
28
28
  };
29
29
  class MultiSelectItem {
30
+ id;
30
31
  option;
31
32
  selected;
32
33
  label;
33
34
  disabled;
34
35
  itemSize;
36
+ focused;
37
+ ariaPosInset;
38
+ ariaSetSize;
35
39
  template;
36
40
  checkIconTemplate;
37
41
  onClick = new EventEmitter();
38
- onKeydown = new EventEmitter();
42
+ onMouseEnter = new EventEmitter();
39
43
  onOptionClick(event) {
40
44
  this.onClick.emit({
41
45
  originalEvent: event,
@@ -43,35 +47,42 @@ class MultiSelectItem {
43
47
  selected: this.selected
44
48
  });
45
49
  }
46
- onOptionKeydown(event) {
47
- this.onKeydown.emit({
50
+ onOptionMouseEnter(event) {
51
+ this.onMouseEnter.emit({
48
52
  originalEvent: event,
49
- option: this.option
53
+ option: this.option,
54
+ selected: this.selected
50
55
  });
51
56
  }
52
57
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: MultiSelectItem, deps: [], target: i0.ɵɵFactoryTarget.Component });
53
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.0.2", type: MultiSelectItem, selector: "p-multiSelectItem", inputs: { option: "option", selected: "selected", label: "label", disabled: "disabled", itemSize: "itemSize", template: "template", checkIconTemplate: "checkIconTemplate" }, outputs: { onClick: "onClick", onKeydown: "onKeydown" }, host: { classAttribute: "p-element" }, ngImport: i0, template: `
58
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.0.2", type: MultiSelectItem, selector: "p-multiSelectItem", inputs: { id: "id", option: "option", selected: "selected", label: "label", disabled: "disabled", itemSize: "itemSize", focused: "focused", ariaPosInset: "ariaPosInset", ariaSetSize: "ariaSetSize", template: "template", checkIconTemplate: "checkIconTemplate" }, outputs: { onClick: "onClick", onMouseEnter: "onMouseEnter" }, host: { classAttribute: "p-element" }, ngImport: i0, template: `
54
59
  <li
60
+ pRipple
61
+ [ngStyle]="{ height: itemSize + 'px' }"
55
62
  class="p-multiselect-item"
56
- (click)="onOptionClick($event)"
57
- (keydown)="onOptionKeydown($event)"
63
+ [ngClass]="{ 'p-multiselect-item': true, 'p-highlight': selected, 'p-disabled': disabled, 'p-focus': focused }"
64
+ [id]="id"
58
65
  [attr.aria-label]="label"
59
- [attr.tabindex]="disabled ? null : '0'"
60
- [ngStyle]="{ height: itemSize + 'px' }"
61
- [ngClass]="{ 'p-highlight': selected, 'p-disabled': disabled }"
62
- pRipple
66
+ [attr.aria-setsize]="ariaSetSize"
67
+ [attr.aria-posinset]="ariaPosInset"
68
+ [attr.aria-selected]="selected"
69
+ [attr.data-p-focused]="focused"
70
+ [attr.data-p-highlight]="selected"
71
+ [attr.data-p-disabled]="disabled"
72
+ (click)="onOptionClick($event)"
73
+ (mouseenter)="onOptionMouseEnter($event)"
63
74
  >
64
75
  <div class="p-checkbox p-component">
65
- <div class="p-checkbox-box" [ngClass]="{ 'p-highlight': selected }">
76
+ <div class="p-checkbox-box" [ngClass]="{ 'p-highlight': selected }" [attr.aria-checked]="selected">
66
77
  <ng-container *ngIf="selected">
67
- <CheckIcon *ngIf="!checkIconTemplate" [styleClass]="'p-checkbox-icon'" />
68
- <span *ngIf="checkIconTemplate" class="p-checkbox-icon">
78
+ <CheckIcon *ngIf="!checkIconTemplate" [styleClass]="'p-checkbox-icon'" [attr.aria-hidden]="true" />
79
+ <span *ngIf="checkIconTemplate" class="p-checkbox-icon" [attr.aria-hidden]="true">
69
80
  <ng-template *ngTemplateOutlet="checkIconTemplate"></ng-template>
70
81
  </span>
71
82
  </ng-container>
72
83
  </div>
73
84
  </div>
74
- <span *ngIf="!template">{{ label }}</span>
85
+ <span *ngIf="!template">{{ label ?? 'empty' }}</span>
75
86
  <ng-container *ngTemplateOutlet="template; context: { $implicit: option }"></ng-container>
76
87
  </li>
77
88
  `, isInline: true, dependencies: [{ kind: "directive", type: i0.forwardRef(function () { return i1.NgClass; }), selector: "[ngClass]", inputs: ["class", "ngClass"] }, { 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: "directive", type: i0.forwardRef(function () { return i2.Ripple; }), selector: "[pRipple]" }, { kind: "component", type: i0.forwardRef(function () { return CheckIcon; }), selector: "CheckIcon" }], encapsulation: i0.ViewEncapsulation.None });
@@ -82,26 +93,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
82
93
  selector: 'p-multiSelectItem',
83
94
  template: `
84
95
  <li
96
+ pRipple
97
+ [ngStyle]="{ height: itemSize + 'px' }"
85
98
  class="p-multiselect-item"
86
- (click)="onOptionClick($event)"
87
- (keydown)="onOptionKeydown($event)"
99
+ [ngClass]="{ 'p-multiselect-item': true, 'p-highlight': selected, 'p-disabled': disabled, 'p-focus': focused }"
100
+ [id]="id"
88
101
  [attr.aria-label]="label"
89
- [attr.tabindex]="disabled ? null : '0'"
90
- [ngStyle]="{ height: itemSize + 'px' }"
91
- [ngClass]="{ 'p-highlight': selected, 'p-disabled': disabled }"
92
- pRipple
102
+ [attr.aria-setsize]="ariaSetSize"
103
+ [attr.aria-posinset]="ariaPosInset"
104
+ [attr.aria-selected]="selected"
105
+ [attr.data-p-focused]="focused"
106
+ [attr.data-p-highlight]="selected"
107
+ [attr.data-p-disabled]="disabled"
108
+ (click)="onOptionClick($event)"
109
+ (mouseenter)="onOptionMouseEnter($event)"
93
110
  >
94
111
  <div class="p-checkbox p-component">
95
- <div class="p-checkbox-box" [ngClass]="{ 'p-highlight': selected }">
112
+ <div class="p-checkbox-box" [ngClass]="{ 'p-highlight': selected }" [attr.aria-checked]="selected">
96
113
  <ng-container *ngIf="selected">
97
- <CheckIcon *ngIf="!checkIconTemplate" [styleClass]="'p-checkbox-icon'" />
98
- <span *ngIf="checkIconTemplate" class="p-checkbox-icon">
114
+ <CheckIcon *ngIf="!checkIconTemplate" [styleClass]="'p-checkbox-icon'" [attr.aria-hidden]="true" />
115
+ <span *ngIf="checkIconTemplate" class="p-checkbox-icon" [attr.aria-hidden]="true">
99
116
  <ng-template *ngTemplateOutlet="checkIconTemplate"></ng-template>
100
117
  </span>
101
118
  </ng-container>
102
119
  </div>
103
120
  </div>
104
- <span *ngIf="!template">{{ label }}</span>
121
+ <span *ngIf="!template">{{ label ?? 'empty' }}</span>
105
122
  <ng-container *ngTemplateOutlet="template; context: { $implicit: option }"></ng-container>
106
123
  </li>
107
124
  `,
@@ -110,7 +127,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
110
127
  class: 'p-element'
111
128
  }
112
129
  }]
113
- }], propDecorators: { option: [{
130
+ }], propDecorators: { id: [{
131
+ type: Input
132
+ }], option: [{
114
133
  type: Input
115
134
  }], selected: [{
116
135
  type: Input
@@ -120,13 +139,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
120
139
  type: Input
121
140
  }], itemSize: [{
122
141
  type: Input
142
+ }], focused: [{
143
+ type: Input
144
+ }], ariaPosInset: [{
145
+ type: Input
146
+ }], ariaSetSize: [{
147
+ type: Input
123
148
  }], template: [{
124
149
  type: Input
125
150
  }], checkIconTemplate: [{
126
151
  type: Input
127
152
  }], onClick: [{
128
153
  type: Output
129
- }], onKeydown: [{
154
+ }], onMouseEnter: [{
130
155
  type: Output
131
156
  }] } });
132
157
  /**
@@ -141,6 +166,16 @@ class MultiSelect {
141
166
  filterService;
142
167
  config;
143
168
  overlayService;
169
+ /**
170
+ * Unique identifier of the component
171
+ * @group Props
172
+ */
173
+ id;
174
+ /**
175
+ * Defines a string that labels the input for accessibility.
176
+ * @group Props
177
+ */
178
+ ariaLabel;
144
179
  /**
145
180
  * Inline style of the element.
146
181
  * @group Props
@@ -205,7 +240,7 @@ class MultiSelect {
205
240
  * Index of the element in tabbing order.
206
241
  * @group Props
207
242
  */
208
- tabindex;
243
+ tabindex = 0;
209
244
  /**
210
245
  * Target element to attach the overlay, valid values are "body" or a local ng-template variable of another element (note: use binding with brackets for template variables, e.g. [appendTo]="mydiv" for a div element having #mydiv as variable name).
211
246
  * @group Props
@@ -221,11 +256,6 @@ class MultiSelect {
221
256
  * @group Props
222
257
  */
223
258
  name;
224
- /**
225
- * Label of the input for accessibility.
226
- * @group Props
227
- */
228
- label;
229
259
  /**
230
260
  * Establishes relationships between the component and label(s) where its value should be one or more element IDs.
231
261
  * @group Props
@@ -241,11 +271,16 @@ class MultiSelect {
241
271
  * @group Props
242
272
  */
243
273
  maxSelectedLabels = 3;
274
+ /**
275
+ * Decides how many selected item labels to show at most.
276
+ * @group Props
277
+ */
278
+ selectionLimit;
244
279
  /**
245
280
  * Label to display after exceeding max selected labels e.g. ({0} items selected), defaults "ellipsis" keyword to indicate a text-overflow.
246
281
  * @group Props
247
282
  */
248
- selectedItemsLabel = 'ellipsis';
283
+ selectedItemsLabel = '{0} items selected';
249
284
  /**
250
285
  * Whether to show the checkbox at header to toggle all items at once.
251
286
  * @group Props
@@ -290,7 +325,7 @@ class MultiSelect {
290
325
  * Name of the label field of an option group.
291
326
  * @group Props
292
327
  */
293
- optionGroupLabel;
328
+ optionGroupLabel = 'label';
294
329
  /**
295
330
  * Name of the options field of an option group.
296
331
  * @group Props
@@ -380,7 +415,7 @@ class MultiSelect {
380
415
  * Defines the autocomplete is active.
381
416
  * @group Props
382
417
  */
383
- autocomplete = 'on';
418
+ autocomplete = 'off';
384
419
  /**
385
420
  * When enabled, a clear icon is displayed to clear the value.
386
421
  * @group Props
@@ -441,7 +476,7 @@ class MultiSelect {
441
476
  */
442
477
  set defaultLabel(val) {
443
478
  this._defaultLabel = val;
444
- this.updateLabel();
479
+ console.warn('defaultLabel property is deprecated since 16.6.0, use placeholder instead');
445
480
  }
446
481
  get defaultLabel() {
447
482
  return this._defaultLabel;
@@ -452,7 +487,6 @@ class MultiSelect {
452
487
  */
453
488
  set placeholder(val) {
454
489
  this._placeholder = val;
455
- this.updateLabel();
456
490
  }
457
491
  get placeholder() {
458
492
  return this._placeholder;
@@ -462,22 +496,21 @@ class MultiSelect {
462
496
  * @group Props
463
497
  */
464
498
  get options() {
465
- return this._options;
499
+ const options = this._options();
500
+ return options;
466
501
  }
467
502
  set options(val) {
468
- this._options = val;
469
- this.updateLabel();
503
+ this._options.set(val);
470
504
  }
471
505
  /**
472
506
  * When specified, filter displays with this value.
473
507
  * @group Props
474
508
  */
475
509
  get filterValue() {
476
- return this._filterValue;
510
+ return this._filterValue();
477
511
  }
478
512
  set filterValue(val) {
479
- this._filterValue = val;
480
- this.activateFilter();
513
+ this._filterValue.set(val);
481
514
  }
482
515
  /**
483
516
  * Item size of item to be virtual scrolled.
@@ -492,25 +525,25 @@ class MultiSelect {
492
525
  console.warn('The itemSize property is deprecated, use virtualScrollItemSize property instead.');
493
526
  }
494
527
  /**
495
- * Number of maximum options that can be selected.
528
+ * Fields used when filtering the options, defaults to optionLabel.
496
529
  * @group Props
497
530
  */
498
- get selectionLimit() {
499
- return this._selectionLimit;
500
- }
501
- set selectionLimit(val) {
502
- this._selectionLimit = val;
503
- this.checkSelectionLimit();
504
- }
505
- containerViewChild;
506
- overlayViewChild;
507
- filterInputChild;
508
- accessibleViewChild;
509
- itemsViewChild;
510
- scroller;
511
- footerFacet;
512
- headerFacet;
513
- templates;
531
+ focusOnHover = false;
532
+ /**
533
+ * Fields used when filtering the options, defaults to optionLabel.
534
+ * @group Props
535
+ */
536
+ filterFields;
537
+ /**
538
+ * Determines if the option will be selected on focus.
539
+ * @group Props
540
+ */
541
+ selectOnFocus = false;
542
+ /**
543
+ * Whether to focus on the first visible or selected element when the overlay panel is shown.
544
+ * @group Props
545
+ */
546
+ autoOptionFocus = true;
514
547
  /**
515
548
  * Callback to invoke when value changes.
516
549
  * @param {MultiSelectChangeEvent} event - Custom change event.
@@ -568,6 +601,20 @@ class MultiSelect {
568
601
  * @group Emits
569
602
  */
570
603
  onRemove = new EventEmitter();
604
+ containerViewChild;
605
+ overlayViewChild;
606
+ filterInputChild;
607
+ focusInputViewChild;
608
+ itemsViewChild;
609
+ scroller;
610
+ lastHiddenFocusableElementOnOverlay;
611
+ firstHiddenFocusableElementOnOverlay;
612
+ headerCheckboxViewChild;
613
+ footerFacet;
614
+ headerFacet;
615
+ templates;
616
+ searchValue;
617
+ searchTimeout;
571
618
  _autoZIndex;
572
619
  _baseZIndex;
573
620
  _showTransitionOptions;
@@ -582,8 +629,6 @@ class MultiSelect {
582
629
  onModelTouched = () => { };
583
630
  valuesAsString;
584
631
  focus;
585
- filled;
586
- _filterValue;
587
632
  filtered;
588
633
  itemTemplate;
589
634
  groupTemplate;
@@ -602,10 +647,112 @@ class MultiSelect {
602
647
  dropdownIconTemplate;
603
648
  headerCheckboxFocus;
604
649
  filterOptions;
605
- _options;
606
650
  maxSelectionLimitReached;
607
651
  preventModelTouched;
608
652
  preventDocumentDefault;
653
+ focused = false;
654
+ itemsWrapper;
655
+ modelValue = signal(null);
656
+ _filterValue = signal(null);
657
+ _options = signal(null);
658
+ startRangeIndex = signal(-1);
659
+ focusedOptionIndex = signal(-1);
660
+ get containerClass() {
661
+ return {
662
+ 'p-multiselect p-component p-inputwrapper': true,
663
+ 'p-disabled': this.disabled,
664
+ 'p-multiselect-clearable': this.showClear && !this.disabled,
665
+ 'p-multiselect-chip': this.display === 'chip',
666
+ 'p-focus': this.focused,
667
+ 'p-inputwrapper-filled': ObjectUtils.isNotEmpty(this.modelValue()),
668
+ 'p-inputwrapper-focus': this.focused || this.overlayVisible
669
+ };
670
+ }
671
+ get inputClass() {
672
+ return {
673
+ 'p-multiselect-label p-inputtext': true,
674
+ 'p-placeholder': (this.placeholder || this.defaultLabel) && (this.label() === this.placeholder || this.label() === this.defaultLabel),
675
+ 'p-multiselect-label-empty': !this.selectedItemsTemplate && (this.label() === 'p-emptylabel' || this.label().length === 0)
676
+ };
677
+ }
678
+ get panelClass() {
679
+ return {
680
+ 'p-multiselect-panel p-component': true,
681
+ 'p-input-filled': this.config.inputStyle === 'filled',
682
+ 'p-ripple-disabled': this.config.ripple === false
683
+ };
684
+ }
685
+ get labelClass() {
686
+ return {
687
+ 'p-multiselect-label': true,
688
+ 'p-placeholder': this.label() === this.placeholder || this.label() === this.defaultLabel,
689
+ 'p-multiselect-label-empty': !this.placeholder && !this.defaultLabel && (!this.modelValue() || this.modelValue().length === 0)
690
+ };
691
+ }
692
+ get emptyMessageLabel() {
693
+ return this.emptyMessage || this.config.getTranslation(TranslationKeys.EMPTY_MESSAGE);
694
+ }
695
+ get emptyFilterMessageLabel() {
696
+ return this.emptyFilterMessage || this.config.getTranslation(TranslationKeys.EMPTY_FILTER_MESSAGE);
697
+ }
698
+ get filled() {
699
+ if (typeof this.modelValue() === 'string')
700
+ return !!this.modelValue();
701
+ return this.modelValue() || this.modelValue() != null || this.modelValue() != undefined;
702
+ }
703
+ get isVisibleClearIcon() {
704
+ return this.modelValue() != null && this.modelValue() !== '' && this.showClear && !this.disabled;
705
+ }
706
+ get toggleAllAriaLabel() {
707
+ return this.config.translation.aria ? this.config.translation.aria[this.allSelected() ? 'selectAll' : 'unselectAll'] : undefined;
708
+ }
709
+ get closeAriaLabel() {
710
+ return this.config.translation.aria ? this.config.translation.aria.close : undefined;
711
+ }
712
+ visibleOptions = computed(() => {
713
+ const options = this.group ? this.flatOptions(this.options) : this.options || [];
714
+ if (this._filterValue()) {
715
+ const filteredOptions = this.filterService.filter(options, this.searchFields(), this._filterValue(), this.filterMatchMode, this.filterLocale);
716
+ if (this.group) {
717
+ const optionGroups = this.options || [];
718
+ const filtered = [];
719
+ optionGroups.forEach((group) => {
720
+ const groupChildren = this.getOptionGroupChildren(group);
721
+ const filteredItems = groupChildren.filter((item) => filteredOptions.includes(item));
722
+ if (filteredItems.length > 0)
723
+ filtered.push({ ...group, [typeof this.optionGroupChildren === 'string' ? this.optionGroupChildren : 'items']: [...filteredItems] });
724
+ });
725
+ return this.flatOptions(filtered);
726
+ }
727
+ return filteredOptions;
728
+ }
729
+ return options;
730
+ });
731
+ label = computed(() => {
732
+ let label;
733
+ const modelValue = this.modelValue();
734
+ if (modelValue && modelValue.length) {
735
+ if (ObjectUtils.isNotEmpty(this.maxSelectedLabels) && modelValue.length > this.maxSelectedLabels) {
736
+ return this.getSelectedItemsLabel();
737
+ }
738
+ else {
739
+ label = '';
740
+ for (let i = 0; i < modelValue.length; i++) {
741
+ if (i !== 0) {
742
+ label += ', ';
743
+ }
744
+ label += this.getLabelByValue(modelValue[i]);
745
+ }
746
+ }
747
+ }
748
+ else {
749
+ label = this.placeholder || this.defaultLabel || '';
750
+ }
751
+ return label;
752
+ });
753
+ chipSelectedItems = computed(() => {
754
+ return ObjectUtils.isNotEmpty(this.maxSelectedLabels) && this.modelValue() && this.modelValue().length > this.maxSelectedLabels ? this.modelValue().slice(0, this.maxSelectedLabels) : this.modelValue();
755
+ });
609
756
  constructor(el, renderer, cd, zone, filterService, config, overlayService) {
610
757
  this.el = el;
611
758
  this.renderer = renderer;
@@ -616,7 +763,8 @@ class MultiSelect {
616
763
  this.overlayService = overlayService;
617
764
  }
618
765
  ngOnInit() {
619
- this.updateLabel();
766
+ this.id = this.id || UniqueComponentId();
767
+ this.autoUpdateModel();
620
768
  if (this.filterBy) {
621
769
  this.filterOptions = {
622
770
  filter: (value) => this.onFilterInputChange(value),
@@ -693,6 +841,154 @@ class MultiSelect {
693
841
  this.filtered = false;
694
842
  }
695
843
  }
844
+ flatOptions(options) {
845
+ return (options || []).reduce((result, option, index) => {
846
+ result.push({ optionGroup: option, group: true, index });
847
+ const optionGroupChildren = this.getOptionGroupChildren(option);
848
+ optionGroupChildren && optionGroupChildren.forEach((o) => result.push(o));
849
+ return result;
850
+ }, []);
851
+ }
852
+ autoUpdateModel() {
853
+ if (this.selectOnFocus && this.autoOptionFocus && !this.hasSelectedOption()) {
854
+ this.focusedOptionIndex.set(this.findFirstFocusedOptionIndex());
855
+ const value = this.getOptionValue(this.visibleOptions()[this.focusedOptionIndex()]);
856
+ this.onOptionSelect({ originalEvent: null, option: [value] });
857
+ }
858
+ }
859
+ updateModel(value, event) {
860
+ this.value = value;
861
+ this.onModelChange(value);
862
+ this.modelValue.set(value);
863
+ this.onChange.emit({
864
+ originalEvent: event,
865
+ value: value
866
+ });
867
+ }
868
+ onOptionSelect(event, isFocus = false, index = -1) {
869
+ const { originalEvent, option } = event;
870
+ if (this.disabled || this.isOptionDisabled(option)) {
871
+ return;
872
+ }
873
+ let selected = this.isSelected(option);
874
+ let value = null;
875
+ if (selected) {
876
+ value = this.modelValue().filter((val) => !ObjectUtils.equals(val, this.getOptionValue(option), this.equalityKey()));
877
+ }
878
+ else {
879
+ value = [...(this.modelValue() || []), this.getOptionValue(option)];
880
+ }
881
+ this.updateModel(value, originalEvent);
882
+ index !== -1 && this.focusedOptionIndex.set(index);
883
+ isFocus && DomHandler.focus(this.focusInputViewChild?.nativeElement);
884
+ }
885
+ onOptionSelectRange(event, start = -1, end = -1) {
886
+ start === -1 && (start = this.findNearestSelectedOptionIndex(end, true));
887
+ end === -1 && (end = this.findNearestSelectedOptionIndex(start));
888
+ if (start !== -1 && end !== -1) {
889
+ const rangeStart = Math.min(start, end);
890
+ const rangeEnd = Math.max(start, end);
891
+ const value = this.visibleOptions()
892
+ .slice(rangeStart, rangeEnd + 1)
893
+ .filter((option) => this.isValidOption(option))
894
+ .map((option) => this.getOptionValue(option));
895
+ this.updateModel(value, event);
896
+ }
897
+ }
898
+ searchFields() {
899
+ return this.filterFields || [this.optionLabel];
900
+ }
901
+ findNearestSelectedOptionIndex(index, firstCheckUp = false) {
902
+ let matchedOptionIndex = -1;
903
+ if (this.hasSelectedOption()) {
904
+ if (firstCheckUp) {
905
+ matchedOptionIndex = this.findPrevSelectedOptionIndex(index);
906
+ matchedOptionIndex = matchedOptionIndex === -1 ? this.findNextSelectedOptionIndex(index) : matchedOptionIndex;
907
+ }
908
+ else {
909
+ matchedOptionIndex = this.findNextSelectedOptionIndex(index);
910
+ matchedOptionIndex = matchedOptionIndex === -1 ? this.findPrevSelectedOptionIndex(index) : matchedOptionIndex;
911
+ }
912
+ }
913
+ return matchedOptionIndex > -1 ? matchedOptionIndex : index;
914
+ }
915
+ findPrevSelectedOptionIndex(index) {
916
+ const matchedOptionIndex = this.hasSelectedOption() && index > 0 ? ObjectUtils.findLastIndex(this.visibleOptions().slice(0, index), (option) => this.isValidSelectedOption(option)) : -1;
917
+ return matchedOptionIndex > -1 ? matchedOptionIndex : -1;
918
+ }
919
+ findFirstFocusedOptionIndex() {
920
+ const selectedIndex = this.findFirstSelectedOptionIndex();
921
+ return selectedIndex < 0 ? this.findFirstOptionIndex() : selectedIndex;
922
+ }
923
+ findFirstOptionIndex() {
924
+ return this.visibleOptions().findIndex((option) => this.isValidOption(option));
925
+ }
926
+ findFirstSelectedOptionIndex() {
927
+ return this.hasSelectedOption() ? this.visibleOptions().findIndex((option) => this.isValidSelectedOption(option)) : -1;
928
+ }
929
+ findNextSelectedOptionIndex(index) {
930
+ const matchedOptionIndex = this.hasSelectedOption() && index < this.visibleOptions().length - 1
931
+ ? this.visibleOptions()
932
+ .slice(index + 1)
933
+ .findIndex((option) => this.isValidSelectedOption(option))
934
+ : -1;
935
+ return matchedOptionIndex > -1 ? matchedOptionIndex + index + 1 : -1;
936
+ }
937
+ equalityKey() {
938
+ return this.optionValue ? null : this.dataKey;
939
+ }
940
+ hasSelectedOption() {
941
+ return ObjectUtils.isNotEmpty(this.modelValue());
942
+ }
943
+ isValidSelectedOption(option) {
944
+ return this.isValidOption(option) && this.isSelected(option);
945
+ }
946
+ isOptionGroup(option) {
947
+ return (this.group || this.optionGroupLabel) && option.optionGroup && option.group;
948
+ }
949
+ isValidOption(option) {
950
+ return option && !(this.isOptionDisabled(option) || this.isOptionGroup(option));
951
+ }
952
+ isOptionDisabled(option) {
953
+ let disabled = this.optionDisabled ? ObjectUtils.resolveFieldData(option, this.optionDisabled) : option && option.disabled !== undefined ? option.disabled : false;
954
+ return disabled || (this.maxSelectionLimitReached && !this.isSelected(option));
955
+ }
956
+ isSelected(option) {
957
+ const optionValue = this.getOptionValue(option);
958
+ return (this.modelValue() || []).some((value) => ObjectUtils.equals(value, optionValue, this.equalityKey()));
959
+ }
960
+ isOptionMatched(option) {
961
+ return this.isValidOption(option) && this.getOptionLabel(option).toLocaleLowerCase(this.filterLocale).startsWith(this.searchValue.toLocaleLowerCase(this.filterLocale));
962
+ }
963
+ isEmpty() {
964
+ return !this._options() || (this._options() && this._options().length === 0);
965
+ }
966
+ getOptionIndex(index, scrollerOptions) {
967
+ return this.virtualScrollerDisabled ? index : scrollerOptions && scrollerOptions.getItemOptions(index)['index'];
968
+ }
969
+ getAriaPosInset(index) {
970
+ return ((this.optionGroupLabel
971
+ ? index -
972
+ this.visibleOptions()
973
+ .slice(0, index)
974
+ .filter((option) => this.isOptionGroup(option)).length
975
+ : index) + 1);
976
+ }
977
+ get ariaSetSize() {
978
+ return this.visibleOptions().filter((option) => !this.isOptionGroup(option)).length;
979
+ }
980
+ getLabelByValue(value) {
981
+ const options = this.group ? this.flatOptions(this._options()) : this._options() || [];
982
+ const matchedOption = options.find((option) => !this.isOptionGroup(option) && ObjectUtils.equals(this.getOptionValue(option), value, this.equalityKey()));
983
+ return matchedOption ? this.getOptionLabel(matchedOption) : null;
984
+ }
985
+ getSelectedItemsLabel() {
986
+ let pattern = /{(.*?)}/;
987
+ if (pattern.test(this.selectedItemsLabel)) {
988
+ return this.selectedItemsLabel.replace(this.selectedItemsLabel.match(pattern)[0], this.modelValue().length + '');
989
+ }
990
+ return this.selectedItemsLabel;
991
+ }
696
992
  getOptionLabel(option) {
697
993
  return this.optionLabel ? ObjectUtils.resolveFieldData(option, this.optionLabel) : option && option.label != undefined ? option.label : option;
698
994
  }
@@ -705,186 +1001,411 @@ class MultiSelect {
705
1001
  getOptionGroupChildren(optionGroup) {
706
1002
  return this.optionGroupChildren ? ObjectUtils.resolveFieldData(optionGroup, this.optionGroupChildren) : optionGroup.items;
707
1003
  }
708
- isOptionDisabled(option) {
709
- let disabled = this.optionDisabled ? ObjectUtils.resolveFieldData(option, this.optionDisabled) : option && option.disabled !== undefined ? option.disabled : false;
710
- return disabled || (this.maxSelectionLimitReached && !this.isSelected(option));
711
- }
712
- writeValue(value) {
713
- this.value = value;
714
- this.updateLabel();
715
- this.updateFilledState();
716
- this.checkSelectionLimit();
717
- this.cd.markForCheck();
718
- }
719
- checkSelectionLimit() {
720
- if (this.selectionLimit && this.value && this.value.length === this.selectionLimit) {
721
- this.maxSelectionLimitReached = true;
1004
+ onKeyDown(event) {
1005
+ if (this.disabled) {
1006
+ event.preventDefault();
1007
+ return;
722
1008
  }
723
- else {
724
- this.maxSelectionLimitReached = false;
1009
+ const metaKey = event.metaKey || event.ctrlKey;
1010
+ switch (event.code) {
1011
+ case 'ArrowDown':
1012
+ this.onArrowDownKey(event);
1013
+ break;
1014
+ case 'ArrowUp':
1015
+ this.onArrowUpKey(event);
1016
+ break;
1017
+ case 'Home':
1018
+ this.onHomeKey(event);
1019
+ break;
1020
+ case 'End':
1021
+ this.onEndKey(event);
1022
+ break;
1023
+ case 'PageDown':
1024
+ this.onPageDownKey(event);
1025
+ break;
1026
+ case 'PageUp':
1027
+ this.onPageUpKey(event);
1028
+ break;
1029
+ case 'Enter':
1030
+ case 'Space':
1031
+ this.onEnterKey(event);
1032
+ break;
1033
+ case 'Escape':
1034
+ this.onEscapeKey(event);
1035
+ break;
1036
+ case 'Tab':
1037
+ this.onTabKey(event);
1038
+ break;
1039
+ case 'ShiftLeft':
1040
+ case 'ShiftRight':
1041
+ this.onShiftKey();
1042
+ break;
1043
+ default:
1044
+ if (event.code === 'KeyA' && metaKey) {
1045
+ const value = this.visibleOptions()
1046
+ .filter((option) => this.isValidOption(option))
1047
+ .map((option) => this.getOptionValue(option));
1048
+ this.updateModel(value, event);
1049
+ event.preventDefault();
1050
+ break;
1051
+ }
1052
+ if (!metaKey && ObjectUtils.isPrintableCharacter(event.key)) {
1053
+ !this.overlayVisible && this.show();
1054
+ this.searchOptions(event, event.key);
1055
+ event.preventDefault();
1056
+ }
1057
+ break;
725
1058
  }
726
1059
  }
727
- updateFilledState() {
728
- this.filled = this.value && this.value.length > 0;
1060
+ onFilterKeyDown(event) {
1061
+ switch (event.code) {
1062
+ case 'ArrowDown':
1063
+ this.onArrowDownKey(event);
1064
+ break;
1065
+ case 'ArrowUp':
1066
+ this.onArrowUpKey(event, true);
1067
+ break;
1068
+ case 'ArrowLeft':
1069
+ case 'ArrowRight':
1070
+ this.onArrowLeftKey(event, true);
1071
+ break;
1072
+ case 'Home':
1073
+ this.onHomeKey(event, true);
1074
+ break;
1075
+ case 'End':
1076
+ this.onEndKey(event, true);
1077
+ break;
1078
+ case 'Enter':
1079
+ this.onEnterKey(event);
1080
+ break;
1081
+ case 'Escape':
1082
+ this.onEscapeKey(event);
1083
+ break;
1084
+ case 'Tab':
1085
+ this.onTabKey(event, true);
1086
+ break;
1087
+ default:
1088
+ break;
1089
+ }
729
1090
  }
730
- registerOnChange(fn) {
731
- this.onModelChange = fn;
1091
+ onArrowLeftKey(event, pressedInInputText = false) {
1092
+ pressedInInputText && this.focusedOptionIndex.set(-1);
732
1093
  }
733
- registerOnTouched(fn) {
734
- this.onModelTouched = fn;
1094
+ onArrowDownKey(event) {
1095
+ const optionIndex = this.focusedOptionIndex() !== -1 ? this.findNextOptionIndex(this.focusedOptionIndex()) : this.findFirstFocusedOptionIndex();
1096
+ if (event.shiftKey) {
1097
+ this.onOptionSelectRange(event, this.startRangeIndex(), optionIndex);
1098
+ }
1099
+ this.changeFocusedOptionIndex(event, optionIndex);
1100
+ !this.overlayVisible && this.show();
1101
+ event.preventDefault();
735
1102
  }
736
- setDisabledState(val) {
737
- this.disabled = val;
738
- this.cd.markForCheck();
1103
+ onArrowUpKey(event, pressedInInputText = false) {
1104
+ if (event.altKey && !pressedInInputText) {
1105
+ if (this.focusedOptionIndex() !== -1) {
1106
+ this.onOptionSelect(event, this.visibleOptions()[this.focusedOptionIndex()]);
1107
+ }
1108
+ this.overlayVisible && this.hide();
1109
+ event.preventDefault();
1110
+ }
1111
+ else {
1112
+ const optionIndex = this.focusedOptionIndex() !== -1 ? this.findPrevOptionIndex(this.focusedOptionIndex()) : this.findLastFocusedOptionIndex();
1113
+ if (event.shiftKey) {
1114
+ this.onOptionSelectRange(event, optionIndex, this.startRangeIndex());
1115
+ }
1116
+ this.changeFocusedOptionIndex(event, optionIndex);
1117
+ !this.overlayVisible && this.show();
1118
+ event.preventDefault();
1119
+ }
739
1120
  }
740
- onOptionClick(event) {
741
- let option = event.option;
742
- if (this.isOptionDisabled(option)) {
743
- return;
1121
+ onHomeKey(event, pressedInInputText = false) {
1122
+ const { currentTarget } = event;
1123
+ if (pressedInInputText) {
1124
+ const len = currentTarget.value.length;
1125
+ currentTarget.setSelectionRange(0, event.shiftKey ? len : 0);
1126
+ this.focusedOptionIndex.set(-1);
744
1127
  }
745
- let optionValue = this.getOptionValue(option);
746
- let selectionIndex = this.findSelectionIndex(optionValue);
747
- if (selectionIndex != -1) {
748
- this.value = this.value.filter((val, i) => i != selectionIndex);
749
- this.onRemove.emit({ newValue: this.value, removed: optionValue });
750
- if (this.selectionLimit) {
751
- this.maxSelectionLimitReached = false;
1128
+ else {
1129
+ let metaKey = event.metaKey || event.ctrlKey;
1130
+ let optionIndex = this.findFirstOptionIndex();
1131
+ if (event.shiftKey && metaKey) {
1132
+ this.onOptionSelectRange(event, optionIndex, this.startRangeIndex());
752
1133
  }
1134
+ this.changeFocusedOptionIndex(event, optionIndex);
1135
+ !this.overlayVisible && this.show();
1136
+ }
1137
+ event.preventDefault();
1138
+ }
1139
+ onEndKey(event, pressedInInputText = false) {
1140
+ const { currentTarget } = event;
1141
+ if (pressedInInputText) {
1142
+ const len = currentTarget.value.length;
1143
+ currentTarget.setSelectionRange(event.shiftKey ? 0 : len, len);
1144
+ this.focusedOptionIndex.set(-1);
753
1145
  }
754
1146
  else {
755
- if (!this.selectionLimit || !this.value || this.value.length < this.selectionLimit) {
756
- this.value = [...(this.value || []), optionValue];
1147
+ let metaKey = event.metaKey || event.ctrlKey;
1148
+ let optionIndex = this.findLastFocusedOptionIndex();
1149
+ if (event.shiftKey && metaKey) {
1150
+ this.onOptionSelectRange(event, this.startRangeIndex(), optionIndex);
757
1151
  }
758
- this.checkSelectionLimit();
1152
+ this.changeFocusedOptionIndex(event, optionIndex);
1153
+ !this.overlayVisible && this.show();
759
1154
  }
760
- this.onModelChange(this.value);
761
- this.onChange.emit({ originalEvent: event.originalEvent, value: this.value, itemValue: optionValue });
762
- this.updateLabel();
763
- this.updateFilledState();
1155
+ event.preventDefault();
764
1156
  }
765
- isSelected(option) {
766
- return this.findSelectionIndex(this.getOptionValue(option)) != -1;
767
- }
768
- findSelectionIndex(val) {
769
- let index = -1;
770
- if (this.value) {
771
- for (let i = 0; i < this.value.length; i++) {
772
- if (ObjectUtils.equals(this.value[i], val, this.dataKey)) {
773
- index = i;
774
- break;
1157
+ onPageDownKey(event) {
1158
+ this.scrollInView(this.visibleOptions().length - 1);
1159
+ event.preventDefault();
1160
+ }
1161
+ onPageUpKey(event) {
1162
+ this.scrollInView(0);
1163
+ event.preventDefault();
1164
+ }
1165
+ onEnterKey(event) {
1166
+ if (!this.overlayVisible) {
1167
+ this.onArrowDownKey(event);
1168
+ }
1169
+ else {
1170
+ if (this.focusedOptionIndex() !== -1) {
1171
+ if (event.shiftKey) {
1172
+ this.onOptionSelectRange(event, this.focusedOptionIndex());
1173
+ }
1174
+ else {
1175
+ this.onOptionSelect({ originalEvent: event, option: this.visibleOptions()[this.focusedOptionIndex()] });
775
1176
  }
776
1177
  }
777
1178
  }
778
- return index;
1179
+ event.preventDefault();
779
1180
  }
780
- get toggleAllDisabled() {
781
- let optionsToRender = this.optionsToRender;
782
- if (!optionsToRender || optionsToRender.length === 0) {
783
- return true;
1181
+ onEscapeKey(event) {
1182
+ this.overlayVisible && this.hide(true);
1183
+ event.preventDefault();
1184
+ }
1185
+ onDeleteKey(event) {
1186
+ if (this.showClear) {
1187
+ this.clear(event);
1188
+ event.preventDefault();
784
1189
  }
785
- else {
786
- for (let option of optionsToRender) {
787
- if (!this.isOptionDisabled(option))
788
- return false;
1190
+ }
1191
+ onTabKey(event, pressedInInputText = false) {
1192
+ if (!pressedInInputText) {
1193
+ if (this.overlayVisible && this.hasFocusableElements()) {
1194
+ DomHandler.focus(event.shiftKey ? this.lastHiddenFocusableElementOnOverlay.nativeElement : this.firstHiddenFocusableElementOnOverlay.nativeElement);
1195
+ event.preventDefault();
1196
+ }
1197
+ else {
1198
+ if (this.focusedOptionIndex() !== -1) {
1199
+ this.onOptionSelect({ originalEvent: event, option: this.visibleOptions()[this.focusedOptionIndex()] });
1200
+ }
1201
+ this.overlayVisible && this.hide(this.filter);
789
1202
  }
790
- return true;
791
1203
  }
792
1204
  }
793
- toggleAll(event) {
794
- if (this.disabled || this.toggleAllDisabled || this.readonly) {
1205
+ onShiftKey() {
1206
+ this.startRangeIndex.set(this.focusedOptionIndex());
1207
+ }
1208
+ onContainerClick(event) {
1209
+ if (this.disabled || this.readonly || event.target.isSameNode(this.focusInputViewChild?.nativeElement)) {
795
1210
  return;
796
1211
  }
797
- let allChecked = this.allChecked;
798
- if (allChecked)
799
- this.uncheckAll();
800
- else
801
- this.checkAll();
802
- this.onModelChange(this.value);
1212
+ this.focusInputViewChild?.nativeElement.focus({ preventScroll: true });
1213
+ if (event.target.tagName === 'INPUT' || event.target.getAttribute('data-pc-section') === 'clearicon' || event.target.closest('[data-pc-section="clearicon"]')) {
1214
+ return;
1215
+ }
1216
+ else if (!this.overlayViewChild || !this.overlayViewChild.el.nativeElement.contains(event.target)) {
1217
+ this.overlayVisible ? this.hide(true) : this.show(true);
1218
+ }
1219
+ this.onClick.emit(event);
1220
+ this.cd.detectChanges();
1221
+ }
1222
+ onFirstHiddenFocus(event) {
1223
+ const focusableEl = event.relatedTarget === this.focusInputViewChild?.nativeElement
1224
+ ? DomHandler.getFirstFocusableElement(this.overlayViewChild?.overlayViewChild?.nativeElement, ':not([data-p-hidden-focusable="true"])')
1225
+ : this.focusInputViewChild?.nativeElement;
1226
+ DomHandler.focus(focusableEl);
1227
+ }
1228
+ onInputFocus(event) {
1229
+ this.focused = true;
1230
+ const focusedOptionIndex = this.focusedOptionIndex() !== -1 ? this.focusedOptionIndex() : this.overlayVisible && this.autoOptionFocus ? this.findFirstFocusedOptionIndex() : -1;
1231
+ this.focusedOptionIndex.set(focusedOptionIndex);
1232
+ this.overlayVisible && this.scrollInView(this.focusedOptionIndex());
1233
+ this.onFocus.emit({ originalEvent: event });
1234
+ }
1235
+ onInputBlur(event) {
1236
+ this.focused = false;
1237
+ this.onBlur.emit({ originalEvent: event });
1238
+ if (!this.preventModelTouched) {
1239
+ this.onModelTouched();
1240
+ }
1241
+ this.preventModelTouched = false;
1242
+ }
1243
+ onFilterInputChange(event) {
1244
+ let value = event.target.value?.trim();
1245
+ this._filterValue.set(value);
1246
+ this.focusedOptionIndex.set(-1);
1247
+ this.onFilter.emit({ originalEvent: event, filter: this._filterValue() });
1248
+ !this.virtualScrollerDisabled && this.scroller.scrollToIndex(0);
1249
+ }
1250
+ onLastHiddenFocus(event) {
1251
+ const focusableEl = event.relatedTarget === this.focusInputViewChild?.nativeElement
1252
+ ? DomHandler.getLastFocusableElement(this.overlayViewChild?.overlayViewChild?.nativeElement, ':not([data-p-hidden-focusable="true"])')
1253
+ : this.focusInputViewChild?.nativeElement;
1254
+ DomHandler.focus(focusableEl);
1255
+ }
1256
+ onOptionMouseEnter(event, index) {
1257
+ if (this.focusOnHover) {
1258
+ this.changeFocusedOptionIndex(event, index);
1259
+ }
1260
+ }
1261
+ onHeaderCheckboxKeyDown(event) {
1262
+ if (this.disabled) {
1263
+ event.preventDefault();
1264
+ return;
1265
+ }
1266
+ switch (event.code) {
1267
+ case 'Space':
1268
+ this.onToggleAll(event);
1269
+ break;
1270
+ case 'Enter':
1271
+ this.onToggleAll(event);
1272
+ break;
1273
+ default:
1274
+ break;
1275
+ }
1276
+ }
1277
+ onFilterBlur(event) {
1278
+ this.focusedOptionIndex.set(-1);
1279
+ }
1280
+ onHeaderCheckboxFocus() {
1281
+ this.headerCheckboxFocus = true;
1282
+ }
1283
+ onHeaderCheckboxBlur() {
1284
+ this.headerCheckboxFocus = false;
1285
+ }
1286
+ onToggleAll(event) {
1287
+ if (this.disabled || this.readonly) {
1288
+ return;
1289
+ }
1290
+ DomHandler.focus(this.headerCheckboxViewChild.nativeElement);
1291
+ const value = this.allSelected()
1292
+ ? []
1293
+ : this.visibleOptions()
1294
+ .filter((option) => this.isValidOption(option))
1295
+ .map((option) => this.getOptionValue(option));
1296
+ this.updateModel(value, event);
803
1297
  this.onChange.emit({ originalEvent: event, value: this.value });
804
- this.updateFilledState();
805
- this.updateLabel();
1298
+ this.headerCheckboxFocus = true;
806
1299
  event.preventDefault();
807
1300
  event.stopPropagation();
808
1301
  }
809
- checkAll() {
810
- let optionsToRender = this.optionsToRender;
811
- let val = [];
812
- optionsToRender.forEach((opt) => {
813
- if (!this.group) {
814
- let optionDisabled = this.isOptionDisabled(opt);
815
- if (!optionDisabled || (optionDisabled && this.isSelected(opt))) {
816
- val.push(this.getOptionValue(opt));
817
- }
818
- }
819
- else {
820
- let subOptions = this.getOptionGroupChildren(opt);
821
- if (subOptions) {
822
- subOptions.forEach((option) => {
823
- let optionDisabled = this.isOptionDisabled(option);
824
- if (!optionDisabled || (optionDisabled && this.isSelected(option))) {
825
- val.push(this.getOptionValue(option));
826
- }
827
- });
828
- }
829
- }
830
- });
831
- this.value = val;
832
- }
833
- uncheckAll() {
834
- let optionsToRender = this.optionsToRender;
835
- let val = [];
836
- optionsToRender.forEach((opt) => {
837
- if (!this.group) {
838
- let optionDisabled = this.isOptionDisabled(opt);
839
- if (optionDisabled && this.isSelected(opt)) {
840
- val.push(this.getOptionValue(opt));
841
- }
1302
+ changeFocusedOptionIndex(event, index) {
1303
+ if (this.focusedOptionIndex() !== index) {
1304
+ this.focusedOptionIndex.set(index);
1305
+ this.scrollInView();
1306
+ }
1307
+ }
1308
+ get virtualScrollerDisabled() {
1309
+ return !this.virtualScroll;
1310
+ }
1311
+ scrollInView(index = -1) {
1312
+ const id = index !== -1 ? `${this.id}_${index}` : this.focusedOptionId;
1313
+ if (this.itemsViewChild && this.itemsViewChild.nativeElement) {
1314
+ const element = DomHandler.findSingle(this.itemsViewChild.nativeElement, `li[id="${id}"]`);
1315
+ if (element) {
1316
+ element.scrollIntoView && element.scrollIntoView({ block: 'nearest', inline: 'nearest' });
842
1317
  }
843
- else {
844
- if (opt.items) {
845
- opt.items.forEach((option) => {
846
- let optionDisabled = this.isOptionDisabled(option);
847
- if (optionDisabled && this.isSelected(option)) {
848
- val.push(this.getOptionValue(option));
849
- }
850
- });
851
- }
1318
+ else if (!this.virtualScrollerDisabled) {
1319
+ setTimeout(() => {
1320
+ this.virtualScroll && this.scroller?.scrollToIndex(index !== -1 ? index : this.focusedOptionIndex());
1321
+ }, 0);
852
1322
  }
853
- });
854
- this.value = val;
1323
+ }
855
1324
  }
856
- show() {
857
- if (!this.overlayVisible) {
858
- this.overlayVisible = true;
859
- this.preventDocumentDefault = true;
860
- this.cd.markForCheck();
1325
+ get focusedOptionId() {
1326
+ return this.focusedOptionIndex() !== -1 ? `${this.id}_${this.focusedOptionIndex()}` : null;
1327
+ }
1328
+ checkSelectionLimit() {
1329
+ if (this.selectionLimit && this.value && this.value.length === this.selectionLimit) {
1330
+ this.maxSelectionLimitReached = true;
861
1331
  }
1332
+ else {
1333
+ this.maxSelectionLimitReached = false;
1334
+ }
1335
+ }
1336
+ writeValue(value) {
1337
+ this.value = this.modelValue();
1338
+ this.updateModel(this.value);
1339
+ this.checkSelectionLimit();
1340
+ this.cd.markForCheck();
1341
+ }
1342
+ registerOnChange(fn) {
1343
+ this.onModelChange = fn;
1344
+ }
1345
+ registerOnTouched(fn) {
1346
+ this.onModelTouched = fn;
1347
+ }
1348
+ setDisabledState(val) {
1349
+ this.disabled = val;
1350
+ this.cd.markForCheck();
1351
+ }
1352
+ allSelected() {
1353
+ const allSelected = this.visibleOptions().length > 0 && this.visibleOptions().every((option) => this.isOptionGroup(option) || this.isOptionDisabled(option) || this.isSelected(option));
1354
+ return ObjectUtils.isNotEmpty(this.visibleOptions()) && allSelected;
1355
+ }
1356
+ /**
1357
+ * Displays the panel.
1358
+ * @group Method
1359
+ */
1360
+ show(isFocus) {
1361
+ this.overlayVisible = true;
1362
+ const focusedOptionIndex = this.focusedOptionIndex() !== -1 ? this.focusedOptionIndex() : this.autoOptionFocus ? this.findFirstFocusedOptionIndex() : -1;
1363
+ this.focusedOptionIndex.set(focusedOptionIndex);
1364
+ if (isFocus) {
1365
+ DomHandler.focus(this.focusInputViewChild?.nativeElement);
1366
+ }
1367
+ this.cd.markForCheck();
1368
+ }
1369
+ /**
1370
+ * Hides the panel.
1371
+ * @group Method
1372
+ */
1373
+ hide(isFocus) {
1374
+ this.overlayVisible = false;
1375
+ this.focusedOptionIndex.set(-1);
1376
+ if (this.filter && this.resetFilterOnHide) {
1377
+ this.resetFilter();
1378
+ }
1379
+ isFocus && DomHandler.focus(this.focusInputViewChild?.nativeElement);
1380
+ this.onPanelHide.emit();
1381
+ this.cd.markForCheck();
862
1382
  }
863
1383
  onOverlayAnimationStart(event) {
864
1384
  switch (event.toState) {
865
1385
  case 'visible':
1386
+ this.itemsWrapper = DomHandler.findSingle(this.overlayViewChild?.overlayViewChild?.nativeElement, this.virtualScroll ? '.p-scroller' : '.p-multiselect-items-wrapper');
866
1387
  this.virtualScroll && this.scroller?.setContentEl(this.itemsViewChild?.nativeElement);
867
- if (this.filterInputChild && this.filterInputChild.nativeElement) {
868
- this.preventModelTouched = true;
869
- if (this.autofocusFilter) {
870
- this.filterInputChild.nativeElement.focus();
1388
+ if (this._options() && this._options().length) {
1389
+ if (this.virtualScroll) {
1390
+ const selectedIndex = ObjectUtils.isNotEmpty(this.modelValue()) ? this.focusedOptionIndex() : -1;
1391
+ if (selectedIndex !== -1) {
1392
+ this.scroller?.scrollToIndex(0);
1393
+ }
1394
+ }
1395
+ else {
1396
+ let selectedListItem = DomHandler.findSingle(this.itemsWrapper, '.p-multiselect-item.p-highlight');
1397
+ if (selectedListItem) {
1398
+ selectedListItem.scrollIntoView({ block: 'nearest', inline: 'center' });
1399
+ }
871
1400
  }
1401
+ this.onPanelShow.emit();
872
1402
  }
873
- this.onPanelShow.emit();
874
- break;
875
1403
  case 'void':
1404
+ this.itemsWrapper = null;
876
1405
  this.onModelTouched();
877
1406
  break;
878
1407
  }
879
1408
  }
880
- hide() {
881
- this.overlayVisible = false;
882
- if (this.resetFilterOnHide) {
883
- this.resetFilter();
884
- }
885
- this.onPanelHide.emit();
886
- this.cd.markForCheck();
887
- }
888
1409
  resetFilter() {
889
1410
  if (this.filterInputChild && this.filterInputChild.nativeElement) {
890
1411
  this.filterInputChild.nativeElement.value = '';
@@ -899,79 +1420,15 @@ class MultiSelect {
899
1420
  }
900
1421
  clear(event) {
901
1422
  this.value = null;
902
- this.updateLabel();
903
- this.updateFilledState();
904
1423
  this.checkSelectionLimit();
1424
+ this.updateModel(null, event);
905
1425
  this.onClear.emit();
906
- this.onModelChange(this.value);
907
1426
  event.stopPropagation();
908
1427
  }
909
- onMouseclick(event, input) {
910
- if (this.disabled || this.readonly || event.target.isSameNode(this.accessibleViewChild?.nativeElement)) {
911
- return;
912
- }
913
- this.onClick.emit(event);
914
- if (!this.overlayViewChild?.el?.nativeElement?.contains(event.target) && !DomHandler.hasClass(event.target, 'p-multiselect-token-icon')) {
915
- if (this.overlayVisible) {
916
- this.hide();
917
- }
918
- else {
919
- this.show();
920
- }
921
- input.focus();
922
- }
923
- }
924
- removeChip(chip, event) {
925
- this.value = this.value.filter((val) => !ObjectUtils.equals(val, chip, this.dataKey));
926
- this.onModelChange(this.value);
927
- this.checkSelectionLimit();
928
- this.onChange.emit({ originalEvent: event, value: this.value, itemValue: chip });
929
- this.updateLabel();
930
- this.updateFilledState();
931
- }
932
- onInputFocus(event) {
933
- this.focus = true;
934
- this.onFocus.emit({ originalEvent: event });
935
- }
936
- onInputBlur(event) {
937
- this.focus = false;
938
- this.onBlur.emit({ originalEvent: event });
939
- if (!this.preventModelTouched) {
940
- this.onModelTouched();
941
- }
942
- this.preventModelTouched = false;
943
- }
944
- onOptionKeydown(event) {
945
- if (this.readonly) {
946
- return;
947
- }
948
- switch (event.originalEvent.which) {
949
- //down
950
- case 40:
951
- var nextItem = this.findNextItem(event.originalEvent.target.parentElement);
952
- if (nextItem) {
953
- nextItem.focus();
954
- }
955
- event.originalEvent.preventDefault();
956
- break;
957
- //up
958
- case 38:
959
- var prevItem = this.findPrevItem(event.originalEvent.target.parentElement);
960
- if (prevItem) {
961
- prevItem.focus();
962
- }
963
- event.originalEvent.preventDefault();
964
- break;
965
- //enter
966
- case 13:
967
- this.onOptionClick(event);
968
- event.originalEvent.preventDefault();
969
- break;
970
- case 27:
971
- case 9:
972
- this.hide();
973
- break;
974
- }
1428
+ removeOption(optionValue, event) {
1429
+ let value = this.modelValue().filter((val) => !ObjectUtils.equals(val, optionValue, this.equalityKey()));
1430
+ this.updateModel(value, event);
1431
+ event && event.stopPropagation();
975
1432
  }
976
1433
  findNextItem(item) {
977
1434
  let nextItem = item.nextElementSibling;
@@ -987,161 +1444,63 @@ class MultiSelect {
987
1444
  else
988
1445
  return null;
989
1446
  }
990
- onKeydown(event) {
991
- switch (event.which) {
992
- //down
993
- case 40:
994
- if (!this.overlayVisible && event.altKey) {
995
- this.show();
996
- event.preventDefault();
997
- }
998
- break;
999
- //space
1000
- case 32:
1001
- if (!this.overlayVisible) {
1002
- this.show();
1003
- event.preventDefault();
1004
- }
1005
- break;
1006
- //escape
1007
- case 27:
1008
- this.hide();
1009
- break;
1010
- }
1011
- }
1012
- updateLabel() {
1013
- if (this.value && this.options && this.value.length && this.displaySelectedLabel) {
1014
- let label = '';
1015
- for (let i = 0; i < this.value.length; i++) {
1016
- let itemLabel = this.findLabelByValue(this.value[i]);
1017
- if (itemLabel) {
1018
- if (label.length > 0) {
1019
- label = label + ', ';
1020
- }
1021
- label = label + itemLabel;
1022
- }
1023
- }
1024
- if (this.value.length <= this.maxSelectedLabels || this.selectedItemsLabel === 'ellipsis') {
1025
- this.valuesAsString = label;
1026
- }
1027
- else {
1028
- let pattern = /{(.*?)}/;
1029
- if (pattern.test(this.selectedItemsLabel)) {
1030
- this.valuesAsString = this.selectedItemsLabel.replace(this.selectedItemsLabel.match(pattern)[0], this.value.length + '');
1031
- }
1032
- else {
1033
- this.valuesAsString = this.selectedItemsLabel;
1034
- }
1035
- }
1447
+ findNextOptionIndex(index) {
1448
+ const matchedOptionIndex = index < this.visibleOptions().length - 1
1449
+ ? this.visibleOptions()
1450
+ .slice(index + 1)
1451
+ .findIndex((option) => this.isValidOption(option))
1452
+ : -1;
1453
+ return matchedOptionIndex > -1 ? matchedOptionIndex + index + 1 : index;
1454
+ }
1455
+ findPrevOptionIndex(index) {
1456
+ const matchedOptionIndex = index > 0 ? ObjectUtils.findLastIndex(this.visibleOptions().slice(0, index), (option) => this.isValidOption(option)) : -1;
1457
+ return matchedOptionIndex > -1 ? matchedOptionIndex : index;
1458
+ }
1459
+ findLastSelectedOptionIndex() {
1460
+ return this.hasSelectedOption() ? ObjectUtils.findLastIndex(this.visibleOptions(), (option) => this.isValidSelectedOption(option)) : -1;
1461
+ }
1462
+ findLastFocusedOptionIndex() {
1463
+ const selectedIndex = this.findLastSelectedOptionIndex();
1464
+ return selectedIndex < 0 ? this.findLastOptionIndex() : selectedIndex;
1465
+ }
1466
+ findLastOptionIndex() {
1467
+ return ObjectUtils.findLastIndex(this.visibleOptions(), (option) => this.isValidOption(option));
1468
+ }
1469
+ searchOptions(event, char) {
1470
+ this.searchValue = (this.searchValue || '') + char;
1471
+ let optionIndex = -1;
1472
+ let matched = false;
1473
+ if (this.focusedOptionIndex() !== -1) {
1474
+ optionIndex = this.visibleOptions()
1475
+ .slice(this.focusedOptionIndex())
1476
+ .findIndex((option) => this.isOptionMatched(option));
1477
+ optionIndex =
1478
+ optionIndex === -1
1479
+ ? this.visibleOptions()
1480
+ .slice(0, this.focusedOptionIndex())
1481
+ .findIndex((option) => this.isOptionMatched(option))
1482
+ : optionIndex + this.focusedOptionIndex();
1036
1483
  }
1037
1484
  else {
1038
- this.valuesAsString = this.placeholder || this.defaultLabel;
1485
+ optionIndex = this.visibleOptions().findIndex((option) => this.isOptionMatched(option));
1039
1486
  }
1040
- }
1041
- findLabelByValue(val) {
1042
- if (this.group) {
1043
- let label = null;
1044
- for (let i = 0; i < this.options.length; i++) {
1045
- let subOptions = this.getOptionGroupChildren(this.options[i]);
1046
- if (subOptions) {
1047
- label = this.searchLabelByValue(val, subOptions);
1048
- if (label) {
1049
- break;
1050
- }
1051
- }
1052
- }
1053
- return label;
1487
+ if (optionIndex !== -1) {
1488
+ matched = true;
1054
1489
  }
1055
- else {
1056
- return this.searchLabelByValue(val, this.options);
1490
+ if (optionIndex === -1 && this.focusedOptionIndex() === -1) {
1491
+ optionIndex = this.findFirstFocusedOptionIndex();
1057
1492
  }
1058
- }
1059
- searchLabelByValue(val, options) {
1060
- let label = null;
1061
- for (let i = 0; i < options.length; i++) {
1062
- let option = options[i];
1063
- let optionValue = this.getOptionValue(option);
1064
- if ((val == null && optionValue == null) || ObjectUtils.equals(val, optionValue, this.dataKey)) {
1065
- label = this.getOptionLabel(option);
1066
- break;
1067
- }
1068
- }
1069
- return label;
1070
- }
1071
- get allChecked() {
1072
- let optionsToRender = this.optionsToRender;
1073
- if (!optionsToRender || optionsToRender.length === 0) {
1074
- return false;
1493
+ if (optionIndex !== -1) {
1494
+ this.changeFocusedOptionIndex(event, optionIndex);
1075
1495
  }
1076
- else {
1077
- let selectedDisabledItemsLength = 0;
1078
- let unselectedDisabledItemsLength = 0;
1079
- let selectedEnabledItemsLength = 0;
1080
- let visibleOptionsLength = this.group ? 0 : this.optionsToRender.length;
1081
- for (let option of optionsToRender) {
1082
- if (!this.group) {
1083
- let disabled = this.isOptionDisabled(option);
1084
- let selected = this.isSelected(option);
1085
- if (disabled) {
1086
- if (selected)
1087
- selectedDisabledItemsLength++;
1088
- else
1089
- unselectedDisabledItemsLength++;
1090
- }
1091
- else {
1092
- if (selected)
1093
- selectedEnabledItemsLength++;
1094
- else
1095
- return false;
1096
- }
1097
- }
1098
- else {
1099
- for (let opt of this.getOptionGroupChildren(option)) {
1100
- let disabled = this.isOptionDisabled(opt);
1101
- let selected = this.isSelected(opt);
1102
- if (disabled) {
1103
- if (selected)
1104
- selectedDisabledItemsLength++;
1105
- else
1106
- unselectedDisabledItemsLength++;
1107
- }
1108
- else {
1109
- if (selected)
1110
- selectedEnabledItemsLength++;
1111
- else {
1112
- return false;
1113
- }
1114
- }
1115
- visibleOptionsLength++;
1116
- }
1117
- }
1118
- }
1119
- return (visibleOptionsLength === selectedDisabledItemsLength ||
1120
- visibleOptionsLength === selectedEnabledItemsLength ||
1121
- (selectedEnabledItemsLength && visibleOptionsLength === selectedEnabledItemsLength + unselectedDisabledItemsLength + selectedDisabledItemsLength));
1496
+ if (this.searchTimeout) {
1497
+ clearTimeout(this.searchTimeout);
1122
1498
  }
1123
- }
1124
- get optionsToRender() {
1125
- return (this._filteredOptions || this.options);
1126
- }
1127
- get emptyMessageLabel() {
1128
- return this.emptyMessage || this.config.getTranslation(TranslationKeys.EMPTY_MESSAGE);
1129
- }
1130
- get emptyFilterMessageLabel() {
1131
- return this.emptyFilterMessage || this.config.getTranslation(TranslationKeys.EMPTY_FILTER_MESSAGE);
1132
- }
1133
- hasFilter() {
1134
- return this._filterValue && this._filterValue.trim().length > 0;
1135
- }
1136
- isEmpty() {
1137
- return !this.optionsToRender || (this.optionsToRender && this.optionsToRender.length === 0);
1138
- }
1139
- onFilterInputChange(event) {
1140
- this._filterValue = event.target.value;
1141
- this.activateFilter();
1142
- this.filtered = true;
1143
- this.onFilter.emit({ originalEvent: event, filter: this._filterValue });
1144
- this.cd.detectChanges();
1499
+ this.searchTimeout = setTimeout(() => {
1500
+ this.searchValue = '';
1501
+ this.searchTimeout = null;
1502
+ }, 500);
1503
+ return matched;
1145
1504
  }
1146
1505
  activateFilter() {
1147
1506
  if (this.hasFilter() && this._options) {
@@ -1164,75 +1523,69 @@ class MultiSelect {
1164
1523
  this._filteredOptions = null;
1165
1524
  }
1166
1525
  }
1167
- onHeaderCheckboxFocus() {
1168
- this.headerCheckboxFocus = true;
1526
+ hasFocusableElements() {
1527
+ return DomHandler.getFocusableElements(this.overlayViewChild.overlayViewChild.nativeElement, ':not([data-p-hidden-focusable="true"])').length > 0;
1169
1528
  }
1170
- onHeaderCheckboxBlur() {
1171
- this.headerCheckboxFocus = false;
1529
+ hasFilter() {
1530
+ return this._filterValue() && this._filterValue().trim().length > 0;
1172
1531
  }
1173
1532
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: MultiSelect, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }, { token: i0.NgZone }, { token: i3.FilterService }, { token: i3.PrimeNGConfig }, { token: i3.OverlayService }], target: i0.ɵɵFactoryTarget.Component });
1174
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.0.2", type: MultiSelect, selector: "p-multiSelect", inputs: { style: "style", styleClass: "styleClass", panelStyle: "panelStyle", panelStyleClass: "panelStyleClass", inputId: "inputId", disabled: "disabled", readonly: "readonly", group: "group", filter: "filter", filterPlaceHolder: "filterPlaceHolder", filterLocale: "filterLocale", overlayVisible: "overlayVisible", tabindex: "tabindex", appendTo: "appendTo", dataKey: "dataKey", name: "name", label: "label", ariaLabelledBy: "ariaLabelledBy", displaySelectedLabel: "displaySelectedLabel", maxSelectedLabels: "maxSelectedLabels", selectedItemsLabel: "selectedItemsLabel", showToggleAll: "showToggleAll", emptyFilterMessage: "emptyFilterMessage", emptyMessage: "emptyMessage", resetFilterOnHide: "resetFilterOnHide", dropdownIcon: "dropdownIcon", optionLabel: "optionLabel", optionValue: "optionValue", optionDisabled: "optionDisabled", optionGroupLabel: "optionGroupLabel", optionGroupChildren: "optionGroupChildren", showHeader: "showHeader", filterBy: "filterBy", scrollHeight: "scrollHeight", lazy: "lazy", virtualScroll: "virtualScroll", virtualScrollItemSize: "virtualScrollItemSize", virtualScrollOptions: "virtualScrollOptions", overlayOptions: "overlayOptions", ariaFilterLabel: "ariaFilterLabel", filterMatchMode: "filterMatchMode", tooltip: "tooltip", tooltipPosition: "tooltipPosition", tooltipPositionStyle: "tooltipPositionStyle", tooltipStyleClass: "tooltipStyleClass", autofocusFilter: "autofocusFilter", display: "display", autocomplete: "autocomplete", showClear: "showClear", autoZIndex: "autoZIndex", baseZIndex: "baseZIndex", showTransitionOptions: "showTransitionOptions", hideTransitionOptions: "hideTransitionOptions", defaultLabel: "defaultLabel", placeholder: "placeholder", options: "options", filterValue: "filterValue", itemSize: "itemSize", selectionLimit: "selectionLimit" }, outputs: { onChange: "onChange", onFilter: "onFilter", onFocus: "onFocus", onBlur: "onBlur", onClick: "onClick", onClear: "onClear", onPanelShow: "onPanelShow", onPanelHide: "onPanelHide", onLazyLoad: "onLazyLoad", onRemove: "onRemove" }, host: { properties: { "class.p-inputwrapper-filled": "filled", "class.p-inputwrapper-focus": "focus || overlayVisible", "class.p-multiselect-clearable": "showClear && !disabled" }, classAttribute: "p-element p-inputwrapper" }, providers: [MULTISELECT_VALUE_ACCESSOR], queries: [{ propertyName: "footerFacet", first: true, predicate: Footer, descendants: true }, { propertyName: "headerFacet", first: true, predicate: Header, descendants: true }, { propertyName: "templates", predicate: PrimeTemplate }], viewQueries: [{ propertyName: "containerViewChild", first: true, predicate: ["container"], descendants: true }, { propertyName: "overlayViewChild", first: true, predicate: ["overlay"], descendants: true }, { propertyName: "filterInputChild", first: true, predicate: ["filterInput"], descendants: true }, { propertyName: "accessibleViewChild", first: true, predicate: ["in"], descendants: true }, { propertyName: "itemsViewChild", first: true, predicate: ["items"], descendants: true }, { propertyName: "scroller", first: true, predicate: ["scroller"], descendants: true }], ngImport: i0, template: `
1175
- <div
1176
- #container
1177
- [ngClass]="{ 'p-multiselect p-component': true, 'p-multiselect-open': overlayVisible, 'p-multiselect-chip': display === 'chip', 'p-focus': focus, 'p-disabled': disabled }"
1178
- [ngStyle]="style"
1179
- [class]="styleClass"
1180
- (click)="onMouseclick($event, in)"
1181
- >
1182
- <div class="p-hidden-accessible">
1533
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.0.2", type: MultiSelect, selector: "p-multiSelect", inputs: { id: "id", ariaLabel: "ariaLabel", style: "style", styleClass: "styleClass", panelStyle: "panelStyle", panelStyleClass: "panelStyleClass", inputId: "inputId", disabled: "disabled", readonly: "readonly", group: "group", filter: "filter", filterPlaceHolder: "filterPlaceHolder", filterLocale: "filterLocale", overlayVisible: "overlayVisible", tabindex: "tabindex", appendTo: "appendTo", dataKey: "dataKey", name: "name", ariaLabelledBy: "ariaLabelledBy", displaySelectedLabel: "displaySelectedLabel", maxSelectedLabels: "maxSelectedLabels", selectionLimit: "selectionLimit", selectedItemsLabel: "selectedItemsLabel", showToggleAll: "showToggleAll", emptyFilterMessage: "emptyFilterMessage", emptyMessage: "emptyMessage", resetFilterOnHide: "resetFilterOnHide", dropdownIcon: "dropdownIcon", optionLabel: "optionLabel", optionValue: "optionValue", optionDisabled: "optionDisabled", optionGroupLabel: "optionGroupLabel", optionGroupChildren: "optionGroupChildren", showHeader: "showHeader", filterBy: "filterBy", scrollHeight: "scrollHeight", lazy: "lazy", virtualScroll: "virtualScroll", virtualScrollItemSize: "virtualScrollItemSize", virtualScrollOptions: "virtualScrollOptions", overlayOptions: "overlayOptions", ariaFilterLabel: "ariaFilterLabel", filterMatchMode: "filterMatchMode", tooltip: "tooltip", tooltipPosition: "tooltipPosition", tooltipPositionStyle: "tooltipPositionStyle", tooltipStyleClass: "tooltipStyleClass", autofocusFilter: "autofocusFilter", display: "display", autocomplete: "autocomplete", showClear: "showClear", autoZIndex: "autoZIndex", baseZIndex: "baseZIndex", showTransitionOptions: "showTransitionOptions", hideTransitionOptions: "hideTransitionOptions", defaultLabel: "defaultLabel", placeholder: "placeholder", options: "options", filterValue: "filterValue", itemSize: "itemSize", focusOnHover: "focusOnHover", filterFields: "filterFields", selectOnFocus: "selectOnFocus", autoOptionFocus: "autoOptionFocus" }, outputs: { onChange: "onChange", onFilter: "onFilter", onFocus: "onFocus", onBlur: "onBlur", onClick: "onClick", onClear: "onClear", onPanelShow: "onPanelShow", onPanelHide: "onPanelHide", onLazyLoad: "onLazyLoad", onRemove: "onRemove" }, host: { properties: { "class.p-inputwrapper-filled": "filled", "class.p-inputwrapper-focus": "focused || overlayVisible" }, classAttribute: "p-element p-inputwrapper" }, providers: [MULTISELECT_VALUE_ACCESSOR], queries: [{ propertyName: "footerFacet", first: true, predicate: Footer, descendants: true }, { propertyName: "headerFacet", first: true, predicate: Header, descendants: true }, { propertyName: "templates", predicate: PrimeTemplate }], viewQueries: [{ propertyName: "containerViewChild", first: true, predicate: ["container"], descendants: true }, { propertyName: "overlayViewChild", first: true, predicate: ["overlay"], descendants: true }, { propertyName: "filterInputChild", first: true, predicate: ["filterInput"], descendants: true }, { propertyName: "focusInputViewChild", first: true, predicate: ["focusInput"], descendants: true }, { propertyName: "itemsViewChild", first: true, predicate: ["items"], descendants: true }, { propertyName: "scroller", first: true, predicate: ["scroller"], descendants: true }, { propertyName: "lastHiddenFocusableElementOnOverlay", first: true, predicate: ["lastHiddenFocusableEl"], descendants: true }, { propertyName: "firstHiddenFocusableElementOnOverlay", first: true, predicate: ["firstHiddenFocusableEl"], descendants: true }, { propertyName: "headerCheckboxViewChild", first: true, predicate: ["headerCheckbox"], descendants: true }], ngImport: i0, template: `
1534
+ <div #container [attr.id]="id" [ngClass]="containerClass" [ngStyle]="style" [class]="styleClass" (click)="onContainerClick($event)">
1535
+ <div class="p-hidden-accessible" [attr.data-p-hidden-accessible]="true">
1183
1536
  <input
1184
- #in
1185
- type="text"
1186
- [attr.label]="label"
1187
- readonly="readonly"
1537
+ #focusInput
1538
+ [pTooltip]="tooltip"
1539
+ [tooltipPosition]="tooltipPosition"
1540
+ [positionStyle]="tooltipPositionStyle"
1541
+ [tooltipStyleClass]="tooltipStyleClass"
1542
+ [attr.aria-disabled]="disabled"
1188
1543
  [attr.id]="inputId"
1189
- [attr.name]="name"
1544
+ role="combobox"
1545
+ [attr.aria-label]="ariaLabel"
1546
+ [attr.aria-labelledby]="ariaLabelledBy"
1547
+ [attr.aria-haspopup]="'listbox'"
1548
+ [attr.aria-expanded]="overlayVisible"
1549
+ [attr.aria-controls]="id + '_list'"
1550
+ [attr.tabindex]="!disabled ? tabindex : -1"
1551
+ [attr.aria-activedescendant]="focused ? focusedOptionId : undefined"
1190
1552
  (focus)="onInputFocus($event)"
1191
1553
  (blur)="onInputBlur($event)"
1192
- [disabled]="disabled"
1193
- [attr.tabindex]="tabindex"
1194
- (keydown)="onKeydown($event)"
1195
- aria-haspopup="listbox"
1196
- [attr.aria-expanded]="overlayVisible"
1197
- [attr.aria-labelledby]="ariaLabelledBy"
1198
- role="listbox"
1554
+ (keydown)="onKeyDown($event)"
1199
1555
  />
1200
1556
  </div>
1201
1557
  <div class="p-multiselect-label-container" [pTooltip]="tooltip" [tooltipPosition]="tooltipPosition" [positionStyle]="tooltipPositionStyle" [tooltipStyleClass]="tooltipStyleClass">
1202
- <div
1203
- class="p-multiselect-label"
1204
- [ngClass]="{ 'p-placeholder': valuesAsString === (defaultLabel || placeholder), 'p-multiselect-label-empty': (valuesAsString == null || valuesAsString.length === 0) && (placeholder == null || placeholder.length === 0) }"
1205
- >
1558
+ <div [ngClass]="labelClass">
1206
1559
  <ng-container *ngIf="!selectedItemsTemplate">
1207
- <ng-container *ngIf="display === 'comma'">{{ valuesAsString || 'empty' }}</ng-container>
1560
+ <ng-container *ngIf="display === 'comma'">{{ label() || 'empty' }}</ng-container>
1208
1561
  <ng-container *ngIf="display === 'chip'">
1209
- <div #token *ngFor="let item of value; let i = index" class="p-multiselect-token">
1210
- <span class="p-multiselect-token-label">{{ findLabelByValue(item) }}</span>
1562
+ <div #token *ngFor="let item of chipSelectedItems(); let i = index" class="p-multiselect-token">
1563
+ <span class="p-multiselect-token-label">{{ getLabelByValue(item) }}</span>
1211
1564
  <ng-container *ngIf="!disabled">
1212
- <TimesCircleIcon *ngIf="!removeTokenIconTemplate" [styleClass]="'p-multiselect-token-icon'" (click)="removeChip(item, event)" />
1213
- <span *ngIf="removeTokenIconTemplate" class="p-multiselect-token-icon" (click)="removeChip(item, event)">
1565
+ <TimesCircleIcon *ngIf="!removeTokenIconTemplate" [styleClass]="'p-multiselect-token-icon'" (click)="removeOption(item, event)" [attr.data-pc-section]="'clearicon'" [attr.aria-hidden]="true" />
1566
+ <span *ngIf="removeTokenIconTemplate" class="p-multiselect-token-icon" (click)="removeOption(item, event)" [attr.data-pc-section]="'clearicon'" [attr.aria-hidden]="true">
1214
1567
  <ng-container *ngTemplateOutlet="removeTokenIconTemplate"></ng-container>
1215
1568
  </span>
1216
1569
  </ng-container>
1217
1570
  </div>
1218
- <ng-container *ngIf="!value || value.length === 0">{{ placeholder || defaultLabel || 'empty' }}</ng-container>
1571
+ <ng-container *ngIf="!modelValue() || modelValue().length === 0">{{ placeholder || defaultLabel || 'empty' }}</ng-container>
1219
1572
  </ng-container>
1220
1573
  </ng-container>
1221
- <ng-container *ngTemplateOutlet="selectedItemsTemplate; context: { $implicit: value, removeChip: removeChip.bind(this) }"></ng-container>
1574
+ <ng-container *ngTemplateOutlet="selectedItemsTemplate; context: { $implicit: modelValue(), removeChip: removeOption.bind(this) }"></ng-container>
1222
1575
  </div>
1223
- <ng-container *ngIf="value != null && filled && !disabled && showClear">
1224
- <TimesIcon *ngIf="!clearIconTemplate" [styleClass]="'p-multiselect-clear-icon'" (click)="clear($event)" />
1225
- <span *ngIf="clearIconTemplate" class="p-multiselect-clear-icon" (click)="clear($event)">
1576
+ <ng-container *ngIf="modelValue() != null && filled && !disabled && showClear">
1577
+ <TimesIcon *ngIf="!clearIconTemplate" [styleClass]="'p-multiselect-clear-icon'" (click)="clear($event)" [attr.data-pc-section]="'clearicon'" [attr.aria-hidden]="true" />
1578
+ <span *ngIf="clearIconTemplate" class="p-multiselect-clear-icon" (click)="clear($event)" [attr.data-pc-section]="'clearicon'" [attr.aria-hidden]="true">
1226
1579
  <ng-template *ngTemplateOutlet="clearIconTemplate"></ng-template>
1227
1580
  </span>
1228
1581
  </ng-container>
1229
1582
  </div>
1230
- <div [ngClass]="{ 'p-multiselect-trigger': true }">
1583
+ <div class="p-multiselect-trigger">
1231
1584
  <ng-container *ngIf="!dropdownIconTemplate">
1232
- <span *ngIf="dropdownIcon" class="p-multiselect-trigger-icon" [ngClass]="dropdownIcon"></span>
1233
- <ChevronDownIcon *ngIf="!dropdownIcon" [styleClass]="'p-multiselect-trigger-icon'" />
1585
+ <span *ngIf="dropdownIcon" class="p-multiselect-trigger-icon" [ngClass]="dropdownIcon" [attr.data-pc-section]="'triggericon'" [attr.aria-hidden]="true"></span>
1586
+ <ChevronDownIcon *ngIf="!dropdownIcon" [styleClass]="'p-multiselect-trigger-icon'" [attr.data-pc-section]="'triggericon'" [attr.aria-hidden]="true" />
1234
1587
  </ng-container>
1235
- <span *ngIf="dropdownIconTemplate" class="p-multiselect-trigger-icon">
1588
+ <span *ngIf="dropdownIconTemplate" class="p-multiselect-trigger-icon" [attr.data-pc-section]="'triggericon'" [attr.aria-hidden]="true">
1236
1589
  <ng-template *ngTemplateOutlet="dropdownIconTemplate"></ng-template>
1237
1590
  </span>
1238
1591
  </div>
@@ -1250,7 +1603,18 @@ class MultiSelect {
1250
1603
  (onHide)="hide()"
1251
1604
  >
1252
1605
  <ng-template pTemplate="content">
1253
- <div [ngClass]="['p-multiselect-panel p-component']" [ngStyle]="panelStyle" [class]="panelStyleClass" (keydown)="onKeydown($event)">
1606
+ <div [ngClass]="'p-multiselect-panel p-component'" [ngStyle]="panelStyle" [class]="panelStyleClass">
1607
+ <span
1608
+ #firstHiddenFocusableEl
1609
+ role="presentation"
1610
+ [attr.aria-hidden]="'true'"
1611
+ class="p-hidden-accessible p-hidden-focusable"
1612
+ [attr.tabindex]="0"
1613
+ (focus)="onFirstHiddenFocus($event)"
1614
+ [attr.data-p-hidden-accessible]="true"
1615
+ [attr.data-p-hidden-focusable]="true"
1616
+ >
1617
+ </span>
1254
1618
  <div class="p-multiselect-header" *ngIf="showHeader">
1255
1619
  <ng-content select="p-header"></ng-content>
1256
1620
  <ng-container *ngTemplateOutlet="headerTemplate"></ng-container>
@@ -1258,28 +1622,29 @@ class MultiSelect {
1258
1622
  <ng-container *ngTemplateOutlet="filterTemplate; context: { options: filterOptions }"></ng-container>
1259
1623
  </ng-container>
1260
1624
  <ng-template #builtInFilterElement>
1261
- <div class="p-checkbox p-component" *ngIf="showToggleAll && !selectionLimit" [ngClass]="{ 'p-checkbox-disabled': disabled || toggleAllDisabled }">
1262
- <div class="p-hidden-accessible">
1625
+ <div
1626
+ class="p-checkbox p-component"
1627
+ *ngIf="showToggleAll && !selectionLimit"
1628
+ [ngClass]="{ 'p-checkbox-disabled': disabled || toggleAllDisabled }"
1629
+ (click)="onToggleAll($event)"
1630
+ (keydown)="onHeaderCheckboxKeyDown($event)"
1631
+ >
1632
+ <div class="p-hidden-accessible" [attr.data-p-hidden-accessible]="true">
1263
1633
  <input
1634
+ #headerCheckbox
1264
1635
  type="checkbox"
1265
- readonly="readonly"
1266
- [checked]="allChecked"
1636
+ [readonly]="readonly"
1637
+ [attr.checked]="allSelected()"
1267
1638
  (focus)="onHeaderCheckboxFocus()"
1268
1639
  (blur)="onHeaderCheckboxBlur()"
1269
- (keydown.space)="toggleAll($event)"
1270
1640
  [disabled]="disabled || toggleAllDisabled"
1641
+ [attr.aria-label]="toggleAllAriaLabel"
1271
1642
  />
1272
1643
  </div>
1273
- <div
1274
- class="p-checkbox-box"
1275
- role="checkbox"
1276
- [attr.aria-checked]="allChecked"
1277
- [ngClass]="{ 'p-highlight': allChecked, 'p-focus': headerCheckboxFocus, 'p-disabled': disabled || toggleAllDisabled }"
1278
- (click)="toggleAll($event)"
1279
- >
1280
- <ng-container *ngIf="allChecked">
1281
- <CheckIcon [styleClass]="'p-checkbox-icon'" *ngIf="!checkIconTemplate" />
1282
- <span *ngIf="checkIconTemplate" class="p-checkbox-icon">
1644
+ <div class="p-checkbox-box" role="checkbox" [attr.aria-checked]="allSelected()" [ngClass]="{ 'p-highlight': allSelected(), 'p-focus': headerCheckboxFocus, 'p-disabled': disabled || toggleAllDisabled }">
1645
+ <ng-container *ngIf="allSelected()">
1646
+ <CheckIcon [styleClass]="'p-checkbox-icon'" *ngIf="!checkIconTemplate" [attr.aria-hidden]="true" />
1647
+ <span *ngIf="checkIconTemplate" class="p-checkbox-icon" [attr.aria-hidden]="true">
1283
1648
  <ng-template *ngTemplateOutlet="checkIconTemplate"></ng-template>
1284
1649
  </span>
1285
1650
  </ng-container>
@@ -1290,9 +1655,14 @@ class MultiSelect {
1290
1655
  #filterInput
1291
1656
  type="text"
1292
1657
  [attr.autocomplete]="autocomplete"
1293
- role="textbox"
1294
- [value]="filterValue || ''"
1658
+ [attr.placeholder]="filterPlaceHolder"
1659
+ role="searchbox"
1660
+ [attr.aria-owns]="id + '_list'"
1661
+ [attr.aria-activedescendant]="focusedOptionId"
1662
+ [value]="_filterValue() || ''"
1295
1663
  (input)="onFilterInputChange($event)"
1664
+ (keydown)="onFilterKeyDown($event)"
1665
+ (blur)="onFilterBlur($event)"
1296
1666
  class="p-multiselect-filter p-inputtext p-component"
1297
1667
  [disabled]="disabled"
1298
1668
  [attr.placeholder]="filterPlaceHolder"
@@ -1316,7 +1686,7 @@ class MultiSelect {
1316
1686
  <p-scroller
1317
1687
  *ngIf="virtualScroll"
1318
1688
  #scroller
1319
- [items]="optionsToRender"
1689
+ [items]="visibleOptions()"
1320
1690
  [style]="{ height: scrollHeight }"
1321
1691
  [itemSize]="virtualScrollItemSize || _itemSize"
1322
1692
  [autoSize]="true"
@@ -1335,38 +1705,37 @@ class MultiSelect {
1335
1705
  </ng-container>
1336
1706
  </p-scroller>
1337
1707
  <ng-container *ngIf="!virtualScroll">
1338
- <ng-container *ngTemplateOutlet="buildInItems; context: { $implicit: optionsToRender, options: {} }"></ng-container>
1708
+ <ng-container *ngTemplateOutlet="buildInItems; context: { $implicit: visibleOptions(), options: {} }"></ng-container>
1339
1709
  </ng-container>
1340
1710
 
1341
1711
  <ng-template #buildInItems let-items let-scrollerOptions="options">
1342
1712
  <ul #items class="p-multiselect-items p-component" [ngClass]="scrollerOptions.contentStyleClass" [style]="scrollerOptions.contentStyle" role="listbox" aria-multiselectable="true">
1343
- <ng-container *ngIf="group">
1344
- <ng-template ngFor let-optgroup [ngForOf]="items">
1345
- <li class="p-multiselect-item-group" [ngStyle]="{ height: scrollerOptions.itemSize + 'px' }">
1346
- <span *ngIf="!groupTemplate">{{ getOptionGroupLabel(optgroup) || 'empty' }}</span>
1347
- <ng-container *ngTemplateOutlet="groupTemplate; context: { $implicit: optgroup }"></ng-container>
1713
+ <ng-template ngFor let-option [ngForOf]="items" let-i="index">
1714
+ <ng-container *ngIf="option.group">
1715
+ <li [attr.id]="id + '_' + getOptionIndex(i, scrollerOptions)" class="p-multiselect-item-group" [ngStyle]="{ height: scrollerOptions.itemSize + 'px' }" role="option">
1716
+ <span *ngIf="!groupTemplate">{{ getOptionGroupLabel(option.optionGroup) }}</span>
1717
+ <ng-container *ngTemplateOutlet="groupTemplate; context: { $implicit: option.optionGroup }"></ng-container>
1348
1718
  </li>
1349
- <ng-container *ngTemplateOutlet="itemslist; context: { $implicit: getOptionGroupChildren(optgroup) }"></ng-container>
1350
- </ng-template>
1351
- </ng-container>
1352
- <ng-container *ngIf="!group">
1353
- <ng-container *ngTemplateOutlet="itemslist; context: { $implicit: items }"></ng-container>
1354
- </ng-container>
1355
- <ng-template #itemslist let-optionsToDisplay let-selectedOption="selectedOption">
1356
- <ng-template ngFor let-option let-i="index" [ngForOf]="optionsToDisplay">
1719
+ </ng-container>
1720
+ <ng-container *ngIf="!option.group">
1357
1721
  <p-multiSelectItem
1722
+ [id]="id + '_' + getOptionIndex(i, scrollerOptions)"
1358
1723
  [option]="option"
1359
1724
  [selected]="isSelected(option)"
1360
1725
  [label]="getOptionLabel(option)"
1361
1726
  [disabled]="isOptionDisabled(option)"
1362
- (onClick)="onOptionClick($event)"
1363
- (onKeydown)="onOptionKeydown($event)"
1364
1727
  [template]="itemTemplate"
1365
1728
  [checkIconTemplate]="checkIconTemplate"
1366
1729
  [itemSize]="scrollerOptions.itemSize"
1730
+ [focused]="focusedOptionIndex() === getOptionIndex(i, scrollerOptions)"
1731
+ [ariaPosInset]="getAriaPosInset(getOptionIndex(i, scrollerOptions))"
1732
+ [ariaSetSize]="ariaSetSize"
1733
+ (onClick)="onOptionSelect($event, false, getOptionIndex(i, scrollerOptions))"
1734
+ (onMouseEnter)="onOptionMouseEnter($event, getOptionIndex(i, scrollerOptions))"
1367
1735
  ></p-multiSelectItem>
1368
- </ng-template>
1736
+ </ng-container>
1369
1737
  </ng-template>
1738
+
1370
1739
  <li *ngIf="hasFilter() && isEmpty()" class="p-multiselect-empty-message" [ngStyle]="{ height: scrollerOptions.itemSize + 'px' }">
1371
1740
  <ng-container *ngIf="!emptyFilterTemplate && !emptyTemplate; else emptyFilter">
1372
1741
  {{ emptyFilterMessageLabel }}
@@ -1386,76 +1755,81 @@ class MultiSelect {
1386
1755
  <ng-content select="p-footer"></ng-content>
1387
1756
  <ng-container *ngTemplateOutlet="footerTemplate"></ng-container>
1388
1757
  </div>
1758
+
1759
+ <span
1760
+ #lastHiddenFocusableEl
1761
+ role="presentation"
1762
+ [attr.aria-hidden]="true"
1763
+ class="p-hidden-accessible p-hidden-focusable"
1764
+ [attr.tabindex]="0"
1765
+ (focus)="onLastHiddenFocus($event)"
1766
+ [attr.data-p-hidden-accessible]="true"
1767
+ [attr.data-p-hidden-focusable]="true"
1768
+ ></span>
1389
1769
  </div>
1390
1770
  </ng-template>
1391
1771
  </p-overlay>
1392
1772
  </div>
1393
- `, isInline: true, styles: ["@layer primeng{.p-multiselect{display:inline-flex;cursor:pointer;position:relative;-webkit-user-select:none;user-select:none}.p-multiselect-trigger{display:flex;align-items:center;justify-content:center;flex-shrink:0}.p-multiselect-label-container{overflow:hidden;flex:1 1 auto;cursor:pointer;display:flex}.p-multiselect-label{display:block;white-space:nowrap;cursor:pointer;overflow:hidden;text-overflow:ellipsis}.p-multiselect-label-empty{overflow:hidden;visibility:hidden}.p-multiselect-token{cursor:default;display:inline-flex;align-items:center;flex:0 0 auto}.p-multiselect-token-icon{cursor:pointer}.p-multiselect-token-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100px}.p-multiselect-items-wrapper{overflow:auto}.p-multiselect-items{margin:0;padding:0;list-style-type:none}.p-multiselect-item{cursor:pointer;display:flex;align-items:center;font-weight:400;white-space:nowrap;position:relative;overflow:hidden}.p-multiselect-header{display:flex;align-items:center;justify-content:space-between}.p-multiselect-filter-container{position:relative;flex:1 1 auto}.p-multiselect-filter-icon{position:absolute;top:50%;margin-top:-.5rem}.p-multiselect-filter-container .p-inputtext{width:100%}.p-multiselect-close{display:flex;align-items:center;justify-content:center;flex-shrink:0;overflow:hidden;position:relative}.p-fluid .p-multiselect{display:flex}.p-multiselect-clear-icon{position:absolute;top:50%;margin-top:-.5rem;cursor:pointer}.p-multiselect-clearable{position:relative}}\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: "directive", type: i0.forwardRef(function () { return i2.Ripple; }), selector: "[pRipple]" }, { 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: "component", type: i0.forwardRef(function () { return CheckIcon; }), selector: "CheckIcon" }, { kind: "component", type: i0.forwardRef(function () { return SearchIcon; }), selector: "SearchIcon" }, { kind: "component", type: i0.forwardRef(function () { return TimesCircleIcon; }), selector: "TimesCircleIcon" }, { 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 MultiSelectItem; }), selector: "p-multiSelectItem", inputs: ["option", "selected", "label", "disabled", "itemSize", "template", "checkIconTemplate"], outputs: ["onClick", "onKeydown"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1773
+ `, isInline: true, styles: ["@layer primeng{.p-multiselect{display:inline-flex;cursor:pointer;position:relative;-webkit-user-select:none;user-select:none}.p-multiselect-trigger{display:flex;align-items:center;justify-content:center;flex-shrink:0}.p-multiselect-label-container{overflow:hidden;flex:1 1 auto;cursor:pointer;display:flex}.p-multiselect-label{display:block;white-space:nowrap;cursor:pointer;overflow:hidden;text-overflow:ellipsis}.p-multiselect-label-empty{overflow:hidden;visibility:hidden}.p-multiselect-token{cursor:default;display:inline-flex;align-items:center;flex:0 0 auto}.p-multiselect-token-icon{cursor:pointer}.p-multiselect-token-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100px}.p-multiselect-items-wrapper{overflow:auto}.p-multiselect-items{margin:0;padding:0;list-style-type:none}.p-multiselect-item{cursor:pointer;display:flex;align-items:center;font-weight:400;white-space:nowrap;position:relative;overflow:hidden}.p-multiselect-header{display:flex;align-items:center;justify-content:space-between}.p-multiselect-filter-container{position:relative;flex:1 1 auto}.p-multiselect-filter-icon{position:absolute;top:50%;margin-top:-.5rem}.p-multiselect-filter-container .p-inputtext{width:100%}.p-multiselect-close{display:flex;align-items:center;justify-content:center;flex-shrink:0;overflow:hidden;position:relative}.p-fluid .p-multiselect{display:flex}.p-multiselect-clear-icon{position:absolute;top:50%;margin-top:-.5rem;cursor:pointer}.p-multiselect-clearable{position:relative}}\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: "directive", type: i0.forwardRef(function () { return i2.Ripple; }), selector: "[pRipple]" }, { 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: "component", type: i0.forwardRef(function () { return CheckIcon; }), selector: "CheckIcon" }, { kind: "component", type: i0.forwardRef(function () { return SearchIcon; }), selector: "SearchIcon" }, { kind: "component", type: i0.forwardRef(function () { return TimesCircleIcon; }), selector: "TimesCircleIcon" }, { 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 MultiSelectItem; }), selector: "p-multiSelectItem", inputs: ["id", "option", "selected", "label", "disabled", "itemSize", "focused", "ariaPosInset", "ariaSetSize", "template", "checkIconTemplate"], outputs: ["onClick", "onMouseEnter"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1394
1774
  }
1395
1775
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: MultiSelect, decorators: [{
1396
1776
  type: Component,
1397
1777
  args: [{ selector: 'p-multiSelect', template: `
1398
- <div
1399
- #container
1400
- [ngClass]="{ 'p-multiselect p-component': true, 'p-multiselect-open': overlayVisible, 'p-multiselect-chip': display === 'chip', 'p-focus': focus, 'p-disabled': disabled }"
1401
- [ngStyle]="style"
1402
- [class]="styleClass"
1403
- (click)="onMouseclick($event, in)"
1404
- >
1405
- <div class="p-hidden-accessible">
1778
+ <div #container [attr.id]="id" [ngClass]="containerClass" [ngStyle]="style" [class]="styleClass" (click)="onContainerClick($event)">
1779
+ <div class="p-hidden-accessible" [attr.data-p-hidden-accessible]="true">
1406
1780
  <input
1407
- #in
1408
- type="text"
1409
- [attr.label]="label"
1410
- readonly="readonly"
1781
+ #focusInput
1782
+ [pTooltip]="tooltip"
1783
+ [tooltipPosition]="tooltipPosition"
1784
+ [positionStyle]="tooltipPositionStyle"
1785
+ [tooltipStyleClass]="tooltipStyleClass"
1786
+ [attr.aria-disabled]="disabled"
1411
1787
  [attr.id]="inputId"
1412
- [attr.name]="name"
1788
+ role="combobox"
1789
+ [attr.aria-label]="ariaLabel"
1790
+ [attr.aria-labelledby]="ariaLabelledBy"
1791
+ [attr.aria-haspopup]="'listbox'"
1792
+ [attr.aria-expanded]="overlayVisible"
1793
+ [attr.aria-controls]="id + '_list'"
1794
+ [attr.tabindex]="!disabled ? tabindex : -1"
1795
+ [attr.aria-activedescendant]="focused ? focusedOptionId : undefined"
1413
1796
  (focus)="onInputFocus($event)"
1414
1797
  (blur)="onInputBlur($event)"
1415
- [disabled]="disabled"
1416
- [attr.tabindex]="tabindex"
1417
- (keydown)="onKeydown($event)"
1418
- aria-haspopup="listbox"
1419
- [attr.aria-expanded]="overlayVisible"
1420
- [attr.aria-labelledby]="ariaLabelledBy"
1421
- role="listbox"
1798
+ (keydown)="onKeyDown($event)"
1422
1799
  />
1423
1800
  </div>
1424
1801
  <div class="p-multiselect-label-container" [pTooltip]="tooltip" [tooltipPosition]="tooltipPosition" [positionStyle]="tooltipPositionStyle" [tooltipStyleClass]="tooltipStyleClass">
1425
- <div
1426
- class="p-multiselect-label"
1427
- [ngClass]="{ 'p-placeholder': valuesAsString === (defaultLabel || placeholder), 'p-multiselect-label-empty': (valuesAsString == null || valuesAsString.length === 0) && (placeholder == null || placeholder.length === 0) }"
1428
- >
1802
+ <div [ngClass]="labelClass">
1429
1803
  <ng-container *ngIf="!selectedItemsTemplate">
1430
- <ng-container *ngIf="display === 'comma'">{{ valuesAsString || 'empty' }}</ng-container>
1804
+ <ng-container *ngIf="display === 'comma'">{{ label() || 'empty' }}</ng-container>
1431
1805
  <ng-container *ngIf="display === 'chip'">
1432
- <div #token *ngFor="let item of value; let i = index" class="p-multiselect-token">
1433
- <span class="p-multiselect-token-label">{{ findLabelByValue(item) }}</span>
1806
+ <div #token *ngFor="let item of chipSelectedItems(); let i = index" class="p-multiselect-token">
1807
+ <span class="p-multiselect-token-label">{{ getLabelByValue(item) }}</span>
1434
1808
  <ng-container *ngIf="!disabled">
1435
- <TimesCircleIcon *ngIf="!removeTokenIconTemplate" [styleClass]="'p-multiselect-token-icon'" (click)="removeChip(item, event)" />
1436
- <span *ngIf="removeTokenIconTemplate" class="p-multiselect-token-icon" (click)="removeChip(item, event)">
1809
+ <TimesCircleIcon *ngIf="!removeTokenIconTemplate" [styleClass]="'p-multiselect-token-icon'" (click)="removeOption(item, event)" [attr.data-pc-section]="'clearicon'" [attr.aria-hidden]="true" />
1810
+ <span *ngIf="removeTokenIconTemplate" class="p-multiselect-token-icon" (click)="removeOption(item, event)" [attr.data-pc-section]="'clearicon'" [attr.aria-hidden]="true">
1437
1811
  <ng-container *ngTemplateOutlet="removeTokenIconTemplate"></ng-container>
1438
1812
  </span>
1439
1813
  </ng-container>
1440
1814
  </div>
1441
- <ng-container *ngIf="!value || value.length === 0">{{ placeholder || defaultLabel || 'empty' }}</ng-container>
1815
+ <ng-container *ngIf="!modelValue() || modelValue().length === 0">{{ placeholder || defaultLabel || 'empty' }}</ng-container>
1442
1816
  </ng-container>
1443
1817
  </ng-container>
1444
- <ng-container *ngTemplateOutlet="selectedItemsTemplate; context: { $implicit: value, removeChip: removeChip.bind(this) }"></ng-container>
1818
+ <ng-container *ngTemplateOutlet="selectedItemsTemplate; context: { $implicit: modelValue(), removeChip: removeOption.bind(this) }"></ng-container>
1445
1819
  </div>
1446
- <ng-container *ngIf="value != null && filled && !disabled && showClear">
1447
- <TimesIcon *ngIf="!clearIconTemplate" [styleClass]="'p-multiselect-clear-icon'" (click)="clear($event)" />
1448
- <span *ngIf="clearIconTemplate" class="p-multiselect-clear-icon" (click)="clear($event)">
1820
+ <ng-container *ngIf="modelValue() != null && filled && !disabled && showClear">
1821
+ <TimesIcon *ngIf="!clearIconTemplate" [styleClass]="'p-multiselect-clear-icon'" (click)="clear($event)" [attr.data-pc-section]="'clearicon'" [attr.aria-hidden]="true" />
1822
+ <span *ngIf="clearIconTemplate" class="p-multiselect-clear-icon" (click)="clear($event)" [attr.data-pc-section]="'clearicon'" [attr.aria-hidden]="true">
1449
1823
  <ng-template *ngTemplateOutlet="clearIconTemplate"></ng-template>
1450
1824
  </span>
1451
1825
  </ng-container>
1452
1826
  </div>
1453
- <div [ngClass]="{ 'p-multiselect-trigger': true }">
1827
+ <div class="p-multiselect-trigger">
1454
1828
  <ng-container *ngIf="!dropdownIconTemplate">
1455
- <span *ngIf="dropdownIcon" class="p-multiselect-trigger-icon" [ngClass]="dropdownIcon"></span>
1456
- <ChevronDownIcon *ngIf="!dropdownIcon" [styleClass]="'p-multiselect-trigger-icon'" />
1829
+ <span *ngIf="dropdownIcon" class="p-multiselect-trigger-icon" [ngClass]="dropdownIcon" [attr.data-pc-section]="'triggericon'" [attr.aria-hidden]="true"></span>
1830
+ <ChevronDownIcon *ngIf="!dropdownIcon" [styleClass]="'p-multiselect-trigger-icon'" [attr.data-pc-section]="'triggericon'" [attr.aria-hidden]="true" />
1457
1831
  </ng-container>
1458
- <span *ngIf="dropdownIconTemplate" class="p-multiselect-trigger-icon">
1832
+ <span *ngIf="dropdownIconTemplate" class="p-multiselect-trigger-icon" [attr.data-pc-section]="'triggericon'" [attr.aria-hidden]="true">
1459
1833
  <ng-template *ngTemplateOutlet="dropdownIconTemplate"></ng-template>
1460
1834
  </span>
1461
1835
  </div>
@@ -1473,7 +1847,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
1473
1847
  (onHide)="hide()"
1474
1848
  >
1475
1849
  <ng-template pTemplate="content">
1476
- <div [ngClass]="['p-multiselect-panel p-component']" [ngStyle]="panelStyle" [class]="panelStyleClass" (keydown)="onKeydown($event)">
1850
+ <div [ngClass]="'p-multiselect-panel p-component'" [ngStyle]="panelStyle" [class]="panelStyleClass">
1851
+ <span
1852
+ #firstHiddenFocusableEl
1853
+ role="presentation"
1854
+ [attr.aria-hidden]="'true'"
1855
+ class="p-hidden-accessible p-hidden-focusable"
1856
+ [attr.tabindex]="0"
1857
+ (focus)="onFirstHiddenFocus($event)"
1858
+ [attr.data-p-hidden-accessible]="true"
1859
+ [attr.data-p-hidden-focusable]="true"
1860
+ >
1861
+ </span>
1477
1862
  <div class="p-multiselect-header" *ngIf="showHeader">
1478
1863
  <ng-content select="p-header"></ng-content>
1479
1864
  <ng-container *ngTemplateOutlet="headerTemplate"></ng-container>
@@ -1481,28 +1866,29 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
1481
1866
  <ng-container *ngTemplateOutlet="filterTemplate; context: { options: filterOptions }"></ng-container>
1482
1867
  </ng-container>
1483
1868
  <ng-template #builtInFilterElement>
1484
- <div class="p-checkbox p-component" *ngIf="showToggleAll && !selectionLimit" [ngClass]="{ 'p-checkbox-disabled': disabled || toggleAllDisabled }">
1485
- <div class="p-hidden-accessible">
1869
+ <div
1870
+ class="p-checkbox p-component"
1871
+ *ngIf="showToggleAll && !selectionLimit"
1872
+ [ngClass]="{ 'p-checkbox-disabled': disabled || toggleAllDisabled }"
1873
+ (click)="onToggleAll($event)"
1874
+ (keydown)="onHeaderCheckboxKeyDown($event)"
1875
+ >
1876
+ <div class="p-hidden-accessible" [attr.data-p-hidden-accessible]="true">
1486
1877
  <input
1878
+ #headerCheckbox
1487
1879
  type="checkbox"
1488
- readonly="readonly"
1489
- [checked]="allChecked"
1880
+ [readonly]="readonly"
1881
+ [attr.checked]="allSelected()"
1490
1882
  (focus)="onHeaderCheckboxFocus()"
1491
1883
  (blur)="onHeaderCheckboxBlur()"
1492
- (keydown.space)="toggleAll($event)"
1493
1884
  [disabled]="disabled || toggleAllDisabled"
1885
+ [attr.aria-label]="toggleAllAriaLabel"
1494
1886
  />
1495
1887
  </div>
1496
- <div
1497
- class="p-checkbox-box"
1498
- role="checkbox"
1499
- [attr.aria-checked]="allChecked"
1500
- [ngClass]="{ 'p-highlight': allChecked, 'p-focus': headerCheckboxFocus, 'p-disabled': disabled || toggleAllDisabled }"
1501
- (click)="toggleAll($event)"
1502
- >
1503
- <ng-container *ngIf="allChecked">
1504
- <CheckIcon [styleClass]="'p-checkbox-icon'" *ngIf="!checkIconTemplate" />
1505
- <span *ngIf="checkIconTemplate" class="p-checkbox-icon">
1888
+ <div class="p-checkbox-box" role="checkbox" [attr.aria-checked]="allSelected()" [ngClass]="{ 'p-highlight': allSelected(), 'p-focus': headerCheckboxFocus, 'p-disabled': disabled || toggleAllDisabled }">
1889
+ <ng-container *ngIf="allSelected()">
1890
+ <CheckIcon [styleClass]="'p-checkbox-icon'" *ngIf="!checkIconTemplate" [attr.aria-hidden]="true" />
1891
+ <span *ngIf="checkIconTemplate" class="p-checkbox-icon" [attr.aria-hidden]="true">
1506
1892
  <ng-template *ngTemplateOutlet="checkIconTemplate"></ng-template>
1507
1893
  </span>
1508
1894
  </ng-container>
@@ -1513,9 +1899,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
1513
1899
  #filterInput
1514
1900
  type="text"
1515
1901
  [attr.autocomplete]="autocomplete"
1516
- role="textbox"
1517
- [value]="filterValue || ''"
1902
+ [attr.placeholder]="filterPlaceHolder"
1903
+ role="searchbox"
1904
+ [attr.aria-owns]="id + '_list'"
1905
+ [attr.aria-activedescendant]="focusedOptionId"
1906
+ [value]="_filterValue() || ''"
1518
1907
  (input)="onFilterInputChange($event)"
1908
+ (keydown)="onFilterKeyDown($event)"
1909
+ (blur)="onFilterBlur($event)"
1519
1910
  class="p-multiselect-filter p-inputtext p-component"
1520
1911
  [disabled]="disabled"
1521
1912
  [attr.placeholder]="filterPlaceHolder"
@@ -1539,7 +1930,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
1539
1930
  <p-scroller
1540
1931
  *ngIf="virtualScroll"
1541
1932
  #scroller
1542
- [items]="optionsToRender"
1933
+ [items]="visibleOptions()"
1543
1934
  [style]="{ height: scrollHeight }"
1544
1935
  [itemSize]="virtualScrollItemSize || _itemSize"
1545
1936
  [autoSize]="true"
@@ -1558,38 +1949,37 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
1558
1949
  </ng-container>
1559
1950
  </p-scroller>
1560
1951
  <ng-container *ngIf="!virtualScroll">
1561
- <ng-container *ngTemplateOutlet="buildInItems; context: { $implicit: optionsToRender, options: {} }"></ng-container>
1952
+ <ng-container *ngTemplateOutlet="buildInItems; context: { $implicit: visibleOptions(), options: {} }"></ng-container>
1562
1953
  </ng-container>
1563
1954
 
1564
1955
  <ng-template #buildInItems let-items let-scrollerOptions="options">
1565
1956
  <ul #items class="p-multiselect-items p-component" [ngClass]="scrollerOptions.contentStyleClass" [style]="scrollerOptions.contentStyle" role="listbox" aria-multiselectable="true">
1566
- <ng-container *ngIf="group">
1567
- <ng-template ngFor let-optgroup [ngForOf]="items">
1568
- <li class="p-multiselect-item-group" [ngStyle]="{ height: scrollerOptions.itemSize + 'px' }">
1569
- <span *ngIf="!groupTemplate">{{ getOptionGroupLabel(optgroup) || 'empty' }}</span>
1570
- <ng-container *ngTemplateOutlet="groupTemplate; context: { $implicit: optgroup }"></ng-container>
1957
+ <ng-template ngFor let-option [ngForOf]="items" let-i="index">
1958
+ <ng-container *ngIf="option.group">
1959
+ <li [attr.id]="id + '_' + getOptionIndex(i, scrollerOptions)" class="p-multiselect-item-group" [ngStyle]="{ height: scrollerOptions.itemSize + 'px' }" role="option">
1960
+ <span *ngIf="!groupTemplate">{{ getOptionGroupLabel(option.optionGroup) }}</span>
1961
+ <ng-container *ngTemplateOutlet="groupTemplate; context: { $implicit: option.optionGroup }"></ng-container>
1571
1962
  </li>
1572
- <ng-container *ngTemplateOutlet="itemslist; context: { $implicit: getOptionGroupChildren(optgroup) }"></ng-container>
1573
- </ng-template>
1574
- </ng-container>
1575
- <ng-container *ngIf="!group">
1576
- <ng-container *ngTemplateOutlet="itemslist; context: { $implicit: items }"></ng-container>
1577
- </ng-container>
1578
- <ng-template #itemslist let-optionsToDisplay let-selectedOption="selectedOption">
1579
- <ng-template ngFor let-option let-i="index" [ngForOf]="optionsToDisplay">
1963
+ </ng-container>
1964
+ <ng-container *ngIf="!option.group">
1580
1965
  <p-multiSelectItem
1966
+ [id]="id + '_' + getOptionIndex(i, scrollerOptions)"
1581
1967
  [option]="option"
1582
1968
  [selected]="isSelected(option)"
1583
1969
  [label]="getOptionLabel(option)"
1584
1970
  [disabled]="isOptionDisabled(option)"
1585
- (onClick)="onOptionClick($event)"
1586
- (onKeydown)="onOptionKeydown($event)"
1587
1971
  [template]="itemTemplate"
1588
1972
  [checkIconTemplate]="checkIconTemplate"
1589
1973
  [itemSize]="scrollerOptions.itemSize"
1974
+ [focused]="focusedOptionIndex() === getOptionIndex(i, scrollerOptions)"
1975
+ [ariaPosInset]="getAriaPosInset(getOptionIndex(i, scrollerOptions))"
1976
+ [ariaSetSize]="ariaSetSize"
1977
+ (onClick)="onOptionSelect($event, false, getOptionIndex(i, scrollerOptions))"
1978
+ (onMouseEnter)="onOptionMouseEnter($event, getOptionIndex(i, scrollerOptions))"
1590
1979
  ></p-multiSelectItem>
1591
- </ng-template>
1980
+ </ng-container>
1592
1981
  </ng-template>
1982
+
1593
1983
  <li *ngIf="hasFilter() && isEmpty()" class="p-multiselect-empty-message" [ngStyle]="{ height: scrollerOptions.itemSize + 'px' }">
1594
1984
  <ng-container *ngIf="!emptyFilterTemplate && !emptyTemplate; else emptyFilter">
1595
1985
  {{ emptyFilterMessageLabel }}
@@ -1609,6 +1999,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
1609
1999
  <ng-content select="p-footer"></ng-content>
1610
2000
  <ng-container *ngTemplateOutlet="footerTemplate"></ng-container>
1611
2001
  </div>
2002
+
2003
+ <span
2004
+ #lastHiddenFocusableEl
2005
+ role="presentation"
2006
+ [attr.aria-hidden]="true"
2007
+ class="p-hidden-accessible p-hidden-focusable"
2008
+ [attr.tabindex]="0"
2009
+ (focus)="onLastHiddenFocus($event)"
2010
+ [attr.data-p-hidden-accessible]="true"
2011
+ [attr.data-p-hidden-focusable]="true"
2012
+ ></span>
1612
2013
  </div>
1613
2014
  </ng-template>
1614
2015
  </p-overlay>
@@ -1616,10 +2017,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
1616
2017
  `, host: {
1617
2018
  class: 'p-element p-inputwrapper',
1618
2019
  '[class.p-inputwrapper-filled]': 'filled',
1619
- '[class.p-inputwrapper-focus]': 'focus || overlayVisible',
1620
- '[class.p-multiselect-clearable]': 'showClear && !disabled'
2020
+ '[class.p-inputwrapper-focus]': 'focused || overlayVisible'
1621
2021
  }, providers: [MULTISELECT_VALUE_ACCESSOR], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, styles: ["@layer primeng{.p-multiselect{display:inline-flex;cursor:pointer;position:relative;-webkit-user-select:none;user-select:none}.p-multiselect-trigger{display:flex;align-items:center;justify-content:center;flex-shrink:0}.p-multiselect-label-container{overflow:hidden;flex:1 1 auto;cursor:pointer;display:flex}.p-multiselect-label{display:block;white-space:nowrap;cursor:pointer;overflow:hidden;text-overflow:ellipsis}.p-multiselect-label-empty{overflow:hidden;visibility:hidden}.p-multiselect-token{cursor:default;display:inline-flex;align-items:center;flex:0 0 auto}.p-multiselect-token-icon{cursor:pointer}.p-multiselect-token-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100px}.p-multiselect-items-wrapper{overflow:auto}.p-multiselect-items{margin:0;padding:0;list-style-type:none}.p-multiselect-item{cursor:pointer;display:flex;align-items:center;font-weight:400;white-space:nowrap;position:relative;overflow:hidden}.p-multiselect-header{display:flex;align-items:center;justify-content:space-between}.p-multiselect-filter-container{position:relative;flex:1 1 auto}.p-multiselect-filter-icon{position:absolute;top:50%;margin-top:-.5rem}.p-multiselect-filter-container .p-inputtext{width:100%}.p-multiselect-close{display:flex;align-items:center;justify-content:center;flex-shrink:0;overflow:hidden;position:relative}.p-fluid .p-multiselect{display:flex}.p-multiselect-clear-icon{position:absolute;top:50%;margin-top:-.5rem;cursor:pointer}.p-multiselect-clearable{position:relative}}\n"] }]
1622
- }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.ChangeDetectorRef }, { type: i0.NgZone }, { type: i3.FilterService }, { type: i3.PrimeNGConfig }, { type: i3.OverlayService }]; }, propDecorators: { style: [{
2022
+ }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.ChangeDetectorRef }, { type: i0.NgZone }, { type: i3.FilterService }, { type: i3.PrimeNGConfig }, { type: i3.OverlayService }]; }, propDecorators: { id: [{
2023
+ type: Input
2024
+ }], ariaLabel: [{
2025
+ type: Input
2026
+ }], style: [{
1623
2027
  type: Input
1624
2028
  }], styleClass: [{
1625
2029
  type: Input
@@ -1651,14 +2055,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
1651
2055
  type: Input
1652
2056
  }], name: [{
1653
2057
  type: Input
1654
- }], label: [{
1655
- type: Input
1656
2058
  }], ariaLabelledBy: [{
1657
2059
  type: Input
1658
2060
  }], displaySelectedLabel: [{
1659
2061
  type: Input
1660
2062
  }], maxSelectedLabels: [{
1661
2063
  type: Input
2064
+ }], selectionLimit: [{
2065
+ type: Input
1662
2066
  }], selectedItemsLabel: [{
1663
2067
  type: Input
1664
2068
  }], showToggleAll: [{
@@ -1735,8 +2139,34 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
1735
2139
  type: Input
1736
2140
  }], itemSize: [{
1737
2141
  type: Input
1738
- }], selectionLimit: [{
2142
+ }], focusOnHover: [{
2143
+ type: Input
2144
+ }], filterFields: [{
2145
+ type: Input
2146
+ }], selectOnFocus: [{
2147
+ type: Input
2148
+ }], autoOptionFocus: [{
1739
2149
  type: Input
2150
+ }], onChange: [{
2151
+ type: Output
2152
+ }], onFilter: [{
2153
+ type: Output
2154
+ }], onFocus: [{
2155
+ type: Output
2156
+ }], onBlur: [{
2157
+ type: Output
2158
+ }], onClick: [{
2159
+ type: Output
2160
+ }], onClear: [{
2161
+ type: Output
2162
+ }], onPanelShow: [{
2163
+ type: Output
2164
+ }], onPanelHide: [{
2165
+ type: Output
2166
+ }], onLazyLoad: [{
2167
+ type: Output
2168
+ }], onRemove: [{
2169
+ type: Output
1740
2170
  }], containerViewChild: [{
1741
2171
  type: ViewChild,
1742
2172
  args: ['container']
@@ -1746,15 +2176,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
1746
2176
  }], filterInputChild: [{
1747
2177
  type: ViewChild,
1748
2178
  args: ['filterInput']
1749
- }], accessibleViewChild: [{
2179
+ }], focusInputViewChild: [{
1750
2180
  type: ViewChild,
1751
- args: ['in']
2181
+ args: ['focusInput']
1752
2182
  }], itemsViewChild: [{
1753
2183
  type: ViewChild,
1754
2184
  args: ['items']
1755
2185
  }], scroller: [{
1756
2186
  type: ViewChild,
1757
2187
  args: ['scroller']
2188
+ }], lastHiddenFocusableElementOnOverlay: [{
2189
+ type: ViewChild,
2190
+ args: ['lastHiddenFocusableEl']
2191
+ }], firstHiddenFocusableElementOnOverlay: [{
2192
+ type: ViewChild,
2193
+ args: ['firstHiddenFocusableEl']
2194
+ }], headerCheckboxViewChild: [{
2195
+ type: ViewChild,
2196
+ args: ['headerCheckbox']
1758
2197
  }], footerFacet: [{
1759
2198
  type: ContentChild,
1760
2199
  args: [Footer]
@@ -1764,26 +2203,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
1764
2203
  }], templates: [{
1765
2204
  type: ContentChildren,
1766
2205
  args: [PrimeTemplate]
1767
- }], onChange: [{
1768
- type: Output
1769
- }], onFilter: [{
1770
- type: Output
1771
- }], onFocus: [{
1772
- type: Output
1773
- }], onBlur: [{
1774
- type: Output
1775
- }], onClick: [{
1776
- type: Output
1777
- }], onClear: [{
1778
- type: Output
1779
- }], onPanelShow: [{
1780
- type: Output
1781
- }], onPanelHide: [{
1782
- type: Output
1783
- }], onLazyLoad: [{
1784
- type: Output
1785
- }], onRemove: [{
1786
- type: Output
1787
2206
  }] } });
1788
2207
  class MultiSelectModule {
1789
2208
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: MultiSelectModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });