@ktortu/aaa 0.9.0 → 0.9.1

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.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, inject, computed, ElementRef, Directive, input, output, booleanAttribute, contentChild, viewChild, forwardRef, ChangeDetectionStrategy, Component, model, TemplateRef, afterNextRender, isDevMode, effect, NgZone, PLATFORM_ID, DestroyRef, signal, untracked, Injector, ChangeDetectorRef, viewChildren, Injectable, LOCALE_ID, Pipe } from '@angular/core';
2
+ import { InjectionToken, inject, computed, ElementRef, Directive, input, output, booleanAttribute, contentChild, viewChild, forwardRef, ChangeDetectionStrategy, Component, Injectable, model, TemplateRef, afterNextRender, isDevMode, effect, NgZone, PLATFORM_ID, DestroyRef, signal, untracked, Injector, ChangeDetectorRef, viewChildren, LOCALE_ID, Pipe } from '@angular/core';
3
3
  import { KtTooltip } from '@ktortu/aaa/tooltip';
4
4
  import { KtIdGenerator, KtViewport, createKtSheetDrag } from '@ktortu/aaa/cdk';
5
5
  import { NgTemplateOutlet, DOCUMENT, isPlatformBrowser } from '@angular/common';
@@ -11,15 +11,33 @@ import { Combobox, ComboboxPopup, ComboboxWidget } from '@angular/aria/combobox'
11
11
  const defaultKtFieldErrorMatcher = (state) => state.invalid && state.touched;
12
12
  const KT_FIELD_CONFIG = new InjectionToken('KT_FIELD_CONFIG');
13
13
  /**
14
- * Fournit des défauts de champ (apparence, libellés, matcher d'erreurs…) pour un sous-arbre ou
15
- * l'application entière. Idéal pour une transition globale — ex. tout passer en `outline` façon
16
- * Material en un seul provider.
14
+ * Fournit des défauts de champ (apparence, libellés, matcher d'erreurs, messages d'erreur par
15
+ * défaut…) pour un sous-arbre ou l'application entière. Idéal pour une transition globale — ex. tout
16
+ * passer en `outline` façon Material en un seul provider.
17
17
  *
18
18
  * @example
19
19
  * ```ts
20
- * // app.config.ts
20
+ * // app.config.ts — apparence globale
21
21
  * providers: [provideKtField({ appearance: 'outline' })]
22
22
  * ```
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * // Surcharger des messages d'erreur par défaut (fusionnés par-dessus les défauts anglais).
27
+ * // Une fabrique reçoit l'erreur complète : ses params typés sont lisibles via `ktErrorParam`.
28
+ * providers: [
29
+ * provideKtField({
30
+ * errorMessages: {
31
+ * required: 'Champ obligatoire.',
32
+ * minLength: (e) => `Au moins ${ktErrorParam<number>(e, 'minLength')} caractères.`,
33
+ * pattern: '', // '' supprime le texte de ce kind : champ rouge, sans message
34
+ * },
35
+ * }),
36
+ * ]
37
+ * ```
38
+ *
39
+ * @remarks Pour passer toute la lib en français d'un coup (libellés + messages d'erreur), préférez
40
+ * `provideKtDefaultFR()` (paquet `@ktortu/aaa/i18n`), qui fournit déjà un dictionnaire complet.
23
41
  */
24
42
  function provideKtField(config) {
25
43
  return { provide: KT_FIELD_CONFIG, useValue: config };
@@ -48,14 +66,16 @@ class KtFieldControl {
48
66
  /** Élément DOM hôte du contrôle (exposé pour le focus / la mesure par le parent). */
49
67
  element = inject(ElementRef).nativeElement;
50
68
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtFieldControl, deps: [], target: i0.ɵɵFactoryTarget.Directive });
51
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.1", type: KtFieldControl, isStandalone: true, selector: "[ktFieldControl]", host: { properties: { "id": "id()", "attr.aria-describedby": "describedBy()", "attr.aria-invalid": "invalid() ? \"true\" : null", "attr.aria-required": "required() ? \"true\" : null" } }, ngImport: i0 });
69
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.1", type: KtFieldControl, isStandalone: true, selector: "[ktFieldControl]", host: { properties: { "attr.id": "id()", "attr.aria-describedby": "describedBy()", "attr.aria-invalid": "invalid() ? \"true\" : null", "attr.aria-required": "required() ? \"true\" : null" } }, ngImport: i0 });
52
70
  }
53
71
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtFieldControl, decorators: [{
54
72
  type: Directive,
55
73
  args: [{
56
74
  selector: '[ktFieldControl]',
57
75
  host: {
58
- '[id]': 'id()',
76
+ // `[attr.id]` (et non `[id]`) : quand le contrôle est orphelin (pas de parent KtField), `id()`
77
+ // vaut null et l'attribut doit DISPARAÎTRE — un binding de propriété poserait `id="null"`.
78
+ '[attr.id]': 'id()',
59
79
  '[attr.aria-describedby]': 'describedBy()',
60
80
  '[attr.aria-invalid]': 'invalid() ? "true" : null',
61
81
  '[attr.aria-required]': 'required() ? "true" : null',
@@ -182,6 +202,89 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
182
202
  }, providers: [{ provide: KT_FIELD, useExisting: forwardRef(() => KtField) }], template: "<div class=\"kt-field__header\">\n @if (label(); as labelText) {\n <label class=\"kt-field__label\" [id]=\"labelId()\" [for]=\"baseId()\">\n {{ labelText }}\n @if (required()) {\n <span class=\"kt-field__required\" aria-hidden=\"true\">*</span>\n }\n </label>\n }\n\n @if (helpText(); as help) {\n <button\n type=\"button\"\n class=\"kt-field__help\"\n [ktTooltip]=\"help\"\n [attr.aria-label]=\"helpLabel()\"\n [attr.aria-describedby]=\"null\"\n (click)=\"onHelpClick($event)\"\n >\n <span class=\"kt-field__help-icon\" aria-hidden=\"true\">help</span>\n </button>\n }\n\n <ng-content select=\"[ktFieldHelp]\" />\n</div>\n\n<div class=\"kt-field__control\">\n <ng-content />\n</div>\n\n@if (showHint()) {\n <p class=\"kt-field__hint\" [id]=\"hintId()\">{{ hint() }}</p>\n}\n\n<!-- R\u00E9gion live toujours pr\u00E9sente : les AT annoncent l'erreur d\u00E8s son apparition. -->\n<p class=\"kt-field__error\" [id]=\"errorId()\" aria-live=\"polite\">\n @if (hasError()) {\n @for (error of displayedErrors(); track $index) {\n <span class=\"kt-field__error-message\">{{ error.message }}</span>\n }\n }\n</p>\n", styles: ["@layer kt-aaa.components{:host{display:flex;flex-direction:column;gap:var(--field-gap, .375rem);font-size:var(--field-font-size, 1rem);color:var(--field-color, inherit)}.kt-field__header{display:flex;align-items:center;gap:.375rem}.kt-field__label{font-size:var(--field-label-font-size, .875rem);font-weight:var(--field-label-weight, 500);text-transform:var(--field-label-transform, none);letter-spacing:var(--field-label-letter-spacing, normal);color:var(--field-label-color, inherit)}.kt-field__help{display:inline-flex;align-items:center;justify-content:center;padding:0;border:0;background:transparent;color:var(--field-icon-color, #474747);cursor:pointer;position:relative}.kt-field__help:after{content:\"\";position:absolute;inset:-12px}.kt-field__help-icon{font-family:Material Symbols Outlined;font-size:1.25rem;line-height:1;font-feature-settings:\"liga\";-webkit-font-smoothing:antialiased}.kt-field__required{margin-inline-start:.125rem;color:var(--field-required-color, #8c1d18)}.kt-field__hint{margin:0;font-size:var(--field-hint-font-size, .8125rem);color:var(--field-hint-color, #474747)}.kt-field__error{margin:0;display:flex;flex-direction:column;font-size:var(--field-hint-font-size, .8125rem);color:var(--field-error-color, #8c1d18)}.kt-field__error-message{animation:var(--field-error-animation, none)}@media(prefers-reduced-motion:reduce){.kt-field__error-message{animation:none}}}\n"] }]
183
203
  }], propDecorators: { 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 }] }], helpClick: [{ type: i0.Output, args: ["helpClick"] }], errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], fieldId: [{ type: i0.Input, args: [{ isSignal: true, alias: "fieldId", required: false }] }], hideHintWhenInvalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideHintWhenInvalid", required: false }] }], showAllErrors: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAllErrors", required: false }] }], appearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "appearance", required: false }] }], floatLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "floatLabel", required: false }] }], control: [{ type: i0.ContentChild, args: [i0.forwardRef(() => KtFieldControl), { isSignal: true }] }], templateTooltip: [{ type: i0.ViewChild, args: [i0.forwardRef(() => KtTooltip), { isSignal: true }] }], projectedTooltip: [{ type: i0.ContentChild, args: [i0.forwardRef(() => KtTooltip), { ...{ descendants: true }, isSignal: true }] }] } });
184
204
 
205
+ /**
206
+ * Lit un param typé d'une `ValidationError` (ex. `min`, `minLength`, `maxLength`, `minDate`…).
207
+ * Les sous-types d'erreur de Signal Forms exposent ces params, mais le type de base `ValidationError`
208
+ * ne les déclare pas : ce helper centralise l'accès pour les fabriques de message, sans `any`.
209
+ *
210
+ * @example
211
+ * ```ts
212
+ * minLength: (e) => `Au moins ${ktErrorParam<number>(e, 'minLength')} caractères.`
213
+ * ```
214
+ */
215
+ function ktErrorParam(error, key) {
216
+ return error[key];
217
+ }
218
+ /**
219
+ * Messages d'erreur **anglais** par défaut de la lib, indexés par `kind`. Couvrent tous les
220
+ * validateurs natifs de Signal Forms (`required`, `email`, `min`, `max`, `minLength`, `maxLength`,
221
+ * `minDate`, `maxDate`, `pattern`). Surchargeables famille par famille via `KT_FIELD_CONFIG.errorMessages`
222
+ * (ou globalement par langue, cf. `provideKtDefaultFR`). Le `numberParseError` reste géré à la source
223
+ * par `kt-number-field` (kind `parse`).
224
+ */
225
+ const KT_DEFAULT_FIELD_ERROR_MESSAGES = {
226
+ required: 'This field is required.',
227
+ email: 'Enter a valid email address.',
228
+ min: (e) => `Enter a value greater than or equal to ${ktErrorParam(e, 'min')}.`,
229
+ max: (e) => `Enter a value less than or equal to ${ktErrorParam(e, 'max')}.`,
230
+ minLength: (e) => `Enter at least ${ktErrorParam(e, 'minLength')} characters.`,
231
+ maxLength: (e) => `Enter at most ${ktErrorParam(e, 'maxLength')} characters.`,
232
+ minDate: (e) => `Choose a date on or after ${ktErrorParam(e, 'minDate').toLocaleDateString()}.`,
233
+ maxDate: (e) => `Choose a date on or before ${ktErrorParam(e, 'maxDate').toLocaleDateString()}.`,
234
+ pattern: 'The value is not in the expected format.',
235
+ };
236
+ /**
237
+ * Résout le **message par défaut** d'une erreur de validation à partir de son `kind` (et de ses
238
+ * params typés), en fusionnant les défauts anglais embarqués avec les surcharges du `KT_FIELD_CONFIG`.
239
+ *
240
+ * Utilisé par chaque contrôle `kt-*` au moment du rendu, là où la `ValidationError` complète (params)
241
+ * est encore disponible — `kt-field` reste agnostique de Signal Forms. Précédence du texte affiché :
242
+ * `message` du validateur > `KT_FIELD_CONFIG.errorMessages[kind]` > défaut anglais > rien.
243
+ *
244
+ * Injectable racine : un seul résolveur partagé par tous les champs.
245
+ */
246
+ // Stryker disable next-line all: `providedIn` doit rester statiquement analysable par l'AOT Angular
247
+ // (NG1010) ; aucune logique à muter dans le décorateur.
248
+ class KtFieldErrorResolver {
249
+ config = inject(KT_FIELD_CONFIG, { optional: true });
250
+ /** Map effective : défauts anglais + surcharges du `KT_FIELD_CONFIG`, par `kind`. */
251
+ messages = {
252
+ ...KT_DEFAULT_FIELD_ERROR_MESSAGES,
253
+ ...this.config?.errorMessages,
254
+ };
255
+ /**
256
+ * Message par défaut d'une erreur (selon son `kind` + params), ou `undefined` si aucun défaut
257
+ * n'est connu pour ce `kind` (l'UI n'affiche alors rien).
258
+ */
259
+ resolve(error) {
260
+ const entry = this.messages[error.kind];
261
+ if (entry === undefined)
262
+ return undefined;
263
+ return typeof entry === 'function' ? entry(error) : entry;
264
+ }
265
+ /**
266
+ * Prépare une liste d'erreurs pour l'affichage : applique la précédence (message du validateur
267
+ * sinon défaut résolu) et **écarte les erreurs au message vide** — suppression explicite via
268
+ * `{ message: '' }`. Le champ reste invalide (rouge / `aria-invalid`), simplement sans texte.
269
+ */
270
+ resolveAll(errors) {
271
+ const resolved = [];
272
+ for (const error of errors) {
273
+ const message = error.message ?? this.resolve(error);
274
+ if (message === undefined || message.trim() === '')
275
+ continue;
276
+ resolved.push({ kind: error.kind, message });
277
+ }
278
+ return resolved;
279
+ }
280
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtFieldErrorResolver, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
281
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtFieldErrorResolver, providedIn: 'root' });
282
+ }
283
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtFieldErrorResolver, decorators: [{
284
+ type: Injectable,
285
+ args: [{ providedIn: 'root' }]
286
+ }] });
287
+
185
288
  /** Base partagée des champs simples (TextField, NumberField) : état FormValueControl,
186
289
  présentation (label/hint/prefix/suffix/clear) et politique d'affichage des erreurs.
187
290
  La valeur, son parsing et la notion de « vide » sont fournis par la sous-classe.
@@ -199,6 +302,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
199
302
  ``` */
200
303
  class KtBaseInputField {
201
304
  config = inject(KT_FIELD_CONFIG, { optional: true });
305
+ errorResolver = inject(KtFieldErrorResolver);
202
306
  // --- État poussé par [formField] ---
203
307
  // Ces entrées sont généralement câblées par l'intégration Signal Forms (`[formField]`) ;
204
308
  // tu peux aussi les piloter à la main en usage contrôlé.
@@ -215,6 +319,8 @@ class KtBaseInputField {
215
319
  required = input(false, { ...(ngDevMode ? { debugName: "required" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
216
320
  /** Le champ a-t-il été modifié depuis sa valeur initiale. @default false */
217
321
  dirty = input(false, { ...(ngDevMode ? { debugName: "dirty" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
322
+ /** Validation asynchrone en cours (poussé par `[field]`) : pose `aria-busy` + `data-pending`. @default false */
323
+ pending = input(false, { ...(ngDevMode ? { debugName: "pending" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
218
324
  /** Liste des erreurs de validation à afficher. @default [] */
219
325
  errors = input([], /* @ts-ignore */
220
326
  ...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
@@ -282,6 +388,9 @@ class KtBaseInputField {
282
388
  // L'erreur ne s'affiche qu'au déclenchement décidé par le matcher (invalid/touched/dirty).
283
389
  showInvalid = computed(() => this.matcher()({ invalid: this.invalid(), touched: this.touched(), dirty: this.dirty() }), /* @ts-ignore */
284
390
  ...(ngDevMode ? [{ debugName: "showInvalid" }] : /* istanbul ignore next */ []));
391
+ /** Erreurs prêtes pour `kt-field` : messages par défaut résolus, suppressions (`message: ''`) écartées. */
392
+ displayErrors = computed(() => this.errorResolver.resolveAll(this.errors()), /* @ts-ignore */
393
+ ...(ngDevMode ? [{ debugName: "displayErrors" }] : /* istanbul ignore next */ []));
285
394
  showClear = computed(() => this.clearable() && !this.disabled() && !this.readonly() && !this.isEmpty(this.value()), /* @ts-ignore */
286
395
  ...(ngDevMode ? [{ debugName: "showClear" }] : /* istanbul ignore next */ []));
287
396
  /** Apparence effective (input ?? config ?? 'fill'). Sert aux templates : forward à `kt-field` et,
@@ -318,17 +427,32 @@ class KtBaseInputField {
318
427
  this.clear();
319
428
  }
320
429
  }
430
+ /** Focus le contrôle natif (utilisé par Signal Forms `focusBoundControl`). */
431
+ focus(options) {
432
+ this.inputRef()?.nativeElement.focus(options);
433
+ }
434
+ /** Ré-aligne le texte affiché sur la valeur courante (utilisé par Signal Forms `reset`). */
435
+ reset() {
436
+ const el = this.inputRef()?.nativeElement;
437
+ if (el)
438
+ el.value = this.displayValue();
439
+ }
440
+ /** Représentation texte de la valeur pour l'input natif. Surchargeable par sous-classe. */
441
+ displayValue() {
442
+ const v = this.value();
443
+ return v == null ? '' : String(v);
444
+ }
321
445
  clear() {
322
446
  this.value.set(this.emptyValue());
323
447
  this.touched.set(true);
324
- this.inputRef()?.nativeElement.focus();
448
+ this.focus();
325
449
  }
326
450
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtBaseInputField, deps: [], target: i0.ɵɵFactoryTarget.Directive });
327
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "22.0.1", type: KtBaseInputField, isStandalone: true, inputs: { 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 }, 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 }, autocomplete: { classPropertyName: "autocomplete", publicName: "autocomplete", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, prefix: { classPropertyName: "prefix", publicName: "prefix", isSignal: true, isRequired: false, transformFunction: null }, suffix: { classPropertyName: "suffix", publicName: "suffix", isSignal: true, isRequired: false, transformFunction: null }, clearLabel: { classPropertyName: "clearLabel", publicName: "clearLabel", 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 } }, outputs: { touched: "touchedChange", helpClick: "helpClick" }, viewQueries: [{ propertyName: "inputRef", first: true, predicate: ["input"], descendants: true, isSignal: true }], ngImport: i0 });
451
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "22.0.1", type: KtBaseInputField, isStandalone: true, inputs: { 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 }, autocomplete: { classPropertyName: "autocomplete", publicName: "autocomplete", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, prefix: { classPropertyName: "prefix", publicName: "prefix", isSignal: true, isRequired: false, transformFunction: null }, suffix: { classPropertyName: "suffix", publicName: "suffix", isSignal: true, isRequired: false, transformFunction: null }, clearLabel: { classPropertyName: "clearLabel", publicName: "clearLabel", 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 } }, outputs: { touched: "touchedChange", helpClick: "helpClick" }, viewQueries: [{ propertyName: "inputRef", first: true, predicate: ["input"], descendants: true, isSignal: true }], ngImport: i0 });
328
452
  }
329
453
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtBaseInputField, decorators: [{
330
454
  type: Directive
331
- }], propDecorators: { 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 }] }], 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 }] }], helpClick: [{ type: i0.Output, args: ["helpClick"] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], autocomplete: [{ type: i0.Input, args: [{ isSignal: true, alias: "autocomplete", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], prefix: [{ type: i0.Input, args: [{ isSignal: true, alias: "prefix", required: false }] }], suffix: [{ type: i0.Input, args: [{ isSignal: true, alias: "suffix", required: false }] }], clearLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearLabel", 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 }] }], inputRef: [{ type: i0.ViewChild, args: ['input', { isSignal: true }] }] } });
455
+ }], propDecorators: { 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 }] }], helpClick: [{ type: i0.Output, args: ["helpClick"] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], autocomplete: [{ type: i0.Input, args: [{ isSignal: true, alias: "autocomplete", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], prefix: [{ type: i0.Input, args: [{ isSignal: true, alias: "prefix", required: false }] }], suffix: [{ type: i0.Input, args: [{ isSignal: true, alias: "suffix", required: false }] }], clearLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearLabel", 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 }] }], inputRef: [{ type: i0.ViewChild, args: ['input', { isSignal: true }] }] } });
332
456
 
333
457
  /** Normalise une liste de suggestions en options `<datalist>`. `toValue` sérialise la valeur en
334
458
  chaîne attendue par l'input natif (identité pour le texte, `String()` pour les nombres,
@@ -449,6 +573,11 @@ class KtNumberField extends KtBaseInputField {
449
573
  }
450
574
  this.value.set(newValue);
451
575
  }
576
+ // `rawValue` est un `transformedValue` : on passe par son canal officiel (et non par
577
+ // `nativeElement.value`) pour ne pas désynchroniser la représentation brute interne.
578
+ reset() {
579
+ this.rawValue.set(this.value() === null ? '' : String(this.value()));
580
+ }
452
581
  emptyValue() {
453
582
  return null;
454
583
  }
@@ -456,11 +585,11 @@ class KtNumberField extends KtBaseInputField {
456
585
  return value === null;
457
586
  }
458
587
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtNumberField, deps: null, target: i0.ɵɵFactoryTarget.Component });
459
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: KtNumberField, isStandalone: true, selector: "kt-number-field", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, suggestions: { classPropertyName: "suggestions", publicName: "suggestions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, usesInheritance: true, ngImport: i0, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"errors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div\n class=\"kt-field-box\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n >\n @if (icon(); as icon) {\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">{{ icon }}</span>\n }\n\n @if (prefix(); as prefix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(prefix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(prefix) }}\n }\n </span>\n }\n\n <input\n #input\n ktFieldControl\n class=\"kt-field-box__input\"\n type=\"text\"\n inputmode=\"decimal\"\n role=\"spinbutton\"\n [attr.aria-valuemin]=\"min() ?? null\"\n [attr.aria-valuemax]=\"max() ?? null\"\n [attr.aria-valuenow]=\"value() ?? null\"\n [value]=\"rawValue()\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.name]=\"name() || null\"\n [attr.placeholder]=\"placeholderAttr()\"\n [attr.autocomplete]=\"autocomplete() || null\"\n [attr.min]=\"min() ?? null\"\n [attr.max]=\"max() ?? null\"\n [attr.step]=\"step() ?? null\"\n [attr.list]=\"hasSuggestions() ? datalistId : null\"\n (input)=\"rawValue.set($event.target.value)\"\n (keydown)=\"onKeyDown($event)\"\n (blur)=\"touched.set(true)\"\n />\n\n @if (hasSuggestions()) {\n <datalist [id]=\"datalistId\">\n @for (option of datalistOptions(); track $index) {\n <option [value]=\"option.value\" [attr.label]=\"option.label\"></option>\n }\n </datalist>\n }\n\n @if (showClear()) {\n <button type=\"button\" class=\"kt-field-box__clear\" [attr.aria-label]=\"clearLabel()\" (click)=\"clear()\">\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n @if (suffix(); as suffix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(suffix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(suffix) }}\n }\n </span>\n }\n </div>\n</kt-field>\n", dependencies: [{ kind: "component", type: KtField, selector: "kt-field", inputs: ["label", "hint", "helpText", "helpLabel", "customDescribedBy", "errors", "invalid", "required", "fieldId", "hideHintWhenInvalid", "showAllErrors", "appearance", "floatLabel"], outputs: ["helpClick"] }, { kind: "directive", type: KtFieldControl, selector: "[ktFieldControl]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
588
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: KtNumberField, isStandalone: true, selector: "kt-number-field", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, suggestions: { classPropertyName: "suggestions", publicName: "suggestions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, usesInheritance: true, ngImport: i0, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"displayErrors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div\n class=\"kt-field-box\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n [attr.data-pending]=\"pending() ? '' : null\"\n >\n @if (icon(); as icon) {\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">{{ icon }}</span>\n }\n\n @if (prefix(); as prefix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(prefix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(prefix) }}\n }\n </span>\n }\n\n <input\n #input\n ktFieldControl\n class=\"kt-field-box__input\"\n type=\"text\"\n inputmode=\"decimal\"\n role=\"spinbutton\"\n [attr.aria-valuemin]=\"min() ?? null\"\n [attr.aria-valuemax]=\"max() ?? null\"\n [attr.aria-valuenow]=\"value() ?? null\"\n [value]=\"rawValue()\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.aria-busy]=\"pending() ? 'true' : null\"\n [attr.name]=\"name() || null\"\n [attr.placeholder]=\"placeholderAttr()\"\n [attr.autocomplete]=\"autocomplete() || null\"\n [attr.min]=\"min() ?? null\"\n [attr.max]=\"max() ?? null\"\n [attr.step]=\"step() ?? null\"\n [attr.list]=\"hasSuggestions() ? datalistId : null\"\n (input)=\"rawValue.set($event.target.value)\"\n (keydown)=\"onKeyDown($event)\"\n (blur)=\"touched.set(true)\"\n />\n\n @if (hasSuggestions()) {\n <datalist [id]=\"datalistId\">\n @for (option of datalistOptions(); track $index) {\n <option [value]=\"option.value\" [attr.label]=\"option.label\"></option>\n }\n </datalist>\n }\n\n @if (showClear()) {\n <button type=\"button\" class=\"kt-field-box__clear\" [attr.aria-label]=\"clearLabel()\" (click)=\"clear()\">\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n @if (suffix(); as suffix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(suffix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(suffix) }}\n }\n </span>\n }\n </div>\n</kt-field>\n", dependencies: [{ kind: "component", type: KtField, selector: "kt-field", inputs: ["label", "hint", "helpText", "helpLabel", "customDescribedBy", "errors", "invalid", "required", "fieldId", "hideHintWhenInvalid", "showAllErrors", "appearance", "floatLabel"], outputs: ["helpClick"] }, { kind: "directive", type: KtFieldControl, selector: "[ktFieldControl]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
460
589
  }
461
590
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtNumberField, decorators: [{
462
591
  type: Component,
463
- args: [{ selector: 'kt-number-field', imports: [KtField, KtFieldControl, NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"errors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div\n class=\"kt-field-box\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n >\n @if (icon(); as icon) {\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">{{ icon }}</span>\n }\n\n @if (prefix(); as prefix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(prefix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(prefix) }}\n }\n </span>\n }\n\n <input\n #input\n ktFieldControl\n class=\"kt-field-box__input\"\n type=\"text\"\n inputmode=\"decimal\"\n role=\"spinbutton\"\n [attr.aria-valuemin]=\"min() ?? null\"\n [attr.aria-valuemax]=\"max() ?? null\"\n [attr.aria-valuenow]=\"value() ?? null\"\n [value]=\"rawValue()\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.name]=\"name() || null\"\n [attr.placeholder]=\"placeholderAttr()\"\n [attr.autocomplete]=\"autocomplete() || null\"\n [attr.min]=\"min() ?? null\"\n [attr.max]=\"max() ?? null\"\n [attr.step]=\"step() ?? null\"\n [attr.list]=\"hasSuggestions() ? datalistId : null\"\n (input)=\"rawValue.set($event.target.value)\"\n (keydown)=\"onKeyDown($event)\"\n (blur)=\"touched.set(true)\"\n />\n\n @if (hasSuggestions()) {\n <datalist [id]=\"datalistId\">\n @for (option of datalistOptions(); track $index) {\n <option [value]=\"option.value\" [attr.label]=\"option.label\"></option>\n }\n </datalist>\n }\n\n @if (showClear()) {\n <button type=\"button\" class=\"kt-field-box__clear\" [attr.aria-label]=\"clearLabel()\" (click)=\"clear()\">\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n @if (suffix(); as suffix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(suffix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(suffix) }}\n }\n </span>\n }\n </div>\n</kt-field>\n" }]
592
+ args: [{ selector: 'kt-number-field', imports: [KtField, KtFieldControl, NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"displayErrors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div\n class=\"kt-field-box\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n [attr.data-pending]=\"pending() ? '' : null\"\n >\n @if (icon(); as icon) {\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">{{ icon }}</span>\n }\n\n @if (prefix(); as prefix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(prefix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(prefix) }}\n }\n </span>\n }\n\n <input\n #input\n ktFieldControl\n class=\"kt-field-box__input\"\n type=\"text\"\n inputmode=\"decimal\"\n role=\"spinbutton\"\n [attr.aria-valuemin]=\"min() ?? null\"\n [attr.aria-valuemax]=\"max() ?? null\"\n [attr.aria-valuenow]=\"value() ?? null\"\n [value]=\"rawValue()\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.aria-busy]=\"pending() ? 'true' : null\"\n [attr.name]=\"name() || null\"\n [attr.placeholder]=\"placeholderAttr()\"\n [attr.autocomplete]=\"autocomplete() || null\"\n [attr.min]=\"min() ?? null\"\n [attr.max]=\"max() ?? null\"\n [attr.step]=\"step() ?? null\"\n [attr.list]=\"hasSuggestions() ? datalistId : null\"\n (input)=\"rawValue.set($event.target.value)\"\n (keydown)=\"onKeyDown($event)\"\n (blur)=\"touched.set(true)\"\n />\n\n @if (hasSuggestions()) {\n <datalist [id]=\"datalistId\">\n @for (option of datalistOptions(); track $index) {\n <option [value]=\"option.value\" [attr.label]=\"option.label\"></option>\n }\n </datalist>\n }\n\n @if (showClear()) {\n <button type=\"button\" class=\"kt-field-box__clear\" [attr.aria-label]=\"clearLabel()\" (click)=\"clear()\">\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n @if (suffix(); as suffix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(suffix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(suffix) }}\n }\n </span>\n }\n </div>\n</kt-field>\n" }]
464
593
  }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], suggestions: [{ type: i0.Input, args: [{ isSignal: true, alias: "suggestions", required: false }] }] } });
465
594
 
466
595
  /**
@@ -479,9 +608,19 @@ class KtTextArea extends KtBaseInputField {
479
608
  /** Hauteur initiale (lignes). L'autosize est géré en CSS via `field-sizing: content`. @default 3 */
480
609
  rows = input(3, /* @ts-ignore */
481
610
  ...(ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []));
611
+ /** Plancher de caractères (attribut `minlength` natif ; poussé par le validateur minLength). @default undefined */
612
+ minLength = input(/* @ts-ignore */
613
+ ...(ngDevMode ? [undefined, { debugName: "minLength" }] : /* istanbul ignore next */ []));
482
614
  /** Plafond de caractères ; poussé par le form (validateur maxLength) ou par le consommateur. @default undefined */
483
615
  maxLength = input(/* @ts-ignore */
484
616
  ...(ngDevMode ? [undefined, { debugName: "maxLength" }] : /* istanbul ignore next */ []));
617
+ /** Motifs de validation (contrat Signal Forms). L'attribut natif `pattern` ne prend qu'une regex →
618
+ seule la première est posée. @default [] */
619
+ pattern = input([], /* @ts-ignore */
620
+ ...(ngDevMode ? [{ debugName: "pattern" }] : /* istanbul ignore next */ []));
621
+ /** Source de la première regex pour l'attribut `pattern` natif (`null` si aucune). */
622
+ patternAttr = computed(() => this.pattern()[0]?.source ?? null, /* @ts-ignore */
623
+ ...(ngDevMode ? [{ debugName: "patternAttr" }] : /* istanbul ignore next */ []));
485
624
  parse(raw) {
486
625
  return raw;
487
626
  }
@@ -492,12 +631,12 @@ class KtTextArea extends KtBaseInputField {
492
631
  return value.length === 0;
493
632
  }
494
633
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtTextArea, deps: null, target: i0.ɵɵFactoryTarget.Component });
495
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: KtTextArea, isStandalone: true, selector: "kt-text-area", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, maxLength: { classPropertyName: "maxLength", publicName: "maxLength", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, usesInheritance: true, ngImport: i0, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"errors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div\n class=\"kt-field-box\"\n data-multiline\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n >\n @if (icon(); as icon) {\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">{{ icon }}</span>\n }\n\n @if (prefix(); as prefix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(prefix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(prefix) }}\n }\n </span>\n }\n\n <textarea\n #input\n ktFieldControl\n class=\"kt-field-box__input\"\n [value]=\"value()\"\n [rows]=\"rows()\"\n [style.min-height.lh]=\"rows()\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.name]=\"name() || null\"\n [attr.placeholder]=\"placeholderAttr()\"\n [attr.autocomplete]=\"autocomplete() || null\"\n [attr.maxlength]=\"maxLength() ?? null\"\n (keydown)=\"onKeyDown($event)\"\n (input)=\"onInput($event)\"\n (blur)=\"touched.set(true)\"\n ></textarea>\n\n @if (showClear()) {\n <button type=\"button\" class=\"kt-field-box__clear\" [attr.aria-label]=\"clearLabel()\" (click)=\"clear()\">\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n @if (suffix(); as suffix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(suffix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(suffix) }}\n }\n </span>\n }\n </div>\n</kt-field>\n", dependencies: [{ kind: "component", type: KtField, selector: "kt-field", inputs: ["label", "hint", "helpText", "helpLabel", "customDescribedBy", "errors", "invalid", "required", "fieldId", "hideHintWhenInvalid", "showAllErrors", "appearance", "floatLabel"], outputs: ["helpClick"] }, { kind: "directive", type: KtFieldControl, selector: "[ktFieldControl]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
634
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: KtTextArea, isStandalone: true, selector: "kt-text-area", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, minLength: { classPropertyName: "minLength", publicName: "minLength", isSignal: true, isRequired: false, transformFunction: null }, maxLength: { classPropertyName: "maxLength", publicName: "maxLength", isSignal: true, isRequired: false, transformFunction: null }, pattern: { classPropertyName: "pattern", publicName: "pattern", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, usesInheritance: true, ngImport: i0, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"displayErrors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div\n class=\"kt-field-box\"\n data-multiline\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n [attr.data-pending]=\"pending() ? '' : null\"\n >\n @if (icon(); as icon) {\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">{{ icon }}</span>\n }\n\n @if (prefix(); as prefix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(prefix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(prefix) }}\n }\n </span>\n }\n\n <textarea\n #input\n ktFieldControl\n class=\"kt-field-box__input\"\n [value]=\"value()\"\n [rows]=\"rows()\"\n [style.min-height.lh]=\"rows()\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.aria-busy]=\"pending() ? 'true' : null\"\n [attr.name]=\"name() || null\"\n [attr.placeholder]=\"placeholderAttr()\"\n [attr.autocomplete]=\"autocomplete() || null\"\n [attr.minlength]=\"minLength() ?? null\"\n [attr.maxlength]=\"maxLength() ?? null\"\n [attr.pattern]=\"patternAttr()\"\n (keydown)=\"onKeyDown($event)\"\n (input)=\"onInput($event)\"\n (blur)=\"touched.set(true)\"\n ></textarea>\n\n @if (showClear()) {\n <button type=\"button\" class=\"kt-field-box__clear\" [attr.aria-label]=\"clearLabel()\" (click)=\"clear()\">\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n @if (suffix(); as suffix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(suffix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(suffix) }}\n }\n </span>\n }\n </div>\n</kt-field>\n", dependencies: [{ kind: "component", type: KtField, selector: "kt-field", inputs: ["label", "hint", "helpText", "helpLabel", "customDescribedBy", "errors", "invalid", "required", "fieldId", "hideHintWhenInvalid", "showAllErrors", "appearance", "floatLabel"], outputs: ["helpClick"] }, { kind: "directive", type: KtFieldControl, selector: "[ktFieldControl]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
496
635
  }
497
636
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtTextArea, decorators: [{
498
637
  type: Component,
499
- args: [{ selector: 'kt-text-area', imports: [KtField, KtFieldControl, NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"errors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div\n class=\"kt-field-box\"\n data-multiline\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n >\n @if (icon(); as icon) {\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">{{ icon }}</span>\n }\n\n @if (prefix(); as prefix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(prefix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(prefix) }}\n }\n </span>\n }\n\n <textarea\n #input\n ktFieldControl\n class=\"kt-field-box__input\"\n [value]=\"value()\"\n [rows]=\"rows()\"\n [style.min-height.lh]=\"rows()\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.name]=\"name() || null\"\n [attr.placeholder]=\"placeholderAttr()\"\n [attr.autocomplete]=\"autocomplete() || null\"\n [attr.maxlength]=\"maxLength() ?? null\"\n (keydown)=\"onKeyDown($event)\"\n (input)=\"onInput($event)\"\n (blur)=\"touched.set(true)\"\n ></textarea>\n\n @if (showClear()) {\n <button type=\"button\" class=\"kt-field-box__clear\" [attr.aria-label]=\"clearLabel()\" (click)=\"clear()\">\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n @if (suffix(); as suffix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(suffix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(suffix) }}\n }\n </span>\n }\n </div>\n</kt-field>\n" }]
500
- }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: false }] }], maxLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxLength", required: false }] }] } });
638
+ args: [{ selector: 'kt-text-area', imports: [KtField, KtFieldControl, NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"displayErrors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div\n class=\"kt-field-box\"\n data-multiline\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n [attr.data-pending]=\"pending() ? '' : null\"\n >\n @if (icon(); as icon) {\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">{{ icon }}</span>\n }\n\n @if (prefix(); as prefix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(prefix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(prefix) }}\n }\n </span>\n }\n\n <textarea\n #input\n ktFieldControl\n class=\"kt-field-box__input\"\n [value]=\"value()\"\n [rows]=\"rows()\"\n [style.min-height.lh]=\"rows()\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.aria-busy]=\"pending() ? 'true' : null\"\n [attr.name]=\"name() || null\"\n [attr.placeholder]=\"placeholderAttr()\"\n [attr.autocomplete]=\"autocomplete() || null\"\n [attr.minlength]=\"minLength() ?? null\"\n [attr.maxlength]=\"maxLength() ?? null\"\n [attr.pattern]=\"patternAttr()\"\n (keydown)=\"onKeyDown($event)\"\n (input)=\"onInput($event)\"\n (blur)=\"touched.set(true)\"\n ></textarea>\n\n @if (showClear()) {\n <button type=\"button\" class=\"kt-field-box__clear\" [attr.aria-label]=\"clearLabel()\" (click)=\"clear()\">\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n @if (suffix(); as suffix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(suffix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(suffix) }}\n }\n </span>\n }\n </div>\n</kt-field>\n" }]
639
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: false }] }], minLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "minLength", required: false }] }], maxLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxLength", required: false }] }], pattern: [{ type: i0.Input, args: [{ isSignal: true, alias: "pattern", required: false }] }] } });
501
640
 
502
641
  /**
503
642
  * Champ texte (valeur `string`) intégré aux Signal Forms via `FormValueControl`. Hérite de la
@@ -515,6 +654,19 @@ class KtTextField extends KtBaseInputField {
515
654
  /** Variante HTML du champ (pilote `type` natif et le clavier mobile). @default 'text' */
516
655
  type = input('text', /* @ts-ignore */
517
656
  ...(ngDevMode ? [{ debugName: "type" }] : /* istanbul ignore next */ []));
657
+ /** Plancher de caractères (attribut `minlength` natif ; poussé par le validateur minLength). @default undefined */
658
+ minLength = input(/* @ts-ignore */
659
+ ...(ngDevMode ? [undefined, { debugName: "minLength" }] : /* istanbul ignore next */ []));
660
+ /** Plafond de caractères (attribut `maxlength` natif ; poussé par le validateur maxLength). @default undefined */
661
+ maxLength = input(/* @ts-ignore */
662
+ ...(ngDevMode ? [undefined, { debugName: "maxLength" }] : /* istanbul ignore next */ []));
663
+ /** Motifs de validation (contrat Signal Forms). L'attribut natif `pattern` ne prend qu'une regex →
664
+ seule la première est posée. @default [] */
665
+ pattern = input([], /* @ts-ignore */
666
+ ...(ngDevMode ? [{ debugName: "pattern" }] : /* istanbul ignore next */ []));
667
+ /** Source de la première regex pour l'attribut `pattern` natif (`null` si aucune). */
668
+ patternAttr = computed(() => this.pattern()[0]?.source ?? null, /* @ts-ignore */
669
+ ...(ngDevMode ? [{ debugName: "patternAttr" }] : /* istanbul ignore next */ []));
518
670
  /** Suggestions d'autocomplétion proposées via un `<datalist>` natif (la saisie reste libre).
519
671
  Valeurs simples (`string[]`) ou couples `{ value, label }` pour distinguer libellé affiché et
520
672
  valeur insérée. @default undefined */
@@ -537,12 +689,12 @@ class KtTextField extends KtBaseInputField {
537
689
  return value.length === 0;
538
690
  }
539
691
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtTextField, deps: null, target: i0.ɵɵFactoryTarget.Component });
540
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: KtTextField, isStandalone: true, selector: "kt-text-field", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, suggestions: { classPropertyName: "suggestions", publicName: "suggestions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, usesInheritance: true, ngImport: i0, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"errors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div\n class=\"kt-field-box\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n >\n @if (icon(); as icon) {\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">{{ icon }}</span>\n }\n\n @if (prefix(); as prefix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(prefix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(prefix) }}\n }\n </span>\n }\n\n <input\n #input\n ktFieldControl\n class=\"kt-field-box__input\"\n [type]=\"type()\"\n [value]=\"value()\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.name]=\"name() || null\"\n [attr.placeholder]=\"placeholderAttr()\"\n [attr.autocomplete]=\"autocomplete() || null\"\n [attr.list]=\"hasSuggestions() ? datalistId : null\"\n (keydown)=\"onKeyDown($event)\"\n (input)=\"onInput($event)\"\n (blur)=\"touched.set(true)\"\n />\n\n @if (hasSuggestions()) {\n <datalist [id]=\"datalistId\">\n @for (option of datalistOptions(); track $index) {\n <option [value]=\"option.value\" [attr.label]=\"option.label\"></option>\n }\n </datalist>\n }\n\n @if (showClear()) {\n <button type=\"button\" class=\"kt-field-box__clear\" [attr.aria-label]=\"clearLabel()\" (click)=\"clear()\">\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n @if (suffix(); as suffix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(suffix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(suffix) }}\n }\n </span>\n }\n </div>\n</kt-field>\n", dependencies: [{ kind: "component", type: KtField, selector: "kt-field", inputs: ["label", "hint", "helpText", "helpLabel", "customDescribedBy", "errors", "invalid", "required", "fieldId", "hideHintWhenInvalid", "showAllErrors", "appearance", "floatLabel"], outputs: ["helpClick"] }, { kind: "directive", type: KtFieldControl, selector: "[ktFieldControl]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
692
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: KtTextField, isStandalone: true, selector: "kt-text-field", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, minLength: { classPropertyName: "minLength", publicName: "minLength", isSignal: true, isRequired: false, transformFunction: null }, maxLength: { classPropertyName: "maxLength", publicName: "maxLength", isSignal: true, isRequired: false, transformFunction: null }, pattern: { classPropertyName: "pattern", publicName: "pattern", isSignal: true, isRequired: false, transformFunction: null }, suggestions: { classPropertyName: "suggestions", publicName: "suggestions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, usesInheritance: true, ngImport: i0, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"displayErrors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div\n class=\"kt-field-box\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n [attr.data-pending]=\"pending() ? '' : null\"\n >\n @if (icon(); as icon) {\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">{{ icon }}</span>\n }\n\n @if (prefix(); as prefix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(prefix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(prefix) }}\n }\n </span>\n }\n\n <input\n #input\n ktFieldControl\n class=\"kt-field-box__input\"\n [type]=\"type()\"\n [value]=\"value()\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.aria-busy]=\"pending() ? 'true' : null\"\n [attr.name]=\"name() || null\"\n [attr.placeholder]=\"placeholderAttr()\"\n [attr.autocomplete]=\"autocomplete() || null\"\n [attr.minlength]=\"minLength() ?? null\"\n [attr.maxlength]=\"maxLength() ?? null\"\n [attr.pattern]=\"patternAttr()\"\n [attr.list]=\"hasSuggestions() ? datalistId : null\"\n (keydown)=\"onKeyDown($event)\"\n (input)=\"onInput($event)\"\n (blur)=\"touched.set(true)\"\n />\n\n @if (hasSuggestions()) {\n <datalist [id]=\"datalistId\">\n @for (option of datalistOptions(); track $index) {\n <option [value]=\"option.value\" [attr.label]=\"option.label\"></option>\n }\n </datalist>\n }\n\n @if (showClear()) {\n <button type=\"button\" class=\"kt-field-box__clear\" [attr.aria-label]=\"clearLabel()\" (click)=\"clear()\">\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n @if (suffix(); as suffix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(suffix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(suffix) }}\n }\n </span>\n }\n </div>\n</kt-field>\n", dependencies: [{ kind: "component", type: KtField, selector: "kt-field", inputs: ["label", "hint", "helpText", "helpLabel", "customDescribedBy", "errors", "invalid", "required", "fieldId", "hideHintWhenInvalid", "showAllErrors", "appearance", "floatLabel"], outputs: ["helpClick"] }, { kind: "directive", type: KtFieldControl, selector: "[ktFieldControl]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
541
693
  }
542
694
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtTextField, decorators: [{
543
695
  type: Component,
544
- args: [{ selector: 'kt-text-field', imports: [KtField, KtFieldControl, NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"errors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div\n class=\"kt-field-box\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n >\n @if (icon(); as icon) {\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">{{ icon }}</span>\n }\n\n @if (prefix(); as prefix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(prefix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(prefix) }}\n }\n </span>\n }\n\n <input\n #input\n ktFieldControl\n class=\"kt-field-box__input\"\n [type]=\"type()\"\n [value]=\"value()\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.name]=\"name() || null\"\n [attr.placeholder]=\"placeholderAttr()\"\n [attr.autocomplete]=\"autocomplete() || null\"\n [attr.list]=\"hasSuggestions() ? datalistId : null\"\n (keydown)=\"onKeyDown($event)\"\n (input)=\"onInput($event)\"\n (blur)=\"touched.set(true)\"\n />\n\n @if (hasSuggestions()) {\n <datalist [id]=\"datalistId\">\n @for (option of datalistOptions(); track $index) {\n <option [value]=\"option.value\" [attr.label]=\"option.label\"></option>\n }\n </datalist>\n }\n\n @if (showClear()) {\n <button type=\"button\" class=\"kt-field-box__clear\" [attr.aria-label]=\"clearLabel()\" (click)=\"clear()\">\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n @if (suffix(); as suffix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(suffix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(suffix) }}\n }\n </span>\n }\n </div>\n</kt-field>\n" }]
545
- }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], suggestions: [{ type: i0.Input, args: [{ isSignal: true, alias: "suggestions", required: false }] }] } });
696
+ args: [{ selector: 'kt-text-field', imports: [KtField, KtFieldControl, NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"displayErrors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div\n class=\"kt-field-box\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n [attr.data-pending]=\"pending() ? '' : null\"\n >\n @if (icon(); as icon) {\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">{{ icon }}</span>\n }\n\n @if (prefix(); as prefix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(prefix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(prefix) }}\n }\n </span>\n }\n\n <input\n #input\n ktFieldControl\n class=\"kt-field-box__input\"\n [type]=\"type()\"\n [value]=\"value()\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.aria-busy]=\"pending() ? 'true' : null\"\n [attr.name]=\"name() || null\"\n [attr.placeholder]=\"placeholderAttr()\"\n [attr.autocomplete]=\"autocomplete() || null\"\n [attr.minlength]=\"minLength() ?? null\"\n [attr.maxlength]=\"maxLength() ?? null\"\n [attr.pattern]=\"patternAttr()\"\n [attr.list]=\"hasSuggestions() ? datalistId : null\"\n (keydown)=\"onKeyDown($event)\"\n (input)=\"onInput($event)\"\n (blur)=\"touched.set(true)\"\n />\n\n @if (hasSuggestions()) {\n <datalist [id]=\"datalistId\">\n @for (option of datalistOptions(); track $index) {\n <option [value]=\"option.value\" [attr.label]=\"option.label\"></option>\n }\n </datalist>\n }\n\n @if (showClear()) {\n <button type=\"button\" class=\"kt-field-box__clear\" [attr.aria-label]=\"clearLabel()\" (click)=\"clear()\">\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n @if (suffix(); as suffix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(suffix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(suffix) }}\n }\n </span>\n }\n </div>\n</kt-field>\n" }]
697
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], minLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "minLength", required: false }] }], maxLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxLength", required: false }] }], pattern: [{ type: i0.Input, args: [{ isSignal: true, alias: "pattern", required: false }] }], suggestions: [{ type: i0.Input, args: [{ isSignal: true, alias: "suggestions", required: false }] }] } });
546
698
 
547
699
  /**
548
700
  * Bouton bascule (Switch / Slide-Toggle) accessible conforme aux normes WAI-ARIA.
@@ -571,6 +723,8 @@ class KtSwitch {
571
723
  required = input(false, { ...(ngDevMode ? { debugName: "required" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
572
724
  /** État « modifié » (entre dans la logique d'affichage des erreurs). @default false */
573
725
  dirty = input(false, { ...(ngDevMode ? { debugName: "dirty" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
726
+ /** Validation asynchrone en cours (poussé par `[field]`) : pose `aria-busy` + `data-pending`. @default false */
727
+ pending = input(false, { ...(ngDevMode ? { debugName: "pending" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
574
728
  /** Erreurs de validation à afficher sous la bascule. @default [] */
575
729
  errors = input([], /* @ts-ignore */
576
730
  ...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
@@ -595,6 +749,8 @@ class KtSwitch {
595
749
  ...(ngDevMode ? [undefined, { debugName: "errorMatcher" }] : /* istanbul ignore next */ []));
596
750
  /** Afficher toutes les erreurs au lieu de la première seule. @default KT_FIELD_CONFIG.showAllErrors ?? false */
597
751
  showAllErrors = input(this.config?.showAllErrors ?? false, { ...(ngDevMode ? { debugName: "showAllErrors" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
752
+ switchBtn = viewChild.required('switchBtn');
753
+ errorResolver = inject(KtFieldErrorResolver);
598
754
  idGen = inject(KtIdGenerator);
599
755
  uid = this.idGen.generateId('switch');
600
756
  baseId = computed(() => this.id() ?? `kt-switch-${this.uid}`, /* @ts-ignore */
@@ -609,7 +765,10 @@ class KtSwitch {
609
765
  ...(ngDevMode ? [{ debugName: "matcher" }] : /* istanbul ignore next */ []));
610
766
  showInvalid = computed(() => this.matcher()({ invalid: this.invalid(), touched: this.touched(), dirty: this.dirty() }), /* @ts-ignore */
611
767
  ...(ngDevMode ? [{ debugName: "showInvalid" }] : /* istanbul ignore next */ []));
612
- displayedErrors = computed(() => this.showAllErrors() ? this.errors() : this.errors().slice(0, 1), /* @ts-ignore */
768
+ /** Erreurs résolues (messages par défaut appliqués, suppressions `message: ''` écartées). */
769
+ resolvedErrors = computed(() => this.errorResolver.resolveAll(this.errors()), /* @ts-ignore */
770
+ ...(ngDevMode ? [{ debugName: "resolvedErrors" }] : /* istanbul ignore next */ []));
771
+ displayedErrors = computed(() => this.showAllErrors() ? this.resolvedErrors() : this.resolvedErrors().slice(0, 1), /* @ts-ignore */
613
772
  ...(ngDevMode ? [{ debugName: "displayedErrors" }] : /* istanbul ignore next */ []));
614
773
  resolvedAriaLabel = computed(() => this.ariaLabel() ?? null, /* @ts-ignore */
615
774
  ...(ngDevMode ? [{ debugName: "resolvedAriaLabel" }] : /* istanbul ignore next */ []));
@@ -617,7 +776,7 @@ class KtSwitch {
617
776
  const ids = [];
618
777
  if (this.hint() && !this.showInvalid())
619
778
  ids.push(this.hintId());
620
- if (this.showInvalid() && this.errors().length > 0)
779
+ if (this.showInvalid() && this.resolvedErrors().length > 0)
621
780
  ids.push(this.errorId());
622
781
  return ids.length ? ids.join(' ') : null;
623
782
  }, /* @ts-ignore */
@@ -631,6 +790,10 @@ class KtSwitch {
631
790
  console.warn('[ktSwitch] sans `label` ni `ariaLabel` : le contrôle est annoncé sans nom accessible (WCAG 4.1.2).');
632
791
  });
633
792
  }
793
+ /** Focus le bouton bascule natif (utilisé par Signal Forms `focusBoundControl`). */
794
+ focus(options) {
795
+ this.switchBtn().nativeElement.focus(options);
796
+ }
634
797
  toggle() {
635
798
  if (this.disabled())
636
799
  return;
@@ -642,11 +805,12 @@ class KtSwitch {
642
805
  this.toggle();
643
806
  }
644
807
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtSwitch, deps: [], target: i0.ɵɵFactoryTarget.Component });
645
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: KtSwitch, isStandalone: true, selector: "kt-switch", inputs: { value: { classPropertyName: "value", publicName: "value", 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 }, 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 }, 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 }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, errorMatcher: { classPropertyName: "errorMatcher", publicName: "errorMatcher", isSignal: true, isRequired: false, transformFunction: null }, showAllErrors: { classPropertyName: "showAllErrors", publicName: "showAllErrors", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange" }, ngImport: i0, template: `
808
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: KtSwitch, isStandalone: true, selector: "kt-switch", inputs: { value: { classPropertyName: "value", publicName: "value", 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 }, 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 }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, errorMatcher: { classPropertyName: "errorMatcher", publicName: "errorMatcher", isSignal: true, isRequired: false, transformFunction: null }, showAllErrors: { classPropertyName: "showAllErrors", publicName: "showAllErrors", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange" }, viewQueries: [{ propertyName: "switchBtn", first: true, predicate: ["switchBtn"], descendants: true, isSignal: true }], ngImport: i0, template: `
646
809
  <div
647
810
  class="kt-switch-field"
648
811
  [class.kt-switch-field--invalid]="showInvalid()"
649
812
  [class.kt-switch-field--disabled]="disabled()"
813
+ [attr.data-pending]="pending() ? '' : null"
650
814
  >
651
815
  <div class="kt-switch-row">
652
816
  <button
@@ -660,6 +824,7 @@ class KtSwitch {
660
824
  [attr.aria-describedby]="describedBy()"
661
825
  [attr.aria-invalid]="showInvalid() ? 'true' : null"
662
826
  [attr.aria-required]="required() ? 'true' : null"
827
+ [attr.aria-busy]="pending() ? 'true' : null"
663
828
  [disabled]="disabled()"
664
829
  (click)="toggle()"
665
830
  (keydown.space)="onSpacebar($event)"
@@ -699,6 +864,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
699
864
  class="kt-switch-field"
700
865
  [class.kt-switch-field--invalid]="showInvalid()"
701
866
  [class.kt-switch-field--disabled]="disabled()"
867
+ [attr.data-pending]="pending() ? '' : null"
702
868
  >
703
869
  <div class="kt-switch-row">
704
870
  <button
@@ -712,6 +878,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
712
878
  [attr.aria-describedby]="describedBy()"
713
879
  [attr.aria-invalid]="showInvalid() ? 'true' : null"
714
880
  [attr.aria-required]="required() ? 'true' : null"
881
+ [attr.aria-busy]="pending() ? 'true' : null"
715
882
  [disabled]="disabled()"
716
883
  (click)="toggle()"
717
884
  (keydown.space)="onSpacebar($event)"
@@ -743,7 +910,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
743
910
  </div>
744
911
  </div>
745
912
  `, 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"] }]
746
- }], 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 }] }], 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 }] }] } });
913
+ }], 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 }] }] } });
747
914
 
748
915
  /**
749
916
  * Groupe de cases à cocher (Checkbox Group) conforme à l'ARIA APG / RGAA.
@@ -780,6 +947,8 @@ class KtCheckboxGroup {
780
947
  required = input(false, { ...(ngDevMode ? { debugName: "required" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
781
948
  /** État « modifié » (entre dans la logique d'affichage des erreurs). @default false */
782
949
  dirty = input(false, { ...(ngDevMode ? { debugName: "dirty" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
950
+ /** Validation asynchrone en cours (poussé par `[field]`) : pose `aria-busy` + `data-pending`. @default false */
951
+ pending = input(false, { ...(ngDevMode ? { debugName: "pending" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
783
952
  /** Erreurs de validation à afficher sous le groupe. @default [] */
784
953
  errors = input([], /* @ts-ignore */
785
954
  ...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
@@ -809,6 +978,8 @@ class KtCheckboxGroup {
809
978
  /** Égalité des valeurs en mode objet (défaut : identité `===`). */
810
979
  compareWith = input(/* @ts-ignore */
811
980
  ...(ngDevMode ? [undefined, { debugName: "compareWith" }] : /* istanbul ignore next */ []));
981
+ el = inject(ElementRef);
982
+ errorResolver = inject(KtFieldErrorResolver);
812
983
  idGen = inject(KtIdGenerator);
813
984
  uid = this.idGen.generateId('checkbox-group');
814
985
  baseId = computed(() => this.id() ?? `kt-checkbox-group-${this.uid}`, /* @ts-ignore */
@@ -823,7 +994,10 @@ class KtCheckboxGroup {
823
994
  ...(ngDevMode ? [{ debugName: "matcher" }] : /* istanbul ignore next */ []));
824
995
  showInvalid = computed(() => this.matcher()({ invalid: this.invalid(), touched: this.touched(), dirty: this.dirty() }), /* @ts-ignore */
825
996
  ...(ngDevMode ? [{ debugName: "showInvalid" }] : /* istanbul ignore next */ []));
826
- displayedErrors = computed(() => this.showAllErrors() ? this.errors() : this.errors().slice(0, 1), /* @ts-ignore */
997
+ /** Erreurs résolues (messages par défaut appliqués, suppressions `message: ''` écartées). */
998
+ resolvedErrors = computed(() => this.errorResolver.resolveAll(this.errors()), /* @ts-ignore */
999
+ ...(ngDevMode ? [{ debugName: "resolvedErrors" }] : /* istanbul ignore next */ []));
1000
+ displayedErrors = computed(() => this.showAllErrors() ? this.resolvedErrors() : this.resolvedErrors().slice(0, 1), /* @ts-ignore */
827
1001
  ...(ngDevMode ? [{ debugName: "displayedErrors" }] : /* istanbul ignore next */ []));
828
1002
  resolvedAriaLabel = computed(() => this.ariaLabel() ?? null, /* @ts-ignore */
829
1003
  ...(ngDevMode ? [{ debugName: "resolvedAriaLabel" }] : /* istanbul ignore next */ []));
@@ -831,7 +1005,7 @@ class KtCheckboxGroup {
831
1005
  const ids = [];
832
1006
  if (this.hint() && !this.showInvalid())
833
1007
  ids.push(this.hintId());
834
- if (this.showInvalid() && this.errors().length > 0)
1008
+ if (this.showInvalid() && this.resolvedErrors().length > 0)
835
1009
  ids.push(this.errorId());
836
1010
  return ids.length ? ids.join(' ') : null;
837
1011
  }, /* @ts-ignore */
@@ -844,6 +1018,10 @@ class KtCheckboxGroup {
844
1018
  const cmp = this.comparator();
845
1019
  return arr.some((v) => cmp(v, optionValue));
846
1020
  }
1021
+ /** Focus la première case activable (utilisé par Signal Forms `focusBoundControl`). */
1022
+ focus(options) {
1023
+ this.el.nativeElement.querySelector('input[type="checkbox"]:not([disabled])')?.focus(options);
1024
+ }
847
1025
  /** Ajoute/retire une valeur d'option de la sélection (émis par un enfant au `change` natif). */
848
1026
  toggle(optionValue, checked) {
849
1027
  if (this.disabled())
@@ -860,7 +1038,7 @@ class KtCheckboxGroup {
860
1038
  this.touched.set(true);
861
1039
  }
862
1040
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtCheckboxGroup, deps: [], target: i0.ɵɵFactoryTarget.Component });
863
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: KtCheckboxGroup, isStandalone: true, selector: "kt-checkbox-group", inputs: { value: { classPropertyName: "value", publicName: "value", 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 }, 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 }, 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 }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, errorMatcher: { classPropertyName: "errorMatcher", publicName: "errorMatcher", isSignal: true, isRequired: false, transformFunction: null }, showAllErrors: { classPropertyName: "showAllErrors", publicName: "showAllErrors", isSignal: true, isRequired: false, transformFunction: null }, compareWith: { classPropertyName: "compareWith", publicName: "compareWith", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange" }, ngImport: i0, template: `
1041
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: KtCheckboxGroup, isStandalone: true, selector: "kt-checkbox-group", inputs: { value: { classPropertyName: "value", publicName: "value", 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 }, 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 }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, errorMatcher: { classPropertyName: "errorMatcher", publicName: "errorMatcher", isSignal: true, isRequired: false, transformFunction: null }, showAllErrors: { classPropertyName: "showAllErrors", publicName: "showAllErrors", isSignal: true, isRequired: false, transformFunction: null }, compareWith: { classPropertyName: "compareWith", publicName: "compareWith", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange" }, ngImport: i0, template: `
864
1042
  <div
865
1043
  class="kt-checkbox-group-field"
866
1044
  [class.kt-checkbox-group-field--invalid]="showInvalid()"
@@ -871,6 +1049,8 @@ class KtCheckboxGroup {
871
1049
  [attr.aria-describedby]="describedBy()"
872
1050
  [attr.aria-required]="required() ? 'true' : null"
873
1051
  [attr.aria-invalid]="showInvalid() ? 'true' : null"
1052
+ [attr.aria-busy]="pending() ? 'true' : null"
1053
+ [attr.data-pending]="pending() ? '' : null"
874
1054
  >
875
1055
  @if (label(); as labelText) {
876
1056
  <span [id]="labelId()" class="kt-checkbox-group__legend">
@@ -896,7 +1076,7 @@ class KtCheckboxGroup {
896
1076
  }
897
1077
  </div>
898
1078
  </div>
899
- `, isInline: true, styles: ["@layer kt-aaa.components{:host{display:block}.kt-checkbox-group-field{display:flex;flex-direction:column;gap:var(--field-gap, .375rem)}.kt-checkbox-group__legend{font-size:var(--field-label-font-size, .875rem);font-weight:var(--field-label-weight, 500);color:var(--field-label-color, inherit)}.kt-checkbox-group__required{margin-inline-start:.125rem;color:var(--field-required-color, var(--kt-danger, #8c1d18))}.kt-checkbox-group__options{display:flex;flex-direction:var(--checkbox-group-direction, column);flex-wrap:wrap;gap:var(--checkbox-group-gap, .25rem)}.kt-checkbox-group__hint{margin:0;font-size:var(--field-hint-font-size, .8125rem);color:var(--field-hint-color, #474747)}.kt-checkbox-group__error{margin:0;display:flex;flex-direction:column;font-size:var(--field-hint-font-size, .8125rem);color:var(--field-error-color, #8c1d18)}.kt-checkbox-group__error-message{animation:var(--field-error-animation, none)}@media(prefers-reduced-motion:reduce){.kt-checkbox-group__error-message{animation:none}}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1079
+ `, isInline: true, styles: ["@layer kt-aaa.components{:host{display:block}.kt-checkbox-group-field{display:flex;flex-direction:column;gap:var(--field-gap, .375rem)}.kt-checkbox-group__legend{font-size:var(--field-label-font-size, .875rem);font-weight:var(--field-label-weight, 500);color:var(--field-label-color, inherit)}.kt-checkbox-group__required{margin-inline-start:.125rem;color:var(--field-required-color, var(--kt-danger, #8c1d18))}.kt-checkbox-group__hint{margin:0;font-size:var(--field-hint-font-size, .8125rem);color:var(--field-hint-color, #474747)}.kt-checkbox-group__error{margin:0;display:flex;flex-direction:column;font-size:var(--field-hint-font-size, .8125rem);color:var(--field-error-color, #8c1d18)}.kt-checkbox-group__error-message{animation:var(--field-error-animation, none)}@media(prefers-reduced-motion:reduce){.kt-checkbox-group__error-message{animation:none}}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
900
1080
  }
901
1081
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtCheckboxGroup, decorators: [{
902
1082
  type: Component,
@@ -911,6 +1091,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
911
1091
  [attr.aria-describedby]="describedBy()"
912
1092
  [attr.aria-required]="required() ? 'true' : null"
913
1093
  [attr.aria-invalid]="showInvalid() ? 'true' : null"
1094
+ [attr.aria-busy]="pending() ? 'true' : null"
1095
+ [attr.data-pending]="pending() ? '' : null"
914
1096
  >
915
1097
  @if (label(); as labelText) {
916
1098
  <span [id]="labelId()" class="kt-checkbox-group__legend">
@@ -936,8 +1118,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
936
1118
  }
937
1119
  </div>
938
1120
  </div>
939
- `, styles: ["@layer kt-aaa.components{:host{display:block}.kt-checkbox-group-field{display:flex;flex-direction:column;gap:var(--field-gap, .375rem)}.kt-checkbox-group__legend{font-size:var(--field-label-font-size, .875rem);font-weight:var(--field-label-weight, 500);color:var(--field-label-color, inherit)}.kt-checkbox-group__required{margin-inline-start:.125rem;color:var(--field-required-color, var(--kt-danger, #8c1d18))}.kt-checkbox-group__options{display:flex;flex-direction:var(--checkbox-group-direction, column);flex-wrap:wrap;gap:var(--checkbox-group-gap, .25rem)}.kt-checkbox-group__hint{margin:0;font-size:var(--field-hint-font-size, .8125rem);color:var(--field-hint-color, #474747)}.kt-checkbox-group__error{margin:0;display:flex;flex-direction:column;font-size:var(--field-hint-font-size, .8125rem);color:var(--field-error-color, #8c1d18)}.kt-checkbox-group__error-message{animation:var(--field-error-animation, none)}@media(prefers-reduced-motion:reduce){.kt-checkbox-group__error-message{animation:none}}}\n"] }]
940
- }], 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 }] }], 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 }] }], compareWith: [{ type: i0.Input, args: [{ isSignal: true, alias: "compareWith", required: false }] }] } });
1121
+ `, styles: ["@layer kt-aaa.components{:host{display:block}.kt-checkbox-group-field{display:flex;flex-direction:column;gap:var(--field-gap, .375rem)}.kt-checkbox-group__legend{font-size:var(--field-label-font-size, .875rem);font-weight:var(--field-label-weight, 500);color:var(--field-label-color, inherit)}.kt-checkbox-group__required{margin-inline-start:.125rem;color:var(--field-required-color, var(--kt-danger, #8c1d18))}.kt-checkbox-group__hint{margin:0;font-size:var(--field-hint-font-size, .8125rem);color:var(--field-hint-color, #474747)}.kt-checkbox-group__error{margin:0;display:flex;flex-direction:column;font-size:var(--field-hint-font-size, .8125rem);color:var(--field-error-color, #8c1d18)}.kt-checkbox-group__error-message{animation:var(--field-error-animation, none)}@media(prefers-reduced-motion:reduce){.kt-checkbox-group__error-message{animation:none}}}\n"] }]
1122
+ }], 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 }] }], compareWith: [{ type: i0.Input, args: [{ isSignal: true, alias: "compareWith", required: false }] }] } });
941
1123
 
942
1124
  /**
943
1125
  * Case à cocher (Checkbox) accessible conforme aux normes WAI-ARIA / RGAA.
@@ -992,6 +1174,8 @@ class KtCheckbox {
992
1174
  required = input(false, { ...(ngDevMode ? { debugName: "required" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
993
1175
  /** État « modifié » (entre dans la logique d'affichage des erreurs). @default false */
994
1176
  dirty = input(false, { ...(ngDevMode ? { debugName: "dirty" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1177
+ /** Validation asynchrone en cours (poussé par `[field]`) : pose `aria-busy` + `data-pending`. @default false */
1178
+ pending = input(false, { ...(ngDevMode ? { debugName: "pending" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
995
1179
  /** Erreurs de validation à afficher sous la case. @default [] */
996
1180
  errors = input([], /* @ts-ignore */
997
1181
  ...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
@@ -1018,6 +1202,7 @@ class KtCheckbox {
1018
1202
  showAllErrors = input(this.config?.showAllErrors ?? false, { ...(ngDevMode ? { debugName: "showAllErrors" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1019
1203
  inputEl = viewChild.required('input');
1020
1204
  el = inject(ElementRef);
1205
+ errorResolver = inject(KtFieldErrorResolver);
1021
1206
  idGen = inject(KtIdGenerator);
1022
1207
  uid = this.idGen.generateId('checkbox');
1023
1208
  baseId = computed(() => this.id() ?? `kt-checkbox-${this.uid}`, /* @ts-ignore */
@@ -1037,7 +1222,10 @@ class KtCheckbox {
1037
1222
  ...(ngDevMode ? [{ debugName: "matcher" }] : /* istanbul ignore next */ []));
1038
1223
  showInvalid = computed(() => this.matcher()({ invalid: this.invalid(), touched: this.touched(), dirty: this.dirty() }), /* @ts-ignore */
1039
1224
  ...(ngDevMode ? [{ debugName: "showInvalid" }] : /* istanbul ignore next */ []));
1040
- displayedErrors = computed(() => this.showAllErrors() ? this.errors() : this.errors().slice(0, 1), /* @ts-ignore */
1225
+ /** Erreurs résolues (messages par défaut appliqués, suppressions `message: ''` écartées). */
1226
+ resolvedErrors = computed(() => this.errorResolver.resolveAll(this.errors()), /* @ts-ignore */
1227
+ ...(ngDevMode ? [{ debugName: "resolvedErrors" }] : /* istanbul ignore next */ []));
1228
+ displayedErrors = computed(() => this.showAllErrors() ? this.resolvedErrors() : this.resolvedErrors().slice(0, 1), /* @ts-ignore */
1041
1229
  ...(ngDevMode ? [{ debugName: "displayedErrors" }] : /* istanbul ignore next */ []));
1042
1230
  resolvedAriaLabel = computed(() => this.ariaLabel() ?? null, /* @ts-ignore */
1043
1231
  ...(ngDevMode ? [{ debugName: "resolvedAriaLabel" }] : /* istanbul ignore next */ []));
@@ -1045,7 +1233,7 @@ class KtCheckbox {
1045
1233
  const ids = [];
1046
1234
  if (this.hint() && !this.showInvalid())
1047
1235
  ids.push(this.hintId());
1048
- if (this.showInvalid() && this.errors().length > 0)
1236
+ if (this.showInvalid() && this.resolvedErrors().length > 0)
1049
1237
  ids.push(this.errorId());
1050
1238
  return ids.length ? ids.join(' ') : null;
1051
1239
  }, /* @ts-ignore */
@@ -1060,12 +1248,19 @@ class KtCheckbox {
1060
1248
  afterNextRender(() => {
1061
1249
  if (!isDevMode() || this.label() || this.ariaLabel())
1062
1250
  return;
1063
- const labelText = this.el.nativeElement.querySelector('.kt-checkbox__label')?.textContent?.replace('*', '').trim();
1251
+ const labelText = this.el.nativeElement
1252
+ .querySelector('.kt-checkbox__label')
1253
+ ?.textContent?.replace('*', '')
1254
+ .trim();
1064
1255
  if (!labelText) {
1065
1256
  console.warn('[ktCheckbox] sans `label`, `ariaLabel` ni contenu projeté : annoncée sans nom accessible (WCAG 4.1.2).');
1066
1257
  }
1067
1258
  });
1068
1259
  }
1260
+ /** Focus la case native (utilisé par Signal Forms `focusBoundControl`). */
1261
+ focus(options) {
1262
+ this.inputEl().nativeElement.focus(options);
1263
+ }
1069
1264
  onChange(event) {
1070
1265
  if (this.isDisabled())
1071
1266
  return;
@@ -1082,11 +1277,12 @@ class KtCheckbox {
1082
1277
  (this.group?.touched ?? this.touched).set(true);
1083
1278
  }
1084
1279
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtCheckbox, deps: [], target: i0.ɵɵFactoryTarget.Component });
1085
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: KtCheckbox, isStandalone: true, selector: "kt-checkbox", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, optionValue: { classPropertyName: "optionValue", publicName: "optionValue", isSignal: true, isRequired: false, transformFunction: null }, indeterminate: { classPropertyName: "indeterminate", publicName: "indeterminate", 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 }, 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 }, 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 }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, errorMatcher: { classPropertyName: "errorMatcher", publicName: "errorMatcher", isSignal: true, isRequired: false, transformFunction: null }, showAllErrors: { classPropertyName: "showAllErrors", publicName: "showAllErrors", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange" }, viewQueries: [{ propertyName: "inputEl", first: true, predicate: ["input"], descendants: true, isSignal: true }], ngImport: i0, template: `
1280
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: KtCheckbox, isStandalone: true, selector: "kt-checkbox", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, optionValue: { classPropertyName: "optionValue", publicName: "optionValue", isSignal: true, isRequired: false, transformFunction: null }, indeterminate: { classPropertyName: "indeterminate", publicName: "indeterminate", 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 }, 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 }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, errorMatcher: { classPropertyName: "errorMatcher", publicName: "errorMatcher", isSignal: true, isRequired: false, transformFunction: null }, showAllErrors: { classPropertyName: "showAllErrors", publicName: "showAllErrors", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange" }, viewQueries: [{ propertyName: "inputEl", first: true, predicate: ["input"], descendants: true, isSignal: true }], ngImport: i0, template: `
1086
1281
  <div
1087
1282
  class="kt-checkbox-field"
1088
1283
  [class.kt-checkbox-field--invalid]="showInvalid()"
1089
1284
  [class.kt-checkbox-field--disabled]="isDisabled()"
1285
+ [attr.data-pending]="pending() ? '' : null"
1090
1286
  >
1091
1287
  <label class="kt-checkbox">
1092
1288
  <input
@@ -1101,6 +1297,7 @@ class KtCheckbox {
1101
1297
  [attr.aria-describedby]="describedBy()"
1102
1298
  [attr.aria-invalid]="showInvalid() ? 'true' : null"
1103
1299
  [attr.aria-required]="required() ? 'true' : null"
1300
+ [attr.aria-busy]="pending() ? 'true' : null"
1104
1301
  (change)="onChange($event)"
1105
1302
  (blur)="onBlur()"
1106
1303
  />
@@ -1132,6 +1329,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
1132
1329
  class="kt-checkbox-field"
1133
1330
  [class.kt-checkbox-field--invalid]="showInvalid()"
1134
1331
  [class.kt-checkbox-field--disabled]="isDisabled()"
1332
+ [attr.data-pending]="pending() ? '' : null"
1135
1333
  >
1136
1334
  <label class="kt-checkbox">
1137
1335
  <input
@@ -1146,6 +1344,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
1146
1344
  [attr.aria-describedby]="describedBy()"
1147
1345
  [attr.aria-invalid]="showInvalid() ? 'true' : null"
1148
1346
  [attr.aria-required]="required() ? 'true' : null"
1347
+ [attr.aria-busy]="pending() ? 'true' : null"
1149
1348
  (change)="onChange($event)"
1150
1349
  (blur)="onBlur()"
1151
1350
  />
@@ -1169,7 +1368,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
1169
1368
  </div>
1170
1369
  </div>
1171
1370
  `, styles: ["@layer kt-aaa.components{:host{display:block}.kt-checkbox-field{display:flex;flex-direction:column;gap:var(--field-gap, .375rem)}.kt-checkbox{display:flex;align-items:center;gap:var(--field-control-gap, .5rem);inline-size:100%;box-sizing:border-box;min-block-size:var(--checkbox-target-size, 44px);padding:var(--checkbox-padding, 0);border-radius:inherit;cursor:pointer;-webkit-user-select:none;user-select:none}.kt-checkbox__input{appearance:none;-webkit-appearance:none;margin:0;flex:none;box-sizing:border-box;display:grid;place-content:center;font-size:var(--checkbox-size, 1.25rem);inline-size:1em;block-size:1em;border:var(--checkbox-border-width, 2px) solid var(--checkbox-border-color, var(--field-border-color, var(--kt-outline, #c4c7c5)));border-radius:var(--checkbox-radius, .25rem);background-color:var(--checkbox-bg, var(--field-bg, var(--kt-surface, #ffffff)));cursor:pointer;box-shadow:var(--checkbox-shadow, var(--field-shadow, none));transition:var( --checkbox-transition, background-color .15s cubic-bezier(.4, 0, .2, 1), border-color .15s cubic-bezier(.4, 0, .2, 1), box-shadow .2s ease )}.kt-checkbox__input:before{content:\"\";inline-size:.65em;block-size:.65em;transform:scale(0);transform-origin:center;box-shadow:inset 1em 1em var(--checkbox-mark-color, #ffffff);clip-path:polygon(14% 44%,0 65%,50% 100%,100% 16%,80% 0%,43% 62%);transition:var(--checkbox-mark-transition, transform .12s ease-in)}.kt-checkbox__input:checked:before,.kt-checkbox__input:indeterminate:before{transform:scale(1);animation:var(--checkbox-mark-animation, kt-checkbox-pop .22s cubic-bezier(.34, 1.56, .64, 1))}.kt-checkbox__input:indeterminate:before{clip-path:inset(42% 12%)}@keyframes kt-checkbox-pop{0%{transform:scale(0)}}.kt-checkbox__input:checked,.kt-checkbox__input:indeterminate{background-color:var(--checkbox-bg-checked, var(--kt-primary, #0842a0));border-color:var(--checkbox-border-color-checked, var(--checkbox-bg-checked, var(--kt-primary, #0842a0)));box-shadow:var( --checkbox-shadow-checked, 0 0 8px color-mix(in srgb, var(--checkbox-bg-checked, var(--kt-primary, #0842a0)) 50%, transparent) )}.kt-checkbox__input:hover:not(:disabled){border-color:var( --checkbox-border-color-hover, var(--field-border-color-hover, var(--kt-outline-strong, #5f6368)) );box-shadow:var( --checkbox-shadow-hover, var(--field-shadow-hover, var(--checkbox-shadow, var(--field-shadow, none))) )}.kt-checkbox__input:checked:hover:not(:disabled),.kt-checkbox__input:indeterminate:hover:not(:disabled){background-color:var(--checkbox-bg-checked-hover, color-mix(in srgb, var(--kt-primary, #0842a0) 90%, black));border-color:var(--checkbox-bg-checked-hover, color-mix(in srgb, var(--kt-primary, #0842a0) 90%, black))}.kt-checkbox__input:focus-visible{outline:var(--kt-focus-ring-width, 2px) solid var(--kt-focus-ring-color, #0842a0);outline-offset:var(--checkbox-focus-ring-offset, 2px);box-shadow:var(--checkbox-shadow-focus, var(--field-shadow-focus, var(--field-shadow, none)))}.kt-checkbox__input:disabled{cursor:not-allowed;opacity:.5}.kt-checkbox-field--disabled .kt-checkbox{cursor:not-allowed}.kt-checkbox-field--invalid .kt-checkbox__input:not(:checked):not(:indeterminate){border-color:var(--field-error-color, var(--kt-danger, #8c1d18))}.kt-checkbox__label{font-size:var(--field-label-font-size, .875rem);font-weight:var(--field-label-weight, 500);color:var(--field-label-color, inherit)}.kt-checkbox-field--disabled .kt-checkbox__label{color:var(--field-hint-color, #5f6368);opacity:.6}.kt-checkbox__required{margin-inline-start:.125rem;color:var(--field-required-color, var(--kt-danger, #8c1d18))}.kt-checkbox-hint{margin:0;font-size:var(--field-hint-font-size, .8125rem);color:var(--field-hint-color, #474747)}.kt-checkbox-error{margin:0;display:flex;flex-direction:column;font-size:var(--field-hint-font-size, .8125rem);color:var(--field-error-color, #8c1d18)}.kt-checkbox-error-message{animation:var(--field-error-animation, none)}@media(forced-colors:active){.kt-checkbox__input{border-color:CanvasText;background-color:Canvas}.kt-checkbox__input:checked,.kt-checkbox__input:indeterminate{background-color:Highlight;border-color:Highlight}.kt-checkbox__input:before{box-shadow:inset 1em 1em HighlightText}.kt-checkbox__input:disabled{border-color:GrayText}.kt-checkbox__input:focus-visible{outline:2px solid CanvasText;outline-offset:2px}}@media(prefers-reduced-motion:reduce){.kt-checkbox__input,.kt-checkbox__input:before{transition:none;animation:none}.kt-checkbox-error-message{animation:none}}}\n"] }]
1172
- }], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], optionValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionValue", required: false }] }], indeterminate: [{ type: i0.Input, args: [{ isSignal: true, alias: "indeterminate", required: false }] }], 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 }] }], 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 }] }], inputEl: [{ type: i0.ViewChild, args: ['input', { isSignal: true }] }] } });
1371
+ }], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], optionValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionValue", required: false }] }], indeterminate: [{ type: i0.Input, args: [{ isSignal: true, alias: "indeterminate", required: false }] }], 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 }] }], inputEl: [{ type: i0.ViewChild, args: ['input', { isSignal: true }] }] } });
1173
1372
 
1174
1373
  /**
1175
1374
  * Groupe de boutons radio (Radio Group) conforme à l'ARIA APG / RGAA.
@@ -1207,6 +1406,8 @@ class KtRadioGroup {
1207
1406
  required = input(false, { ...(ngDevMode ? { debugName: "required" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1208
1407
  /** État « modifié » (entre dans la logique d'affichage des erreurs). @default false */
1209
1408
  dirty = input(false, { ...(ngDevMode ? { debugName: "dirty" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1409
+ /** Validation asynchrone en cours (poussé par `[field]`) : pose `aria-busy` + `data-pending`. @default false */
1410
+ pending = input(false, { ...(ngDevMode ? { debugName: "pending" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1210
1411
  /** Erreurs de validation à afficher sous le groupe. @default [] */
1211
1412
  errors = input([], /* @ts-ignore */
1212
1413
  ...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
@@ -1234,6 +1435,8 @@ class KtRadioGroup {
1234
1435
  /** Égalité des valeurs en mode objet (défaut : identité `===`). Seul rescapé du contrat select. */
1235
1436
  compareWith = input(/* @ts-ignore */
1236
1437
  ...(ngDevMode ? [undefined, { debugName: "compareWith" }] : /* istanbul ignore next */ []));
1438
+ el = inject(ElementRef);
1439
+ errorResolver = inject(KtFieldErrorResolver);
1237
1440
  idGen = inject(KtIdGenerator);
1238
1441
  uid = this.idGen.generateId('radio-group');
1239
1442
  baseId = computed(() => this.id() ?? `kt-radio-group-${this.uid}`, /* @ts-ignore */
@@ -1251,7 +1454,10 @@ class KtRadioGroup {
1251
1454
  ...(ngDevMode ? [{ debugName: "matcher" }] : /* istanbul ignore next */ []));
1252
1455
  showInvalid = computed(() => this.matcher()({ invalid: this.invalid(), touched: this.touched(), dirty: this.dirty() }), /* @ts-ignore */
1253
1456
  ...(ngDevMode ? [{ debugName: "showInvalid" }] : /* istanbul ignore next */ []));
1254
- displayedErrors = computed(() => this.showAllErrors() ? this.errors() : this.errors().slice(0, 1), /* @ts-ignore */
1457
+ /** Erreurs résolues (messages par défaut appliqués, suppressions `message: ''` écartées). */
1458
+ resolvedErrors = computed(() => this.errorResolver.resolveAll(this.errors()), /* @ts-ignore */
1459
+ ...(ngDevMode ? [{ debugName: "resolvedErrors" }] : /* istanbul ignore next */ []));
1460
+ displayedErrors = computed(() => this.showAllErrors() ? this.resolvedErrors() : this.resolvedErrors().slice(0, 1), /* @ts-ignore */
1255
1461
  ...(ngDevMode ? [{ debugName: "displayedErrors" }] : /* istanbul ignore next */ []));
1256
1462
  resolvedAriaLabel = computed(() => this.ariaLabel() ?? null, /* @ts-ignore */
1257
1463
  ...(ngDevMode ? [{ debugName: "resolvedAriaLabel" }] : /* istanbul ignore next */ []));
@@ -1259,7 +1465,7 @@ class KtRadioGroup {
1259
1465
  const ids = [];
1260
1466
  if (this.hint() && !this.showInvalid())
1261
1467
  ids.push(this.hintId());
1262
- if (this.showInvalid() && this.errors().length > 0)
1468
+ if (this.showInvalid() && this.resolvedErrors().length > 0)
1263
1469
  ids.push(this.errorId());
1264
1470
  return ids.length ? ids.join(' ') : null;
1265
1471
  }, /* @ts-ignore */
@@ -1273,6 +1479,14 @@ class KtRadioGroup {
1273
1479
  return false;
1274
1480
  return this.comparator()(radioValue, v);
1275
1481
  }
1482
+ /** Focus l'option pertinente (utilisé par Signal Forms `focusBoundControl`) : le radio coché
1483
+ s'il existe, sinon le premier radio activable — conforme au roving tabindex natif. */
1484
+ focus(options) {
1485
+ const root = this.el.nativeElement;
1486
+ const target = root.querySelector('input[type="radio"]:checked') ??
1487
+ root.querySelector('input[type="radio"]:not([disabled])');
1488
+ target?.focus(options);
1489
+ }
1276
1490
  /** Commit d'une sélection émis par un enfant au `change` natif. */
1277
1491
  select(radioValue) {
1278
1492
  if (this.disabled())
@@ -1281,7 +1495,7 @@ class KtRadioGroup {
1281
1495
  this.touched.set(true);
1282
1496
  }
1283
1497
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtRadioGroup, deps: [], target: i0.ɵɵFactoryTarget.Component });
1284
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: KtRadioGroup, isStandalone: true, selector: "kt-radio-group", inputs: { value: { classPropertyName: "value", publicName: "value", 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 }, 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 }, 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 }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, errorMatcher: { classPropertyName: "errorMatcher", publicName: "errorMatcher", isSignal: true, isRequired: false, transformFunction: null }, showAllErrors: { classPropertyName: "showAllErrors", publicName: "showAllErrors", isSignal: true, isRequired: false, transformFunction: null }, compareWith: { classPropertyName: "compareWith", publicName: "compareWith", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange" }, ngImport: i0, template: `
1498
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: KtRadioGroup, isStandalone: true, selector: "kt-radio-group", inputs: { value: { classPropertyName: "value", publicName: "value", 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 }, 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 }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, errorMatcher: { classPropertyName: "errorMatcher", publicName: "errorMatcher", isSignal: true, isRequired: false, transformFunction: null }, showAllErrors: { classPropertyName: "showAllErrors", publicName: "showAllErrors", isSignal: true, isRequired: false, transformFunction: null }, compareWith: { classPropertyName: "compareWith", publicName: "compareWith", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange" }, ngImport: i0, template: `
1285
1499
  <div
1286
1500
  class="kt-radio-group-field"
1287
1501
  [class.kt-radio-group-field--invalid]="showInvalid()"
@@ -1292,6 +1506,8 @@ class KtRadioGroup {
1292
1506
  [attr.aria-describedby]="describedBy()"
1293
1507
  [attr.aria-required]="required() ? 'true' : null"
1294
1508
  [attr.aria-invalid]="showInvalid() ? 'true' : null"
1509
+ [attr.aria-busy]="pending() ? 'true' : null"
1510
+ [attr.data-pending]="pending() ? '' : null"
1295
1511
  >
1296
1512
  @if (label(); as labelText) {
1297
1513
  <span [id]="labelId()" class="kt-radio-group__legend">
@@ -1317,7 +1533,7 @@ class KtRadioGroup {
1317
1533
  }
1318
1534
  </div>
1319
1535
  </div>
1320
- `, isInline: true, styles: ["@layer kt-aaa.components{:host{display:block}.kt-radio-group-field{display:flex;flex-direction:column;gap:var(--field-gap, .375rem)}.kt-radio-group__legend{font-size:var(--field-label-font-size, .875rem);font-weight:var(--field-label-weight, 500);color:var(--field-label-color, inherit)}.kt-radio-group__required{margin-inline-start:.125rem;color:var(--field-required-color, var(--kt-danger, #8c1d18))}.kt-radio-group__options{display:flex;flex-direction:var(--radio-group-direction, row);flex-wrap:wrap;gap:var(--radio-group-gap, 1rem)}.kt-radio-group__hint{margin:0;font-size:var(--field-hint-font-size, .8125rem);color:var(--field-hint-color, #474747)}.kt-radio-group__error{margin:0;display:flex;flex-direction:column;font-size:var(--field-hint-font-size, .8125rem);color:var(--field-error-color, #8c1d18)}.kt-radio-group__error-message{animation:var(--field-error-animation, none)}@media(prefers-reduced-motion:reduce){.kt-radio-group__error-message{animation:none}}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1536
+ `, isInline: true, styles: ["@layer kt-aaa.components{:host{display:block}.kt-radio-group-field{display:flex;flex-direction:column;gap:var(--field-gap, .375rem)}.kt-radio-group__legend{font-size:var(--field-label-font-size, .875rem);font-weight:var(--field-label-weight, 500);color:var(--field-label-color, inherit)}.kt-radio-group__required{margin-inline-start:.125rem;color:var(--field-required-color, var(--kt-danger, #8c1d18))}.kt-radio-group__hint{margin:0;font-size:var(--field-hint-font-size, .8125rem);color:var(--field-hint-color, #474747)}.kt-radio-group__error{margin:0;display:flex;flex-direction:column;font-size:var(--field-hint-font-size, .8125rem);color:var(--field-error-color, #8c1d18)}.kt-radio-group__error-message{animation:var(--field-error-animation, none)}@media(prefers-reduced-motion:reduce){.kt-radio-group__error-message{animation:none}}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1321
1537
  }
1322
1538
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtRadioGroup, decorators: [{
1323
1539
  type: Component,
@@ -1332,6 +1548,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
1332
1548
  [attr.aria-describedby]="describedBy()"
1333
1549
  [attr.aria-required]="required() ? 'true' : null"
1334
1550
  [attr.aria-invalid]="showInvalid() ? 'true' : null"
1551
+ [attr.aria-busy]="pending() ? 'true' : null"
1552
+ [attr.data-pending]="pending() ? '' : null"
1335
1553
  >
1336
1554
  @if (label(); as labelText) {
1337
1555
  <span [id]="labelId()" class="kt-radio-group__legend">
@@ -1357,8 +1575,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
1357
1575
  }
1358
1576
  </div>
1359
1577
  </div>
1360
- `, styles: ["@layer kt-aaa.components{:host{display:block}.kt-radio-group-field{display:flex;flex-direction:column;gap:var(--field-gap, .375rem)}.kt-radio-group__legend{font-size:var(--field-label-font-size, .875rem);font-weight:var(--field-label-weight, 500);color:var(--field-label-color, inherit)}.kt-radio-group__required{margin-inline-start:.125rem;color:var(--field-required-color, var(--kt-danger, #8c1d18))}.kt-radio-group__options{display:flex;flex-direction:var(--radio-group-direction, row);flex-wrap:wrap;gap:var(--radio-group-gap, 1rem)}.kt-radio-group__hint{margin:0;font-size:var(--field-hint-font-size, .8125rem);color:var(--field-hint-color, #474747)}.kt-radio-group__error{margin:0;display:flex;flex-direction:column;font-size:var(--field-hint-font-size, .8125rem);color:var(--field-error-color, #8c1d18)}.kt-radio-group__error-message{animation:var(--field-error-animation, none)}@media(prefers-reduced-motion:reduce){.kt-radio-group__error-message{animation:none}}}\n"] }]
1361
- }], 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 }] }], 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 }] }], compareWith: [{ type: i0.Input, args: [{ isSignal: true, alias: "compareWith", required: false }] }] } });
1578
+ `, styles: ["@layer kt-aaa.components{:host{display:block}.kt-radio-group-field{display:flex;flex-direction:column;gap:var(--field-gap, .375rem)}.kt-radio-group__legend{font-size:var(--field-label-font-size, .875rem);font-weight:var(--field-label-weight, 500);color:var(--field-label-color, inherit)}.kt-radio-group__required{margin-inline-start:.125rem;color:var(--field-required-color, var(--kt-danger, #8c1d18))}.kt-radio-group__hint{margin:0;font-size:var(--field-hint-font-size, .8125rem);color:var(--field-hint-color, #474747)}.kt-radio-group__error{margin:0;display:flex;flex-direction:column;font-size:var(--field-hint-font-size, .8125rem);color:var(--field-error-color, #8c1d18)}.kt-radio-group__error-message{animation:var(--field-error-animation, none)}@media(prefers-reduced-motion:reduce){.kt-radio-group__error-message{animation:none}}}\n"] }]
1579
+ }], 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 }] }], compareWith: [{ type: i0.Input, args: [{ isSignal: true, alias: "compareWith", required: false }] }] } });
1362
1580
 
1363
1581
  /**
1364
1582
  * Bouton radio individuel (enfant déclaratif de `kt-radio-group`).
@@ -1554,6 +1772,7 @@ function normalizeForFilter(s) {
1554
1772
  ou la clé extraite quand `optionValue` est fourni). */
1555
1773
  class KtBaseSelect {
1556
1774
  fieldConfig = inject(KT_FIELD_CONFIG, { optional: true });
1775
+ errorResolver = inject(KtFieldErrorResolver);
1557
1776
  config = inject(KT_SELECT_CONFIG, { optional: true });
1558
1777
  host = inject(ElementRef);
1559
1778
  ngZone = inject(NgZone);
@@ -1595,6 +1814,8 @@ class KtBaseSelect {
1595
1814
  required = input(false, { ...(ngDevMode ? { debugName: "required" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1596
1815
  /** Le champ a-t-il été modifié depuis sa valeur initiale ? Poussé par `[formField]`. @default false */
1597
1816
  dirty = input(false, { ...(ngDevMode ? { debugName: "dirty" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1817
+ /** Validation asynchrone en cours (poussé par `[field]`) : pose `aria-busy` + `data-pending`. @default false */
1818
+ pending = input(false, { ...(ngDevMode ? { debugName: "pending" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1598
1819
  /** Erreurs de validation à afficher. Poussé par `[formField]`. @default [] */
1599
1820
  errors = input([], /* @ts-ignore */
1600
1821
  ...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
@@ -1709,8 +1930,9 @@ class KtBaseSelect {
1709
1930
  this.config?.truncatedResultsAnnouncement ??
1710
1931
  DEFAULT_KT_SELECT_CONFIG.truncatedResultsAnnouncement, /* @ts-ignore */
1711
1932
  ...(ngDevMode ? [{ debugName: "resolvedTruncatedResultsAnnouncement" }] : /* istanbul ignore next */ []));
1712
- // Field attend des { kind, message } ; on mappe les ValidationError.
1713
- fieldErrors = computed(() => this.errors().map((e) => ({ kind: e.kind, message: e.message })), /* @ts-ignore */
1933
+ // Field attend des { kind, message } ; on résout les messages par défaut et on écarte les
1934
+ // suppressions explicites (`message: ''`).
1935
+ fieldErrors = computed(() => this.errorResolver.resolveAll(this.errors()), /* @ts-ignore */
1714
1936
  ...(ngDevMode ? [{ debugName: "fieldErrors" }] : /* istanbul ignore next */ []));
1715
1937
  // --- Accès aux options ---
1716
1938
  labelAccessor = computed(() => accessor(this.optionLabel(), defaultLabel), /* @ts-ignore */
@@ -1966,6 +2188,16 @@ class KtBaseSelect {
1966
2188
  return;
1967
2189
  listbox.value.set(expected);
1968
2190
  }
2191
+ /** Focus le trigger natif (utilisé par Signal Forms `focusBoundControl`). */
2192
+ focus(options) {
2193
+ this.triggerEl()?.nativeElement.focus(options);
2194
+ }
2195
+ /** Referme le panneau et vide le filtre (utilisé par Signal Forms `reset`). La sélection du
2196
+ listbox dérive de `value()` (computed) et se resynchronise seule. */
2197
+ reset() {
2198
+ this.expanded.set(false);
2199
+ this.filterText.set('');
2200
+ }
1969
2201
  /** Desktop filtrable : le focus DOM vit dans le popup (champ/options) — on le rend au trigger
1970
2202
  à la fermeture, sinon il tombe sur `<body>`. (Écran compact : déjà géré par l'effect `compact`.) */
1971
2203
  refocusTriggerAfterFilterClose() {
@@ -2039,7 +2271,7 @@ class KtBaseSelect {
2039
2271
  }, durationMs + 50);
2040
2272
  }
2041
2273
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtBaseSelect, deps: [], target: i0.ɵɵFactoryTarget.Directive });
2042
- 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 }, 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 }, 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 });
2274
+ 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 }, 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 });
2043
2275
  }
2044
2276
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtBaseSelect, decorators: [{
2045
2277
  type: Directive,
@@ -2048,7 +2280,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
2048
2280
  '(keydown)': 'onHostKeydown($event)',
2049
2281
  },
2050
2282
  }]
2051
- }], 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 }] }], 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 }] }], 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 }] }] } });
2283
+ }], 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 }] }], 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 }] }] } });
2052
2284
 
2053
2285
  /** Template de rendu d'une option, posé sur un `<ng-template>` projeté dans `kt-select`.
2054
2286
  L'input sert UNIQUEMENT à inférer `T` (re-bind de la liste d'options) ; `ngTemplateContextGuard`
@@ -2188,11 +2420,11 @@ class KtSelect extends KtBaseSelect {
2188
2420
  }
2189
2421
  }
2190
2422
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtSelect, deps: null, target: i0.ɵɵFactoryTarget.Component });
2191
- 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 (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 >\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, #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, #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;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, #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", "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 });
2423
+ 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 (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, #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, #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, #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", "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 });
2192
2424
  }
2193
2425
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtSelect, decorators: [{
2194
2426
  type: Component,
2195
- 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 (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 >\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, #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, #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;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, #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"] }]
2427
+ 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 (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, #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, #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, #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"] }]
2196
2428
  }], 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 }] }] } });
2197
2429
 
2198
2430
  /** Configure les `kt-select` d'un sous-arbre via DI (équivalent du Context provider de react-select).
@@ -2635,7 +2867,7 @@ class KtChipList {
2635
2867
  }
2636
2868
  }
2637
2869
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtChipList, deps: [], target: i0.ɵɵFactoryTarget.Component });
2638
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: KtChipList, isStandalone: true, selector: "kt-chip-list", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, itemLabel: { classPropertyName: "itemLabel", publicName: "itemLabel", isSignal: true, isRequired: false, transformFunction: null }, itemKey: { classPropertyName: "itemKey", publicName: "itemKey", isSignal: true, isRequired: false, transformFunction: null }, removable: { classPropertyName: "removable", publicName: "removable", 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 }, maxVisible: { classPropertyName: "maxVisible", publicName: "maxVisible", isSignal: true, isRequired: false, transformFunction: null }, listLabel: { classPropertyName: "listLabel", publicName: "listLabel", isSignal: true, isRequired: false, transformFunction: null }, removeItemLabel: { classPropertyName: "removeItemLabel", publicName: "removeItemLabel", isSignal: true, isRequired: false, transformFunction: null }, itemRemovedText: { classPropertyName: "itemRemovedText", publicName: "itemRemovedText", isSignal: true, isRequired: false, transformFunction: null }, moreLabel: { classPropertyName: "moreLabel", publicName: "moreLabel", isSignal: true, isRequired: false, transformFunction: null }, lessLabel: { classPropertyName: "lessLabel", publicName: "lessLabel", isSignal: true, isRequired: false, transformFunction: null }, chipTemplate: { classPropertyName: "chipTemplate", publicName: "chipTemplate", isSignal: true, isRequired: false, transformFunction: null }, emptyFocusTarget: { classPropertyName: "emptyFocusTarget", publicName: "emptyFocusTarget", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { removed: "removed" }, host: { listeners: { "keydown": "onKeydown($event)" }, properties: { "attr.data-empty": "items().length === 0 ? '' : null", "attr.data-vt-active": "transitioning() ? '' : null" } }, providers: [{ provide: ChipTransitionScope, useExisting: KtChipList }], queries: [{ propertyName: "itemDef", first: true, predicate: KtChipItemDef, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "chips", predicate: KtChip, descendants: true, isSignal: true }], ngImport: i0, template: "@if (items().length > 0) {\n <div class=\"kt-chip-list\">\n <div class=\"kt-chip-list__items\" role=\"list\" [attr.aria-label]=\"resolvedListLabel()\">\n @for (item of visibleItems(); track keyOf(item); let i = $index) {\n @if (effectiveTemplate(); as tpl) {\n <div role=\"listitem\" class=\"kt-chip-list__item\">\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: item, remove: removeCallback(item, i) }\"\n />\n </div>\n } @else {\n <kt-chip\n role=\"listitem\"\n [removable]=\"showRemove()\"\n [disabled]=\"disabled()\"\n [removeLabel]=\"removeLabelFor(item)\"\n (remove)=\"removeAt(item, i)\"\n >{{ labelOf(item) }}</kt-chip\n >\n }\n }\n </div>\n <!-- Le bouton de repli/d\u00E9pli n'est PAS un chip : hors du role=\"list\" pour ne pas \u00EAtre\n annonc\u00E9 comme un item de la liste (reste dans la m\u00EAme rang\u00E9e flex). -->\n @if (overflow()) {\n <button\n type=\"button\"\n class=\"kt-chip-list__more\"\n [attr.aria-expanded]=\"expanded()\"\n [style.view-transition-name]=\"transitioning() ? moreBtnTransitionName : null\"\n [style.view-transition-class]=\"'chip-transition'\"\n (click)=\"toggleExpanded()\"\n >\n {{ expanded() ? resolvedLessLabel() : resolvedMoreLabel()(hiddenCount()) }}\n </button>\n }\n </div>\n}\n<!-- Annonce des retraits : TOUJOURS rendue (hors du @if, sinon elle dispara\u00EEt avec le dernier chip). -->\n<div class=\"kt-chip-list__status\" role=\"status\" aria-live=\"polite\">{{ status() }}</div>\n", styles: ["@layer kt-aaa.components{:host{display:block}.kt-chip-list{display:flex;flex-wrap:wrap;gap:.5rem}.kt-chip-list__items,.kt-chip-list__item{display:contents}.kt-chip-list__more{display:inline-flex;align-items:center;gap:var(--chip-gap);padding:var(--chip-padding-y) var(--chip-padding-x);border-radius:var(--chip-radius);background:var(--chip-bg);border:1px solid var(--chip-border);box-shadow:var(--chip-shadow, none);font:inherit;font-size:var(--chip-font-size);color:var(--chip-color);cursor:pointer;min-block-size:24px}.kt-chip-list__more:hover{background:var(--chip-bg-hover);box-shadow:var(--chip-shadow-hover, var(--chip-shadow, none))}.kt-chip-list__more:focus-visible{outline:2px solid var(--chip-focus-ring);outline-offset:1px}.kt-chip-list__status{position:absolute;inline-size:1px;block-size:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}@media(pointer:coarse){.kt-chip-list__more{min-block-size:32px}}}\n"], dependencies: [{ kind: "component", type: KtChip, selector: "kt-chip", inputs: ["removable", "disabled", "removeLabel"], outputs: ["remove"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2870
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: KtChipList, isStandalone: true, selector: "kt-chip-list", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, itemLabel: { classPropertyName: "itemLabel", publicName: "itemLabel", isSignal: true, isRequired: false, transformFunction: null }, itemKey: { classPropertyName: "itemKey", publicName: "itemKey", isSignal: true, isRequired: false, transformFunction: null }, removable: { classPropertyName: "removable", publicName: "removable", 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 }, maxVisible: { classPropertyName: "maxVisible", publicName: "maxVisible", isSignal: true, isRequired: false, transformFunction: null }, listLabel: { classPropertyName: "listLabel", publicName: "listLabel", isSignal: true, isRequired: false, transformFunction: null }, removeItemLabel: { classPropertyName: "removeItemLabel", publicName: "removeItemLabel", isSignal: true, isRequired: false, transformFunction: null }, itemRemovedText: { classPropertyName: "itemRemovedText", publicName: "itemRemovedText", isSignal: true, isRequired: false, transformFunction: null }, moreLabel: { classPropertyName: "moreLabel", publicName: "moreLabel", isSignal: true, isRequired: false, transformFunction: null }, lessLabel: { classPropertyName: "lessLabel", publicName: "lessLabel", isSignal: true, isRequired: false, transformFunction: null }, chipTemplate: { classPropertyName: "chipTemplate", publicName: "chipTemplate", isSignal: true, isRequired: false, transformFunction: null }, emptyFocusTarget: { classPropertyName: "emptyFocusTarget", publicName: "emptyFocusTarget", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { removed: "removed" }, host: { listeners: { "keydown": "onKeydown($event)" }, properties: { "attr.data-empty": "items().length === 0 ? '' : null", "attr.data-vt-active": "transitioning() ? '' : null" } }, providers: [{ provide: ChipTransitionScope, useExisting: KtChipList }], queries: [{ propertyName: "itemDef", first: true, predicate: KtChipItemDef, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "chips", predicate: KtChip, descendants: true, isSignal: true }], ngImport: i0, template: "@if (items().length > 0) {\n <div class=\"kt-chip-list\">\n <div class=\"kt-chip-list__items\" role=\"list\" [attr.aria-label]=\"resolvedListLabel()\">\n @for (item of visibleItems(); track keyOf(item); let i = $index) {\n @if (effectiveTemplate(); as tpl) {\n <div role=\"listitem\" class=\"kt-chip-list__item\">\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: item, remove: removeCallback(item, i) }\"\n />\n </div>\n } @else {\n <kt-chip\n role=\"listitem\"\n [removable]=\"showRemove()\"\n [disabled]=\"disabled()\"\n [removeLabel]=\"removeLabelFor(item)\"\n (remove)=\"removeAt(item, i)\"\n >{{ labelOf(item) }}</kt-chip\n >\n }\n }\n </div>\n <!-- Le bouton de repli/d\u00E9pli n'est PAS un chip : hors du role=\"list\" pour ne pas \u00EAtre\n annonc\u00E9 comme un item de la liste (reste dans la m\u00EAme rang\u00E9e flex). -->\n @if (overflow()) {\n <button\n type=\"button\"\n class=\"kt-chip-list__more\"\n [attr.aria-expanded]=\"expanded()\"\n [style.view-transition-name]=\"transitioning() ? moreBtnTransitionName : null\"\n [style.view-transition-class]=\"'chip-transition'\"\n (click)=\"toggleExpanded()\"\n >\n {{ expanded() ? resolvedLessLabel() : resolvedMoreLabel()(hiddenCount()) }}\n </button>\n }\n </div>\n}\n<!-- Annonce des retraits : TOUJOURS rendue (hors du @if, sinon elle dispara\u00EEt avec le dernier chip). -->\n<div class=\"kt-chip-list__status\" role=\"status\" aria-live=\"polite\">{{ status() }}</div>\n", styles: ["@layer kt-aaa.components{:host{display:block}.kt-chip-list{display:flex;flex-wrap:wrap;gap:.5rem}.kt-chip-list__items,.kt-chip-list__item{display:contents}.kt-chip-list__more{display:inline-flex;align-items:center;gap:var(--chip-gap);padding:var(--chip-padding-y) var(--chip-padding-x);border-radius:var(--chip-radius);background:var(--chip-bg);border:1px solid var(--chip-border);box-shadow:var(--chip-shadow, none);font:inherit;font-size:var(--chip-font-size);color:var(--chip-color);cursor:pointer;min-block-size:24px}.kt-chip-list__more:hover{background:var(--chip-bg-hover);box-shadow:var(--chip-shadow-hover, var(--chip-shadow, none))}.kt-chip-list__more:focus-visible{outline:2px solid var(--chip-focus-ring);outline-offset:1px}.kt-chip-list__status{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}@media(pointer:coarse){.kt-chip-list__more{min-block-size:32px}}}\n"], dependencies: [{ kind: "component", type: KtChip, selector: "kt-chip", inputs: ["removable", "disabled", "removeLabel"], outputs: ["remove"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2639
2871
  }
2640
2872
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtChipList, decorators: [{
2641
2873
  type: Component,
@@ -2645,7 +2877,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
2645
2877
  // nomment les chips à template custom QUE sous ce marqueur (cf. ChipTransitionScope).
2646
2878
  '[attr.data-vt-active]': "transitioning() ? '' : null",
2647
2879
  '(keydown)': 'onKeydown($event)',
2648
- }, template: "@if (items().length > 0) {\n <div class=\"kt-chip-list\">\n <div class=\"kt-chip-list__items\" role=\"list\" [attr.aria-label]=\"resolvedListLabel()\">\n @for (item of visibleItems(); track keyOf(item); let i = $index) {\n @if (effectiveTemplate(); as tpl) {\n <div role=\"listitem\" class=\"kt-chip-list__item\">\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: item, remove: removeCallback(item, i) }\"\n />\n </div>\n } @else {\n <kt-chip\n role=\"listitem\"\n [removable]=\"showRemove()\"\n [disabled]=\"disabled()\"\n [removeLabel]=\"removeLabelFor(item)\"\n (remove)=\"removeAt(item, i)\"\n >{{ labelOf(item) }}</kt-chip\n >\n }\n }\n </div>\n <!-- Le bouton de repli/d\u00E9pli n'est PAS un chip : hors du role=\"list\" pour ne pas \u00EAtre\n annonc\u00E9 comme un item de la liste (reste dans la m\u00EAme rang\u00E9e flex). -->\n @if (overflow()) {\n <button\n type=\"button\"\n class=\"kt-chip-list__more\"\n [attr.aria-expanded]=\"expanded()\"\n [style.view-transition-name]=\"transitioning() ? moreBtnTransitionName : null\"\n [style.view-transition-class]=\"'chip-transition'\"\n (click)=\"toggleExpanded()\"\n >\n {{ expanded() ? resolvedLessLabel() : resolvedMoreLabel()(hiddenCount()) }}\n </button>\n }\n </div>\n}\n<!-- Annonce des retraits : TOUJOURS rendue (hors du @if, sinon elle dispara\u00EEt avec le dernier chip). -->\n<div class=\"kt-chip-list__status\" role=\"status\" aria-live=\"polite\">{{ status() }}</div>\n", styles: ["@layer kt-aaa.components{:host{display:block}.kt-chip-list{display:flex;flex-wrap:wrap;gap:.5rem}.kt-chip-list__items,.kt-chip-list__item{display:contents}.kt-chip-list__more{display:inline-flex;align-items:center;gap:var(--chip-gap);padding:var(--chip-padding-y) var(--chip-padding-x);border-radius:var(--chip-radius);background:var(--chip-bg);border:1px solid var(--chip-border);box-shadow:var(--chip-shadow, none);font:inherit;font-size:var(--chip-font-size);color:var(--chip-color);cursor:pointer;min-block-size:24px}.kt-chip-list__more:hover{background:var(--chip-bg-hover);box-shadow:var(--chip-shadow-hover, var(--chip-shadow, none))}.kt-chip-list__more:focus-visible{outline:2px solid var(--chip-focus-ring);outline-offset:1px}.kt-chip-list__status{position:absolute;inline-size:1px;block-size:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}@media(pointer:coarse){.kt-chip-list__more{min-block-size:32px}}}\n"] }]
2880
+ }, template: "@if (items().length > 0) {\n <div class=\"kt-chip-list\">\n <div class=\"kt-chip-list__items\" role=\"list\" [attr.aria-label]=\"resolvedListLabel()\">\n @for (item of visibleItems(); track keyOf(item); let i = $index) {\n @if (effectiveTemplate(); as tpl) {\n <div role=\"listitem\" class=\"kt-chip-list__item\">\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: item, remove: removeCallback(item, i) }\"\n />\n </div>\n } @else {\n <kt-chip\n role=\"listitem\"\n [removable]=\"showRemove()\"\n [disabled]=\"disabled()\"\n [removeLabel]=\"removeLabelFor(item)\"\n (remove)=\"removeAt(item, i)\"\n >{{ labelOf(item) }}</kt-chip\n >\n }\n }\n </div>\n <!-- Le bouton de repli/d\u00E9pli n'est PAS un chip : hors du role=\"list\" pour ne pas \u00EAtre\n annonc\u00E9 comme un item de la liste (reste dans la m\u00EAme rang\u00E9e flex). -->\n @if (overflow()) {\n <button\n type=\"button\"\n class=\"kt-chip-list__more\"\n [attr.aria-expanded]=\"expanded()\"\n [style.view-transition-name]=\"transitioning() ? moreBtnTransitionName : null\"\n [style.view-transition-class]=\"'chip-transition'\"\n (click)=\"toggleExpanded()\"\n >\n {{ expanded() ? resolvedLessLabel() : resolvedMoreLabel()(hiddenCount()) }}\n </button>\n }\n </div>\n}\n<!-- Annonce des retraits : TOUJOURS rendue (hors du @if, sinon elle dispara\u00EEt avec le dernier chip). -->\n<div class=\"kt-chip-list__status\" role=\"status\" aria-live=\"polite\">{{ status() }}</div>\n", styles: ["@layer kt-aaa.components{:host{display:block}.kt-chip-list{display:flex;flex-wrap:wrap;gap:.5rem}.kt-chip-list__items,.kt-chip-list__item{display:contents}.kt-chip-list__more{display:inline-flex;align-items:center;gap:var(--chip-gap);padding:var(--chip-padding-y) var(--chip-padding-x);border-radius:var(--chip-radius);background:var(--chip-bg);border:1px solid var(--chip-border);box-shadow:var(--chip-shadow, none);font:inherit;font-size:var(--chip-font-size);color:var(--chip-color);cursor:pointer;min-block-size:24px}.kt-chip-list__more:hover{background:var(--chip-bg-hover);box-shadow:var(--chip-shadow-hover, var(--chip-shadow, none))}.kt-chip-list__more:focus-visible{outline:2px solid var(--chip-focus-ring);outline-offset:1px}.kt-chip-list__status{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}@media(pointer:coarse){.kt-chip-list__more{min-block-size:32px}}}\n"] }]
2649
2881
  }], ctorParameters: () => [], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], itemLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemLabel", required: false }] }], itemKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemKey", required: false }] }], removable: [{ type: i0.Input, args: [{ isSignal: true, alias: "removable", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], maxVisible: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxVisible", required: false }] }], listLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "listLabel", required: false }] }], removeItemLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "removeItemLabel", required: false }] }], itemRemovedText: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemRemovedText", required: false }] }], moreLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "moreLabel", required: false }] }], lessLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "lessLabel", required: false }] }], chipTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "chipTemplate", required: false }] }], emptyFocusTarget: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyFocusTarget", required: false }] }], removed: [{ type: i0.Output, args: ["removed"] }], itemDef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => KtChipItemDef), { isSignal: true }] }], chips: [{ type: i0.ViewChildren, args: [i0.forwardRef(() => KtChip), { isSignal: true }] }] } });
2650
2882
 
2651
2883
  /** Template de rendu d'une option dans la liste du multi-select. L'input sert à inférer `T` ;
@@ -2982,7 +3214,7 @@ class KtMultiSelect extends KtBaseSelect {
2982
3214
  this.announceNow(this.resolvedSelectionCountText()(this.selectedOptions().length));
2983
3215
  }
2984
3216
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtMultiSelect, deps: null, target: i0.ɵɵFactoryTarget.Component });
2985
- 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 (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 (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, #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, #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;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, #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", "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 });
3217
+ 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 (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, #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, #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, #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", "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 });
2986
3218
  }
2987
3219
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtMultiSelect, decorators: [{
2988
3220
  type: Component,
@@ -2996,7 +3228,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
2996
3228
  Listbox,
2997
3229
  Option,
2998
3230
  KtChipList,
2999
- ], 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 (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 (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, #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, #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;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, #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"] }]
3231
+ ], 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 (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, #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, #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, #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"] }]
3000
3232
  }], 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 }] }] } });
3001
3233
 
3002
3234
  /** Base partagée des champs Temporal (Date/Time/DateTime/YearMonth).
@@ -3053,6 +3285,20 @@ class KtBaseTemporalField extends KtBaseInputField {
3053
3285
  return null;
3054
3286
  }
3055
3287
  }
3288
+ displayValue() {
3289
+ const v = this.value();
3290
+ return v === null ? '' : this.serialize(v);
3291
+ }
3292
+ /** Efface AUSSI l'input natif. L'effet de synchro ignore une mise à `null` quand l'input est
3293
+ focalisé (pour ne pas écraser une saisie partielle en cours), or `clear()` focalise justement
3294
+ le champ — sans ce forçage, le bouton « effacer » (et Échap) resterait sans effet sur les
3295
+ champs temporels. */
3296
+ clear() {
3297
+ super.clear();
3298
+ const el = this.inputRef()?.nativeElement;
3299
+ if (el)
3300
+ el.value = '';
3301
+ }
3056
3302
  emptyValue() {
3057
3303
  return null;
3058
3304
  }
@@ -3131,16 +3377,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
3131
3377
  type: Directive
3132
3378
  }], propDecorators: { precision: [{ type: i0.Input, args: [{ isSignal: true, alias: "precision", required: false }] }] } });
3133
3379
 
3134
- /** Valeur runtime `Temporal` (native ou polyfill). Cast via `unknown` : selon le contexte de
3135
- compilation, `globalThis.Temporal` peut déjà être typé (augmentation `temporal-polyfill/global`)
3136
- ou non ce cast fonctionne dans les deux cas. */
3137
- const rawTemporal = globalThis.Temporal;
3138
- if (typeof rawTemporal === 'undefined') {
3139
- throw new Error(`[ktortu/aaa] L'espace de noms 'Temporal' est introuvable. ` +
3140
- `Veuillez vous assurer que le polyfill 'temporal-polyfill/global' est correctement importé ` +
3141
- `dans le fichier 'main.ts' de votre application.`);
3380
+ /** Résout la valeur runtime `Temporal` (native ou polyfill) au moment de l'APPEL, pas à
3381
+ l'évaluation du module. Capturer `globalThis.Temporal` à l'import rendrait la lib fragile à
3382
+ l'ordre d'initialisation des modules décidé par le bundler : sur un moteur sans Temporal natif
3383
+ (Safari/WebKit), le module Temporal de la lib pouvait s'évaluer avant l'installation du polyfill
3384
+ et jeter au boot. */
3385
+ function resolveTemporal() {
3386
+ const value = globalThis.Temporal;
3387
+ if (value == null) {
3388
+ throw new Error(`[ktortu/aaa] L'espace de noms 'Temporal' est introuvable. ` +
3389
+ `Veuillez vous assurer que le polyfill 'temporal-polyfill/global' est correctement importé ` +
3390
+ `dans le fichier 'main.ts' de votre application.`);
3391
+ }
3392
+ return value;
3142
3393
  }
3143
- const Temporal = rawTemporal;
3394
+ /** Point d'accès `Temporal` de la lib. Proxy à résolution paresseuse : le namespace réel n'est lu
3395
+ qu'au premier accès de propriété (`Temporal.PlainDate`…), jamais à l'import — ce qui supprime la
3396
+ dépendance à l'ordre d'init des modules et fait booter Safari/WebKit tant que le polyfill est
3397
+ importé dans `main.ts`. */
3398
+ const Temporal = new Proxy({}, {
3399
+ get: (_target, property) => Reflect.get(resolveTemporal(), property),
3400
+ has: (_target, property) => Reflect.has(resolveTemporal(), property),
3401
+ });
3144
3402
 
3145
3403
  /** Champ « date sans heure » : valeur = `Temporal.PlainDate`, input natif `type="date"`.
3146
3404
  *
@@ -3162,11 +3420,11 @@ class KtDateField extends KtBaseTemporalField {
3162
3420
  return value.toString();
3163
3421
  }
3164
3422
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtDateField, deps: null, target: i0.ɵɵFactoryTarget.Component });
3165
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: KtDateField, isStandalone: true, selector: "kt-date-field", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, usesInheritance: true, ngImport: i0, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"errors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div\n class=\"kt-field-box\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n >\n @if (icon(); as icon) {\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">{{ icon }}</span>\n }\n\n @if (prefix(); as prefix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(prefix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(prefix) }}\n }\n </span>\n }\n\n <input\n #input\n ktFieldControl\n class=\"kt-field-box__input\"\n type=\"date\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.name]=\"name() || null\"\n [attr.placeholder]=\"placeholder()\"\n [attr.min]=\"serializedMin()\"\n [attr.max]=\"serializedMax()\"\n [attr.list]=\"hasSuggestions() ? datalistId : null\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeyDown($event)\"\n (blur)=\"touched.set(true)\"\n />\n\n @if (hasSuggestions()) {\n <datalist [id]=\"datalistId\">\n @for (option of datalistOptions(); track $index) {\n <option [value]=\"option.value\" [attr.label]=\"option.label\"></option>\n }\n </datalist>\n }\n\n @if (showClear()) {\n <button type=\"button\" class=\"kt-field-box__clear\" [attr.aria-label]=\"clearLabel()\" (click)=\"clear()\">\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n @if (suffix(); as suffix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(suffix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(suffix) }}\n }\n </span>\n }\n </div>\n</kt-field>\n", dependencies: [{ kind: "component", type: KtField, selector: "kt-field", inputs: ["label", "hint", "helpText", "helpLabel", "customDescribedBy", "errors", "invalid", "required", "fieldId", "hideHintWhenInvalid", "showAllErrors", "appearance", "floatLabel"], outputs: ["helpClick"] }, { kind: "directive", type: KtFieldControl, selector: "[ktFieldControl]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3423
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: KtDateField, isStandalone: true, selector: "kt-date-field", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, usesInheritance: true, ngImport: i0, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"displayErrors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div\n class=\"kt-field-box\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n [attr.data-pending]=\"pending() ? '' : null\"\n >\n @if (icon(); as icon) {\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">{{ icon }}</span>\n }\n\n @if (prefix(); as prefix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(prefix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(prefix) }}\n }\n </span>\n }\n\n <input\n #input\n ktFieldControl\n class=\"kt-field-box__input\"\n type=\"date\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.aria-busy]=\"pending() ? 'true' : null\"\n [attr.name]=\"name() || null\"\n [attr.placeholder]=\"placeholder()\"\n [attr.min]=\"serializedMin()\"\n [attr.max]=\"serializedMax()\"\n [attr.list]=\"hasSuggestions() ? datalistId : null\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeyDown($event)\"\n (blur)=\"touched.set(true)\"\n />\n\n @if (hasSuggestions()) {\n <datalist [id]=\"datalistId\">\n @for (option of datalistOptions(); track $index) {\n <option [value]=\"option.value\" [attr.label]=\"option.label\"></option>\n }\n </datalist>\n }\n\n @if (showClear()) {\n <button type=\"button\" class=\"kt-field-box__clear\" [attr.aria-label]=\"clearLabel()\" (click)=\"clear()\">\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n @if (suffix(); as suffix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(suffix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(suffix) }}\n }\n </span>\n }\n </div>\n</kt-field>\n", dependencies: [{ kind: "component", type: KtField, selector: "kt-field", inputs: ["label", "hint", "helpText", "helpLabel", "customDescribedBy", "errors", "invalid", "required", "fieldId", "hideHintWhenInvalid", "showAllErrors", "appearance", "floatLabel"], outputs: ["helpClick"] }, { kind: "directive", type: KtFieldControl, selector: "[ktFieldControl]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3166
3424
  }
3167
3425
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtDateField, decorators: [{
3168
3426
  type: Component,
3169
- args: [{ selector: 'kt-date-field', imports: [KtField, KtFieldControl, NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"errors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div\n class=\"kt-field-box\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n >\n @if (icon(); as icon) {\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">{{ icon }}</span>\n }\n\n @if (prefix(); as prefix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(prefix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(prefix) }}\n }\n </span>\n }\n\n <input\n #input\n ktFieldControl\n class=\"kt-field-box__input\"\n type=\"date\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.name]=\"name() || null\"\n [attr.placeholder]=\"placeholder()\"\n [attr.min]=\"serializedMin()\"\n [attr.max]=\"serializedMax()\"\n [attr.list]=\"hasSuggestions() ? datalistId : null\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeyDown($event)\"\n (blur)=\"touched.set(true)\"\n />\n\n @if (hasSuggestions()) {\n <datalist [id]=\"datalistId\">\n @for (option of datalistOptions(); track $index) {\n <option [value]=\"option.value\" [attr.label]=\"option.label\"></option>\n }\n </datalist>\n }\n\n @if (showClear()) {\n <button type=\"button\" class=\"kt-field-box__clear\" [attr.aria-label]=\"clearLabel()\" (click)=\"clear()\">\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n @if (suffix(); as suffix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(suffix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(suffix) }}\n }\n </span>\n }\n </div>\n</kt-field>\n" }]
3427
+ args: [{ selector: 'kt-date-field', imports: [KtField, KtFieldControl, NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"displayErrors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div\n class=\"kt-field-box\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n [attr.data-pending]=\"pending() ? '' : null\"\n >\n @if (icon(); as icon) {\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">{{ icon }}</span>\n }\n\n @if (prefix(); as prefix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(prefix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(prefix) }}\n }\n </span>\n }\n\n <input\n #input\n ktFieldControl\n class=\"kt-field-box__input\"\n type=\"date\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.aria-busy]=\"pending() ? 'true' : null\"\n [attr.name]=\"name() || null\"\n [attr.placeholder]=\"placeholder()\"\n [attr.min]=\"serializedMin()\"\n [attr.max]=\"serializedMax()\"\n [attr.list]=\"hasSuggestions() ? datalistId : null\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeyDown($event)\"\n (blur)=\"touched.set(true)\"\n />\n\n @if (hasSuggestions()) {\n <datalist [id]=\"datalistId\">\n @for (option of datalistOptions(); track $index) {\n <option [value]=\"option.value\" [attr.label]=\"option.label\"></option>\n }\n </datalist>\n }\n\n @if (showClear()) {\n <button type=\"button\" class=\"kt-field-box__clear\" [attr.aria-label]=\"clearLabel()\" (click)=\"clear()\">\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n @if (suffix(); as suffix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(suffix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(suffix) }}\n }\n </span>\n }\n </div>\n</kt-field>\n" }]
3170
3428
  }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }] } });
3171
3429
 
3172
3430
  /** Champ « heure sans date » : valeur = `Temporal.PlainTime`, input natif `type="time"`.
@@ -3190,11 +3448,11 @@ class KtTimeField extends KtBaseTimeTemporalField {
3190
3448
  return value.toString({ smallestUnit: this.precision() });
3191
3449
  }
3192
3450
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtTimeField, deps: null, target: i0.ɵɵFactoryTarget.Component });
3193
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: KtTimeField, isStandalone: true, selector: "kt-time-field", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, usesInheritance: true, ngImport: i0, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"errors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div\n class=\"kt-field-box\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n >\n @if (icon(); as icon) {\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">{{ icon }}</span>\n }\n\n @if (prefix(); as prefix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(prefix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(prefix) }}\n }\n </span>\n }\n\n <input\n #input\n ktFieldControl\n class=\"kt-field-box__input\"\n type=\"time\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.name]=\"name() || null\"\n [attr.placeholder]=\"placeholder()\"\n [attr.min]=\"serializedMin()\"\n [attr.max]=\"serializedMax()\"\n [attr.step]=\"step()\"\n [attr.list]=\"hasSuggestions() ? datalistId : null\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeyDown($event)\"\n (blur)=\"touched.set(true)\"\n />\n\n @if (hasSuggestions()) {\n <datalist [id]=\"datalistId\">\n @for (option of datalistOptions(); track $index) {\n <option [value]=\"option.value\" [attr.label]=\"option.label\"></option>\n }\n </datalist>\n }\n\n @if (showClear()) {\n <button type=\"button\" class=\"kt-field-box__clear\" [attr.aria-label]=\"clearLabel()\" (click)=\"clear()\">\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n @if (suffix(); as suffix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(suffix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(suffix) }}\n }\n </span>\n }\n </div>\n</kt-field>\n", dependencies: [{ kind: "component", type: KtField, selector: "kt-field", inputs: ["label", "hint", "helpText", "helpLabel", "customDescribedBy", "errors", "invalid", "required", "fieldId", "hideHintWhenInvalid", "showAllErrors", "appearance", "floatLabel"], outputs: ["helpClick"] }, { kind: "directive", type: KtFieldControl, selector: "[ktFieldControl]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3451
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: KtTimeField, isStandalone: true, selector: "kt-time-field", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, usesInheritance: true, ngImport: i0, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"displayErrors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div\n class=\"kt-field-box\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n [attr.data-pending]=\"pending() ? '' : null\"\n >\n @if (icon(); as icon) {\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">{{ icon }}</span>\n }\n\n @if (prefix(); as prefix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(prefix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(prefix) }}\n }\n </span>\n }\n\n <input\n #input\n ktFieldControl\n class=\"kt-field-box__input\"\n type=\"time\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.aria-busy]=\"pending() ? 'true' : null\"\n [attr.name]=\"name() || null\"\n [attr.placeholder]=\"placeholder()\"\n [attr.min]=\"serializedMin()\"\n [attr.max]=\"serializedMax()\"\n [attr.step]=\"step()\"\n [attr.list]=\"hasSuggestions() ? datalistId : null\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeyDown($event)\"\n (blur)=\"touched.set(true)\"\n />\n\n @if (hasSuggestions()) {\n <datalist [id]=\"datalistId\">\n @for (option of datalistOptions(); track $index) {\n <option [value]=\"option.value\" [attr.label]=\"option.label\"></option>\n }\n </datalist>\n }\n\n @if (showClear()) {\n <button type=\"button\" class=\"kt-field-box__clear\" [attr.aria-label]=\"clearLabel()\" (click)=\"clear()\">\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n @if (suffix(); as suffix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(suffix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(suffix) }}\n }\n </span>\n }\n </div>\n</kt-field>\n", dependencies: [{ kind: "component", type: KtField, selector: "kt-field", inputs: ["label", "hint", "helpText", "helpLabel", "customDescribedBy", "errors", "invalid", "required", "fieldId", "hideHintWhenInvalid", "showAllErrors", "appearance", "floatLabel"], outputs: ["helpClick"] }, { kind: "directive", type: KtFieldControl, selector: "[ktFieldControl]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3194
3452
  }
3195
3453
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtTimeField, decorators: [{
3196
3454
  type: Component,
3197
- args: [{ selector: 'kt-time-field', imports: [KtField, KtFieldControl, NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"errors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div\n class=\"kt-field-box\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n >\n @if (icon(); as icon) {\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">{{ icon }}</span>\n }\n\n @if (prefix(); as prefix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(prefix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(prefix) }}\n }\n </span>\n }\n\n <input\n #input\n ktFieldControl\n class=\"kt-field-box__input\"\n type=\"time\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.name]=\"name() || null\"\n [attr.placeholder]=\"placeholder()\"\n [attr.min]=\"serializedMin()\"\n [attr.max]=\"serializedMax()\"\n [attr.step]=\"step()\"\n [attr.list]=\"hasSuggestions() ? datalistId : null\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeyDown($event)\"\n (blur)=\"touched.set(true)\"\n />\n\n @if (hasSuggestions()) {\n <datalist [id]=\"datalistId\">\n @for (option of datalistOptions(); track $index) {\n <option [value]=\"option.value\" [attr.label]=\"option.label\"></option>\n }\n </datalist>\n }\n\n @if (showClear()) {\n <button type=\"button\" class=\"kt-field-box__clear\" [attr.aria-label]=\"clearLabel()\" (click)=\"clear()\">\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n @if (suffix(); as suffix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(suffix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(suffix) }}\n }\n </span>\n }\n </div>\n</kt-field>\n" }]
3455
+ args: [{ selector: 'kt-time-field', imports: [KtField, KtFieldControl, NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"displayErrors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div\n class=\"kt-field-box\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n [attr.data-pending]=\"pending() ? '' : null\"\n >\n @if (icon(); as icon) {\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">{{ icon }}</span>\n }\n\n @if (prefix(); as prefix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(prefix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(prefix) }}\n }\n </span>\n }\n\n <input\n #input\n ktFieldControl\n class=\"kt-field-box__input\"\n type=\"time\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.aria-busy]=\"pending() ? 'true' : null\"\n [attr.name]=\"name() || null\"\n [attr.placeholder]=\"placeholder()\"\n [attr.min]=\"serializedMin()\"\n [attr.max]=\"serializedMax()\"\n [attr.step]=\"step()\"\n [attr.list]=\"hasSuggestions() ? datalistId : null\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeyDown($event)\"\n (blur)=\"touched.set(true)\"\n />\n\n @if (hasSuggestions()) {\n <datalist [id]=\"datalistId\">\n @for (option of datalistOptions(); track $index) {\n <option [value]=\"option.value\" [attr.label]=\"option.label\"></option>\n }\n </datalist>\n }\n\n @if (showClear()) {\n <button type=\"button\" class=\"kt-field-box__clear\" [attr.aria-label]=\"clearLabel()\" (click)=\"clear()\">\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n @if (suffix(); as suffix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(suffix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(suffix) }}\n }\n </span>\n }\n </div>\n</kt-field>\n" }]
3198
3456
  }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }] } });
3199
3457
 
3200
3458
  /** Champ « date-heure sans fuseau » : valeur = `Temporal.PlainDateTime`, input
@@ -3219,11 +3477,11 @@ class KtDateTimeField extends KtBaseTimeTemporalField {
3219
3477
  return value.toString({ smallestUnit: this.precision() });
3220
3478
  }
3221
3479
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtDateTimeField, deps: null, target: i0.ɵɵFactoryTarget.Component });
3222
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: KtDateTimeField, isStandalone: true, selector: "kt-date-time-field", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, usesInheritance: true, ngImport: i0, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"errors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div\n class=\"kt-field-box\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n >\n @if (icon(); as icon) {\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">{{ icon }}</span>\n }\n\n @if (prefix(); as prefix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(prefix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(prefix) }}\n }\n </span>\n }\n\n <input\n #input\n ktFieldControl\n class=\"kt-field-box__input\"\n type=\"datetime-local\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.name]=\"name() || null\"\n [attr.placeholder]=\"placeholder()\"\n [attr.min]=\"serializedMin()\"\n [attr.max]=\"serializedMax()\"\n [attr.step]=\"step()\"\n [attr.list]=\"hasSuggestions() ? datalistId : null\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeyDown($event)\"\n (blur)=\"touched.set(true)\"\n />\n\n @if (hasSuggestions()) {\n <datalist [id]=\"datalistId\">\n @for (option of datalistOptions(); track $index) {\n <option [value]=\"option.value\" [attr.label]=\"option.label\"></option>\n }\n </datalist>\n }\n\n @if (showClear()) {\n <button type=\"button\" class=\"kt-field-box__clear\" [attr.aria-label]=\"clearLabel()\" (click)=\"clear()\">\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n @if (suffix(); as suffix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(suffix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(suffix) }}\n }\n </span>\n }\n </div>\n</kt-field>\n", dependencies: [{ kind: "component", type: KtField, selector: "kt-field", inputs: ["label", "hint", "helpText", "helpLabel", "customDescribedBy", "errors", "invalid", "required", "fieldId", "hideHintWhenInvalid", "showAllErrors", "appearance", "floatLabel"], outputs: ["helpClick"] }, { kind: "directive", type: KtFieldControl, selector: "[ktFieldControl]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3480
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: KtDateTimeField, isStandalone: true, selector: "kt-date-time-field", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, usesInheritance: true, ngImport: i0, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"displayErrors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div\n class=\"kt-field-box\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n [attr.data-pending]=\"pending() ? '' : null\"\n >\n @if (icon(); as icon) {\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">{{ icon }}</span>\n }\n\n @if (prefix(); as prefix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(prefix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(prefix) }}\n }\n </span>\n }\n\n <input\n #input\n ktFieldControl\n class=\"kt-field-box__input\"\n type=\"datetime-local\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.aria-busy]=\"pending() ? 'true' : null\"\n [attr.name]=\"name() || null\"\n [attr.placeholder]=\"placeholder()\"\n [attr.min]=\"serializedMin()\"\n [attr.max]=\"serializedMax()\"\n [attr.step]=\"step()\"\n [attr.list]=\"hasSuggestions() ? datalistId : null\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeyDown($event)\"\n (blur)=\"touched.set(true)\"\n />\n\n @if (hasSuggestions()) {\n <datalist [id]=\"datalistId\">\n @for (option of datalistOptions(); track $index) {\n <option [value]=\"option.value\" [attr.label]=\"option.label\"></option>\n }\n </datalist>\n }\n\n @if (showClear()) {\n <button type=\"button\" class=\"kt-field-box__clear\" [attr.aria-label]=\"clearLabel()\" (click)=\"clear()\">\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n @if (suffix(); as suffix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(suffix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(suffix) }}\n }\n </span>\n }\n </div>\n</kt-field>\n", dependencies: [{ kind: "component", type: KtField, selector: "kt-field", inputs: ["label", "hint", "helpText", "helpLabel", "customDescribedBy", "errors", "invalid", "required", "fieldId", "hideHintWhenInvalid", "showAllErrors", "appearance", "floatLabel"], outputs: ["helpClick"] }, { kind: "directive", type: KtFieldControl, selector: "[ktFieldControl]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3223
3481
  }
3224
3482
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtDateTimeField, decorators: [{
3225
3483
  type: Component,
3226
- args: [{ selector: 'kt-date-time-field', imports: [KtField, KtFieldControl, NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"errors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div\n class=\"kt-field-box\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n >\n @if (icon(); as icon) {\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">{{ icon }}</span>\n }\n\n @if (prefix(); as prefix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(prefix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(prefix) }}\n }\n </span>\n }\n\n <input\n #input\n ktFieldControl\n class=\"kt-field-box__input\"\n type=\"datetime-local\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.name]=\"name() || null\"\n [attr.placeholder]=\"placeholder()\"\n [attr.min]=\"serializedMin()\"\n [attr.max]=\"serializedMax()\"\n [attr.step]=\"step()\"\n [attr.list]=\"hasSuggestions() ? datalistId : null\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeyDown($event)\"\n (blur)=\"touched.set(true)\"\n />\n\n @if (hasSuggestions()) {\n <datalist [id]=\"datalistId\">\n @for (option of datalistOptions(); track $index) {\n <option [value]=\"option.value\" [attr.label]=\"option.label\"></option>\n }\n </datalist>\n }\n\n @if (showClear()) {\n <button type=\"button\" class=\"kt-field-box__clear\" [attr.aria-label]=\"clearLabel()\" (click)=\"clear()\">\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n @if (suffix(); as suffix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(suffix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(suffix) }}\n }\n </span>\n }\n </div>\n</kt-field>\n" }]
3484
+ args: [{ selector: 'kt-date-time-field', imports: [KtField, KtFieldControl, NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"displayErrors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div\n class=\"kt-field-box\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n [attr.data-pending]=\"pending() ? '' : null\"\n >\n @if (icon(); as icon) {\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">{{ icon }}</span>\n }\n\n @if (prefix(); as prefix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(prefix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(prefix) }}\n }\n </span>\n }\n\n <input\n #input\n ktFieldControl\n class=\"kt-field-box__input\"\n type=\"datetime-local\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.aria-busy]=\"pending() ? 'true' : null\"\n [attr.name]=\"name() || null\"\n [attr.placeholder]=\"placeholder()\"\n [attr.min]=\"serializedMin()\"\n [attr.max]=\"serializedMax()\"\n [attr.step]=\"step()\"\n [attr.list]=\"hasSuggestions() ? datalistId : null\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeyDown($event)\"\n (blur)=\"touched.set(true)\"\n />\n\n @if (hasSuggestions()) {\n <datalist [id]=\"datalistId\">\n @for (option of datalistOptions(); track $index) {\n <option [value]=\"option.value\" [attr.label]=\"option.label\"></option>\n }\n </datalist>\n }\n\n @if (showClear()) {\n <button type=\"button\" class=\"kt-field-box__clear\" [attr.aria-label]=\"clearLabel()\" (click)=\"clear()\">\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n @if (suffix(); as suffix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(suffix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(suffix) }}\n }\n </span>\n }\n </div>\n</kt-field>\n" }]
3227
3485
  }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }] } });
3228
3486
 
3229
3487
  /** Champ « mois/année » (ex. expiration de carte) : valeur = `Temporal.PlainYearMonth`,
@@ -3247,11 +3505,11 @@ class KtYearMonthField extends KtBaseTemporalField {
3247
3505
  return value.toString();
3248
3506
  }
3249
3507
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtYearMonthField, deps: null, target: i0.ɵɵFactoryTarget.Component });
3250
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: KtYearMonthField, isStandalone: true, selector: "kt-year-month-field", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, usesInheritance: true, ngImport: i0, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"errors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div\n class=\"kt-field-box\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n >\n @if (icon(); as icon) {\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">{{ icon }}</span>\n }\n\n @if (prefix(); as prefix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(prefix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(prefix) }}\n }\n </span>\n }\n\n <input\n #input\n ktFieldControl\n class=\"kt-field-box__input\"\n type=\"month\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.name]=\"name() || null\"\n [attr.placeholder]=\"placeholder()\"\n [attr.min]=\"serializedMin()\"\n [attr.max]=\"serializedMax()\"\n [attr.list]=\"hasSuggestions() ? datalistId : null\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeyDown($event)\"\n (blur)=\"touched.set(true)\"\n />\n\n @if (hasSuggestions()) {\n <datalist [id]=\"datalistId\">\n @for (option of datalistOptions(); track $index) {\n <option [value]=\"option.value\" [attr.label]=\"option.label\"></option>\n }\n </datalist>\n }\n\n @if (showClear()) {\n <button type=\"button\" class=\"kt-field-box__clear\" [attr.aria-label]=\"clearLabel()\" (click)=\"clear()\">\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n @if (suffix(); as suffix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(suffix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(suffix) }}\n }\n </span>\n }\n </div>\n</kt-field>\n", dependencies: [{ kind: "component", type: KtField, selector: "kt-field", inputs: ["label", "hint", "helpText", "helpLabel", "customDescribedBy", "errors", "invalid", "required", "fieldId", "hideHintWhenInvalid", "showAllErrors", "appearance", "floatLabel"], outputs: ["helpClick"] }, { kind: "directive", type: KtFieldControl, selector: "[ktFieldControl]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3508
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: KtYearMonthField, isStandalone: true, selector: "kt-year-month-field", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, usesInheritance: true, ngImport: i0, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"displayErrors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div\n class=\"kt-field-box\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n [attr.data-pending]=\"pending() ? '' : null\"\n >\n @if (icon(); as icon) {\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">{{ icon }}</span>\n }\n\n @if (prefix(); as prefix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(prefix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(prefix) }}\n }\n </span>\n }\n\n <input\n #input\n ktFieldControl\n class=\"kt-field-box__input\"\n type=\"month\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.aria-busy]=\"pending() ? 'true' : null\"\n [attr.name]=\"name() || null\"\n [attr.placeholder]=\"placeholder()\"\n [attr.min]=\"serializedMin()\"\n [attr.max]=\"serializedMax()\"\n [attr.list]=\"hasSuggestions() ? datalistId : null\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeyDown($event)\"\n (blur)=\"touched.set(true)\"\n />\n\n @if (hasSuggestions()) {\n <datalist [id]=\"datalistId\">\n @for (option of datalistOptions(); track $index) {\n <option [value]=\"option.value\" [attr.label]=\"option.label\"></option>\n }\n </datalist>\n }\n\n @if (showClear()) {\n <button type=\"button\" class=\"kt-field-box__clear\" [attr.aria-label]=\"clearLabel()\" (click)=\"clear()\">\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n @if (suffix(); as suffix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(suffix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(suffix) }}\n }\n </span>\n }\n </div>\n</kt-field>\n", dependencies: [{ kind: "component", type: KtField, selector: "kt-field", inputs: ["label", "hint", "helpText", "helpLabel", "customDescribedBy", "errors", "invalid", "required", "fieldId", "hideHintWhenInvalid", "showAllErrors", "appearance", "floatLabel"], outputs: ["helpClick"] }, { kind: "directive", type: KtFieldControl, selector: "[ktFieldControl]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3251
3509
  }
3252
3510
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtYearMonthField, decorators: [{
3253
3511
  type: Component,
3254
- args: [{ selector: 'kt-year-month-field', imports: [KtField, KtFieldControl, NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"errors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div\n class=\"kt-field-box\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n >\n @if (icon(); as icon) {\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">{{ icon }}</span>\n }\n\n @if (prefix(); as prefix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(prefix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(prefix) }}\n }\n </span>\n }\n\n <input\n #input\n ktFieldControl\n class=\"kt-field-box__input\"\n type=\"month\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.name]=\"name() || null\"\n [attr.placeholder]=\"placeholder()\"\n [attr.min]=\"serializedMin()\"\n [attr.max]=\"serializedMax()\"\n [attr.list]=\"hasSuggestions() ? datalistId : null\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeyDown($event)\"\n (blur)=\"touched.set(true)\"\n />\n\n @if (hasSuggestions()) {\n <datalist [id]=\"datalistId\">\n @for (option of datalistOptions(); track $index) {\n <option [value]=\"option.value\" [attr.label]=\"option.label\"></option>\n }\n </datalist>\n }\n\n @if (showClear()) {\n <button type=\"button\" class=\"kt-field-box__clear\" [attr.aria-label]=\"clearLabel()\" (click)=\"clear()\">\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n @if (suffix(); as suffix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(suffix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(suffix) }}\n }\n </span>\n }\n </div>\n</kt-field>\n" }]
3512
+ args: [{ selector: 'kt-year-month-field', imports: [KtField, KtFieldControl, NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"displayErrors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div\n class=\"kt-field-box\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n [attr.data-pending]=\"pending() ? '' : null\"\n >\n @if (icon(); as icon) {\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">{{ icon }}</span>\n }\n\n @if (prefix(); as prefix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(prefix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(prefix) }}\n }\n </span>\n }\n\n <input\n #input\n ktFieldControl\n class=\"kt-field-box__input\"\n type=\"month\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.aria-busy]=\"pending() ? 'true' : null\"\n [attr.name]=\"name() || null\"\n [attr.placeholder]=\"placeholder()\"\n [attr.min]=\"serializedMin()\"\n [attr.max]=\"serializedMax()\"\n [attr.list]=\"hasSuggestions() ? datalistId : null\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeyDown($event)\"\n (blur)=\"touched.set(true)\"\n />\n\n @if (hasSuggestions()) {\n <datalist [id]=\"datalistId\">\n @for (option of datalistOptions(); track $index) {\n <option [value]=\"option.value\" [attr.label]=\"option.label\"></option>\n }\n </datalist>\n }\n\n @if (showClear()) {\n <button type=\"button\" class=\"kt-field-box__clear\" [attr.aria-label]=\"clearLabel()\" (click)=\"clear()\">\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n @if (suffix(); as suffix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(suffix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(suffix) }}\n }\n </span>\n }\n </div>\n</kt-field>\n" }]
3255
3513
  }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }] } });
3256
3514
 
3257
3515
  /** Source unique de l'heure courante et du **fuseau local** de l'utilisateur.
@@ -3349,11 +3607,11 @@ class KtInstantField extends KtBaseTimeTemporalField {
3349
3607
  .toString({ smallestUnit: this.precision() });
3350
3608
  }
3351
3609
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtInstantField, deps: null, target: i0.ɵɵFactoryTarget.Component });
3352
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: KtInstantField, isStandalone: true, selector: "kt-instant-field", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, usesInheritance: true, ngImport: i0, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"errors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div\n class=\"kt-field-box\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n >\n @if (icon(); as icon) {\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">{{ icon }}</span>\n }\n\n @if (prefix(); as prefix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(prefix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(prefix) }}\n }\n </span>\n }\n\n <input\n #input\n ktFieldControl\n class=\"kt-field-box__input\"\n type=\"datetime-local\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.name]=\"name() || null\"\n [attr.placeholder]=\"placeholder()\"\n [attr.min]=\"serializedMin()\"\n [attr.max]=\"serializedMax()\"\n [attr.step]=\"step()\"\n [attr.list]=\"hasSuggestions() ? datalistId : null\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeyDown($event)\"\n (blur)=\"touched.set(true)\"\n />\n\n @if (hasSuggestions()) {\n <datalist [id]=\"datalistId\">\n @for (option of datalistOptions(); track $index) {\n <option [value]=\"option.value\" [attr.label]=\"option.label\"></option>\n }\n </datalist>\n }\n\n @if (showClear()) {\n <button type=\"button\" class=\"kt-field-box__clear\" [attr.aria-label]=\"clearLabel()\" (click)=\"clear()\">\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n @if (suffix(); as suffix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(suffix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(suffix) }}\n }\n </span>\n }\n </div>\n</kt-field>\n", dependencies: [{ kind: "component", type: KtField, selector: "kt-field", inputs: ["label", "hint", "helpText", "helpLabel", "customDescribedBy", "errors", "invalid", "required", "fieldId", "hideHintWhenInvalid", "showAllErrors", "appearance", "floatLabel"], outputs: ["helpClick"] }, { kind: "directive", type: KtFieldControl, selector: "[ktFieldControl]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3610
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: KtInstantField, isStandalone: true, selector: "kt-instant-field", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, usesInheritance: true, ngImport: i0, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"displayErrors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div\n class=\"kt-field-box\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n [attr.data-pending]=\"pending() ? '' : null\"\n >\n @if (icon(); as icon) {\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">{{ icon }}</span>\n }\n\n @if (prefix(); as prefix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(prefix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(prefix) }}\n }\n </span>\n }\n\n <input\n #input\n ktFieldControl\n class=\"kt-field-box__input\"\n type=\"datetime-local\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.aria-busy]=\"pending() ? 'true' : null\"\n [attr.name]=\"name() || null\"\n [attr.placeholder]=\"placeholder()\"\n [attr.min]=\"serializedMin()\"\n [attr.max]=\"serializedMax()\"\n [attr.step]=\"step()\"\n [attr.list]=\"hasSuggestions() ? datalistId : null\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeyDown($event)\"\n (blur)=\"touched.set(true)\"\n />\n\n @if (hasSuggestions()) {\n <datalist [id]=\"datalistId\">\n @for (option of datalistOptions(); track $index) {\n <option [value]=\"option.value\" [attr.label]=\"option.label\"></option>\n }\n </datalist>\n }\n\n @if (showClear()) {\n <button type=\"button\" class=\"kt-field-box__clear\" [attr.aria-label]=\"clearLabel()\" (click)=\"clear()\">\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n @if (suffix(); as suffix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(suffix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(suffix) }}\n }\n </span>\n }\n </div>\n</kt-field>\n", dependencies: [{ kind: "component", type: KtField, selector: "kt-field", inputs: ["label", "hint", "helpText", "helpLabel", "customDescribedBy", "errors", "invalid", "required", "fieldId", "hideHintWhenInvalid", "showAllErrors", "appearance", "floatLabel"], outputs: ["helpClick"] }, { kind: "directive", type: KtFieldControl, selector: "[ktFieldControl]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3353
3611
  }
3354
3612
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtInstantField, decorators: [{
3355
3613
  type: Component,
3356
- args: [{ selector: 'kt-instant-field', imports: [KtField, KtFieldControl, NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"errors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div\n class=\"kt-field-box\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n >\n @if (icon(); as icon) {\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">{{ icon }}</span>\n }\n\n @if (prefix(); as prefix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(prefix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(prefix) }}\n }\n </span>\n }\n\n <input\n #input\n ktFieldControl\n class=\"kt-field-box__input\"\n type=\"datetime-local\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.name]=\"name() || null\"\n [attr.placeholder]=\"placeholder()\"\n [attr.min]=\"serializedMin()\"\n [attr.max]=\"serializedMax()\"\n [attr.step]=\"step()\"\n [attr.list]=\"hasSuggestions() ? datalistId : null\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeyDown($event)\"\n (blur)=\"touched.set(true)\"\n />\n\n @if (hasSuggestions()) {\n <datalist [id]=\"datalistId\">\n @for (option of datalistOptions(); track $index) {\n <option [value]=\"option.value\" [attr.label]=\"option.label\"></option>\n }\n </datalist>\n }\n\n @if (showClear()) {\n <button type=\"button\" class=\"kt-field-box__clear\" [attr.aria-label]=\"clearLabel()\" (click)=\"clear()\">\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n @if (suffix(); as suffix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(suffix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(suffix) }}\n }\n </span>\n }\n </div>\n</kt-field>\n" }]
3614
+ args: [{ selector: 'kt-instant-field', imports: [KtField, KtFieldControl, NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "<kt-field\n [label]=\"label()\"\n [hint]=\"hint()\"\n [helpText]=\"helpText()\"\n [helpLabel]=\"helpLabel()\"\n [customDescribedBy]=\"customDescribedBy()\"\n [errors]=\"displayErrors()\"\n [invalid]=\"showInvalid()\"\n [required]=\"required()\"\n [fieldId]=\"id()\"\n [appearance]=\"appearance()\"\n [floatLabel]=\"floatLabel()\"\n (helpClick)=\"helpClick.emit($event)\"\n>\n <ng-content select=\"[ktFieldHelp]\" />\n <div\n class=\"kt-field-box\"\n [attr.data-invalid]=\"showInvalid() ? '' : null\"\n [attr.data-disabled]=\"disabled() ? '' : null\"\n [attr.data-pending]=\"pending() ? '' : null\"\n >\n @if (icon(); as icon) {\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">{{ icon }}</span>\n }\n\n @if (prefix(); as prefix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(prefix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(prefix) }}\n }\n </span>\n }\n\n <input\n #input\n ktFieldControl\n class=\"kt-field-box__input\"\n type=\"datetime-local\"\n [disabled]=\"disabled()\"\n [readOnly]=\"readonly()\"\n [attr.aria-busy]=\"pending() ? 'true' : null\"\n [attr.name]=\"name() || null\"\n [attr.placeholder]=\"placeholder()\"\n [attr.min]=\"serializedMin()\"\n [attr.max]=\"serializedMax()\"\n [attr.step]=\"step()\"\n [attr.list]=\"hasSuggestions() ? datalistId : null\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeyDown($event)\"\n (blur)=\"touched.set(true)\"\n />\n\n @if (hasSuggestions()) {\n <datalist [id]=\"datalistId\">\n @for (option of datalistOptions(); track $index) {\n <option [value]=\"option.value\" [attr.label]=\"option.label\"></option>\n }\n </datalist>\n }\n\n @if (showClear()) {\n <button type=\"button\" class=\"kt-field-box__clear\" [attr.aria-label]=\"clearLabel()\" (click)=\"clear()\">\n <span class=\"kt-field-box__icon\" aria-hidden=\"true\">close</span>\n </button>\n }\n\n @if (suffix(); as suffix) {\n <span class=\"kt-field-box__affix\">\n @if (asTemplate(suffix); as tpl) {\n <ng-container [ngTemplateOutlet]=\"tpl\" />\n } @else {\n {{ asText(suffix) }}\n }\n </span>\n }\n </div>\n</kt-field>\n" }]
3357
3615
  }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }] } });
3358
3616
 
3359
3617
  /** Formate une valeur Temporal pour l'affichage selon la locale active.
@@ -3376,6 +3634,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
3376
3634
  // Exception R1 ASSUMÉE : le name `temporalDate` (non préfixé `kt`) relève du domaine Temporal,
3377
3635
  // exempté de préfixe au même titre que le namespace `Temporal` et ses alias de types. La CLASSE
3378
3636
  // reste préfixée (`KtTemporalDatePipe`). Choix ergonomique acté (ADR-4).
3637
+ // Stryker disable next-line all: le `name` du pipe doit rester statiquement analysable par l'AOT (NG1010).
3379
3638
  class KtTemporalDatePipe {
3380
3639
  locale = inject(LOCALE_ID);
3381
3640
  clock = inject(KtClock);
@@ -3406,5 +3665,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
3406
3665
  * Generated bundle index. Do not edit.
3407
3666
  */
3408
3667
 
3409
- export { DEFAULT_KT_SELECT_CONFIG, KT_CHIPS_CONFIG, KT_FIELD, KT_FIELD_CONFIG, KT_SELECT_CONFIG, KtBaseInputField, KtBaseSelect, KtBaseTemporalField, KtBaseTimeTemporalField, KtCheckbox, KtCheckboxGroup, KtChip, KtChipItemDef, KtChipList, KtClock, KtDateField, KtDateTimeField, KtField, KtFieldControl, KtFixedClock, KtInstantField, KtMultiSelect, KtMultiSelectChipDef, KtMultiSelectOptionDef, KtMultiSelectTriggerDef, KtNumberField, KtRadio, KtRadioGroup, KtSelect, KtSelectConfig, KtSelectOptionDef, KtSelectTriggerDef, KtSwitch, KtTemporalDatePipe, KtTextArea, KtTextField, KtTimeField, KtYearMonthField, Temporal, defaultKtFieldErrorMatcher, normalizeKtSuggestions, provideKtField };
3668
+ export { DEFAULT_KT_SELECT_CONFIG, KT_CHIPS_CONFIG, KT_DEFAULT_FIELD_ERROR_MESSAGES, KT_FIELD, KT_FIELD_CONFIG, KT_SELECT_CONFIG, KtBaseInputField, KtBaseSelect, KtBaseTemporalField, KtBaseTimeTemporalField, KtCheckbox, KtCheckboxGroup, KtChip, KtChipItemDef, KtChipList, KtClock, KtDateField, KtDateTimeField, KtField, KtFieldControl, KtFieldErrorResolver, KtFixedClock, KtInstantField, KtMultiSelect, KtMultiSelectChipDef, KtMultiSelectOptionDef, KtMultiSelectTriggerDef, KtNumberField, KtRadio, KtRadioGroup, KtSelect, KtSelectConfig, KtSelectOptionDef, KtSelectTriggerDef, KtSwitch, KtTemporalDatePipe, KtTextArea, KtTextField, KtTimeField, KtYearMonthField, Temporal, defaultKtFieldErrorMatcher, ktErrorParam, normalizeKtSuggestions, provideKtField };
3410
3669
  //# sourceMappingURL=ktortu-aaa-forms.mjs.map