@nanahoshi/mona-ui 0.24.4 → 0.24.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/README.md +3 -0
  2. package/fesm2022/nanahoshi-mona-ui-auto-complete.mjs +95 -70
  3. package/fesm2022/nanahoshi-mona-ui-calendar.mjs +196 -137
  4. package/fesm2022/nanahoshi-mona-ui-combo-box.mjs +136 -89
  5. package/fesm2022/nanahoshi-mona-ui-date-input.mjs +164 -3
  6. package/fesm2022/nanahoshi-mona-ui-date-picker.mjs +124 -140
  7. package/fesm2022/nanahoshi-mona-ui-datetime-picker.mjs +205 -202
  8. package/fesm2022/nanahoshi-mona-ui-dropdown-list.mjs +108 -56
  9. package/fesm2022/nanahoshi-mona-ui-dropdowns.mjs +68 -59
  10. package/fesm2022/nanahoshi-mona-ui-editor.mjs +3 -3
  11. package/fesm2022/nanahoshi-mona-ui-filter.mjs +1 -1
  12. package/fesm2022/{nanahoshi-mona-ui-grid-grid-footer-row.component-DLOPRuFv.mjs → nanahoshi-mona-ui-grid-grid-footer-row.component-CD_ODHpU.mjs} +2 -2
  13. package/fesm2022/{nanahoshi-mona-ui-grid-grid-list.component-Dw5U9H0a.mjs → nanahoshi-mona-ui-grid-grid-list.component-0jN7I1jo.mjs} +4 -4
  14. package/fesm2022/{nanahoshi-mona-ui-grid-grid-row.component-D1kyAzD8.mjs → nanahoshi-mona-ui-grid-grid-row.component-BI_iE7pl.mjs} +3 -3
  15. package/fesm2022/{nanahoshi-mona-ui-grid-grid-virtual-list.component-ECK1_smx.mjs → nanahoshi-mona-ui-grid-grid-virtual-list.component-Sa1aAtJ-.mjs} +4 -4
  16. package/fesm2022/{nanahoshi-mona-ui-grid-nanahoshi-mona-ui-grid-D4lUDbfx.mjs → nanahoshi-mona-ui-grid-nanahoshi-mona-ui-grid-BvUM9nPt.mjs} +8 -8
  17. package/fesm2022/nanahoshi-mona-ui-grid.mjs +1 -1
  18. package/fesm2022/nanahoshi-mona-ui-i18n-icu.mjs +2 -1
  19. package/fesm2022/nanahoshi-mona-ui-internal-indicator-icon.mjs +2 -2
  20. package/fesm2022/nanahoshi-mona-ui-internal.mjs +4 -2
  21. package/fesm2022/nanahoshi-mona-ui-locales-ar-sa.mjs +2 -1
  22. package/fesm2022/nanahoshi-mona-ui-locales-de-de.mjs +4 -1
  23. package/fesm2022/nanahoshi-mona-ui-locales-es-es.mjs +4 -1
  24. package/fesm2022/nanahoshi-mona-ui-locales-fr-fr.mjs +4 -1
  25. package/fesm2022/nanahoshi-mona-ui-locales-id-id.mjs +2 -1
  26. package/fesm2022/nanahoshi-mona-ui-locales-it-it.mjs +2 -1
  27. package/fesm2022/nanahoshi-mona-ui-locales-ja-jp.mjs +2 -1
  28. package/fesm2022/nanahoshi-mona-ui-locales-ko-kr.mjs +2 -1
  29. package/fesm2022/nanahoshi-mona-ui-locales-pt-br.mjs +2 -1
  30. package/fesm2022/nanahoshi-mona-ui-locales-ru-ru.mjs +2 -1
  31. package/fesm2022/nanahoshi-mona-ui-locales-tr-tr.mjs +2 -1
  32. package/fesm2022/nanahoshi-mona-ui-locales-zh-cn.mjs +2 -1
  33. package/fesm2022/nanahoshi-mona-ui-locales-zh-tw.mjs +2 -1
  34. package/fesm2022/nanahoshi-mona-ui-multi-select.mjs +118 -66
  35. package/fesm2022/nanahoshi-mona-ui-numeric-text-box.mjs +195 -122
  36. package/fesm2022/nanahoshi-mona-ui-pager.mjs +1 -1
  37. package/fesm2022/nanahoshi-mona-ui-time-picker.mjs +149 -167
  38. package/fesm2022/nanahoshi-mona-ui-time-selector.mjs +182 -137
  39. package/i18n/catalogs/en-US.messages.json +2 -1
  40. package/locales/ar-sa/ar-sa.messages.json +2 -1
  41. package/locales/de-de/de-de.messages.json +2 -1
  42. package/locales/es-es/es-es.messages.json +2 -1
  43. package/locales/fr-fr/fr-fr.messages.json +2 -1
  44. package/locales/id-id/id-id.messages.json +2 -1
  45. package/locales/it-it/it-it.messages.json +2 -1
  46. package/locales/ja-jp/ja-jp.messages.json +2 -1
  47. package/locales/ko-kr/ko-kr.messages.json +2 -1
  48. package/locales/pt-br/pt-br.messages.json +2 -1
  49. package/locales/ru-ru/ru-ru.messages.json +2 -1
  50. package/locales/tr-tr/tr-tr.messages.json +2 -1
  51. package/locales/zh-cn/zh-cn.messages.json +2 -1
  52. package/locales/zh-tw/zh-tw.messages.json +2 -1
  53. package/package.json +2 -2
  54. package/types/nanahoshi-mona-ui-auto-complete.d.ts +34 -20
  55. package/types/nanahoshi-mona-ui-calendar.d.ts +30 -11
  56. package/types/nanahoshi-mona-ui-combo-box.d.ts +42 -23
  57. package/types/nanahoshi-mona-ui-date-input.d.ts +74 -3
  58. package/types/nanahoshi-mona-ui-date-picker.d.ts +61 -33
  59. package/types/nanahoshi-mona-ui-datetime-picker.d.ts +79 -38
  60. package/types/nanahoshi-mona-ui-dropdown-list.d.ts +29 -15
  61. package/types/nanahoshi-mona-ui-dropdowns.d.ts +30 -19
  62. package/types/nanahoshi-mona-ui-i18n.d.ts +1 -0
  63. package/types/nanahoshi-mona-ui-internal.d.ts +3 -1
  64. package/types/nanahoshi-mona-ui-locales-ar-sa.d.ts +1 -0
  65. package/types/nanahoshi-mona-ui-locales-de-de.d.ts +1 -0
  66. package/types/nanahoshi-mona-ui-locales-es-es.d.ts +1 -0
  67. package/types/nanahoshi-mona-ui-locales-fr-fr.d.ts +1 -0
  68. package/types/nanahoshi-mona-ui-locales-id-id.d.ts +1 -0
  69. package/types/nanahoshi-mona-ui-locales-it-it.d.ts +1 -0
  70. package/types/nanahoshi-mona-ui-locales-ja-jp.d.ts +1 -0
  71. package/types/nanahoshi-mona-ui-locales-ko-kr.d.ts +1 -0
  72. package/types/nanahoshi-mona-ui-locales-pt-br.d.ts +1 -0
  73. package/types/nanahoshi-mona-ui-locales-ru-ru.d.ts +1 -0
  74. package/types/nanahoshi-mona-ui-locales-tr-tr.d.ts +1 -0
  75. package/types/nanahoshi-mona-ui-locales-zh-cn.d.ts +1 -0
  76. package/types/nanahoshi-mona-ui-locales-zh-tw.d.ts +1 -0
  77. package/types/nanahoshi-mona-ui-multi-select.d.ts +45 -21
  78. package/types/nanahoshi-mona-ui-numeric-text-box.d.ts +57 -16
  79. package/types/nanahoshi-mona-ui-time-picker.d.ts +72 -42
  80. package/types/nanahoshi-mona-ui-time-selector.d.ts +78 -46
@@ -1,11 +1,11 @@
1
1
  import { NgTemplateOutlet } from '@angular/common';
2
2
  import * as i0 from '@angular/core';
3
- import { Directive, signal, Injectable, inject, DestroyRef, ElementRef, computed, contentChild, TemplateRef, viewChild, input, output, model, afterNextRender, effect, untracked, forwardRef, Component } from '@angular/core';
3
+ import { Directive, signal, Injectable, inject, DestroyRef, ElementRef, computed, contentChild, TemplateRef, viewChild, input, booleanAttribute, output, model, afterNextRender, effect, untracked, forwardRef, Component } from '@angular/core';
4
4
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
5
5
  import { none } from '@mirei/ts-collections';
6
- import { ChipComponent } from '@nanahoshi/mona-ui/chip';
6
+ import { CHIP_DEFAULT_MESSAGES, ChipComponent } from '@nanahoshi/mona-ui/chip';
7
7
  import * as i1 from '@nanahoshi/mona-ui/dropdowns';
8
- import { DropdownService, DropdownFooterTemplateDirective, DropdownGroupHeaderTemplateDirective, DropdownHeaderTemplateDirective, DropdownItemTemplateDirective, dropdownPopupThemeVariants, DropdownNoDataTemplateDirective, DropdownPrefixTemplateDirective, DropdownLiveRegionDirective, DropdownDataInputToken, DROPDOWN_POPUP_INPUT_TOKEN, DropdownDataHandlerDirective, DropdownListPopupHandlerDirective } from '@nanahoshi/mona-ui/dropdowns';
8
+ import { DropdownService, DropdownFooterTemplateDirective, DropdownGroupHeaderTemplateDirective, DropdownHeaderTemplateDirective, DropdownItemTemplateDirective, dropdownPopupThemeVariants, DropdownNoDataTemplateDirective, DropdownPrefixTemplateDirective, DROPDOWN_DATA_INPUT_TOKEN, DROPDOWN_POPUP_INPUT_TOKEN, DropdownDataHandlerDirective, DropdownListPopupHandlerDirective, DropdownLiveRegionDirective } from '@nanahoshi/mona-ui/dropdowns';
9
9
  import { formatNumber, MonaI18nService } from '@nanahoshi/mona-ui/i18n';
10
10
  import { themeControlSurfaceClasses, createElementControlId, restoreOverlayScroll, rxFromResize } from '@nanahoshi/mona-ui/internal';
11
11
  import { IndicatorIconComponent } from '@nanahoshi/mona-ui/internal/indicator-icon';
@@ -32,7 +32,8 @@ function localizeNumber(value, options) {
32
32
  }
33
33
  const MULTI_SELECT_DEFAULT_MESSAGES = {
34
34
  clear: "Clear",
35
- itemsCount: (count) => count === 1 ? `+ ${localizeNumber(count)} item` : `+ ${localizeNumber(count)} items`
35
+ itemsCount: (count) => count === 1 ? `+ ${localizeNumber(count)} item` : `+ ${localizeNumber(count)} items`,
36
+ removeMoreItems: (count) => count === 1 ? `Remove ${localizeNumber(count)} more item` : `Remove ${localizeNumber(count)} more items`
36
37
  };
37
38
 
38
39
  class MultiSelectService {
@@ -154,6 +155,15 @@ class MultiSelectComponent {
154
155
  return twMerge(variantClass, userClass);
155
156
  }, /* @ts-ignore */
156
157
  ...(ngDevMode ? [{ debugName: "baseClass" }] : /* istanbul ignore next */ []));
158
+ this.chipMessages = this.#i18n.componentMessages("chip", CHIP_DEFAULT_MESSAGES);
159
+ this.clearButtonVisible = computed(() => this.showClearButton() &&
160
+ this.selectedListItems().any() &&
161
+ !this.loading() &&
162
+ !this.disabled() &&
163
+ !this.readonly(), /* @ts-ignore */
164
+ ...(ngDevMode ? [{ debugName: "clearButtonVisible" }] : /* istanbul ignore next */ []));
165
+ this.effectiveAriaLabel = computed(() => this.ariaLabel() || (this.ariaLabelledBy() ? "" : this.placeholder()), /* @ts-ignore */
166
+ ...(ngDevMode ? [{ debugName: "effectiveAriaLabel" }] : /* istanbul ignore next */ []));
157
167
  this.expanded = computed(() => this.#dropdownService.popupRef() !== null, /* @ts-ignore */
158
168
  ...(ngDevMode ? [{ debugName: "expanded" }] : /* istanbul ignore next */ []));
159
169
  this.footerTemplate = contentChild(DropdownFooterTemplateDirective, { ...(ngDevMode ? { debugName: "footerTemplate" } : /* istanbul ignore next */ {}), read: TemplateRef });
@@ -178,7 +188,9 @@ class MultiSelectComponent {
178
188
  const size = this.size();
179
189
  const userClass = this.popupClass();
180
190
  const variantClass = dropdownPopupThemeVariants({ rounded, size });
181
- return twMerge(variantClass, userClass);
191
+ // With a popupHeight, the overlay sets the limit; the default max-h-64 would cut a taller popup short.
192
+ const heightClass = this.popupHeight() ? "max-h-none" : "";
193
+ return twMerge(variantClass, heightClass, userClass);
182
194
  }, /* @ts-ignore */
183
195
  ...(ngDevMode ? [{ debugName: "listPopupClass" }] : /* istanbul ignore next */ []));
184
196
  this.messages = this.#i18n.componentMessages("multiSelect", MULTI_SELECT_DEFAULT_MESSAGES);
@@ -216,7 +228,13 @@ class MultiSelectComponent {
216
228
  }, /* @ts-ignore */
217
229
  ...(ngDevMode ? [{ debugName: "visibleTagCount" }] : /* istanbul ignore next */ []));
218
230
  /**
219
- * @description Sets the aria-label attribute of the multi select component.
231
+ * @description ID of an element that describes the multi select, such as help text or an error message.
232
+ * @default ""
233
+ */
234
+ this.ariaDescribedBy = input("", { ...(ngDevMode ? { debugName: "ariaDescribedBy" } : /* istanbul ignore next */ {}), alias: "aria-describedby" });
235
+ /**
236
+ * @description Accessible name for the multi select. Describe what it represents.
237
+ * Falls back to {@link placeholder} when neither this nor {@link ariaLabelledBy} is set.
220
238
  * @default ""
221
239
  */
222
240
  this.ariaLabel = input("", { ...(ngDevMode ? { debugName: "ariaLabel" } : /* istanbul ignore next */ {}), alias: "aria-label" });
@@ -229,17 +247,16 @@ class MultiSelectComponent {
229
247
  * @description Closes the popup automatically after an item is selected or deselected.
230
248
  * @default false
231
249
  */
232
- this.autoClose = input(false, /* @ts-ignore */
233
- ...(ngDevMode ? [{ debugName: "autoClose" }] : /* istanbul ignore next */ []));
250
+ this.autoClose = input(false, { ...(ngDevMode ? { debugName: "autoClose" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
234
251
  /**
235
252
  * @description Renders a checkbox next to each item in the popup list to indicate its selected state.
236
253
  * @default false
237
254
  */
238
- this.checkboxes = input(false, /* @ts-ignore */
239
- ...(ngDevMode ? [{ debugName: "checkboxes" }] : /* istanbul ignore next */ []));
255
+ this.checkboxes = input(false, { ...(ngDevMode ? { debugName: "checkboxes" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
240
256
  /**
241
257
  * @description Emits when the popup is about to close. This event is preventable.
242
258
  */
259
+ // eslint-disable-next-line @angular-eslint/no-output-native -- renaming the output would break existing (close) bindings
243
260
  this.close = output();
244
261
  /**
245
262
  * @description Emits after the popup is closed.
@@ -255,26 +272,24 @@ class MultiSelectComponent {
255
272
  * @description Disables the component, preventing the popup from opening and blocking tag removal.
256
273
  * @default false
257
274
  */
258
- this.disabled = model(false, /* @ts-ignore */
259
- ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
275
+ this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
260
276
  /**
261
277
  * @description Marks the multi select as invalid. When bound to a signal form field via `[formField]`,
262
278
  * this is written by the `FormField` directive.
263
279
  * @default false
264
280
  */
265
- this.invalid = input(false, /* @ts-ignore */
266
- ...(ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []));
281
+ this.invalid = input(false, { ...(ngDevMode ? { debugName: "invalid" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
267
282
  /**
268
283
  * @description A predicate function or the name of the field that determines whether an item is disabled.
269
284
  */
270
285
  this.itemDisabled = input(/* @ts-ignore */
271
286
  ...(ngDevMode ? [undefined, { debugName: "itemDisabled" }] : /* istanbul ignore next */ []));
272
287
  /**
273
- * @description Sets the loading state of the multi select component.
288
+ * @description Shows a loading indicator, in place of the clear button, and marks the field busy. It doesn't
289
+ * block interaction: the field stays usable while data loads.
274
290
  * @default false
275
291
  */
276
- this.loading = input(false, /* @ts-ignore */
277
- ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
292
+ this.loading = input(false, { ...(ngDevMode ? { debugName: "loading" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
278
293
  /**
279
294
  * @description Emits when the popup is about to open. This event is preventable.
280
295
  */
@@ -283,6 +298,13 @@ class MultiSelectComponent {
283
298
  * @description Emits after the popup is opened.
284
299
  */
285
300
  this.opened = output();
301
+ /**
302
+ * @description Text shown when nothing is selected. It also names the multi select when neither {@link ariaLabel}
303
+ * nor {@link ariaLabelledBy} is set.
304
+ * @default ""
305
+ */
306
+ this.placeholder = input("", /* @ts-ignore */
307
+ ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
286
308
  /**
287
309
  * @description Sets the class of the popup element.
288
310
  * @default ""
@@ -290,7 +312,8 @@ class MultiSelectComponent {
290
312
  this.popupClass = input("", /* @ts-ignore */
291
313
  ...(ngDevMode ? [{ debugName: "popupClass" }] : /* istanbul ignore next */ []));
292
314
  /**
293
- * @description Sets the height of the popup element.
315
+ * @description Maximum height of the popup, in pixels or as a CSS length. Shorter lists shrink to fit. When
316
+ * unset, the popup is at most 200 pixels tall.
294
317
  * @default null
295
318
  */
296
319
  this.popupHeight = input(null, /* @ts-ignore */
@@ -305,14 +328,12 @@ class MultiSelectComponent {
305
328
  * @description Sets the readonly state of the multi select component.
306
329
  * @default false
307
330
  */
308
- this.readonly = input(false, /* @ts-ignore */
309
- ...(ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []));
331
+ this.readonly = input(false, { ...(ngDevMode ? { debugName: "readonly" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
310
332
  /**
311
333
  * @description Sets the required state of the multi select component.
312
334
  * @default false
313
335
  */
314
- this.required = input(false, /* @ts-ignore */
315
- ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
336
+ this.required = input(false, { ...(ngDevMode ? { debugName: "required" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
316
337
  /**
317
338
  * @description Sets the border radius of the multi select component.
318
339
  * @default "medium"
@@ -323,8 +344,7 @@ class MultiSelectComponent {
323
344
  * @description Renders a button that clears all selected items when at least one item is selected.
324
345
  * @default false
325
346
  */
326
- this.showClearButton = input(false, /* @ts-ignore */
327
- ...(ngDevMode ? [{ debugName: "showClearButton" }] : /* istanbul ignore next */ []));
347
+ this.showClearButton = input(false, { ...(ngDevMode ? { debugName: "showClearButton" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
328
348
  /**
329
349
  * @description The size of the multi select component.
330
350
  * @default "medium"
@@ -340,8 +360,8 @@ class MultiSelectComponent {
340
360
  this.textField = input(/* @ts-ignore */
341
361
  ...(ngDevMode ? [undefined, { debugName: "textField" }] : /* istanbul ignore next */ []));
342
362
  /**
343
- * @description Emitted when the multi select is interacted with on blur, selection, remove, or clear.
344
- * The `FormField` directive listens to this to mark the field as touched.
363
+ * @description Emitted when focus leaves the multi select. Moving between it, its chips, its clear button and its
364
+ * popup doesn't count. The `FormField` directive listens to this to mark the field as touched.
345
365
  */
346
366
  this.touch = output();
347
367
  /**
@@ -349,8 +369,7 @@ class MultiSelectComponent {
349
369
  * this is written by the `FormField` directive.
350
370
  * @default false
351
371
  */
352
- this.touched = input(false, /* @ts-ignore */
353
- ...(ngDevMode ? [{ debugName: "touched" }] : /* istanbul ignore next */ []));
372
+ this.touched = input(false, { ...(ngDevMode ? { debugName: "touched" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
354
373
  /**
355
374
  * @description Additional CSS classes merged onto the host element via `tailwind-merge`.
356
375
  * @default ""
@@ -385,8 +404,7 @@ class MultiSelectComponent {
385
404
  *
386
405
  * @default false
387
406
  */
388
- this.valuePrimitive = input(false, /* @ts-ignore */
389
- ...(ngDevMode ? [{ debugName: "valuePrimitive" }] : /* istanbul ignore next */ []));
407
+ this.valuePrimitive = input(false, { ...(ngDevMode ? { debugName: "valuePrimitive" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
390
408
  afterNextRender({
391
409
  read: () => {
392
410
  this.initialize();
@@ -412,14 +430,25 @@ class MultiSelectComponent {
412
430
  untracked(() => this.#listService.setSelectableOptions({ checkboxes: checkboxVisible }));
413
431
  });
414
432
  }
415
- focus() {
416
- this.#hostElementRef.nativeElement.focus();
433
+ /**
434
+ * @description Moves focus to the multi select.
435
+ * @param options Passed to `HTMLElement.focus()`, for example `{ preventScroll: true }`.
436
+ */
437
+ focus(options) {
438
+ this.#hostElementRef.nativeElement.focus(options);
417
439
  }
418
- onBlur(event) {
419
- const popupElement = this.#dropdownService.popupRef()?.overlayRef.overlayElement;
420
- if (popupElement && event?.relatedTarget instanceof Node && popupElement.contains(event.relatedTarget)) {
440
+ onFocusOut(event) {
441
+ // Removing a focused dropdown from the page fires focusout after it is destroyed.
442
+ if (this.#destroyRef.destroyed) {
421
443
  return;
422
444
  }
445
+ const nextTarget = event.relatedTarget;
446
+ if (nextTarget instanceof Node) {
447
+ const popupElement = this.#dropdownService.popupRef()?.overlayRef.overlayElement;
448
+ if (this.#hostElementRef.nativeElement.contains(nextTarget) || popupElement?.contains(nextTarget)) {
449
+ return;
450
+ }
451
+ }
423
452
  this.touch.emit();
424
453
  }
425
454
  onItemSelect() {
@@ -457,7 +486,9 @@ class MultiSelectComponent {
457
486
  this.focus();
458
487
  }
459
488
  onValueClear(event) {
460
- if (this.readonly() || (event instanceof KeyboardEvent && event.key !== "Enter" && event.key !== " ")) {
489
+ if (this.disabled() ||
490
+ this.readonly() ||
491
+ (event instanceof KeyboardEvent && event.key !== "Enter" && event.key !== " ")) {
461
492
  return;
462
493
  }
463
494
  event.preventDefault();
@@ -479,21 +510,7 @@ class MultiSelectComponent {
479
510
  this.#dropdownService.triggerPopupOpen$.next({});
480
511
  return;
481
512
  }
482
- const highlightedItem = this.#listService.highlightedItem();
483
- if (!highlightedItem) {
484
- return;
485
- }
486
- const selected = this.#listService.isSelected(highlightedItem);
487
- if (selected) {
488
- this.#listService.deselectItems([highlightedItem]);
489
- }
490
- else {
491
- this.#listService.selectItem(highlightedItem);
492
- }
493
- this.updateValue(this.getSelectedControlValues());
494
- if (this.autoClose()) {
495
- this.#popupRef()?.close();
496
- }
513
+ this.toggleHighlightedItem();
497
514
  }
498
515
  handlePopupPositionUpdate() {
499
516
  const popupRef = this.#popupRef();
@@ -529,9 +546,30 @@ class MultiSelectComponent {
529
546
  .pipe(takeUntilDestroyed(this.#destroyRef))
530
547
  .subscribe(() => this.handlePopupPositionUpdate());
531
548
  }
549
+ setPopupCloseSubscription() {
550
+ this.#dropdownService.popupCloseComplete$.pipe(takeUntilDestroyed(this.#destroyRef)).subscribe(() => {
551
+ if (!this.#dropdownService.focusCanReturn() && !this.#destroyRef.destroyed) {
552
+ // Focus left from inside the popup (its filter box), so the host never saw a focusout.
553
+ this.touch.emit();
554
+ }
555
+ });
556
+ }
557
+ setSpaceKeySubscription() {
558
+ // While the popup is open, Space toggles the highlighted option, as Enter does. While it is closed, the shared
559
+ // handler opens the popup.
560
+ this.#dropdownService.beforeKeydown$
561
+ .pipe(takeUntilDestroyed(this.#destroyRef), filter(e => e.originalEvent?.key === " " && this.#popupRef() != null))
562
+ .subscribe(event => {
563
+ event.preventDefault();
564
+ event.originalEvent?.preventDefault();
565
+ this.toggleHighlightedItem();
566
+ });
567
+ }
532
568
  setSubscriptions() {
533
569
  this.setBackspaceKeySubscription();
534
570
  this.setEnterKeySubscription();
571
+ this.setPopupCloseSubscription();
572
+ this.setSpaceKeySubscription();
535
573
  }
536
574
  synchronizeSelection(value) {
537
575
  if (this.valuePrimitive()) {
@@ -541,19 +579,33 @@ class MultiSelectComponent {
541
579
  this.#listService.setSelectedDataItems(value);
542
580
  }
543
581
  }
544
- updateValue(value, notify = true) {
545
- this.value.set(value);
546
- if (notify) {
547
- this.touch.emit();
582
+ toggleHighlightedItem() {
583
+ const highlightedItem = this.#listService.highlightedItem();
584
+ if (!highlightedItem) {
585
+ return;
586
+ }
587
+ const selected = this.#listService.isSelected(highlightedItem);
588
+ if (selected) {
589
+ this.#listService.deselectItems([highlightedItem]);
590
+ }
591
+ else {
592
+ this.#listService.selectItem(highlightedItem);
548
593
  }
594
+ this.updateValue(this.getSelectedControlValues());
595
+ if (this.autoClose()) {
596
+ this.#popupRef()?.close();
597
+ }
598
+ }
599
+ updateValue(value) {
600
+ this.value.set(value);
549
601
  }
550
602
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: MultiSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
551
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.6", type: MultiSelectComponent, isStandalone: true, selector: "mona-multi-select", inputs: { ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelledBy: { classPropertyName: "ariaLabelledBy", publicName: "aria-labelledby", isSignal: true, isRequired: false, transformFunction: null }, autoClose: { classPropertyName: "autoClose", publicName: "autoClose", isSignal: true, isRequired: false, transformFunction: null }, checkboxes: { classPropertyName: "checkboxes", publicName: "checkboxes", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, itemDisabled: { classPropertyName: "itemDisabled", publicName: "itemDisabled", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, popupClass: { classPropertyName: "popupClass", publicName: "popupClass", isSignal: true, isRequired: false, transformFunction: null }, popupHeight: { classPropertyName: "popupHeight", publicName: "popupHeight", isSignal: true, isRequired: false, transformFunction: null }, popupWidth: { classPropertyName: "popupWidth", publicName: "popupWidth", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, rounded: { classPropertyName: "rounded", publicName: "rounded", isSignal: true, isRequired: false, transformFunction: null }, showClearButton: { classPropertyName: "showClearButton", publicName: "showClearButton", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, textField: { classPropertyName: "textField", publicName: "textField", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, valueField: { classPropertyName: "valueField", publicName: "valueField", isSignal: true, isRequired: false, transformFunction: null }, valuePrimitive: { classPropertyName: "valuePrimitive", publicName: "valuePrimitive", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { close: "close", closed: "closed", disabled: "disabledChange", open: "open", opened: "opened", touch: "touch", value: "valueChange" }, host: { listeners: { "blur": "onBlur()" }, properties: { "attr.aria-activedescendant": "activeDescendant()", "attr.aria-busy": "loading() ? 'true' : undefined", "attr.aria-controls": "listId", "attr.aria-disabled": "disabled() ? true : undefined", "attr.aria-expanded": "expanded()", "attr.aria-haspopup": "'listbox'", "attr.aria-invalid": "invalidState() ? true : undefined", "attr.aria-label": "ariaLabel()", "attr.aria-labelledby": "ariaLabelledBy()", "attr.aria-readonly": "readonly() ? true : undefined", "attr.aria-required": "required() ? true : undefined", "attr.data-disabled": "disabled() || null", "attr.data-invalid": "invalidState() || null", "attr.data-readonly": "readonly() || null", "attr.role": "'combobox'", "attr.tabindex": "disabled() ? null : 0", "class": "baseClass()" } }, providers: [
603
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.6", type: MultiSelectComponent, isStandalone: true, selector: "mona-multi-select", inputs: { ariaDescribedBy: { classPropertyName: "ariaDescribedBy", publicName: "aria-describedby", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelledBy: { classPropertyName: "ariaLabelledBy", publicName: "aria-labelledby", isSignal: true, isRequired: false, transformFunction: null }, autoClose: { classPropertyName: "autoClose", publicName: "autoClose", isSignal: true, isRequired: false, transformFunction: null }, checkboxes: { classPropertyName: "checkboxes", publicName: "checkboxes", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, itemDisabled: { classPropertyName: "itemDisabled", publicName: "itemDisabled", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, popupClass: { classPropertyName: "popupClass", publicName: "popupClass", isSignal: true, isRequired: false, transformFunction: null }, popupHeight: { classPropertyName: "popupHeight", publicName: "popupHeight", isSignal: true, isRequired: false, transformFunction: null }, popupWidth: { classPropertyName: "popupWidth", publicName: "popupWidth", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, rounded: { classPropertyName: "rounded", publicName: "rounded", isSignal: true, isRequired: false, transformFunction: null }, showClearButton: { classPropertyName: "showClearButton", publicName: "showClearButton", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, textField: { classPropertyName: "textField", publicName: "textField", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, valueField: { classPropertyName: "valueField", publicName: "valueField", isSignal: true, isRequired: false, transformFunction: null }, valuePrimitive: { classPropertyName: "valuePrimitive", publicName: "valuePrimitive", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { close: "close", closed: "closed", open: "open", opened: "opened", touch: "touch", value: "valueChange" }, host: { listeners: { "focusout": "onFocusOut($event)" }, properties: { "attr.aria-activedescendant": "activeDescendant()", "attr.aria-busy": "loading() ? 'true' : undefined", "attr.aria-controls": "listId", "attr.aria-describedby": "ariaDescribedBy() || null", "attr.aria-disabled": "disabled() ? true : undefined", "attr.aria-expanded": "expanded()", "attr.aria-haspopup": "'listbox'", "attr.aria-invalid": "invalidState() ? true : undefined", "attr.aria-label": "effectiveAriaLabel() || null", "attr.aria-labelledby": "ariaLabelledBy() || null", "attr.aria-readonly": "readonly() ? true : undefined", "attr.aria-required": "required() ? true : undefined", "attr.data-disabled": "disabled() || null", "attr.data-invalid": "invalidState() || null", "attr.data-readonly": "readonly() || null", "attr.role": "'combobox'", "attr.tabindex": "disabled() ? null : 0", "class": "baseClass()" } }, providers: [
552
604
  ListService,
553
605
  DropdownService,
554
606
  MultiSelectService,
555
607
  {
556
- provide: DropdownDataInputToken,
608
+ provide: DROPDOWN_DATA_INPUT_TOKEN,
557
609
  useExisting: forwardRef(() => MultiSelectComponent),
558
610
  multi: false
559
611
  },
@@ -562,7 +614,7 @@ class MultiSelectComponent {
562
614
  useExisting: forwardRef(() => MultiSelectComponent),
563
615
  multi: false
564
616
  }
565
- ], queries: [{ propertyName: "footerTemplate", first: true, predicate: DropdownFooterTemplateDirective, descendants: true, read: TemplateRef, isSignal: true }, { propertyName: "groupHeaderTemplate", first: true, predicate: DropdownGroupHeaderTemplateDirective, descendants: true, read: TemplateRef, isSignal: true }, { propertyName: "headerTemplate", first: true, predicate: DropdownHeaderTemplateDirective, descendants: true, read: TemplateRef, isSignal: true }, { propertyName: "itemTemplate", first: true, predicate: DropdownItemTemplateDirective, descendants: true, read: TemplateRef, isSignal: true }, { propertyName: "noDataTemplate", first: true, predicate: DropdownNoDataTemplateDirective, descendants: true, read: TemplateRef, isSignal: true }, { propertyName: "prefixTemplate", first: true, predicate: DropdownPrefixTemplateDirective, descendants: true, read: TemplateRef, isSignal: true }, { propertyName: "tagTemplate", first: true, predicate: MultiSelectTagTemplateDirective, descendants: true, read: TemplateRef, isSignal: true }], viewQueries: [{ propertyName: "popupTemplate", first: true, predicate: ["popupTemplate"], descendants: true, isSignal: true }], hostDirectives: [{ directive: i1.DropdownDataHandlerDirective }, { directive: i1.DropdownListPopupHandlerDirective }], ngImport: i0, template: "@if (prefixTemplate()) {\n <span [class]=\"affixClass()\">\n <ng-container [ngTemplateOutlet]=\"prefixTemplate()\"></ng-container>\n </span>\n}\n\n<div [class]=\"itemContainerClass()\">\n @for (pair of valueTextMap(); track pair.key) {\n <mona-chip\n look=\"default\"\n [tabindex]=\"-1\"\n [removable]=\"true\"\n [removeTabIndex]=\"-1\"\n [disabled]=\"disabled()\"\n [rounded]=\"rounded()\"\n [size]=\"size()\"\n (remove)=\"onSelectedItemRemove($event, pair.key!)\">\n @if (tagTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"tagTemplate()\"\n [ngTemplateOutletContext]=\"{ $implicit: pair.key!.data }\"></ng-container>\n } @else {\n {{ pair.value }}\n }\n </mona-chip>\n }\n\n @if (tagCount() >= 0 && selectedListItems().length > tagCount()) {\n <mona-chip\n look=\"outline\"\n [tabindex]=\"-1\"\n [removable]=\"true\"\n [removeTabIndex]=\"-1\"\n [disabled]=\"disabled()\"\n [rounded]=\"rounded()\"\n [size]=\"size()\"\n (remove)=\"onSelectedItemGroupRemove($event)\">\n @let remainingCount = selectedDataItems().length - tagCount();\n @if (summaryTagTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"summaryTagTemplate()\"\n [ngTemplateOutletContext]=\"{ $implicit: selectedDataItems(), tagCount: tagCount() }\"></ng-container>\n } @else {\n {{ messages().itemsCount(remainingCount) }}\n }\n </mona-chip>\n }\n</div>\n\n@if (showClearButton() && selectedListItems().length !== 0 && !loading()) {\n <mona-indicator-icon\n preset=\"clear\"\n [class]=\"indicatorClass()\"\n [interactive]=\"true\"\n [label]=\"messages().clear\"\n (activate)=\"onValueClear($event)\"></mona-indicator-icon>\n}\n\n@if (loading()) {\n <mona-indicator-icon preset=\"loading\" [class]=\"indicatorClass()\" [size]=\"12\"></mona-indicator-icon>\n}\n\n<mona-indicator-icon preset=\"dropdown\" [class]=\"indicatorClass()\" [size]=\"18\"></mona-indicator-icon>\n\n<span monaDropdownLiveRegion></span>\n\n<ng-template #popupTemplate>\n <div [class]=\"listPopupClass()\" (pointerdown)=\"onPopupPointerDown($event)\">\n <mona-list [listId]=\"listId\" [focusOnMount]=\"false\" [size]=\"size()\" (itemSelect)=\"onItemSelect()\">\n @if (footerTemplate()) {\n <ng-template monaListFooterTemplate>\n <ng-container [ngTemplateOutlet]=\"footerTemplate() ?? null\"></ng-container>\n </ng-template>\n }\n @if (groupHeaderTemplate()) {\n <ng-template monaListGroupHeaderTemplate let-group>\n <ng-container\n [ngTemplateOutlet]=\"groupHeaderTemplate() ?? null\"\n [ngTemplateOutletContext]=\"{ $implicit: group }\"></ng-container>\n </ng-template>\n }\n @if (headerTemplate()) {\n <ng-template monaListHeaderTemplate>\n <ng-container [ngTemplateOutlet]=\"headerTemplate() ?? null\"></ng-container>\n </ng-template>\n }\n @if (itemTemplate()) {\n <ng-template monaListItemTemplate let-dataItem>\n <ng-container\n [ngTemplateOutlet]=\"itemTemplate() ?? null\"\n [ngTemplateOutletContext]=\"{ $implicit: dataItem }\"></ng-container>\n </ng-template>\n }\n @if (noDataTemplate()) {\n <ng-template monaListNoDataTemplate>\n <ng-container [ngTemplateOutlet]=\"noDataTemplate() ?? null\"></ng-container>\n </ng-template>\n }\n </mona-list>\n </div>\n</ng-template>\n", dependencies: [{ kind: "component", type: ChipComponent, selector: "mona-chip", inputs: ["aria-label", "disabled", "label", "look", "removable", "removeLabel", "removeTabIndex", "rounded", "selected", "size", "tabindex", "toggleable", "class", "value"], outputs: ["contentClick", "remove", "selectedChange"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ListComponent, selector: "mona-list", inputs: ["ariaLabel", "data", "focusOnMount", "height", "listClass", "listId", "listItemClass", "listItemStyle", "listStyle", "maxHeight", "maxWidth", "size", "textField", "width"], outputs: ["itemSelect"] }, { kind: "directive", type: ListGroupHeaderTemplateDirective, selector: "ng-template[monaListGroupHeaderTemplate]" }, { kind: "directive", type: ListItemTemplateDirective, selector: "ng-template[monaListItemTemplate]" }, { kind: "directive", type: ListFooterTemplateDirective, selector: "ng-template[monaListFooterTemplate]" }, { kind: "directive", type: ListHeaderTemplateDirective, selector: "ng-template[monaListHeaderTemplate]" }, { kind: "directive", type: ListNoDataTemplateDirective, selector: "ng-template[monaListNoDataTemplate]" }, { kind: "directive", type: DropdownLiveRegionDirective, selector: "span[monaDropdownLiveRegion]" }, { kind: "component", type: IndicatorIconComponent, selector: "mona-indicator-icon", inputs: ["icon", "interactive", "label", "preset", "size", "class"], outputs: ["activate"] }] }); }
617
+ ], queries: [{ propertyName: "footerTemplate", first: true, predicate: DropdownFooterTemplateDirective, descendants: true, read: TemplateRef, isSignal: true }, { propertyName: "groupHeaderTemplate", first: true, predicate: DropdownGroupHeaderTemplateDirective, descendants: true, read: TemplateRef, isSignal: true }, { propertyName: "headerTemplate", first: true, predicate: DropdownHeaderTemplateDirective, descendants: true, read: TemplateRef, isSignal: true }, { propertyName: "itemTemplate", first: true, predicate: DropdownItemTemplateDirective, descendants: true, read: TemplateRef, isSignal: true }, { propertyName: "noDataTemplate", first: true, predicate: DropdownNoDataTemplateDirective, descendants: true, read: TemplateRef, isSignal: true }, { propertyName: "prefixTemplate", first: true, predicate: DropdownPrefixTemplateDirective, descendants: true, read: TemplateRef, isSignal: true }, { propertyName: "tagTemplate", first: true, predicate: MultiSelectTagTemplateDirective, descendants: true, read: TemplateRef, isSignal: true }], viewQueries: [{ propertyName: "popupTemplate", first: true, predicate: ["popupTemplate"], descendants: true, isSignal: true }], hostDirectives: [{ directive: i1.DropdownDataHandlerDirective }, { directive: i1.DropdownListPopupHandlerDirective }, { directive: i1.DropdownLiveRegionDirective }], ngImport: i0, template: "@if (prefixTemplate()) {\n <span [class]=\"affixClass()\">\n <ng-container [ngTemplateOutlet]=\"prefixTemplate()\"></ng-container>\n </span>\n}\n\n<div [class]=\"itemContainerClass()\">\n @for (pair of valueTextMap(); track pair.key) {\n <mona-chip\n look=\"default\"\n [tabindex]=\"-1\"\n [removable]=\"true\"\n [removeTabIndex]=\"-1\"\n [disabled]=\"disabled()\"\n [removeLabel]=\"chipMessages().removeLabel(pair.value)\"\n [rounded]=\"rounded()\"\n [size]=\"size()\"\n (remove)=\"onSelectedItemRemove($event, pair.key!)\">\n @if (tagTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"tagTemplate()\"\n [ngTemplateOutletContext]=\"{ $implicit: pair.key!.data }\"></ng-container>\n } @else {\n {{ pair.value }}\n }\n </mona-chip>\n }\n\n @if (tagCount() >= 0 && selectedListItems().length > tagCount()) {\n @let remainingCount = selectedDataItems().length - tagCount();\n <mona-chip\n look=\"outline\"\n [tabindex]=\"-1\"\n [removable]=\"true\"\n [removeTabIndex]=\"-1\"\n [disabled]=\"disabled()\"\n [removeLabel]=\"messages().removeMoreItems(remainingCount)\"\n [rounded]=\"rounded()\"\n [size]=\"size()\"\n (remove)=\"onSelectedItemGroupRemove($event)\">\n @if (summaryTagTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"summaryTagTemplate()\"\n [ngTemplateOutletContext]=\"{ $implicit: selectedDataItems(), tagCount: tagCount() }\"></ng-container>\n } @else {\n {{ messages().itemsCount(remainingCount) }}\n }\n </mona-chip>\n }\n\n @if (placeholder() && selectedListItems().isEmpty()) {\n <span class=\"px-1.5 text-muted-foreground\">{{ placeholder() }}</span>\n }\n</div>\n\n@if (clearButtonVisible()) {\n <mona-indicator-icon\n preset=\"clear\"\n [class]=\"indicatorClass()\"\n [interactive]=\"true\"\n [label]=\"messages().clear\"\n (activate)=\"onValueClear($event)\"></mona-indicator-icon>\n}\n\n@if (loading()) {\n <mona-indicator-icon preset=\"loading\" [class]=\"indicatorClass()\" [size]=\"12\"></mona-indicator-icon>\n}\n\n<mona-indicator-icon preset=\"dropdown\" [class]=\"indicatorClass()\" [size]=\"18\"></mona-indicator-icon>\n\n<ng-template #popupTemplate>\n <div [class]=\"listPopupClass()\" (pointerdown)=\"onPopupPointerDown($event)\">\n <mona-list [listId]=\"listId\" [focusOnMount]=\"false\" [size]=\"size()\" (itemSelect)=\"onItemSelect()\">\n @if (footerTemplate()) {\n <ng-template monaListFooterTemplate>\n <ng-container [ngTemplateOutlet]=\"footerTemplate() ?? null\"></ng-container>\n </ng-template>\n }\n @if (groupHeaderTemplate()) {\n <ng-template monaListGroupHeaderTemplate let-group>\n <ng-container\n [ngTemplateOutlet]=\"groupHeaderTemplate() ?? null\"\n [ngTemplateOutletContext]=\"{ $implicit: group }\"></ng-container>\n </ng-template>\n }\n @if (headerTemplate()) {\n <ng-template monaListHeaderTemplate>\n <ng-container [ngTemplateOutlet]=\"headerTemplate() ?? null\"></ng-container>\n </ng-template>\n }\n @if (itemTemplate()) {\n <ng-template monaListItemTemplate let-dataItem>\n <ng-container\n [ngTemplateOutlet]=\"itemTemplate() ?? null\"\n [ngTemplateOutletContext]=\"{ $implicit: dataItem }\"></ng-container>\n </ng-template>\n }\n @if (noDataTemplate()) {\n <ng-template monaListNoDataTemplate>\n <ng-container [ngTemplateOutlet]=\"noDataTemplate() ?? null\"></ng-container>\n </ng-template>\n }\n </mona-list>\n </div>\n</ng-template>\n", dependencies: [{ kind: "component", type: ChipComponent, selector: "mona-chip", inputs: ["aria-label", "disabled", "label", "look", "removable", "removeLabel", "removeTabIndex", "rounded", "selected", "size", "tabindex", "toggleable", "class", "value"], outputs: ["contentClick", "remove", "selectedChange"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ListComponent, selector: "mona-list", inputs: ["ariaLabel", "data", "focusOnMount", "height", "listClass", "listId", "listItemClass", "listItemStyle", "listStyle", "maxHeight", "maxWidth", "size", "textField", "width"], outputs: ["itemSelect"] }, { kind: "directive", type: ListGroupHeaderTemplateDirective, selector: "ng-template[monaListGroupHeaderTemplate]" }, { kind: "directive", type: ListItemTemplateDirective, selector: "ng-template[monaListItemTemplate]" }, { kind: "directive", type: ListFooterTemplateDirective, selector: "ng-template[monaListFooterTemplate]" }, { kind: "directive", type: ListHeaderTemplateDirective, selector: "ng-template[monaListHeaderTemplate]" }, { kind: "directive", type: ListNoDataTemplateDirective, selector: "ng-template[monaListNoDataTemplate]" }, { kind: "component", type: IndicatorIconComponent, selector: "mona-indicator-icon", inputs: ["icon", "interactive", "label", "preset", "size", "class"], outputs: ["activate"] }] }); }
566
618
  }
567
619
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: MultiSelectComponent, decorators: [{
568
620
  type: Component,
@@ -571,7 +623,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImpor
571
623
  DropdownService,
572
624
  MultiSelectService,
573
625
  {
574
- provide: DropdownDataInputToken,
626
+ provide: DROPDOWN_DATA_INPUT_TOKEN,
575
627
  useExisting: forwardRef(() => MultiSelectComponent),
576
628
  multi: false
577
629
  },
@@ -589,18 +641,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImpor
589
641
  ListFooterTemplateDirective,
590
642
  ListHeaderTemplateDirective,
591
643
  ListNoDataTemplateDirective,
592
- DropdownLiveRegionDirective,
593
644
  IndicatorIconComponent
594
- ], hostDirectives: [DropdownDataHandlerDirective, DropdownListPopupHandlerDirective], host: {
645
+ ], hostDirectives: [DropdownDataHandlerDirective, DropdownListPopupHandlerDirective, DropdownLiveRegionDirective], host: {
595
646
  "[attr.aria-activedescendant]": "activeDescendant()",
596
647
  "[attr.aria-busy]": "loading() ? 'true' : undefined",
597
648
  "[attr.aria-controls]": "listId",
649
+ "[attr.aria-describedby]": "ariaDescribedBy() || null",
598
650
  "[attr.aria-disabled]": "disabled() ? true : undefined",
599
651
  "[attr.aria-expanded]": "expanded()",
600
652
  "[attr.aria-haspopup]": "'listbox'",
601
653
  "[attr.aria-invalid]": "invalidState() ? true : undefined",
602
- "[attr.aria-label]": "ariaLabel()",
603
- "[attr.aria-labelledby]": "ariaLabelledBy()",
654
+ "[attr.aria-label]": "effectiveAriaLabel() || null",
655
+ "[attr.aria-labelledby]": "ariaLabelledBy() || null",
604
656
  "[attr.aria-readonly]": "readonly() ? true : undefined",
605
657
  "[attr.aria-required]": "required() ? true : undefined",
606
658
  "[attr.data-disabled]": "disabled() || null",
@@ -609,11 +661,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImpor
609
661
  "[attr.role]": "'combobox'",
610
662
  "[attr.tabindex]": "disabled() ? null : 0",
611
663
  "[class]": "baseClass()",
612
- "(blur)": "onBlur()"
613
- }, template: "@if (prefixTemplate()) {\n <span [class]=\"affixClass()\">\n <ng-container [ngTemplateOutlet]=\"prefixTemplate()\"></ng-container>\n </span>\n}\n\n<div [class]=\"itemContainerClass()\">\n @for (pair of valueTextMap(); track pair.key) {\n <mona-chip\n look=\"default\"\n [tabindex]=\"-1\"\n [removable]=\"true\"\n [removeTabIndex]=\"-1\"\n [disabled]=\"disabled()\"\n [rounded]=\"rounded()\"\n [size]=\"size()\"\n (remove)=\"onSelectedItemRemove($event, pair.key!)\">\n @if (tagTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"tagTemplate()\"\n [ngTemplateOutletContext]=\"{ $implicit: pair.key!.data }\"></ng-container>\n } @else {\n {{ pair.value }}\n }\n </mona-chip>\n }\n\n @if (tagCount() >= 0 && selectedListItems().length > tagCount()) {\n <mona-chip\n look=\"outline\"\n [tabindex]=\"-1\"\n [removable]=\"true\"\n [removeTabIndex]=\"-1\"\n [disabled]=\"disabled()\"\n [rounded]=\"rounded()\"\n [size]=\"size()\"\n (remove)=\"onSelectedItemGroupRemove($event)\">\n @let remainingCount = selectedDataItems().length - tagCount();\n @if (summaryTagTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"summaryTagTemplate()\"\n [ngTemplateOutletContext]=\"{ $implicit: selectedDataItems(), tagCount: tagCount() }\"></ng-container>\n } @else {\n {{ messages().itemsCount(remainingCount) }}\n }\n </mona-chip>\n }\n</div>\n\n@if (showClearButton() && selectedListItems().length !== 0 && !loading()) {\n <mona-indicator-icon\n preset=\"clear\"\n [class]=\"indicatorClass()\"\n [interactive]=\"true\"\n [label]=\"messages().clear\"\n (activate)=\"onValueClear($event)\"></mona-indicator-icon>\n}\n\n@if (loading()) {\n <mona-indicator-icon preset=\"loading\" [class]=\"indicatorClass()\" [size]=\"12\"></mona-indicator-icon>\n}\n\n<mona-indicator-icon preset=\"dropdown\" [class]=\"indicatorClass()\" [size]=\"18\"></mona-indicator-icon>\n\n<span monaDropdownLiveRegion></span>\n\n<ng-template #popupTemplate>\n <div [class]=\"listPopupClass()\" (pointerdown)=\"onPopupPointerDown($event)\">\n <mona-list [listId]=\"listId\" [focusOnMount]=\"false\" [size]=\"size()\" (itemSelect)=\"onItemSelect()\">\n @if (footerTemplate()) {\n <ng-template monaListFooterTemplate>\n <ng-container [ngTemplateOutlet]=\"footerTemplate() ?? null\"></ng-container>\n </ng-template>\n }\n @if (groupHeaderTemplate()) {\n <ng-template monaListGroupHeaderTemplate let-group>\n <ng-container\n [ngTemplateOutlet]=\"groupHeaderTemplate() ?? null\"\n [ngTemplateOutletContext]=\"{ $implicit: group }\"></ng-container>\n </ng-template>\n }\n @if (headerTemplate()) {\n <ng-template monaListHeaderTemplate>\n <ng-container [ngTemplateOutlet]=\"headerTemplate() ?? null\"></ng-container>\n </ng-template>\n }\n @if (itemTemplate()) {\n <ng-template monaListItemTemplate let-dataItem>\n <ng-container\n [ngTemplateOutlet]=\"itemTemplate() ?? null\"\n [ngTemplateOutletContext]=\"{ $implicit: dataItem }\"></ng-container>\n </ng-template>\n }\n @if (noDataTemplate()) {\n <ng-template monaListNoDataTemplate>\n <ng-container [ngTemplateOutlet]=\"noDataTemplate() ?? null\"></ng-container>\n </ng-template>\n }\n </mona-list>\n </div>\n</ng-template>\n" }]
664
+ "(focusout)": "onFocusOut($event)"
665
+ }, template: "@if (prefixTemplate()) {\n <span [class]=\"affixClass()\">\n <ng-container [ngTemplateOutlet]=\"prefixTemplate()\"></ng-container>\n </span>\n}\n\n<div [class]=\"itemContainerClass()\">\n @for (pair of valueTextMap(); track pair.key) {\n <mona-chip\n look=\"default\"\n [tabindex]=\"-1\"\n [removable]=\"true\"\n [removeTabIndex]=\"-1\"\n [disabled]=\"disabled()\"\n [removeLabel]=\"chipMessages().removeLabel(pair.value)\"\n [rounded]=\"rounded()\"\n [size]=\"size()\"\n (remove)=\"onSelectedItemRemove($event, pair.key!)\">\n @if (tagTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"tagTemplate()\"\n [ngTemplateOutletContext]=\"{ $implicit: pair.key!.data }\"></ng-container>\n } @else {\n {{ pair.value }}\n }\n </mona-chip>\n }\n\n @if (tagCount() >= 0 && selectedListItems().length > tagCount()) {\n @let remainingCount = selectedDataItems().length - tagCount();\n <mona-chip\n look=\"outline\"\n [tabindex]=\"-1\"\n [removable]=\"true\"\n [removeTabIndex]=\"-1\"\n [disabled]=\"disabled()\"\n [removeLabel]=\"messages().removeMoreItems(remainingCount)\"\n [rounded]=\"rounded()\"\n [size]=\"size()\"\n (remove)=\"onSelectedItemGroupRemove($event)\">\n @if (summaryTagTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"summaryTagTemplate()\"\n [ngTemplateOutletContext]=\"{ $implicit: selectedDataItems(), tagCount: tagCount() }\"></ng-container>\n } @else {\n {{ messages().itemsCount(remainingCount) }}\n }\n </mona-chip>\n }\n\n @if (placeholder() && selectedListItems().isEmpty()) {\n <span class=\"px-1.5 text-muted-foreground\">{{ placeholder() }}</span>\n }\n</div>\n\n@if (clearButtonVisible()) {\n <mona-indicator-icon\n preset=\"clear\"\n [class]=\"indicatorClass()\"\n [interactive]=\"true\"\n [label]=\"messages().clear\"\n (activate)=\"onValueClear($event)\"></mona-indicator-icon>\n}\n\n@if (loading()) {\n <mona-indicator-icon preset=\"loading\" [class]=\"indicatorClass()\" [size]=\"12\"></mona-indicator-icon>\n}\n\n<mona-indicator-icon preset=\"dropdown\" [class]=\"indicatorClass()\" [size]=\"18\"></mona-indicator-icon>\n\n<ng-template #popupTemplate>\n <div [class]=\"listPopupClass()\" (pointerdown)=\"onPopupPointerDown($event)\">\n <mona-list [listId]=\"listId\" [focusOnMount]=\"false\" [size]=\"size()\" (itemSelect)=\"onItemSelect()\">\n @if (footerTemplate()) {\n <ng-template monaListFooterTemplate>\n <ng-container [ngTemplateOutlet]=\"footerTemplate() ?? null\"></ng-container>\n </ng-template>\n }\n @if (groupHeaderTemplate()) {\n <ng-template monaListGroupHeaderTemplate let-group>\n <ng-container\n [ngTemplateOutlet]=\"groupHeaderTemplate() ?? null\"\n [ngTemplateOutletContext]=\"{ $implicit: group }\"></ng-container>\n </ng-template>\n }\n @if (headerTemplate()) {\n <ng-template monaListHeaderTemplate>\n <ng-container [ngTemplateOutlet]=\"headerTemplate() ?? null\"></ng-container>\n </ng-template>\n }\n @if (itemTemplate()) {\n <ng-template monaListItemTemplate let-dataItem>\n <ng-container\n [ngTemplateOutlet]=\"itemTemplate() ?? null\"\n [ngTemplateOutletContext]=\"{ $implicit: dataItem }\"></ng-container>\n </ng-template>\n }\n @if (noDataTemplate()) {\n <ng-template monaListNoDataTemplate>\n <ng-container [ngTemplateOutlet]=\"noDataTemplate() ?? null\"></ng-container>\n </ng-template>\n }\n </mona-list>\n </div>\n</ng-template>\n" }]
614
666
  }], ctorParameters: () => [], propDecorators: { footerTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => DropdownFooterTemplateDirective), { ...{ read: TemplateRef }, isSignal: true }] }], groupHeaderTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => DropdownGroupHeaderTemplateDirective), { ...{
615
667
  read: TemplateRef
616
- }, isSignal: true }] }], headerTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => DropdownHeaderTemplateDirective), { ...{ read: TemplateRef }, isSignal: true }] }], itemTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => DropdownItemTemplateDirective), { ...{ read: TemplateRef }, isSignal: true }] }], noDataTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => DropdownNoDataTemplateDirective), { ...{ read: TemplateRef }, isSignal: true }] }], popupTemplate: [{ type: i0.ViewChild, args: ["popupTemplate", { isSignal: true }] }], prefixTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => DropdownPrefixTemplateDirective), { ...{ read: TemplateRef }, isSignal: true }] }], tagTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => MultiSelectTagTemplateDirective), { ...{ read: TemplateRef }, isSignal: true }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-label", required: false }] }], ariaLabelledBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-labelledby", required: false }] }], autoClose: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoClose", required: false }] }], checkboxes: [{ type: i0.Input, args: [{ isSignal: true, alias: "checkboxes", required: false }] }], close: [{ type: i0.Output, args: ["close"] }], closed: [{ type: i0.Output, args: ["closed"] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], itemDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemDisabled", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], open: [{ type: i0.Output, args: ["open"] }], opened: [{ type: i0.Output, args: ["opened"] }], popupClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "popupClass", required: false }] }], popupHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "popupHeight", required: false }] }], popupWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "popupWidth", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], rounded: [{ type: i0.Input, args: [{ isSignal: true, alias: "rounded", required: false }] }], showClearButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showClearButton", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], textField: [{ type: i0.Input, args: [{ isSignal: true, alias: "textField", required: false }] }], touch: [{ type: i0.Output, args: ["touch"] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], valueField: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueField", required: false }] }], valuePrimitive: [{ type: i0.Input, args: [{ isSignal: true, alias: "valuePrimitive", required: false }] }] } });
668
+ }, isSignal: true }] }], headerTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => DropdownHeaderTemplateDirective), { ...{ read: TemplateRef }, isSignal: true }] }], itemTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => DropdownItemTemplateDirective), { ...{ read: TemplateRef }, isSignal: true }] }], noDataTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => DropdownNoDataTemplateDirective), { ...{ read: TemplateRef }, isSignal: true }] }], popupTemplate: [{ type: i0.ViewChild, args: ["popupTemplate", { isSignal: true }] }], prefixTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => DropdownPrefixTemplateDirective), { ...{ read: TemplateRef }, isSignal: true }] }], tagTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => MultiSelectTagTemplateDirective), { ...{ read: TemplateRef }, isSignal: true }] }], ariaDescribedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-describedby", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-label", required: false }] }], ariaLabelledBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-labelledby", required: false }] }], autoClose: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoClose", required: false }] }], checkboxes: [{ type: i0.Input, args: [{ isSignal: true, alias: "checkboxes", required: false }] }], close: [{ type: i0.Output, args: ["close"] }], closed: [{ type: i0.Output, args: ["closed"] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], itemDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemDisabled", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], open: [{ type: i0.Output, args: ["open"] }], opened: [{ type: i0.Output, args: ["opened"] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], popupClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "popupClass", required: false }] }], popupHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "popupHeight", required: false }] }], popupWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "popupWidth", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], rounded: [{ type: i0.Input, args: [{ isSignal: true, alias: "rounded", required: false }] }], showClearButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showClearButton", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], textField: [{ type: i0.Input, args: [{ isSignal: true, alias: "textField", required: false }] }], touch: [{ type: i0.Output, args: ["touch"] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], valueField: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueField", required: false }] }], valuePrimitive: [{ type: i0.Input, args: [{ isSignal: true, alias: "valuePrimitive", required: false }] }] } });
617
669
 
618
670
  class MultiSelectSummaryTagTemplateDirective {
619
671
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: MultiSelectSummaryTagTemplateDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }