@ktortu/aaa 0.1.0-beta.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -7
- package/cdk/styles/tabs.css +100 -21
- package/fesm2022/ktortu-aaa-button.mjs +18 -11
- package/fesm2022/ktortu-aaa-button.mjs.map +1 -1
- package/fesm2022/ktortu-aaa-card.mjs +29 -4
- package/fesm2022/ktortu-aaa-card.mjs.map +1 -1
- package/fesm2022/ktortu-aaa-cdk.mjs +58 -15
- package/fesm2022/ktortu-aaa-cdk.mjs.map +1 -1
- package/fesm2022/ktortu-aaa-dialog.mjs +69 -12
- package/fesm2022/ktortu-aaa-dialog.mjs.map +1 -1
- package/fesm2022/ktortu-aaa-forms.mjs +455 -260
- package/fesm2022/ktortu-aaa-forms.mjs.map +1 -1
- package/fesm2022/ktortu-aaa-i18n.mjs +114 -0
- package/fesm2022/ktortu-aaa-i18n.mjs.map +1 -0
- package/fesm2022/ktortu-aaa-menu.mjs +38 -13
- package/fesm2022/ktortu-aaa-menu.mjs.map +1 -1
- package/fesm2022/ktortu-aaa-tabs.mjs +319 -42
- package/fesm2022/ktortu-aaa-tabs.mjs.map +1 -1
- package/fesm2022/ktortu-aaa-tooltip.mjs +3 -2
- package/fesm2022/ktortu-aaa-tooltip.mjs.map +1 -1
- package/fesm2022/ktortu-aaa.mjs +1 -0
- package/fesm2022/ktortu-aaa.mjs.map +1 -1
- package/forms/radio/radio-group.css +3 -3
- package/forms/styles/field-box.css +150 -2
- package/forms/styles/tokens.css +3 -0
- package/menu/menu.css +8 -4
- package/package.json +5 -1
- package/types/ktortu-aaa-button.d.ts +22 -8
- package/types/ktortu-aaa-card.d.ts +24 -4
- package/types/ktortu-aaa-cdk.d.ts +38 -0
- package/types/ktortu-aaa-dialog.d.ts +45 -9
- package/types/ktortu-aaa-forms.d.ts +336 -149
- package/types/ktortu-aaa-i18n.d.ts +74 -0
- package/types/ktortu-aaa-menu.d.ts +15 -8
- package/types/ktortu-aaa-tabs.d.ts +130 -13
- package/types/ktortu-aaa-tooltip.d.ts +5 -0
- package/types/ktortu-aaa.d.ts +1 -0
|
@@ -1,19 +1,40 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, inject, computed, ElementRef, Directive, input, output, contentChild, viewChild, forwardRef, ChangeDetectionStrategy, Component, model,
|
|
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';
|
|
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';
|
|
6
6
|
import { transformedValue } from '@angular/forms/signals';
|
|
7
|
-
import { Combobox, ComboboxPopup, ComboboxWidget } from '@angular/aria/combobox';
|
|
8
7
|
import { Listbox, Option } from '@angular/aria/listbox';
|
|
8
|
+
import { Combobox, ComboboxPopup, ComboboxWidget } from '@angular/aria/combobox';
|
|
9
9
|
|
|
10
10
|
/** Défaut : afficher l'erreur une fois le champ quitté (blur). */
|
|
11
11
|
const defaultKtFieldErrorMatcher = (state) => state.invalid && state.touched;
|
|
12
12
|
const KT_FIELD_CONFIG = new InjectionToken('KT_FIELD_CONFIG');
|
|
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.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* // app.config.ts
|
|
21
|
+
* providers: [provideKtField({ appearance: 'outline' })]
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
function provideKtField(config) {
|
|
25
|
+
return { provide: KT_FIELD_CONFIG, useValue: config };
|
|
26
|
+
}
|
|
13
27
|
const KT_FIELD = new InjectionToken('KT_FIELD');
|
|
14
28
|
|
|
15
29
|
/** Marque le contrôle (natif ou custom) d'un champ pour que `Field` y câble l'a11y
|
|
16
|
-
(id, aria-describedby, aria-invalid, aria-required).
|
|
30
|
+
(id, aria-describedby, aria-invalid, aria-required).
|
|
31
|
+
|
|
32
|
+
@example
|
|
33
|
+
```html
|
|
34
|
+
<kt-field label="E-mail" [invalid]="invalid()" [errors]="errors()">
|
|
35
|
+
<input ktFieldControl type="email" [(ngModel)]="email" />
|
|
36
|
+
</kt-field>
|
|
37
|
+
``` */
|
|
17
38
|
class KtFieldControl {
|
|
18
39
|
parent = inject(KT_FIELD, { optional: true });
|
|
19
40
|
id = computed(() => this.parent?.baseId() ?? null, /* @ts-ignore */
|
|
@@ -24,6 +45,7 @@ class KtFieldControl {
|
|
|
24
45
|
...(ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []));
|
|
25
46
|
required = computed(() => this.parent?.required() ?? false, /* @ts-ignore */
|
|
26
47
|
...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
|
|
48
|
+
/** Élément DOM hôte du contrôle (exposé pour le focus / la mesure par le parent). */
|
|
27
49
|
element = inject(ElementRef).nativeElement;
|
|
28
50
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtFieldControl, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
29
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 });
|
|
@@ -73,20 +95,30 @@ class KtField {
|
|
|
73
95
|
errors = input([], /* @ts-ignore */
|
|
74
96
|
...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
|
|
75
97
|
/** Marque le champ comme invalide (pose `aria-invalid` et conditionne l'affichage des erreurs). @default false */
|
|
76
|
-
invalid = input(false, /*
|
|
77
|
-
...(ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []));
|
|
98
|
+
invalid = input(false, { ...(ngDevMode ? { debugName: "invalid" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
78
99
|
/** Affiche l'astérisque requis et pose `aria-required` sur le contrôle. @default false */
|
|
79
|
-
required = input(false, /*
|
|
80
|
-
|
|
81
|
-
/** id imposé (sélecteurs de test stables) ; sinon auto-généré, anti-collision. */
|
|
100
|
+
required = input(false, { ...(ngDevMode ? { debugName: "required" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
101
|
+
/** id imposé (sélecteurs de test stables) ; sinon auto-généré, anti-collision. @default undefined */
|
|
82
102
|
fieldId = input(/* @ts-ignore */
|
|
83
103
|
...(ngDevMode ? [undefined, { debugName: "fieldId" }] : /* istanbul ignore next */ []));
|
|
84
|
-
/** Masquer le hint quand l'erreur s'affiche (façon Material). */
|
|
85
|
-
hideHintWhenInvalid = input(this.config?.hideHintWhenInvalid ?? false, /*
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
104
|
+
/** Masquer le hint quand l'erreur s'affiche (façon Material). @default KT_FIELD_CONFIG.hideHintWhenInvalid ?? false */
|
|
105
|
+
hideHintWhenInvalid = input(this.config?.hideHintWhenInvalid ?? false, { ...(ngDevMode ? { debugName: "hideHintWhenInvalid" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
106
|
+
/** Afficher toutes les erreurs au lieu de la première seule. @default KT_FIELD_CONFIG.showAllErrors ?? false */
|
|
107
|
+
showAllErrors = input(this.config?.showAllErrors ?? false, { ...(ngDevMode ? { debugName: "showAllErrors" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
108
|
+
/** Apparence du chrome : `fill` (label au-dessus) ou `outline` (bordure + label flottant, façon
|
|
109
|
+
Material). Non fournie ⇒ valeur du `KT_FIELD_CONFIG`, sinon `'fill'`. @default undefined */
|
|
110
|
+
appearance = input(/* @ts-ignore */
|
|
111
|
+
...(ngDevMode ? [undefined, { debugName: "appearance" }] : /* istanbul ignore next */ []));
|
|
112
|
+
/** Apparence effective : input ?? KT_FIELD_CONFIG.appearance ?? 'fill'. */
|
|
113
|
+
resolvedAppearance = computed(() => this.appearance() ?? this.config?.appearance ?? 'fill', /* @ts-ignore */
|
|
114
|
+
...(ngDevMode ? [{ debugName: "resolvedAppearance" }] : /* istanbul ignore next */ []));
|
|
115
|
+
/** Politique du label flottant (outline) : `auto` (flotte au focus/rempli) ou `always` (toujours
|
|
116
|
+
flotté, même vide). Non fournie ⇒ valeur du `KT_FIELD_CONFIG`, sinon `'auto'`. @default undefined */
|
|
117
|
+
floatLabel = input(/* @ts-ignore */
|
|
118
|
+
...(ngDevMode ? [undefined, { debugName: "floatLabel" }] : /* istanbul ignore next */ []));
|
|
119
|
+
/** Politique effective : input ?? KT_FIELD_CONFIG.floatLabel ?? 'auto'. */
|
|
120
|
+
resolvedFloatLabel = computed(() => this.floatLabel() ?? this.config?.floatLabel ?? 'auto', /* @ts-ignore */
|
|
121
|
+
...(ngDevMode ? [{ debugName: "resolvedFloatLabel" }] : /* istanbul ignore next */ []));
|
|
90
122
|
// Le contrôle est projeté : l'injection DI ne le traverse pas, on le cible via contentChild.
|
|
91
123
|
control = contentChild(KtFieldControl, /* @ts-ignore */
|
|
92
124
|
...(ngDevMode ? [{ debugName: "control" }] : /* istanbul ignore next */ []));
|
|
@@ -99,7 +131,7 @@ class KtField {
|
|
|
99
131
|
activeTooltip = computed(() => this.projectedTooltip() ?? this.templateTooltip(), /* @ts-ignore */
|
|
100
132
|
...(ngDevMode ? [{ debugName: "activeTooltip" }] : /* istanbul ignore next */ []));
|
|
101
133
|
idGen = inject(KtIdGenerator);
|
|
102
|
-
uid = this.idGen.generateId();
|
|
134
|
+
uid = this.idGen.generateId('field');
|
|
103
135
|
baseId = computed(() => this.fieldId() ?? `kt-field-${this.uid}`, /* @ts-ignore */
|
|
104
136
|
...(ngDevMode ? [{ debugName: "baseId" }] : /* istanbul ignore next */ []));
|
|
105
137
|
labelId = computed(() => `${this.baseId()}-label`, /* @ts-ignore */
|
|
@@ -140,16 +172,31 @@ class KtField {
|
|
|
140
172
|
this.helpClick.emit(event);
|
|
141
173
|
}
|
|
142
174
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtField, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
143
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: KtField, isStandalone: true, selector: "kt-field", inputs: { 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 }, errors: { classPropertyName: "errors", publicName: "errors", 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 }, fieldId: { classPropertyName: "fieldId", publicName: "fieldId", isSignal: true, isRequired: false, transformFunction: null }, hideHintWhenInvalid: { classPropertyName: "hideHintWhenInvalid", publicName: "hideHintWhenInvalid", isSignal: true, isRequired: false, transformFunction: null }, showAllErrors: { classPropertyName: "showAllErrors", publicName: "showAllErrors", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { helpClick: "helpClick" }, providers: [{ provide: KT_FIELD, useExisting: forwardRef(() => KtField) }], queries: [{ propertyName: "control", first: true, predicate: KtFieldControl, descendants: true, isSignal: true }, { propertyName: "projectedTooltip", first: true, predicate: KtTooltip, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "templateTooltip", first: true, predicate: KtTooltip, descendants: true, isSignal: true }], ngImport: i0, 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"], dependencies: [{ kind: "directive", type: KtTooltip, selector: "[ktTooltip]", inputs: ["ktTooltip", "tooltipPosition", "tooltipDisabled", "showDelay", "hideDelay"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
175
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: KtField, isStandalone: true, selector: "kt-field", inputs: { 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 }, errors: { classPropertyName: "errors", publicName: "errors", 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 }, fieldId: { classPropertyName: "fieldId", publicName: "fieldId", isSignal: true, isRequired: false, transformFunction: null }, hideHintWhenInvalid: { classPropertyName: "hideHintWhenInvalid", publicName: "hideHintWhenInvalid", isSignal: true, isRequired: false, transformFunction: null }, showAllErrors: { classPropertyName: "showAllErrors", publicName: "showAllErrors", 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: { helpClick: "helpClick" }, host: { properties: { "attr.data-appearance": "resolvedAppearance()", "attr.data-float-label": "resolvedFloatLabel()" } }, providers: [{ provide: KT_FIELD, useExisting: forwardRef(() => KtField) }], queries: [{ propertyName: "control", first: true, predicate: KtFieldControl, descendants: true, isSignal: true }, { propertyName: "projectedTooltip", first: true, predicate: KtTooltip, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "templateTooltip", first: true, predicate: KtTooltip, descendants: true, isSignal: true }], ngImport: i0, 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"], dependencies: [{ kind: "directive", type: KtTooltip, selector: "[ktTooltip]", inputs: ["ktTooltip", "tooltipPosition", "tooltipDisabled", "showDelay", "hideDelay"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
144
176
|
}
|
|
145
177
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtField, decorators: [{
|
|
146
178
|
type: Component,
|
|
147
|
-
args: [{ selector: 'kt-field', imports: [KtTooltip], changeDetection: ChangeDetectionStrategy.OnPush,
|
|
148
|
-
|
|
179
|
+
args: [{ selector: 'kt-field', imports: [KtTooltip], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
180
|
+
'[attr.data-appearance]': 'resolvedAppearance()',
|
|
181
|
+
'[attr.data-float-label]': 'resolvedFloatLabel()',
|
|
182
|
+
}, 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
|
+
}], 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 }] }] } });
|
|
149
184
|
|
|
150
185
|
/** Base partagée des champs simples (TextField, NumberField) : état FormValueControl,
|
|
151
186
|
présentation (label/hint/prefix/suffix/clear) et politique d'affichage des erreurs.
|
|
152
|
-
La valeur, son parsing et la notion de « vide » sont fournis par la sous-classe.
|
|
187
|
+
La valeur, son parsing et la notion de « vide » sont fournis par la sous-classe.
|
|
188
|
+
|
|
189
|
+
@example
|
|
190
|
+
```ts
|
|
191
|
+
// Sous-classement : on fournit value (model concret) + parse/emptyValue/isEmpty.
|
|
192
|
+
@Component({ selector: 'kt-text-field', templateUrl: './text-field.html' })
|
|
193
|
+
export class KtTextField extends KtBaseInputField<string> implements FormValueControl<string> {
|
|
194
|
+
readonly value = model<string>('');
|
|
195
|
+
protected parse(raw: string): string { return raw; }
|
|
196
|
+
protected emptyValue(): string { return ''; }
|
|
197
|
+
protected isEmpty(value: string): boolean { return value.length === 0; }
|
|
198
|
+
}
|
|
199
|
+
``` */
|
|
153
200
|
class KtBaseInputField {
|
|
154
201
|
config = inject(KT_FIELD_CONFIG, { optional: true });
|
|
155
202
|
// --- État poussé par [formField] ---
|
|
@@ -159,20 +206,15 @@ class KtBaseInputField {
|
|
|
159
206
|
touched = model(false, /* @ts-ignore */
|
|
160
207
|
...(ngDevMode ? [{ debugName: "touched" }] : /* istanbul ignore next */ []));
|
|
161
208
|
/** Désactive la saisie et le focus. @default false */
|
|
162
|
-
disabled = input(false, /*
|
|
163
|
-
...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
|
|
209
|
+
disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
164
210
|
/** Rend le champ en lecture seule (valeur visible, non modifiable). @default false */
|
|
165
|
-
readonly = input(false, /*
|
|
166
|
-
...(ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []));
|
|
211
|
+
readonly = input(false, { ...(ngDevMode ? { debugName: "readonly" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
167
212
|
/** Le champ est-il en erreur (état fourni par la validation). @default false */
|
|
168
|
-
invalid = input(false, /*
|
|
169
|
-
...(ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []));
|
|
213
|
+
invalid = input(false, { ...(ngDevMode ? { debugName: "invalid" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
170
214
|
/** Marque le champ comme requis (ajoute `aria-required`). @default false */
|
|
171
|
-
required = input(false, /*
|
|
172
|
-
...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
|
|
215
|
+
required = input(false, { ...(ngDevMode ? { debugName: "required" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
173
216
|
/** Le champ a-t-il été modifié depuis sa valeur initiale. @default false */
|
|
174
|
-
dirty = input(false, /*
|
|
175
|
-
...(ngDevMode ? [{ debugName: "dirty" }] : /* istanbul ignore next */ []));
|
|
217
|
+
dirty = input(false, { ...(ngDevMode ? { debugName: "dirty" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
176
218
|
/** Liste des erreurs de validation à afficher. @default [] */
|
|
177
219
|
errors = input([], /* @ts-ignore */
|
|
178
220
|
...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
|
|
@@ -180,27 +222,27 @@ class KtBaseInputField {
|
|
|
180
222
|
name = input('', /* @ts-ignore */
|
|
181
223
|
...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
|
|
182
224
|
// --- Présentation ---
|
|
183
|
-
/** id imposé pour des sélecteurs de test stables ; sinon auto-généré par Field. */
|
|
225
|
+
/** id imposé pour des sélecteurs de test stables ; sinon auto-généré par Field. @default undefined */
|
|
184
226
|
id = input(/* @ts-ignore */
|
|
185
227
|
...(ngDevMode ? [undefined, { debugName: "id" }] : /* istanbul ignore next */ []));
|
|
186
|
-
/** Libellé du champ (associé via `<label for>`). */
|
|
228
|
+
/** Libellé du champ (associé via `<label for>`). @default undefined */
|
|
187
229
|
label = input(/* @ts-ignore */
|
|
188
230
|
...(ngDevMode ? [undefined, { debugName: "label" }] : /* istanbul ignore next */ []));
|
|
189
|
-
/** Texte d'aide affiché sous le champ quand il est valide. */
|
|
231
|
+
/** Texte d'aide affiché sous le champ quand il est valide. @default undefined */
|
|
190
232
|
hint = input(/* @ts-ignore */
|
|
191
233
|
...(ngDevMode ? [undefined, { debugName: "hint" }] : /* istanbul ignore next */ []));
|
|
192
|
-
/** Aide contextuelle riche : texte ou `TemplateRef` projeté dans une infobulle d'aide. */
|
|
234
|
+
/** Aide contextuelle riche : texte ou `TemplateRef` projeté dans une infobulle d'aide. @default undefined */
|
|
193
235
|
helpText = input(/* @ts-ignore */
|
|
194
236
|
...(ngDevMode ? [undefined, { debugName: "helpText" }] : /* istanbul ignore next */ []));
|
|
195
237
|
/** Libellé accessible du bouton d'aide. @default 'Help' (ou KT_FIELD_CONFIG.helpLabel) */
|
|
196
238
|
helpLabel = input(this.config?.helpLabel ?? 'Help', /* @ts-ignore */
|
|
197
239
|
...(ngDevMode ? [{ debugName: "helpLabel" }] : /* istanbul ignore next */ []));
|
|
198
|
-
/** Force la valeur de `aria-describedby` (sinon dérivée de hint/erreur). */
|
|
240
|
+
/** Force la valeur de `aria-describedby` (sinon dérivée de hint/erreur). @default undefined */
|
|
199
241
|
customDescribedBy = input(/* @ts-ignore */
|
|
200
242
|
...(ngDevMode ? [undefined, { debugName: "customDescribedBy" }] : /* istanbul ignore next */ []));
|
|
201
243
|
/** Émis au clic sur le bouton d'aide contextuelle. */
|
|
202
244
|
helpClick = output();
|
|
203
|
-
/** Texte indicatif affiché dans le champ vide. */
|
|
245
|
+
/** Texte indicatif affiché dans le champ vide. @default undefined */
|
|
204
246
|
placeholder = input(/* @ts-ignore */
|
|
205
247
|
...(ngDevMode ? [undefined, { debugName: "placeholder" }] : /* istanbul ignore next */ []));
|
|
206
248
|
/** Indice d'autoremplissage du navigateur (attribut `autocomplete` natif) ; ex. `'current-password'`,
|
|
@@ -208,23 +250,31 @@ class KtBaseInputField {
|
|
|
208
250
|
@default undefined */
|
|
209
251
|
autocomplete = input(/* @ts-ignore */
|
|
210
252
|
...(ngDevMode ? [undefined, { debugName: "autocomplete" }] : /* istanbul ignore next */ []));
|
|
211
|
-
/** Nom d'icône Material Symbols affichée en tête de champ. */
|
|
253
|
+
/** Nom d'icône Material Symbols affichée en tête de champ. @default undefined */
|
|
212
254
|
icon = input(/* @ts-ignore */
|
|
213
255
|
...(ngDevMode ? [undefined, { debugName: "icon" }] : /* istanbul ignore next */ []));
|
|
214
256
|
/** Affiche un bouton « effacer » quand le champ contient une valeur. @default false */
|
|
215
257
|
clearable = input(false, { ...(ngDevMode ? { debugName: "clearable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
216
|
-
/** Contenu décoratif en tête de champ : texte ou `TemplateRef`. */
|
|
258
|
+
/** Contenu décoratif en tête de champ : texte ou `TemplateRef`. @default undefined */
|
|
217
259
|
prefix = input(/* @ts-ignore */
|
|
218
260
|
...(ngDevMode ? [undefined, { debugName: "prefix" }] : /* istanbul ignore next */ []));
|
|
219
|
-
/** Contenu décoratif en fin de champ : texte ou `TemplateRef`. */
|
|
261
|
+
/** Contenu décoratif en fin de champ : texte ou `TemplateRef`. @default undefined */
|
|
220
262
|
suffix = input(/* @ts-ignore */
|
|
221
263
|
...(ngDevMode ? [undefined, { debugName: "suffix" }] : /* istanbul ignore next */ []));
|
|
222
264
|
/** Libellé i18n du bouton « effacer ». @default 'Clear' (ou KT_FIELD_CONFIG.clearLabel) */
|
|
223
265
|
clearLabel = input(this.config?.clearLabel ?? 'Clear', /* @ts-ignore */
|
|
224
266
|
...(ngDevMode ? [{ debugName: "clearLabel" }] : /* istanbul ignore next */ []));
|
|
225
|
-
/** Quand afficher l'erreur ; surcharge KT_FIELD_CONFIG et le défaut (`invalid && touched`). */
|
|
267
|
+
/** Quand afficher l'erreur ; surcharge KT_FIELD_CONFIG et le défaut (`invalid && touched`). @default undefined */
|
|
226
268
|
errorMatcher = input(/* @ts-ignore */
|
|
227
269
|
...(ngDevMode ? [undefined, { debugName: "errorMatcher" }] : /* istanbul ignore next */ []));
|
|
270
|
+
/** Apparence du chrome (`fill` | `outline`) ; non fournie ⇒ `KT_FIELD_CONFIG.appearance` ?? `'fill'`.
|
|
271
|
+
@default undefined */
|
|
272
|
+
appearance = input(/* @ts-ignore */
|
|
273
|
+
...(ngDevMode ? [undefined, { debugName: "appearance" }] : /* istanbul ignore next */ []));
|
|
274
|
+
/** Politique du label flottant en outline (`auto` | `always`) ; non fournie ⇒ `KT_FIELD_CONFIG.floatLabel`
|
|
275
|
+
?? `'auto'`. En `always`, le label reste en haut même vide et le placeholder s'affiche. @default undefined */
|
|
276
|
+
floatLabel = input(/* @ts-ignore */
|
|
277
|
+
...(ngDevMode ? [undefined, { debugName: "floatLabel" }] : /* istanbul ignore next */ []));
|
|
228
278
|
inputRef = viewChild('input', /* @ts-ignore */
|
|
229
279
|
...(ngDevMode ? [{ debugName: "inputRef" }] : /* istanbul ignore next */ []));
|
|
230
280
|
matcher = computed(() => this.errorMatcher() ?? this.config?.errorMatcher ?? defaultKtFieldErrorMatcher, /* @ts-ignore */
|
|
@@ -234,6 +284,25 @@ class KtBaseInputField {
|
|
|
234
284
|
...(ngDevMode ? [{ debugName: "showInvalid" }] : /* istanbul ignore next */ []));
|
|
235
285
|
showClear = computed(() => this.clearable() && !this.disabled() && !this.readonly() && !this.isEmpty(this.value()), /* @ts-ignore */
|
|
236
286
|
...(ngDevMode ? [{ debugName: "showClear" }] : /* istanbul ignore next */ []));
|
|
287
|
+
/** Apparence effective (input ?? config ?? 'fill'). Sert aux templates : forward à `kt-field` et,
|
|
288
|
+
en outline, pose une sentinelle de placeholder pour la détection « rempli » du label flottant. */
|
|
289
|
+
outline = computed(() => (this.appearance() ?? this.config?.appearance ?? 'fill') === 'outline', /* @ts-ignore */
|
|
290
|
+
...(ngDevMode ? [{ debugName: "outline" }] : /* istanbul ignore next */ []));
|
|
291
|
+
/** Label toujours flotté en outline (input ?? config ?? 'auto'). */
|
|
292
|
+
alwaysFloat = computed(() => (this.floatLabel() ?? this.config?.floatLabel ?? 'auto') === 'always', /* @ts-ignore */
|
|
293
|
+
...(ngDevMode ? [{ debugName: "alwaysFloat" }] : /* istanbul ignore next */ []));
|
|
294
|
+
/** Valeur de l'attribut `placeholder` natif selon l'apparence :
|
|
295
|
+
- fill : le placeholder tel quel ;
|
|
296
|
+
- outline + always : le vrai placeholder (le label est en haut, pas de chevauchement) ;
|
|
297
|
+
- outline + auto : sentinelle `' '` (le label tient lieu de placeholder ; active `:placeholder-shown`). */
|
|
298
|
+
placeholderAttr = computed(() => {
|
|
299
|
+
if (!this.outline())
|
|
300
|
+
return this.placeholder() ?? null;
|
|
301
|
+
if (this.alwaysFloat())
|
|
302
|
+
return this.placeholder() ?? null;
|
|
303
|
+
return this.placeholder() ?? ' ';
|
|
304
|
+
}, /* @ts-ignore */
|
|
305
|
+
...(ngDevMode ? [{ debugName: "placeholderAttr" }] : /* istanbul ignore next */ []));
|
|
237
306
|
asTemplate(value) {
|
|
238
307
|
return value instanceof TemplateRef ? value : null;
|
|
239
308
|
}
|
|
@@ -255,11 +324,11 @@ class KtBaseInputField {
|
|
|
255
324
|
this.inputRef()?.nativeElement.focus();
|
|
256
325
|
}
|
|
257
326
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtBaseInputField, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
258
|
-
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 } }, outputs: { touched: "touchedChange", helpClick: "helpClick" }, viewQueries: [{ propertyName: "inputRef", first: true, predicate: ["input"], descendants: true, isSignal: true }], ngImport: i0 });
|
|
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 });
|
|
259
328
|
}
|
|
260
329
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtBaseInputField, decorators: [{
|
|
261
330
|
type: Directive
|
|
262
|
-
}], 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 }] }], inputRef: [{ type: i0.ViewChild, args: ['input', { isSignal: true }] }] } });
|
|
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 }] }] } });
|
|
263
332
|
|
|
264
333
|
/** Normalise une liste de suggestions en options `<datalist>`. `toValue` sérialise la valeur en
|
|
265
334
|
chaîne attendue par l'input natif (identité pour le texte, `String()` pour les nombres,
|
|
@@ -304,23 +373,25 @@ class KtNumberField extends KtBaseInputField {
|
|
|
304
373
|
suggestions = input(/* @ts-ignore */
|
|
305
374
|
...(ngDevMode ? [undefined, { debugName: "suggestions" }] : /* istanbul ignore next */ []));
|
|
306
375
|
idGen = inject(KtIdGenerator);
|
|
307
|
-
uid = this.idGen.generateId();
|
|
376
|
+
uid = this.idGen.generateId('number-field');
|
|
308
377
|
datalistId = `kt-number-field-list-${this.uid}`;
|
|
309
378
|
hasSuggestions = computed(() => (this.suggestions()?.length ?? 0) > 0, /* @ts-ignore */
|
|
310
379
|
...(ngDevMode ? [{ debugName: "hasSuggestions" }] : /* istanbul ignore next */ []));
|
|
311
380
|
datalistOptions = computed(() => normalizeKtSuggestions(this.suggestions(), (value) => String(value)), /* @ts-ignore */
|
|
312
381
|
...(ngDevMode ? [{ debugName: "datalistOptions" }] : /* istanbul ignore next */ []));
|
|
313
|
-
//
|
|
382
|
+
// Chemin de valeur unique : `parse()` (contrat de `KtBaseInputField`) est la SEULE source de
|
|
383
|
+
// vérité du parsing numérique ; `transformedValue` ne fait que l'envelopper pour émettre une
|
|
384
|
+
// erreur de validation Signal Forms sur une saisie non numérique (et formater pour l'affichage).
|
|
314
385
|
rawValue = transformedValue(this.value, {
|
|
315
386
|
parse: (val) => {
|
|
316
387
|
const trimmed = val.trim().replace(',', '.');
|
|
317
|
-
if (trimmed
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
388
|
+
if (trimmed !== '' && Number.isNaN(Number(trimmed))) {
|
|
389
|
+
// Défaut anglais neutre ; surchargeable via KT_FIELD_CONFIG.numberParseError (cf. provideKtDefaultFR).
|
|
390
|
+
return {
|
|
391
|
+
error: { kind: 'parse', message: this.config?.numberParseError ?? 'Please enter a valid number.' },
|
|
392
|
+
};
|
|
322
393
|
}
|
|
323
|
-
return { value:
|
|
394
|
+
return { value: this.parse(val) };
|
|
324
395
|
},
|
|
325
396
|
format: (val) => (val === null ? '' : String(val)),
|
|
326
397
|
});
|
|
@@ -385,11 +456,11 @@ class KtNumberField extends KtBaseInputField {
|
|
|
385
456
|
return value === null;
|
|
386
457
|
}
|
|
387
458
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtNumberField, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
388
|
-
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 (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]=\"
|
|
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 });
|
|
389
460
|
}
|
|
390
461
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtNumberField, decorators: [{
|
|
391
462
|
type: Component,
|
|
392
|
-
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 (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]=\"
|
|
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" }]
|
|
393
464
|
}], 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 }] }] } });
|
|
394
465
|
|
|
395
466
|
/**
|
|
@@ -421,11 +492,11 @@ class KtTextArea extends KtBaseInputField {
|
|
|
421
492
|
return value.length === 0;
|
|
422
493
|
}
|
|
423
494
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtTextArea, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
424
|
-
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 (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]=\"
|
|
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 });
|
|
425
496
|
}
|
|
426
497
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtTextArea, decorators: [{
|
|
427
498
|
type: Component,
|
|
428
|
-
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 (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]=\"
|
|
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" }]
|
|
429
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 }] }] } });
|
|
430
501
|
|
|
431
502
|
/**
|
|
@@ -450,7 +521,7 @@ class KtTextField extends KtBaseInputField {
|
|
|
450
521
|
suggestions = input(/* @ts-ignore */
|
|
451
522
|
...(ngDevMode ? [undefined, { debugName: "suggestions" }] : /* istanbul ignore next */ []));
|
|
452
523
|
idGen = inject(KtIdGenerator);
|
|
453
|
-
uid = this.idGen.generateId();
|
|
524
|
+
uid = this.idGen.generateId('text-field');
|
|
454
525
|
datalistId = `kt-text-field-list-${this.uid}`;
|
|
455
526
|
hasSuggestions = computed(() => (this.suggestions()?.length ?? 0) > 0, /* @ts-ignore */
|
|
456
527
|
...(ngDevMode ? [{ debugName: "hasSuggestions" }] : /* istanbul ignore next */ []));
|
|
@@ -466,11 +537,11 @@ class KtTextField extends KtBaseInputField {
|
|
|
466
537
|
return value.length === 0;
|
|
467
538
|
}
|
|
468
539
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtTextField, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
469
|
-
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 (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]=\"
|
|
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 });
|
|
470
541
|
}
|
|
471
542
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtTextField, decorators: [{
|
|
472
543
|
type: Component,
|
|
473
|
-
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 (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]=\"
|
|
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" }]
|
|
474
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 }] }] } });
|
|
475
546
|
|
|
476
547
|
/**
|
|
@@ -495,13 +566,11 @@ class KtSwitch {
|
|
|
495
566
|
/** Désactive la bascule (non actionnable). @default false */
|
|
496
567
|
disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
497
568
|
/** Marque la bascule comme invalide (combiné à `touched`/`dirty` via l'`errorMatcher`). @default false */
|
|
498
|
-
invalid = input(false, /*
|
|
499
|
-
...(ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []));
|
|
569
|
+
invalid = input(false, { ...(ngDevMode ? { debugName: "invalid" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
500
570
|
/** Affiche l'astérisque requis sur le libellé. @default false */
|
|
501
571
|
required = input(false, { ...(ngDevMode ? { debugName: "required" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
502
572
|
/** État « modifié » (entre dans la logique d'affichage des erreurs). @default false */
|
|
503
|
-
dirty = input(false, /*
|
|
504
|
-
...(ngDevMode ? [{ debugName: "dirty" }] : /* istanbul ignore next */ []));
|
|
573
|
+
dirty = input(false, { ...(ngDevMode ? { debugName: "dirty" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
505
574
|
/** Erreurs de validation à afficher sous la bascule. @default [] */
|
|
506
575
|
errors = input([], /* @ts-ignore */
|
|
507
576
|
...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
|
|
@@ -525,8 +594,7 @@ class KtSwitch {
|
|
|
525
594
|
errorMatcher = input(/* @ts-ignore */
|
|
526
595
|
...(ngDevMode ? [undefined, { debugName: "errorMatcher" }] : /* istanbul ignore next */ []));
|
|
527
596
|
/** Afficher toutes les erreurs au lieu de la première seule. @default KT_FIELD_CONFIG.showAllErrors ?? false */
|
|
528
|
-
showAllErrors = input(this.config?.showAllErrors ?? false, /*
|
|
529
|
-
...(ngDevMode ? [{ debugName: "showAllErrors" }] : /* istanbul ignore next */ []));
|
|
597
|
+
showAllErrors = input(this.config?.showAllErrors ?? false, { ...(ngDevMode ? { debugName: "showAllErrors" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
530
598
|
idGen = inject(KtIdGenerator);
|
|
531
599
|
uid = this.idGen.generateId('switch');
|
|
532
600
|
baseId = computed(() => this.id() ?? `kt-switch-${this.uid}`, /* @ts-ignore */
|
|
@@ -554,6 +622,15 @@ class KtSwitch {
|
|
|
554
622
|
return ids.length ? ids.join(' ') : null;
|
|
555
623
|
}, /* @ts-ignore */
|
|
556
624
|
...(ngDevMode ? [{ debugName: "describedBy" }] : /* istanbul ignore next */ []));
|
|
625
|
+
constructor() {
|
|
626
|
+
// Garde-fou a11y (dev, navigateur uniquement) : un switch sans nom accessible est annoncé vide
|
|
627
|
+
// (WCAG 4.1.2). Le nom vient de `label` ou `ariaLabel` (pas de contenu projeté ici).
|
|
628
|
+
afterNextRender(() => {
|
|
629
|
+
if (!isDevMode() || this.label() || this.ariaLabel())
|
|
630
|
+
return;
|
|
631
|
+
console.warn('[ktSwitch] sans `label` ni `ariaLabel` : le contrôle est annoncé sans nom accessible (WCAG 4.1.2).');
|
|
632
|
+
});
|
|
633
|
+
}
|
|
557
634
|
toggle() {
|
|
558
635
|
if (this.disabled())
|
|
559
636
|
return;
|
|
@@ -582,9 +659,11 @@ class KtSwitch {
|
|
|
582
659
|
[attr.aria-labelledby]="label() ? labelId() : null"
|
|
583
660
|
[attr.aria-describedby]="describedBy()"
|
|
584
661
|
[attr.aria-invalid]="showInvalid() ? 'true' : null"
|
|
662
|
+
[attr.aria-required]="required() ? 'true' : null"
|
|
585
663
|
[disabled]="disabled()"
|
|
586
664
|
(click)="toggle()"
|
|
587
665
|
(keydown.space)="onSpacebar($event)"
|
|
666
|
+
(blur)="touched.set(true)"
|
|
588
667
|
class="kt-switch"
|
|
589
668
|
>
|
|
590
669
|
<span class="kt-switch__thumb"></span>
|
|
@@ -632,9 +711,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
|
|
|
632
711
|
[attr.aria-labelledby]="label() ? labelId() : null"
|
|
633
712
|
[attr.aria-describedby]="describedBy()"
|
|
634
713
|
[attr.aria-invalid]="showInvalid() ? 'true' : null"
|
|
714
|
+
[attr.aria-required]="required() ? 'true' : null"
|
|
635
715
|
[disabled]="disabled()"
|
|
636
716
|
(click)="toggle()"
|
|
637
717
|
(keydown.space)="onSpacebar($event)"
|
|
718
|
+
(blur)="touched.set(true)"
|
|
638
719
|
class="kt-switch"
|
|
639
720
|
>
|
|
640
721
|
<span class="kt-switch__thumb"></span>
|
|
@@ -662,7 +743,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
|
|
|
662
743
|
</div>
|
|
663
744
|
</div>
|
|
664
745
|
`, 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"] }]
|
|
665
|
-
}], 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 }] }] } });
|
|
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 }] }] } });
|
|
666
747
|
|
|
667
748
|
/**
|
|
668
749
|
* Groupe de cases à cocher (Checkbox Group) conforme à l'ARIA APG / RGAA.
|
|
@@ -676,9 +757,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
|
|
|
676
757
|
* @example
|
|
677
758
|
* ```html
|
|
678
759
|
* <kt-checkbox-group label="Centres d'intérêt" [(value)]="interests" required>
|
|
679
|
-
* <kt-checkbox [
|
|
680
|
-
* <kt-checkbox [
|
|
681
|
-
* <kt-checkbox [
|
|
760
|
+
* <kt-checkbox [optionValue]="'sport'" label="Sport" />
|
|
761
|
+
* <kt-checkbox [optionValue]="'musique'" label="Musique" />
|
|
762
|
+
* <kt-checkbox [optionValue]="'cinema'" label="Cinéma" />
|
|
682
763
|
* </kt-checkbox-group>
|
|
683
764
|
* ```
|
|
684
765
|
*/
|
|
@@ -694,17 +775,17 @@ class KtCheckboxGroup {
|
|
|
694
775
|
/** Désactive le groupe entier (hérité par chaque case enfant). @default false */
|
|
695
776
|
disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
696
777
|
/** Marque le groupe comme invalide (combiné à `touched`/`dirty` via l'`errorMatcher`). @default false */
|
|
697
|
-
invalid = input(false, /*
|
|
698
|
-
...(ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []));
|
|
778
|
+
invalid = input(false, { ...(ngDevMode ? { debugName: "invalid" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
699
779
|
/** Affiche l'astérisque requis et `aria-required` sur le groupe. @default false */
|
|
700
780
|
required = input(false, { ...(ngDevMode ? { debugName: "required" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
701
781
|
/** État « modifié » (entre dans la logique d'affichage des erreurs). @default false */
|
|
702
|
-
dirty = input(false, /*
|
|
703
|
-
...(ngDevMode ? [{ debugName: "dirty" }] : /* istanbul ignore next */ []));
|
|
782
|
+
dirty = input(false, { ...(ngDevMode ? { debugName: "dirty" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
704
783
|
/** Erreurs de validation à afficher sous le groupe. @default [] */
|
|
705
784
|
errors = input([], /* @ts-ignore */
|
|
706
785
|
...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
|
|
707
|
-
/**
|
|
786
|
+
/** Nom logique du groupe, à titre INDICATIF : contrairement à `kt-radio-group` (où `name` est
|
|
787
|
+
propagé aux `<input>` natifs pour le regroupement radio), il n'est PAS répercuté sur les cases
|
|
788
|
+
enfants (les checkboxes n'ont pas besoin d'un `name` partagé). @default '' */
|
|
708
789
|
name = input('', /* @ts-ignore */
|
|
709
790
|
...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
|
|
710
791
|
// --- Présentation ---
|
|
@@ -724,8 +805,7 @@ class KtCheckboxGroup {
|
|
|
724
805
|
errorMatcher = input(/* @ts-ignore */
|
|
725
806
|
...(ngDevMode ? [undefined, { debugName: "errorMatcher" }] : /* istanbul ignore next */ []));
|
|
726
807
|
/** Afficher toutes les erreurs au lieu de la première seule. @default KT_FIELD_CONFIG.showAllErrors ?? false */
|
|
727
|
-
showAllErrors = input(this.config?.showAllErrors ?? false, /*
|
|
728
|
-
...(ngDevMode ? [{ debugName: "showAllErrors" }] : /* istanbul ignore next */ []));
|
|
808
|
+
showAllErrors = input(this.config?.showAllErrors ?? false, { ...(ngDevMode ? { debugName: "showAllErrors" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
729
809
|
/** Égalité des valeurs en mode objet (défaut : identité `===`). */
|
|
730
810
|
compareWith = input(/* @ts-ignore */
|
|
731
811
|
...(ngDevMode ? [undefined, { debugName: "compareWith" }] : /* istanbul ignore next */ []));
|
|
@@ -867,8 +947,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
|
|
|
867
947
|
* DEUX MODES, selon la présence d'un `kt-checkbox-group` parent :
|
|
868
948
|
* - Autonome : `value` est l'état coché (`boolean`, two-way), intégré aux Signal Forms via
|
|
869
949
|
* `FormValueControl<boolean>` (même contrat que `kt-switch`).
|
|
870
|
-
* - Dans un groupe : `
|
|
871
|
-
* l'appartenance au tableau du groupe, et le (dé)cochage met à jour ce tableau.
|
|
950
|
+
* - Dans un groupe : `optionValue` porte la VALEUR d'option représentée ; l'état coché dérive de
|
|
951
|
+
* l'appartenance au tableau du groupe, et le (dé)cochage met à jour ce tableau. `value` est
|
|
952
|
+
* alors ignoré (c'est le groupe qui détient la sélection).
|
|
872
953
|
*
|
|
873
954
|
* Libellé : `label` (texte) par défaut ; un contenu projeté le remplace visuellement pour les
|
|
874
955
|
* rendus riches (carte/option), `ariaLabel` portant alors le nom accessible si besoin.
|
|
@@ -880,8 +961,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
|
|
|
880
961
|
*
|
|
881
962
|
* <!-- Dans un groupe -->
|
|
882
963
|
* <kt-checkbox-group label="Centres d'intérêt" [(value)]="interests">
|
|
883
|
-
* <kt-checkbox [
|
|
884
|
-
* <kt-checkbox [
|
|
964
|
+
* <kt-checkbox [optionValue]="'sport'" label="Sport" />
|
|
965
|
+
* <kt-checkbox [optionValue]="'musique'" label="Musique" />
|
|
885
966
|
* </kt-checkbox-group>
|
|
886
967
|
* ```
|
|
887
968
|
*/
|
|
@@ -889,9 +970,14 @@ class KtCheckbox {
|
|
|
889
970
|
config = inject(KT_FIELD_CONFIG, { optional: true });
|
|
890
971
|
/** Groupe parent optionnel : présent ⇒ la case appartient à un `kt-checkbox-group`. */
|
|
891
972
|
group = inject(KtCheckboxGroup, { optional: true });
|
|
892
|
-
/**
|
|
973
|
+
/** État coché (`boolean`, two-way) en mode autonome. Ignoré en mode groupe : c'est alors
|
|
974
|
+
`optionValue` + le tableau du groupe qui font foi. @default false */
|
|
893
975
|
value = model(false, /* @ts-ignore */
|
|
894
976
|
...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
977
|
+
/** Mode groupe uniquement : valeur d'option contribuée au tableau du `kt-checkbox-group` parent
|
|
978
|
+
quand la case est cochée. Sans effet en mode autonome. @default undefined */
|
|
979
|
+
optionValue = input(/* @ts-ignore */
|
|
980
|
+
...(ngDevMode ? [undefined, { debugName: "optionValue" }] : /* istanbul ignore next */ []));
|
|
895
981
|
/** Tri-état visuel (parent d'une arborescence) : propriété DOM `indeterminate`, pas un attribut. */
|
|
896
982
|
indeterminate = input(false, { ...(ngDevMode ? { debugName: "indeterminate" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
897
983
|
// --- État poussé par [formField] (mode autonome) ---
|
|
@@ -901,13 +987,11 @@ class KtCheckbox {
|
|
|
901
987
|
/** Désactive la case (héritable du groupe parent). @default false */
|
|
902
988
|
disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
903
989
|
/** Marque la case comme invalide (combiné à `touched`/`dirty` via l'`errorMatcher`). @default false */
|
|
904
|
-
invalid = input(false, /*
|
|
905
|
-
...(ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []));
|
|
990
|
+
invalid = input(false, { ...(ngDevMode ? { debugName: "invalid" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
906
991
|
/** Affiche l'astérisque requis et `aria-required`. @default false */
|
|
907
992
|
required = input(false, { ...(ngDevMode ? { debugName: "required" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
908
993
|
/** État « modifié » (entre dans la logique d'affichage des erreurs). @default false */
|
|
909
|
-
dirty = input(false, /*
|
|
910
|
-
...(ngDevMode ? [{ debugName: "dirty" }] : /* istanbul ignore next */ []));
|
|
994
|
+
dirty = input(false, { ...(ngDevMode ? { debugName: "dirty" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
911
995
|
/** Erreurs de validation à afficher sous la case. @default [] */
|
|
912
996
|
errors = input([], /* @ts-ignore */
|
|
913
997
|
...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
|
|
@@ -931,9 +1015,9 @@ class KtCheckbox {
|
|
|
931
1015
|
errorMatcher = input(/* @ts-ignore */
|
|
932
1016
|
...(ngDevMode ? [undefined, { debugName: "errorMatcher" }] : /* istanbul ignore next */ []));
|
|
933
1017
|
/** Afficher toutes les erreurs au lieu de la première seule. @default KT_FIELD_CONFIG.showAllErrors ?? false */
|
|
934
|
-
showAllErrors = input(this.config?.showAllErrors ?? false, /*
|
|
935
|
-
...(ngDevMode ? [{ debugName: "showAllErrors" }] : /* istanbul ignore next */ []));
|
|
1018
|
+
showAllErrors = input(this.config?.showAllErrors ?? false, { ...(ngDevMode ? { debugName: "showAllErrors" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
936
1019
|
inputEl = viewChild.required('input');
|
|
1020
|
+
el = inject(ElementRef);
|
|
937
1021
|
idGen = inject(KtIdGenerator);
|
|
938
1022
|
uid = this.idGen.generateId('checkbox');
|
|
939
1023
|
baseId = computed(() => this.id() ?? `kt-checkbox-${this.uid}`, /* @ts-ignore */
|
|
@@ -944,7 +1028,7 @@ class KtCheckbox {
|
|
|
944
1028
|
...(ngDevMode ? [{ debugName: "errorId" }] : /* istanbul ignore next */ []));
|
|
945
1029
|
/** Coché : appartenance au groupe le cas échéant, sinon l'état booléen propre.
|
|
946
1030
|
(Nommé `isChecked` car `FormValueControl` réserve la propriété `checked`.) */
|
|
947
|
-
isChecked = computed(() => this.group ? this.group.isSelected(this.
|
|
1031
|
+
isChecked = computed(() => this.group ? this.group.isSelected(this.optionValue()) : this.value(), /* @ts-ignore */
|
|
948
1032
|
...(ngDevMode ? [{ debugName: "isChecked" }] : /* istanbul ignore next */ []));
|
|
949
1033
|
/** Désactivé : hérité du groupe le cas échéant. */
|
|
950
1034
|
isDisabled = computed(() => (this.group?.disabled() ?? false) || this.disabled(), /* @ts-ignore */
|
|
@@ -971,13 +1055,23 @@ class KtCheckbox {
|
|
|
971
1055
|
effect(() => {
|
|
972
1056
|
this.inputEl().nativeElement.indeterminate = this.indeterminate();
|
|
973
1057
|
});
|
|
1058
|
+
// Garde-fou a11y (dev, navigateur uniquement) : nom accessible = `label`, `ariaLabel` OU contenu
|
|
1059
|
+
// projeté. Sans aucun des trois, la case est annoncée vide (WCAG 4.1.2).
|
|
1060
|
+
afterNextRender(() => {
|
|
1061
|
+
if (!isDevMode() || this.label() || this.ariaLabel())
|
|
1062
|
+
return;
|
|
1063
|
+
const labelText = this.el.nativeElement.querySelector('.kt-checkbox__label')?.textContent?.replace('*', '').trim();
|
|
1064
|
+
if (!labelText) {
|
|
1065
|
+
console.warn('[ktCheckbox] sans `label`, `ariaLabel` ni contenu projeté : annoncée sans nom accessible (WCAG 4.1.2).');
|
|
1066
|
+
}
|
|
1067
|
+
});
|
|
974
1068
|
}
|
|
975
1069
|
onChange(event) {
|
|
976
1070
|
if (this.isDisabled())
|
|
977
1071
|
return;
|
|
978
1072
|
const checked = event.target.checked;
|
|
979
1073
|
if (this.group) {
|
|
980
|
-
this.group.toggle(this.
|
|
1074
|
+
this.group.toggle(this.optionValue(), checked);
|
|
981
1075
|
this.group.touched.set(true);
|
|
982
1076
|
return;
|
|
983
1077
|
}
|
|
@@ -988,7 +1082,7 @@ class KtCheckbox {
|
|
|
988
1082
|
(this.group?.touched ?? this.touched).set(true);
|
|
989
1083
|
}
|
|
990
1084
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtCheckbox, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
991
|
-
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 }, 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: `
|
|
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: `
|
|
992
1086
|
<div
|
|
993
1087
|
class="kt-checkbox-field"
|
|
994
1088
|
[class.kt-checkbox-field--invalid]="showInvalid()"
|
|
@@ -1075,7 +1169,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
|
|
|
1075
1169
|
</div>
|
|
1076
1170
|
</div>
|
|
1077
1171
|
`, 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"] }]
|
|
1078
|
-
}], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], 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 }] }] } });
|
|
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 }] }] } });
|
|
1079
1173
|
|
|
1080
1174
|
/**
|
|
1081
1175
|
* Groupe de boutons radio (Radio Group) conforme à l'ARIA APG / RGAA.
|
|
@@ -1090,9 +1184,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
|
|
|
1090
1184
|
* @example
|
|
1091
1185
|
* ```html
|
|
1092
1186
|
* <kt-radio-group label="Civilité" [(value)]="civility" required>
|
|
1093
|
-
* <kt-radio [
|
|
1094
|
-
* <kt-radio [
|
|
1095
|
-
* <kt-radio [
|
|
1187
|
+
* <kt-radio [optionValue]="'mme'" label="Madame" />
|
|
1188
|
+
* <kt-radio [optionValue]="'m'" label="Monsieur" />
|
|
1189
|
+
* <kt-radio [optionValue]="'autre'" label="Autre" />
|
|
1096
1190
|
* </kt-radio-group>
|
|
1097
1191
|
* ```
|
|
1098
1192
|
*/
|
|
@@ -1108,13 +1202,11 @@ class KtRadioGroup {
|
|
|
1108
1202
|
/** Désactive le groupe entier (hérité par chaque radio enfant). @default false */
|
|
1109
1203
|
disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
1110
1204
|
/** Marque le groupe comme invalide (combiné à `touched`/`dirty` via l'`errorMatcher`). @default false */
|
|
1111
|
-
invalid = input(false, /*
|
|
1112
|
-
...(ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []));
|
|
1205
|
+
invalid = input(false, { ...(ngDevMode ? { debugName: "invalid" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
1113
1206
|
/** Affiche l'astérisque requis et `aria-required` sur le groupe. @default false */
|
|
1114
1207
|
required = input(false, { ...(ngDevMode ? { debugName: "required" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
1115
1208
|
/** État « modifié » (entre dans la logique d'affichage des erreurs). @default false */
|
|
1116
|
-
dirty = input(false, /*
|
|
1117
|
-
...(ngDevMode ? [{ debugName: "dirty" }] : /* istanbul ignore next */ []));
|
|
1209
|
+
dirty = input(false, { ...(ngDevMode ? { debugName: "dirty" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
1118
1210
|
/** Erreurs de validation à afficher sous le groupe. @default [] */
|
|
1119
1211
|
errors = input([], /* @ts-ignore */
|
|
1120
1212
|
...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
|
|
@@ -1138,8 +1230,7 @@ class KtRadioGroup {
|
|
|
1138
1230
|
errorMatcher = input(/* @ts-ignore */
|
|
1139
1231
|
...(ngDevMode ? [undefined, { debugName: "errorMatcher" }] : /* istanbul ignore next */ []));
|
|
1140
1232
|
/** Afficher toutes les erreurs au lieu de la première seule. @default KT_FIELD_CONFIG.showAllErrors ?? false */
|
|
1141
|
-
showAllErrors = input(this.config?.showAllErrors ?? false, /*
|
|
1142
|
-
...(ngDevMode ? [{ debugName: "showAllErrors" }] : /* istanbul ignore next */ []));
|
|
1233
|
+
showAllErrors = input(this.config?.showAllErrors ?? false, { ...(ngDevMode ? { debugName: "showAllErrors" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
1143
1234
|
/** Égalité des valeurs en mode objet (défaut : identité `===`). Seul rescapé du contrat select. */
|
|
1144
1235
|
compareWith = input(/* @ts-ignore */
|
|
1145
1236
|
...(ngDevMode ? [undefined, { debugName: "compareWith" }] : /* istanbul ignore next */ []));
|
|
@@ -1175,7 +1266,7 @@ class KtRadioGroup {
|
|
|
1175
1266
|
...(ngDevMode ? [{ debugName: "describedBy" }] : /* istanbul ignore next */ []));
|
|
1176
1267
|
comparator = computed(() => this.compareWith() ?? ((a, b) => a === b), /* @ts-ignore */
|
|
1177
1268
|
...(ngDevMode ? [{ debugName: "comparator" }] : /* istanbul ignore next */ []));
|
|
1178
|
-
/**
|
|
1269
|
+
/** L'`optionValue` d'un enfant correspond-il à la sélection courante ? (lu dans le `computed` enfant) */
|
|
1179
1270
|
isSelected(radioValue) {
|
|
1180
1271
|
const v = this.value();
|
|
1181
1272
|
if (v === null || v === undefined)
|
|
@@ -1226,7 +1317,7 @@ class KtRadioGroup {
|
|
|
1226
1317
|
}
|
|
1227
1318
|
</div>
|
|
1228
1319
|
</div>
|
|
1229
|
-
`, 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,
|
|
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 });
|
|
1230
1321
|
}
|
|
1231
1322
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtRadioGroup, decorators: [{
|
|
1232
1323
|
type: Component,
|
|
@@ -1266,7 +1357,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
|
|
|
1266
1357
|
}
|
|
1267
1358
|
</div>
|
|
1268
1359
|
</div>
|
|
1269
|
-
`, 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,
|
|
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"] }]
|
|
1270
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 }] }] } });
|
|
1271
1362
|
|
|
1272
1363
|
/**
|
|
@@ -1278,16 +1369,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
|
|
|
1278
1369
|
* @example
|
|
1279
1370
|
* ```html
|
|
1280
1371
|
* <kt-radio-group label="Civilité" [(value)]="civility">
|
|
1281
|
-
* <kt-radio [
|
|
1282
|
-
* <kt-radio [
|
|
1372
|
+
* <kt-radio [optionValue]="'mme'" label="Madame" />
|
|
1373
|
+
* <kt-radio [optionValue]="'m'" label="Monsieur" />
|
|
1283
1374
|
* </kt-radio-group>
|
|
1284
1375
|
* ```
|
|
1285
1376
|
*/
|
|
1286
1377
|
class KtRadio {
|
|
1287
1378
|
group = inject(KtRadioGroup);
|
|
1288
|
-
/** Valeur d'option représentée par ce radio (sélectionnée ⇒ devient la valeur du groupe).
|
|
1289
|
-
|
|
1290
|
-
|
|
1379
|
+
/** Valeur d'option représentée par ce radio (sélectionnée ⇒ devient la valeur du groupe). Nommée
|
|
1380
|
+
`optionValue` pour s'aligner sur `kt-checkbox` (où `value` = état coché). @default (requis) */
|
|
1381
|
+
optionValue = input.required(/* @ts-ignore */
|
|
1382
|
+
...(ngDevMode ? [{ debugName: "optionValue" }] : /* istanbul ignore next */ []));
|
|
1291
1383
|
/** Texte du libellé (remplacé visuellement par un contenu projeté). @default undefined */
|
|
1292
1384
|
label = input(/* @ts-ignore */
|
|
1293
1385
|
...(ngDevMode ? [undefined, { debugName: "label" }] : /* istanbul ignore next */ []));
|
|
@@ -1308,15 +1400,32 @@ class KtRadio {
|
|
|
1308
1400
|
...(ngDevMode ? [{ debugName: "baseId" }] : /* istanbul ignore next */ []));
|
|
1309
1401
|
hintId = computed(() => `${this.baseId()}-hint`, /* @ts-ignore */
|
|
1310
1402
|
...(ngDevMode ? [{ debugName: "hintId" }] : /* istanbul ignore next */ []));
|
|
1311
|
-
checked = computed(() => this.group.isSelected(this.
|
|
1403
|
+
checked = computed(() => this.group.isSelected(this.optionValue()), /* @ts-ignore */
|
|
1312
1404
|
...(ngDevMode ? [{ debugName: "checked" }] : /* istanbul ignore next */ []));
|
|
1313
1405
|
isDisabled = computed(() => this.group.disabled() || this.disabled(), /* @ts-ignore */
|
|
1314
1406
|
...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
|
|
1407
|
+
el = inject(ElementRef);
|
|
1408
|
+
constructor() {
|
|
1409
|
+
// Garde-fou a11y (dev, navigateur uniquement) : nom accessible = `label`, `ariaLabel` OU contenu
|
|
1410
|
+
// projeté. Sans aucun des trois, le radio est annoncé vide (WCAG 4.1.2).
|
|
1411
|
+
afterNextRender(() => {
|
|
1412
|
+
if (!isDevMode() || this.label() || this.ariaLabel())
|
|
1413
|
+
return;
|
|
1414
|
+
const labelText = this.el.nativeElement.querySelector('.kt-radio__label')?.textContent?.trim();
|
|
1415
|
+
if (!labelText) {
|
|
1416
|
+
console.warn('[ktRadio] sans `label`, `ariaLabel` ni contenu projeté : annoncé sans nom accessible (WCAG 4.1.2).');
|
|
1417
|
+
}
|
|
1418
|
+
});
|
|
1419
|
+
}
|
|
1315
1420
|
onChange() {
|
|
1316
|
-
|
|
1421
|
+
// Garde défensive : un input natif `disabled` n'émet pas `change`, mais on protège un appel
|
|
1422
|
+
// programmatique éventuel (cohérence avec switch/checkbox qui gardent leur commit).
|
|
1423
|
+
if (this.isDisabled())
|
|
1424
|
+
return;
|
|
1425
|
+
this.group.select(this.optionValue());
|
|
1317
1426
|
}
|
|
1318
1427
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtRadio, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1319
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: KtRadio, isStandalone: true, selector: "kt-radio", inputs: {
|
|
1428
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: KtRadio, isStandalone: true, selector: "kt-radio", inputs: { optionValue: { classPropertyName: "optionValue", publicName: "optionValue", isSignal: true, isRequired: true, 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 }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
1320
1429
|
<label class="kt-radio">
|
|
1321
1430
|
<input
|
|
1322
1431
|
type="radio"
|
|
@@ -1365,9 +1474,35 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
|
|
|
1365
1474
|
<p [id]="hintId()" class="kt-radio__hint">{{ hintText }}</p>
|
|
1366
1475
|
}
|
|
1367
1476
|
`, styles: ["@layer kt-aaa.components{:host{display:block}.kt-radio{display:flex;align-items:center;gap:var(--field-control-gap, .5rem);inline-size:100%;box-sizing:border-box;min-block-size:var(--radio-target-size, 44px);padding:var(--radio-padding, 0);border-radius:inherit;cursor:pointer;-webkit-user-select:none;user-select:none}.kt-radio__input{appearance:none;-webkit-appearance:none;margin:0;flex:none;box-sizing:border-box;display:grid;place-content:center;font-size:var(--radio-size, 1.25rem);inline-size:1em;block-size:1em;border:var(--radio-border-width, 2px) solid var(--radio-border-color, var(--field-border-color, var(--kt-outline, #c4c7c5)));border-radius:50%;background-color:var(--radio-bg, var(--field-bg, var(--kt-surface, #ffffff)));cursor:pointer;box-shadow:var(--radio-shadow, var(--field-shadow, none));transition:var( --radio-transition, background-color .15s cubic-bezier(.4, 0, .2, 1), border-color .15s cubic-bezier(.4, 0, .2, 1), box-shadow .2s ease )}.kt-radio__input:before{content:\"\";inline-size:.5em;block-size:.5em;border-radius:50%;transform:scale(0);transform-origin:center;box-shadow:inset 1em 1em var(--radio-dot-color, #ffffff);transition:var(--radio-dot-transition, transform .12s ease-in)}.kt-radio__input:checked:before{transform:scale(1);animation:var(--radio-dot-animation, kt-radio-pop .22s cubic-bezier(.34, 1.56, .64, 1))}@keyframes kt-radio-pop{0%{transform:scale(0)}}.kt-radio__input:checked{background-color:var(--radio-bg-checked, var(--kt-primary, #0842a0));border-color:var(--radio-border-color-checked, var(--radio-bg-checked, var(--kt-primary, #0842a0)));box-shadow:var( --radio-shadow-checked, 0 0 8px color-mix(in srgb, var(--radio-bg-checked, var(--kt-primary, #0842a0)) 50%, transparent) )}.kt-radio__input:hover:not(:disabled){border-color:var(--radio-border-color-hover, var(--field-border-color-hover, var(--kt-outline-strong, #5f6368)));box-shadow:var(--radio-shadow-hover, var(--field-shadow-hover, var(--radio-shadow, var(--field-shadow, none))))}.kt-radio__input:checked:hover:not(:disabled){background-color:var(--radio-bg-checked-hover, color-mix(in srgb, var(--kt-primary, #0842a0) 90%, black));border-color:var(--radio-bg-checked-hover, color-mix(in srgb, var(--kt-primary, #0842a0) 90%, black))}.kt-radio__input:focus-visible{outline:var(--kt-focus-ring-width, 2px) solid var(--kt-focus-ring-color, #0842a0);outline-offset:var(--radio-focus-ring-offset, 2px);box-shadow:var(--radio-shadow-focus, var(--field-shadow-focus, var(--field-shadow, none)))}.kt-radio__input:disabled{cursor:not-allowed;opacity:.5}.kt-radio:has(.kt-radio__input:disabled){cursor:not-allowed}.kt-radio__label{font-size:var(--field-label-font-size, .875rem);font-weight:var(--field-label-weight, 500);color:var(--field-label-color, inherit)}.kt-radio:has(.kt-radio__input:disabled) .kt-radio__label{color:var(--field-hint-color, #5f6368);opacity:.6}.kt-radio__hint{margin:0;margin-inline-start:calc(var(--radio-size, 1.25rem) + var(--field-control-gap, .5rem));font-size:var(--field-hint-font-size, .8125rem);color:var(--field-hint-color, #474747)}@media(forced-colors:active){.kt-radio__input{border-color:CanvasText;background-color:Canvas}.kt-radio__input:checked{border-color:Highlight;background-color:Canvas}.kt-radio__input:before{box-shadow:inset 1em 1em Highlight}.kt-radio__input:disabled{border-color:GrayText}.kt-radio__input:focus-visible{outline:2px solid CanvasText;outline-offset:2px}}@media(prefers-reduced-motion:reduce){.kt-radio__input,.kt-radio__input:before{transition:none;animation:none}}}\n"] }]
|
|
1368
|
-
}], propDecorators: {
|
|
1477
|
+
}], ctorParameters: () => [], propDecorators: { optionValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionValue", required: true }] }], 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 }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }] } });
|
|
1369
1478
|
|
|
1370
1479
|
const KT_SELECT_CONFIG = new InjectionToken('KT_SELECT_CONFIG');
|
|
1480
|
+
/**
|
|
1481
|
+
* Source UNIQUE des défauts (anglais neutre) de la config select / multi-select. Constitue le 3e
|
|
1482
|
+
* maillon de la résolution `input() ?? KT_SELECT_CONFIG ?? DEFAULT_KT_SELECT_CONFIG`, jusqu'ici
|
|
1483
|
+
* éparpillé entre `base-select.ts`, `multi-select.ts` et des fonctions locales. Centralisé ici pour
|
|
1484
|
+
* éviter toute dérive et garantir la complétude des traductions (cf. test de complétude i18n).
|
|
1485
|
+
*/
|
|
1486
|
+
const DEFAULT_KT_SELECT_CONFIG = {
|
|
1487
|
+
placeholder: '',
|
|
1488
|
+
emptyText: 'No options',
|
|
1489
|
+
closeLabel: 'Close',
|
|
1490
|
+
closeOnSelect: true,
|
|
1491
|
+
filterPlaceholder: '',
|
|
1492
|
+
filterLabel: 'Filter options',
|
|
1493
|
+
filterResultsText: (count) => (count === 1 ? '1 result' : `${count} results`),
|
|
1494
|
+
removeItemLabel: (itemLabel) => `Remove ${itemLabel}`,
|
|
1495
|
+
selectedItemsLabel: (fieldLabel) => (fieldLabel ? `Selected items for ${fieldLabel}` : 'Selected items'),
|
|
1496
|
+
selectionSummaryText: (count) => `${count} items selected`,
|
|
1497
|
+
itemRemovedText: (itemLabel) => `${itemLabel} removed`,
|
|
1498
|
+
selectionCountText: (count) => (count === 1 ? '1 selected' : `${count} selected`),
|
|
1499
|
+
selectAllLabel: 'Select all',
|
|
1500
|
+
clearAllLabel: 'Clear all',
|
|
1501
|
+
moreChipsLabel: (hiddenCount) => `+${hiddenCount} more`,
|
|
1502
|
+
lessChipsLabel: 'Show less',
|
|
1503
|
+
truncatedResultsText: (max, total) => `Showing first ${max} results of ${total}. Refine your search to see more.`,
|
|
1504
|
+
truncatedResultsAnnouncement: (max, total) => `${max} results displayed out of ${total}. Refine your search to see more.`,
|
|
1505
|
+
};
|
|
1371
1506
|
|
|
1372
1507
|
/** Normalise une clé/fonction en fonction d'accès, avec repli si non fourni. */
|
|
1373
1508
|
function accessor(key, fallback) {
|
|
@@ -1406,16 +1541,6 @@ function normalizeForFilter(s) {
|
|
|
1406
1541
|
.replace(/[\u0300-\u036f]/g, '')
|
|
1407
1542
|
.toLowerCase();
|
|
1408
1543
|
}
|
|
1409
|
-
/** Annonce par défaut du nombre de résultats (lib neutre : anglais, comme `emptyText`). */
|
|
1410
|
-
function defaultFilterResultsText(count) {
|
|
1411
|
-
return count === 1 ? '1 result' : `${count} results`;
|
|
1412
|
-
}
|
|
1413
|
-
function defaultTruncatedResultsText(max, total) {
|
|
1414
|
-
return `Showing first ${max} results of ${total}. Refine your search to see more.`;
|
|
1415
|
-
}
|
|
1416
|
-
function defaultTruncatedResultsAnnouncement(max, total) {
|
|
1417
|
-
return `${max} results displayed out of ${total}. Refine your search to see more.`;
|
|
1418
|
-
}
|
|
1419
1544
|
/** Base partagée des sélecteurs à liste fermée (Select single et MultiSelect), bâtis sur
|
|
1420
1545
|
`@angular/aria` (Combobox + Listbox) : options et dérivation (clé/fonction), état poussé
|
|
1421
1546
|
par `[formField]`, popup Popover responsive (dropdown ancré desktop ↔ bottom-sheet
|
|
@@ -1461,20 +1586,15 @@ class KtBaseSelect {
|
|
|
1461
1586
|
touched = model(false, /* @ts-ignore */
|
|
1462
1587
|
...(ngDevMode ? [{ debugName: "touched" }] : /* istanbul ignore next */ []));
|
|
1463
1588
|
/** Champ désactivé (trigger inerte). Poussé par `[formField]`. @default false */
|
|
1464
|
-
disabled = input(false, /*
|
|
1465
|
-
...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
|
|
1589
|
+
disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
1466
1590
|
/** Champ en lecture seule (sélection figée, valeur affichée). Poussé par `[formField]`. @default false */
|
|
1467
|
-
readonly = input(false, /*
|
|
1468
|
-
...(ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []));
|
|
1591
|
+
readonly = input(false, { ...(ngDevMode ? { debugName: "readonly" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
1469
1592
|
/** Le champ est-il invalide ? Pilote l'affichage des erreurs. Poussé par `[formField]`. @default false */
|
|
1470
|
-
invalid = input(false, /*
|
|
1471
|
-
...(ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []));
|
|
1593
|
+
invalid = input(false, { ...(ngDevMode ? { debugName: "invalid" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
1472
1594
|
/** Champ obligatoire (marqueur visuel/ARIA). Poussé par `[formField]`. @default false */
|
|
1473
|
-
required = input(false, /*
|
|
1474
|
-
...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
|
|
1595
|
+
required = input(false, { ...(ngDevMode ? { debugName: "required" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
1475
1596
|
/** Le champ a-t-il été modifié depuis sa valeur initiale ? Poussé par `[formField]`. @default false */
|
|
1476
|
-
dirty = input(false, /*
|
|
1477
|
-
...(ngDevMode ? [{ debugName: "dirty" }] : /* istanbul ignore next */ []));
|
|
1597
|
+
dirty = input(false, { ...(ngDevMode ? { debugName: "dirty" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
1478
1598
|
/** Erreurs de validation à afficher. Poussé par `[formField]`. @default [] */
|
|
1479
1599
|
errors = input([], /* @ts-ignore */
|
|
1480
1600
|
...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
|
|
@@ -1506,11 +1626,18 @@ class KtBaseSelect {
|
|
|
1506
1626
|
/** Quand afficher l'erreur ; surcharge KT_FIELD_CONFIG et le défaut (`invalid && touched`). @default undefined */
|
|
1507
1627
|
errorMatcher = input(/* @ts-ignore */
|
|
1508
1628
|
...(ngDevMode ? [undefined, { debugName: "errorMatcher" }] : /* istanbul ignore next */ []));
|
|
1629
|
+
/** Apparence du chrome (`fill` | `outline`) ; non fournie ⇒ `KT_FIELD_CONFIG.appearance` ?? `'fill'`.
|
|
1630
|
+
@default undefined */
|
|
1631
|
+
appearance = input(/* @ts-ignore */
|
|
1632
|
+
...(ngDevMode ? [undefined, { debugName: "appearance" }] : /* istanbul ignore next */ []));
|
|
1633
|
+
/** Politique du label flottant en outline (`auto` | `always`) ; non fournie ⇒ `KT_FIELD_CONFIG.floatLabel`
|
|
1634
|
+
?? `'auto'`. @default undefined */
|
|
1635
|
+
floatLabel = input(/* @ts-ignore */
|
|
1636
|
+
...(ngDevMode ? [undefined, { debugName: "floatLabel" }] : /* istanbul ignore next */ []));
|
|
1509
1637
|
// --- Filtrage (champ de recherche dans le popup, opt-in) ---
|
|
1510
1638
|
/** Affiche un champ de recherche en tête du popup (desktop) / de la sheet (téléphone).
|
|
1511
|
-
Pour les listes longues ; le texte tapé ne sert qu'à filtrer (réinitialisé à la fermeture). */
|
|
1512
|
-
filterable = input(false, /*
|
|
1513
|
-
...(ngDevMode ? [{ debugName: "filterable" }] : /* istanbul ignore next */ []));
|
|
1639
|
+
Pour les listes longues ; le texte tapé ne sert qu'à filtrer (réinitialisé à la fermeture). @default false */
|
|
1640
|
+
filterable = input(false, { ...(ngDevMode ? { debugName: "filterable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
1514
1641
|
/** Placeholder du champ de recherche du popup. Défaut : `KT_SELECT_CONFIG.filterPlaceholder` ou vide. */
|
|
1515
1642
|
filterPlaceholder = input(/* @ts-ignore */
|
|
1516
1643
|
...(ngDevMode ? [undefined, { debugName: "filterPlaceholder" }] : /* istanbul ignore next */ []));
|
|
@@ -1563,24 +1690,24 @@ class KtBaseSelect {
|
|
|
1563
1690
|
...(ngDevMode ? [{ debugName: "matcher" }] : /* istanbul ignore next */ []));
|
|
1564
1691
|
showInvalid = computed(() => this.matcher()({ invalid: this.invalid(), touched: this.touched(), dirty: this.dirty() }), /* @ts-ignore */
|
|
1565
1692
|
...(ngDevMode ? [{ debugName: "showInvalid" }] : /* istanbul ignore next */ []));
|
|
1566
|
-
// --- Textes résolus (input > KT_SELECT_CONFIG >
|
|
1567
|
-
resolvedPlaceholder = computed(() => this.placeholder() ?? this.config?.placeholder ??
|
|
1693
|
+
// --- Textes résolus (input > KT_SELECT_CONFIG > DEFAULT_KT_SELECT_CONFIG, défauts EN centralisés) ---
|
|
1694
|
+
resolvedPlaceholder = computed(() => this.placeholder() ?? this.config?.placeholder ?? DEFAULT_KT_SELECT_CONFIG.placeholder, /* @ts-ignore */
|
|
1568
1695
|
...(ngDevMode ? [{ debugName: "resolvedPlaceholder" }] : /* istanbul ignore next */ []));
|
|
1569
|
-
resolvedEmptyText = computed(() => this.config?.emptyText ??
|
|
1696
|
+
resolvedEmptyText = computed(() => this.config?.emptyText ?? DEFAULT_KT_SELECT_CONFIG.emptyText, /* @ts-ignore */
|
|
1570
1697
|
...(ngDevMode ? [{ debugName: "resolvedEmptyText" }] : /* istanbul ignore next */ []));
|
|
1571
|
-
resolvedCloseLabel = computed(() => this.config?.closeLabel ??
|
|
1698
|
+
resolvedCloseLabel = computed(() => this.config?.closeLabel ?? DEFAULT_KT_SELECT_CONFIG.closeLabel, /* @ts-ignore */
|
|
1572
1699
|
...(ngDevMode ? [{ debugName: "resolvedCloseLabel" }] : /* istanbul ignore next */ []));
|
|
1573
|
-
resolvedFilterPlaceholder = computed(() => this.filterPlaceholder() ?? this.config?.filterPlaceholder ??
|
|
1700
|
+
resolvedFilterPlaceholder = computed(() => this.filterPlaceholder() ?? this.config?.filterPlaceholder ?? DEFAULT_KT_SELECT_CONFIG.filterPlaceholder, /* @ts-ignore */
|
|
1574
1701
|
...(ngDevMode ? [{ debugName: "resolvedFilterPlaceholder" }] : /* istanbul ignore next */ []));
|
|
1575
|
-
resolvedFilterLabel = computed(() => this.filterLabel() ?? this.config?.filterLabel ??
|
|
1702
|
+
resolvedFilterLabel = computed(() => this.filterLabel() ?? this.config?.filterLabel ?? DEFAULT_KT_SELECT_CONFIG.filterLabel, /* @ts-ignore */
|
|
1576
1703
|
...(ngDevMode ? [{ debugName: "resolvedFilterLabel" }] : /* istanbul ignore next */ []));
|
|
1577
|
-
resolvedFilterResultsText = computed(() => this.config?.filterResultsText ??
|
|
1704
|
+
resolvedFilterResultsText = computed(() => this.config?.filterResultsText ?? DEFAULT_KT_SELECT_CONFIG.filterResultsText, /* @ts-ignore */
|
|
1578
1705
|
...(ngDevMode ? [{ debugName: "resolvedFilterResultsText" }] : /* istanbul ignore next */ []));
|
|
1579
|
-
resolvedTruncatedResultsText = computed(() => this.truncatedResultsText() ?? this.config?.truncatedResultsText ??
|
|
1706
|
+
resolvedTruncatedResultsText = computed(() => this.truncatedResultsText() ?? this.config?.truncatedResultsText ?? DEFAULT_KT_SELECT_CONFIG.truncatedResultsText, /* @ts-ignore */
|
|
1580
1707
|
...(ngDevMode ? [{ debugName: "resolvedTruncatedResultsText" }] : /* istanbul ignore next */ []));
|
|
1581
1708
|
resolvedTruncatedResultsAnnouncement = computed(() => this.truncatedResultsAnnouncement() ??
|
|
1582
1709
|
this.config?.truncatedResultsAnnouncement ??
|
|
1583
|
-
|
|
1710
|
+
DEFAULT_KT_SELECT_CONFIG.truncatedResultsAnnouncement, /* @ts-ignore */
|
|
1584
1711
|
...(ngDevMode ? [{ debugName: "resolvedTruncatedResultsAnnouncement" }] : /* istanbul ignore next */ []));
|
|
1585
1712
|
// Field attend des { kind, message } ; on mappe les ValidationError.
|
|
1586
1713
|
fieldErrors = computed(() => this.errors().map((e) => ({ kind: e.kind, message: e.message })), /* @ts-ignore */
|
|
@@ -1912,7 +2039,7 @@ class KtBaseSelect {
|
|
|
1912
2039
|
}, durationMs + 50);
|
|
1913
2040
|
}
|
|
1914
2041
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtBaseSelect, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
1915
|
-
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 }, 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 });
|
|
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 });
|
|
1916
2043
|
}
|
|
1917
2044
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtBaseSelect, decorators: [{
|
|
1918
2045
|
type: Directive,
|
|
@@ -1921,7 +2048,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
|
|
|
1921
2048
|
'(keydown)': 'onHostKeydown($event)',
|
|
1922
2049
|
},
|
|
1923
2050
|
}]
|
|
1924
|
-
}], 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 }] }], 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 }] }] } });
|
|
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 }] }] } });
|
|
1925
2052
|
|
|
1926
2053
|
/** Template de rendu d'une option, posé sur un `<ng-template>` projeté dans `kt-select`.
|
|
1927
2054
|
L'input sert UNIQUEMENT à inférer `T` (re-bind de la liste d'options) ; `ngTemplateContextGuard`
|
|
@@ -1985,7 +2112,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
|
|
|
1985
2112
|
|
|
1986
2113
|
@example
|
|
1987
2114
|
```html
|
|
1988
|
-
<kt-select
|
|
2115
|
+
<kt-select
|
|
2116
|
+
[options]="users"
|
|
2117
|
+
optionLabel="name"
|
|
2118
|
+
optionValue="id"
|
|
2119
|
+
[(value)]="selectedId"
|
|
2120
|
+
(selectionChange)="onSelectionChange($event)" />
|
|
1989
2121
|
``` */
|
|
1990
2122
|
class KtSelect extends KtBaseSelect {
|
|
1991
2123
|
// --- Modèle / sortie ---
|
|
@@ -2056,11 +2188,11 @@ class KtSelect extends KtBaseSelect {
|
|
|
2056
2188
|
}
|
|
2057
2189
|
}
|
|
2058
2190
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtSelect, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
2059
|
-
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 (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 >\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"], 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 });
|
|
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 });
|
|
2060
2192
|
}
|
|
2061
2193
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtSelect, decorators: [{
|
|
2062
2194
|
type: Component,
|
|
2063
|
-
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 (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 >\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"] }]
|
|
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"] }]
|
|
2064
2196
|
}], 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 }] }] } });
|
|
2065
2197
|
|
|
2066
2198
|
/** Configure les `kt-select` d'un sous-arbre via DI (équivalent du Context provider de react-select).
|
|
@@ -2081,71 +2213,42 @@ class KtSelectConfig {
|
|
|
2081
2213
|
/** Config héritée du contexte parent (provider global ou directive englobante) : la
|
|
2082
2214
|
directive ne masque que les clés qu'elle définit, le reste continue d'en hériter. */
|
|
2083
2215
|
parent = inject(KT_SELECT_CONFIG, { optional: true, skipSelf: true });
|
|
2216
|
+
/** Résout une clé : valeur bindée sur la directive, sinon valeur héritée du contexte parent. */
|
|
2084
2217
|
resolve(key) {
|
|
2085
2218
|
return this.ktSelectConfig()[key] ?? this.parent?.[key];
|
|
2086
2219
|
}
|
|
2087
|
-
get placeholder() {
|
|
2088
|
-
return this.resolve('placeholder');
|
|
2089
|
-
}
|
|
2090
|
-
get emptyText() {
|
|
2091
|
-
return this.resolve('emptyText');
|
|
2092
|
-
}
|
|
2093
|
-
get closeLabel() {
|
|
2094
|
-
return this.resolve('closeLabel');
|
|
2095
|
-
}
|
|
2096
|
-
get closeOnSelect() {
|
|
2097
|
-
return this.resolve('closeOnSelect');
|
|
2098
|
-
}
|
|
2099
|
-
get filterPlaceholder() {
|
|
2100
|
-
return this.resolve('filterPlaceholder');
|
|
2101
|
-
}
|
|
2102
|
-
get filterLabel() {
|
|
2103
|
-
return this.resolve('filterLabel');
|
|
2104
|
-
}
|
|
2105
|
-
get filterResultsText() {
|
|
2106
|
-
return this.resolve('filterResultsText');
|
|
2107
|
-
}
|
|
2108
|
-
get removeItemLabel() {
|
|
2109
|
-
return this.resolve('removeItemLabel');
|
|
2110
|
-
}
|
|
2111
|
-
get selectedItemsLabel() {
|
|
2112
|
-
return this.resolve('selectedItemsLabel');
|
|
2113
|
-
}
|
|
2114
|
-
get selectionSummaryText() {
|
|
2115
|
-
return this.resolve('selectionSummaryText');
|
|
2116
|
-
}
|
|
2117
|
-
get itemRemovedText() {
|
|
2118
|
-
return this.resolve('itemRemovedText');
|
|
2119
|
-
}
|
|
2120
|
-
get selectionCountText() {
|
|
2121
|
-
return this.resolve('selectionCountText');
|
|
2122
|
-
}
|
|
2123
|
-
get selectAllLabel() {
|
|
2124
|
-
return this.resolve('selectAllLabel');
|
|
2125
|
-
}
|
|
2126
|
-
get clearAllLabel() {
|
|
2127
|
-
return this.resolve('clearAllLabel');
|
|
2128
|
-
}
|
|
2129
|
-
get moreChipsLabel() {
|
|
2130
|
-
return this.resolve('moreChipsLabel');
|
|
2131
|
-
}
|
|
2132
|
-
get lessChipsLabel() {
|
|
2133
|
-
return this.resolve('lessChipsLabel');
|
|
2134
|
-
}
|
|
2135
|
-
get truncatedResultsText() {
|
|
2136
|
-
return this.resolve('truncatedResultsText');
|
|
2137
|
-
}
|
|
2138
|
-
get truncatedResultsAnnouncement() {
|
|
2139
|
-
return this.resolve('truncatedResultsAnnouncement');
|
|
2140
|
-
}
|
|
2141
2220
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtSelectConfig, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2142
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.1", type: KtSelectConfig, isStandalone: true, selector: "[ktSelectConfig]", inputs: { ktSelectConfig: { classPropertyName: "ktSelectConfig", publicName: "ktSelectConfig", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
|
|
2221
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.1", type: KtSelectConfig, isStandalone: true, selector: "[ktSelectConfig]", inputs: { ktSelectConfig: { classPropertyName: "ktSelectConfig", publicName: "ktSelectConfig", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
|
|
2222
|
+
{
|
|
2223
|
+
provide: KT_SELECT_CONFIG,
|
|
2224
|
+
// Vue `Partial<KtSelectConfigOptions>` calculée à la volée : chaque accès de clé résout
|
|
2225
|
+
// `input bindé ?? contexte parent hérité`. Un Proxy évite d'énumérer (et de maintenir à la
|
|
2226
|
+
// main) un getter par clé — toute nouvelle clé de `KtSelectConfigOptions` est couverte
|
|
2227
|
+
// automatiquement, sans risque de dérive entre les deux fichiers.
|
|
2228
|
+
useFactory: (directive) => new Proxy({}, {
|
|
2229
|
+
get: (_target, key) => directive.resolve(key),
|
|
2230
|
+
}),
|
|
2231
|
+
deps: [KtSelectConfig],
|
|
2232
|
+
},
|
|
2233
|
+
], ngImport: i0 });
|
|
2143
2234
|
}
|
|
2144
2235
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtSelectConfig, decorators: [{
|
|
2145
2236
|
type: Directive,
|
|
2146
2237
|
args: [{
|
|
2147
2238
|
selector: '[ktSelectConfig]',
|
|
2148
|
-
providers: [
|
|
2239
|
+
providers: [
|
|
2240
|
+
{
|
|
2241
|
+
provide: KT_SELECT_CONFIG,
|
|
2242
|
+
// Vue `Partial<KtSelectConfigOptions>` calculée à la volée : chaque accès de clé résout
|
|
2243
|
+
// `input bindé ?? contexte parent hérité`. Un Proxy évite d'énumérer (et de maintenir à la
|
|
2244
|
+
// main) un getter par clé — toute nouvelle clé de `KtSelectConfigOptions` est couverte
|
|
2245
|
+
// automatiquement, sans risque de dérive entre les deux fichiers.
|
|
2246
|
+
useFactory: (directive) => new Proxy({}, {
|
|
2247
|
+
get: (_target, key) => directive.resolve(key),
|
|
2248
|
+
}),
|
|
2249
|
+
deps: [KtSelectConfig],
|
|
2250
|
+
},
|
|
2251
|
+
],
|
|
2149
2252
|
}]
|
|
2150
2253
|
}], propDecorators: { ktSelectConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "ktSelectConfig", required: false }] }] } });
|
|
2151
2254
|
|
|
@@ -2184,7 +2287,11 @@ class KtChip {
|
|
|
2184
2287
|
remove = output();
|
|
2185
2288
|
removeBtn = viewChild('removeBtn', /* @ts-ignore */
|
|
2186
2289
|
...(ngDevMode ? [{ debugName: "removeBtn" }] : /* istanbul ignore next */ []));
|
|
2187
|
-
/**
|
|
2290
|
+
/**
|
|
2291
|
+
* Focus programmatique du bouton « retirer ». Helper de coordination interne (focus management
|
|
2292
|
+
* d'`kt-chip-list`), non destiné aux consommateurs.
|
|
2293
|
+
* @internal
|
|
2294
|
+
*/
|
|
2188
2295
|
focusRemove() {
|
|
2189
2296
|
this.removeBtn()?.nativeElement.focus();
|
|
2190
2297
|
}
|
|
@@ -2215,6 +2322,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
|
|
|
2215
2322
|
</kt-chip-list>
|
|
2216
2323
|
``` */
|
|
2217
2324
|
class KtChipItemDef {
|
|
2325
|
+
/** Liste des items rendus par ce template (sert aussi à inférer le type `T` du contexte). */
|
|
2218
2326
|
ktChipItem = input.required(/* @ts-ignore */
|
|
2219
2327
|
...(ngDevMode ? [{ debugName: "ktChipItem" }] : /* istanbul ignore next */ []));
|
|
2220
2328
|
template = inject(TemplateRef);
|
|
@@ -2255,6 +2363,7 @@ class KtChipList {
|
|
|
2255
2363
|
doc = inject(DOCUMENT);
|
|
2256
2364
|
platformId = inject(PLATFORM_ID);
|
|
2257
2365
|
cdr = inject(ChangeDetectorRef);
|
|
2366
|
+
ngZone = inject(NgZone);
|
|
2258
2367
|
/** Vrai pendant la View Transition de CETTE liste : les chips (standards via Chip,
|
|
2259
2368
|
custom via tokens.css) ne portent leur `view-transition-name` que dans cette fenêtre. */
|
|
2260
2369
|
transitioning = signal(false, /* @ts-ignore */
|
|
@@ -2421,9 +2530,28 @@ class KtChipList {
|
|
|
2421
2530
|
this.transitioning.set(true);
|
|
2422
2531
|
this.cdr.detectChanges();
|
|
2423
2532
|
const vt = startViewTransition(() => {
|
|
2424
|
-
|
|
2425
|
-
//
|
|
2426
|
-
|
|
2533
|
+
// `items` est un input POSSÉDÉ par le parent (`[items]="selectedOptions()"` côté MultiSelect) :
|
|
2534
|
+
// le retrait émet `removed`, le parent met à jour son signal, et seule une CD du PARENT re-pousse
|
|
2535
|
+
// le nouvel `items` dans cette liste. Une CD locale (`cdr.detectChanges()`) ne verrait que l'ancien
|
|
2536
|
+
// input → snapshot « après » identique au « avant » → aucune animation. Une CD globale forcée
|
|
2537
|
+
// (`appRef.tick()`) corrigerait le rendu mais ajouterait une passe synchrone sur toute l'appli à
|
|
2538
|
+
// chaque retrait. On préfère DIFFÉRER la capture de l'état « après » : le callback d'une View
|
|
2539
|
+
// Transition peut renvoyer une Promise, le navigateur attend sa résolution avant le snapshot.
|
|
2540
|
+
// On déclenche la mutation dans la zone (la CD déjà planifiée, OnPush, ne vérifie que les vues
|
|
2541
|
+
// « dirty » : pas de passe globale supplémentaire) et on résout au prochain rendu.
|
|
2542
|
+
this.ngZone.run(action);
|
|
2543
|
+
return new Promise((resolve) => {
|
|
2544
|
+
let settled = false;
|
|
2545
|
+
const done = () => {
|
|
2546
|
+
if (settled)
|
|
2547
|
+
return;
|
|
2548
|
+
settled = true;
|
|
2549
|
+
resolve();
|
|
2550
|
+
};
|
|
2551
|
+
afterNextRender({ read: done }, { injector: this.injector });
|
|
2552
|
+
// Garde-fou : si aucun rendu n'est planifié (retrait ignoré par le parent), ne pas figer la page.
|
|
2553
|
+
this.ngZone.runOutsideAngular(() => setTimeout(done, 100));
|
|
2554
|
+
});
|
|
2427
2555
|
});
|
|
2428
2556
|
this.activeTransition = vt;
|
|
2429
2557
|
// `ready` rejette (AbortError) si la transition est sautée : attendu, ne pas laisser
|
|
@@ -2594,17 +2722,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
|
|
|
2594
2722
|
args: [{ selector: 'ng-template[ktMultiSelectChip]' }]
|
|
2595
2723
|
}], propDecorators: { ktMultiSelectChip: [{ type: i0.Input, args: [{ isSignal: true, alias: "ktMultiSelectChip", required: true }] }] } });
|
|
2596
2724
|
|
|
2597
|
-
// Défauts lib neutre (anglais, comme le Select single) : le consommateur fournit
|
|
2598
|
-
// ses textes via KT_SELECT_CONFIG / les inputs (pas de $localize — cf. select-config.ts).
|
|
2599
|
-
function defaultSelectionSummaryText(count) {
|
|
2600
|
-
return `${count} items selected`;
|
|
2601
|
-
}
|
|
2602
|
-
function defaultSelectionCountText(count) {
|
|
2603
|
-
return count === 1 ? '1 selected' : `${count} selected`;
|
|
2604
|
-
}
|
|
2605
|
-
function defaultSelectedItemsLabel(fieldLabel) {
|
|
2606
|
-
return fieldLabel ? `Selected items for ${fieldLabel}` : 'Selected items';
|
|
2607
|
-
}
|
|
2608
2725
|
/**
|
|
2609
2726
|
* Composant de sélection multiple (Multi-Select) conforme aux exigences d'accessibilité (WCAG 2.2 AAA / RGAA).
|
|
2610
2727
|
* Repose sur `@angular/aria/combobox` et `@angular/aria/listbox` avec [multi]="true".
|
|
@@ -2621,7 +2738,12 @@ function defaultSelectedItemsLabel(fieldLabel) {
|
|
|
2621
2738
|
*
|
|
2622
2739
|
* @example
|
|
2623
2740
|
* ```html
|
|
2624
|
-
* <kt-multi-select
|
|
2741
|
+
* <kt-multi-select
|
|
2742
|
+
* [options]="tags"
|
|
2743
|
+
* optionLabel="name"
|
|
2744
|
+
* optionValue="id"
|
|
2745
|
+
* [(value)]="selectedIds"
|
|
2746
|
+
* (selectionChange)="onSelectionChange($event)" />
|
|
2625
2747
|
* ```
|
|
2626
2748
|
*/
|
|
2627
2749
|
class KtMultiSelect extends KtBaseSelect {
|
|
@@ -2652,24 +2774,24 @@ class KtMultiSelect extends KtBaseSelect {
|
|
|
2652
2774
|
...(ngDevMode ? [{ debugName: "chipDef" }] : /* istanbul ignore next */ []));
|
|
2653
2775
|
chipList = viewChild(KtChipList, /* @ts-ignore */
|
|
2654
2776
|
...(ngDevMode ? [{ debugName: "chipList" }] : /* istanbul ignore next */ []));
|
|
2655
|
-
// --- Textes résolus spécifiques multi (input > KT_SELECT_CONFIG >
|
|
2656
|
-
resolvedRemoveItemLabel = computed(() => this.config?.removeItemLabel ??
|
|
2777
|
+
// --- Textes résolus spécifiques multi (input > KT_SELECT_CONFIG > DEFAULT_KT_SELECT_CONFIG centralisé) ---
|
|
2778
|
+
resolvedRemoveItemLabel = computed(() => this.config?.removeItemLabel ?? DEFAULT_KT_SELECT_CONFIG.removeItemLabel, /* @ts-ignore */
|
|
2657
2779
|
...(ngDevMode ? [{ debugName: "resolvedRemoveItemLabel" }] : /* istanbul ignore next */ []));
|
|
2658
|
-
resolvedSelectedItemsLabel = computed(() => (this.config?.selectedItemsLabel ??
|
|
2780
|
+
resolvedSelectedItemsLabel = computed(() => (this.config?.selectedItemsLabel ?? DEFAULT_KT_SELECT_CONFIG.selectedItemsLabel)(this.label()), /* @ts-ignore */
|
|
2659
2781
|
...(ngDevMode ? [{ debugName: "resolvedSelectedItemsLabel" }] : /* istanbul ignore next */ []));
|
|
2660
|
-
resolvedSelectionSummaryText = computed(() => this.config?.selectionSummaryText ??
|
|
2782
|
+
resolvedSelectionSummaryText = computed(() => this.config?.selectionSummaryText ?? DEFAULT_KT_SELECT_CONFIG.selectionSummaryText, /* @ts-ignore */
|
|
2661
2783
|
...(ngDevMode ? [{ debugName: "resolvedSelectionSummaryText" }] : /* istanbul ignore next */ []));
|
|
2662
|
-
resolvedItemRemovedText = computed(() => this.config?.itemRemovedText ??
|
|
2784
|
+
resolvedItemRemovedText = computed(() => this.config?.itemRemovedText ?? DEFAULT_KT_SELECT_CONFIG.itemRemovedText, /* @ts-ignore */
|
|
2663
2785
|
...(ngDevMode ? [{ debugName: "resolvedItemRemovedText" }] : /* istanbul ignore next */ []));
|
|
2664
|
-
resolvedSelectionCountText = computed(() => this.config?.selectionCountText ??
|
|
2786
|
+
resolvedSelectionCountText = computed(() => this.config?.selectionCountText ?? DEFAULT_KT_SELECT_CONFIG.selectionCountText, /* @ts-ignore */
|
|
2665
2787
|
...(ngDevMode ? [{ debugName: "resolvedSelectionCountText" }] : /* istanbul ignore next */ []));
|
|
2666
|
-
resolvedSelectAllLabel = computed(() => this.config?.selectAllLabel ??
|
|
2788
|
+
resolvedSelectAllLabel = computed(() => this.config?.selectAllLabel ?? DEFAULT_KT_SELECT_CONFIG.selectAllLabel, /* @ts-ignore */
|
|
2667
2789
|
...(ngDevMode ? [{ debugName: "resolvedSelectAllLabel" }] : /* istanbul ignore next */ []));
|
|
2668
|
-
resolvedClearAllLabel = computed(() => this.config?.clearAllLabel ??
|
|
2790
|
+
resolvedClearAllLabel = computed(() => this.config?.clearAllLabel ?? DEFAULT_KT_SELECT_CONFIG.clearAllLabel, /* @ts-ignore */
|
|
2669
2791
|
...(ngDevMode ? [{ debugName: "resolvedClearAllLabel" }] : /* istanbul ignore next */ []));
|
|
2670
|
-
resolvedMoreChipsLabel = computed(() => this.config?.moreChipsLabel ??
|
|
2792
|
+
resolvedMoreChipsLabel = computed(() => this.config?.moreChipsLabel ?? DEFAULT_KT_SELECT_CONFIG.moreChipsLabel, /* @ts-ignore */
|
|
2671
2793
|
...(ngDevMode ? [{ debugName: "resolvedMoreChipsLabel" }] : /* istanbul ignore next */ []));
|
|
2672
|
-
resolvedLessChipsLabel = computed(() => this.config?.lessChipsLabel ??
|
|
2794
|
+
resolvedLessChipsLabel = computed(() => this.config?.lessChipsLabel ?? DEFAULT_KT_SELECT_CONFIG.lessChipsLabel, /* @ts-ignore */
|
|
2673
2795
|
...(ngDevMode ? [{ debugName: "resolvedLessChipsLabel" }] : /* istanbul ignore next */ []));
|
|
2674
2796
|
/** Accesseurs bridgés vers le ChipList (fonctions fléchées : une référence de méthode
|
|
2675
2797
|
non liée perdrait `this`). */
|
|
@@ -2860,7 +2982,7 @@ class KtMultiSelect extends KtBaseSelect {
|
|
|
2860
2982
|
this.announceNow(this.resolvedSelectionCountText()(this.selectedOptions().length));
|
|
2861
2983
|
}
|
|
2862
2984
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtMultiSelect, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
2863
|
-
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 (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 (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"], 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 });
|
|
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 });
|
|
2864
2986
|
}
|
|
2865
2987
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtMultiSelect, decorators: [{
|
|
2866
2988
|
type: Component,
|
|
@@ -2874,12 +2996,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
|
|
|
2874
2996
|
Listbox,
|
|
2875
2997
|
Option,
|
|
2876
2998
|
KtChipList,
|
|
2877
|
-
], 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 (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 (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"] }]
|
|
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"] }]
|
|
2878
3000
|
}], 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 }] }] } });
|
|
2879
3001
|
|
|
2880
3002
|
/** Base partagée des champs Temporal (Date/Time/DateTime/YearMonth).
|
|
2881
|
-
Toute la logique commune (parsing tolérant, valeur vide `null`,
|
|
2882
|
-
|
|
3003
|
+
Toute la logique commune (parsing tolérant, valeur vide `null`, synchronisation de l'input natif)
|
|
3004
|
+
vit ici ; chaque sous-classe ne fournit que la construction et la sérialisation propres
|
|
2883
3005
|
à son type Temporal (`fromString` / `serialize`).
|
|
2884
3006
|
|
|
2885
3007
|
Contrat abstrait : une sous-classe implémente uniquement le couple
|
|
@@ -2889,7 +3011,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
|
|
|
2889
3011
|
tolérant (saisie partielle/invalide → `null`, jamais d'exception ni de valeur fausse).
|
|
2890
3012
|
|
|
2891
3013
|
@template T Type Temporal porté par le champ (ex. `Temporal.PlainDate`,
|
|
2892
|
-
`Temporal.PlainTime`, …). Doit exposer `toString()`. La valeur du champ est `T | null`.
|
|
3014
|
+
`Temporal.PlainTime`, …). Doit exposer `toString()`. La valeur du champ est `T | null`.
|
|
3015
|
+
|
|
3016
|
+
@example
|
|
3017
|
+
```ts
|
|
3018
|
+
// Sous-classer : ne fournir que fromString (input natif → T) et serialize (T → input natif).
|
|
3019
|
+
export class KtDateField extends KtBaseTemporalField<Temporal.PlainDate> {
|
|
3020
|
+
protected override fromString(raw: string): Temporal.PlainDate {
|
|
3021
|
+
return Temporal.PlainDate.from(raw);
|
|
3022
|
+
}
|
|
3023
|
+
protected override serialize(value: Temporal.PlainDate): string {
|
|
3024
|
+
return value.toString();
|
|
3025
|
+
}
|
|
3026
|
+
}
|
|
3027
|
+
``` */
|
|
2893
3028
|
class KtBaseTemporalField extends KtBaseInputField {
|
|
2894
3029
|
doc = inject(DOCUMENT);
|
|
2895
3030
|
constructor() {
|
|
@@ -2924,12 +3059,26 @@ class KtBaseTemporalField extends KtBaseInputField {
|
|
|
2924
3059
|
isEmpty(value) {
|
|
2925
3060
|
return value === null;
|
|
2926
3061
|
}
|
|
2927
|
-
/**
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
3062
|
+
/** Borne minimale autorisée (membre `min` du contrat `FormValueControl`, aussi posé en attribut
|
|
3063
|
+
`min` natif via `serialize`). Non bornée par défaut. @default undefined */
|
|
3064
|
+
min = input(/* @ts-ignore */
|
|
3065
|
+
...(ngDevMode ? [undefined, { debugName: "min" }] : /* istanbul ignore next */ []));
|
|
3066
|
+
/** Borne maximale autorisée (membre `max` du contrat `FormValueControl`, aussi posé en attribut
|
|
3067
|
+
`max` natif via `serialize`). Non bornée par défaut. @default undefined */
|
|
3068
|
+
max = input(/* @ts-ignore */
|
|
3069
|
+
...(ngDevMode ? [undefined, { debugName: "max" }] : /* istanbul ignore next */ []));
|
|
3070
|
+
/** Représentation ISO de `min` pour l'attribut natif (`null` quand non borné). */
|
|
3071
|
+
serializedMin = computed(() => {
|
|
3072
|
+
const value = this.min();
|
|
3073
|
+
return value == null ? null : this.serialize(value);
|
|
3074
|
+
}, /* @ts-ignore */
|
|
3075
|
+
...(ngDevMode ? [{ debugName: "serializedMin" }] : /* istanbul ignore next */ []));
|
|
3076
|
+
/** Représentation ISO de `max` pour l'attribut natif (`null` quand non borné). */
|
|
3077
|
+
serializedMax = computed(() => {
|
|
3078
|
+
const value = this.max();
|
|
3079
|
+
return value == null ? null : this.serialize(value);
|
|
2931
3080
|
}, /* @ts-ignore */
|
|
2932
|
-
...(ngDevMode ? [{ debugName: "
|
|
3081
|
+
...(ngDevMode ? [{ debugName: "serializedMax" }] : /* istanbul ignore next */ []));
|
|
2933
3082
|
/** Suggestions proposées via un `<datalist>` natif (le picker date/heure reste disponible).
|
|
2934
3083
|
Valeurs Temporal simples ou couples `{ value, label }` ; chaque valeur est sérialisée au
|
|
2935
3084
|
format de l'input via `serialize`. @default undefined */
|
|
@@ -2943,11 +3092,44 @@ class KtBaseTemporalField extends KtBaseInputField {
|
|
|
2943
3092
|
datalistOptions = computed(() => normalizeKtSuggestions(this.suggestions(), (value) => this.serialize(value)), /* @ts-ignore */
|
|
2944
3093
|
...(ngDevMode ? [{ debugName: "datalistOptions" }] : /* istanbul ignore next */ []));
|
|
2945
3094
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtBaseTemporalField, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2946
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.1", type: KtBaseTemporalField, isStandalone: true, inputs: { suggestions: { classPropertyName: "suggestions", publicName: "suggestions", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0 });
|
|
3095
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.1", type: KtBaseTemporalField, isStandalone: true, inputs: { min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, suggestions: { classPropertyName: "suggestions", publicName: "suggestions", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0 });
|
|
2947
3096
|
}
|
|
2948
3097
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtBaseTemporalField, decorators: [{
|
|
2949
3098
|
type: Directive
|
|
2950
|
-
}], ctorParameters: () => [], propDecorators: { suggestions: [{ type: i0.Input, args: [{ isSignal: true, alias: "suggestions", required: false }] }] } });
|
|
3099
|
+
}], ctorParameters: () => [], propDecorators: { min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], suggestions: [{ type: i0.Input, args: [{ isSignal: true, alias: "suggestions", required: false }] }] } });
|
|
3100
|
+
|
|
3101
|
+
/** Base des champs Temporal porteurs d'une heure (`Time`, `DateTime`, `Instant`). Ajoute le réglage
|
|
3102
|
+
`precision` qui pilote, d'un seul point, la sérialisation (`smallestUnit` du `toString`) et
|
|
3103
|
+
l'attribut `step` natif de l'input — un input `time`/`datetime-local` n'affiche le sélecteur de
|
|
3104
|
+
secondes que si `step` < 60. Les champs sans heure (`Date`, `YearMonth`) n'héritent pas de cette
|
|
3105
|
+
base. Chaque sous-classe lit `precision()` dans son `serialize`.
|
|
3106
|
+
|
|
3107
|
+
@example
|
|
3108
|
+
```ts
|
|
3109
|
+
// Sous-classer : lire precision() dans serialize pour piloter smallestUnit.
|
|
3110
|
+
export class KtTimeField extends KtBaseTimeTemporalField<Temporal.PlainTime> {
|
|
3111
|
+
protected override fromString(raw: string): Temporal.PlainTime {
|
|
3112
|
+
return Temporal.PlainTime.from(raw);
|
|
3113
|
+
}
|
|
3114
|
+
protected override serialize(value: Temporal.PlainTime): string {
|
|
3115
|
+
return value.toString({ smallestUnit: this.precision() });
|
|
3116
|
+
}
|
|
3117
|
+
}
|
|
3118
|
+
``` */
|
|
3119
|
+
class KtBaseTimeTemporalField extends KtBaseTemporalField {
|
|
3120
|
+
/** Précision de l'heure : `'minute'` (secondes masquées) ou `'second'`.
|
|
3121
|
+
@default 'minute' */
|
|
3122
|
+
precision = input('minute', /* @ts-ignore */
|
|
3123
|
+
...(ngDevMode ? [{ debugName: "precision" }] : /* istanbul ignore next */ []));
|
|
3124
|
+
/** Attribut `step` natif : `'1'` (seconde) en précision seconde, sinon `null` (pas natif = minute). */
|
|
3125
|
+
step = computed(() => (this.precision() === 'second' ? '1' : null), /* @ts-ignore */
|
|
3126
|
+
...(ngDevMode ? [{ debugName: "step" }] : /* istanbul ignore next */ []));
|
|
3127
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtBaseTimeTemporalField, deps: null, target: i0.ɵɵFactoryTarget.Directive });
|
|
3128
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.1", type: KtBaseTimeTemporalField, isStandalone: true, inputs: { precision: { classPropertyName: "precision", publicName: "precision", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0 });
|
|
3129
|
+
}
|
|
3130
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtBaseTimeTemporalField, decorators: [{
|
|
3131
|
+
type: Directive
|
|
3132
|
+
}], propDecorators: { precision: [{ type: i0.Input, args: [{ isSignal: true, alias: "precision", required: false }] }] } });
|
|
2951
3133
|
|
|
2952
3134
|
/** Valeur runtime `Temporal` (native ou polyfill). Cast via `unknown` : selon le contexte de
|
|
2953
3135
|
compilation, `globalThis.Temporal` peut déjà être typé (augmentation `temporal-polyfill/global`)
|
|
@@ -2980,11 +3162,11 @@ class KtDateField extends KtBaseTemporalField {
|
|
|
2980
3162
|
return value.toString();
|
|
2981
3163
|
}
|
|
2982
3164
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtDateField, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
2983
|
-
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 (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.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"], outputs: ["helpClick"] }, { kind: "directive", type: KtFieldControl, selector: "[ktFieldControl]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
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 });
|
|
2984
3166
|
}
|
|
2985
3167
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtDateField, decorators: [{
|
|
2986
3168
|
type: Component,
|
|
2987
|
-
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 (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.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" }]
|
|
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" }]
|
|
2988
3170
|
}], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }] } });
|
|
2989
3171
|
|
|
2990
3172
|
/** Champ « heure sans date » : valeur = `Temporal.PlainTime`, input natif `type="time"`.
|
|
@@ -2994,7 +3176,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
|
|
|
2994
3176
|
* <kt-time-field label="Heure de rendez-vous" [(value)]="appointmentTime" />
|
|
2995
3177
|
* ```
|
|
2996
3178
|
*/
|
|
2997
|
-
class KtTimeField extends
|
|
3179
|
+
class KtTimeField extends KtBaseTimeTemporalField {
|
|
2998
3180
|
/** Valeur du champ : un `Temporal.PlainTime` (heure « au mur », sans date ni fuseau).
|
|
2999
3181
|
`null` = champ vide.
|
|
3000
3182
|
@default null */
|
|
@@ -3004,15 +3186,15 @@ class KtTimeField extends KtBaseTemporalField {
|
|
|
3004
3186
|
return Temporal.PlainTime.from(raw);
|
|
3005
3187
|
}
|
|
3006
3188
|
serialize(value) {
|
|
3007
|
-
// Précision
|
|
3008
|
-
return value.toString({ smallestUnit:
|
|
3189
|
+
// Précision pilotée par `precision()` : minute (défaut) ou seconde.
|
|
3190
|
+
return value.toString({ smallestUnit: this.precision() });
|
|
3009
3191
|
}
|
|
3010
3192
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtTimeField, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
3011
|
-
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 (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.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"], outputs: ["helpClick"] }, { kind: "directive", type: KtFieldControl, selector: "[ktFieldControl]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
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 });
|
|
3012
3194
|
}
|
|
3013
3195
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtTimeField, decorators: [{
|
|
3014
3196
|
type: Component,
|
|
3015
|
-
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 (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.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" }]
|
|
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" }]
|
|
3016
3198
|
}], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }] } });
|
|
3017
3199
|
|
|
3018
3200
|
/** Champ « date-heure sans fuseau » : valeur = `Temporal.PlainDateTime`, input
|
|
@@ -3023,7 +3205,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
|
|
|
3023
3205
|
* <kt-date-time-field label="Début de l'événement" [(value)]="startsAt" />
|
|
3024
3206
|
* ```
|
|
3025
3207
|
*/
|
|
3026
|
-
class KtDateTimeField extends
|
|
3208
|
+
class KtDateTimeField extends KtBaseTimeTemporalField {
|
|
3027
3209
|
/** Valeur du champ : un `Temporal.PlainDateTime` (date + heure « au mur », sans fuseau).
|
|
3028
3210
|
`null` = champ vide.
|
|
3029
3211
|
@default null */
|
|
@@ -3033,15 +3215,15 @@ class KtDateTimeField extends KtBaseTemporalField {
|
|
|
3033
3215
|
return Temporal.PlainDateTime.from(raw);
|
|
3034
3216
|
}
|
|
3035
3217
|
serialize(value) {
|
|
3036
|
-
// Précision
|
|
3037
|
-
return value.toString({ smallestUnit:
|
|
3218
|
+
// Précision pilotée par `precision()` : minute (défaut) ou seconde.
|
|
3219
|
+
return value.toString({ smallestUnit: this.precision() });
|
|
3038
3220
|
}
|
|
3039
3221
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtDateTimeField, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
3040
|
-
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 (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.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"], outputs: ["helpClick"] }, { kind: "directive", type: KtFieldControl, selector: "[ktFieldControl]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
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 });
|
|
3041
3223
|
}
|
|
3042
3224
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtDateTimeField, decorators: [{
|
|
3043
3225
|
type: Component,
|
|
3044
|
-
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 (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.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" }]
|
|
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" }]
|
|
3045
3227
|
}], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }] } });
|
|
3046
3228
|
|
|
3047
3229
|
/** Champ « mois/année » (ex. expiration de carte) : valeur = `Temporal.PlainYearMonth`,
|
|
@@ -3065,11 +3247,11 @@ class KtYearMonthField extends KtBaseTemporalField {
|
|
|
3065
3247
|
return value.toString();
|
|
3066
3248
|
}
|
|
3067
3249
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtYearMonthField, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
3068
|
-
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 (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.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"], outputs: ["helpClick"] }, { kind: "directive", type: KtFieldControl, selector: "[ktFieldControl]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
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 });
|
|
3069
3251
|
}
|
|
3070
3252
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtYearMonthField, decorators: [{
|
|
3071
3253
|
type: Component,
|
|
3072
|
-
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 (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.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" }]
|
|
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" }]
|
|
3073
3255
|
}], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }] } });
|
|
3074
3256
|
|
|
3075
3257
|
/** Source unique de l'heure courante et du **fuseau local** de l'utilisateur.
|
|
@@ -3147,7 +3329,7 @@ class KtFixedClock extends KtClock {
|
|
|
3147
3329
|
* <kt-instant-field label="Horodatage" [(value)]="recordedAt" />
|
|
3148
3330
|
* ```
|
|
3149
3331
|
*/
|
|
3150
|
-
class KtInstantField extends
|
|
3332
|
+
class KtInstantField extends KtBaseTimeTemporalField {
|
|
3151
3333
|
clock = inject(KtClock);
|
|
3152
3334
|
/** Valeur du champ : un `Temporal.Instant` (instant absolu en UTC), saisi/affiché en heure
|
|
3153
3335
|
locale via `KtClock`. `null` = champ vide.
|
|
@@ -3159,16 +3341,19 @@ class KtInstantField extends KtBaseTemporalField {
|
|
|
3159
3341
|
fromString(raw) {
|
|
3160
3342
|
return Temporal.PlainDateTime.from(raw).toZonedDateTime(this.clock.timeZoneId()).toInstant();
|
|
3161
3343
|
}
|
|
3162
|
-
// Instant absolu → heure locale
|
|
3344
|
+
// Instant absolu → heure locale ; précision pilotée par `precision()` (minute par défaut).
|
|
3163
3345
|
serialize(value) {
|
|
3164
|
-
return value
|
|
3346
|
+
return value
|
|
3347
|
+
.toZonedDateTimeISO(this.clock.timeZoneId())
|
|
3348
|
+
.toPlainDateTime()
|
|
3349
|
+
.toString({ smallestUnit: this.precision() });
|
|
3165
3350
|
}
|
|
3166
3351
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtInstantField, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
3167
|
-
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 (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.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"], outputs: ["helpClick"] }, { kind: "directive", type: KtFieldControl, selector: "[ktFieldControl]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
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 });
|
|
3168
3353
|
}
|
|
3169
3354
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtInstantField, decorators: [{
|
|
3170
3355
|
type: Component,
|
|
3171
|
-
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 (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.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" }]
|
|
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" }]
|
|
3172
3357
|
}], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }] } });
|
|
3173
3358
|
|
|
3174
3359
|
/** Formate une valeur Temporal pour l'affichage selon la locale active.
|
|
@@ -3188,9 +3373,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
|
|
|
3188
3373
|
* {{ d | temporalDate:{ dateStyle: 'full' } }}
|
|
3189
3374
|
* ```
|
|
3190
3375
|
*/
|
|
3376
|
+
// Exception R1 ASSUMÉE : le name `temporalDate` (non préfixé `kt`) relève du domaine Temporal,
|
|
3377
|
+
// exempté de préfixe au même titre que le namespace `Temporal` et ses alias de types. La CLASSE
|
|
3378
|
+
// reste préfixée (`KtTemporalDatePipe`). Choix ergonomique acté (ADR-4).
|
|
3191
3379
|
class KtTemporalDatePipe {
|
|
3192
3380
|
locale = inject(LOCALE_ID);
|
|
3193
3381
|
clock = inject(KtClock);
|
|
3382
|
+
/** Formate la valeur Temporal en chaîne localisée via `toLocaleString`.
|
|
3383
|
+
* @param value Valeur Temporal à formater (`Plain*`, `Instant` ou `ZonedDateTime`) ; `null`/`undefined` → chaîne vide.
|
|
3384
|
+
* @param options Options `Intl.DateTimeFormatOptions` transmises telles quelles. Styles globaux :
|
|
3385
|
+
* `dateStyle`/`timeStyle` (`'full' | 'long' | 'medium' | 'short'`). Champs fins :
|
|
3386
|
+
* `weekday`/`era`/`month` (`'long' | 'short' | 'narrow'`), `year`/`day`/`hour`/`minute`/`second`
|
|
3387
|
+
* (`'numeric' | '2-digit'`), `hour12`, `timeZoneName`, `timeZone`, etc. Omis → format par défaut de la locale.
|
|
3388
|
+
* @returns La chaîne formatée selon la locale active (`LOCALE_ID`), ou `''` si la valeur est absente. */
|
|
3194
3389
|
transform(value, options) {
|
|
3195
3390
|
if (value == null)
|
|
3196
3391
|
return '';
|
|
@@ -3211,5 +3406,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
|
|
|
3211
3406
|
* Generated bundle index. Do not edit.
|
|
3212
3407
|
*/
|
|
3213
3408
|
|
|
3214
|
-
export { KT_CHIPS_CONFIG, KT_FIELD, KT_FIELD_CONFIG, KT_SELECT_CONFIG, KtBaseTemporalField, 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, defaultKtFieldErrorMatcher };
|
|
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 };
|
|
3215
3410
|
//# sourceMappingURL=ktortu-aaa-forms.mjs.map
|