@edugouvfr/ngx-dsfr-ext
Version:
NgxDsfrExt est une extension au package @edugouvfr/ngx-dsfr (portage Angular des éléments DSFR)
715 lines (703 loc) • 795 kB
JavaScript
import * as i3 from '@angular/cdk/scrolling';
import { ScrollingModule, CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
import * as i1 from '@angular/common';
import { CommonModule } from '@angular/common';
import * as i0 from '@angular/core';
import { EventEmitter, inject, ElementRef, NgZone, Renderer2, Output, Directive, input, afterNextRender, Input, booleanAttribute, ContentChild, ViewChild, ViewEncapsulation, Component, HostBinding, signal, computed, ChangeDetectorRef, effect, forwardRef, numberAttribute, ChangeDetectionStrategy, TemplateRef, HostListener, viewChild, contentChildren, viewChildren, linkedSignal, Injectable, afterRenderEffect, model, InjectionToken, ViewContainerRef, DestroyRef, inputBinding, outputBinding, Pipe } from '@angular/core';
import * as i2 from '@angular/forms';
import { FormsModule, ReactiveFormsModule, NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms';
import * as i2$1 from '@edugouvfr/ngx-dsfr';
import { DsfrSeverityConst, DsfrI18nService, Language, DsfrSizeConst, DsfrI18nPipe, DefaultControlComponent, newUniqueId, DsfrFormInputModule, DsfrButtonModule, DsfrTagModule, jsonPath2Value, LangService, LoggerService, DsfrFormSelectModule, DefaultValueAccessorComponent, DsfrFormInputComponent, DsfrFormFieldsetComponent, DsfrFormFieldsetElementDirective, DsfrButtonComponent, DsfrLinkComponent, DsfrLinkModule, EduCheckboxLightComponent, DsfrCardModule, DsfrButtonsGroupModule, DsfrTableComponent, DsfrDataTableModule, DsfrDataTableService, DsfrUploadModule } from '@edugouvfr/ngx-dsfr';
export { DsfrUserMenuComponent as DsfrProfileMenuComponent, DsfrToolLinkMenuComponent as DsfrToolsMenuComponent } from '@edugouvfr/ngx-dsfr';
import { Subject, debounceTime, distinctUntilChanged, takeUntil, Subscription, map } from 'rxjs';
import * as i1$1 from '@angular/cdk/a11y';
import { A11yModule } from '@angular/cdk/a11y';
import { BreakpointObserver } from '@angular/cdk/layout';
import { toSignal } from '@angular/core/rxjs-interop';
import * as i2$2 from '@angular/router';
import { RouterModule } from '@angular/router';
/**
* Directive pour détecter un click en dehors du composant (ex. pour fermer une liste déroulante)
* Nécessite l'ajout d'un attribut data-expanded sur le composant possedant clickOutside
*/
class EduClickOutsideDirective {
constructor() {
this.clickOutsideEvent = new EventEmitter();
this._unlisten = [];
this._elementRef = inject(ElementRef);
this.ngZone = inject(NgZone);
this.renderer2 = inject(Renderer2);
}
ngOnInit() {
this.ngZone.runOutsideAngular(() => {
this._unlisten.push(this.renderer2.listen('window', 'mouseup', (e) => {
this.onDocumentClick(e);
}), this.renderer2.listen('window', 'resize', (e) => {
this.onDocumentResize(e);
}));
});
}
ngOnDestroy() {
this._unlisten.forEach((unlistenFunc) => unlistenFunc());
}
/**
* En cas de redimensionnement ou de zoom de la fenetre
* Si on est en mode appendTo, on force la fermeture de la dropdown pour eviter son mauvais positionnement
* @internal */
onDocumentResize(e) {
if (this._elementRef.nativeElement.hasAttribute('data-expanded') &&
!this._elementRef.nativeElement.querySelector('ul.dsfrx-treeselect__list') &&
!this._elementRef.nativeElement.querySelector('ul.dsfrx-select__list')) {
this.onNeedToCloseDropdown(e);
}
}
/**
* Emet l'evenement click outside en cas de clic en dehors du composant
* @internal */
onDocumentClick(e) {
const elem = e?.target;
// positionnement d'un attribut data-expanded qui indique l'affiche de la liste sur le composant
if (elem &&
this._elementRef.nativeElement.hasAttribute('data-expanded') &&
!this._elementRef.nativeElement.contains(elem) &&
!elem.closest('.dsfrx-dropdown')) {
this.onNeedToCloseDropdown(e);
}
}
/** Emet l'evenement clickOutsideEvent pour forcer la fermeture de la dropdown */
onNeedToCloseDropdown(e) {
this.ngZone.run(() => {
e.preventDefault();
this.clickOutsideEvent.emit();
});
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: EduClickOutsideDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.24", type: EduClickOutsideDirective, isStandalone: true, selector: "[clickOutside]", outputs: { clickOutsideEvent: "clickOutsideEvent" }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: EduClickOutsideDirective, decorators: [{
type: Directive,
args: [{
selector: '[clickOutside]',
standalone: true,
}]
}], propDecorators: { clickOutsideEvent: [{
type: Output
}] } });
class ListToolbarUtils {
constructor() { }
/**
* cas TAB : L'élément est le dernier élément focusable de la toolbar :
* - l'élément est la croix pour vider la recherche
* - l'élément est la barre de recherche et la croix n'est pas présente
* - la barre de recherche n'est pas présente (un seul élément focusable : tout sélectionner)
*/
static isLastFocusableOnToolBar(element, toolBarWrapper) {
return (element.className.includes('fr-icon-close-line') ||
(!toolBarWrapper.querySelector('.fr-icon-close-line') && element.className.includes('fr-input')) ||
!toolBarWrapper.querySelector('.fr-input'));
}
}
class DropdownUtils {
constructor() { }
/**
* Si appendTo est défini, trouver le container auquel le rattacher (element ou classe)
* Si le container parent ne correspond ni au body ni à une modale, le placer en position relative
* */
static setParentContainer(appendTo, comboBox) {
let containerToAttach = undefined;
if (appendTo === 'body') {
containerToAttach = document.querySelector('body');
}
else {
if (typeof appendTo === 'string') {
const elem = comboBox.closest(`.${appendTo}`);
containerToAttach = elem ?? undefined;
}
else {
containerToAttach = appendTo;
}
if (!containerToAttach) {
console.warn('`appendTo` must be equal to `body`, an element ref or a class of an ancestor container');
}
if (containerToAttach && !DropdownUtils.isBodyOrFixedElement(containerToAttach)) {
// surcharge du style de l'élément parent avec position relative si appendTo !== body
containerToAttach.style.position = 'relative';
}
}
return containerToAttach;
}
/**
* Get viewport for overlay position
* From primeNG */
static getViewport() {
const win = window, d = document, e = d.documentElement, g = d.getElementsByTagName('body')[0], w = win.innerWidth || e.clientWidth || g.clientWidth, h = win.innerHeight || e.clientHeight || g.clientHeight;
return { width: w, height: h };
}
/**
* Get scroll from top for overlay position
* From primeNG */
static getWindowScrollTop() {
const doc = document.documentElement;
return (window.scrollY || doc.scrollTop) - (doc.clientTop || 0);
}
static isBodyOrFixedElement(container) {
return container.tagName === 'BODY' || container.tagName === 'DIALOG' || container.style.position === 'fixed';
}
}
class DsfrDropdownPositionDirective {
/**
* Ajoute l'élément dropdown et le repositionne
* /!\ ne pas utiliser un effect() : le cycle de rendu est différent entre angular 17 et angular 19,
* le composant ne sera pas encore ajouté dans le DOM en angular 19.
*/
constructor() {
this.autoWidth = false;
/** Emission après attachement de la dropdown au parentContainer en appendTo */
this.appendDropdown = new EventEmitter();
this.comboBox = input.required(...(ngDevMode ? [{ debugName: "comboBox" }] : []));
this.dropdownRef = inject((ElementRef));
this._renderer = inject(Renderer2);
afterNextRender(() => {
if (this.dropdownRef) {
if (this.parentContainer) {
this.appendElement(this.dropdownRef.nativeElement);
}
this.setPosition(this.dropdownRef.nativeElement);
this.appendDropdown.emit();
}
});
}
/** A la destruction du composant, supprimer l'élément listbox si il a été ajouté au parent ou body (appendTo) */
ngOnDestroy() {
if (this.parentContainer && this.dropdownRef) {
this.destroyOverlayDropdown();
}
}
setPosition(dropdownElement) {
const viewport = DropdownUtils.getViewport();
let comboBox = this.comboBox(); //box container to attach to
if (dropdownElement) {
const top = this.calcPositionY(dropdownElement, comboBox, viewport.height);
this._renderer.setStyle(dropdownElement, 'top', top);
// Ajuster la hauteur (marginTop) en cas d'éléments messages présents à l'interieur de la comboBox
const marginTopOffset = this.adjustMarginTop(comboBox);
this._renderer.setStyle(dropdownElement, 'margin-top', `${marginTopOffset}rem`);
// Calculer le positionnement en valeur absolue
if (this.autoWidth || this.parentContainer) {
const left = this.calcPositionX(dropdownElement, comboBox, viewport.width);
this._renderer.setStyle(dropdownElement, 'left', left);
if (this.parentContainer && marginTopOffset) {
this._renderer.setStyle(dropdownElement, 'margin-top', `${marginTopOffset}rem`);
}
}
}
}
/**
* Calcul de la position verticale de la dropdown
* - selon la place disponible (en dessous / au dessus)
* - en valeur absolue selon le container parent (si appendTo)
* @param dropdown dropdown a positionner
* @param comboBox container auquel rattacher la dropdown visuellement
* @param viewportHeight
* @returns nouvelle position en string (px/auto)
*/
calcPositionY(dropdown, comboBox, viewportHeight) {
let top = 'auto';
const dropdownHeight = dropdown.offsetHeight; // hauteur de mon dropdownElement // ELEMENTOUTERHEIGHT
const comboBoxOffset = comboBox.getBoundingClientRect(); // position de ma box container (ex. select)
const windowScrollTop = DropdownUtils.getWindowScrollTop();
// si position de ma box container + hauteur de ma box container + hauteur de mon dropdownElement inférieur a hauteur disponible
const canDisplayBelow = comboBoxOffset.top + comboBox.offsetHeight + dropdownHeight < viewportHeight;
let calcPos = 0;
if (this.parentContainer) {
// calcul de la position si appendTo en fonction du container passé en parametre
calcPos = this.computeTopPositionRelative(comboBox, this.parentContainer);
top = `${calcPos}px`;
}
if (!canDisplayBelow) {
// si il n'y a pas assez de place pour afficher au-dessus, on laisse en dessous par défaut
const candisplayAbove = comboBoxOffset.top + windowScrollTop - dropdownHeight > 0;
// TODO FIX BETTER -- fix pour la hauteur de l'input qui n'est pas la bonne a cause de l'ensemble combobox
let diff = 0;
let input = comboBox.querySelector('.fr-input');
if (input) {
diff = comboBox.offsetHeight - input.getBoundingClientRect().height;
}
// ----------------------
if (candisplayAbove) {
// calcul de la position en fonction de appendTo (container to attach)
calcPos = this.parentContainer
? calcPos + diff - dropdownHeight - comboBox.offsetHeight
: -dropdownHeight + diff;
top = `${calcPos}px`; // afficher au dessus du combobox
}
}
return top;
}
/**
* Calcul de la position horizontale de la dropdown
* - selon la place disponible (décalage à gauche éventuel)
* - en valeur absolue selon le container parent (si appendTo)
* @param dropdown dropdown a positionner
* @param comboBox container auquel rattacher la dropdown visuellement
* @param viewportWidth
* @returns nouvelle position en string (px/auto)
*/
calcPositionX(dropdown, comboBox, viewportWidth) {
const elementOuterWidth = dropdown.offsetWidth;
const comboBoxOffset = comboBox.getBoundingClientRect(); // position de ma box container (ex. select)
if (this.autoWidth) {
if (comboBoxOffset.left + elementOuterWidth > viewportWidth) {
return this.parentContainer
? Math.max(0, comboBoxOffset.left + comboBox.offsetWidth - elementOuterWidth) + 'px'
: comboBox.offsetWidth - elementOuterWidth + 'px';
}
}
if (this.parentContainer && DropdownUtils.isBodyOrFixedElement(this.parentContainer)) {
// decalage a droite en cas de body
return comboBox.getBoundingClientRect().left + 'px';
}
else if (this.parentContainer && comboBox.offsetLeft > 0) {
return comboBox.offsetLeft + 'px';
}
return 'auto';
}
/**
* Compute top position relative to parent element (top position, margin/padding, scroll inside parent)
* @param element element to move relatively
* @param parentElement parent container
* @returns new top position
*/
computeTopPositionRelative(element, parentElement) {
if (DropdownUtils.isBodyOrFixedElement(parentElement)) {
return (element.getBoundingClientRect().top +
element.offsetHeight +
(parentElement.tagName === 'BODY' ? window.scrollY : 0));
}
return (element.getBoundingClientRect().top +
element.offsetHeight +
parentElement.scrollTop -
parentElement.getBoundingClientRect().top);
}
/**
* Ajouter l'element dropdown directement au body ou container spécifié dans le cas de appendTo
* Permet d'afficher la dropdown "en dehors" d'un container visuel type modale ou accordéon (pas de scroll)
* @param element dropdown
*/
appendElement(element) {
const box = this.comboBox();
if (!this.autoWidth) {
this._renderer.setStyle(element, 'width', `${box.offsetWidth}px`);
}
this._renderer.setStyle(element, 'top', `0px`); // obligatoire pour positionner correctement l'element ensuite
// Attach element to new parent
this._renderer.appendChild(this.parentContainer, element);
}
/** Suppression de la liste rattachée au container appendTo */
destroyOverlayDropdown() {
if (this.dropdownRef.nativeElement?.parentElement === this.parentContainer) {
this._renderer.removeChild(this.parentContainer, this.dropdownRef.nativeElement);
}
if (this._unlistenFn)
this._unlistenFn();
}
/**
* Réajuster la marge supérieure de la dropdown en cas de fieldset ou de messages groupe
*/
adjustMarginTop(comboBox) {
const hasInputGroupWithMessage = !!comboBox.querySelector('.fr-input-group .fr-message');
const hasFieldsetWithMessage = !!comboBox.querySelector('.fr-fieldset .fr-message');
if (!hasInputGroupWithMessage && !hasFieldsetWithMessage)
return 0;
const messageElemList = comboBox.querySelectorAll('.fr-messages-group');
const messageElem = messageElemList[messageElemList.length - 1]; // on prend le dernier pour supporter le cas du fieldset
const heightMessagePx = messageElem ? messageElem.getBoundingClientRect().height : 0;
let heightMessageRem = this.pxToRem(heightMessagePx);
if (hasInputGroupWithMessage) {
// si on se trouve dans le cas d'un input-group on doit ajouter la valeur de la marge haute soit 1rem
heightMessageRem = 1 + heightMessageRem;
}
// et on bascule en négatif
return heightMessageRem * -1;
}
pxToRem(pixelNumber, base = 16) {
return (1 / base) * pixelNumber;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: DsfrDropdownPositionDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.24", type: DsfrDropdownPositionDirective, isStandalone: true, selector: "[dsfrxDropdown]", inputs: { autoWidth: { classPropertyName: "autoWidth", publicName: "autoWidth", isSignal: false, isRequired: false, transformFunction: null }, parentContainer: { classPropertyName: "parentContainer", publicName: "parentContainer", isSignal: false, isRequired: false, transformFunction: null }, comboBox: { classPropertyName: "comboBox", publicName: "comboBox", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { appendDropdown: "appendDropdown" }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: DsfrDropdownPositionDirective, decorators: [{
type: Directive,
args: [{
selector: '[dsfrxDropdown]',
standalone: true,
}]
}], ctorParameters: () => [], propDecorators: { autoWidth: [{
type: Input
}], parentContainer: [{
type: Input
}], appendDropdown: [{
type: Output
}], comboBox: [{ type: i0.Input, args: [{ isSignal: true, alias: "comboBox", required: true }] }] } });
class DropdownContainerComponent {
constructor() {
/** Activer le virtual scroll */
this.virtualScroll = false;
/** Surcharger la hauteur d'un item dans le cas du virtual scroll. Par défaut 24px. */
this.virtualScrollItemHeight = 24;
this.hasOptions = false;
/** Hauteur maximale avant le scroll sur la liste déroulante. */
this.scrollHeight = '224px';
this.hasToolBar = false;
this.indexFirstSelected = null;
/** Set focus on list on opening */
this.autofocus = false;
/** La dropdown prend la taille des éléments qu'il contient (par défaut : taille du select) */
this.autoWidthDropdown = false;
this.hideList = new EventEmitter();
this.focusOnList = new EventEmitter();
this.dropdownAttached = new EventEmitter(); // la box est append et positionnée
this._displayDropdown = false;
this._renderer = inject(Renderer2);
// Recherche du container parent apres initialisation complete du DOM (= afterViewInit non suffisant)
afterNextRender(() => {
if (!this.listbox && this.listOptionsComponent?.listbox) {
this.listbox = this.listOptionsComponent.listbox;
}
if (this.appendTo && this.controlElement) {
this.containerToAttach = DropdownUtils.setParentContainer(this.appendTo, this.controlElement);
}
});
}
get displayDropdown() {
return this._displayDropdown;
}
/* Element auquel attacher visuellement le container de la dropdown (ex. la combobox contenant le fr-select) */
get controlElement() {
return this.customControlElement ? this.customControlElement : this.comboBox?.nativeElement;
}
set displayDropdown(value) {
this._displayDropdown = value;
if (!this.displayDropdown && this.comboBox && this.autofocus) {
this.comboBox.nativeElement?.querySelector('.fr-select')?.focus();
}
}
/**
* Fermer la liste déroulante en cas de clic en dehors du composant et detruire le composant si il a été ajouté en appendTo
* @internal */
onClickOutside() {
this.hideList.emit();
}
/** La dropdown est visible et positionnée */
onDropdownAttached() {
this.dropdownAttached.emit();
this.setFocus();
}
/**
* Positionne le focus sur la toolbar si elle existe ou un élément de la liste à l'ouverture de la dropdown
* @internal */
setFocus() {
if (!this.autofocus)
return;
if (this.hasToolBar && !this._toolBarFirstElement && this.toolbarWrapper) {
const elem = this.toolbarWrapper.nativeElement.querySelector('.fr-btn--select-all');
this._toolBarFirstElement = elem ? elem : this.toolbarWrapper.nativeElement.querySelector('.fr-input');
}
if (this.listbox && !this.hasToolBar) {
this.focusOnListElement();
}
else if (this._toolBarFirstElement) {
this._toolBarFirstElement.focus();
}
}
/**
* Gestion des événements clavier sur la toolbar
* - "flèche bas" : le focus est positionné sur la liste.
* - "TAB" : si dernier élément focusable de la toolbar, fermer la dropdown et aller sur l'element suivant
* - "SHIFT TAB": si premier élément focusable de la toolbar, fermer la dropdown et aller sur l'element suivant
* - "ECHAP" : fermer la dropdown et conserver le focus sur le select
*/
onKeyDownToolbar(event) {
switch (event.key) {
case 'ArrowDown':
if (this.listbox) {
event.preventDefault();
this.focusOnListElement();
}
break;
case 'Tab':
if ((event.shiftKey && event.target == this._toolBarFirstElement) ||
(!event.shiftKey &&
ListToolbarUtils.isLastFocusableOnToolBar(event.target, this.toolbarWrapper?.nativeElement))) {
this.hideList.emit();
}
break;
case 'Escape':
event.preventDefault();
this.controlElement.querySelector('.fr-select')?.focus();
this.hideList.emit();
break;
}
}
/**
* Positionne le focus sur un élément de la liste lors de l'ouverture ou après "flèche bas" depuis le champ de recherche.
* - Si un élément est déjà sélectionné, le focus est positionné sur celui-ci.
* - Sinon, le focus est placé sur le premier élément de la liste.
*/
focusOnListElement() {
if (!this.listbox)
return;
// en virtualScroll le premier container est cdk-virtualscroll
const listboxNode = this.virtualScroll
? this.listbox.nativeElement?.querySelector('ul')
: this.listbox.nativeElement;
let elementToFocus = listboxNode?.firstElementChild;
if (this.indexFirstSelected && this.indexFirstSelected !== -1) {
elementToFocus = listboxNode?.children[this.indexFirstSelected] ?? listboxNode?.firstElementChild;
}
if (elementToFocus) {
this.setAriaActiveDescendant(listboxNode, elementToFocus.getAttribute('id'));
elementToFocus.focus();
this.focusOnList.emit(elementToFocus);
}
}
/**
* Attribut aria-activedescendant sur l'input égal à l'option qui a le focus
* @internal */
setAriaActiveDescendant(listboxNode, optionId) {
if (optionId && listboxNode.getAttribute('role')) {
this._renderer.setAttribute(listboxNode, 'aria-activedescendant', optionId);
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: DropdownContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.24", type: DropdownContainerComponent, isStandalone: true, selector: "edu-dropdown-container", inputs: { virtualScroll: ["virtualScroll", "virtualScroll", booleanAttribute], virtualScrollItemHeight: "virtualScrollItemHeight", appendTo: "appendTo", hasOptions: ["hasOptions", "hasOptions", booleanAttribute], zIndex: "zIndex", scrollHeight: "scrollHeight", classToWrap: "classToWrap", hasToolBar: ["hasToolBar", "hasToolBar", booleanAttribute], indexFirstSelected: "indexFirstSelected", autofocus: ["autofocus", "autofocus", booleanAttribute], autoWidthDropdown: ["autoWidthDropdown", "autoWidthDropdown", booleanAttribute], customControlElement: "customControlElement", displayDropdown: "displayDropdown" }, outputs: { hideList: "hideList", focusOnList: "focusOnList", dropdownAttached: "dropdownAttached" }, queries: [{ propertyName: "listbox", first: true, predicate: ["listbox"], descendants: true }, { propertyName: "listOptionsComponent", first: true, predicate: ["listOptionsComponent"], descendants: true }], viewQueries: [{ propertyName: "comboBox", first: true, predicate: ["combobox"], descendants: true }, { propertyName: "toolbarWrapper", first: true, predicate: ["toolbarWrapper"], descendants: true }], ngImport: i0, template: "<div\n #combobox\n [attr.data-expanded]=\"displayDropdown ? displayDropdown : null\"\n clickOutside\n class=\"{{ classToWrap }}\"\n (clickOutsideEvent)=\"onClickOutside()\">\n <ng-content select=\"control\"></ng-content>\n\n @if (displayDropdown) {\n <div\n #dropdown\n dsfrxDropdown\n (appendDropdown)=\"onDropdownAttached()\"\n [comboBox]=\"controlElement\"\n [parentContainer]=\"containerToAttach\"\n [autoWidth]=\"autoWidthDropdown\"\n [ngClass]=\"{ 'dsfrx-dropdown--auto-width': autoWidthDropdown }\"\n class=\"dsfrx-dropdown\"\n [ngStyle]=\"{ 'z-index': zIndex }\">\n @if (hasToolBar) {\n <div #toolbarWrapper (keydown)=\"onKeyDownToolbar($event)\" class=\"{{ classToWrap }}__toolbar\">\n <ng-content select=\"[toolbar]\"></ng-content>\n </div>\n }\n <ng-content select=\"empty\"> </ng-content>\n <ng-content></ng-content>\n </div>\n }\n</div>\n", styles: [".dsfrx-dropdown{position:absolute;left:auto;top:auto;width:100%;z-index:2001;container-type:inline-size;background-color:var(--background-overlap-grey);filter:drop-shadow(var(--overlap-shadow))}.dsfrx-dropdown edu-list-options:not(.dsfrx-select__list--disabled) .dsfrx-select__item:focus-visible{outline:none}.dsfrx-dropdown--auto-width{min-width:fit-content;container-type:initial;width:auto}.dsfrx-multiselect{display:block;position:relative}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: EduClickOutsideDirective, selector: "[clickOutside]", outputs: ["clickOutsideEvent"] }, { kind: "directive", type: DsfrDropdownPositionDirective, selector: "[dsfrxDropdown]", inputs: ["autoWidth", "parentContainer", "comboBox"], outputs: ["appendDropdown"] }], encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: DropdownContainerComponent, decorators: [{
type: Component,
args: [{ selector: 'edu-dropdown-container', encapsulation: ViewEncapsulation.None, imports: [
CommonModule,
FormsModule,
ReactiveFormsModule,
ScrollingModule,
EduClickOutsideDirective,
DsfrDropdownPositionDirective,
], template: "<div\n #combobox\n [attr.data-expanded]=\"displayDropdown ? displayDropdown : null\"\n clickOutside\n class=\"{{ classToWrap }}\"\n (clickOutsideEvent)=\"onClickOutside()\">\n <ng-content select=\"control\"></ng-content>\n\n @if (displayDropdown) {\n <div\n #dropdown\n dsfrxDropdown\n (appendDropdown)=\"onDropdownAttached()\"\n [comboBox]=\"controlElement\"\n [parentContainer]=\"containerToAttach\"\n [autoWidth]=\"autoWidthDropdown\"\n [ngClass]=\"{ 'dsfrx-dropdown--auto-width': autoWidthDropdown }\"\n class=\"dsfrx-dropdown\"\n [ngStyle]=\"{ 'z-index': zIndex }\">\n @if (hasToolBar) {\n <div #toolbarWrapper (keydown)=\"onKeyDownToolbar($event)\" class=\"{{ classToWrap }}__toolbar\">\n <ng-content select=\"[toolbar]\"></ng-content>\n </div>\n }\n <ng-content select=\"empty\"> </ng-content>\n <ng-content></ng-content>\n </div>\n }\n</div>\n", styles: [".dsfrx-dropdown{position:absolute;left:auto;top:auto;width:100%;z-index:2001;container-type:inline-size;background-color:var(--background-overlap-grey);filter:drop-shadow(var(--overlap-shadow))}.dsfrx-dropdown edu-list-options:not(.dsfrx-select__list--disabled) .dsfrx-select__item:focus-visible{outline:none}.dsfrx-dropdown--auto-width{min-width:fit-content;container-type:initial;width:auto}.dsfrx-multiselect{display:block;position:relative}\n"] }]
}], ctorParameters: () => [], propDecorators: { comboBox: [{
type: ViewChild,
args: ['combobox']
}], toolbarWrapper: [{
type: ViewChild,
args: ['toolbarWrapper']
}], listbox: [{
type: ContentChild,
args: ['listbox']
}], listOptionsComponent: [{
type: ContentChild,
args: ['listOptionsComponent']
}], virtualScroll: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], virtualScrollItemHeight: [{
type: Input
}], appendTo: [{
type: Input
}], hasOptions: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], zIndex: [{
type: Input
}], scrollHeight: [{
type: Input
}], classToWrap: [{
type: Input
}], hasToolBar: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], indexFirstSelected: [{
type: Input
}], autofocus: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], autoWidthDropdown: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], customControlElement: [{
type: Input
}], hideList: [{
type: Output
}], focusOnList: [{
type: Output
}], dropdownAttached: [{
type: Output
}], displayDropdown: [{
type: Input
}] } });
/**
*/
class EduMessageSeverityDirective {
constructor() {
this._severity = null;
}
get className() {
switch (this._severity) {
case DsfrSeverityConst.ERROR:
return 'fr-message fr-message--error';
case DsfrSeverityConst.SUCCESS:
case DsfrSeverityConst.VALID:
return 'fr-message fr-message--valid';
case DsfrSeverityConst.INFO:
return 'fr-message fr-message--info';
case DsfrSeverityConst.WARNING:
return 'fr-message fr-message--warning';
default:
return 'fr-message ';
}
}
set severity(value) {
if (value)
this._severity = value;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: EduMessageSeverityDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.24", type: EduMessageSeverityDirective, isStandalone: true, selector: "[eduMessageSeverity]", inputs: { severity: ["eduMessageSeverity", "severity"] }, host: { properties: { "class": "this.className" } }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: EduMessageSeverityDirective, decorators: [{
type: Directive,
args: [{ selector: '[eduMessageSeverity]', standalone: true }]
}], propDecorators: { className: [{
type: HostBinding,
args: ['class']
}], severity: [{
type: Input,
args: ['eduMessageSeverity']
}] } });
// Ordre alphabétique requis
const MESSAGES_EN$b = {
spinner: {
messageContext: 'Loading',
},
};
// Ordre alphabétique requis
const MESSAGES_FR$b = {
spinner: {
messageContext: 'Chargement en cours',
},
};
class DsfrSpinnerComponent {
constructor() {
/**
* Type de loader.
*/
this.typeLoader = 'sun';
/**
* Permet de masquer visuellement le libellé fourni par la propriété `label`.
*
* ⚠️ Changement depuis 1.6.0, cette propriété ne sert plus à fournir le libellé accessible : les types `string` et
* `undefined` sont dépréciés au profit d'un type `boolean` permettant de masquer le libellé (par défaut à `true`).
*/
this.labelSrOnly = true;
/**
* Ajoute un overlay fullscreen.
*/
this.overlay = false;
/**
* Permet le changement de taille du spinner.
*/
this.spinnerSize = `SM`;
this.i18n = inject(DsfrI18nService);
this.i18n.extendsLabelsBundle(Language.EN, MESSAGES_EN$b);
this.i18n.extendsLabelsBundle(Language.FR, MESSAGES_FR$b);
}
getSpinnerClasses() {
return {
'dsfrx-spinner': true,
'dsfrx-spinner--sun': this.typeLoader === 'sun',
'dsfrx-spinner--quarter': this.typeLoader === 'quarter',
'dsfrx-spinner--line': this.typeLoader === 'line',
'dsfrx-spinner--sm': this.spinnerSize === DsfrSizeConst.SM,
'dsfrx-spinner--md': this.spinnerSize === DsfrSizeConst.MD,
'dsfrx-spinner--lg': this.spinnerSize === DsfrSizeConst.LG,
};
}
isNonEmptyString(value) {
return typeof value === 'string' && value.length > 0;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: DsfrSpinnerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.24", type: DsfrSpinnerComponent, isStandalone: true, selector: "dsfr-ext-spinner, dsfrx-spinner", inputs: { typeLoader: "typeLoader", label: "label", labelSrOnly: "labelSrOnly", overlay: "overlay", spinnerSize: "spinnerSize" }, ngImport: i0, template: "@if (overlay) {\n <div class=\"dsfrx-overlay\" aria-busy=\"true\">\n <div class=\"content\">\n <ng-container *ngTemplateOutlet=\"spinner\"></ng-container>\n </div>\n </div>\n} @else {\n <ng-container *ngTemplateOutlet=\"spinner\"></ng-container>\n}\n\n<ng-template #spinner>\n <div [ngClass]=\"getSpinnerClasses()\">\n @switch (typeLoader) {\n @default {\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\">\n <path\n d=\"M11.9995 2C12.5518 2 12.9995 2.44772 12.9995 3V6C12.9995 6.55228 12.5518 7 11.9995 7C11.4472 7 10.9995 6.55228 10.9995 6V3C10.9995 2.44772 11.4472 2 11.9995 2ZM11.9995 17C12.5518 17 12.9995 17.4477 12.9995 18V21C12.9995 21.5523 12.5518 22 11.9995 22C11.4472 22 10.9995 21.5523 10.9995 21V18C10.9995 17.4477 11.4472 17 11.9995 17ZM20.6597 7C20.9359 7.47829 20.772 8.08988 20.2937 8.36602L17.6956 9.86602C17.2173 10.1422 16.6057 9.97829 16.3296 9.5C16.0535 9.02171 16.2173 8.41012 16.6956 8.13398L19.2937 6.63397C19.772 6.35783 20.3836 6.52171 20.6597 7ZM7.66935 14.5C7.94549 14.9783 7.78161 15.5899 7.30332 15.866L4.70525 17.366C4.22695 17.6422 3.61536 17.4783 3.33922 17C3.06308 16.5217 3.22695 15.9101 3.70525 15.634L6.30332 14.134C6.78161 13.8578 7.3932 14.0217 7.66935 14.5ZM20.6597 17C20.3836 17.4783 19.772 17.6422 19.2937 17.366L16.6956 15.866C16.2173 15.5899 16.0535 14.9783 16.3296 14.5C16.6057 14.0217 17.2173 13.8578 17.6956 14.134L20.2937 15.634C20.772 15.9101 20.9359 16.5217 20.6597 17ZM7.66935 9.5C7.3932 9.97829 6.78161 10.1422 6.30332 9.86602L3.70525 8.36602C3.22695 8.08988 3.06308 7.47829 3.33922 7C3.61536 6.52171 4.22695 6.35783 4.70525 6.63397L7.30332 8.13398C7.78161 8.41012 7.94549 9.02171 7.66935 9.5Z\" />\n </svg>\n }\n @case ('quarter') {\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\">\n <path d=\"M12 3C16.9706 3 21 7.02944 21 12H19C19 8.13401 15.866 5 12 5V3Z\"></path>\n </svg>\n }\n @case ('line') {\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\">\n <path\n d=\"M18.364 5.63604L16.9497 7.05025C15.683 5.7835 13.933 5 12 5C8.13401 5 5 8.13401 5 12C5 15.866 8.13401 19 12 19C15.866 19 19 15.866 19 12H21C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C14.4853 3 16.7353 4.00736 18.364 5.63604Z\"></path>\n </svg>\n }\n }\n </div>\n @if (label) {\n <span [ngClass]=\"{ 'fr-sr-only': labelSrOnly === true }\">{{ label }}</span>\n } @else {\n <span class=\"fr-sr-only\">{{\n isNonEmptyString(labelSrOnly) ? labelSrOnly : ('spinner.messageContext' | dsfrI18n)\n }}</span>\n }\n</ng-template>\n", styles: ["dsfrx-spinner,dsfr-ext-spinner{display:inline-flex;flex-direction:column;align-items:center}dsfrx-spinner .dsfrx-overlay,dsfr-ext-spinner .dsfrx-overlay{position:fixed;display:flex;align-items:center;justify-content:center;inset:0;background-color:#161616a3;z-index:9999;cursor:not-allowed}dsfrx-spinner .dsfrx-overlay .content,dsfr-ext-spinner .dsfrx-overlay .content{display:inline-flex;flex-direction:column;align-items:center;min-width:3.5rem;min-height:3.5rem;padding:.5rem 1rem;background-color:var(--background-lifted-grey)}dsfrx-spinner .dsfrx-overlay .dsfrx-spinner,dsfr-ext-spinner .dsfrx-overlay .dsfrx-spinner{width:2.5rem;height:2.5rem}dsfrx-spinner .dsfrx-spinner,dsfr-ext-spinner .dsfrx-spinner{width:2rem;height:2rem;fill:var(--background-action-high-blue-france)}dsfrx-spinner .dsfrx-spinner--sun,dsfr-ext-spinner .dsfrx-spinner--sun{clip-path:polygon(60% 0%,60% 50%,100% 50%,100% 99%,0% 100%,0% 0%);animation:rotateSpinner1 1s ease-in-out infinite}dsfrx-spinner .dsfrx-spinner--quarter,dsfrx-spinner .dsfrx-spinner--line,dsfr-ext-spinner .dsfrx-spinner--quarter,dsfr-ext-spinner .dsfrx-spinner--line{animation:rotateSpinner2 1s ease-in-out infinite}dsfrx-spinner .dsfrx-spinner--md,dsfr-ext-spinner .dsfrx-spinner--md{width:2.857rem;height:2.857rem}dsfrx-spinner .dsfrx-spinner--lg,dsfr-ext-spinner .dsfrx-spinner--lg{width:3.429rem;height:3.429rem}@keyframes rotateSpinner1{0%{clip-path:polygon(60% 0%,60% 50%,100% 50%,100% 100%,0% 100%,0% 0%)}16%{clip-path:polygon(60% 0%,60% 50%,100% 50%,100% 100%,0% 100%,0% 0%)}17%{clip-path:polygon(100% 0%,100% 50%,60% 50%,60% 100%,0% 100%,0% 0%)}33%{clip-path:polygon(100% 0%,100% 50%,60% 50%,60% 100%,0% 100%,0% 0%)}34%{clip-path:polygon(0% 0%,100% 0%,100% 100%,50% 50%,50% 50%,0% 100%)}50%{clip-path:polygon(0% 0%,100% 0%,100% 100%,50% 50%,50% 50%,0% 100%)}51%{clip-path:polygon(0% 0%,100% 0%,100% 100%,40% 100%,40% 50%,0% 50%)}67%{clip-path:polygon(0% 0%,100% 0%,100% 100%,40% 100%,40% 50%,0% 50%)}68%{clip-path:polygon(40% 0%,100% 0%,100% 100%,0% 100%,0% 50%,40% 50%)}83%{clip-path:polygon(40% 0%,100% 0%,100% 100%,0% 100%,0% 50%,40% 50%)}84%{clip-path:polygon(50% 50%,100% 0%,100% 100%,0% 100%,0% 0%,50% 50%)}99%{clip-path:polygon(51% 50%,100% 0%,100% 100%,0% 100%,0% 0%,50% 50%)}to{clip-path:polygon(60% 0%,60% 50%,100% 50%,100% 100%,0% 100%,0% 0%)}}@keyframes rotateSpinner2{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: DsfrI18nPipe, name: "dsfrI18n" }], encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: DsfrSpinnerComponent, decorators: [{
type: Component,
args: [{ selector: 'dsfr-ext-spinner, dsfrx-spinner', encapsulation: ViewEncapsulation.None, imports: [CommonModule, DsfrI18nPipe], template: "@if (overlay) {\n <div class=\"dsfrx-overlay\" aria-busy=\"true\">\n <div class=\"content\">\n <ng-container *ngTemplateOutlet=\"spinner\"></ng-container>\n </div>\n </div>\n} @else {\n <ng-container *ngTemplateOutlet=\"spinner\"></ng-container>\n}\n\n<ng-template #spinner>\n <div [ngClass]=\"getSpinnerClasses()\">\n @switch (typeLoader) {\n @default {\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\">\n <path\n d=\"M11.9995 2C12.5518 2 12.9995 2.44772 12.9995 3V6C12.9995 6.55228 12.5518 7 11.9995 7C11.4472 7 10.9995 6.55228 10.9995 6V3C10.9995 2.44772 11.4472 2 11.9995 2ZM11.9995 17C12.5518 17 12.9995 17.4477 12.9995 18V21C12.9995 21.5523 12.5518 22 11.9995 22C11.4472 22 10.9995 21.5523 10.9995 21V18C10.9995 17.4477 11.4472 17 11.9995 17ZM20.6597 7C20.9359 7.47829 20.772 8.08988 20.2937 8.36602L17.6956 9.86602C17.2173 10.1422 16.6057 9.97829 16.3296 9.5C16.0535 9.02171 16.2173 8.41012 16.6956 8.13398L19.2937 6.63397C19.772 6.35783 20.3836 6.52171 20.6597 7ZM7.66935 14.5C7.94549 14.9783 7.78161 15.5899 7.30332 15.866L4.70525 17.366C4.22695 17.6422 3.61536 17.4783 3.33922 17C3.06308 16.5217 3.22695 15.9101 3.70525 15.634L6.30332 14.134C6.78161 13.8578 7.3932 14.0217 7.66935 14.5ZM20.6597 17C20.3836 17.4783 19.772 17.6422 19.2937 17.366L16.6956 15.866C16.2173 15.5899 16.0535 14.9783 16.3296 14.5C16.6057 14.0217 17.2173 13.8578 17.6956 14.134L20.2937 15.634C20.772 15.9101 20.9359 16.5217 20.6597 17ZM7.66935 9.5C7.3932 9.97829 6.78161 10.1422 6.30332 9.86602L3.70525 8.36602C3.22695 8.08988 3.06308 7.47829 3.33922 7C3.61536 6.52171 4.22695 6.35783 4.70525 6.63397L7.30332 8.13398C7.78161 8.41012 7.94549 9.02171 7.66935 9.5Z\" />\n </svg>\n }\n @case ('quarter') {\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\">\n <path d=\"M12 3C16.9706 3 21 7.02944 21 12H19C19 8.13401 15.866 5 12 5V3Z\"></path>\n </svg>\n }\n @case ('line') {\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\">\n <path\n d=\"M18.364 5.63604L16.9497 7.05025C15.683 5.7835 13.933 5 12 5C8.13401 5 5 8.13401 5 12C5 15.866 8.13401 19 12 19C15.866 19 19 15.866 19 12H21C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C14.4853 3 16.7353 4.00736 18.364 5.63604Z\"></path>\n </svg>\n }\n }\n </div>\n @if (label) {\n <span [ngClass]=\"{ 'fr-sr-only': labelSrOnly === true }\">{{ label }}</span>\n } @else {\n <span class=\"fr-sr-only\">{{\n isNonEmptyString(labelSrOnly) ? labelSrOnly : ('spinner.messageContext' | dsfrI18n)\n }}</span>\n }\n</ng-template>\n", styles: ["dsfrx-spinner,dsfr-ext-spinner{display:inline-flex;flex-direction:column;align-items:center}dsfrx-spinner .dsfrx-overlay,dsfr-ext-spinner .dsfrx-overlay{position:fixed;display:flex;align-items:center;justify-content:center;inset:0;background-color:#161616a3;z-index:9999;cursor:not-allowed}dsfrx-spinner .dsfrx-overlay .content,dsfr-ext-spinner .dsfrx-overlay .content{display:inline-flex;flex-direction:column;align-items:center;min-width:3.5rem;min-height:3.5rem;padding:.5rem 1rem;background-color:var(--background-lifted-grey)}dsfrx-spinner .dsfrx-overlay .dsfrx-spinner,dsfr-ext-spinner .dsfrx-overlay .dsfrx-spinner{width:2.5rem;height:2.5rem}dsfrx-spinner .dsfrx-spinner,dsfr-ext-spinner .dsfrx-spinner{width:2rem;height:2rem;fill:var(--background-action-high-blue-france)}dsfrx-spinner .dsfrx-spinner--sun,dsfr-ext-spinner .dsfrx-spinner--sun{clip-path:polygon(60% 0%,60% 50%,100% 50%,100% 99%,0% 100%,0% 0%);animation:rotateSpinner1 1s ease-in-out infinite}dsfrx-spinner .dsfrx-spinner--quarter,dsfrx-spinner .dsfrx-spinner--line,dsfr-ext-spinner .dsfrx-spinner--quarter,dsfr-ext-spinner .dsfrx-spinner--line{animation:rotateSpinner2 1s ease-in-out infinite}dsfrx-spinner .dsfrx-spinner--md,dsfr-ext-spinner .dsfrx-spinner--md{width:2.857rem;height:2.857rem}dsfrx-spinner .dsfrx-spinner--lg,dsfr-ext-spinner .dsfrx-spinner--lg{width:3.429rem;height:3.429rem}@keyframes rotateSpinner1{0%{clip-path:polygon(60% 0%,60% 50%,100% 50%,100% 100%,0% 100%,0% 0%)}16%{clip-path:polygon(60% 0%,60% 50%,100% 50%,100% 100%,0% 100%,0% 0%)}17%{clip-path:polygon(100% 0%,100% 50%,60% 50%,60% 100%,0% 100%,0% 0%)}33%{clip-path:polygon(100% 0%,100% 50%,60% 50%,60% 100%,0% 100%,0% 0%)}34%{clip-path:polygon(0% 0%,100% 0%,100% 100%,50% 50%,50% 50%,0% 100%)}50%{clip-path:polygon(0% 0%,100% 0%,100% 100%,50% 50%,50% 50%,0% 100%)}51%{clip-path:polygon(0% 0%,100% 0%,100% 100%,40% 100%,40% 50%,0% 50%)}67%{clip-path:polygon(0% 0%,100% 0%,100% 100%,40% 100%,40% 50%,0% 50%)}68%{clip-path:polygon(40% 0%,100% 0%,100% 100%,0% 100%,0% 50%,40% 50%)}83%{clip-path:polygon(40% 0%,100% 0%,100% 100%,0% 100%,0% 50%,40% 50%)}84%{clip-path:polygon(50% 50%,100% 0%,100% 100%,0% 100%,0% 0%,50% 50%)}99%{clip-path:polygon(51% 50%,100% 0%,100% 100%,0% 100%,0% 0%,50% 50%)}to{clip-path:polygon(60% 0%,60% 50%,100% 50%,100% 100%,0% 100%,0% 0%)}}@keyframes rotateSpinner2{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"] }]
}], ctorParameters: () => [], propDecorators: { typeLoader: [{
type: Input
}], label: [{
type: Input
}], labelSrOnly: [{
type: Input
}], overlay: [{
type: Input
}], spinnerSize: [{
type: Input
}] } });
const MESSAGES_EN$a = {
autocomplete: {
loading: 'Loading',
deleteTag: 'Unselect option',
availableResults: 'options available',
noResults: 'No option available',
noSelect: 'No option selected',
alreadyExist: 'This value already exists in the list of selected values.',
maxSelection: 'The maximum number of selectable values has been reached.',
},
};
// Ordre alphabétique requis
const MESSAGES_FR$a = {
autocomplete: {
loading: 'Chargement',
deleteTag: "Déselectionner l'option",
availableResults: 'suggestions disponibles',
noResults: 'Aucune suggestion disponible',
noSelect: 'Aucune suggestion sélectionnée',
alreadyExist: 'Cette valeur existe déjà dans la liste des valeurs sélectionnées.',
maxSelection: 'Le nombre maximum de valeurs sélectionnables est atteint.',
},
};
/**
* Plus d'héritage de DsfrFormInputComponent afin de pouvoir utiliser le type de value (générique)
* fixme : éviter la copie des différents inputs de DsfrFormInputComponent
*/
class DsfrAutocompleteComponent extends DefaultControlComponent {
constructor() {
super();
// Attributs c/c pour le dsfr-form-input -----------------------------------------------------------------------------
/** (form-input) type de l'input, 'text' ou 'search'. 'text' par défaut */
this.type = 'text';
/** (form-input) champ obligatoire ou non, faux par défaut. */
this.required = false;
/** Emission de l'événement si le type du bouton est différent de `submit`. */
this.buttonSelect = new EventEmitter();
// Attributs pour le combo du dsfr-form-input
/*** (form-input) permet de désactiver le bouton d'action. 'false' par défaut. */
this.buttonDisabled = false;
/*** (form-input) type du button,'button' par défaut. */
this.buttonType = 'button';
/** (form-input) style du bouton, 'primary' par défaut. */
this.buttonVariant = 'primary';
/** (form-input) Change la mise en page d'un input accompagné d'un bouton. */
this.inputWrapMode = 'addon';
/**
* [accessibilité] Permet de masquer visuellement le libellé du bouton en le laissant accessible aux dispositifs d'assistance.
*
* A utiliser pour le bouton si icône seule.
*/
this.buttonLabelSrOnly = false; // TODO
// -------------------------------------------------------------------------------------------------------------------
/** L'utilisateur doit traiter cet événement pour déclencher une méthode de recherche qui met à jour la propriété suggestions. */
this.filterChange = new EventEmitter();
/** Emet la suggestion à la sélection de celle-ci */
this.suggestionSelect = new EventEmitter();
/** Fermeture de la liste de suggestions */
this.listClose = new EventEmitter();
/** Mode multiple : à la suppression d'une suggestion (tag) */
this.clearOptionSelect = new EventEmitter();
/** Attacher l'élément de liste déroulante au 'body' ou a un container (réf. vers un élément #div ou nom de la classe du parent) */
thi