@ktortu/aaa 0.9.7 → 0.9.9

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.
@@ -2,7 +2,7 @@ import { NgTemplateOutlet, DOCUMENT, isPlatformBrowser } from '@angular/common';
2
2
  import * as i0 from '@angular/core';
3
3
  import { InjectionToken, inject, computed, ElementRef, Directive, input, output, booleanAttribute, contentChild, TemplateRef, forwardRef, ChangeDetectionStrategy, Component, Injectable, model, viewChild, signal, afterNextRender, isDevMode, DestroyRef, effect, PLATFORM_ID, untracked, afterRenderEffect, Injector, ChangeDetectorRef, viewChildren, LOCALE_ID, Pipe } from '@angular/core';
4
4
  import { KtTooltip } from '@ktortu/aaa/tooltip';
5
- import { KtIdGenerator, KT_AUDIT_ENABLED, KtBodyScrollLock, KtViewport, createKtSheetDrag } from '@ktortu/aaa/cdk';
5
+ import { KtIdGenerator, KT_AUDIT_ENABLED, KtBodyScrollLock, KtViewport } from '@ktortu/aaa/cdk';
6
6
  import { transformedValue } from '@angular/forms/signals';
7
7
  import { Listbox, Option } from '@angular/aria/listbox';
8
8
  import { Combobox, ComboboxPopup, ComboboxWidget } from '@angular/aria/combobox';
@@ -782,9 +782,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
782
782
  * Permet d'activer ou désactiver une option avec effet immédiat.
783
783
  * Intégré aux Signal Forms de l'application via FormValueControl.
784
784
  *
785
+ * Libellé : `label` (texte) par défaut ; un contenu projeté le remplace pour les rendus riches
786
+ * (image + texte, spans empilés…). `ariaLabel` porte alors le nom accessible si le contenu projeté
787
+ * n'a pas de texte (WCAG 4.1.2). Même règle que `kt-checkbox` / `kt-radio`.
788
+ *
785
789
  * @example
786
790
  * ```html
791
+ * <!-- Simple -->
787
792
  * <kt-switch label="Notifications par e-mail" [(value)]="emailNotif" />
793
+ *
794
+ * <!-- Contenu projeté (image + texte) -->
795
+ * <kt-switch [(value)]="emailNotif">
796
+ * <img ngSrc="/assets/mail.png" width="20" height="20" alt="" /> Notifications par e-mail
797
+ * </kt-switch>
788
798
  * ```
789
799
  */
790
800
  class KtSwitch {
@@ -816,7 +826,7 @@ class KtSwitch {
816
826
  /** id imposé (sélecteurs de test stables) ; sinon auto-généré, anti-collision. @default undefined */
817
827
  id = input(/* @ts-ignore */
818
828
  ...(ngDevMode ? [undefined, { debugName: "id" }] : /* istanbul ignore next */ []));
819
- /** Texte du libellé associé à la bascule. @default undefined */
829
+ /** Texte du libellé (remplacé visuellement par un contenu projeté). @default undefined */
820
830
  label = input(/* @ts-ignore */
821
831
  ...(ngDevMode ? [undefined, { debugName: "label" }] : /* istanbul ignore next */ []));
822
832
  /** Texte d'aide affiché sous la bascule (masqué quand une erreur s'affiche). @default undefined */
@@ -831,6 +841,7 @@ class KtSwitch {
831
841
  /** Afficher toutes les erreurs au lieu de la première seule. @default KT_FIELD_CONFIG.showAllErrors ?? false */
832
842
  showAllErrors = input(this.config?.showAllErrors ?? false, { ...(ngDevMode ? { debugName: "showAllErrors" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
833
843
  switchBtn = viewChild.required('switchBtn');
844
+ el = inject(ElementRef);
834
845
  errorResolver = inject(KtFieldErrorResolver);
835
846
  idGen = inject(KtIdGenerator);
836
847
  uid = this.idGen.generateId('switch');
@@ -864,11 +875,15 @@ class KtSwitch {
864
875
  ...(ngDevMode ? [{ debugName: "describedBy" }] : /* istanbul ignore next */ []));
865
876
  constructor() {
866
877
  // Garde-fou a11y (dev, navigateur uniquement) : un switch sans nom accessible est annoncé vide
867
- // (WCAG 4.1.2). Le nom vient de `label` ou `ariaLabel` (pas de contenu projeté ici).
878
+ // (WCAG 4.1.2). Le nom vient de `label`, `ariaLabel` OU du contenu projeté (même règle que
879
+ // checkbox/radio) : sans label ni ariaLabel, on inspecte le texte réellement rendu dans le label.
868
880
  afterNextRender(() => {
869
881
  if (!isDevMode() || this.label() || this.ariaLabel())
870
882
  return;
871
- console.warn('[ktSwitch] sans `label` ni `ariaLabel` : le contrôle est annoncé sans nom accessible (WCAG 4.1.2).');
883
+ const labelText = this.el.nativeElement.querySelector('.kt-switch-label')?.textContent?.replace('*', '').trim();
884
+ if (!labelText) {
885
+ console.warn('[ktSwitch] sans `label`, `ariaLabel` ni contenu projeté : le contrôle est annoncé sans nom accessible (WCAG 4.1.2).');
886
+ }
872
887
  });
873
888
  }
874
889
  /** Focus le bouton bascule natif (utilisé par Signal Forms `focusBoundControl`). */
@@ -901,7 +916,7 @@ class KtSwitch {
901
916
  [id]="baseId()"
902
917
  [attr.aria-checked]="value()"
903
918
  [attr.aria-label]="resolvedAriaLabel()"
904
- [attr.aria-labelledby]="label() ? labelId() : null"
919
+ [attr.aria-labelledby]="resolvedAriaLabel() ? null : labelId()"
905
920
  [attr.aria-describedby]="describedBy()"
906
921
  [attr.aria-invalid]="showInvalid() ? 'true' : null"
907
922
  [attr.aria-required]="required() ? 'true' : null"
@@ -915,14 +930,12 @@ class KtSwitch {
915
930
  <span class="kt-switch__thumb"></span>
916
931
  </button>
917
932
 
918
- @if (label(); as labelText) {
919
- <label [id]="labelId()" [attr.for]="baseId()" class="kt-switch-label">
920
- {{ labelText }}
921
- @if (required()) {
922
- <span class="kt-switch-label__required" aria-hidden="true">*</span>
923
- }
924
- </label>
925
- }
933
+ <label [id]="labelId()" [attr.for]="baseId()" class="kt-switch-label">
934
+ <ng-content>{{ label() }}</ng-content>
935
+ @if (required()) {
936
+ <span class="kt-switch-label__required" aria-hidden="true">*</span>
937
+ }
938
+ </label>
926
939
  </div>
927
940
 
928
941
  @if (hint() && !showInvalid()) {
@@ -936,7 +949,7 @@ class KtSwitch {
936
949
  }
937
950
  </div>
938
951
  </div>
939
- `, isInline: true, styles: ["@layer kt-aaa.components{:host{display:block}.kt-switch-field{display:flex;flex-direction:column;gap:var(--field-gap, .375rem)}.kt-switch-row{display:flex;align-items:center;gap:var(--field-control-gap, .5rem)}.kt-switch{position:relative;display:inline-flex;align-items:center;box-sizing:border-box;inline-size:var(--switch-width, 2.75rem);block-size:var(--switch-height, 1.5rem);padding:var(--switch-padding, 2px);border-radius:var(--switch-radius, 999px);border:var(--switch-border-width, 2px) solid var(--switch-border-color, var(--field-border-color, var(--kt-outline, #c4c7c5)));background-color:var(--switch-bg, var(--field-bg, var(--kt-surface, #ffffff)));cursor:pointer;outline:none;box-shadow:var(--switch-shadow, var(--field-shadow, none));transition:var( --switch-transition, background-color .2s cubic-bezier(.4, 0, .2, 1), border-color .2s cubic-bezier(.4, 0, .2, 1), box-shadow .2s ease )}.kt-switch:after{content:\"\";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:100%;height:44px}.kt-switch__thumb{display:block;inline-size:var(--switch-thumb-size, 1rem);block-size:var(--switch-thumb-size, 1rem);border-radius:var(--switch-thumb-radius, 50%);background-color:var(--switch-thumb-bg, var(--kt-outline-strong, #5f6368));box-shadow:var(--switch-thumb-shadow, 0 1px 3px rgba(0, 0, 0, .2));transition:var( --switch-thumb-transition, transform .2s cubic-bezier(.34, 1.56, .64, 1), background-color .2s ease );transform:translate(0)}.kt-switch[aria-checked=true]{background-color:var(--switch-bg-active, var(--kt-primary, #0b57d0));border-color:var(--switch-border-color-active, var(--kt-primary, #0b57d0));box-shadow:var( --switch-shadow-active, 0 0 8px color-mix(in srgb, var(--switch-bg-active, var(--kt-primary, #0b57d0)) 50%, transparent) )}.kt-switch[aria-checked=true] .kt-switch__thumb{background-color:var(--switch-thumb-bg-active, #ffffff);transform:translate(calc(var(--switch-width, 2.75rem) - var(--switch-thumb-size, 1rem) - (var(--switch-padding, 2px) * 2) - (var(--switch-border-width, 2px) * 2)))}.kt-switch:hover:not(:disabled){border-color:var(--switch-border-color-hover, var(--field-border-color-hover, var(--kt-outline-strong, #5f6368)));box-shadow:var(--switch-shadow-hover, var(--field-shadow-hover, var(--switch-shadow, var(--field-shadow, none))))}.kt-switch[aria-checked=true]:hover:not(:disabled){background-color:var(--switch-bg-active-hover, color-mix(in srgb, var(--kt-primary, #0b57d0) 90%, black));border-color:var(--switch-border-color-active-hover, color-mix(in srgb, var(--kt-primary, #0b57d0) 90%, black))}.kt-switch:focus-visible{outline:var(--kt-focus-ring-width, 2px) solid var(--kt-focus-ring-color, #0b57d0);outline-offset:var(--switch-focus-ring-offset, 2px);box-shadow:var(--switch-shadow-focus, var(--field-shadow-focus, var(--switch-shadow, var(--field-shadow, none))))}.kt-switch:disabled{cursor:not-allowed;opacity:.5;background-color:var(--field-disabled-bg, #f1f3f4);border-color:var(--field-border-color, #c4c7c5)}.kt-switch:disabled .kt-switch__thumb{background-color:var(--kt-outline, #c4c7c5);box-shadow:none}.kt-switch-field--invalid .kt-switch{border-color:var(--field-error-color, var(--kt-danger, #b3261e))}.kt-switch-field--invalid .kt-switch[aria-checked=true]{background-color:var(--field-error-color, var(--kt-danger, #b3261e));border-color:var(--field-error-color, var(--kt-danger, #b3261e))}.kt-switch-label{font-size:var(--field-label-font-size, .875rem);font-weight:var(--field-label-weight, 500);color:var(--field-label-color, inherit);cursor:pointer;-webkit-user-select:none;user-select:none}.kt-switch-field--disabled .kt-switch-label{cursor:not-allowed;color:var(--field-hint-color, #5f6368);opacity:.6}.kt-switch-label__required{margin-inline-start:.125rem;color:var(--field-required-color, #8c1d18)}.kt-switch-hint{margin:0;font-size:var(--field-hint-font-size, .8125rem);color:var(--field-hint-color, #474747)}.kt-switch-error{margin:0;display:flex;flex-direction:column;font-size:var(--field-hint-font-size, .8125rem);color:var(--field-error-color, #8c1d18)}.kt-switch-error-message{animation:var(--field-error-animation, none)}@media(prefers-reduced-motion:reduce){.kt-switch,.kt-switch__thumb{transition:none}.kt-switch-error-message{animation:none}}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
952
+ `, isInline: true, styles: ["@layer kt-aaa.components{:host{display:block}.kt-switch-field{display:flex;flex-direction:column;gap:var(--field-gap, .375rem)}.kt-switch-row{display:flex;align-items:center;gap:var(--field-control-gap, .5rem)}.kt-switch{position:relative;display:inline-flex;align-items:center;box-sizing:border-box;inline-size:var(--switch-width, 2.75rem);block-size:var(--switch-height, 1.5rem);padding:var(--switch-padding, 2px);border-radius:var(--switch-radius, 999px);border:var(--switch-border-width, 2px) solid var(--switch-border-color, var(--field-border-color, var(--kt-outline, #c4c7c5)));background-color:var(--switch-bg, var(--field-bg, var(--kt-surface, #ffffff)));cursor:pointer;outline:none;box-shadow:var(--switch-shadow, var(--field-shadow, none));transition:var( --switch-transition, background-color .2s cubic-bezier(.4, 0, .2, 1), border-color .2s cubic-bezier(.4, 0, .2, 1), box-shadow .2s ease )}.kt-switch:after{content:\"\";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:100%;height:44px}.kt-switch__thumb{display:block;inline-size:var(--switch-thumb-size, 1rem);block-size:var(--switch-thumb-size, 1rem);border-radius:var(--switch-thumb-radius, 50%);background-color:var(--switch-thumb-bg, var(--kt-outline-strong, #5f6368));box-shadow:var(--switch-thumb-shadow, 0 1px 3px rgba(0, 0, 0, .2));transition:var( --switch-thumb-transition, transform .2s cubic-bezier(.34, 1.56, .64, 1), background-color .2s ease );transform:translate(0)}.kt-switch[aria-checked=true]{background-color:var(--switch-bg-active, var(--kt-primary, #0b57d0));border-color:var(--switch-border-color-active, var(--kt-primary, #0b57d0));box-shadow:var( --switch-shadow-active, 0 0 8px color-mix(in srgb, var(--switch-bg-active, var(--kt-primary, #0b57d0)) 50%, transparent) )}.kt-switch[aria-checked=true] .kt-switch__thumb{background-color:var(--switch-thumb-bg-active, #ffffff);transform:translate(calc(var(--switch-width, 2.75rem) - var(--switch-thumb-size, 1rem) - (var(--switch-padding, 2px) * 2) - (var(--switch-border-width, 2px) * 2)))}.kt-switch:hover:not(:disabled){border-color:var(--switch-border-color-hover, var(--field-border-color-hover, var(--kt-outline-strong, #5f6368)));box-shadow:var(--switch-shadow-hover, var(--field-shadow-hover, var(--switch-shadow, var(--field-shadow, none))))}.kt-switch[aria-checked=true]:hover:not(:disabled){background-color:var(--switch-bg-active-hover, color-mix(in srgb, var(--kt-primary, #0b57d0) 90%, black));border-color:var(--switch-border-color-active-hover, color-mix(in srgb, var(--kt-primary, #0b57d0) 90%, black))}.kt-switch:focus-visible{outline:var(--kt-focus-ring-width, 2px) solid var(--kt-focus-ring-color, #0b57d0);outline-offset:var(--switch-focus-ring-offset, 2px);box-shadow:var(--switch-shadow-focus, var(--field-shadow-focus, var(--switch-shadow, var(--field-shadow, none))))}.kt-switch:disabled{cursor:not-allowed;opacity:.5;background-color:var(--field-disabled-bg, #f1f3f4);border-color:var(--field-border-color, #c4c7c5)}.kt-switch:disabled .kt-switch__thumb{background-color:var(--kt-outline, #c4c7c5);box-shadow:none}.kt-switch-field--invalid .kt-switch{border-color:var(--field-error-color, var(--kt-danger, #b3261e))}.kt-switch-field--invalid .kt-switch[aria-checked=true]{background-color:var(--field-error-color, var(--kt-danger, #b3261e));border-color:var(--field-error-color, var(--kt-danger, #b3261e))}.kt-switch-label{font-size:var(--field-label-font-size, .875rem);font-weight:var(--field-label-weight, 500);color:var(--field-label-color, inherit);cursor:pointer;-webkit-user-select:none;user-select:none}.kt-switch-label:empty{display:none}.kt-switch-field--disabled .kt-switch-label{cursor:not-allowed;color:var(--field-hint-color, #5f6368);opacity:.6}.kt-switch-label__required{margin-inline-start:.125rem;color:var(--field-required-color, #8c1d18)}.kt-switch-hint{margin:0;font-size:var(--field-hint-font-size, .8125rem);color:var(--field-hint-color, #474747)}.kt-switch-error{margin:0;display:flex;flex-direction:column;font-size:var(--field-hint-font-size, .8125rem);color:var(--field-error-color, #8c1d18)}.kt-switch-error-message{animation:var(--field-error-animation, none)}@media(prefers-reduced-motion:reduce){.kt-switch,.kt-switch__thumb{transition:none}.kt-switch-error-message{animation:none}}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
940
953
  }
941
954
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtSwitch, decorators: [{
942
955
  type: Component,
@@ -955,7 +968,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
955
968
  [id]="baseId()"
956
969
  [attr.aria-checked]="value()"
957
970
  [attr.aria-label]="resolvedAriaLabel()"
958
- [attr.aria-labelledby]="label() ? labelId() : null"
971
+ [attr.aria-labelledby]="resolvedAriaLabel() ? null : labelId()"
959
972
  [attr.aria-describedby]="describedBy()"
960
973
  [attr.aria-invalid]="showInvalid() ? 'true' : null"
961
974
  [attr.aria-required]="required() ? 'true' : null"
@@ -969,14 +982,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
969
982
  <span class="kt-switch__thumb"></span>
970
983
  </button>
971
984
 
972
- @if (label(); as labelText) {
973
- <label [id]="labelId()" [attr.for]="baseId()" class="kt-switch-label">
974
- {{ labelText }}
975
- @if (required()) {
976
- <span class="kt-switch-label__required" aria-hidden="true">*</span>
977
- }
978
- </label>
979
- }
985
+ <label [id]="labelId()" [attr.for]="baseId()" class="kt-switch-label">
986
+ <ng-content>{{ label() }}</ng-content>
987
+ @if (required()) {
988
+ <span class="kt-switch-label__required" aria-hidden="true">*</span>
989
+ }
990
+ </label>
980
991
  </div>
981
992
 
982
993
  @if (hint() && !showInvalid()) {
@@ -990,7 +1001,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
990
1001
  }
991
1002
  </div>
992
1003
  </div>
993
- `, styles: ["@layer kt-aaa.components{:host{display:block}.kt-switch-field{display:flex;flex-direction:column;gap:var(--field-gap, .375rem)}.kt-switch-row{display:flex;align-items:center;gap:var(--field-control-gap, .5rem)}.kt-switch{position:relative;display:inline-flex;align-items:center;box-sizing:border-box;inline-size:var(--switch-width, 2.75rem);block-size:var(--switch-height, 1.5rem);padding:var(--switch-padding, 2px);border-radius:var(--switch-radius, 999px);border:var(--switch-border-width, 2px) solid var(--switch-border-color, var(--field-border-color, var(--kt-outline, #c4c7c5)));background-color:var(--switch-bg, var(--field-bg, var(--kt-surface, #ffffff)));cursor:pointer;outline:none;box-shadow:var(--switch-shadow, var(--field-shadow, none));transition:var( --switch-transition, background-color .2s cubic-bezier(.4, 0, .2, 1), border-color .2s cubic-bezier(.4, 0, .2, 1), box-shadow .2s ease )}.kt-switch:after{content:\"\";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:100%;height:44px}.kt-switch__thumb{display:block;inline-size:var(--switch-thumb-size, 1rem);block-size:var(--switch-thumb-size, 1rem);border-radius:var(--switch-thumb-radius, 50%);background-color:var(--switch-thumb-bg, var(--kt-outline-strong, #5f6368));box-shadow:var(--switch-thumb-shadow, 0 1px 3px rgba(0, 0, 0, .2));transition:var( --switch-thumb-transition, transform .2s cubic-bezier(.34, 1.56, .64, 1), background-color .2s ease );transform:translate(0)}.kt-switch[aria-checked=true]{background-color:var(--switch-bg-active, var(--kt-primary, #0b57d0));border-color:var(--switch-border-color-active, var(--kt-primary, #0b57d0));box-shadow:var( --switch-shadow-active, 0 0 8px color-mix(in srgb, var(--switch-bg-active, var(--kt-primary, #0b57d0)) 50%, transparent) )}.kt-switch[aria-checked=true] .kt-switch__thumb{background-color:var(--switch-thumb-bg-active, #ffffff);transform:translate(calc(var(--switch-width, 2.75rem) - var(--switch-thumb-size, 1rem) - (var(--switch-padding, 2px) * 2) - (var(--switch-border-width, 2px) * 2)))}.kt-switch:hover:not(:disabled){border-color:var(--switch-border-color-hover, var(--field-border-color-hover, var(--kt-outline-strong, #5f6368)));box-shadow:var(--switch-shadow-hover, var(--field-shadow-hover, var(--switch-shadow, var(--field-shadow, none))))}.kt-switch[aria-checked=true]:hover:not(:disabled){background-color:var(--switch-bg-active-hover, color-mix(in srgb, var(--kt-primary, #0b57d0) 90%, black));border-color:var(--switch-border-color-active-hover, color-mix(in srgb, var(--kt-primary, #0b57d0) 90%, black))}.kt-switch:focus-visible{outline:var(--kt-focus-ring-width, 2px) solid var(--kt-focus-ring-color, #0b57d0);outline-offset:var(--switch-focus-ring-offset, 2px);box-shadow:var(--switch-shadow-focus, var(--field-shadow-focus, var(--switch-shadow, var(--field-shadow, none))))}.kt-switch:disabled{cursor:not-allowed;opacity:.5;background-color:var(--field-disabled-bg, #f1f3f4);border-color:var(--field-border-color, #c4c7c5)}.kt-switch:disabled .kt-switch__thumb{background-color:var(--kt-outline, #c4c7c5);box-shadow:none}.kt-switch-field--invalid .kt-switch{border-color:var(--field-error-color, var(--kt-danger, #b3261e))}.kt-switch-field--invalid .kt-switch[aria-checked=true]{background-color:var(--field-error-color, var(--kt-danger, #b3261e));border-color:var(--field-error-color, var(--kt-danger, #b3261e))}.kt-switch-label{font-size:var(--field-label-font-size, .875rem);font-weight:var(--field-label-weight, 500);color:var(--field-label-color, inherit);cursor:pointer;-webkit-user-select:none;user-select:none}.kt-switch-field--disabled .kt-switch-label{cursor:not-allowed;color:var(--field-hint-color, #5f6368);opacity:.6}.kt-switch-label__required{margin-inline-start:.125rem;color:var(--field-required-color, #8c1d18)}.kt-switch-hint{margin:0;font-size:var(--field-hint-font-size, .8125rem);color:var(--field-hint-color, #474747)}.kt-switch-error{margin:0;display:flex;flex-direction:column;font-size:var(--field-hint-font-size, .8125rem);color:var(--field-error-color, #8c1d18)}.kt-switch-error-message{animation:var(--field-error-animation, none)}@media(prefers-reduced-motion:reduce){.kt-switch,.kt-switch__thumb{transition:none}.kt-switch-error-message{animation:none}}}\n"] }]
1004
+ `, styles: ["@layer kt-aaa.components{:host{display:block}.kt-switch-field{display:flex;flex-direction:column;gap:var(--field-gap, .375rem)}.kt-switch-row{display:flex;align-items:center;gap:var(--field-control-gap, .5rem)}.kt-switch{position:relative;display:inline-flex;align-items:center;box-sizing:border-box;inline-size:var(--switch-width, 2.75rem);block-size:var(--switch-height, 1.5rem);padding:var(--switch-padding, 2px);border-radius:var(--switch-radius, 999px);border:var(--switch-border-width, 2px) solid var(--switch-border-color, var(--field-border-color, var(--kt-outline, #c4c7c5)));background-color:var(--switch-bg, var(--field-bg, var(--kt-surface, #ffffff)));cursor:pointer;outline:none;box-shadow:var(--switch-shadow, var(--field-shadow, none));transition:var( --switch-transition, background-color .2s cubic-bezier(.4, 0, .2, 1), border-color .2s cubic-bezier(.4, 0, .2, 1), box-shadow .2s ease )}.kt-switch:after{content:\"\";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:100%;height:44px}.kt-switch__thumb{display:block;inline-size:var(--switch-thumb-size, 1rem);block-size:var(--switch-thumb-size, 1rem);border-radius:var(--switch-thumb-radius, 50%);background-color:var(--switch-thumb-bg, var(--kt-outline-strong, #5f6368));box-shadow:var(--switch-thumb-shadow, 0 1px 3px rgba(0, 0, 0, .2));transition:var( --switch-thumb-transition, transform .2s cubic-bezier(.34, 1.56, .64, 1), background-color .2s ease );transform:translate(0)}.kt-switch[aria-checked=true]{background-color:var(--switch-bg-active, var(--kt-primary, #0b57d0));border-color:var(--switch-border-color-active, var(--kt-primary, #0b57d0));box-shadow:var( --switch-shadow-active, 0 0 8px color-mix(in srgb, var(--switch-bg-active, var(--kt-primary, #0b57d0)) 50%, transparent) )}.kt-switch[aria-checked=true] .kt-switch__thumb{background-color:var(--switch-thumb-bg-active, #ffffff);transform:translate(calc(var(--switch-width, 2.75rem) - var(--switch-thumb-size, 1rem) - (var(--switch-padding, 2px) * 2) - (var(--switch-border-width, 2px) * 2)))}.kt-switch:hover:not(:disabled){border-color:var(--switch-border-color-hover, var(--field-border-color-hover, var(--kt-outline-strong, #5f6368)));box-shadow:var(--switch-shadow-hover, var(--field-shadow-hover, var(--switch-shadow, var(--field-shadow, none))))}.kt-switch[aria-checked=true]:hover:not(:disabled){background-color:var(--switch-bg-active-hover, color-mix(in srgb, var(--kt-primary, #0b57d0) 90%, black));border-color:var(--switch-border-color-active-hover, color-mix(in srgb, var(--kt-primary, #0b57d0) 90%, black))}.kt-switch:focus-visible{outline:var(--kt-focus-ring-width, 2px) solid var(--kt-focus-ring-color, #0b57d0);outline-offset:var(--switch-focus-ring-offset, 2px);box-shadow:var(--switch-shadow-focus, var(--field-shadow-focus, var(--switch-shadow, var(--field-shadow, none))))}.kt-switch:disabled{cursor:not-allowed;opacity:.5;background-color:var(--field-disabled-bg, #f1f3f4);border-color:var(--field-border-color, #c4c7c5)}.kt-switch:disabled .kt-switch__thumb{background-color:var(--kt-outline, #c4c7c5);box-shadow:none}.kt-switch-field--invalid .kt-switch{border-color:var(--field-error-color, var(--kt-danger, #b3261e))}.kt-switch-field--invalid .kt-switch[aria-checked=true]{background-color:var(--field-error-color, var(--kt-danger, #b3261e));border-color:var(--field-error-color, var(--kt-danger, #b3261e))}.kt-switch-label{font-size:var(--field-label-font-size, .875rem);font-weight:var(--field-label-weight, 500);color:var(--field-label-color, inherit);cursor:pointer;-webkit-user-select:none;user-select:none}.kt-switch-label:empty{display:none}.kt-switch-field--disabled .kt-switch-label{cursor:not-allowed;color:var(--field-hint-color, #5f6368);opacity:.6}.kt-switch-label__required{margin-inline-start:.125rem;color:var(--field-required-color, #8c1d18)}.kt-switch-hint{margin:0;font-size:var(--field-hint-font-size, .8125rem);color:var(--field-hint-color, #474747)}.kt-switch-error{margin:0;display:flex;flex-direction:column;font-size:var(--field-hint-font-size, .8125rem);color:var(--field-error-color, #8c1d18)}.kt-switch-error-message{animation:var(--field-error-animation, none)}@media(prefers-reduced-motion:reduce){.kt-switch,.kt-switch__thumb{transition:none}.kt-switch-error-message{animation:none}}}\n"] }]
994
1005
  }], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], dirty: [{ type: i0.Input, args: [{ isSignal: true, alias: "dirty", required: false }] }], pending: [{ type: i0.Input, args: [{ isSignal: true, alias: "pending", required: false }] }], errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], errorMatcher: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMatcher", required: false }] }], showAllErrors: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAllErrors", required: false }] }], switchBtn: [{ type: i0.ViewChild, args: ['switchBtn', { isSignal: true }] }] } });
995
1006
 
996
1007
  /**
@@ -1956,6 +1967,13 @@ class KtBaseSelect {
1956
1967
  hideLabel = input(this.fieldConfig?.hideLabel ?? false, { ...(ngDevMode ? { debugName: "hideLabel" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1957
1968
  /** Masquer visuellement le bloc d'erreur. @default KT_FIELD_CONFIG.hideErrors ?? false */
1958
1969
  hideErrors = input(this.fieldConfig?.hideErrors ?? false, { ...(ngDevMode ? { debugName: "hideErrors" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1970
+ // --- Effacement depuis le champ (clearable) ---
1971
+ /** Bouton « effacer » (×) sur le champ quand une valeur est sélectionnée (même contrat que
1972
+ `clearable` de BaseInputField ; single vide la sélection, multi vide toute la sélection). @default false */
1973
+ clearable = input(false, { ...(ngDevMode ? { debugName: "clearable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1974
+ /** Libellé i18n du bouton « effacer ». @default 'Clear' (ou KT_FIELD_CONFIG.clearLabel) */
1975
+ clearLabel = input(this.fieldConfig?.clearLabel ?? 'Clear', /* @ts-ignore */
1976
+ ...(ngDevMode ? [{ debugName: "clearLabel" }] : /* istanbul ignore next */ []));
1959
1977
  // --- Filtrage (champ de recherche dans le popup, opt-in) ---
1960
1978
  /** Affiche un champ de recherche en tête du popup (desktop) / de la sheet (téléphone).
1961
1979
  Pour les listes longues ; le texte tapé ne sert qu'à filtrer (réinitialisé à la fermeture). @default false */
@@ -2108,10 +2126,12 @@ class KtBaseSelect {
2108
2126
  return;
2109
2127
  if (this.expanded()) {
2110
2128
  el.classList.remove('kt-select__popup--closing');
2111
- el.style.translate = ''; // efface un éventuel translate résiduel d'un drag-to-dismiss précédent
2112
2129
  el.style.setProperty('position-anchor', this.anchorName);
2113
2130
  el.showPopover?.();
2114
2131
  this.popoverShown = true;
2132
+ // Sheet (ADR-0005) : l'animation d'entrée est le scroll programmatique vers le snap ouvert.
2133
+ if (this.compact() && this.sheetState === 'idle')
2134
+ this.openSheetByScroll(el);
2115
2135
  // Desktop filtrable : le champ de recherche prend le focus à l'ouverture (pattern
2116
2136
  // SelectPanel). Pas sur téléphone : le clavier virtuel recouvrirait la bottom-sheet.
2117
2137
  if (this.filterable() && !this.compact())
@@ -2121,6 +2141,19 @@ class KtBaseSelect {
2121
2141
  this.animateAndCloseSelect(el);
2122
2142
  }
2123
2143
  });
2144
+ // Sheet (ADR-0005) : détection du snap « fermé » (scroll) + garde molette (wheel non-passif).
2145
+ // Attachés une fois par élément popup ; inertes hors mode compact (le scroll ne bulle pas,
2146
+ // la garde s'auto-neutralise). preserveContent garde l'élément vivant sur mobile.
2147
+ effect(() => {
2148
+ const el = this.popupEl()?.nativeElement;
2149
+ if (!el || el === this.sheetEl)
2150
+ return;
2151
+ this.sheetEl?.removeEventListener('scroll', this.onSheetScroll);
2152
+ this.sheetEl?.removeEventListener('wheel', this.onSheetWheel);
2153
+ this.sheetEl = el;
2154
+ el.addEventListener('scroll', this.onSheetScroll);
2155
+ el.addEventListener('wheel', this.onSheetWheel, { passive: false });
2156
+ });
2124
2157
  // Filtre éphémère : réinitialisé à la fermeture (liste complète à la réouverture).
2125
2158
  effect(() => {
2126
2159
  if (this.expanded())
@@ -2133,7 +2166,9 @@ class KtBaseSelect {
2133
2166
  });
2134
2167
  this.destroyRef.onDestroy(() => {
2135
2168
  clearTimeout(this.announceTimer);
2136
- this.sheetDrag.destroy();
2169
+ clearTimeout(this.sheetCloseTimer);
2170
+ this.sheetEl?.removeEventListener('scroll', this.onSheetScroll);
2171
+ this.sheetEl?.removeEventListener('wheel', this.onSheetWheel);
2137
2172
  this.setBodyScrollLock(false);
2138
2173
  });
2139
2174
  // Préserve le contenu du template sur mobile pour permettre l'animation de sortie
@@ -2175,19 +2210,25 @@ class KtBaseSelect {
2175
2210
  this.doc.removeEventListener('pointerdown', onPointerDown);
2176
2211
  });
2177
2212
  }
2178
- // Fait défiler la liste pour afficher l'option active lors de la navigation au clavier (mode activedescendant).
2213
+ // Fait défiler la liste pour afficher l'option active lors de la navigation au clavier (mode
2214
+ // activedescendant). Défilement SCOPÉ à la listbox (sémantique « nearest » manuelle) — PAS
2215
+ // scrollIntoView : il scrolle aussi les ANCÊTRES, dont le popup sheet scroll-snap (ADR-0005),
2216
+ // ce qui annulait le scroll d'entrée de la sheet et la re-snappait fermée.
2179
2217
  effect(() => {
2180
2218
  const activeId = this.listboxDir()?.activeDescendant();
2181
2219
  if (!this.expanded() || !activeId)
2182
2220
  return;
2183
2221
  requestAnimationFrame(() => {
2184
2222
  const listbox = this.listboxEl()?.nativeElement;
2185
- if (!listbox)
2223
+ const activeEl = listbox?.querySelector('.kt-select__option--active');
2224
+ if (!listbox || !activeEl)
2186
2225
  return;
2187
- const activeEl = listbox.querySelector('.kt-select__option--active');
2188
- // `?.` : scrollIntoView n'est pas implémenté par tous les environnements de test (jsdom) ;
2189
- // sans ce garde, un consommateur testant le Select en jsdom subit un crash en rAF.
2190
- activeEl?.scrollIntoView?.({ block: 'nearest' });
2226
+ const lbRect = listbox.getBoundingClientRect();
2227
+ const optRect = activeEl.getBoundingClientRect();
2228
+ if (optRect.top < lbRect.top)
2229
+ listbox.scrollTop += optRect.top - lbRect.top;
2230
+ else if (optRect.bottom > lbRect.bottom)
2231
+ listbox.scrollTop += optRect.bottom - lbRect.bottom;
2191
2232
  });
2192
2233
  });
2193
2234
  if (isDevMode()) {
@@ -2297,6 +2338,7 @@ class KtBaseSelect {
2297
2338
  /** Fermeture synchrone du Popover (l'effect, différé, ne re-cachera pas : flag popoverShown). */
2298
2339
  closePopupNow() {
2299
2340
  this.expanded.set(false);
2341
+ this.resetSheetState();
2300
2342
  if (!this.popoverShown)
2301
2343
  return;
2302
2344
  const el = this.popupEl()?.nativeElement;
@@ -2304,18 +2346,80 @@ class KtBaseSelect {
2304
2346
  el?.hidePopover?.();
2305
2347
  this.popoverShown = false;
2306
2348
  }
2307
- // --- Drag-to-dismiss de la bottom-sheet (téléphone) ---
2308
- // Geste DOUBLÉ par le bouton Fermer + tap-extérieur + Échap (WCAG 2.5.1). Logique FACTORISÉE
2309
- // avec le mode `sheet` du Dialog via createKtSheetDrag (@ktortu/aaa).
2310
- sheetDrag = createKtSheetDrag({
2311
- pane: () => this.popupEl()?.nativeElement.querySelector('.kt-select__sheet-card') ?? null,
2312
- onDismiss: () => this.expanded.set(false),
2313
- draggingClass: 'kt-select__popup--dragging',
2314
- });
2315
- onDragStart(event) {
2316
- if (!this.compact())
2317
- return; // glissement actif sur écran compact uniquement
2318
- this.sheetDrag.start(event);
2349
+ // --- Bottom-sheet scroll-snap (téléphone, ADR-0005) ---
2350
+ // Le popup est un scroller à snap (spacer « fermé » / carte « ouvert ») : le drag-to-dismiss
2351
+ // « attrapable partout » et l'arbitrage avec la listbox interne sont NATIFS (latching du
2352
+ // navigateur). Le JS ne fait plus que : l'entrée/sortie (scrolls programmatiques), la
2353
+ // détection du repos au snap « fermé », et la garde molette. Geste DOUBLÉ par le bouton
2354
+ // Fermer + tap-scrim + Échap (WCAG 2.5.1 / 2.5.7).
2355
+ sheetEl = null;
2356
+ sheetState = 'idle';
2357
+ /** Armé quand l'ouverture a dépassé 50px : un repos à ~0 est alors forcément le snap « fermé »
2358
+ (et non la position initiale) — même logique que le prototype du spike. */
2359
+ sheetArmed = false;
2360
+ sheetCloseTimer;
2361
+ resetSheetState() {
2362
+ this.sheetState = 'idle';
2363
+ this.sheetArmed = false;
2364
+ clearTimeout(this.sheetCloseTimer);
2365
+ }
2366
+ prefersReducedMotion() {
2367
+ return this.doc.defaultView?.matchMedia?.('(prefers-reduced-motion: reduce)').matches ?? false;
2368
+ }
2369
+ /** Entrée de la sheet : position « fermée » puis scroll animé vers le snap « ouvert ». */
2370
+ openSheetByScroll(el) {
2371
+ if (!isPlatformBrowser(this.platformId))
2372
+ return;
2373
+ this.sheetState = 'opening';
2374
+ this.sheetArmed = false;
2375
+ el.scrollTop = 0;
2376
+ const behavior = this.prefersReducedMotion() ? 'auto' : 'smooth';
2377
+ requestAnimationFrame(() => {
2378
+ el.scrollTo?.({ top: el.scrollHeight - el.clientHeight, behavior });
2379
+ });
2380
+ }
2381
+ /** Détection du snap « fermé » par position de scroll (ni scrollsnapchange ni scrollend :
2382
+ non interopérables — cf. ADR-0005). Un geste de l'utilisateur qui amène la sheet au repos
2383
+ à 0 EST la fermeture ; les fermetures programmatiques y convergent aussi. */
2384
+ onSheetScroll = () => {
2385
+ const el = this.sheetEl;
2386
+ if (!el || !this.compact() || this.sheetState === 'idle')
2387
+ return;
2388
+ const top = el.scrollTop;
2389
+ if (top > 50)
2390
+ this.sheetArmed = true;
2391
+ if (this.sheetState === 'opening' && top >= el.scrollHeight - el.clientHeight - 2) {
2392
+ this.sheetState = 'open';
2393
+ return;
2394
+ }
2395
+ if (this.sheetArmed && top <= 1)
2396
+ this.finalizeSheetClose();
2397
+ };
2398
+ /** La molette ne ferme JAMAIS la sheet (pas de geste souris — ADR-0005) : seule la listbox
2399
+ peut consommer, dans les limites de son propre défilement. */
2400
+ onSheetWheel = (event) => {
2401
+ if (!this.compact() || !this.expanded())
2402
+ return;
2403
+ const listbox = this.listboxEl()?.nativeElement;
2404
+ if (listbox?.contains(event.target)) {
2405
+ const canScrollDown = listbox.scrollTop + listbox.clientHeight < listbox.scrollHeight - 1;
2406
+ const canScrollUp = listbox.scrollTop > 0;
2407
+ if ((event.deltaY > 0 && canScrollDown) || (event.deltaY < 0 && canScrollUp))
2408
+ return;
2409
+ }
2410
+ event.preventDefault();
2411
+ };
2412
+ finalizeSheetClose() {
2413
+ this.resetSheetState();
2414
+ const el = this.sheetEl;
2415
+ if (this.popoverShown) {
2416
+ el?.hidePopover?.();
2417
+ el?.classList.remove('kt-select__popup--closing');
2418
+ this.popoverShown = false;
2419
+ }
2420
+ // Dismissal par geste : synchronise le signal (les fermetures programmatiques l'ont déjà fait).
2421
+ if (this.expanded())
2422
+ this.expanded.set(false);
2319
2423
  }
2320
2424
  animateAndCloseSelect(el) {
2321
2425
  if (!this.compact() || !isPlatformBrowser(this.platformId)) {
@@ -2323,44 +2427,26 @@ class KtBaseSelect {
2323
2427
  this.popoverShown = false;
2324
2428
  return;
2325
2429
  }
2326
- el.classList.add('kt-select__popup--closing');
2327
- const card = el.querySelector('.kt-select__sheet-card') || el;
2328
- // Récupérer la durée de transition configurée en CSS (ex: "150ms" ou "0.2s")
2329
- const styles = window.getComputedStyle(card);
2330
- const durationStr = styles.transitionDuration || '0s';
2331
- const durationMs = parseFloat(durationStr) * (durationStr.includes('ms') ? 1 : 1000);
2332
- if (durationMs === 0) {
2333
- el.hidePopover?.();
2334
- el.classList.remove('kt-select__popup--closing');
2335
- this.popoverShown = false;
2430
+ // Sheet : sortie = scroll programmatique vers le snap « fermé » ; onSheetScroll finalise au
2431
+ // repos. Déjà en bas (jsdom, reduced-motion instantané, geste déjà abouti) : finalise direct.
2432
+ if (el.scrollTop <= 1) {
2433
+ this.finalizeSheetClose();
2336
2434
  return;
2337
2435
  }
2338
- // Écouter la fin de la transition sur la propriété 'translate'
2339
- const onTransitionEnd = (event) => {
2340
- if (event.target === card && event.propertyName === 'translate') {
2341
- card.removeEventListener('transitionend', onTransitionEnd);
2342
- if (this.expanded())
2343
- return;
2344
- el.hidePopover?.();
2345
- el.classList.remove('kt-select__popup--closing');
2346
- this.popoverShown = false;
2347
- }
2348
- };
2349
- card.addEventListener('transitionend', onTransitionEnd);
2350
- // Sécurité (au cas où la transition n'aboutirait pas)
2351
- setTimeout(() => {
2352
- card.removeEventListener('transitionend', onTransitionEnd);
2353
- if (this.expanded())
2354
- return;
2355
- if (this.popoverShown) {
2356
- el.hidePopover?.();
2357
- el.classList.remove('kt-select__popup--closing');
2358
- this.popoverShown = false;
2359
- }
2360
- }, durationMs + 50);
2436
+ this.sheetState = 'closing';
2437
+ this.sheetArmed = true;
2438
+ el.classList.add('kt-select__popup--closing'); // fondu du scrim pendant la sortie
2439
+ el.scrollTo?.({ top: 0, behavior: this.prefersReducedMotion() ? 'auto' : 'smooth' });
2440
+ // Sécurité (scroll lisse interrompu, moteur sans événement final) — même filet que l'ancien
2441
+ // transitionend : on finalise si la fermeture est toujours d'actualité.
2442
+ clearTimeout(this.sheetCloseTimer);
2443
+ this.sheetCloseTimer = setTimeout(() => {
2444
+ if (!this.expanded() && this.popoverShown)
2445
+ this.finalizeSheetClose();
2446
+ }, 400);
2361
2447
  }
2362
2448
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtBaseSelect, deps: [], target: i0.ɵɵFactoryTarget.Directive });
2363
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "22.0.1", type: KtBaseSelect, isStandalone: true, inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null }, optionLabel: { classPropertyName: "optionLabel", publicName: "optionLabel", isSignal: true, isRequired: false, transformFunction: null }, optionValue: { classPropertyName: "optionValue", publicName: "optionValue", isSignal: true, isRequired: false, transformFunction: null }, optionDisabled: { classPropertyName: "optionDisabled", publicName: "optionDisabled", isSignal: true, isRequired: false, transformFunction: null }, compareWith: { classPropertyName: "compareWith", publicName: "compareWith", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, dirty: { classPropertyName: "dirty", publicName: "dirty", isSignal: true, isRequired: false, transformFunction: null }, pending: { classPropertyName: "pending", publicName: "pending", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, helpText: { classPropertyName: "helpText", publicName: "helpText", isSignal: true, isRequired: false, transformFunction: null }, helpLabel: { classPropertyName: "helpLabel", publicName: "helpLabel", isSignal: true, isRequired: false, transformFunction: null }, customDescribedBy: { classPropertyName: "customDescribedBy", publicName: "customDescribedBy", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, errorMatcher: { classPropertyName: "errorMatcher", publicName: "errorMatcher", isSignal: true, isRequired: false, transformFunction: null }, appearance: { classPropertyName: "appearance", publicName: "appearance", isSignal: true, isRequired: false, transformFunction: null }, floatLabel: { classPropertyName: "floatLabel", publicName: "floatLabel", isSignal: true, isRequired: false, transformFunction: null }, hideLabel: { classPropertyName: "hideLabel", publicName: "hideLabel", isSignal: true, isRequired: false, transformFunction: null }, hideErrors: { classPropertyName: "hideErrors", publicName: "hideErrors", isSignal: true, isRequired: false, transformFunction: null }, filterable: { classPropertyName: "filterable", publicName: "filterable", isSignal: true, isRequired: false, transformFunction: null }, filterPlaceholder: { classPropertyName: "filterPlaceholder", publicName: "filterPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, filterLabel: { classPropertyName: "filterLabel", publicName: "filterLabel", isSignal: true, isRequired: false, transformFunction: null }, filterFn: { classPropertyName: "filterFn", publicName: "filterFn", isSignal: true, isRequired: false, transformFunction: null }, maxVisibleOptions: { classPropertyName: "maxVisibleOptions", publicName: "maxVisibleOptions", isSignal: true, isRequired: false, transformFunction: null }, truncatedResultsText: { classPropertyName: "truncatedResultsText", publicName: "truncatedResultsText", isSignal: true, isRequired: false, transformFunction: null }, truncatedResultsAnnouncement: { classPropertyName: "truncatedResultsAnnouncement", publicName: "truncatedResultsAnnouncement", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { helpClick: "helpClick", touched: "touchedChange" }, host: { listeners: { "keydown": "onHostKeydown($event)" } }, viewQueries: [{ propertyName: "triggerEl", first: true, predicate: ["trigger"], descendants: true, isSignal: true }, { propertyName: "popupEl", first: true, predicate: ["popup"], descendants: true, isSignal: true }, { propertyName: "filterInputEl", first: true, predicate: ["filterInput"], descendants: true, isSignal: true }, { propertyName: "listboxEl", first: true, predicate: ["listboxEl"], descendants: true, isSignal: true }, { propertyName: "listboxDir", first: true, predicate: Listbox, descendants: true, isSignal: true }, { propertyName: "comboboxDir", first: true, predicate: Combobox, descendants: true, isSignal: true }], ngImport: i0 });
2449
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "22.0.1", type: KtBaseSelect, isStandalone: true, inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null }, optionLabel: { classPropertyName: "optionLabel", publicName: "optionLabel", isSignal: true, isRequired: false, transformFunction: null }, optionValue: { classPropertyName: "optionValue", publicName: "optionValue", isSignal: true, isRequired: false, transformFunction: null }, optionDisabled: { classPropertyName: "optionDisabled", publicName: "optionDisabled", isSignal: true, isRequired: false, transformFunction: null }, compareWith: { classPropertyName: "compareWith", publicName: "compareWith", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, dirty: { classPropertyName: "dirty", publicName: "dirty", isSignal: true, isRequired: false, transformFunction: null }, pending: { classPropertyName: "pending", publicName: "pending", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, helpText: { classPropertyName: "helpText", publicName: "helpText", isSignal: true, isRequired: false, transformFunction: null }, helpLabel: { classPropertyName: "helpLabel", publicName: "helpLabel", isSignal: true, isRequired: false, transformFunction: null }, customDescribedBy: { classPropertyName: "customDescribedBy", publicName: "customDescribedBy", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, errorMatcher: { classPropertyName: "errorMatcher", publicName: "errorMatcher", isSignal: true, isRequired: false, transformFunction: null }, appearance: { classPropertyName: "appearance", publicName: "appearance", isSignal: true, isRequired: false, transformFunction: null }, floatLabel: { classPropertyName: "floatLabel", publicName: "floatLabel", isSignal: true, isRequired: false, transformFunction: null }, hideLabel: { classPropertyName: "hideLabel", publicName: "hideLabel", isSignal: true, isRequired: false, transformFunction: null }, hideErrors: { classPropertyName: "hideErrors", publicName: "hideErrors", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, clearLabel: { classPropertyName: "clearLabel", publicName: "clearLabel", isSignal: true, isRequired: false, transformFunction: null }, filterable: { classPropertyName: "filterable", publicName: "filterable", isSignal: true, isRequired: false, transformFunction: null }, filterPlaceholder: { classPropertyName: "filterPlaceholder", publicName: "filterPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, filterLabel: { classPropertyName: "filterLabel", publicName: "filterLabel", isSignal: true, isRequired: false, transformFunction: null }, filterFn: { classPropertyName: "filterFn", publicName: "filterFn", isSignal: true, isRequired: false, transformFunction: null }, maxVisibleOptions: { classPropertyName: "maxVisibleOptions", publicName: "maxVisibleOptions", isSignal: true, isRequired: false, transformFunction: null }, truncatedResultsText: { classPropertyName: "truncatedResultsText", publicName: "truncatedResultsText", isSignal: true, isRequired: false, transformFunction: null }, truncatedResultsAnnouncement: { classPropertyName: "truncatedResultsAnnouncement", publicName: "truncatedResultsAnnouncement", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { helpClick: "helpClick", touched: "touchedChange" }, host: { listeners: { "keydown": "onHostKeydown($event)" } }, viewQueries: [{ propertyName: "triggerEl", first: true, predicate: ["trigger"], descendants: true, isSignal: true }, { propertyName: "popupEl", first: true, predicate: ["popup"], descendants: true, isSignal: true }, { propertyName: "filterInputEl", first: true, predicate: ["filterInput"], descendants: true, isSignal: true }, { propertyName: "listboxEl", first: true, predicate: ["listboxEl"], descendants: true, isSignal: true }, { propertyName: "listboxDir", first: true, predicate: Listbox, descendants: true, isSignal: true }, { propertyName: "comboboxDir", first: true, predicate: Combobox, descendants: true, isSignal: true }], ngImport: i0 });
2364
2450
  }
2365
2451
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtBaseSelect, decorators: [{
2366
2452
  type: Directive,
@@ -2369,7 +2455,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
2369
2455
  '(keydown)': 'onHostKeydown($event)',
2370
2456
  },
2371
2457
  }]
2372
- }], ctorParameters: () => [], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], optionLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionLabel", required: false }] }], optionValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionValue", required: false }] }], optionDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionDisabled", required: false }] }], compareWith: [{ type: i0.Input, args: [{ isSignal: true, alias: "compareWith", required: false }] }], helpClick: [{ type: i0.Output, args: ["helpClick"] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], dirty: [{ type: i0.Input, args: [{ isSignal: true, alias: "dirty", required: false }] }], pending: [{ type: i0.Input, args: [{ isSignal: true, alias: "pending", required: false }] }], errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], helpText: [{ type: i0.Input, args: [{ isSignal: true, alias: "helpText", required: false }] }], helpLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "helpLabel", required: false }] }], customDescribedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "customDescribedBy", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], errorMatcher: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMatcher", required: false }] }], appearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "appearance", required: false }] }], floatLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "floatLabel", required: false }] }], hideLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideLabel", required: false }] }], hideErrors: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideErrors", required: false }] }], filterable: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterable", required: false }] }], filterPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterPlaceholder", required: false }] }], filterLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterLabel", required: false }] }], filterFn: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterFn", required: false }] }], maxVisibleOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxVisibleOptions", required: false }] }], truncatedResultsText: [{ type: i0.Input, args: [{ isSignal: true, alias: "truncatedResultsText", required: false }] }], truncatedResultsAnnouncement: [{ type: i0.Input, args: [{ isSignal: true, alias: "truncatedResultsAnnouncement", required: false }] }], triggerEl: [{ type: i0.ViewChild, args: ['trigger', { isSignal: true }] }], popupEl: [{ type: i0.ViewChild, args: ['popup', { isSignal: true }] }], filterInputEl: [{ type: i0.ViewChild, args: ['filterInput', { isSignal: true }] }], listboxEl: [{ type: i0.ViewChild, args: ['listboxEl', { isSignal: true }] }], listboxDir: [{ type: i0.ViewChild, args: [i0.forwardRef(() => Listbox), { isSignal: true }] }], comboboxDir: [{ type: i0.ViewChild, args: [i0.forwardRef(() => Combobox), { isSignal: true }] }] } });
2458
+ }], ctorParameters: () => [], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], optionLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionLabel", required: false }] }], optionValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionValue", required: false }] }], optionDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionDisabled", required: false }] }], compareWith: [{ type: i0.Input, args: [{ isSignal: true, alias: "compareWith", required: false }] }], helpClick: [{ type: i0.Output, args: ["helpClick"] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], dirty: [{ type: i0.Input, args: [{ isSignal: true, alias: "dirty", required: false }] }], pending: [{ type: i0.Input, args: [{ isSignal: true, alias: "pending", required: false }] }], errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], helpText: [{ type: i0.Input, args: [{ isSignal: true, alias: "helpText", required: false }] }], helpLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "helpLabel", required: false }] }], customDescribedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "customDescribedBy", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], errorMatcher: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMatcher", required: false }] }], appearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "appearance", required: false }] }], floatLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "floatLabel", required: false }] }], hideLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideLabel", required: false }] }], hideErrors: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideErrors", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], clearLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearLabel", required: false }] }], filterable: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterable", required: false }] }], filterPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterPlaceholder", required: false }] }], filterLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterLabel", required: false }] }], filterFn: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterFn", required: false }] }], maxVisibleOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxVisibleOptions", required: false }] }], truncatedResultsText: [{ type: i0.Input, args: [{ isSignal: true, alias: "truncatedResultsText", required: false }] }], truncatedResultsAnnouncement: [{ type: i0.Input, args: [{ isSignal: true, alias: "truncatedResultsAnnouncement", required: false }] }], triggerEl: [{ type: i0.ViewChild, args: ['trigger', { isSignal: true }] }], popupEl: [{ type: i0.ViewChild, args: ['popup', { isSignal: true }] }], filterInputEl: [{ type: i0.ViewChild, args: ['filterInput', { isSignal: true }] }], listboxEl: [{ type: i0.ViewChild, args: ['listboxEl', { isSignal: true }] }], listboxDir: [{ type: i0.ViewChild, args: [i0.forwardRef(() => Listbox), { isSignal: true }] }], comboboxDir: [{ type: i0.ViewChild, args: [i0.forwardRef(() => Combobox), { isSignal: true }] }] } });
2373
2459
 
2374
2460
  /** Template de rendu d'une option, posé sur un `<ng-template>` projeté dans `kt-select`.
2375
2461
  L'input sert UNIQUEMENT à inférer `T` (re-bind de la liste d'options) ; `ngTemplateContextGuard`
@@ -2456,6 +2542,11 @@ class KtSelect extends KtBaseSelect {
2456
2542
  /** Fermer le popup après une sélection (sémantique single ; le multi reste ouvert). */
2457
2543
  closeOnSelect = computed(() => this.config?.closeOnSelect ?? true, /* @ts-ignore */
2458
2544
  ...(ngDevMode ? [{ debugName: "closeOnSelect" }] : /* istanbul ignore next */ []));
2545
+ /** Affiche le bouton « effacer » (×) sur le champ dès qu'une valeur est présente (`clearable`).
2546
+ Basé sur `value()` et non `selectedOption()` : une clé orpheline (option retirée des données)
2547
+ reste effaçable. */
2548
+ showClear = computed(() => this.clearable() && !this.disabled() && !this.readonly() && this.value() !== null, /* @ts-ignore */
2549
+ ...(ngDevMode ? [{ debugName: "showClear" }] : /* istanbul ignore next */ []));
2459
2550
  /** Option correspondant à la valeur courante (clé extraite, ou objet si `optionValue` est omis). */
2460
2551
  selectedOption = computed(() => {
2461
2552
  const v = this.value();
@@ -2508,12 +2599,19 @@ class KtSelect extends KtBaseSelect {
2508
2599
  this.refocusTriggerAfterFilterClose();
2509
2600
  }
2510
2601
  }
2602
+ /** Efface la sélection depuis le champ (bouton `clearable`) et rend le focus au trigger. */
2603
+ clearSelection() {
2604
+ if (!this.showClear())
2605
+ return;
2606
+ this.commitSelection(null);
2607
+ this.triggerEl()?.nativeElement.focus();
2608
+ }
2511
2609
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtSelect, deps: null, target: i0.ɵɵFactoryTarget.Component });
2512
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: KtSelect, isStandalone: true, selector: "kt-select", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", selectionChange: "selectionChange" }, queries: [{ propertyName: "optionDef", first: true, predicate: KtSelectOptionDef, descendants: true, isSignal: true }, { propertyName: "triggerDef", first: true, predicate: KtSelectTriggerDef, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"fieldErrors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n [hideLabel]=\"hideLabel()\"\n [hideErrors]=\"hideErrors()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div class=\"kt-select\" [class.kt-select--open]=\"expanded()\">\n <button\n #combobox=\"ngCombobox\"\n #trigger\n ngCombobox\n ktFieldControl\n type=\"button\"\n class=\"kt-field-box kt-select__trigger\"\n [(expanded)]=\"expanded\"\n [disabled]=\"disabled()\"\n [softDisabled]=\"false\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n [attr.data-filled]=\"selectedOption() ? '' : null\"\n [attr.data-pending]=\"pending() ? '' : null\"\n [attr.aria-busy]=\"pending() ? 'true' : null\"\n >\n <span class=\"kt-select__value\">\n @if (triggerDef(); as def) {\n <ng-container [ngTemplateOutlet]=\"def.template\" [ngTemplateOutletContext]=\"{ $implicit: selectedOption() }\" />\n } @else if (selectedOption(); as option) {\n {{ labelOf(option) }}\n } @else {\n <span class=\"kt-select__placeholder\">{{ resolvedPlaceholder() }}</span>\n }\n </span>\n <span class=\"kt-select__arrow\" aria-hidden=\"true\">arrow_drop_down</span>\n </button>\n\n <!-- Un seul Popover (top-layer). CSS @media : dropdown ancr\u00E9 (desktop) \u2194 bottom-sheet (t\u00E9l\u00E9phone).\n Pas de <dialog>.showModal() : ce combobox se ferme au blur, et showModal volerait le focus. -->\n <ng-template ngComboboxPopup [combobox]=\"combobox\" [popupType]=\"filterable() ? 'dialog' : 'listbox'\">\n <div #popup popover=\"manual\" class=\"kt-select__popup\" [class.kt-select__popup--sheet]=\"compact()\">\n @if (compact()) {\n <div class=\"kt-select__sheet-scrim\" aria-hidden=\"true\" (click)=\"expanded.set(false)\"></div>\n }\n <div class=\"kt-select__sheet-card\">\n @if (compact()) {\n <div\n class=\"kt-select__sheet-grab\"\n aria-hidden=\"true\"\n (pointerdown)=\"onDragStart($event)\"\n (mousedown)=\"$event.preventDefault()\"\n ></div>\n <header class=\"kt-select__sheet-header\">\n <span class=\"kt-select__sheet-title\">{{ label() }}</span>\n <button\n type=\"button\"\n class=\"kt-select__sheet-close\"\n [attr.aria-label]=\"resolvedCloseLabel()\"\n (click)=\"expanded.set(false)\"\n >\n <span class=\"kt-select__sheet-close-icon\" aria-hidden=\"true\">close</span>\n </button>\n </header>\n }\n @if (filterable()) {\n <!-- Mode filtrable : le widget combobox est le panneau ENTIER (champ + annonce + liste).\n Indispensable : un focus pos\u00E9 hors de l'\u00E9l\u00E9ment ngComboboxWidget ferme le popup\n (closePopupOnBlur de @angular/aria) \u2014 le champ doit donc vivre dans ce sous-arbre. -->\n <div\n ngComboboxWidget\n role=\"dialog\"\n class=\"kt-select__panel\"\n [id]=\"panelId\"\n [attr.aria-label]=\"label()\"\n [activeDescendant]=\"lb.activeDescendant()\"\n >\n <div class=\"kt-select__filter\">\n <input\n #filterInput\n type=\"search\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n aria-expanded=\"true\"\n class=\"kt-select__filter-input\"\n autocomplete=\"off\"\n [placeholder]=\"resolvedFilterPlaceholder()\"\n [attr.aria-label]=\"resolvedFilterLabel()\"\n [attr.aria-controls]=\"lb.id()\"\n [attr.aria-activedescendant]=\"lb.activeDescendant()\"\n [value]=\"filterText()\"\n (input)=\"onFilterInput($event)\"\n (keydown)=\"onFilterKeydown($event)\"\n />\n </div>\n <!-- Nombre de r\u00E9sultats annonc\u00E9 (diff\u00E9r\u00E9) aux lecteurs d'\u00E9cran : une liste qui\n r\u00E9tr\u00E9cit en silence est per\u00E7ue comme un bug (tests utilisateurs S. Higley). -->\n <div class=\"kt-select__sr-only\" role=\"status\" aria-live=\"polite\">{{ announcedCount() }}</div>\n <ul\n #lb=\"ngListbox\"\n #listboxEl\n ngListbox\n [focusMode]=\"compact() && !filterable() ? 'roving' : 'activedescendant'\"\n selectionMode=\"explicit\"\n class=\"kt-select__listbox\"\n [attr.aria-label]=\"label()\"\n [value]=\"listboxValue()\"\n (valueChange)=\"onListboxValueChange($event)\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n >\n @for (item of displayedOptions(); track keyOf(item)) {\n <li\n #opt=\"ngOption\"\n ngOption\n class=\"kt-select__option\"\n [value]=\"keyOf(item)\"\n [label]=\"labelOf(item)\"\n [disabled]=\"disabledOf(item)\"\n [class.kt-select__option--active]=\"opt.active()\"\n >\n @if (optionDef(); as def) {\n <ng-container\n [ngTemplateOutlet]=\"def.template\"\n [ngTemplateOutletContext]=\"{\n $implicit: item,\n selected: !!opt.selected(),\n active: opt.active(),\n }\"\n />\n } @else {\n {{ labelOf(item) }}\n }\n </li>\n } @empty {\n <li class=\"kt-select__empty\" role=\"option\" aria-disabled=\"true\" aria-selected=\"false\">\n {{ resolvedEmptyText() }}\n </li>\n }\n @if (filterable() && filteredOptions().length > maxVisibleOptions()) {\n <li class=\"kt-select__truncated-info\" role=\"option\" aria-disabled=\"true\" aria-selected=\"false\">\n {{ resolvedTruncatedResultsText()(maxVisibleOptions(), filteredOptions().length) }}\n </li>\n }\n </ul>\n </div>\n } @else {\n <ul\n #listbox=\"ngListbox\"\n #listboxEl\n ngComboboxWidget\n ngListbox\n [focusMode]=\"compact() ? 'roving' : 'activedescendant'\"\n selectionMode=\"explicit\"\n class=\"kt-select__listbox\"\n [attr.aria-label]=\"label()\"\n [value]=\"listboxValue()\"\n (valueChange)=\"onListboxValueChange($event)\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n [activeDescendant]=\"listbox.activeDescendant()\"\n >\n @for (item of options(); track keyOf(item)) {\n <li\n #opt=\"ngOption\"\n ngOption\n class=\"kt-select__option\"\n [value]=\"keyOf(item)\"\n [label]=\"labelOf(item)\"\n [disabled]=\"disabledOf(item)\"\n [class.kt-select__option--active]=\"opt.active()\"\n >\n @if (optionDef(); as def) {\n <ng-container\n [ngTemplateOutlet]=\"def.template\"\n [ngTemplateOutletContext]=\"{ $implicit: item, selected: !!opt.selected(), active: opt.active() }\"\n />\n } @else {\n {{ labelOf(item) }}\n }\n </li>\n } @empty {\n <li class=\"kt-select__empty\" role=\"option\" aria-disabled=\"true\" aria-selected=\"false\">\n {{ resolvedEmptyText() }}\n </li>\n }\n </ul>\n }\n </div>\n </div>\n </ng-template>\n </div>\n</kt-field>\n", styles: ["@layer kt-aaa.components{:host{display:block}.kt-select{position:relative}.kt-select__trigger{display:flex;align-items:center;justify-content:space-between;gap:var(--field-control-gap, .5rem);inline-size:100%;cursor:pointer;text-align:start;font:inherit;color:var(--field-color, inherit)}.kt-select__trigger:disabled{cursor:not-allowed;background:var(--field-disabled-bg, #f1f3f4);color:color-mix(in srgb,currentColor 50%,transparent)}.kt-select__value{flex:1;min-inline-size:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kt-select__placeholder{color:var(--field-hint-color, #5f6368)}.kt-select__arrow{flex:none;font-family:Material Symbols Outlined;font-size:1.25em;line-height:1;font-feature-settings:\"liga\";color:var(--field-icon-color, #5f6368);transition:var(--select-arrow-transition, transform .12s ease);-webkit-font-smoothing:antialiased}.kt-select--open .kt-select__arrow{transform:rotate(180deg)}.kt-select__popup{box-sizing:border-box;display:flex;flex-direction:column;margin:0;padding:0;border-width:var(--select-popup-border-width, var(--field-border-width, 1px));border-style:var(--field-border-style, solid);border-color:var(--field-border-color, #c4c7c5);border-radius:var(--field-radius, 8px);background:var(--select-popup-bg, var(--kt-surface-container, var(--kt-surface, #fff)));color:var(--field-color, inherit);box-shadow:var(--select-popup-shadow, 0 4px 12px rgb(0 0 0 / 12%));-webkit-backdrop-filter:var(--select-popup-backdrop-filter, none);backdrop-filter:var(--select-popup-backdrop-filter, none);max-block-size:var(--select-popup-max-height, 16rem);overflow:hidden}.kt-select__sheet-card{display:contents}.kt-select__popup:not(:popover-open){display:none!important}.kt-select__popup:popover-open{animation:var(--select-popup-enter-animation, none)}@media(prefers-reduced-motion:reduce){.kt-select__popup:popover-open{animation:none}}.kt-select__listbox{flex:1 1 auto;min-block-size:0;margin:0;padding:.25rem;list-style:none;overflow-y:auto}.kt-select__panel{display:flex;flex-direction:column;flex:1 1 auto;min-block-size:0}.kt-select__filter{flex:none;padding:.5rem;border-block-end:1px solid var(--field-border-color, #c4c7c5)}.kt-select__filter-input{box-sizing:border-box;inline-size:100%;min-block-size:var(--field-min-height, 44px);padding:.375rem .625rem;border:var(--field-border-width, 1px) var(--field-border-style, solid) var(--field-border-color, #c4c7c5);border-radius:calc(var(--field-radius, 8px) * .75);background:var(--select-popup-bg, var(--kt-surface-container, var(--kt-surface, #fff)));color:var(--field-color, inherit);font:inherit;appearance:none}.kt-select__filter-input::placeholder{color:var(--field-hint-color, #5f6368)}.kt-select__filter-input:focus-visible{outline:2px solid var(--field-border-color-focus, #0b57d0);outline-offset:-1px}.kt-select__filter-input::-webkit-search-cancel-button{appearance:none;inline-size:1rem;block-size:1rem;margin-inline-start:.375rem;cursor:pointer;background-color:var(--field-icon-color, #5f6368);-webkit-mask:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z'/%3E%3C/svg%3E\") center / contain no-repeat;mask:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z'/%3E%3C/svg%3E\") center / contain no-repeat}.kt-select__sr-only{position:absolute;inset-block-start:0;inset-inline-start:0;inline-size:1px;block-size:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}@supports (anchor-name: --x){.kt-select__popup{position:fixed;inset:auto;top:anchor(bottom);left:anchor(left);margin-block-start:.25rem;min-inline-size:anchor-size(width);width:max-content;max-inline-size:min(90vw,28rem);position-try-fallbacks:flip-block,flip-inline,flip-block flip-inline}}@supports not (anchor-name: --x){.kt-select__popup{position:fixed;inset:auto 0 0;inline-size:100%;max-inline-size:100%;border-radius:var(--kt-sheet-radius, 16px) var(--kt-sheet-radius, 16px) 0 0}}.kt-select__popup--sheet{position:fixed!important;inset:0!important;inline-size:100%!important;max-inline-size:100%!important;min-inline-size:0!important;width:100%!important;height:100%!important;max-block-size:none!important;margin:0!important;padding:0!important;border:none!important;background:transparent!important;box-shadow:none!important;border-radius:0!important;overflow:visible!important;display:flex;flex-direction:column!important;justify-content:flex-end!important}.kt-select__popup--sheet .kt-select__sheet-card{position:relative;z-index:2;display:flex;flex-direction:column;background:var(--select-popup-bg, var(--kt-surface-container, var(--kt-surface, #fff)));border-radius:var(--kt-sheet-radius, 16px) var(--kt-sheet-radius, 16px) 0 0;box-shadow:var(--kt-sheet-shadow, 0 -4px 16px rgb(0 0 0 / 12%));max-block-size:var(--kt-sheet-max-block-size, 85svh);width:100%;overflow:hidden;translate:0 0;transition:translate var(--kt-sheet-anim-duration, .12s) ease}.kt-select__popup--sheet .kt-select__sheet-card:has(.kt-select__filter){block-size:var(--kt-sheet-max-block-size, 85svh);max-block-size:var(--kt-sheet-max-block-size, 85svh)}.kt-select__popup--sheet:popover-open .kt-select__sheet-card{translate:0 0;animation:var(--select-sheet-enter-animation, kt-sheet-in var(--kt-sheet-anim-duration, .12s) ease)}.kt-select__popup--sheet .kt-select__sheet-card.kt-select__popup--dragging{transition:none}.kt-select__popup--sheet.kt-select__popup--closing .kt-select__sheet-card,.kt-select__popup--sheet:popover-open.kt-select__popup--closing .kt-select__sheet-card{translate:0 100%;transition:translate var(--kt-sheet-exit-duration, 90ms) cubic-bezier(.4,0,.2,1)}::ng-deep .kt-select__popup--sheet::backdrop{display:none!important}.kt-select__sheet-scrim{display:none}.kt-select__popup--sheet .kt-select__sheet-scrim{display:block;position:fixed;inset:0;z-index:1;background:var(--kt-sheet-scrim, rgb(0 0 0 / 40%));opacity:0;pointer-events:auto;transition:opacity var(--kt-sheet-anim-duration, .12s) ease,overlay var(--kt-sheet-anim-duration, .12s) allow-discrete,display var(--kt-sheet-anim-duration, .12s) allow-discrete}.kt-select__popup--sheet:popover-open .kt-select__sheet-scrim{opacity:1}@starting-style{.kt-select__popup--sheet:popover-open .kt-select__sheet-scrim{opacity:0}}.kt-select__popup--sheet.kt-select__popup--closing .kt-select__sheet-scrim,.kt-select__popup--sheet:popover-open.kt-select__popup--closing .kt-select__sheet-scrim{opacity:0;transition:opacity var(--kt-sheet-exit-duration, 90ms) ease}.kt-select__popup--sheet .kt-select__option{--select-option-min-height: 44px;padding-block:.625rem}.kt-select__popup--sheet .kt-select__filter-input{font-size:1rem;min-block-size:44px}@media(prefers-reduced-motion:reduce){.kt-select__popup--sheet .kt-select__sheet-card,.kt-select__popup--sheet .kt-select__sheet-scrim{transition:none;translate:0 0}}.kt-select__sheet-grab{display:flex;align-items:center;justify-content:center;flex:none;block-size:44px;cursor:grab;touch-action:none}.kt-select__sheet-grab:active{cursor:grabbing}.kt-select__sheet-grab:before{content:\"\";inline-size:2.25rem;block-size:.25rem;border-radius:999px;background:var(--kt-sheet-grab-color, var(--kt-outline, #c4c7c5))}.kt-select__sheet-header{display:flex;align-items:center;justify-content:space-between;gap:.5rem;flex:none;padding-block:.5rem;padding-inline:1rem .5rem;border-block-end:1px solid var(--field-border-color, #c4c7c5)}.kt-select__sheet-title{font-weight:600}.kt-select__sheet-close{display:inline-flex;align-items:center;justify-content:center;flex:none;inline-size:44px;block-size:44px;padding:0;border:0;border-radius:50%;background:transparent;color:var(--field-icon-color, #5f6368);cursor:pointer}.kt-select__sheet-close:focus-visible{outline:2px solid var(--field-border-color-focus, #0b57d0);outline-offset:2px}.kt-select__sheet-close-icon{font-family:Material Symbols Outlined;font-feature-settings:\"liga\";font-size:1.5rem;line-height:1;-webkit-font-smoothing:antialiased}.kt-select__option{display:flex;align-items:center;gap:.5rem;box-sizing:border-box;min-block-size:var( --select-option-min-height, 44px );padding:.5rem .625rem;border-radius:6px;cursor:pointer}.kt-select__option[aria-selected=true]{background:var(--select-option-selected-bg, color-mix(in srgb, var(--kt-primary, #0b57d0) 14%, transparent));color:var(--select-option-selected-color, inherit);font-weight:var(--select-option-selected-weight, 600)}.kt-select__option--active:not([aria-disabled=true]),.kt-select__option:hover:not([aria-disabled=true]){background:var(--select-option-hover-bg, color-mix(in srgb, currentColor 8%, transparent))}.kt-select__option[aria-disabled=true]{opacity:.5;cursor:not-allowed}.kt-select__empty{padding:.5rem .625rem;color:var(--field-hint-color, #5f6368)}.kt-select__truncated-info{box-sizing:border-box;padding:.5rem .625rem;font-size:.875rem;font-style:italic;color:var(--field-hint-color, #5f6368);border-block-start:1px solid var(--field-border-color, #c4c7c5);pointer-events:none}}\n"], dependencies: [{ kind: "component", type: KtField, selector: "kt-field", inputs: ["label", "hint", "helpText", "helpLabel", "customDescribedBy", "errors", "invalid", "required", "fieldId", "hideHintWhenInvalid", "showAllErrors", "hideLabel", "hideErrors", "appearance", "floatLabel"], outputs: ["helpClick"] }, { kind: "directive", type: KtFieldControl, selector: "[ktFieldControl]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: Combobox, selector: "[ngCombobox]", inputs: ["disabled", "softDisabled", "alwaysExpanded", "tabindex", "expanded", "value", "inlineSuggestion"], outputs: ["expandedChange", "valueChange"], exportAs: ["ngCombobox"] }, { kind: "directive", type: ComboboxPopup, selector: "ng-template[ngComboboxPopup]", inputs: ["combobox", "popupType"], exportAs: ["ngComboboxPopup"] }, { kind: "directive", type: ComboboxWidget, selector: "[ngComboboxWidget]", inputs: ["activeDescendant"], exportAs: ["ngComboboxWidget"] }, { kind: "directive", type: Listbox, selector: "[ngListbox]", inputs: ["id", "orientation", "multi", "wrap", "softDisabled", "focusMode", "selectionMode", "typeaheadDelay", "disabled", "readonly", "tabindex", "value"], outputs: ["valueChange"], exportAs: ["ngListbox"] }, { kind: "directive", type: Option, selector: "[ngOption]", inputs: ["id", "value", "disabled", "label"], exportAs: ["ngOption"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2610
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: KtSelect, isStandalone: true, selector: "kt-select", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", selectionChange: "selectionChange" }, queries: [{ propertyName: "optionDef", first: true, predicate: KtSelectOptionDef, descendants: true, isSignal: true }, { propertyName: "triggerDef", first: true, predicate: KtSelectTriggerDef, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"fieldErrors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n [hideLabel]=\"hideLabel()\"\n [hideErrors]=\"hideErrors()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div class=\"kt-select\" [class.kt-select--open]=\"expanded()\">\n <button\n #combobox=\"ngCombobox\"\n #trigger\n ngCombobox\n ktFieldControl\n type=\"button\"\n class=\"kt-field-box kt-select__trigger\"\n [class.kt-select__trigger--clearable]=\"showClear()\"\n [(expanded)]=\"expanded\"\n [disabled]=\"disabled()\"\n [softDisabled]=\"false\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n [attr.data-filled]=\"selectedOption() ? '' : null\"\n [attr.data-pending]=\"pending() ? '' : null\"\n [attr.aria-busy]=\"pending() ? 'true' : null\"\n >\n <span class=\"kt-select__value\">\n @if (triggerDef(); as def) {\n <ng-container [ngTemplateOutlet]=\"def.template\" [ngTemplateOutletContext]=\"{ $implicit: selectedOption() }\" />\n } @else if (selectedOption(); as option) {\n {{ labelOf(option) }}\n } @else {\n <span class=\"kt-select__placeholder\">{{ resolvedPlaceholder() }}</span>\n }\n </span>\n <span class=\"kt-select__arrow\" aria-hidden=\"true\">arrow_drop_down</span>\n </button>\n\n <!-- Effacer la s\u00E9lection depuis le champ : sibling du trigger (pas de bouton imbriqu\u00E9 dans un bouton).\n mousedown pr\u00E9ventif : un tap ne doit pas voler le focus du combobox (closePopupOnBlur). -->\n @if (showClear()) {\n <button\n type=\"button\"\n class=\"kt-select__clear\"\n [attr.aria-label]=\"clearLabel()\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"clearSelection()\"\n >\n <span class=\"kt-select__clear-icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n <!-- Un seul Popover (top-layer). CSS @media : dropdown ancr\u00E9 (desktop) \u2194 bottom-sheet (t\u00E9l\u00E9phone).\n Pas de <dialog>.showModal() : ce combobox se ferme au blur, et showModal volerait le focus.\n Sheet = SCROLLER \u00E0 snap (ADR-0005) : le spacer occupe un \u00E9cran (snap \u00AB ferm\u00E9 \u00BB), la carte\n snappe en bas (snap \u00AB ouvert \u00BB) ; le geste de fermeture est le scroll natif lui-m\u00EAme. -->\n <ng-template ngComboboxPopup [combobox]=\"combobox\" [popupType]=\"filterable() ? 'dialog' : 'listbox'\">\n <div #popup popover=\"manual\" class=\"kt-select__popup\" [class.kt-select__popup--sheet]=\"compact()\">\n @if (compact()) {\n <div class=\"kt-select__sheet-scrim\" aria-hidden=\"true\" (click)=\"expanded.set(false)\"></div>\n <div class=\"kt-select__sheet-spacer\" aria-hidden=\"true\"></div>\n }\n <div class=\"kt-select__sheet-card\">\n @if (compact()) {\n <!-- Poign\u00E9e D\u00C9CORATIVE (ADR-0005) : la sheet s'attrape partout, le geste est natif. -->\n <div class=\"kt-select__sheet-grab\" aria-hidden=\"true\" (mousedown)=\"$event.preventDefault()\"></div>\n <!-- mousedown pr\u00E9ventif : un tap sur la carcasse ne doit pas voler le focus du widget\n (closePopupOnBlur fermerait le combobox) ; le click du bouton Fermer survit. -->\n <header class=\"kt-select__sheet-header\" (mousedown)=\"$event.preventDefault()\">\n <span class=\"kt-select__sheet-title\">{{ label() }}</span>\n <button\n type=\"button\"\n class=\"kt-select__sheet-close\"\n [attr.aria-label]=\"resolvedCloseLabel()\"\n (click)=\"expanded.set(false)\"\n >\n <span class=\"kt-select__sheet-close-icon\" aria-hidden=\"true\">close</span>\n </button>\n </header>\n }\n @if (filterable()) {\n <!-- Mode filtrable : le widget combobox est le panneau ENTIER (champ + annonce + liste).\n Indispensable : un focus pos\u00E9 hors de l'\u00E9l\u00E9ment ngComboboxWidget ferme le popup\n (closePopupOnBlur de @angular/aria) \u2014 le champ doit donc vivre dans ce sous-arbre. -->\n <div\n ngComboboxWidget\n role=\"dialog\"\n class=\"kt-select__panel\"\n [id]=\"panelId\"\n [attr.aria-label]=\"label()\"\n [activeDescendant]=\"lb.activeDescendant()\"\n >\n <div class=\"kt-select__filter\">\n <input\n #filterInput\n type=\"search\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n aria-expanded=\"true\"\n class=\"kt-select__filter-input\"\n autocomplete=\"off\"\n [placeholder]=\"resolvedFilterPlaceholder()\"\n [attr.aria-label]=\"resolvedFilterLabel()\"\n [attr.aria-controls]=\"lb.id()\"\n [attr.aria-activedescendant]=\"lb.activeDescendant()\"\n [value]=\"filterText()\"\n (input)=\"onFilterInput($event)\"\n (keydown)=\"onFilterKeydown($event)\"\n />\n </div>\n <!-- Nombre de r\u00E9sultats annonc\u00E9 (diff\u00E9r\u00E9) aux lecteurs d'\u00E9cran : une liste qui\n r\u00E9tr\u00E9cit en silence est per\u00E7ue comme un bug (tests utilisateurs S. Higley). -->\n <div class=\"kt-select__sr-only\" role=\"status\" aria-live=\"polite\">{{ announcedCount() }}</div>\n <ul\n #lb=\"ngListbox\"\n #listboxEl\n ngListbox\n [focusMode]=\"compact() && !filterable() ? 'roving' : 'activedescendant'\"\n selectionMode=\"explicit\"\n class=\"kt-select__listbox\"\n [attr.aria-label]=\"label()\"\n [value]=\"listboxValue()\"\n (valueChange)=\"onListboxValueChange($event)\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n >\n @for (item of displayedOptions(); track keyOf(item)) {\n <li\n #opt=\"ngOption\"\n ngOption\n class=\"kt-select__option\"\n [value]=\"keyOf(item)\"\n [label]=\"labelOf(item)\"\n [disabled]=\"disabledOf(item)\"\n [class.kt-select__option--active]=\"opt.active()\"\n >\n @if (optionDef(); as def) {\n <ng-container\n [ngTemplateOutlet]=\"def.template\"\n [ngTemplateOutletContext]=\"{\n $implicit: item,\n selected: !!opt.selected(),\n active: opt.active(),\n }\"\n />\n } @else {\n {{ labelOf(item) }}\n }\n </li>\n } @empty {\n <li class=\"kt-select__empty\" role=\"option\" aria-disabled=\"true\" aria-selected=\"false\">\n {{ resolvedEmptyText() }}\n </li>\n }\n @if (filterable() && filteredOptions().length > maxVisibleOptions()) {\n <li class=\"kt-select__truncated-info\" role=\"option\" aria-disabled=\"true\" aria-selected=\"false\">\n {{ resolvedTruncatedResultsText()(maxVisibleOptions(), filteredOptions().length) }}\n </li>\n }\n </ul>\n </div>\n } @else {\n <ul\n #listbox=\"ngListbox\"\n #listboxEl\n ngComboboxWidget\n ngListbox\n [focusMode]=\"compact() ? 'roving' : 'activedescendant'\"\n selectionMode=\"explicit\"\n class=\"kt-select__listbox\"\n [attr.aria-label]=\"label()\"\n [value]=\"listboxValue()\"\n (valueChange)=\"onListboxValueChange($event)\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n [activeDescendant]=\"listbox.activeDescendant()\"\n >\n @for (item of options(); track keyOf(item)) {\n <li\n #opt=\"ngOption\"\n ngOption\n class=\"kt-select__option\"\n [value]=\"keyOf(item)\"\n [label]=\"labelOf(item)\"\n [disabled]=\"disabledOf(item)\"\n [class.kt-select__option--active]=\"opt.active()\"\n >\n @if (optionDef(); as def) {\n <ng-container\n [ngTemplateOutlet]=\"def.template\"\n [ngTemplateOutletContext]=\"{ $implicit: item, selected: !!opt.selected(), active: opt.active() }\"\n />\n } @else {\n {{ labelOf(item) }}\n }\n </li>\n } @empty {\n <li class=\"kt-select__empty\" role=\"option\" aria-disabled=\"true\" aria-selected=\"false\">\n {{ resolvedEmptyText() }}\n </li>\n }\n </ul>\n }\n </div>\n </div>\n </ng-template>\n </div>\n</kt-field>\n", styles: ["@layer kt-aaa.components{:host{display:block}.kt-select{position:relative}.kt-select__trigger{display:flex;align-items:center;justify-content:space-between;gap:var(--field-control-gap, .5rem);inline-size:100%;cursor:pointer;text-align:start;font:inherit;color:var(--field-color, inherit)}.kt-select__trigger:disabled{cursor:not-allowed;background:var(--field-disabled-bg, #f1f3f4);color:color-mix(in srgb,currentColor 50%,transparent)}.kt-select__value{flex:1;min-inline-size:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kt-select__placeholder{color:var(--field-hint-color, #5f6368)}.kt-select__arrow{flex:none;font-family:Material Symbols Outlined;font-size:1.25em;line-height:1;font-feature-settings:\"liga\";color:var(--field-icon-color, #5f6368);transition:var(--select-arrow-transition, transform .12s ease);-webkit-font-smoothing:antialiased}.kt-select--open .kt-select__arrow{transform:rotate(180deg)}.kt-select__trigger--clearable .kt-select__value{margin-inline-end:2rem}.kt-select__clear{position:absolute;inset-block-start:50%;inset-inline-end:2.5rem;translate:0 -50%;display:inline-flex;align-items:center;justify-content:center;inline-size:24px;block-size:24px;padding:0;border:0;border-radius:50%;background:transparent;color:var(--field-icon-color, #5f6368);cursor:pointer}.kt-select__clear:after{content:\"\";position:absolute;inset:-10px}.kt-select__clear:hover{background-color:color-mix(in srgb,currentColor 12%,transparent);color:var(--field-color, inherit)}.kt-select__clear:focus-visible{outline:2px solid var(--field-border-color-focus, #0b57d0);outline-offset:1px}.kt-select__clear-icon{font-family:Material Symbols Outlined;font-feature-settings:\"liga\";font-size:1.25rem;line-height:1;-webkit-font-smoothing:antialiased}.kt-select__popup{box-sizing:border-box;display:flex;flex-direction:column;margin:0;padding:0;border-width:var(--select-popup-border-width, var(--field-border-width, 1px));border-style:var(--field-border-style, solid);border-color:var(--field-border-color, #c4c7c5);border-radius:var(--field-radius, 8px);background:var(--select-popup-bg, var(--kt-surface-container, var(--kt-surface, #fff)));color:var(--field-color, inherit);box-shadow:var(--select-popup-shadow, 0 4px 12px rgb(0 0 0 / 12%));-webkit-backdrop-filter:var(--select-popup-backdrop-filter, none);backdrop-filter:var(--select-popup-backdrop-filter, none);max-block-size:var(--select-popup-max-height, 16rem);overflow:hidden}.kt-select__sheet-card{display:contents}.kt-select__popup:not(:popover-open){display:none!important}.kt-select__popup:popover-open{animation:var(--select-popup-enter-animation, none)}@media(prefers-reduced-motion:reduce){.kt-select__popup:popover-open{animation:none}}.kt-select__listbox{flex:1 1 auto;min-block-size:0;margin:0;padding:.25rem;list-style:none;overflow-y:auto}.kt-select__panel{display:flex;flex-direction:column;flex:1 1 auto;min-block-size:0}.kt-select__filter{flex:none;padding:.5rem;border-block-end:1px solid var(--field-border-color, #c4c7c5)}.kt-select__filter-input{box-sizing:border-box;inline-size:100%;min-block-size:var(--field-min-height, 44px);padding:.375rem .625rem;border:var(--field-border-width, 1px) var(--field-border-style, solid) var(--field-border-color, #c4c7c5);border-radius:calc(var(--field-radius, 8px) * .75);background:var(--select-popup-bg, var(--kt-surface-container, var(--kt-surface, #fff)));color:var(--field-color, inherit);font:inherit;appearance:none}.kt-select__filter-input::placeholder{color:var(--field-hint-color, #5f6368)}.kt-select__filter-input:focus-visible{outline:2px solid var(--field-border-color-focus, #0b57d0);outline-offset:-1px}.kt-select__filter-input::-webkit-search-cancel-button{appearance:none;inline-size:1rem;block-size:1rem;margin-inline-start:.375rem;cursor:pointer;background-color:var(--field-icon-color, #5f6368);-webkit-mask:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z'/%3E%3C/svg%3E\") center / contain no-repeat;mask:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z'/%3E%3C/svg%3E\") center / contain no-repeat}.kt-select__sr-only{position:absolute;inset-block-start:0;inset-inline-start:0;inline-size:1px;block-size:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}@supports (anchor-name: --x){.kt-select__popup{position:fixed;inset:auto;top:anchor(bottom);left:anchor(left);margin-block-start:.25rem;min-inline-size:anchor-size(width);width:max-content;max-inline-size:min(90vw,28rem);position-try-fallbacks:flip-block,flip-inline,flip-block flip-inline}}@supports not (anchor-name: --x){.kt-select__popup{position:fixed;inset:auto 0 0;inline-size:100%;max-inline-size:100%;border-radius:var(--kt-sheet-radius, 16px) var(--kt-sheet-radius, 16px) 0 0}}.kt-select__popup--sheet{position:fixed!important;inset:0!important;inline-size:100%!important;max-inline-size:100%!important;min-inline-size:0!important;width:100%!important;height:100%!important;max-block-size:none!important;margin:0!important;padding:0!important;border:none!important;background:transparent!important;box-shadow:none!important;border-radius:0!important;display:block;overflow-y:auto!important;scroll-snap-type:y mandatory;overscroll-behavior:contain;scrollbar-width:none}.kt-select__popup--sheet .kt-select__sheet-spacer{block-size:100%;scroll-snap-align:start;scroll-snap-stop:always}.kt-select__popup--sheet .kt-select__sheet-card{position:relative;z-index:2;display:flex;flex-direction:column;background:var(--select-popup-bg, var(--kt-surface-container, var(--kt-surface, #fff)));border-radius:var(--kt-sheet-radius, 16px) var(--kt-sheet-radius, 16px) 0 0;box-shadow:var(--kt-sheet-shadow, 0 -4px 16px rgb(0 0 0 / 12%));max-block-size:var(--kt-sheet-max-block-size, 85svh);width:100%;overflow:hidden;scroll-snap-align:end;scroll-snap-stop:always}.kt-select__popup--sheet .kt-select__sheet-card:has(.kt-select__filter){block-size:var(--kt-sheet-max-block-size, 85svh);max-block-size:var(--kt-sheet-max-block-size, 85svh)}::ng-deep .kt-select__popup--sheet::backdrop{display:none!important}.kt-select__sheet-scrim{display:none}.kt-select__popup--sheet .kt-select__sheet-scrim{display:block;position:fixed;inset:0;z-index:1;background:var(--kt-sheet-scrim, rgb(0 0 0 / 40%));opacity:0;pointer-events:auto;transition:opacity var(--kt-sheet-anim-duration, .12s) ease,overlay var(--kt-sheet-anim-duration, .12s) allow-discrete,display var(--kt-sheet-anim-duration, .12s) allow-discrete}.kt-select__popup--sheet:popover-open .kt-select__sheet-scrim{opacity:1}@starting-style{.kt-select__popup--sheet:popover-open .kt-select__sheet-scrim{opacity:0}}.kt-select__popup--sheet.kt-select__popup--closing .kt-select__sheet-scrim,.kt-select__popup--sheet:popover-open.kt-select__popup--closing .kt-select__sheet-scrim{opacity:0;transition:opacity var(--kt-sheet-exit-duration, 90ms) ease}.kt-select__popup--sheet .kt-select__option{--select-option-min-height: 44px;padding-block:.625rem}.kt-select__popup--sheet .kt-select__filter-input{font-size:1rem;min-block-size:44px}@media(prefers-reduced-motion:reduce){.kt-select__popup--sheet .kt-select__sheet-scrim{transition:none}}.kt-select__sheet-grab{display:flex;align-items:center;justify-content:center;flex:none;block-size:28px}.kt-select__sheet-grab:before{content:\"\";inline-size:2.25rem;block-size:.25rem;border-radius:999px;background:var(--kt-sheet-grab-color, var(--kt-outline, #c4c7c5))}.kt-select__sheet-header{display:flex;align-items:center;justify-content:space-between;gap:.5rem;flex:none;padding-block:.5rem;padding-inline:1rem .5rem;border-block-end:1px solid var(--field-border-color, #c4c7c5)}.kt-select__sheet-title{font-weight:600}.kt-select__sheet-close{display:inline-flex;align-items:center;justify-content:center;flex:none;inline-size:44px;block-size:44px;padding:0;border:0;border-radius:50%;background:transparent;color:var(--field-icon-color, #5f6368);cursor:pointer}.kt-select__sheet-close:focus-visible{outline:2px solid var(--field-border-color-focus, #0b57d0);outline-offset:2px}.kt-select__sheet-close-icon{font-family:Material Symbols Outlined;font-feature-settings:\"liga\";font-size:1.5rem;line-height:1;-webkit-font-smoothing:antialiased}.kt-select__option{display:flex;align-items:center;gap:.5rem;box-sizing:border-box;min-block-size:var( --select-option-min-height, 44px );padding:.5rem .625rem;border-radius:6px;cursor:pointer}.kt-select__option[aria-selected=true]{background:var(--select-option-selected-bg, color-mix(in srgb, var(--kt-primary, #0b57d0) 14%, transparent));color:var(--select-option-selected-color, inherit);font-weight:var(--select-option-selected-weight, 600)}.kt-select__option--active:not([aria-disabled=true]),.kt-select__option:hover:not([aria-disabled=true]){background:var(--select-option-hover-bg, color-mix(in srgb, currentColor 8%, transparent))}.kt-select__option[aria-disabled=true]{opacity:.5;cursor:not-allowed}.kt-select__empty{padding:.5rem .625rem;color:var(--field-hint-color, #5f6368)}.kt-select__truncated-info{box-sizing:border-box;padding:.5rem .625rem;font-size:.875rem;font-style:italic;color:var(--field-hint-color, #5f6368);border-block-start:1px solid var(--field-border-color, #c4c7c5);pointer-events:none}}\n"], dependencies: [{ kind: "component", type: KtField, selector: "kt-field", inputs: ["label", "hint", "helpText", "helpLabel", "customDescribedBy", "errors", "invalid", "required", "fieldId", "hideHintWhenInvalid", "showAllErrors", "hideLabel", "hideErrors", "appearance", "floatLabel"], outputs: ["helpClick"] }, { kind: "directive", type: KtFieldControl, selector: "[ktFieldControl]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: Combobox, selector: "[ngCombobox]", inputs: ["disabled", "softDisabled", "alwaysExpanded", "tabindex", "expanded", "value", "inlineSuggestion"], outputs: ["expandedChange", "valueChange"], exportAs: ["ngCombobox"] }, { kind: "directive", type: ComboboxPopup, selector: "ng-template[ngComboboxPopup]", inputs: ["combobox", "popupType"], exportAs: ["ngComboboxPopup"] }, { kind: "directive", type: ComboboxWidget, selector: "[ngComboboxWidget]", inputs: ["activeDescendant"], exportAs: ["ngComboboxWidget"] }, { kind: "directive", type: Listbox, selector: "[ngListbox]", inputs: ["id", "orientation", "multi", "wrap", "softDisabled", "focusMode", "selectionMode", "typeaheadDelay", "disabled", "readonly", "tabindex", "value"], outputs: ["valueChange"], exportAs: ["ngListbox"] }, { kind: "directive", type: Option, selector: "[ngOption]", inputs: ["id", "value", "disabled", "label"], exportAs: ["ngOption"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2513
2611
  }
2514
2612
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtSelect, decorators: [{
2515
2613
  type: Component,
2516
- args: [{ selector: 'kt-select', changeDetection: ChangeDetectionStrategy.OnPush, imports: [KtField, KtFieldControl, NgTemplateOutlet, Combobox, ComboboxPopup, ComboboxWidget, Listbox, Option], template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"fieldErrors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n [hideLabel]=\"hideLabel()\"\n [hideErrors]=\"hideErrors()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div class=\"kt-select\" [class.kt-select--open]=\"expanded()\">\n <button\n #combobox=\"ngCombobox\"\n #trigger\n ngCombobox\n ktFieldControl\n type=\"button\"\n class=\"kt-field-box kt-select__trigger\"\n [(expanded)]=\"expanded\"\n [disabled]=\"disabled()\"\n [softDisabled]=\"false\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n [attr.data-filled]=\"selectedOption() ? '' : null\"\n [attr.data-pending]=\"pending() ? '' : null\"\n [attr.aria-busy]=\"pending() ? 'true' : null\"\n >\n <span class=\"kt-select__value\">\n @if (triggerDef(); as def) {\n <ng-container [ngTemplateOutlet]=\"def.template\" [ngTemplateOutletContext]=\"{ $implicit: selectedOption() }\" />\n } @else if (selectedOption(); as option) {\n {{ labelOf(option) }}\n } @else {\n <span class=\"kt-select__placeholder\">{{ resolvedPlaceholder() }}</span>\n }\n </span>\n <span class=\"kt-select__arrow\" aria-hidden=\"true\">arrow_drop_down</span>\n </button>\n\n <!-- Un seul Popover (top-layer). CSS @media : dropdown ancr\u00E9 (desktop) \u2194 bottom-sheet (t\u00E9l\u00E9phone).\n Pas de <dialog>.showModal() : ce combobox se ferme au blur, et showModal volerait le focus. -->\n <ng-template ngComboboxPopup [combobox]=\"combobox\" [popupType]=\"filterable() ? 'dialog' : 'listbox'\">\n <div #popup popover=\"manual\" class=\"kt-select__popup\" [class.kt-select__popup--sheet]=\"compact()\">\n @if (compact()) {\n <div class=\"kt-select__sheet-scrim\" aria-hidden=\"true\" (click)=\"expanded.set(false)\"></div>\n }\n <div class=\"kt-select__sheet-card\">\n @if (compact()) {\n <div\n class=\"kt-select__sheet-grab\"\n aria-hidden=\"true\"\n (pointerdown)=\"onDragStart($event)\"\n (mousedown)=\"$event.preventDefault()\"\n ></div>\n <header class=\"kt-select__sheet-header\">\n <span class=\"kt-select__sheet-title\">{{ label() }}</span>\n <button\n type=\"button\"\n class=\"kt-select__sheet-close\"\n [attr.aria-label]=\"resolvedCloseLabel()\"\n (click)=\"expanded.set(false)\"\n >\n <span class=\"kt-select__sheet-close-icon\" aria-hidden=\"true\">close</span>\n </button>\n </header>\n }\n @if (filterable()) {\n <!-- Mode filtrable : le widget combobox est le panneau ENTIER (champ + annonce + liste).\n Indispensable : un focus pos\u00E9 hors de l'\u00E9l\u00E9ment ngComboboxWidget ferme le popup\n (closePopupOnBlur de @angular/aria) \u2014 le champ doit donc vivre dans ce sous-arbre. -->\n <div\n ngComboboxWidget\n role=\"dialog\"\n class=\"kt-select__panel\"\n [id]=\"panelId\"\n [attr.aria-label]=\"label()\"\n [activeDescendant]=\"lb.activeDescendant()\"\n >\n <div class=\"kt-select__filter\">\n <input\n #filterInput\n type=\"search\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n aria-expanded=\"true\"\n class=\"kt-select__filter-input\"\n autocomplete=\"off\"\n [placeholder]=\"resolvedFilterPlaceholder()\"\n [attr.aria-label]=\"resolvedFilterLabel()\"\n [attr.aria-controls]=\"lb.id()\"\n [attr.aria-activedescendant]=\"lb.activeDescendant()\"\n [value]=\"filterText()\"\n (input)=\"onFilterInput($event)\"\n (keydown)=\"onFilterKeydown($event)\"\n />\n </div>\n <!-- Nombre de r\u00E9sultats annonc\u00E9 (diff\u00E9r\u00E9) aux lecteurs d'\u00E9cran : une liste qui\n r\u00E9tr\u00E9cit en silence est per\u00E7ue comme un bug (tests utilisateurs S. Higley). -->\n <div class=\"kt-select__sr-only\" role=\"status\" aria-live=\"polite\">{{ announcedCount() }}</div>\n <ul\n #lb=\"ngListbox\"\n #listboxEl\n ngListbox\n [focusMode]=\"compact() && !filterable() ? 'roving' : 'activedescendant'\"\n selectionMode=\"explicit\"\n class=\"kt-select__listbox\"\n [attr.aria-label]=\"label()\"\n [value]=\"listboxValue()\"\n (valueChange)=\"onListboxValueChange($event)\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n >\n @for (item of displayedOptions(); track keyOf(item)) {\n <li\n #opt=\"ngOption\"\n ngOption\n class=\"kt-select__option\"\n [value]=\"keyOf(item)\"\n [label]=\"labelOf(item)\"\n [disabled]=\"disabledOf(item)\"\n [class.kt-select__option--active]=\"opt.active()\"\n >\n @if (optionDef(); as def) {\n <ng-container\n [ngTemplateOutlet]=\"def.template\"\n [ngTemplateOutletContext]=\"{\n $implicit: item,\n selected: !!opt.selected(),\n active: opt.active(),\n }\"\n />\n } @else {\n {{ labelOf(item) }}\n }\n </li>\n } @empty {\n <li class=\"kt-select__empty\" role=\"option\" aria-disabled=\"true\" aria-selected=\"false\">\n {{ resolvedEmptyText() }}\n </li>\n }\n @if (filterable() && filteredOptions().length > maxVisibleOptions()) {\n <li class=\"kt-select__truncated-info\" role=\"option\" aria-disabled=\"true\" aria-selected=\"false\">\n {{ resolvedTruncatedResultsText()(maxVisibleOptions(), filteredOptions().length) }}\n </li>\n }\n </ul>\n </div>\n } @else {\n <ul\n #listbox=\"ngListbox\"\n #listboxEl\n ngComboboxWidget\n ngListbox\n [focusMode]=\"compact() ? 'roving' : 'activedescendant'\"\n selectionMode=\"explicit\"\n class=\"kt-select__listbox\"\n [attr.aria-label]=\"label()\"\n [value]=\"listboxValue()\"\n (valueChange)=\"onListboxValueChange($event)\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n [activeDescendant]=\"listbox.activeDescendant()\"\n >\n @for (item of options(); track keyOf(item)) {\n <li\n #opt=\"ngOption\"\n ngOption\n class=\"kt-select__option\"\n [value]=\"keyOf(item)\"\n [label]=\"labelOf(item)\"\n [disabled]=\"disabledOf(item)\"\n [class.kt-select__option--active]=\"opt.active()\"\n >\n @if (optionDef(); as def) {\n <ng-container\n [ngTemplateOutlet]=\"def.template\"\n [ngTemplateOutletContext]=\"{ $implicit: item, selected: !!opt.selected(), active: opt.active() }\"\n />\n } @else {\n {{ labelOf(item) }}\n }\n </li>\n } @empty {\n <li class=\"kt-select__empty\" role=\"option\" aria-disabled=\"true\" aria-selected=\"false\">\n {{ resolvedEmptyText() }}\n </li>\n }\n </ul>\n }\n </div>\n </div>\n </ng-template>\n </div>\n</kt-field>\n", styles: ["@layer kt-aaa.components{:host{display:block}.kt-select{position:relative}.kt-select__trigger{display:flex;align-items:center;justify-content:space-between;gap:var(--field-control-gap, .5rem);inline-size:100%;cursor:pointer;text-align:start;font:inherit;color:var(--field-color, inherit)}.kt-select__trigger:disabled{cursor:not-allowed;background:var(--field-disabled-bg, #f1f3f4);color:color-mix(in srgb,currentColor 50%,transparent)}.kt-select__value{flex:1;min-inline-size:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kt-select__placeholder{color:var(--field-hint-color, #5f6368)}.kt-select__arrow{flex:none;font-family:Material Symbols Outlined;font-size:1.25em;line-height:1;font-feature-settings:\"liga\";color:var(--field-icon-color, #5f6368);transition:var(--select-arrow-transition, transform .12s ease);-webkit-font-smoothing:antialiased}.kt-select--open .kt-select__arrow{transform:rotate(180deg)}.kt-select__popup{box-sizing:border-box;display:flex;flex-direction:column;margin:0;padding:0;border-width:var(--select-popup-border-width, var(--field-border-width, 1px));border-style:var(--field-border-style, solid);border-color:var(--field-border-color, #c4c7c5);border-radius:var(--field-radius, 8px);background:var(--select-popup-bg, var(--kt-surface-container, var(--kt-surface, #fff)));color:var(--field-color, inherit);box-shadow:var(--select-popup-shadow, 0 4px 12px rgb(0 0 0 / 12%));-webkit-backdrop-filter:var(--select-popup-backdrop-filter, none);backdrop-filter:var(--select-popup-backdrop-filter, none);max-block-size:var(--select-popup-max-height, 16rem);overflow:hidden}.kt-select__sheet-card{display:contents}.kt-select__popup:not(:popover-open){display:none!important}.kt-select__popup:popover-open{animation:var(--select-popup-enter-animation, none)}@media(prefers-reduced-motion:reduce){.kt-select__popup:popover-open{animation:none}}.kt-select__listbox{flex:1 1 auto;min-block-size:0;margin:0;padding:.25rem;list-style:none;overflow-y:auto}.kt-select__panel{display:flex;flex-direction:column;flex:1 1 auto;min-block-size:0}.kt-select__filter{flex:none;padding:.5rem;border-block-end:1px solid var(--field-border-color, #c4c7c5)}.kt-select__filter-input{box-sizing:border-box;inline-size:100%;min-block-size:var(--field-min-height, 44px);padding:.375rem .625rem;border:var(--field-border-width, 1px) var(--field-border-style, solid) var(--field-border-color, #c4c7c5);border-radius:calc(var(--field-radius, 8px) * .75);background:var(--select-popup-bg, var(--kt-surface-container, var(--kt-surface, #fff)));color:var(--field-color, inherit);font:inherit;appearance:none}.kt-select__filter-input::placeholder{color:var(--field-hint-color, #5f6368)}.kt-select__filter-input:focus-visible{outline:2px solid var(--field-border-color-focus, #0b57d0);outline-offset:-1px}.kt-select__filter-input::-webkit-search-cancel-button{appearance:none;inline-size:1rem;block-size:1rem;margin-inline-start:.375rem;cursor:pointer;background-color:var(--field-icon-color, #5f6368);-webkit-mask:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z'/%3E%3C/svg%3E\") center / contain no-repeat;mask:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z'/%3E%3C/svg%3E\") center / contain no-repeat}.kt-select__sr-only{position:absolute;inset-block-start:0;inset-inline-start:0;inline-size:1px;block-size:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}@supports (anchor-name: --x){.kt-select__popup{position:fixed;inset:auto;top:anchor(bottom);left:anchor(left);margin-block-start:.25rem;min-inline-size:anchor-size(width);width:max-content;max-inline-size:min(90vw,28rem);position-try-fallbacks:flip-block,flip-inline,flip-block flip-inline}}@supports not (anchor-name: --x){.kt-select__popup{position:fixed;inset:auto 0 0;inline-size:100%;max-inline-size:100%;border-radius:var(--kt-sheet-radius, 16px) var(--kt-sheet-radius, 16px) 0 0}}.kt-select__popup--sheet{position:fixed!important;inset:0!important;inline-size:100%!important;max-inline-size:100%!important;min-inline-size:0!important;width:100%!important;height:100%!important;max-block-size:none!important;margin:0!important;padding:0!important;border:none!important;background:transparent!important;box-shadow:none!important;border-radius:0!important;overflow:visible!important;display:flex;flex-direction:column!important;justify-content:flex-end!important}.kt-select__popup--sheet .kt-select__sheet-card{position:relative;z-index:2;display:flex;flex-direction:column;background:var(--select-popup-bg, var(--kt-surface-container, var(--kt-surface, #fff)));border-radius:var(--kt-sheet-radius, 16px) var(--kt-sheet-radius, 16px) 0 0;box-shadow:var(--kt-sheet-shadow, 0 -4px 16px rgb(0 0 0 / 12%));max-block-size:var(--kt-sheet-max-block-size, 85svh);width:100%;overflow:hidden;translate:0 0;transition:translate var(--kt-sheet-anim-duration, .12s) ease}.kt-select__popup--sheet .kt-select__sheet-card:has(.kt-select__filter){block-size:var(--kt-sheet-max-block-size, 85svh);max-block-size:var(--kt-sheet-max-block-size, 85svh)}.kt-select__popup--sheet:popover-open .kt-select__sheet-card{translate:0 0;animation:var(--select-sheet-enter-animation, kt-sheet-in var(--kt-sheet-anim-duration, .12s) ease)}.kt-select__popup--sheet .kt-select__sheet-card.kt-select__popup--dragging{transition:none}.kt-select__popup--sheet.kt-select__popup--closing .kt-select__sheet-card,.kt-select__popup--sheet:popover-open.kt-select__popup--closing .kt-select__sheet-card{translate:0 100%;transition:translate var(--kt-sheet-exit-duration, 90ms) cubic-bezier(.4,0,.2,1)}::ng-deep .kt-select__popup--sheet::backdrop{display:none!important}.kt-select__sheet-scrim{display:none}.kt-select__popup--sheet .kt-select__sheet-scrim{display:block;position:fixed;inset:0;z-index:1;background:var(--kt-sheet-scrim, rgb(0 0 0 / 40%));opacity:0;pointer-events:auto;transition:opacity var(--kt-sheet-anim-duration, .12s) ease,overlay var(--kt-sheet-anim-duration, .12s) allow-discrete,display var(--kt-sheet-anim-duration, .12s) allow-discrete}.kt-select__popup--sheet:popover-open .kt-select__sheet-scrim{opacity:1}@starting-style{.kt-select__popup--sheet:popover-open .kt-select__sheet-scrim{opacity:0}}.kt-select__popup--sheet.kt-select__popup--closing .kt-select__sheet-scrim,.kt-select__popup--sheet:popover-open.kt-select__popup--closing .kt-select__sheet-scrim{opacity:0;transition:opacity var(--kt-sheet-exit-duration, 90ms) ease}.kt-select__popup--sheet .kt-select__option{--select-option-min-height: 44px;padding-block:.625rem}.kt-select__popup--sheet .kt-select__filter-input{font-size:1rem;min-block-size:44px}@media(prefers-reduced-motion:reduce){.kt-select__popup--sheet .kt-select__sheet-card,.kt-select__popup--sheet .kt-select__sheet-scrim{transition:none;translate:0 0}}.kt-select__sheet-grab{display:flex;align-items:center;justify-content:center;flex:none;block-size:44px;cursor:grab;touch-action:none}.kt-select__sheet-grab:active{cursor:grabbing}.kt-select__sheet-grab:before{content:\"\";inline-size:2.25rem;block-size:.25rem;border-radius:999px;background:var(--kt-sheet-grab-color, var(--kt-outline, #c4c7c5))}.kt-select__sheet-header{display:flex;align-items:center;justify-content:space-between;gap:.5rem;flex:none;padding-block:.5rem;padding-inline:1rem .5rem;border-block-end:1px solid var(--field-border-color, #c4c7c5)}.kt-select__sheet-title{font-weight:600}.kt-select__sheet-close{display:inline-flex;align-items:center;justify-content:center;flex:none;inline-size:44px;block-size:44px;padding:0;border:0;border-radius:50%;background:transparent;color:var(--field-icon-color, #5f6368);cursor:pointer}.kt-select__sheet-close:focus-visible{outline:2px solid var(--field-border-color-focus, #0b57d0);outline-offset:2px}.kt-select__sheet-close-icon{font-family:Material Symbols Outlined;font-feature-settings:\"liga\";font-size:1.5rem;line-height:1;-webkit-font-smoothing:antialiased}.kt-select__option{display:flex;align-items:center;gap:.5rem;box-sizing:border-box;min-block-size:var( --select-option-min-height, 44px );padding:.5rem .625rem;border-radius:6px;cursor:pointer}.kt-select__option[aria-selected=true]{background:var(--select-option-selected-bg, color-mix(in srgb, var(--kt-primary, #0b57d0) 14%, transparent));color:var(--select-option-selected-color, inherit);font-weight:var(--select-option-selected-weight, 600)}.kt-select__option--active:not([aria-disabled=true]),.kt-select__option:hover:not([aria-disabled=true]){background:var(--select-option-hover-bg, color-mix(in srgb, currentColor 8%, transparent))}.kt-select__option[aria-disabled=true]{opacity:.5;cursor:not-allowed}.kt-select__empty{padding:.5rem .625rem;color:var(--field-hint-color, #5f6368)}.kt-select__truncated-info{box-sizing:border-box;padding:.5rem .625rem;font-size:.875rem;font-style:italic;color:var(--field-hint-color, #5f6368);border-block-start:1px solid var(--field-border-color, #c4c7c5);pointer-events:none}}\n"] }]
2614
+ args: [{ selector: 'kt-select', changeDetection: ChangeDetectionStrategy.OnPush, imports: [KtField, KtFieldControl, NgTemplateOutlet, Combobox, ComboboxPopup, ComboboxWidget, Listbox, Option], template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"fieldErrors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n [hideLabel]=\"hideLabel()\"\n [hideErrors]=\"hideErrors()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div class=\"kt-select\" [class.kt-select--open]=\"expanded()\">\n <button\n #combobox=\"ngCombobox\"\n #trigger\n ngCombobox\n ktFieldControl\n type=\"button\"\n class=\"kt-field-box kt-select__trigger\"\n [class.kt-select__trigger--clearable]=\"showClear()\"\n [(expanded)]=\"expanded\"\n [disabled]=\"disabled()\"\n [softDisabled]=\"false\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n [attr.data-filled]=\"selectedOption() ? '' : null\"\n [attr.data-pending]=\"pending() ? '' : null\"\n [attr.aria-busy]=\"pending() ? 'true' : null\"\n >\n <span class=\"kt-select__value\">\n @if (triggerDef(); as def) {\n <ng-container [ngTemplateOutlet]=\"def.template\" [ngTemplateOutletContext]=\"{ $implicit: selectedOption() }\" />\n } @else if (selectedOption(); as option) {\n {{ labelOf(option) }}\n } @else {\n <span class=\"kt-select__placeholder\">{{ resolvedPlaceholder() }}</span>\n }\n </span>\n <span class=\"kt-select__arrow\" aria-hidden=\"true\">arrow_drop_down</span>\n </button>\n\n <!-- Effacer la s\u00E9lection depuis le champ : sibling du trigger (pas de bouton imbriqu\u00E9 dans un bouton).\n mousedown pr\u00E9ventif : un tap ne doit pas voler le focus du combobox (closePopupOnBlur). -->\n @if (showClear()) {\n <button\n type=\"button\"\n class=\"kt-select__clear\"\n [attr.aria-label]=\"clearLabel()\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"clearSelection()\"\n >\n <span class=\"kt-select__clear-icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n <!-- Un seul Popover (top-layer). CSS @media : dropdown ancr\u00E9 (desktop) \u2194 bottom-sheet (t\u00E9l\u00E9phone).\n Pas de <dialog>.showModal() : ce combobox se ferme au blur, et showModal volerait le focus.\n Sheet = SCROLLER \u00E0 snap (ADR-0005) : le spacer occupe un \u00E9cran (snap \u00AB ferm\u00E9 \u00BB), la carte\n snappe en bas (snap \u00AB ouvert \u00BB) ; le geste de fermeture est le scroll natif lui-m\u00EAme. -->\n <ng-template ngComboboxPopup [combobox]=\"combobox\" [popupType]=\"filterable() ? 'dialog' : 'listbox'\">\n <div #popup popover=\"manual\" class=\"kt-select__popup\" [class.kt-select__popup--sheet]=\"compact()\">\n @if (compact()) {\n <div class=\"kt-select__sheet-scrim\" aria-hidden=\"true\" (click)=\"expanded.set(false)\"></div>\n <div class=\"kt-select__sheet-spacer\" aria-hidden=\"true\"></div>\n }\n <div class=\"kt-select__sheet-card\">\n @if (compact()) {\n <!-- Poign\u00E9e D\u00C9CORATIVE (ADR-0005) : la sheet s'attrape partout, le geste est natif. -->\n <div class=\"kt-select__sheet-grab\" aria-hidden=\"true\" (mousedown)=\"$event.preventDefault()\"></div>\n <!-- mousedown pr\u00E9ventif : un tap sur la carcasse ne doit pas voler le focus du widget\n (closePopupOnBlur fermerait le combobox) ; le click du bouton Fermer survit. -->\n <header class=\"kt-select__sheet-header\" (mousedown)=\"$event.preventDefault()\">\n <span class=\"kt-select__sheet-title\">{{ label() }}</span>\n <button\n type=\"button\"\n class=\"kt-select__sheet-close\"\n [attr.aria-label]=\"resolvedCloseLabel()\"\n (click)=\"expanded.set(false)\"\n >\n <span class=\"kt-select__sheet-close-icon\" aria-hidden=\"true\">close</span>\n </button>\n </header>\n }\n @if (filterable()) {\n <!-- Mode filtrable : le widget combobox est le panneau ENTIER (champ + annonce + liste).\n Indispensable : un focus pos\u00E9 hors de l'\u00E9l\u00E9ment ngComboboxWidget ferme le popup\n (closePopupOnBlur de @angular/aria) \u2014 le champ doit donc vivre dans ce sous-arbre. -->\n <div\n ngComboboxWidget\n role=\"dialog\"\n class=\"kt-select__panel\"\n [id]=\"panelId\"\n [attr.aria-label]=\"label()\"\n [activeDescendant]=\"lb.activeDescendant()\"\n >\n <div class=\"kt-select__filter\">\n <input\n #filterInput\n type=\"search\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n aria-expanded=\"true\"\n class=\"kt-select__filter-input\"\n autocomplete=\"off\"\n [placeholder]=\"resolvedFilterPlaceholder()\"\n [attr.aria-label]=\"resolvedFilterLabel()\"\n [attr.aria-controls]=\"lb.id()\"\n [attr.aria-activedescendant]=\"lb.activeDescendant()\"\n [value]=\"filterText()\"\n (input)=\"onFilterInput($event)\"\n (keydown)=\"onFilterKeydown($event)\"\n />\n </div>\n <!-- Nombre de r\u00E9sultats annonc\u00E9 (diff\u00E9r\u00E9) aux lecteurs d'\u00E9cran : une liste qui\n r\u00E9tr\u00E9cit en silence est per\u00E7ue comme un bug (tests utilisateurs S. Higley). -->\n <div class=\"kt-select__sr-only\" role=\"status\" aria-live=\"polite\">{{ announcedCount() }}</div>\n <ul\n #lb=\"ngListbox\"\n #listboxEl\n ngListbox\n [focusMode]=\"compact() && !filterable() ? 'roving' : 'activedescendant'\"\n selectionMode=\"explicit\"\n class=\"kt-select__listbox\"\n [attr.aria-label]=\"label()\"\n [value]=\"listboxValue()\"\n (valueChange)=\"onListboxValueChange($event)\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n >\n @for (item of displayedOptions(); track keyOf(item)) {\n <li\n #opt=\"ngOption\"\n ngOption\n class=\"kt-select__option\"\n [value]=\"keyOf(item)\"\n [label]=\"labelOf(item)\"\n [disabled]=\"disabledOf(item)\"\n [class.kt-select__option--active]=\"opt.active()\"\n >\n @if (optionDef(); as def) {\n <ng-container\n [ngTemplateOutlet]=\"def.template\"\n [ngTemplateOutletContext]=\"{\n $implicit: item,\n selected: !!opt.selected(),\n active: opt.active(),\n }\"\n />\n } @else {\n {{ labelOf(item) }}\n }\n </li>\n } @empty {\n <li class=\"kt-select__empty\" role=\"option\" aria-disabled=\"true\" aria-selected=\"false\">\n {{ resolvedEmptyText() }}\n </li>\n }\n @if (filterable() && filteredOptions().length > maxVisibleOptions()) {\n <li class=\"kt-select__truncated-info\" role=\"option\" aria-disabled=\"true\" aria-selected=\"false\">\n {{ resolvedTruncatedResultsText()(maxVisibleOptions(), filteredOptions().length) }}\n </li>\n }\n </ul>\n </div>\n } @else {\n <ul\n #listbox=\"ngListbox\"\n #listboxEl\n ngComboboxWidget\n ngListbox\n [focusMode]=\"compact() ? 'roving' : 'activedescendant'\"\n selectionMode=\"explicit\"\n class=\"kt-select__listbox\"\n [attr.aria-label]=\"label()\"\n [value]=\"listboxValue()\"\n (valueChange)=\"onListboxValueChange($event)\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n [activeDescendant]=\"listbox.activeDescendant()\"\n >\n @for (item of options(); track keyOf(item)) {\n <li\n #opt=\"ngOption\"\n ngOption\n class=\"kt-select__option\"\n [value]=\"keyOf(item)\"\n [label]=\"labelOf(item)\"\n [disabled]=\"disabledOf(item)\"\n [class.kt-select__option--active]=\"opt.active()\"\n >\n @if (optionDef(); as def) {\n <ng-container\n [ngTemplateOutlet]=\"def.template\"\n [ngTemplateOutletContext]=\"{ $implicit: item, selected: !!opt.selected(), active: opt.active() }\"\n />\n } @else {\n {{ labelOf(item) }}\n }\n </li>\n } @empty {\n <li class=\"kt-select__empty\" role=\"option\" aria-disabled=\"true\" aria-selected=\"false\">\n {{ resolvedEmptyText() }}\n </li>\n }\n </ul>\n }\n </div>\n </div>\n </ng-template>\n </div>\n</kt-field>\n", styles: ["@layer kt-aaa.components{:host{display:block}.kt-select{position:relative}.kt-select__trigger{display:flex;align-items:center;justify-content:space-between;gap:var(--field-control-gap, .5rem);inline-size:100%;cursor:pointer;text-align:start;font:inherit;color:var(--field-color, inherit)}.kt-select__trigger:disabled{cursor:not-allowed;background:var(--field-disabled-bg, #f1f3f4);color:color-mix(in srgb,currentColor 50%,transparent)}.kt-select__value{flex:1;min-inline-size:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kt-select__placeholder{color:var(--field-hint-color, #5f6368)}.kt-select__arrow{flex:none;font-family:Material Symbols Outlined;font-size:1.25em;line-height:1;font-feature-settings:\"liga\";color:var(--field-icon-color, #5f6368);transition:var(--select-arrow-transition, transform .12s ease);-webkit-font-smoothing:antialiased}.kt-select--open .kt-select__arrow{transform:rotate(180deg)}.kt-select__trigger--clearable .kt-select__value{margin-inline-end:2rem}.kt-select__clear{position:absolute;inset-block-start:50%;inset-inline-end:2.5rem;translate:0 -50%;display:inline-flex;align-items:center;justify-content:center;inline-size:24px;block-size:24px;padding:0;border:0;border-radius:50%;background:transparent;color:var(--field-icon-color, #5f6368);cursor:pointer}.kt-select__clear:after{content:\"\";position:absolute;inset:-10px}.kt-select__clear:hover{background-color:color-mix(in srgb,currentColor 12%,transparent);color:var(--field-color, inherit)}.kt-select__clear:focus-visible{outline:2px solid var(--field-border-color-focus, #0b57d0);outline-offset:1px}.kt-select__clear-icon{font-family:Material Symbols Outlined;font-feature-settings:\"liga\";font-size:1.25rem;line-height:1;-webkit-font-smoothing:antialiased}.kt-select__popup{box-sizing:border-box;display:flex;flex-direction:column;margin:0;padding:0;border-width:var(--select-popup-border-width, var(--field-border-width, 1px));border-style:var(--field-border-style, solid);border-color:var(--field-border-color, #c4c7c5);border-radius:var(--field-radius, 8px);background:var(--select-popup-bg, var(--kt-surface-container, var(--kt-surface, #fff)));color:var(--field-color, inherit);box-shadow:var(--select-popup-shadow, 0 4px 12px rgb(0 0 0 / 12%));-webkit-backdrop-filter:var(--select-popup-backdrop-filter, none);backdrop-filter:var(--select-popup-backdrop-filter, none);max-block-size:var(--select-popup-max-height, 16rem);overflow:hidden}.kt-select__sheet-card{display:contents}.kt-select__popup:not(:popover-open){display:none!important}.kt-select__popup:popover-open{animation:var(--select-popup-enter-animation, none)}@media(prefers-reduced-motion:reduce){.kt-select__popup:popover-open{animation:none}}.kt-select__listbox{flex:1 1 auto;min-block-size:0;margin:0;padding:.25rem;list-style:none;overflow-y:auto}.kt-select__panel{display:flex;flex-direction:column;flex:1 1 auto;min-block-size:0}.kt-select__filter{flex:none;padding:.5rem;border-block-end:1px solid var(--field-border-color, #c4c7c5)}.kt-select__filter-input{box-sizing:border-box;inline-size:100%;min-block-size:var(--field-min-height, 44px);padding:.375rem .625rem;border:var(--field-border-width, 1px) var(--field-border-style, solid) var(--field-border-color, #c4c7c5);border-radius:calc(var(--field-radius, 8px) * .75);background:var(--select-popup-bg, var(--kt-surface-container, var(--kt-surface, #fff)));color:var(--field-color, inherit);font:inherit;appearance:none}.kt-select__filter-input::placeholder{color:var(--field-hint-color, #5f6368)}.kt-select__filter-input:focus-visible{outline:2px solid var(--field-border-color-focus, #0b57d0);outline-offset:-1px}.kt-select__filter-input::-webkit-search-cancel-button{appearance:none;inline-size:1rem;block-size:1rem;margin-inline-start:.375rem;cursor:pointer;background-color:var(--field-icon-color, #5f6368);-webkit-mask:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z'/%3E%3C/svg%3E\") center / contain no-repeat;mask:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z'/%3E%3C/svg%3E\") center / contain no-repeat}.kt-select__sr-only{position:absolute;inset-block-start:0;inset-inline-start:0;inline-size:1px;block-size:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}@supports (anchor-name: --x){.kt-select__popup{position:fixed;inset:auto;top:anchor(bottom);left:anchor(left);margin-block-start:.25rem;min-inline-size:anchor-size(width);width:max-content;max-inline-size:min(90vw,28rem);position-try-fallbacks:flip-block,flip-inline,flip-block flip-inline}}@supports not (anchor-name: --x){.kt-select__popup{position:fixed;inset:auto 0 0;inline-size:100%;max-inline-size:100%;border-radius:var(--kt-sheet-radius, 16px) var(--kt-sheet-radius, 16px) 0 0}}.kt-select__popup--sheet{position:fixed!important;inset:0!important;inline-size:100%!important;max-inline-size:100%!important;min-inline-size:0!important;width:100%!important;height:100%!important;max-block-size:none!important;margin:0!important;padding:0!important;border:none!important;background:transparent!important;box-shadow:none!important;border-radius:0!important;display:block;overflow-y:auto!important;scroll-snap-type:y mandatory;overscroll-behavior:contain;scrollbar-width:none}.kt-select__popup--sheet .kt-select__sheet-spacer{block-size:100%;scroll-snap-align:start;scroll-snap-stop:always}.kt-select__popup--sheet .kt-select__sheet-card{position:relative;z-index:2;display:flex;flex-direction:column;background:var(--select-popup-bg, var(--kt-surface-container, var(--kt-surface, #fff)));border-radius:var(--kt-sheet-radius, 16px) var(--kt-sheet-radius, 16px) 0 0;box-shadow:var(--kt-sheet-shadow, 0 -4px 16px rgb(0 0 0 / 12%));max-block-size:var(--kt-sheet-max-block-size, 85svh);width:100%;overflow:hidden;scroll-snap-align:end;scroll-snap-stop:always}.kt-select__popup--sheet .kt-select__sheet-card:has(.kt-select__filter){block-size:var(--kt-sheet-max-block-size, 85svh);max-block-size:var(--kt-sheet-max-block-size, 85svh)}::ng-deep .kt-select__popup--sheet::backdrop{display:none!important}.kt-select__sheet-scrim{display:none}.kt-select__popup--sheet .kt-select__sheet-scrim{display:block;position:fixed;inset:0;z-index:1;background:var(--kt-sheet-scrim, rgb(0 0 0 / 40%));opacity:0;pointer-events:auto;transition:opacity var(--kt-sheet-anim-duration, .12s) ease,overlay var(--kt-sheet-anim-duration, .12s) allow-discrete,display var(--kt-sheet-anim-duration, .12s) allow-discrete}.kt-select__popup--sheet:popover-open .kt-select__sheet-scrim{opacity:1}@starting-style{.kt-select__popup--sheet:popover-open .kt-select__sheet-scrim{opacity:0}}.kt-select__popup--sheet.kt-select__popup--closing .kt-select__sheet-scrim,.kt-select__popup--sheet:popover-open.kt-select__popup--closing .kt-select__sheet-scrim{opacity:0;transition:opacity var(--kt-sheet-exit-duration, 90ms) ease}.kt-select__popup--sheet .kt-select__option{--select-option-min-height: 44px;padding-block:.625rem}.kt-select__popup--sheet .kt-select__filter-input{font-size:1rem;min-block-size:44px}@media(prefers-reduced-motion:reduce){.kt-select__popup--sheet .kt-select__sheet-scrim{transition:none}}.kt-select__sheet-grab{display:flex;align-items:center;justify-content:center;flex:none;block-size:28px}.kt-select__sheet-grab:before{content:\"\";inline-size:2.25rem;block-size:.25rem;border-radius:999px;background:var(--kt-sheet-grab-color, var(--kt-outline, #c4c7c5))}.kt-select__sheet-header{display:flex;align-items:center;justify-content:space-between;gap:.5rem;flex:none;padding-block:.5rem;padding-inline:1rem .5rem;border-block-end:1px solid var(--field-border-color, #c4c7c5)}.kt-select__sheet-title{font-weight:600}.kt-select__sheet-close{display:inline-flex;align-items:center;justify-content:center;flex:none;inline-size:44px;block-size:44px;padding:0;border:0;border-radius:50%;background:transparent;color:var(--field-icon-color, #5f6368);cursor:pointer}.kt-select__sheet-close:focus-visible{outline:2px solid var(--field-border-color-focus, #0b57d0);outline-offset:2px}.kt-select__sheet-close-icon{font-family:Material Symbols Outlined;font-feature-settings:\"liga\";font-size:1.5rem;line-height:1;-webkit-font-smoothing:antialiased}.kt-select__option{display:flex;align-items:center;gap:.5rem;box-sizing:border-box;min-block-size:var( --select-option-min-height, 44px );padding:.5rem .625rem;border-radius:6px;cursor:pointer}.kt-select__option[aria-selected=true]{background:var(--select-option-selected-bg, color-mix(in srgb, var(--kt-primary, #0b57d0) 14%, transparent));color:var(--select-option-selected-color, inherit);font-weight:var(--select-option-selected-weight, 600)}.kt-select__option--active:not([aria-disabled=true]),.kt-select__option:hover:not([aria-disabled=true]){background:var(--select-option-hover-bg, color-mix(in srgb, currentColor 8%, transparent))}.kt-select__option[aria-disabled=true]{opacity:.5;cursor:not-allowed}.kt-select__empty{padding:.5rem .625rem;color:var(--field-hint-color, #5f6368)}.kt-select__truncated-info{box-sizing:border-box;padding:.5rem .625rem;font-size:.875rem;font-style:italic;color:var(--field-hint-color, #5f6368);border-block-start:1px solid var(--field-border-color, #c4c7c5);pointer-events:none}}\n"] }]
2517
2615
  }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], optionDef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => KtSelectOptionDef), { isSignal: true }] }], triggerDef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => KtSelectTriggerDef), { isSignal: true }] }] } });
2518
2616
 
2519
2617
  /** Configure les `kt-select` d'un sous-arbre via DI (équivalent du Context provider de react-select).
@@ -3194,12 +3292,32 @@ class KtChipList {
3194
3292
  this.statusTimer = setTimeout(() => this.status.set(''), STATUS_CLEAR_MS);
3195
3293
  }
3196
3294
  activeTransition = null;
3295
+ /**
3296
+ * Vrai sur le moteur WebKit (Safari desktop + TOUS les navigateurs iOS, qui embarquent WebKit).
3297
+ *
3298
+ * Contournement DOCUMENTÉ et RÉVERSIBLE d'un bug de compositing des View Transitions au niveau
3299
+ * document sur WebKit : après la transition, les chips (hôtes d'éléments custom dont le
3300
+ * `view-transition-name` est posé puis retiré dynamiquement) ne se repeignent pas — seules les
3301
+ * croix « retirer » (boutons natifs, compositées sur une couche distincte) subsistent à l'écran.
3302
+ * Touche aussi bien le retrait que le déplier/replier : les deux passent par ce wrapper.
3303
+ *
3304
+ * Le défaut n'est PAS feature-detectable : `startViewTransition` répond présente puis rate le
3305
+ * rendu final, d'où la détection de MOTEUR. `navigator.vendor` est gelé pour compat — vaut
3306
+ * « Apple Computer, Inc. » sur WebKit UNIQUEMENT (Blink = « Google Inc. », Gecko = « »). On NE
3307
+ * gate PAS sur l'absence de la variante scopée `element.startViewTransition` : cela exclurait
3308
+ * Firefox à tort (transition document parfaitement rendue chez lui). À RETIRER quand Safari
3309
+ * corrigera le compositing.
3310
+ */
3311
+ isWebKitEngine() {
3312
+ return this.doc.defaultView?.navigator.vendor === 'Apple Computer, Inc.';
3313
+ }
3197
3314
  /** Exécute `action` dans une View Transition (morph des chips qui se déplacent, entrée/sortie
3198
3315
  stylées via `::view-transition-*(.chip-transition)` — cf. tokens.css). Transition SCOPÉE à
3199
3316
  l'élément quand le navigateur le permet (`element.startViewTransition`, Chrome 147+) ; sinon
3200
3317
  transition document — dans les deux cas, seuls les chips de CETTE liste sont nommés (cf.
3201
- `transitioning`). Fallback : action directe si l'API est absente ou si l'utilisateur
3202
- préfère moins de mouvement. */
3318
+ `transitioning`). Fallback : action directe (retrait/dépli instantané, état final garanti
3319
+ correct) si l'API est absente, si l'utilisateur préfère moins de mouvement, ou sur WebKit
3320
+ (bug de compositing, cf. `isWebKitEngine`). */
3203
3321
  withViewTransition(action) {
3204
3322
  if (!isPlatformBrowser(this.platformId)) {
3205
3323
  action();
@@ -3212,7 +3330,8 @@ class KtChipList {
3212
3330
  const hostEl = this.host.nativeElement;
3213
3331
  const startViewTransition = hostEl.startViewTransition?.bind(hostEl) ??
3214
3332
  this.doc.startViewTransition?.bind(this.doc);
3215
- if (!startViewTransition || prefersReducedMotion) {
3333
+ // WebKit : court-circuit AVANT tout nommage — sinon les chips restent fantômes (bug iOS).
3334
+ if (!startViewTransition || prefersReducedMotion || this.isWebKitEngine()) {
3216
3335
  action();
3217
3336
  return;
3218
3337
  }
@@ -3467,11 +3586,7 @@ class KtMultiSelect extends KtBaseSelect {
3467
3586
  (clés ou objets), `options` les objets options correspondants, dans l'ordre de sélection. */
3468
3587
  selectionChange = output();
3469
3588
  // --- Présentation / Configuration (spécifique multi) ---
3470
- /** Bouton « tout effacer » sur le champ (même contrat que `clearable` de BaseInputField). @default false */
3471
- clearable = input(false, { ...(ngDevMode ? { debugName: "clearable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
3472
- /** Libellé i18n du bouton « tout effacer ». @default 'Clear' (ou KT_FIELD_CONFIG.clearLabel) */
3473
- clearLabel = input(this.fieldConfig?.clearLabel ?? 'Clear', /* @ts-ignore */
3474
- ...(ngDevMode ? [{ debugName: "clearLabel" }] : /* istanbul ignore next */ []));
3589
+ // `clearable` / `clearLabel` sont mutualisés dans KtBaseSelect (contrat identique au single).
3475
3590
  /** Barre « Tout sélectionner / Tout effacer » en tête du popup (bascule le popup en panneau dialog). */
3476
3591
  selectionActions = input(false, { ...(ngDevMode ? { debugName: "selectionActions" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
3477
3592
  /** Nombre maximal de chips affichés avant repli derrière un bouton « +N more ». Défaut : illimité. */
@@ -3694,7 +3809,7 @@ class KtMultiSelect extends KtBaseSelect {
3694
3809
  this.announceNow(this.resolvedSelectionCountText()(this.selectedOptions().length));
3695
3810
  }
3696
3811
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtMultiSelect, deps: null, target: i0.ɵɵFactoryTarget.Component });
3697
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: KtMultiSelect, isStandalone: true, selector: "kt-multi-select", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, clearLabel: { classPropertyName: "clearLabel", publicName: "clearLabel", isSignal: true, isRequired: false, transformFunction: null }, selectionActions: { classPropertyName: "selectionActions", publicName: "selectionActions", isSignal: true, isRequired: false, transformFunction: null }, maxVisibleChips: { classPropertyName: "maxVisibleChips", publicName: "maxVisibleChips", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", selectionChange: "selectionChange" }, queries: [{ propertyName: "optionDef", first: true, predicate: KtMultiSelectOptionDef, descendants: true, isSignal: true }, { propertyName: "triggerDef", first: true, predicate: KtMultiSelectTriggerDef, descendants: true, isSignal: true }, { propertyName: "chipDef", first: true, predicate: KtMultiSelectChipDef, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "chipList", first: true, predicate: KtChipList, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"fieldErrors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n [hideLabel]=\"hideLabel()\"\n [hideErrors]=\"hideErrors()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div class=\"kt-select\" [class.kt-select--open]=\"expanded()\">\n <button\n #combobox=\"ngCombobox\"\n #trigger\n ngCombobox\n ktFieldControl\n type=\"button\"\n class=\"kt-field-box kt-select__trigger\"\n [class.kt-select__trigger--clearable]=\"showClear()\"\n [(expanded)]=\"expanded\"\n [disabled]=\"disabled()\"\n [softDisabled]=\"false\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n [attr.data-filled]=\"selectedOptions().length ? '' : null\"\n [attr.data-pending]=\"pending() ? '' : null\"\n [attr.aria-busy]=\"pending() ? 'true' : null\"\n (keydown)=\"onTriggerKeydown($event)\"\n >\n <span class=\"kt-select__value\">\n @if (triggerDef(); as def) {\n <ng-container\n [ngTemplateOutlet]=\"def.template\"\n [ngTemplateOutletContext]=\"{ $implicit: selectedOptions() }\"\n />\n } @else if (selectedOptions().length > 0) {\n {{ triggerText() }}\n } @else {\n <span class=\"kt-select__placeholder\">{{ resolvedPlaceholder() }}</span>\n }\n </span>\n <span class=\"kt-select__arrow\" aria-hidden=\"true\">arrow_drop_down</span>\n </button>\n\n <!-- Tout effacer depuis le champ : sibling du trigger (pas de bouton imbriqu\u00E9 dans un bouton). -->\n @if (showClear()) {\n <button\n type=\"button\"\n class=\"kt-select__clear\"\n [attr.aria-label]=\"clearLabel()\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"clearSelection()\"\n >\n <span class=\"kt-select__clear-icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n <!-- Popup Popover (top-layer). M\u00EAme logique mobile bottom-sheet adaptative que le select classique. -->\n <ng-template ngComboboxPopup [combobox]=\"combobox\" [popupType]=\"dialogMode() ? 'dialog' : 'listbox'\">\n <div #popup popover=\"manual\" class=\"kt-select__popup\" [class.kt-select__popup--sheet]=\"compact()\">\n @if (compact()) {\n <div class=\"kt-select__sheet-scrim\" aria-hidden=\"true\" (click)=\"expanded.set(false)\"></div>\n }\n <div class=\"kt-select__sheet-card\">\n @if (compact()) {\n <div\n class=\"kt-select__sheet-grab\"\n aria-hidden=\"true\"\n (pointerdown)=\"onDragStart($event)\"\n (mousedown)=\"$event.preventDefault()\"\n ></div>\n <header class=\"kt-select__sheet-header\">\n <span class=\"kt-select__sheet-title\">{{ label() }}</span>\n <button\n type=\"button\"\n class=\"kt-select__sheet-close\"\n [attr.aria-label]=\"resolvedCloseLabel()\"\n (click)=\"expanded.set(false)\"\n >\n <span class=\"kt-select__sheet-close-icon\" aria-hidden=\"true\">close</span>\n </button>\n </header>\n }\n @if (dialogMode()) {\n <!-- Mode panneau (filtre et/ou actions de masse) : Widget Dialog -->\n <div\n ngComboboxWidget\n role=\"dialog\"\n class=\"kt-select__panel\"\n [id]=\"panelId\"\n [attr.aria-label]=\"label()\"\n [activeDescendant]=\"lb.activeDescendant()\"\n (keydown)=\"onPanelKeydown($event)\"\n >\n @if (selectionActions()) {\n <div class=\"kt-select__actions\">\n <button type=\"button\" class=\"kt-select__action\" (click)=\"selectAllFiltered()\">\n {{ resolvedSelectAllLabel() }}\n </button>\n <button type=\"button\" class=\"kt-select__action\" (click)=\"clearAllFiltered()\">\n {{ resolvedClearAllLabel() }}\n </button>\n </div>\n }\n @if (filterable()) {\n <div class=\"kt-select__filter\">\n <input\n #filterInput\n type=\"search\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n aria-expanded=\"true\"\n class=\"kt-select__filter-input\"\n autocomplete=\"off\"\n [placeholder]=\"resolvedFilterPlaceholder()\"\n [attr.aria-label]=\"resolvedFilterLabel()\"\n [attr.aria-controls]=\"lb.id()\"\n [attr.aria-activedescendant]=\"lb.activeDescendant()\"\n [value]=\"filterText()\"\n (input)=\"onFilterInput($event)\"\n (keydown)=\"onFilterKeydown($event)\"\n />\n </div>\n }\n @if (selectedOptions().length > 0) {\n <!-- Rappel visuel (s\u00E9lections potentiellement masqu\u00E9es par le filtre) ;\n l'info SR passe par la live region ci-dessous \u2192 aria-hidden. -->\n <div class=\"kt-select__count\" aria-hidden=\"true\">{{ selectionCountLabel() }}</div>\n }\n <div class=\"kt-select__sr-only kt-select__filter-status\" role=\"status\" aria-live=\"polite\">\n {{ announcedCount() }}\n </div>\n <ul\n #lb=\"ngListbox\"\n #listboxEl\n ngListbox\n [multi]=\"true\"\n [focusMode]=\"compact() && !filterable() ? 'roving' : 'activedescendant'\"\n selectionMode=\"explicit\"\n class=\"kt-select__listbox\"\n [attr.aria-label]=\"label()\"\n [value]=\"listboxValue()\"\n (valueChange)=\"onListboxValueChange($event)\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n >\n @for (item of displayedOptions(); track keyOf(item)) {\n <li\n #opt=\"ngOption\"\n ngOption\n class=\"kt-select__option kt-select__option--multiple\"\n [value]=\"keyOf(item)\"\n [label]=\"labelOf(item)\"\n [disabled]=\"disabledOf(item)\"\n [class.kt-select__option--active]=\"opt.active()\"\n >\n <span class=\"kt-select__checkbox\" aria-hidden=\"true\">\n @if (opt.selected()) {\n <span class=\"kt-select__checkbox-icon\">check_box</span>\n } @else {\n <span class=\"kt-select__checkbox-icon\">check_box_outline_blank</span>\n }\n </span>\n <span class=\"kt-select__option-content\">\n @if (optionDef(); as def) {\n <ng-container\n [ngTemplateOutlet]=\"def.template\"\n [ngTemplateOutletContext]=\"{\n $implicit: item,\n selected: !!opt.selected(),\n active: opt.active(),\n }\"\n />\n } @else {\n {{ labelOf(item) }}\n }\n </span>\n </li>\n } @empty {\n <li class=\"kt-select__empty\" role=\"option\" aria-disabled=\"true\" aria-selected=\"false\">\n {{ resolvedEmptyText() }}\n </li>\n }\n @if (filterable() && filteredOptions().length > maxVisibleOptions()) {\n <li class=\"kt-select__truncated-info\" role=\"option\" aria-disabled=\"true\" aria-selected=\"false\">\n {{ resolvedTruncatedResultsText()(maxVisibleOptions(), filteredOptions().length) }}\n </li>\n }\n </ul>\n </div>\n } @else {\n <!-- Mode simple : Widget Listbox direct -->\n <ul\n #listbox=\"ngListbox\"\n #listboxEl\n ngComboboxWidget\n ngListbox\n [multi]=\"true\"\n [focusMode]=\"compact() ? 'roving' : 'activedescendant'\"\n selectionMode=\"explicit\"\n class=\"kt-select__listbox\"\n [attr.aria-label]=\"label()\"\n [value]=\"listboxValue()\"\n (valueChange)=\"onListboxValueChange($event)\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n [activeDescendant]=\"listbox.activeDescendant()\"\n >\n @for (item of options(); track keyOf(item)) {\n <li\n #opt=\"ngOption\"\n ngOption\n class=\"kt-select__option kt-select__option--multiple\"\n [value]=\"keyOf(item)\"\n [label]=\"labelOf(item)\"\n [disabled]=\"disabledOf(item)\"\n [class.kt-select__option--active]=\"opt.active()\"\n >\n <span class=\"kt-select__checkbox\" aria-hidden=\"true\">\n @if (opt.selected()) {\n <span class=\"kt-select__checkbox-icon\">check_box</span>\n } @else {\n <span class=\"kt-select__checkbox-icon\">check_box_outline_blank</span>\n }\n </span>\n <span class=\"kt-select__option-content\">\n @if (optionDef(); as def) {\n <ng-container\n [ngTemplateOutlet]=\"def.template\"\n [ngTemplateOutletContext]=\"{\n $implicit: item,\n selected: !!opt.selected(),\n active: opt.active(),\n }\"\n />\n } @else {\n {{ labelOf(item) }}\n }\n </span>\n </li>\n } @empty {\n <li class=\"kt-select__empty\" role=\"option\" aria-disabled=\"true\" aria-selected=\"false\">\n {{ resolvedEmptyText() }}\n </li>\n }\n </ul>\n }\n </div>\n </div>\n </ng-template>\n </div>\n\n <!-- Chips r\u00E9vocables (Option 1) sous le trigger : d\u00E9l\u00E9gu\u00E9s au composant r\u00E9utilisable\n kt-chip-list (focus management, repli +N, live region). Les textes r\u00E9solus depuis\n KT_SELECT_CONFIG sont pass\u00E9s en inputs (ils priment sur un \u00E9ventuel KT_CHIPS_CONFIG). -->\n <kt-chip-list\n [items]=\"selectedOptions()\"\n [itemLabel]=\"chipLabelOf\"\n [itemKey]=\"chipKeyOf\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n [maxVisible]=\"maxVisibleChips()\"\n [listLabel]=\"resolvedSelectedItemsLabel()\"\n [removeItemLabel]=\"resolvedRemoveItemLabel()\"\n [itemRemovedText]=\"resolvedItemRemovedText()\"\n [moreLabel]=\"resolvedMoreChipsLabel()\"\n [lessLabel]=\"resolvedLessChipsLabel()\"\n [chipTemplate]=\"chipDef()?.template ?? null\"\n [emptyFocusTarget]=\"triggerEl()?.nativeElement\"\n (removed)=\"removeOption($event.item)\"\n />\n</kt-field>\n", styles: ["@layer kt-aaa.components{:host{display:block}.kt-select{position:relative}.kt-select__trigger{display:flex;align-items:center;justify-content:space-between;gap:var(--field-control-gap, .5rem);inline-size:100%;cursor:pointer;text-align:start;font:inherit;color:var(--field-color, inherit)}.kt-select__trigger:disabled{cursor:not-allowed;background:var(--field-disabled-bg, #f1f3f4);color:color-mix(in srgb,currentColor 50%,transparent)}.kt-select__value{flex:1;min-inline-size:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kt-select__placeholder{color:var(--field-hint-color, #5f6368)}.kt-select__arrow{flex:none;font-family:Material Symbols Outlined;font-size:1.25em;line-height:1;font-feature-settings:\"liga\";color:var(--field-icon-color, #5f6368);transition:var(--select-arrow-transition, transform .12s ease);-webkit-font-smoothing:antialiased}.kt-select--open .kt-select__arrow{transform:rotate(180deg)}.kt-select__popup{box-sizing:border-box;display:flex;flex-direction:column;margin:0;padding:0;border-width:var(--select-popup-border-width, var(--field-border-width, 1px));border-style:var(--field-border-style, solid);border-color:var(--field-border-color, #c4c7c5);border-radius:var(--field-radius, 8px);background:var(--select-popup-bg, var(--kt-surface-container, var(--kt-surface, #fff)));color:var(--field-color, inherit);box-shadow:var(--select-popup-shadow, 0 4px 12px rgb(0 0 0 / 12%));-webkit-backdrop-filter:var(--select-popup-backdrop-filter, none);backdrop-filter:var(--select-popup-backdrop-filter, none);max-block-size:var(--select-popup-max-height, 16rem);overflow:hidden}.kt-select__sheet-card{display:contents}.kt-select__popup:not(:popover-open){display:none!important}.kt-select__popup:popover-open{animation:var(--select-popup-enter-animation, none)}@media(prefers-reduced-motion:reduce){.kt-select__popup:popover-open{animation:none}}.kt-select__listbox{flex:1 1 auto;min-block-size:0;margin:0;padding:.25rem;list-style:none;overflow-y:auto}.kt-select__panel{display:flex;flex-direction:column;flex:1 1 auto;min-block-size:0}.kt-select__filter{flex:none;padding:.5rem;border-block-end:1px solid var(--field-border-color, #c4c7c5)}.kt-select__filter-input{box-sizing:border-box;inline-size:100%;min-block-size:var(--field-min-height, 44px);padding:.375rem .625rem;border:var(--field-border-width, 1px) var(--field-border-style, solid) var(--field-border-color, #c4c7c5);border-radius:calc(var(--field-radius, 8px) * .75);background:var(--select-popup-bg, var(--kt-surface-container, var(--kt-surface, #fff)));color:var(--field-color, inherit);font:inherit;appearance:none}.kt-select__filter-input::placeholder{color:var(--field-hint-color, #5f6368)}.kt-select__filter-input:focus-visible{outline:2px solid var(--field-border-color-focus, #0b57d0);outline-offset:-1px}.kt-select__filter-input::-webkit-search-cancel-button{appearance:none;inline-size:1rem;block-size:1rem;margin-inline-start:.375rem;cursor:pointer;background-color:var(--field-icon-color, #5f6368);-webkit-mask:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z'/%3E%3C/svg%3E\") center / contain no-repeat;mask:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z'/%3E%3C/svg%3E\") center / contain no-repeat}.kt-select__sr-only{position:absolute;inset-block-start:0;inset-inline-start:0;inline-size:1px;block-size:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}@supports (anchor-name: --x){.kt-select__popup{position:fixed;inset:auto;top:anchor(bottom);left:anchor(left);margin-block-start:.25rem;min-inline-size:anchor-size(width);width:max-content;max-inline-size:min(90vw,28rem);position-try-fallbacks:flip-block,flip-inline,flip-block flip-inline}}@supports not (anchor-name: --x){.kt-select__popup{position:fixed;inset:auto 0 0;inline-size:100%;max-inline-size:100%;border-radius:var(--kt-sheet-radius, 16px) var(--kt-sheet-radius, 16px) 0 0}}.kt-select__popup--sheet{position:fixed!important;inset:0!important;inline-size:100%!important;max-inline-size:100%!important;min-inline-size:0!important;width:100%!important;height:100%!important;max-block-size:none!important;margin:0!important;padding:0!important;border:none!important;background:transparent!important;box-shadow:none!important;border-radius:0!important;overflow:visible!important;display:flex;flex-direction:column!important;justify-content:flex-end!important}.kt-select__popup--sheet .kt-select__sheet-card{position:relative;z-index:2;display:flex;flex-direction:column;background:var(--select-popup-bg, var(--kt-surface-container, var(--kt-surface, #fff)));border-radius:var(--kt-sheet-radius, 16px) var(--kt-sheet-radius, 16px) 0 0;box-shadow:var(--kt-sheet-shadow, 0 -4px 16px rgb(0 0 0 / 12%));max-block-size:var(--kt-sheet-max-block-size, 85svh);width:100%;overflow:hidden;translate:0 0;transition:translate var(--kt-sheet-anim-duration, .12s) ease}.kt-select__popup--sheet .kt-select__sheet-card:has(.kt-select__filter){block-size:var(--kt-sheet-max-block-size, 85svh);max-block-size:var(--kt-sheet-max-block-size, 85svh)}.kt-select__popup--sheet:popover-open .kt-select__sheet-card{translate:0 0;animation:var(--select-sheet-enter-animation, kt-sheet-in var(--kt-sheet-anim-duration, .12s) ease)}.kt-select__popup--sheet .kt-select__sheet-card.kt-select__popup--dragging{transition:none}.kt-select__popup--sheet.kt-select__popup--closing .kt-select__sheet-card,.kt-select__popup--sheet:popover-open.kt-select__popup--closing .kt-select__sheet-card{translate:0 100%;transition:translate var(--kt-sheet-exit-duration, 90ms) cubic-bezier(.4,0,.2,1)}::ng-deep .kt-select__popup--sheet::backdrop{display:none!important}.kt-select__sheet-scrim{display:none}.kt-select__popup--sheet .kt-select__sheet-scrim{display:block;position:fixed;inset:0;z-index:1;background:var(--kt-sheet-scrim, rgb(0 0 0 / 40%));opacity:0;pointer-events:auto;transition:opacity var(--kt-sheet-anim-duration, .12s) ease,overlay var(--kt-sheet-anim-duration, .12s) allow-discrete,display var(--kt-sheet-anim-duration, .12s) allow-discrete}.kt-select__popup--sheet:popover-open .kt-select__sheet-scrim{opacity:1}@starting-style{.kt-select__popup--sheet:popover-open .kt-select__sheet-scrim{opacity:0}}.kt-select__popup--sheet.kt-select__popup--closing .kt-select__sheet-scrim,.kt-select__popup--sheet:popover-open.kt-select__popup--closing .kt-select__sheet-scrim{opacity:0;transition:opacity var(--kt-sheet-exit-duration, 90ms) ease}.kt-select__popup--sheet .kt-select__option{--select-option-min-height: 44px;padding-block:.625rem}.kt-select__popup--sheet .kt-select__filter-input{font-size:1rem;min-block-size:44px}@media(prefers-reduced-motion:reduce){.kt-select__popup--sheet .kt-select__sheet-card,.kt-select__popup--sheet .kt-select__sheet-scrim{transition:none;translate:0 0}}.kt-select__sheet-grab{display:flex;align-items:center;justify-content:center;flex:none;block-size:44px;cursor:grab;touch-action:none}.kt-select__sheet-grab:active{cursor:grabbing}.kt-select__sheet-grab:before{content:\"\";inline-size:2.25rem;block-size:.25rem;border-radius:999px;background:var(--kt-sheet-grab-color, var(--kt-outline, #c4c7c5))}.kt-select__sheet-header{display:flex;align-items:center;justify-content:space-between;gap:.5rem;flex:none;padding-block:.5rem;padding-inline:1rem .5rem;border-block-end:1px solid var(--field-border-color, #c4c7c5)}.kt-select__sheet-title{font-weight:600}.kt-select__sheet-close{display:inline-flex;align-items:center;justify-content:center;flex:none;inline-size:44px;block-size:44px;padding:0;border:0;border-radius:50%;background:transparent;color:var(--field-icon-color, #5f6368);cursor:pointer}.kt-select__sheet-close:focus-visible{outline:2px solid var(--field-border-color-focus, #0b57d0);outline-offset:2px}.kt-select__sheet-close-icon{font-family:Material Symbols Outlined;font-feature-settings:\"liga\";font-size:1.5rem;line-height:1;-webkit-font-smoothing:antialiased}.kt-select__option{display:flex;align-items:center;gap:.5rem;box-sizing:border-box;min-block-size:var( --select-option-min-height, 44px );padding:.5rem .625rem;border-radius:6px;cursor:pointer}.kt-select__option[aria-selected=true]{background:var(--select-option-selected-bg, color-mix(in srgb, var(--kt-primary, #0b57d0) 14%, transparent));color:var(--select-option-selected-color, inherit);font-weight:var(--select-option-selected-weight, 600)}.kt-select__option--active:not([aria-disabled=true]),.kt-select__option:hover:not([aria-disabled=true]){background:var(--select-option-hover-bg, color-mix(in srgb, currentColor 8%, transparent))}.kt-select__option[aria-disabled=true]{opacity:.5;cursor:not-allowed}.kt-select__empty{padding:.5rem .625rem;color:var(--field-hint-color, #5f6368)}.kt-select__truncated-info{box-sizing:border-box;padding:.5rem .625rem;font-size:.875rem;font-style:italic;color:var(--field-hint-color, #5f6368);border-block-start:1px solid var(--field-border-color, #c4c7c5);pointer-events:none}}\n", "@layer kt-aaa.components{.kt-select__trigger--clearable .kt-select__value{margin-inline-end:2rem}.kt-select__clear{position:absolute;inset-block-start:50%;inset-inline-end:2.5rem;translate:0 -50%;display:inline-flex;align-items:center;justify-content:center;inline-size:24px;block-size:24px;padding:0;border:0;border-radius:50%;background:transparent;color:var(--field-icon-color, #5f6368);cursor:pointer}.kt-select__clear:after{content:\"\";position:absolute;inset:-10px}.kt-select__clear:hover{background-color:color-mix(in srgb,currentColor 12%,transparent);color:var(--field-color, inherit)}.kt-select__clear:focus-visible{outline:2px solid var(--field-border-color-focus, #0b57d0);outline-offset:1px}.kt-select__clear-icon{font-family:Material Symbols Outlined;font-feature-settings:\"liga\";font-size:1.25rem;line-height:1;-webkit-font-smoothing:antialiased}.kt-select__actions{display:flex;gap:.25rem;flex:none;padding:.25rem .5rem;border-block-end:1px solid var(--field-border-color, #c4c7c5)}.kt-select__action{flex:1;min-block-size:44px;padding:.375rem .625rem;border:0;border-radius:calc(var(--field-radius, 8px) * .75);background:transparent;color:var(--kt-primary, #0b57d0);font:inherit;font-weight:500;cursor:pointer}.kt-select__action:hover{background:var(--select-option-hover-bg, color-mix(in srgb, currentColor 8%, transparent))}.kt-select__action:focus-visible{outline:2px solid var(--field-border-color-focus, #0b57d0);outline-offset:-2px}.kt-select__count{flex:none;padding:.25rem .75rem;font-size:.8125rem;color:var(--field-hint-color, #5f6368);border-block-end:1px solid var(--field-border-color, #c4c7c5)}.kt-select__checkbox{display:inline-flex;align-items:center;justify-content:center;flex:none;margin-inline-end:.25rem;-webkit-user-select:none;user-select:none}.kt-select__checkbox-icon{font-family:Material Symbols Outlined;font-feature-settings:\"liga\";font-size:1.25rem;line-height:1;color:var(--field-icon-color, #5f6368);-webkit-font-smoothing:antialiased}.kt-select__option[aria-selected=true] .kt-select__checkbox-icon{color:var(--kt-primary, #0b57d0)}.kt-select__option--multiple{display:flex;align-items:center;gap:.5rem}.kt-select__option-content{flex:1;min-inline-size:0}kt-chip-list:not([data-empty]){margin-block-start:.5rem}}\n"], dependencies: [{ kind: "component", type: KtField, selector: "kt-field", inputs: ["label", "hint", "helpText", "helpLabel", "customDescribedBy", "errors", "invalid", "required", "fieldId", "hideHintWhenInvalid", "showAllErrors", "hideLabel", "hideErrors", "appearance", "floatLabel"], outputs: ["helpClick"] }, { kind: "directive", type: KtFieldControl, selector: "[ktFieldControl]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: Combobox, selector: "[ngCombobox]", inputs: ["disabled", "softDisabled", "alwaysExpanded", "tabindex", "expanded", "value", "inlineSuggestion"], outputs: ["expandedChange", "valueChange"], exportAs: ["ngCombobox"] }, { kind: "directive", type: ComboboxPopup, selector: "ng-template[ngComboboxPopup]", inputs: ["combobox", "popupType"], exportAs: ["ngComboboxPopup"] }, { kind: "directive", type: ComboboxWidget, selector: "[ngComboboxWidget]", inputs: ["activeDescendant"], exportAs: ["ngComboboxWidget"] }, { kind: "directive", type: Listbox, selector: "[ngListbox]", inputs: ["id", "orientation", "multi", "wrap", "softDisabled", "focusMode", "selectionMode", "typeaheadDelay", "disabled", "readonly", "tabindex", "value"], outputs: ["valueChange"], exportAs: ["ngListbox"] }, { kind: "directive", type: Option, selector: "[ngOption]", inputs: ["id", "value", "disabled", "label"], exportAs: ["ngOption"] }, { kind: "component", type: KtChipList, selector: "kt-chip-list", inputs: ["items", "itemLabel", "itemKey", "removable", "disabled", "readonly", "maxVisible", "listLabel", "removeItemLabel", "itemRemovedText", "moreLabel", "lessLabel", "chipTemplate", "emptyFocusTarget"], outputs: ["removed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3812
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: KtMultiSelect, isStandalone: true, selector: "kt-multi-select", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, selectionActions: { classPropertyName: "selectionActions", publicName: "selectionActions", isSignal: true, isRequired: false, transformFunction: null }, maxVisibleChips: { classPropertyName: "maxVisibleChips", publicName: "maxVisibleChips", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", selectionChange: "selectionChange" }, queries: [{ propertyName: "optionDef", first: true, predicate: KtMultiSelectOptionDef, descendants: true, isSignal: true }, { propertyName: "triggerDef", first: true, predicate: KtMultiSelectTriggerDef, descendants: true, isSignal: true }, { propertyName: "chipDef", first: true, predicate: KtMultiSelectChipDef, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "chipList", first: true, predicate: KtChipList, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"fieldErrors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n [hideLabel]=\"hideLabel()\"\n [hideErrors]=\"hideErrors()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div class=\"kt-select\" [class.kt-select--open]=\"expanded()\">\n <button\n #combobox=\"ngCombobox\"\n #trigger\n ngCombobox\n ktFieldControl\n type=\"button\"\n class=\"kt-field-box kt-select__trigger\"\n [class.kt-select__trigger--clearable]=\"showClear()\"\n [(expanded)]=\"expanded\"\n [disabled]=\"disabled()\"\n [softDisabled]=\"false\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n [attr.data-filled]=\"selectedOptions().length ? '' : null\"\n [attr.data-pending]=\"pending() ? '' : null\"\n [attr.aria-busy]=\"pending() ? 'true' : null\"\n (keydown)=\"onTriggerKeydown($event)\"\n >\n <span class=\"kt-select__value\">\n @if (triggerDef(); as def) {\n <ng-container\n [ngTemplateOutlet]=\"def.template\"\n [ngTemplateOutletContext]=\"{ $implicit: selectedOptions() }\"\n />\n } @else if (selectedOptions().length > 0) {\n {{ triggerText() }}\n } @else {\n <span class=\"kt-select__placeholder\">{{ resolvedPlaceholder() }}</span>\n }\n </span>\n <span class=\"kt-select__arrow\" aria-hidden=\"true\">arrow_drop_down</span>\n </button>\n\n <!-- Tout effacer depuis le champ : sibling du trigger (pas de bouton imbriqu\u00E9 dans un bouton). -->\n @if (showClear()) {\n <button\n type=\"button\"\n class=\"kt-select__clear\"\n [attr.aria-label]=\"clearLabel()\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"clearSelection()\"\n >\n <span class=\"kt-select__clear-icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n <!-- Popup Popover (top-layer). M\u00EAme logique mobile bottom-sheet adaptative que le select classique. -->\n <ng-template ngComboboxPopup [combobox]=\"combobox\" [popupType]=\"dialogMode() ? 'dialog' : 'listbox'\">\n <div #popup popover=\"manual\" class=\"kt-select__popup\" [class.kt-select__popup--sheet]=\"compact()\">\n @if (compact()) {\n <div class=\"kt-select__sheet-scrim\" aria-hidden=\"true\" (click)=\"expanded.set(false)\"></div>\n <div class=\"kt-select__sheet-spacer\" aria-hidden=\"true\"></div>\n }\n <div class=\"kt-select__sheet-card\">\n @if (compact()) {\n <!-- Poign\u00E9e D\u00C9CORATIVE (ADR-0005) : la sheet s'attrape partout, le geste est natif. -->\n <div class=\"kt-select__sheet-grab\" aria-hidden=\"true\" (mousedown)=\"$event.preventDefault()\"></div>\n <!-- mousedown pr\u00E9ventif : un tap sur la carcasse ne doit pas voler le focus du widget\n (closePopupOnBlur fermerait le combobox) ; le click du bouton Fermer survit. -->\n <header class=\"kt-select__sheet-header\" (mousedown)=\"$event.preventDefault()\">\n <span class=\"kt-select__sheet-title\">{{ label() }}</span>\n <button\n type=\"button\"\n class=\"kt-select__sheet-close\"\n [attr.aria-label]=\"resolvedCloseLabel()\"\n (click)=\"expanded.set(false)\"\n >\n <span class=\"kt-select__sheet-close-icon\" aria-hidden=\"true\">close</span>\n </button>\n </header>\n }\n @if (dialogMode()) {\n <!-- Mode panneau (filtre et/ou actions de masse) : Widget Dialog -->\n <div\n ngComboboxWidget\n role=\"dialog\"\n class=\"kt-select__panel\"\n [id]=\"panelId\"\n [attr.aria-label]=\"label()\"\n [activeDescendant]=\"lb.activeDescendant()\"\n (keydown)=\"onPanelKeydown($event)\"\n >\n @if (selectionActions()) {\n <div class=\"kt-select__actions\">\n <button type=\"button\" class=\"kt-select__action\" (click)=\"selectAllFiltered()\">\n {{ resolvedSelectAllLabel() }}\n </button>\n <button type=\"button\" class=\"kt-select__action\" (click)=\"clearAllFiltered()\">\n {{ resolvedClearAllLabel() }}\n </button>\n </div>\n }\n @if (filterable()) {\n <div class=\"kt-select__filter\">\n <input\n #filterInput\n type=\"search\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n aria-expanded=\"true\"\n class=\"kt-select__filter-input\"\n autocomplete=\"off\"\n [placeholder]=\"resolvedFilterPlaceholder()\"\n [attr.aria-label]=\"resolvedFilterLabel()\"\n [attr.aria-controls]=\"lb.id()\"\n [attr.aria-activedescendant]=\"lb.activeDescendant()\"\n [value]=\"filterText()\"\n (input)=\"onFilterInput($event)\"\n (keydown)=\"onFilterKeydown($event)\"\n />\n </div>\n }\n @if (selectedOptions().length > 0) {\n <!-- Rappel visuel (s\u00E9lections potentiellement masqu\u00E9es par le filtre) ;\n l'info SR passe par la live region ci-dessous \u2192 aria-hidden. -->\n <div class=\"kt-select__count\" aria-hidden=\"true\">{{ selectionCountLabel() }}</div>\n }\n <div class=\"kt-select__sr-only kt-select__filter-status\" role=\"status\" aria-live=\"polite\">\n {{ announcedCount() }}\n </div>\n <ul\n #lb=\"ngListbox\"\n #listboxEl\n ngListbox\n [multi]=\"true\"\n [focusMode]=\"compact() && !filterable() ? 'roving' : 'activedescendant'\"\n selectionMode=\"explicit\"\n class=\"kt-select__listbox\"\n [attr.aria-label]=\"label()\"\n [value]=\"listboxValue()\"\n (valueChange)=\"onListboxValueChange($event)\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n >\n @for (item of displayedOptions(); track keyOf(item)) {\n <li\n #opt=\"ngOption\"\n ngOption\n class=\"kt-select__option kt-select__option--multiple\"\n [value]=\"keyOf(item)\"\n [label]=\"labelOf(item)\"\n [disabled]=\"disabledOf(item)\"\n [class.kt-select__option--active]=\"opt.active()\"\n >\n <span class=\"kt-select__checkbox\" aria-hidden=\"true\">\n @if (opt.selected()) {\n <span class=\"kt-select__checkbox-icon\">check_box</span>\n } @else {\n <span class=\"kt-select__checkbox-icon\">check_box_outline_blank</span>\n }\n </span>\n <span class=\"kt-select__option-content\">\n @if (optionDef(); as def) {\n <ng-container\n [ngTemplateOutlet]=\"def.template\"\n [ngTemplateOutletContext]=\"{\n $implicit: item,\n selected: !!opt.selected(),\n active: opt.active(),\n }\"\n />\n } @else {\n {{ labelOf(item) }}\n }\n </span>\n </li>\n } @empty {\n <li class=\"kt-select__empty\" role=\"option\" aria-disabled=\"true\" aria-selected=\"false\">\n {{ resolvedEmptyText() }}\n </li>\n }\n @if (filterable() && filteredOptions().length > maxVisibleOptions()) {\n <li class=\"kt-select__truncated-info\" role=\"option\" aria-disabled=\"true\" aria-selected=\"false\">\n {{ resolvedTruncatedResultsText()(maxVisibleOptions(), filteredOptions().length) }}\n </li>\n }\n </ul>\n </div>\n } @else {\n <!-- Mode simple : Widget Listbox direct -->\n <ul\n #listbox=\"ngListbox\"\n #listboxEl\n ngComboboxWidget\n ngListbox\n [multi]=\"true\"\n [focusMode]=\"compact() ? 'roving' : 'activedescendant'\"\n selectionMode=\"explicit\"\n class=\"kt-select__listbox\"\n [attr.aria-label]=\"label()\"\n [value]=\"listboxValue()\"\n (valueChange)=\"onListboxValueChange($event)\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n [activeDescendant]=\"listbox.activeDescendant()\"\n >\n @for (item of options(); track keyOf(item)) {\n <li\n #opt=\"ngOption\"\n ngOption\n class=\"kt-select__option kt-select__option--multiple\"\n [value]=\"keyOf(item)\"\n [label]=\"labelOf(item)\"\n [disabled]=\"disabledOf(item)\"\n [class.kt-select__option--active]=\"opt.active()\"\n >\n <span class=\"kt-select__checkbox\" aria-hidden=\"true\">\n @if (opt.selected()) {\n <span class=\"kt-select__checkbox-icon\">check_box</span>\n } @else {\n <span class=\"kt-select__checkbox-icon\">check_box_outline_blank</span>\n }\n </span>\n <span class=\"kt-select__option-content\">\n @if (optionDef(); as def) {\n <ng-container\n [ngTemplateOutlet]=\"def.template\"\n [ngTemplateOutletContext]=\"{\n $implicit: item,\n selected: !!opt.selected(),\n active: opt.active(),\n }\"\n />\n } @else {\n {{ labelOf(item) }}\n }\n </span>\n </li>\n } @empty {\n <li class=\"kt-select__empty\" role=\"option\" aria-disabled=\"true\" aria-selected=\"false\">\n {{ resolvedEmptyText() }}\n </li>\n }\n </ul>\n }\n </div>\n </div>\n </ng-template>\n </div>\n\n <!-- Chips r\u00E9vocables (Option 1) sous le trigger : d\u00E9l\u00E9gu\u00E9s au composant r\u00E9utilisable\n kt-chip-list (focus management, repli +N, live region). Les textes r\u00E9solus depuis\n KT_SELECT_CONFIG sont pass\u00E9s en inputs (ils priment sur un \u00E9ventuel KT_CHIPS_CONFIG). -->\n <kt-chip-list\n [items]=\"selectedOptions()\"\n [itemLabel]=\"chipLabelOf\"\n [itemKey]=\"chipKeyOf\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n [maxVisible]=\"maxVisibleChips()\"\n [listLabel]=\"resolvedSelectedItemsLabel()\"\n [removeItemLabel]=\"resolvedRemoveItemLabel()\"\n [itemRemovedText]=\"resolvedItemRemovedText()\"\n [moreLabel]=\"resolvedMoreChipsLabel()\"\n [lessLabel]=\"resolvedLessChipsLabel()\"\n [chipTemplate]=\"chipDef()?.template ?? null\"\n [emptyFocusTarget]=\"triggerEl()?.nativeElement\"\n (removed)=\"removeOption($event.item)\"\n />\n</kt-field>\n", styles: ["@layer kt-aaa.components{:host{display:block}.kt-select{position:relative}.kt-select__trigger{display:flex;align-items:center;justify-content:space-between;gap:var(--field-control-gap, .5rem);inline-size:100%;cursor:pointer;text-align:start;font:inherit;color:var(--field-color, inherit)}.kt-select__trigger:disabled{cursor:not-allowed;background:var(--field-disabled-bg, #f1f3f4);color:color-mix(in srgb,currentColor 50%,transparent)}.kt-select__value{flex:1;min-inline-size:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kt-select__placeholder{color:var(--field-hint-color, #5f6368)}.kt-select__arrow{flex:none;font-family:Material Symbols Outlined;font-size:1.25em;line-height:1;font-feature-settings:\"liga\";color:var(--field-icon-color, #5f6368);transition:var(--select-arrow-transition, transform .12s ease);-webkit-font-smoothing:antialiased}.kt-select--open .kt-select__arrow{transform:rotate(180deg)}.kt-select__trigger--clearable .kt-select__value{margin-inline-end:2rem}.kt-select__clear{position:absolute;inset-block-start:50%;inset-inline-end:2.5rem;translate:0 -50%;display:inline-flex;align-items:center;justify-content:center;inline-size:24px;block-size:24px;padding:0;border:0;border-radius:50%;background:transparent;color:var(--field-icon-color, #5f6368);cursor:pointer}.kt-select__clear:after{content:\"\";position:absolute;inset:-10px}.kt-select__clear:hover{background-color:color-mix(in srgb,currentColor 12%,transparent);color:var(--field-color, inherit)}.kt-select__clear:focus-visible{outline:2px solid var(--field-border-color-focus, #0b57d0);outline-offset:1px}.kt-select__clear-icon{font-family:Material Symbols Outlined;font-feature-settings:\"liga\";font-size:1.25rem;line-height:1;-webkit-font-smoothing:antialiased}.kt-select__popup{box-sizing:border-box;display:flex;flex-direction:column;margin:0;padding:0;border-width:var(--select-popup-border-width, var(--field-border-width, 1px));border-style:var(--field-border-style, solid);border-color:var(--field-border-color, #c4c7c5);border-radius:var(--field-radius, 8px);background:var(--select-popup-bg, var(--kt-surface-container, var(--kt-surface, #fff)));color:var(--field-color, inherit);box-shadow:var(--select-popup-shadow, 0 4px 12px rgb(0 0 0 / 12%));-webkit-backdrop-filter:var(--select-popup-backdrop-filter, none);backdrop-filter:var(--select-popup-backdrop-filter, none);max-block-size:var(--select-popup-max-height, 16rem);overflow:hidden}.kt-select__sheet-card{display:contents}.kt-select__popup:not(:popover-open){display:none!important}.kt-select__popup:popover-open{animation:var(--select-popup-enter-animation, none)}@media(prefers-reduced-motion:reduce){.kt-select__popup:popover-open{animation:none}}.kt-select__listbox{flex:1 1 auto;min-block-size:0;margin:0;padding:.25rem;list-style:none;overflow-y:auto}.kt-select__panel{display:flex;flex-direction:column;flex:1 1 auto;min-block-size:0}.kt-select__filter{flex:none;padding:.5rem;border-block-end:1px solid var(--field-border-color, #c4c7c5)}.kt-select__filter-input{box-sizing:border-box;inline-size:100%;min-block-size:var(--field-min-height, 44px);padding:.375rem .625rem;border:var(--field-border-width, 1px) var(--field-border-style, solid) var(--field-border-color, #c4c7c5);border-radius:calc(var(--field-radius, 8px) * .75);background:var(--select-popup-bg, var(--kt-surface-container, var(--kt-surface, #fff)));color:var(--field-color, inherit);font:inherit;appearance:none}.kt-select__filter-input::placeholder{color:var(--field-hint-color, #5f6368)}.kt-select__filter-input:focus-visible{outline:2px solid var(--field-border-color-focus, #0b57d0);outline-offset:-1px}.kt-select__filter-input::-webkit-search-cancel-button{appearance:none;inline-size:1rem;block-size:1rem;margin-inline-start:.375rem;cursor:pointer;background-color:var(--field-icon-color, #5f6368);-webkit-mask:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z'/%3E%3C/svg%3E\") center / contain no-repeat;mask:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z'/%3E%3C/svg%3E\") center / contain no-repeat}.kt-select__sr-only{position:absolute;inset-block-start:0;inset-inline-start:0;inline-size:1px;block-size:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}@supports (anchor-name: --x){.kt-select__popup{position:fixed;inset:auto;top:anchor(bottom);left:anchor(left);margin-block-start:.25rem;min-inline-size:anchor-size(width);width:max-content;max-inline-size:min(90vw,28rem);position-try-fallbacks:flip-block,flip-inline,flip-block flip-inline}}@supports not (anchor-name: --x){.kt-select__popup{position:fixed;inset:auto 0 0;inline-size:100%;max-inline-size:100%;border-radius:var(--kt-sheet-radius, 16px) var(--kt-sheet-radius, 16px) 0 0}}.kt-select__popup--sheet{position:fixed!important;inset:0!important;inline-size:100%!important;max-inline-size:100%!important;min-inline-size:0!important;width:100%!important;height:100%!important;max-block-size:none!important;margin:0!important;padding:0!important;border:none!important;background:transparent!important;box-shadow:none!important;border-radius:0!important;display:block;overflow-y:auto!important;scroll-snap-type:y mandatory;overscroll-behavior:contain;scrollbar-width:none}.kt-select__popup--sheet .kt-select__sheet-spacer{block-size:100%;scroll-snap-align:start;scroll-snap-stop:always}.kt-select__popup--sheet .kt-select__sheet-card{position:relative;z-index:2;display:flex;flex-direction:column;background:var(--select-popup-bg, var(--kt-surface-container, var(--kt-surface, #fff)));border-radius:var(--kt-sheet-radius, 16px) var(--kt-sheet-radius, 16px) 0 0;box-shadow:var(--kt-sheet-shadow, 0 -4px 16px rgb(0 0 0 / 12%));max-block-size:var(--kt-sheet-max-block-size, 85svh);width:100%;overflow:hidden;scroll-snap-align:end;scroll-snap-stop:always}.kt-select__popup--sheet .kt-select__sheet-card:has(.kt-select__filter){block-size:var(--kt-sheet-max-block-size, 85svh);max-block-size:var(--kt-sheet-max-block-size, 85svh)}::ng-deep .kt-select__popup--sheet::backdrop{display:none!important}.kt-select__sheet-scrim{display:none}.kt-select__popup--sheet .kt-select__sheet-scrim{display:block;position:fixed;inset:0;z-index:1;background:var(--kt-sheet-scrim, rgb(0 0 0 / 40%));opacity:0;pointer-events:auto;transition:opacity var(--kt-sheet-anim-duration, .12s) ease,overlay var(--kt-sheet-anim-duration, .12s) allow-discrete,display var(--kt-sheet-anim-duration, .12s) allow-discrete}.kt-select__popup--sheet:popover-open .kt-select__sheet-scrim{opacity:1}@starting-style{.kt-select__popup--sheet:popover-open .kt-select__sheet-scrim{opacity:0}}.kt-select__popup--sheet.kt-select__popup--closing .kt-select__sheet-scrim,.kt-select__popup--sheet:popover-open.kt-select__popup--closing .kt-select__sheet-scrim{opacity:0;transition:opacity var(--kt-sheet-exit-duration, 90ms) ease}.kt-select__popup--sheet .kt-select__option{--select-option-min-height: 44px;padding-block:.625rem}.kt-select__popup--sheet .kt-select__filter-input{font-size:1rem;min-block-size:44px}@media(prefers-reduced-motion:reduce){.kt-select__popup--sheet .kt-select__sheet-scrim{transition:none}}.kt-select__sheet-grab{display:flex;align-items:center;justify-content:center;flex:none;block-size:28px}.kt-select__sheet-grab:before{content:\"\";inline-size:2.25rem;block-size:.25rem;border-radius:999px;background:var(--kt-sheet-grab-color, var(--kt-outline, #c4c7c5))}.kt-select__sheet-header{display:flex;align-items:center;justify-content:space-between;gap:.5rem;flex:none;padding-block:.5rem;padding-inline:1rem .5rem;border-block-end:1px solid var(--field-border-color, #c4c7c5)}.kt-select__sheet-title{font-weight:600}.kt-select__sheet-close{display:inline-flex;align-items:center;justify-content:center;flex:none;inline-size:44px;block-size:44px;padding:0;border:0;border-radius:50%;background:transparent;color:var(--field-icon-color, #5f6368);cursor:pointer}.kt-select__sheet-close:focus-visible{outline:2px solid var(--field-border-color-focus, #0b57d0);outline-offset:2px}.kt-select__sheet-close-icon{font-family:Material Symbols Outlined;font-feature-settings:\"liga\";font-size:1.5rem;line-height:1;-webkit-font-smoothing:antialiased}.kt-select__option{display:flex;align-items:center;gap:.5rem;box-sizing:border-box;min-block-size:var( --select-option-min-height, 44px );padding:.5rem .625rem;border-radius:6px;cursor:pointer}.kt-select__option[aria-selected=true]{background:var(--select-option-selected-bg, color-mix(in srgb, var(--kt-primary, #0b57d0) 14%, transparent));color:var(--select-option-selected-color, inherit);font-weight:var(--select-option-selected-weight, 600)}.kt-select__option--active:not([aria-disabled=true]),.kt-select__option:hover:not([aria-disabled=true]){background:var(--select-option-hover-bg, color-mix(in srgb, currentColor 8%, transparent))}.kt-select__option[aria-disabled=true]{opacity:.5;cursor:not-allowed}.kt-select__empty{padding:.5rem .625rem;color:var(--field-hint-color, #5f6368)}.kt-select__truncated-info{box-sizing:border-box;padding:.5rem .625rem;font-size:.875rem;font-style:italic;color:var(--field-hint-color, #5f6368);border-block-start:1px solid var(--field-border-color, #c4c7c5);pointer-events:none}}\n", "@layer kt-aaa.components{.kt-select__actions{display:flex;gap:.25rem;flex:none;padding:.25rem .5rem;border-block-end:1px solid var(--field-border-color, #c4c7c5)}.kt-select__action{flex:1;min-block-size:44px;padding:.375rem .625rem;border:0;border-radius:calc(var(--field-radius, 8px) * .75);background:transparent;color:var(--kt-primary, #0b57d0);font:inherit;font-weight:500;cursor:pointer}.kt-select__action:hover{background:var(--select-option-hover-bg, color-mix(in srgb, currentColor 8%, transparent))}.kt-select__action:focus-visible{outline:2px solid var(--field-border-color-focus, #0b57d0);outline-offset:-2px}.kt-select__count{flex:none;padding:.25rem .75rem;font-size:.8125rem;color:var(--field-hint-color, #5f6368);border-block-end:1px solid var(--field-border-color, #c4c7c5)}.kt-select__checkbox{display:inline-flex;align-items:center;justify-content:center;flex:none;margin-inline-end:.25rem;-webkit-user-select:none;user-select:none}.kt-select__checkbox-icon{font-family:Material Symbols Outlined;font-feature-settings:\"liga\";font-size:1.25rem;line-height:1;color:var(--field-icon-color, #5f6368);-webkit-font-smoothing:antialiased}.kt-select__option[aria-selected=true] .kt-select__checkbox-icon{color:var(--kt-primary, #0b57d0)}.kt-select__option--multiple{display:flex;align-items:center;gap:.5rem}.kt-select__option-content{flex:1;min-inline-size:0}kt-chip-list:not([data-empty]){margin-block-start:.5rem}}\n"], dependencies: [{ kind: "component", type: KtField, selector: "kt-field", inputs: ["label", "hint", "helpText", "helpLabel", "customDescribedBy", "errors", "invalid", "required", "fieldId", "hideHintWhenInvalid", "showAllErrors", "hideLabel", "hideErrors", "appearance", "floatLabel"], outputs: ["helpClick"] }, { kind: "directive", type: KtFieldControl, selector: "[ktFieldControl]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: Combobox, selector: "[ngCombobox]", inputs: ["disabled", "softDisabled", "alwaysExpanded", "tabindex", "expanded", "value", "inlineSuggestion"], outputs: ["expandedChange", "valueChange"], exportAs: ["ngCombobox"] }, { kind: "directive", type: ComboboxPopup, selector: "ng-template[ngComboboxPopup]", inputs: ["combobox", "popupType"], exportAs: ["ngComboboxPopup"] }, { kind: "directive", type: ComboboxWidget, selector: "[ngComboboxWidget]", inputs: ["activeDescendant"], exportAs: ["ngComboboxWidget"] }, { kind: "directive", type: Listbox, selector: "[ngListbox]", inputs: ["id", "orientation", "multi", "wrap", "softDisabled", "focusMode", "selectionMode", "typeaheadDelay", "disabled", "readonly", "tabindex", "value"], outputs: ["valueChange"], exportAs: ["ngListbox"] }, { kind: "directive", type: Option, selector: "[ngOption]", inputs: ["id", "value", "disabled", "label"], exportAs: ["ngOption"] }, { kind: "component", type: KtChipList, selector: "kt-chip-list", inputs: ["items", "itemLabel", "itemKey", "removable", "disabled", "readonly", "maxVisible", "listLabel", "removeItemLabel", "itemRemovedText", "moreLabel", "lessLabel", "chipTemplate", "emptyFocusTarget"], outputs: ["removed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3698
3813
  }
3699
3814
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtMultiSelect, decorators: [{
3700
3815
  type: Component,
@@ -3708,8 +3823,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
3708
3823
  Listbox,
3709
3824
  Option,
3710
3825
  KtChipList,
3711
- ], template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"fieldErrors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n [hideLabel]=\"hideLabel()\"\n [hideErrors]=\"hideErrors()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div class=\"kt-select\" [class.kt-select--open]=\"expanded()\">\n <button\n #combobox=\"ngCombobox\"\n #trigger\n ngCombobox\n ktFieldControl\n type=\"button\"\n class=\"kt-field-box kt-select__trigger\"\n [class.kt-select__trigger--clearable]=\"showClear()\"\n [(expanded)]=\"expanded\"\n [disabled]=\"disabled()\"\n [softDisabled]=\"false\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n [attr.data-filled]=\"selectedOptions().length ? '' : null\"\n [attr.data-pending]=\"pending() ? '' : null\"\n [attr.aria-busy]=\"pending() ? 'true' : null\"\n (keydown)=\"onTriggerKeydown($event)\"\n >\n <span class=\"kt-select__value\">\n @if (triggerDef(); as def) {\n <ng-container\n [ngTemplateOutlet]=\"def.template\"\n [ngTemplateOutletContext]=\"{ $implicit: selectedOptions() }\"\n />\n } @else if (selectedOptions().length > 0) {\n {{ triggerText() }}\n } @else {\n <span class=\"kt-select__placeholder\">{{ resolvedPlaceholder() }}</span>\n }\n </span>\n <span class=\"kt-select__arrow\" aria-hidden=\"true\">arrow_drop_down</span>\n </button>\n\n <!-- Tout effacer depuis le champ : sibling du trigger (pas de bouton imbriqu\u00E9 dans un bouton). -->\n @if (showClear()) {\n <button\n type=\"button\"\n class=\"kt-select__clear\"\n [attr.aria-label]=\"clearLabel()\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"clearSelection()\"\n >\n <span class=\"kt-select__clear-icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n <!-- Popup Popover (top-layer). M\u00EAme logique mobile bottom-sheet adaptative que le select classique. -->\n <ng-template ngComboboxPopup [combobox]=\"combobox\" [popupType]=\"dialogMode() ? 'dialog' : 'listbox'\">\n <div #popup popover=\"manual\" class=\"kt-select__popup\" [class.kt-select__popup--sheet]=\"compact()\">\n @if (compact()) {\n <div class=\"kt-select__sheet-scrim\" aria-hidden=\"true\" (click)=\"expanded.set(false)\"></div>\n }\n <div class=\"kt-select__sheet-card\">\n @if (compact()) {\n <div\n class=\"kt-select__sheet-grab\"\n aria-hidden=\"true\"\n (pointerdown)=\"onDragStart($event)\"\n (mousedown)=\"$event.preventDefault()\"\n ></div>\n <header class=\"kt-select__sheet-header\">\n <span class=\"kt-select__sheet-title\">{{ label() }}</span>\n <button\n type=\"button\"\n class=\"kt-select__sheet-close\"\n [attr.aria-label]=\"resolvedCloseLabel()\"\n (click)=\"expanded.set(false)\"\n >\n <span class=\"kt-select__sheet-close-icon\" aria-hidden=\"true\">close</span>\n </button>\n </header>\n }\n @if (dialogMode()) {\n <!-- Mode panneau (filtre et/ou actions de masse) : Widget Dialog -->\n <div\n ngComboboxWidget\n role=\"dialog\"\n class=\"kt-select__panel\"\n [id]=\"panelId\"\n [attr.aria-label]=\"label()\"\n [activeDescendant]=\"lb.activeDescendant()\"\n (keydown)=\"onPanelKeydown($event)\"\n >\n @if (selectionActions()) {\n <div class=\"kt-select__actions\">\n <button type=\"button\" class=\"kt-select__action\" (click)=\"selectAllFiltered()\">\n {{ resolvedSelectAllLabel() }}\n </button>\n <button type=\"button\" class=\"kt-select__action\" (click)=\"clearAllFiltered()\">\n {{ resolvedClearAllLabel() }}\n </button>\n </div>\n }\n @if (filterable()) {\n <div class=\"kt-select__filter\">\n <input\n #filterInput\n type=\"search\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n aria-expanded=\"true\"\n class=\"kt-select__filter-input\"\n autocomplete=\"off\"\n [placeholder]=\"resolvedFilterPlaceholder()\"\n [attr.aria-label]=\"resolvedFilterLabel()\"\n [attr.aria-controls]=\"lb.id()\"\n [attr.aria-activedescendant]=\"lb.activeDescendant()\"\n [value]=\"filterText()\"\n (input)=\"onFilterInput($event)\"\n (keydown)=\"onFilterKeydown($event)\"\n />\n </div>\n }\n @if (selectedOptions().length > 0) {\n <!-- Rappel visuel (s\u00E9lections potentiellement masqu\u00E9es par le filtre) ;\n l'info SR passe par la live region ci-dessous \u2192 aria-hidden. -->\n <div class=\"kt-select__count\" aria-hidden=\"true\">{{ selectionCountLabel() }}</div>\n }\n <div class=\"kt-select__sr-only kt-select__filter-status\" role=\"status\" aria-live=\"polite\">\n {{ announcedCount() }}\n </div>\n <ul\n #lb=\"ngListbox\"\n #listboxEl\n ngListbox\n [multi]=\"true\"\n [focusMode]=\"compact() && !filterable() ? 'roving' : 'activedescendant'\"\n selectionMode=\"explicit\"\n class=\"kt-select__listbox\"\n [attr.aria-label]=\"label()\"\n [value]=\"listboxValue()\"\n (valueChange)=\"onListboxValueChange($event)\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n >\n @for (item of displayedOptions(); track keyOf(item)) {\n <li\n #opt=\"ngOption\"\n ngOption\n class=\"kt-select__option kt-select__option--multiple\"\n [value]=\"keyOf(item)\"\n [label]=\"labelOf(item)\"\n [disabled]=\"disabledOf(item)\"\n [class.kt-select__option--active]=\"opt.active()\"\n >\n <span class=\"kt-select__checkbox\" aria-hidden=\"true\">\n @if (opt.selected()) {\n <span class=\"kt-select__checkbox-icon\">check_box</span>\n } @else {\n <span class=\"kt-select__checkbox-icon\">check_box_outline_blank</span>\n }\n </span>\n <span class=\"kt-select__option-content\">\n @if (optionDef(); as def) {\n <ng-container\n [ngTemplateOutlet]=\"def.template\"\n [ngTemplateOutletContext]=\"{\n $implicit: item,\n selected: !!opt.selected(),\n active: opt.active(),\n }\"\n />\n } @else {\n {{ labelOf(item) }}\n }\n </span>\n </li>\n } @empty {\n <li class=\"kt-select__empty\" role=\"option\" aria-disabled=\"true\" aria-selected=\"false\">\n {{ resolvedEmptyText() }}\n </li>\n }\n @if (filterable() && filteredOptions().length > maxVisibleOptions()) {\n <li class=\"kt-select__truncated-info\" role=\"option\" aria-disabled=\"true\" aria-selected=\"false\">\n {{ resolvedTruncatedResultsText()(maxVisibleOptions(), filteredOptions().length) }}\n </li>\n }\n </ul>\n </div>\n } @else {\n <!-- Mode simple : Widget Listbox direct -->\n <ul\n #listbox=\"ngListbox\"\n #listboxEl\n ngComboboxWidget\n ngListbox\n [multi]=\"true\"\n [focusMode]=\"compact() ? 'roving' : 'activedescendant'\"\n selectionMode=\"explicit\"\n class=\"kt-select__listbox\"\n [attr.aria-label]=\"label()\"\n [value]=\"listboxValue()\"\n (valueChange)=\"onListboxValueChange($event)\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n [activeDescendant]=\"listbox.activeDescendant()\"\n >\n @for (item of options(); track keyOf(item)) {\n <li\n #opt=\"ngOption\"\n ngOption\n class=\"kt-select__option kt-select__option--multiple\"\n [value]=\"keyOf(item)\"\n [label]=\"labelOf(item)\"\n [disabled]=\"disabledOf(item)\"\n [class.kt-select__option--active]=\"opt.active()\"\n >\n <span class=\"kt-select__checkbox\" aria-hidden=\"true\">\n @if (opt.selected()) {\n <span class=\"kt-select__checkbox-icon\">check_box</span>\n } @else {\n <span class=\"kt-select__checkbox-icon\">check_box_outline_blank</span>\n }\n </span>\n <span class=\"kt-select__option-content\">\n @if (optionDef(); as def) {\n <ng-container\n [ngTemplateOutlet]=\"def.template\"\n [ngTemplateOutletContext]=\"{\n $implicit: item,\n selected: !!opt.selected(),\n active: opt.active(),\n }\"\n />\n } @else {\n {{ labelOf(item) }}\n }\n </span>\n </li>\n } @empty {\n <li class=\"kt-select__empty\" role=\"option\" aria-disabled=\"true\" aria-selected=\"false\">\n {{ resolvedEmptyText() }}\n </li>\n }\n </ul>\n }\n </div>\n </div>\n </ng-template>\n </div>\n\n <!-- Chips r\u00E9vocables (Option 1) sous le trigger : d\u00E9l\u00E9gu\u00E9s au composant r\u00E9utilisable\n kt-chip-list (focus management, repli +N, live region). Les textes r\u00E9solus depuis\n KT_SELECT_CONFIG sont pass\u00E9s en inputs (ils priment sur un \u00E9ventuel KT_CHIPS_CONFIG). -->\n <kt-chip-list\n [items]=\"selectedOptions()\"\n [itemLabel]=\"chipLabelOf\"\n [itemKey]=\"chipKeyOf\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n [maxVisible]=\"maxVisibleChips()\"\n [listLabel]=\"resolvedSelectedItemsLabel()\"\n [removeItemLabel]=\"resolvedRemoveItemLabel()\"\n [itemRemovedText]=\"resolvedItemRemovedText()\"\n [moreLabel]=\"resolvedMoreChipsLabel()\"\n [lessLabel]=\"resolvedLessChipsLabel()\"\n [chipTemplate]=\"chipDef()?.template ?? null\"\n [emptyFocusTarget]=\"triggerEl()?.nativeElement\"\n (removed)=\"removeOption($event.item)\"\n />\n</kt-field>\n", styles: ["@layer kt-aaa.components{:host{display:block}.kt-select{position:relative}.kt-select__trigger{display:flex;align-items:center;justify-content:space-between;gap:var(--field-control-gap, .5rem);inline-size:100%;cursor:pointer;text-align:start;font:inherit;color:var(--field-color, inherit)}.kt-select__trigger:disabled{cursor:not-allowed;background:var(--field-disabled-bg, #f1f3f4);color:color-mix(in srgb,currentColor 50%,transparent)}.kt-select__value{flex:1;min-inline-size:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kt-select__placeholder{color:var(--field-hint-color, #5f6368)}.kt-select__arrow{flex:none;font-family:Material Symbols Outlined;font-size:1.25em;line-height:1;font-feature-settings:\"liga\";color:var(--field-icon-color, #5f6368);transition:var(--select-arrow-transition, transform .12s ease);-webkit-font-smoothing:antialiased}.kt-select--open .kt-select__arrow{transform:rotate(180deg)}.kt-select__popup{box-sizing:border-box;display:flex;flex-direction:column;margin:0;padding:0;border-width:var(--select-popup-border-width, var(--field-border-width, 1px));border-style:var(--field-border-style, solid);border-color:var(--field-border-color, #c4c7c5);border-radius:var(--field-radius, 8px);background:var(--select-popup-bg, var(--kt-surface-container, var(--kt-surface, #fff)));color:var(--field-color, inherit);box-shadow:var(--select-popup-shadow, 0 4px 12px rgb(0 0 0 / 12%));-webkit-backdrop-filter:var(--select-popup-backdrop-filter, none);backdrop-filter:var(--select-popup-backdrop-filter, none);max-block-size:var(--select-popup-max-height, 16rem);overflow:hidden}.kt-select__sheet-card{display:contents}.kt-select__popup:not(:popover-open){display:none!important}.kt-select__popup:popover-open{animation:var(--select-popup-enter-animation, none)}@media(prefers-reduced-motion:reduce){.kt-select__popup:popover-open{animation:none}}.kt-select__listbox{flex:1 1 auto;min-block-size:0;margin:0;padding:.25rem;list-style:none;overflow-y:auto}.kt-select__panel{display:flex;flex-direction:column;flex:1 1 auto;min-block-size:0}.kt-select__filter{flex:none;padding:.5rem;border-block-end:1px solid var(--field-border-color, #c4c7c5)}.kt-select__filter-input{box-sizing:border-box;inline-size:100%;min-block-size:var(--field-min-height, 44px);padding:.375rem .625rem;border:var(--field-border-width, 1px) var(--field-border-style, solid) var(--field-border-color, #c4c7c5);border-radius:calc(var(--field-radius, 8px) * .75);background:var(--select-popup-bg, var(--kt-surface-container, var(--kt-surface, #fff)));color:var(--field-color, inherit);font:inherit;appearance:none}.kt-select__filter-input::placeholder{color:var(--field-hint-color, #5f6368)}.kt-select__filter-input:focus-visible{outline:2px solid var(--field-border-color-focus, #0b57d0);outline-offset:-1px}.kt-select__filter-input::-webkit-search-cancel-button{appearance:none;inline-size:1rem;block-size:1rem;margin-inline-start:.375rem;cursor:pointer;background-color:var(--field-icon-color, #5f6368);-webkit-mask:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z'/%3E%3C/svg%3E\") center / contain no-repeat;mask:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z'/%3E%3C/svg%3E\") center / contain no-repeat}.kt-select__sr-only{position:absolute;inset-block-start:0;inset-inline-start:0;inline-size:1px;block-size:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}@supports (anchor-name: --x){.kt-select__popup{position:fixed;inset:auto;top:anchor(bottom);left:anchor(left);margin-block-start:.25rem;min-inline-size:anchor-size(width);width:max-content;max-inline-size:min(90vw,28rem);position-try-fallbacks:flip-block,flip-inline,flip-block flip-inline}}@supports not (anchor-name: --x){.kt-select__popup{position:fixed;inset:auto 0 0;inline-size:100%;max-inline-size:100%;border-radius:var(--kt-sheet-radius, 16px) var(--kt-sheet-radius, 16px) 0 0}}.kt-select__popup--sheet{position:fixed!important;inset:0!important;inline-size:100%!important;max-inline-size:100%!important;min-inline-size:0!important;width:100%!important;height:100%!important;max-block-size:none!important;margin:0!important;padding:0!important;border:none!important;background:transparent!important;box-shadow:none!important;border-radius:0!important;overflow:visible!important;display:flex;flex-direction:column!important;justify-content:flex-end!important}.kt-select__popup--sheet .kt-select__sheet-card{position:relative;z-index:2;display:flex;flex-direction:column;background:var(--select-popup-bg, var(--kt-surface-container, var(--kt-surface, #fff)));border-radius:var(--kt-sheet-radius, 16px) var(--kt-sheet-radius, 16px) 0 0;box-shadow:var(--kt-sheet-shadow, 0 -4px 16px rgb(0 0 0 / 12%));max-block-size:var(--kt-sheet-max-block-size, 85svh);width:100%;overflow:hidden;translate:0 0;transition:translate var(--kt-sheet-anim-duration, .12s) ease}.kt-select__popup--sheet .kt-select__sheet-card:has(.kt-select__filter){block-size:var(--kt-sheet-max-block-size, 85svh);max-block-size:var(--kt-sheet-max-block-size, 85svh)}.kt-select__popup--sheet:popover-open .kt-select__sheet-card{translate:0 0;animation:var(--select-sheet-enter-animation, kt-sheet-in var(--kt-sheet-anim-duration, .12s) ease)}.kt-select__popup--sheet .kt-select__sheet-card.kt-select__popup--dragging{transition:none}.kt-select__popup--sheet.kt-select__popup--closing .kt-select__sheet-card,.kt-select__popup--sheet:popover-open.kt-select__popup--closing .kt-select__sheet-card{translate:0 100%;transition:translate var(--kt-sheet-exit-duration, 90ms) cubic-bezier(.4,0,.2,1)}::ng-deep .kt-select__popup--sheet::backdrop{display:none!important}.kt-select__sheet-scrim{display:none}.kt-select__popup--sheet .kt-select__sheet-scrim{display:block;position:fixed;inset:0;z-index:1;background:var(--kt-sheet-scrim, rgb(0 0 0 / 40%));opacity:0;pointer-events:auto;transition:opacity var(--kt-sheet-anim-duration, .12s) ease,overlay var(--kt-sheet-anim-duration, .12s) allow-discrete,display var(--kt-sheet-anim-duration, .12s) allow-discrete}.kt-select__popup--sheet:popover-open .kt-select__sheet-scrim{opacity:1}@starting-style{.kt-select__popup--sheet:popover-open .kt-select__sheet-scrim{opacity:0}}.kt-select__popup--sheet.kt-select__popup--closing .kt-select__sheet-scrim,.kt-select__popup--sheet:popover-open.kt-select__popup--closing .kt-select__sheet-scrim{opacity:0;transition:opacity var(--kt-sheet-exit-duration, 90ms) ease}.kt-select__popup--sheet .kt-select__option{--select-option-min-height: 44px;padding-block:.625rem}.kt-select__popup--sheet .kt-select__filter-input{font-size:1rem;min-block-size:44px}@media(prefers-reduced-motion:reduce){.kt-select__popup--sheet .kt-select__sheet-card,.kt-select__popup--sheet .kt-select__sheet-scrim{transition:none;translate:0 0}}.kt-select__sheet-grab{display:flex;align-items:center;justify-content:center;flex:none;block-size:44px;cursor:grab;touch-action:none}.kt-select__sheet-grab:active{cursor:grabbing}.kt-select__sheet-grab:before{content:\"\";inline-size:2.25rem;block-size:.25rem;border-radius:999px;background:var(--kt-sheet-grab-color, var(--kt-outline, #c4c7c5))}.kt-select__sheet-header{display:flex;align-items:center;justify-content:space-between;gap:.5rem;flex:none;padding-block:.5rem;padding-inline:1rem .5rem;border-block-end:1px solid var(--field-border-color, #c4c7c5)}.kt-select__sheet-title{font-weight:600}.kt-select__sheet-close{display:inline-flex;align-items:center;justify-content:center;flex:none;inline-size:44px;block-size:44px;padding:0;border:0;border-radius:50%;background:transparent;color:var(--field-icon-color, #5f6368);cursor:pointer}.kt-select__sheet-close:focus-visible{outline:2px solid var(--field-border-color-focus, #0b57d0);outline-offset:2px}.kt-select__sheet-close-icon{font-family:Material Symbols Outlined;font-feature-settings:\"liga\";font-size:1.5rem;line-height:1;-webkit-font-smoothing:antialiased}.kt-select__option{display:flex;align-items:center;gap:.5rem;box-sizing:border-box;min-block-size:var( --select-option-min-height, 44px );padding:.5rem .625rem;border-radius:6px;cursor:pointer}.kt-select__option[aria-selected=true]{background:var(--select-option-selected-bg, color-mix(in srgb, var(--kt-primary, #0b57d0) 14%, transparent));color:var(--select-option-selected-color, inherit);font-weight:var(--select-option-selected-weight, 600)}.kt-select__option--active:not([aria-disabled=true]),.kt-select__option:hover:not([aria-disabled=true]){background:var(--select-option-hover-bg, color-mix(in srgb, currentColor 8%, transparent))}.kt-select__option[aria-disabled=true]{opacity:.5;cursor:not-allowed}.kt-select__empty{padding:.5rem .625rem;color:var(--field-hint-color, #5f6368)}.kt-select__truncated-info{box-sizing:border-box;padding:.5rem .625rem;font-size:.875rem;font-style:italic;color:var(--field-hint-color, #5f6368);border-block-start:1px solid var(--field-border-color, #c4c7c5);pointer-events:none}}\n", "@layer kt-aaa.components{.kt-select__trigger--clearable .kt-select__value{margin-inline-end:2rem}.kt-select__clear{position:absolute;inset-block-start:50%;inset-inline-end:2.5rem;translate:0 -50%;display:inline-flex;align-items:center;justify-content:center;inline-size:24px;block-size:24px;padding:0;border:0;border-radius:50%;background:transparent;color:var(--field-icon-color, #5f6368);cursor:pointer}.kt-select__clear:after{content:\"\";position:absolute;inset:-10px}.kt-select__clear:hover{background-color:color-mix(in srgb,currentColor 12%,transparent);color:var(--field-color, inherit)}.kt-select__clear:focus-visible{outline:2px solid var(--field-border-color-focus, #0b57d0);outline-offset:1px}.kt-select__clear-icon{font-family:Material Symbols Outlined;font-feature-settings:\"liga\";font-size:1.25rem;line-height:1;-webkit-font-smoothing:antialiased}.kt-select__actions{display:flex;gap:.25rem;flex:none;padding:.25rem .5rem;border-block-end:1px solid var(--field-border-color, #c4c7c5)}.kt-select__action{flex:1;min-block-size:44px;padding:.375rem .625rem;border:0;border-radius:calc(var(--field-radius, 8px) * .75);background:transparent;color:var(--kt-primary, #0b57d0);font:inherit;font-weight:500;cursor:pointer}.kt-select__action:hover{background:var(--select-option-hover-bg, color-mix(in srgb, currentColor 8%, transparent))}.kt-select__action:focus-visible{outline:2px solid var(--field-border-color-focus, #0b57d0);outline-offset:-2px}.kt-select__count{flex:none;padding:.25rem .75rem;font-size:.8125rem;color:var(--field-hint-color, #5f6368);border-block-end:1px solid var(--field-border-color, #c4c7c5)}.kt-select__checkbox{display:inline-flex;align-items:center;justify-content:center;flex:none;margin-inline-end:.25rem;-webkit-user-select:none;user-select:none}.kt-select__checkbox-icon{font-family:Material Symbols Outlined;font-feature-settings:\"liga\";font-size:1.25rem;line-height:1;color:var(--field-icon-color, #5f6368);-webkit-font-smoothing:antialiased}.kt-select__option[aria-selected=true] .kt-select__checkbox-icon{color:var(--kt-primary, #0b57d0)}.kt-select__option--multiple{display:flex;align-items:center;gap:.5rem}.kt-select__option-content{flex:1;min-inline-size:0}kt-chip-list:not([data-empty]){margin-block-start:.5rem}}\n"] }]
3712
- }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], clearLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearLabel", required: false }] }], selectionActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionActions", required: false }] }], maxVisibleChips: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxVisibleChips", required: false }] }], optionDef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => KtMultiSelectOptionDef), { isSignal: true }] }], triggerDef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => KtMultiSelectTriggerDef), { isSignal: true }] }], chipDef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => KtMultiSelectChipDef), { isSignal: true }] }], chipList: [{ type: i0.ViewChild, args: [i0.forwardRef(() => KtChipList), { isSignal: true }] }] } });
3826
+ ], template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"fieldErrors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n [hideLabel]=\"hideLabel()\"\n [hideErrors]=\"hideErrors()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div class=\"kt-select\" [class.kt-select--open]=\"expanded()\">\n <button\n #combobox=\"ngCombobox\"\n #trigger\n ngCombobox\n ktFieldControl\n type=\"button\"\n class=\"kt-field-box kt-select__trigger\"\n [class.kt-select__trigger--clearable]=\"showClear()\"\n [(expanded)]=\"expanded\"\n [disabled]=\"disabled()\"\n [softDisabled]=\"false\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n [attr.data-filled]=\"selectedOptions().length ? '' : null\"\n [attr.data-pending]=\"pending() ? '' : null\"\n [attr.aria-busy]=\"pending() ? 'true' : null\"\n (keydown)=\"onTriggerKeydown($event)\"\n >\n <span class=\"kt-select__value\">\n @if (triggerDef(); as def) {\n <ng-container\n [ngTemplateOutlet]=\"def.template\"\n [ngTemplateOutletContext]=\"{ $implicit: selectedOptions() }\"\n />\n } @else if (selectedOptions().length > 0) {\n {{ triggerText() }}\n } @else {\n <span class=\"kt-select__placeholder\">{{ resolvedPlaceholder() }}</span>\n }\n </span>\n <span class=\"kt-select__arrow\" aria-hidden=\"true\">arrow_drop_down</span>\n </button>\n\n <!-- Tout effacer depuis le champ : sibling du trigger (pas de bouton imbriqu\u00E9 dans un bouton). -->\n @if (showClear()) {\n <button\n type=\"button\"\n class=\"kt-select__clear\"\n [attr.aria-label]=\"clearLabel()\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"clearSelection()\"\n >\n <span class=\"kt-select__clear-icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n <!-- Popup Popover (top-layer). M\u00EAme logique mobile bottom-sheet adaptative que le select classique. -->\n <ng-template ngComboboxPopup [combobox]=\"combobox\" [popupType]=\"dialogMode() ? 'dialog' : 'listbox'\">\n <div #popup popover=\"manual\" class=\"kt-select__popup\" [class.kt-select__popup--sheet]=\"compact()\">\n @if (compact()) {\n <div class=\"kt-select__sheet-scrim\" aria-hidden=\"true\" (click)=\"expanded.set(false)\"></div>\n <div class=\"kt-select__sheet-spacer\" aria-hidden=\"true\"></div>\n }\n <div class=\"kt-select__sheet-card\">\n @if (compact()) {\n <!-- Poign\u00E9e D\u00C9CORATIVE (ADR-0005) : la sheet s'attrape partout, le geste est natif. -->\n <div class=\"kt-select__sheet-grab\" aria-hidden=\"true\" (mousedown)=\"$event.preventDefault()\"></div>\n <!-- mousedown pr\u00E9ventif : un tap sur la carcasse ne doit pas voler le focus du widget\n (closePopupOnBlur fermerait le combobox) ; le click du bouton Fermer survit. -->\n <header class=\"kt-select__sheet-header\" (mousedown)=\"$event.preventDefault()\">\n <span class=\"kt-select__sheet-title\">{{ label() }}</span>\n <button\n type=\"button\"\n class=\"kt-select__sheet-close\"\n [attr.aria-label]=\"resolvedCloseLabel()\"\n (click)=\"expanded.set(false)\"\n >\n <span class=\"kt-select__sheet-close-icon\" aria-hidden=\"true\">close</span>\n </button>\n </header>\n }\n @if (dialogMode()) {\n <!-- Mode panneau (filtre et/ou actions de masse) : Widget Dialog -->\n <div\n ngComboboxWidget\n role=\"dialog\"\n class=\"kt-select__panel\"\n [id]=\"panelId\"\n [attr.aria-label]=\"label()\"\n [activeDescendant]=\"lb.activeDescendant()\"\n (keydown)=\"onPanelKeydown($event)\"\n >\n @if (selectionActions()) {\n <div class=\"kt-select__actions\">\n <button type=\"button\" class=\"kt-select__action\" (click)=\"selectAllFiltered()\">\n {{ resolvedSelectAllLabel() }}\n </button>\n <button type=\"button\" class=\"kt-select__action\" (click)=\"clearAllFiltered()\">\n {{ resolvedClearAllLabel() }}\n </button>\n </div>\n }\n @if (filterable()) {\n <div class=\"kt-select__filter\">\n <input\n #filterInput\n type=\"search\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n aria-expanded=\"true\"\n class=\"kt-select__filter-input\"\n autocomplete=\"off\"\n [placeholder]=\"resolvedFilterPlaceholder()\"\n [attr.aria-label]=\"resolvedFilterLabel()\"\n [attr.aria-controls]=\"lb.id()\"\n [attr.aria-activedescendant]=\"lb.activeDescendant()\"\n [value]=\"filterText()\"\n (input)=\"onFilterInput($event)\"\n (keydown)=\"onFilterKeydown($event)\"\n />\n </div>\n }\n @if (selectedOptions().length > 0) {\n <!-- Rappel visuel (s\u00E9lections potentiellement masqu\u00E9es par le filtre) ;\n l'info SR passe par la live region ci-dessous \u2192 aria-hidden. -->\n <div class=\"kt-select__count\" aria-hidden=\"true\">{{ selectionCountLabel() }}</div>\n }\n <div class=\"kt-select__sr-only kt-select__filter-status\" role=\"status\" aria-live=\"polite\">\n {{ announcedCount() }}\n </div>\n <ul\n #lb=\"ngListbox\"\n #listboxEl\n ngListbox\n [multi]=\"true\"\n [focusMode]=\"compact() && !filterable() ? 'roving' : 'activedescendant'\"\n selectionMode=\"explicit\"\n class=\"kt-select__listbox\"\n [attr.aria-label]=\"label()\"\n [value]=\"listboxValue()\"\n (valueChange)=\"onListboxValueChange($event)\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n >\n @for (item of displayedOptions(); track keyOf(item)) {\n <li\n #opt=\"ngOption\"\n ngOption\n class=\"kt-select__option kt-select__option--multiple\"\n [value]=\"keyOf(item)\"\n [label]=\"labelOf(item)\"\n [disabled]=\"disabledOf(item)\"\n [class.kt-select__option--active]=\"opt.active()\"\n >\n <span class=\"kt-select__checkbox\" aria-hidden=\"true\">\n @if (opt.selected()) {\n <span class=\"kt-select__checkbox-icon\">check_box</span>\n } @else {\n <span class=\"kt-select__checkbox-icon\">check_box_outline_blank</span>\n }\n </span>\n <span class=\"kt-select__option-content\">\n @if (optionDef(); as def) {\n <ng-container\n [ngTemplateOutlet]=\"def.template\"\n [ngTemplateOutletContext]=\"{\n $implicit: item,\n selected: !!opt.selected(),\n active: opt.active(),\n }\"\n />\n } @else {\n {{ labelOf(item) }}\n }\n </span>\n </li>\n } @empty {\n <li class=\"kt-select__empty\" role=\"option\" aria-disabled=\"true\" aria-selected=\"false\">\n {{ resolvedEmptyText() }}\n </li>\n }\n @if (filterable() && filteredOptions().length > maxVisibleOptions()) {\n <li class=\"kt-select__truncated-info\" role=\"option\" aria-disabled=\"true\" aria-selected=\"false\">\n {{ resolvedTruncatedResultsText()(maxVisibleOptions(), filteredOptions().length) }}\n </li>\n }\n </ul>\n </div>\n } @else {\n <!-- Mode simple : Widget Listbox direct -->\n <ul\n #listbox=\"ngListbox\"\n #listboxEl\n ngComboboxWidget\n ngListbox\n [multi]=\"true\"\n [focusMode]=\"compact() ? 'roving' : 'activedescendant'\"\n selectionMode=\"explicit\"\n class=\"kt-select__listbox\"\n [attr.aria-label]=\"label()\"\n [value]=\"listboxValue()\"\n (valueChange)=\"onListboxValueChange($event)\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n [activeDescendant]=\"listbox.activeDescendant()\"\n >\n @for (item of options(); track keyOf(item)) {\n <li\n #opt=\"ngOption\"\n ngOption\n class=\"kt-select__option kt-select__option--multiple\"\n [value]=\"keyOf(item)\"\n [label]=\"labelOf(item)\"\n [disabled]=\"disabledOf(item)\"\n [class.kt-select__option--active]=\"opt.active()\"\n >\n <span class=\"kt-select__checkbox\" aria-hidden=\"true\">\n @if (opt.selected()) {\n <span class=\"kt-select__checkbox-icon\">check_box</span>\n } @else {\n <span class=\"kt-select__checkbox-icon\">check_box_outline_blank</span>\n }\n </span>\n <span class=\"kt-select__option-content\">\n @if (optionDef(); as def) {\n <ng-container\n [ngTemplateOutlet]=\"def.template\"\n [ngTemplateOutletContext]=\"{\n $implicit: item,\n selected: !!opt.selected(),\n active: opt.active(),\n }\"\n />\n } @else {\n {{ labelOf(item) }}\n }\n </span>\n </li>\n } @empty {\n <li class=\"kt-select__empty\" role=\"option\" aria-disabled=\"true\" aria-selected=\"false\">\n {{ resolvedEmptyText() }}\n </li>\n }\n </ul>\n }\n </div>\n </div>\n </ng-template>\n </div>\n\n <!-- Chips r\u00E9vocables (Option 1) sous le trigger : d\u00E9l\u00E9gu\u00E9s au composant r\u00E9utilisable\n kt-chip-list (focus management, repli +N, live region). Les textes r\u00E9solus depuis\n KT_SELECT_CONFIG sont pass\u00E9s en inputs (ils priment sur un \u00E9ventuel KT_CHIPS_CONFIG). -->\n <kt-chip-list\n [items]=\"selectedOptions()\"\n [itemLabel]=\"chipLabelOf\"\n [itemKey]=\"chipKeyOf\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n [maxVisible]=\"maxVisibleChips()\"\n [listLabel]=\"resolvedSelectedItemsLabel()\"\n [removeItemLabel]=\"resolvedRemoveItemLabel()\"\n [itemRemovedText]=\"resolvedItemRemovedText()\"\n [moreLabel]=\"resolvedMoreChipsLabel()\"\n [lessLabel]=\"resolvedLessChipsLabel()\"\n [chipTemplate]=\"chipDef()?.template ?? null\"\n [emptyFocusTarget]=\"triggerEl()?.nativeElement\"\n (removed)=\"removeOption($event.item)\"\n />\n</kt-field>\n", styles: ["@layer kt-aaa.components{:host{display:block}.kt-select{position:relative}.kt-select__trigger{display:flex;align-items:center;justify-content:space-between;gap:var(--field-control-gap, .5rem);inline-size:100%;cursor:pointer;text-align:start;font:inherit;color:var(--field-color, inherit)}.kt-select__trigger:disabled{cursor:not-allowed;background:var(--field-disabled-bg, #f1f3f4);color:color-mix(in srgb,currentColor 50%,transparent)}.kt-select__value{flex:1;min-inline-size:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kt-select__placeholder{color:var(--field-hint-color, #5f6368)}.kt-select__arrow{flex:none;font-family:Material Symbols Outlined;font-size:1.25em;line-height:1;font-feature-settings:\"liga\";color:var(--field-icon-color, #5f6368);transition:var(--select-arrow-transition, transform .12s ease);-webkit-font-smoothing:antialiased}.kt-select--open .kt-select__arrow{transform:rotate(180deg)}.kt-select__trigger--clearable .kt-select__value{margin-inline-end:2rem}.kt-select__clear{position:absolute;inset-block-start:50%;inset-inline-end:2.5rem;translate:0 -50%;display:inline-flex;align-items:center;justify-content:center;inline-size:24px;block-size:24px;padding:0;border:0;border-radius:50%;background:transparent;color:var(--field-icon-color, #5f6368);cursor:pointer}.kt-select__clear:after{content:\"\";position:absolute;inset:-10px}.kt-select__clear:hover{background-color:color-mix(in srgb,currentColor 12%,transparent);color:var(--field-color, inherit)}.kt-select__clear:focus-visible{outline:2px solid var(--field-border-color-focus, #0b57d0);outline-offset:1px}.kt-select__clear-icon{font-family:Material Symbols Outlined;font-feature-settings:\"liga\";font-size:1.25rem;line-height:1;-webkit-font-smoothing:antialiased}.kt-select__popup{box-sizing:border-box;display:flex;flex-direction:column;margin:0;padding:0;border-width:var(--select-popup-border-width, var(--field-border-width, 1px));border-style:var(--field-border-style, solid);border-color:var(--field-border-color, #c4c7c5);border-radius:var(--field-radius, 8px);background:var(--select-popup-bg, var(--kt-surface-container, var(--kt-surface, #fff)));color:var(--field-color, inherit);box-shadow:var(--select-popup-shadow, 0 4px 12px rgb(0 0 0 / 12%));-webkit-backdrop-filter:var(--select-popup-backdrop-filter, none);backdrop-filter:var(--select-popup-backdrop-filter, none);max-block-size:var(--select-popup-max-height, 16rem);overflow:hidden}.kt-select__sheet-card{display:contents}.kt-select__popup:not(:popover-open){display:none!important}.kt-select__popup:popover-open{animation:var(--select-popup-enter-animation, none)}@media(prefers-reduced-motion:reduce){.kt-select__popup:popover-open{animation:none}}.kt-select__listbox{flex:1 1 auto;min-block-size:0;margin:0;padding:.25rem;list-style:none;overflow-y:auto}.kt-select__panel{display:flex;flex-direction:column;flex:1 1 auto;min-block-size:0}.kt-select__filter{flex:none;padding:.5rem;border-block-end:1px solid var(--field-border-color, #c4c7c5)}.kt-select__filter-input{box-sizing:border-box;inline-size:100%;min-block-size:var(--field-min-height, 44px);padding:.375rem .625rem;border:var(--field-border-width, 1px) var(--field-border-style, solid) var(--field-border-color, #c4c7c5);border-radius:calc(var(--field-radius, 8px) * .75);background:var(--select-popup-bg, var(--kt-surface-container, var(--kt-surface, #fff)));color:var(--field-color, inherit);font:inherit;appearance:none}.kt-select__filter-input::placeholder{color:var(--field-hint-color, #5f6368)}.kt-select__filter-input:focus-visible{outline:2px solid var(--field-border-color-focus, #0b57d0);outline-offset:-1px}.kt-select__filter-input::-webkit-search-cancel-button{appearance:none;inline-size:1rem;block-size:1rem;margin-inline-start:.375rem;cursor:pointer;background-color:var(--field-icon-color, #5f6368);-webkit-mask:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z'/%3E%3C/svg%3E\") center / contain no-repeat;mask:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z'/%3E%3C/svg%3E\") center / contain no-repeat}.kt-select__sr-only{position:absolute;inset-block-start:0;inset-inline-start:0;inline-size:1px;block-size:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}@supports (anchor-name: --x){.kt-select__popup{position:fixed;inset:auto;top:anchor(bottom);left:anchor(left);margin-block-start:.25rem;min-inline-size:anchor-size(width);width:max-content;max-inline-size:min(90vw,28rem);position-try-fallbacks:flip-block,flip-inline,flip-block flip-inline}}@supports not (anchor-name: --x){.kt-select__popup{position:fixed;inset:auto 0 0;inline-size:100%;max-inline-size:100%;border-radius:var(--kt-sheet-radius, 16px) var(--kt-sheet-radius, 16px) 0 0}}.kt-select__popup--sheet{position:fixed!important;inset:0!important;inline-size:100%!important;max-inline-size:100%!important;min-inline-size:0!important;width:100%!important;height:100%!important;max-block-size:none!important;margin:0!important;padding:0!important;border:none!important;background:transparent!important;box-shadow:none!important;border-radius:0!important;display:block;overflow-y:auto!important;scroll-snap-type:y mandatory;overscroll-behavior:contain;scrollbar-width:none}.kt-select__popup--sheet .kt-select__sheet-spacer{block-size:100%;scroll-snap-align:start;scroll-snap-stop:always}.kt-select__popup--sheet .kt-select__sheet-card{position:relative;z-index:2;display:flex;flex-direction:column;background:var(--select-popup-bg, var(--kt-surface-container, var(--kt-surface, #fff)));border-radius:var(--kt-sheet-radius, 16px) var(--kt-sheet-radius, 16px) 0 0;box-shadow:var(--kt-sheet-shadow, 0 -4px 16px rgb(0 0 0 / 12%));max-block-size:var(--kt-sheet-max-block-size, 85svh);width:100%;overflow:hidden;scroll-snap-align:end;scroll-snap-stop:always}.kt-select__popup--sheet .kt-select__sheet-card:has(.kt-select__filter){block-size:var(--kt-sheet-max-block-size, 85svh);max-block-size:var(--kt-sheet-max-block-size, 85svh)}::ng-deep .kt-select__popup--sheet::backdrop{display:none!important}.kt-select__sheet-scrim{display:none}.kt-select__popup--sheet .kt-select__sheet-scrim{display:block;position:fixed;inset:0;z-index:1;background:var(--kt-sheet-scrim, rgb(0 0 0 / 40%));opacity:0;pointer-events:auto;transition:opacity var(--kt-sheet-anim-duration, .12s) ease,overlay var(--kt-sheet-anim-duration, .12s) allow-discrete,display var(--kt-sheet-anim-duration, .12s) allow-discrete}.kt-select__popup--sheet:popover-open .kt-select__sheet-scrim{opacity:1}@starting-style{.kt-select__popup--sheet:popover-open .kt-select__sheet-scrim{opacity:0}}.kt-select__popup--sheet.kt-select__popup--closing .kt-select__sheet-scrim,.kt-select__popup--sheet:popover-open.kt-select__popup--closing .kt-select__sheet-scrim{opacity:0;transition:opacity var(--kt-sheet-exit-duration, 90ms) ease}.kt-select__popup--sheet .kt-select__option{--select-option-min-height: 44px;padding-block:.625rem}.kt-select__popup--sheet .kt-select__filter-input{font-size:1rem;min-block-size:44px}@media(prefers-reduced-motion:reduce){.kt-select__popup--sheet .kt-select__sheet-scrim{transition:none}}.kt-select__sheet-grab{display:flex;align-items:center;justify-content:center;flex:none;block-size:28px}.kt-select__sheet-grab:before{content:\"\";inline-size:2.25rem;block-size:.25rem;border-radius:999px;background:var(--kt-sheet-grab-color, var(--kt-outline, #c4c7c5))}.kt-select__sheet-header{display:flex;align-items:center;justify-content:space-between;gap:.5rem;flex:none;padding-block:.5rem;padding-inline:1rem .5rem;border-block-end:1px solid var(--field-border-color, #c4c7c5)}.kt-select__sheet-title{font-weight:600}.kt-select__sheet-close{display:inline-flex;align-items:center;justify-content:center;flex:none;inline-size:44px;block-size:44px;padding:0;border:0;border-radius:50%;background:transparent;color:var(--field-icon-color, #5f6368);cursor:pointer}.kt-select__sheet-close:focus-visible{outline:2px solid var(--field-border-color-focus, #0b57d0);outline-offset:2px}.kt-select__sheet-close-icon{font-family:Material Symbols Outlined;font-feature-settings:\"liga\";font-size:1.5rem;line-height:1;-webkit-font-smoothing:antialiased}.kt-select__option{display:flex;align-items:center;gap:.5rem;box-sizing:border-box;min-block-size:var( --select-option-min-height, 44px );padding:.5rem .625rem;border-radius:6px;cursor:pointer}.kt-select__option[aria-selected=true]{background:var(--select-option-selected-bg, color-mix(in srgb, var(--kt-primary, #0b57d0) 14%, transparent));color:var(--select-option-selected-color, inherit);font-weight:var(--select-option-selected-weight, 600)}.kt-select__option--active:not([aria-disabled=true]),.kt-select__option:hover:not([aria-disabled=true]){background:var(--select-option-hover-bg, color-mix(in srgb, currentColor 8%, transparent))}.kt-select__option[aria-disabled=true]{opacity:.5;cursor:not-allowed}.kt-select__empty{padding:.5rem .625rem;color:var(--field-hint-color, #5f6368)}.kt-select__truncated-info{box-sizing:border-box;padding:.5rem .625rem;font-size:.875rem;font-style:italic;color:var(--field-hint-color, #5f6368);border-block-start:1px solid var(--field-border-color, #c4c7c5);pointer-events:none}}\n", "@layer kt-aaa.components{.kt-select__actions{display:flex;gap:.25rem;flex:none;padding:.25rem .5rem;border-block-end:1px solid var(--field-border-color, #c4c7c5)}.kt-select__action{flex:1;min-block-size:44px;padding:.375rem .625rem;border:0;border-radius:calc(var(--field-radius, 8px) * .75);background:transparent;color:var(--kt-primary, #0b57d0);font:inherit;font-weight:500;cursor:pointer}.kt-select__action:hover{background:var(--select-option-hover-bg, color-mix(in srgb, currentColor 8%, transparent))}.kt-select__action:focus-visible{outline:2px solid var(--field-border-color-focus, #0b57d0);outline-offset:-2px}.kt-select__count{flex:none;padding:.25rem .75rem;font-size:.8125rem;color:var(--field-hint-color, #5f6368);border-block-end:1px solid var(--field-border-color, #c4c7c5)}.kt-select__checkbox{display:inline-flex;align-items:center;justify-content:center;flex:none;margin-inline-end:.25rem;-webkit-user-select:none;user-select:none}.kt-select__checkbox-icon{font-family:Material Symbols Outlined;font-feature-settings:\"liga\";font-size:1.25rem;line-height:1;color:var(--field-icon-color, #5f6368);-webkit-font-smoothing:antialiased}.kt-select__option[aria-selected=true] .kt-select__checkbox-icon{color:var(--kt-primary, #0b57d0)}.kt-select__option--multiple{display:flex;align-items:center;gap:.5rem}.kt-select__option-content{flex:1;min-inline-size:0}kt-chip-list:not([data-empty]){margin-block-start:.5rem}}\n"] }]
3827
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], selectionActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionActions", required: false }] }], maxVisibleChips: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxVisibleChips", required: false }] }], optionDef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => KtMultiSelectOptionDef), { isSignal: true }] }], triggerDef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => KtMultiSelectTriggerDef), { isSignal: true }] }], chipDef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => KtMultiSelectChipDef), { isSignal: true }] }], chipList: [{ type: i0.ViewChild, args: [i0.forwardRef(() => KtChipList), { isSignal: true }] }] } });
3713
3828
 
3714
3829
  /** Base partagée des champs Temporal (Date/Time/DateTime/YearMonth).
3715
3830
  Toute la logique commune (parsing tolérant, valeur vide `null`, synchronisation de l'input natif)