UNPKG

@edugouvfr/ngx-dsfr-ext

Version:

NgxDsfrExt est une extension au package @edugouvfr/ngx-dsfr (portage Angular des éléments DSFR)

164 lines 83.5 kB
import { BreakpointObserver } from '@angular/cdk/layout'; import { ChangeDetectionStrategy, Component, ElementRef, EventEmitter, Input, Output, Renderer2, ViewChild, ViewEncapsulation, forwardRef, inject, } from '@angular/core'; import { toSignal } from '@angular/core/rxjs-interop'; import { map } from 'rxjs'; import { CommonModule } from '@angular/common'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { DefaultControlComponent, DsfrButtonModule, DsfrI18nPipe, DsfrI18nService, DsfrUploadModule, Language, newUniqueId, } from '@edugouvfr/ngx-dsfr'; import { EduMessageSeverityDirective } from '../shared/directives/message-severity.directive'; import { FileDetailsPipe } from './file-details.pipe'; import { MESSAGES_EN } from './i18n/messages.en'; import { MESSAGES_FR } from './i18n/messages.fr'; import * as i0 from "@angular/core"; import * as i1 from "@angular/common"; import * as i2 from "@edugouvfr/ngx-dsfr"; export class DsfrUploadDndComponent extends DefaultControlComponent { constructor(cdr) { super(); this.cdr = cdr; /** Version inline du composant. */ this.inline = false; /** En mode full, n'affiche pas l'illustration. */ this.hideIllustration = false; /** Unité de poids de fichier autorisé. */ this.sizeUnit = 'octets'; /** * L'attribut `accept` prend comme valeur une chaîne de caractères contenant une ou plusieurs spécificateurs de type de fichier unique, séparées par des virgules. * Ces spécificateurs décrivent les types de fichiers pouvant être sélectionnés par l'utilisateur. * * ex: .jpg,.png,audio/*... */ this.accept = '.pdf, .jpg, .jpeg, .png'; /** Permet l'ajout de plusieurs fichiers à la fois. */ this.multiple = false; /** Message d'information lié au composant. */ this.message = undefined; /** Représente la sévérité du message. */ this.messageSeverity = 'info'; /** Evénement émis à la sélection d'un ou plusieurs fichiers. */ this.selectionChange = new EventEmitter(); /** Evénement émis lorsque l'utilisateur annule la sélection. */ this.fileBrowsingCancel = new EventEmitter(); /** @internal */ this.i18n = inject(DsfrI18nService); this.breakpointObserver = inject(BreakpointObserver); this.customBreakpoint = '(max-width: 320px)'; this.restitutionSelectedFiles = ''; this.formatAskedUniqueId = `formatAsked-${newUniqueId()}`; this.ariaDescribedby = this.formatAskedUniqueId; /** Gère l'affichage du bon markup en mode mobile. */ this.isMobile = toSignal(this.breakpointObserver.observe([this.customBreakpoint]).pipe(map((result) => result.matches)), { initialValue: false, }); this._renderer = inject(Renderer2); this.i18n.extendsLabelsBundle(Language.EN, MESSAGES_EN); this.i18n.extendsLabelsBundle(Language.FR, MESSAGES_FR); } /** * Surcharge permettant de gérer la mise à jour du DOM. * * @internal */ writeValue(value) { // afin de se prémunir des initialisations avec une chaîne de caractères (vide ou pas) il faut s'assurer du type // d'argument transmis en entrée et forcer la chaîne vide le cas échéant const isFileArray = value && value[0] && value[0].name !== undefined; if (!isFileArray) { value = []; } super.writeValue(value); if (this.inputFile && value && value.length > 0) { const fileList = this.convertFileArrayToFileList(value); this._renderer.setProperty(this.inputFile.nativeElement, 'files', fileList); } else if (this.inputFile) { this._renderer.setProperty(this.inputFile.nativeElement, 'value', ''); this._renderer.setProperty(this.inputFile.nativeElement, 'files', null); } this.cdr.markForCheck(); } setDisabledState(isDisabled) { super.setDisabledState(isDisabled); this.cdr.markForCheck(); } /** @internal */ ngOnInit() { super.ngOnInit(); this.value = []; if (this.message) { this.ariaDescribedby = `${this.formatAskedUniqueId} ${this.messagesGroupId}`; } } /** * Permet de programmatiquement réinitialiser le champ après une sélection de fichier(s). * @deprecated utiliser directement value */ reset() { this.value = undefined; super.writeValue(this.value); } /** * Fonction issue de la lib principale. */ onFileBrowsingCancel() { this.fileBrowsingCancel.emit(); } /** * Fonction issue de la lib principale. */ /** TODO: en version inline, après la sélection d'un fichier forcer le focus sur le btn de suppressions (accessibility). */ onFileChange(event) { const target = event.target; const newFiles = target.files !== null ? Array.from(target.files) : undefined; if (newFiles) { if (this.multiple) { this.value = this.value.concat(newFiles); } else { this.value = newFiles; } this.selectionChange.emit(this.value); } } deleteFile(index) { this.value.splice(index, 1); if (this.value?.length === 0) { this.inputFile.nativeElement.focus(); } } deleteAllFiles() { this.value = []; this.inputFile.nativeElement.focus(); } convertFileArrayToFileList(fileArray) { const dataTransfer = new DataTransfer(); fileArray.forEach((file) => { dataTransfer.items.add(file); }); return dataTransfer.files; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DsfrUploadDndComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: DsfrUploadDndComponent, isStandalone: true, selector: "dsfr-ext-upload-dnd, dsfrx-upload-dnd", inputs: { inline: "inline", buttonLabel: "buttonLabel", hideIllustration: "hideIllustration", formatAsked: "formatAsked", maxSizeInfo: "maxSizeInfo", sizeUnit: "sizeUnit", ariaInvalid: "ariaInvalid", accept: "accept", multiple: "multiple", message: "message", messageSeverity: "messageSeverity", messagesGroupId: "messagesGroupId" }, outputs: { selectionChange: "selectionChange", fileBrowsingCancel: "fileBrowsingCancel" }, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => DsfrUploadDndComponent), multi: true, }, ], viewQueries: [{ propertyName: "inputFile", first: true, predicate: ["inputFile"], descendants: true }, { propertyName: "inlineDeleteBtn", first: true, predicate: ["inlineDeleteBtn"], descendants: true, read: ElementRef }], usesInheritance: true, ngImport: i0, template: "<div\n class=\"edu-upload-dnd__container\"\n [class]=\"{\n 'edu-upload-dnd--error': message && messageSeverity === 'error',\n 'edu-upload-dnd--valid': message && (messageSeverity === 'valid' || messageSeverity === 'success'),\n 'edu-upload-dnd--info': message && messageSeverity === 'info',\n 'edu-upload-dnd--warning': message && messageSeverity === 'warning',\n 'edu-upload-dnd__container--inline': inline,\n }\">\n <label class=\"fr-label\" [for]=\"inputId\">{{ label }}</label>\n\n @if (!inline) {\n <ng-container *ngTemplateOutlet=\"templateFull\"></ng-container>\n } @else {\n <ng-container *ngTemplateOutlet=\"templateInline\"></ng-container>\n }\n</div>\n\n<div aria-live=\"polite\">\n @if (message) {\n <p [attr.id]=\"messagesGroupId\" [eduMessageSeverity]=\"messageSeverity\">\n {{ message }}\n </p>\n }\n</div>\n\n<!-- MARK: Template Full -->\n<ng-template #templateFull>\n <div class=\"edu-upload-dnd__area\" [ngClass]=\"{ 'edu-upload-dnd__area--disabled': disabled }\">\n @if (!hideIllustration && !isMobile()) {\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"80\" height=\"80\" viewBox=\"0 0 80 80\" fill=\"none\">\n <rect width=\"80\" height=\"80\" fill=\"white\" />\n <path\n d=\"M38.4783 43.7609C40 39.4493 45.7826 30.8261 56.7391 30.8261C70.4348 30.8261 75 43 75 49.8478C75 56.6957 68.1522 67.5163 58.2609 67.5163C50.3478 67.5163 47.2572 67.5163 46 67.5163M34.5 67.5163H21.7391C16.1594 66.9529 5 62.6304 5 49.8478C5 37.0652 13.6232 32.3478 17.9348 31.587C17.9348 23.7246 22.3478 8 40 8C57.6522 8 61.558 20.6812 61.3043 27.0217\"\n [attr.stroke]=\"disabled ? '#929292' : '#000091'\"\n stroke-width=\"2\"\n stroke-linecap=\"round\" />\n <path\n d=\"M39 71.3913C39 71.9436 39.4477 72.3913 40 72.3913C40.5523 72.3913 41 71.9436 41 71.3913H39ZM40.7071 56.6842C40.3166 56.2937 39.6834 56.2937 39.2929 56.6842L32.9289 63.0482C32.5384 63.4387 32.5384 64.0718 32.9289 64.4624C33.3195 64.8529 33.9526 64.8529 34.3431 64.4624L40 58.8055L45.6569 64.4624C46.0474 64.8529 46.6805 64.8529 47.0711 64.4624C47.4616 64.0718 47.4616 63.4387 47.0711 63.0482L40.7071 56.6842ZM41 71.3913V57.3913H39V71.3913H41Z\"\n [attr.fill]=\"disabled ? '#929292' : '#E1000F'\" />\n <path\n d=\"M24.7827 30.0652C25.0363 24.9928 28.4349 14.8478 40.0001 14.8478M56.7392 36.1522C61.0508 36.1522 67.3914 39.1957 68.9131 45.2826\"\n [attr.stroke]=\"disabled ? '#929292' : '#000091'\"\n stroke-width=\"2\"\n stroke-linecap=\"round\" />\n <path\n d=\"M34 53.3913H46\"\n [attr.stroke]=\"disabled ? '#929292' : '#E1000F'\"\n stroke-width=\"2\"\n stroke-linecap=\"round\" />\n </svg>\n }\n\n <div class=\"edu-upload-dnd__description\">\n @if (multiple && isMobile()) {\n <p class=\"edu-upload-dnd__description--mobile\">{{ 'uploadDnd.description.mobile' | dsfrI18n }}</p>\n }\n @if (!isMobile()) {\n <p>{{ (multiple ? 'uploadDnd.description.desktopMultiple' : 'uploadDnd.description.desktop') | dsfrI18n }}</p>\n <p class=\"fr-hint-text\">{{ 'uploadDnd.description.or' | dsfrI18n }}</p>\n }\n </div>\n\n <div class=\"edu-upload-dnd__input fr-btn fr-btn--secondary\" [ngClass]=\"{ 'fr-btn--disabled': disabled }\">\n <ng-container *ngTemplateOutlet=\"templateInput\"></ng-container>\n @if (multiple) {\n <span>{{ (buttonLabel ? buttonLabel : 'uploadDnd.buttonMultiple') | dsfrI18n }}</span>\n } @else {\n <span>{{ (buttonLabel ? buttonLabel : 'uploadDnd.buttonSingle') | dsfrI18n }}</span>\n }\n </div>\n\n <p [id]=\"formatAskedUniqueId\" class=\"fr-hint-text\">\n @if (hint) {\n {{ hint }}\n } @else {\n {{ 'uploadDnd.infos.format' | dsfrI18n }} : {{ formatAsked ?? accept }}.\n {{ maxSizeInfo ?? 'uploadDnd.infos.size' | dsfrI18n }}.\n }\n </p>\n </div>\n <!--Liste des r\u00E9sultats-->\n @if (value && value.length > 0) {\n <div class=\"edu-upload-dnd__resume\">\n <p class=\"fr-sr-only\">\n {{ (value.length > 1 ? 'uploadDnd.fileList.selectedFiles' : 'uploadDnd.fileList.selectedFile') | dsfrI18n }} :\n </p>\n @if (multiple && value.length >= 1) {\n <div class=\"edu-upload-dnd__head\">\n <p>\n <span class=\"fr-icon-file-fill\" aria-hidden=\"true\"></span\n ><span class=\"edu-upload-dnd__list-length\"\n >{{ value.length }}\n {{\n (value.length > 1 ? 'uploadDnd.fileList.selectedFiles' : 'uploadDnd.fileList.selectedFile') | dsfrI18n\n }}</span\n >\n </p>\n <dsfr-button\n [label]=\"'uploadDnd.fileList.removeAll' | dsfrI18n\"\n [ariaLabel]=\"'uploadDnd.fileList.removeAllDetailed' | dsfrI18n\"\n [type]=\"'button'\"\n [variant]=\"'tertiary'\"\n size=\"SM\"\n [iconPosition]=\"'right'\"\n icon=\"fr-icon-delete-line\"\n [disabled]=\"disabled\"\n (click)=\"deleteAllFiles()\"></dsfr-button>\n </div>\n }\n <ul>\n @for (file of value; track $index) {\n <li>\n <div class=\"edu-upload-dnd__result-line\">\n <span class=\"fr-icon-file-line\" aria-hidden=\"true\"></span>\n <div>\n <p class=\"edu-upload-dnd__name\">{{ file.name }}</p>\n <p class=\"edu-upload-dnd__detail\">\n <span class=\"fr-sr-only\">Formats et poids :</span>{{ file | fileDetails: sizeUnit }}\n </p>\n </div>\n <dsfr-button\n [type]=\"'button'\"\n [tooltipMessage]=\"'Supprimer le document - ' + file.name\"\n variant=\"tertiary-no-outline\"\n size=\"SM\"\n icon=\"fr-icon-delete-line\"\n [disabled]=\"disabled\"\n (click)=\"deleteFile($index)\"></dsfr-button>\n </div>\n </li>\n }\n </ul>\n </div>\n @if (isMobile()) {\n <div class=\"edu-upload-dnd__resume--mobile\">\n <ng-container *ngTemplateOutlet=\"templateFileList\"></ng-container>\n </div>\n }\n }\n</ng-template>\n\n<!-- MARK: Template Inline -->\n<ng-template #templateInline>\n <p [id]=\"formatAskedUniqueId\" class=\"fr-hint-text\">\n @if (hint) {\n {{ hint }}\n } @else {\n {{ 'uploadDnd.infos.format' | dsfrI18n }} : {{ formatAsked ?? accept }}.\n {{ maxSizeInfo ?? 'uploadDnd.infos.size' | dsfrI18n }}.\n }\n </p>\n\n <div class=\"edu-upload-dnd__input\">\n <div class=\"edu-upload-dnd__area\">\n <ng-container *ngTemplateOutlet=\"templateInput\"></ng-container>\n <button tabindex=\"-1\" class=\"fr-btn fr-btn--secondary\" [disabled]=\"disabled\">\n {{ 'uploadDnd.inline.button' | dsfrI18n }}\n </button>\n @if (!isMobile()) {\n <span>{{ 'uploadDnd.description.or' | dsfrI18n }}</span>\n <p class=\"edu-upload-dnd__drop-zone fr-btn fr-btn--tertiary\">{{ 'uploadDnd.inline.drop' | dsfrI18n }}</p>\n }\n </div>\n <ng-container *ngTemplateOutlet=\"templateFileList\"></ng-container>\n </div>\n</ng-template>\n\n<!-- MARK: Template Input -->\n<ng-template #templateInput>\n <input\n #inputFile\n class=\"fr-upload\"\n type=\"file\"\n title=\"\"\n [multiple]=\"multiple\"\n [disabled]=\"disabled\"\n [attr.id]=\"inputId || null\"\n [attr.name]=\"name || null\"\n [attr.accept]=\"accept || null\"\n [attr.aria-describedby]=\"ariaDescribedby\"\n [attr.aria-invalid]=\"ariaInvalid || null\"\n (change)=\"onFileChange($event)\"\n (cancel)=\"onFileBrowsingCancel()\" />\n <p class=\"fr-sr-only\">\n {{\n !value || value.length === 0\n ? ('uploadDnd.fileList.noFile' | dsfrI18n)\n : 'Fichiers s\u00E9lectionn\u00E9s : ' + restitutionSelectedFiles\n }}\n </p>\n</ng-template>\n\n<!-- MARK: Template File List -->\n<ng-template #templateFileList>\n @if (value && value.length < 2) {\n <div class=\"edu-upload-dnd__resume--single\">\n <div class=\"fr-input\">\n @if (value.length === 1) {\n <span class=\"edu-upload-dnd__file-name\">{{ value[0].name }}</span>\n <span class=\"edu-upload-dnd__file-size\">{{ value[0] | fileDetails: sizeUnit }}</span>\n } @else {\n {{ 'uploadDnd.fileList.noFile' | dsfrI18n }}\n }\n </div>\n @if (value.length === 1) {\n <dsfr-button\n variant=\"secondary\"\n [type]=\"'button'\"\n [ariaLabel]=\"'uploadDnd.fileList.removeAllDetailed' | dsfrI18n\"\n [size]=\"'MD'\"\n [icon]=\"'fr-icon-delete-line'\"\n [disabled]=\"disabled\"\n (click)=\"deleteAllFiles()\"></dsfr-button>\n }\n </div>\n } @else {\n <div class=\"edu-upload-dnd__resume\" [class.edu-upload-dnd__resume--mobile]=\"isMobile()\">\n <p class=\"fr-sr-only\">{{ 'uploadDnd.fileList.selectedFiles' | dsfrI18n }} :</p>\n @if (multiple && value && value.length > 1) {\n <div class=\"edu-upload-dnd__head\">\n <p>\n <span class=\"fr-icon-file-fill\" aria-hidden=\"true\"></span\n ><span class=\"edu-upload-dnd__list-length\"\n >{{ value.length }} {{ 'uploadDnd.fileList.selectedFiles' | dsfrI18n }}</span\n >\n </p>\n <dsfr-button\n label=\"\"\n icon=\"fr-icon-delete-line\"\n size=\"SM\"\n [ariaLabel]=\"'uploadDnd.fileList.removeAllDetailed' | dsfrI18n\"\n [type]=\"'button'\"\n [variant]=\"'tertiary'\"\n [iconPosition]=\"'right'\"\n [disabled]=\"disabled\"\n (click)=\"deleteAllFiles()\"></dsfr-button>\n </div>\n }\n <ul>\n @for (file of value; track $index) {\n <li>\n <div class=\"edu-upload-dnd__result-line\">\n <span class=\"fr-icon-file-line\" aria-hidden=\"true\"></span>\n <div>\n <p>{{ file.name }}</p>\n <p class=\"edu-upload-dnd__detail\">\n <span class=\"fr-sr-only\">{{ 'uploadDnd.fileList.formatSize' | dsfrI18n }} :</span\n >{{ file | fileDetails: sizeUnit }}\n </p>\n </div>\n <dsfr-button\n [type]=\"'button'\"\n [tooltipMessage]=\"'Supprimer ce document - ' + file.name\"\n variant=\"tertiary-no-outline\"\n size=\"SM\"\n icon=\"fr-icon-delete-line\"\n [disabled]=\"disabled\"\n (click)=\"deleteFile($index)\"></dsfr-button>\n </div>\n </li>\n }\n </ul>\n </div>\n }\n</ng-template>\n", styles: [".edu-upload-dnd__container.edu-upload-dnd__container--inline label{margin-bottom:0}.edu-upload-dnd__container.edu-upload-dnd__container--inline .fr-hint-text{margin-top:.25rem}.edu-upload-dnd__container.edu-upload-dnd__container--inline .edu-upload-dnd__input{position:relative;display:flex;flex-wrap:wrap;flex-direction:row-reverse;align-items:flex-start;justify-content:flex-end;margin-top:.5rem}.edu-upload-dnd__container.edu-upload-dnd__container--inline .edu-upload-dnd__input:has(.fr-upload:focus){outline-width:0}.edu-upload-dnd__container.edu-upload-dnd__container--inline .edu-upload-dnd__input .fr-input{width:17.625rem;margin-right:1rem;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;display:flex;justify-content:space-between;align-items:baseline}.edu-upload-dnd__container.edu-upload-dnd__container--inline .edu-upload-dnd__input .edu-upload-dnd__area .fr-upload:focus+.fr-btn--secondary{outline-offset:2px;outline-color:#0a76f6;outline-width:2px;outline-style:solid}.edu-upload-dnd__container.edu-upload-dnd__container--inline .edu-upload-dnd__input .edu-upload-dnd__area:has(.fr-upload:hover){background-color:var(--hover-tint)}.edu-upload-dnd__container.edu-upload-dnd__container--inline .edu-upload-dnd__input .edu-upload-dnd__area{display:flex;flex-direction:row;align-items:center;padding:0;gap:.5rem;border:0;margin-bottom:1rem}.edu-upload-dnd__container.edu-upload-dnd__container--inline .edu-upload-dnd__input .edu-upload-dnd__drop-zone{border:1px dashed var(--border-plain-grey);color:var(--text-action-high-grey);box-shadow:none;padding:.375rem 1rem}.edu-upload-dnd__container.edu-upload-dnd__container--inline__area:has(.fr-upload:focus) .fr-btn--secondary{outline-offset:2px;outline-color:#0a76f6;outline-width:2px;outline-style:solid}.edu-upload-dnd__container.edu-upload-dnd__container--inline__input:has(.fr-upload:hover) .fr-btn--secondary{background-color:var(--hover-tint)}@media screen and (max-width: 20rem){.edu-upload-dnd__container--inline .edu-upload-dnd__input{flex-wrap:wrap}.edu-upload-dnd__container--inline .edu-upload-dnd__input .fr-input{margin-right:0;width:100%}.edu-upload-dnd__container--inline .edu-upload-dnd__input dsfr-button{padding-right:0;margin-right:0;border-right:0}.edu-upload-dnd__container--inline .edu-upload-dnd__area{margin-top:1rem;width:100%}.edu-upload-dnd__container--inline .edu-upload-dnd__area .fr-upload,.edu-upload-dnd__container--inline .edu-upload-dnd__area .fr-btn--secondary{width:100%;justify-content:center}.edu-upload-dnd__container--inline edu-upload-dnd-resume{display:block;width:100%}}\n", ".edu-upload-dnd__resume{margin-top:0;margin-right:.5rem}.edu-upload-dnd__resume--single{display:flex;width:auto;max-width:100%}.edu-upload-dnd__resume .edu-upload-dnd__head{padding:.25rem .5rem;background-color:var(--background-alt-grey)}.edu-upload-dnd__resume .edu-upload-dnd__result-line dsfr-button,.edu-upload-dnd__resume .edu-upload-dnd__head dsfr-button{padding-right:0;margin-right:0;border-right:0}.edu-upload-dnd__resume .edu-upload-dnd__result-line{padding:.25rem .5rem;align-items:flex-start;width:100%}.edu-upload-dnd__resume .edu-upload-dnd__result-line .fr-icon-file-line:before{--icon-size: 1rem}.edu-upload-dnd__resume .edu-upload-dnd__result-line div{flex-direction:column;gap:0;align-items:flex-start;flex:1;overflow:hidden;white-space:nowrap}.edu-upload-dnd__resume .edu-upload-dnd__result-line div p{font-size:.875rem}.edu-upload-dnd__resume .edu-upload-dnd__result-line .edu-upload-dnd__name{overflow:hidden;text-overflow:ellipsis}.edu-upload-dnd__resume .edu-upload-dnd__result-line .edu-upload-dnd__detail{font-size:.75rem}.edu-upload-dnd__resume ul{margin:0;padding:0;list-style:none}.edu-upload-dnd__resume ul li{margin:0;padding:0}.edu-upload-dnd__file-name{overflow:hidden;text-overflow:ellipsis}.edu-upload-dnd__file-size{font-size:.75rem}.edu-upload-dnd__container--inline .edu-upload-dnd__resume--single{width:auto}.edu-upload-dnd__container--inline .edu-upload-dnd__resume--single dsfr-button{padding-right:.5rem;margin-right:.5rem;border-right:1px solid var(--border-plain-grey)}.edu-upload-dnd__container--inline .edu-upload-dnd__resume{margin-top:0;margin-right:.5rem}.edu-upload-dnd__container--inline .edu-upload-dnd__resume .edu-upload-dnd__head{background-color:var(--background-alt-grey);padding:.25rem .5rem}.edu-upload-dnd__container--inline .edu-upload-dnd__resume .edu-upload-dnd__result-line{align-items:flex-start;padding:.5rem}.edu-upload-dnd__container--inline .edu-upload-dnd__resume .edu-upload-dnd__result-line div{flex-direction:column}@media screen and (max-width: 20rem){.edu-upload-dnd__resume{display:none}.edu-upload-dnd__resume--mobile .edu-upload-dnd__resume{display:block;width:100%;margin-top:0}.edu-upload-dnd__resume--mobile{display:flex;flex-wrap:wrap;margin-top:1rem;margin-right:0}.edu-upload-dnd__resume--mobile .fr-input{text-overflow:ellipsis;overflow:hidden;white-space:nowrap;margin-right:1rem}.edu-upload-dnd__resume--single{width:100%}.edu-upload-dnd__resume--single dsfr-button{margin-left:1rem}.edu-upload-dnd__result-line{padding:.25rem .5rem;align-items:flex-start}.edu-upload-dnd__result-line .fr-icon-file-line:before{--icon-size: 1rem}.edu-upload-dnd__result-line div{flex-direction:column;gap:0;align-items:flex-start;flex:1}.edu-upload-dnd__result-line div p{font-size:.875rem;line-height:normal;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;max-width:190px}.edu-upload-dnd__result-line dsfr-button{margin-left:0}.edu-upload-dnd__result-line .edu-upload-dnd__detail{font-size:.75rem}}\n", ".edu-upload-dnd--error,.edu-upload-dnd--valid,.edu-upload-dnd--info,.edu-upload-dnd--warning{position:relative}.edu-upload-dnd--error:before,.edu-upload-dnd--valid:before,.edu-upload-dnd--info:before,.edu-upload-dnd--warning:before{background-position:0 0;background-repeat:no-repeat;background-size:.125rem 100%;bottom:0;content:\"\";display:block;left:-.75rem;pointer-events:none;position:absolute;right:-.75rem;top:0}.edu-upload-dnd--error:before{background-image:linear-gradient(0deg,var(--border-plain-error),var(--border-plain-error))}.edu-upload-dnd--error label{color:var(--text-default-error)}.edu-upload-dnd--valid:before{background-image:linear-gradient(0deg,var(--border-plain-success),var(--border-plain-success))}.edu-upload-dnd--valid label{color:var(--text-default-success)}.edu-upload-dnd--info:before{background-image:linear-gradient(0deg,var(--border-plain-info),var(--border-plain-info))}.edu-upload-dnd--info label{color:var(--text-default-info)}.edu-upload-dnd--warning:before{background-image:linear-gradient(0deg,var(--border-plain-warning),var(--border-plain-warning))}.edu-upload-dnd--warning label{color:var(--text-default-warning)}.edu-upload-dnd__container p{margin:0;text-overflow:ellipsis}.edu-upload-dnd__container label{margin-bottom:1rem}.edu-upload-dnd__area{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:1rem 2rem;gap:.625rem;border:1px dashed var(--border-action-high-blue-france)}.edu-upload-dnd__area--disabled{border-color:var(--text-disabled-grey)}.edu-upload-dnd__description{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.38rem}.edu-upload-dnd__input .fr-upload{position:absolute;inset:0;opacity:0}.edu-upload-dnd__input:has(.fr-upload:focus){outline-offset:2px;outline-color:#0a76f6;outline-width:2px;outline-style:solid}.edu-upload-dnd__input:has(.fr-upload:hover){background-color:var(--hover-tint)}.edu-upload-dnd__resume{margin-top:1rem;margin-right:0;border:1px solid var(--border-default-grey)}.edu-upload-dnd__resume--single{display:flex;width:100%}.edu-upload-dnd__resume div{overflow:hidden;white-space:nowrap}.edu-upload-dnd__resume span{margin-right:.625rem}.edu-upload-dnd__resume ul{margin:0;padding:0;list-style:none}.edu-upload-dnd__resume ul li{margin:0;padding:0}.edu-upload-dnd__resume .edu-upload-dnd__head,.edu-upload-dnd__resume .edu-upload-dnd__result-line{padding:1rem;display:flex;align-items:center;justify-content:space-between}.edu-upload-dnd__resume .edu-upload-dnd__head{border-bottom:1px solid var(--border-plain-grey);background-color:var(--background-default-grey)}.edu-upload-dnd__resume .edu-upload-dnd__head p{overflow:hidden;white-space:nowrap}.edu-upload-dnd__resume .edu-upload-dnd__head p .edu-upload-dnd__list-length{text-overflow:ellipsis}.edu-upload-dnd__resume .edu-upload-dnd__head dsfr-button{margin-left:.5rem}.edu-upload-dnd__resume .edu-upload-dnd__result-line{background-color:var(--background-alt-grey)}.edu-upload-dnd__resume .edu-upload-dnd__result-line div{display:flex;flex:1;justify-content:space-between;flex-direction:row}.edu-upload-dnd__resume .edu-upload-dnd__result-line dsfr-button{margin-left:1rem}.edu-upload-dnd__resume .edu-upload-dnd__result-line button:hover{background-color:var(--active-tint)}.edu-upload-dnd__resume li:not(:last-child) .edu-upload-dnd__result-line{border-bottom:1px solid var(--border-default-grey)}.edu-upload-dnd__input.fr-btn.fr-btn--secondary.fr-btn--disabled{color:var(--text-disabled-grey);box-shadow:inset 0 0 0 1px var(--text-disabled-grey)}@media screen and (max-width: 20rem){.edu-upload-dnd__area{border:0;padding:0;align-items:flex-start}.edu-upload-dnd__description .edu-upload-dnd__description--mobile{color:var(--text-mention-grey)}.edu-upload-dnd .fr-hint-text{order:2}.edu-upload-dnd__input{position:relative;order:3}.edu-upload-dnd__head{padding:.5rem;width:100%}}\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: "ngmodule", type: DsfrUploadModule }, { kind: "ngmodule", type: DsfrButtonModule }, { kind: "component", type: i2.DsfrButtonComponent, selector: "dsfr-button", inputs: ["label", "type", "tooltipMessage", "variant", "buttonSize", "icon", "iconPosition", "disabled", "uppercase", "loader", "ariaLabel", "invertedOutlineContrast", "id", "buttonId", "ariaControls", "ariaPressed", "ariaHasPopup", "ariaExpanded", "tabIndex", "customClass", "buttonRole", "labelSrOnly", "size"] }, { kind: "pipe", type: DsfrI18nPipe, name: "dsfrI18n" }, { kind: "pipe", type: FileDetailsPipe, name: "fileDetails" }, { kind: "directive", type: EduMessageSeverityDirective, selector: "[eduMessageSeverity]", inputs: ["eduMessageSeverity"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DsfrUploadDndComponent, decorators: [{ type: Component, args: [{ selector: 'dsfr-ext-upload-dnd, dsfrx-upload-dnd', standalone: true, imports: [ CommonModule, DsfrUploadModule, DsfrButtonModule, DsfrI18nPipe, FileDetailsPipe, EduMessageSeverityDirective, ], encapsulation: ViewEncapsulation.None, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => DsfrUploadDndComponent), multi: true, }, ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n class=\"edu-upload-dnd__container\"\n [class]=\"{\n 'edu-upload-dnd--error': message && messageSeverity === 'error',\n 'edu-upload-dnd--valid': message && (messageSeverity === 'valid' || messageSeverity === 'success'),\n 'edu-upload-dnd--info': message && messageSeverity === 'info',\n 'edu-upload-dnd--warning': message && messageSeverity === 'warning',\n 'edu-upload-dnd__container--inline': inline,\n }\">\n <label class=\"fr-label\" [for]=\"inputId\">{{ label }}</label>\n\n @if (!inline) {\n <ng-container *ngTemplateOutlet=\"templateFull\"></ng-container>\n } @else {\n <ng-container *ngTemplateOutlet=\"templateInline\"></ng-container>\n }\n</div>\n\n<div aria-live=\"polite\">\n @if (message) {\n <p [attr.id]=\"messagesGroupId\" [eduMessageSeverity]=\"messageSeverity\">\n {{ message }}\n </p>\n }\n</div>\n\n<!-- MARK: Template Full -->\n<ng-template #templateFull>\n <div class=\"edu-upload-dnd__area\" [ngClass]=\"{ 'edu-upload-dnd__area--disabled': disabled }\">\n @if (!hideIllustration && !isMobile()) {\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"80\" height=\"80\" viewBox=\"0 0 80 80\" fill=\"none\">\n <rect width=\"80\" height=\"80\" fill=\"white\" />\n <path\n d=\"M38.4783 43.7609C40 39.4493 45.7826 30.8261 56.7391 30.8261C70.4348 30.8261 75 43 75 49.8478C75 56.6957 68.1522 67.5163 58.2609 67.5163C50.3478 67.5163 47.2572 67.5163 46 67.5163M34.5 67.5163H21.7391C16.1594 66.9529 5 62.6304 5 49.8478C5 37.0652 13.6232 32.3478 17.9348 31.587C17.9348 23.7246 22.3478 8 40 8C57.6522 8 61.558 20.6812 61.3043 27.0217\"\n [attr.stroke]=\"disabled ? '#929292' : '#000091'\"\n stroke-width=\"2\"\n stroke-linecap=\"round\" />\n <path\n d=\"M39 71.3913C39 71.9436 39.4477 72.3913 40 72.3913C40.5523 72.3913 41 71.9436 41 71.3913H39ZM40.7071 56.6842C40.3166 56.2937 39.6834 56.2937 39.2929 56.6842L32.9289 63.0482C32.5384 63.4387 32.5384 64.0718 32.9289 64.4624C33.3195 64.8529 33.9526 64.8529 34.3431 64.4624L40 58.8055L45.6569 64.4624C46.0474 64.8529 46.6805 64.8529 47.0711 64.4624C47.4616 64.0718 47.4616 63.4387 47.0711 63.0482L40.7071 56.6842ZM41 71.3913V57.3913H39V71.3913H41Z\"\n [attr.fill]=\"disabled ? '#929292' : '#E1000F'\" />\n <path\n d=\"M24.7827 30.0652C25.0363 24.9928 28.4349 14.8478 40.0001 14.8478M56.7392 36.1522C61.0508 36.1522 67.3914 39.1957 68.9131 45.2826\"\n [attr.stroke]=\"disabled ? '#929292' : '#000091'\"\n stroke-width=\"2\"\n stroke-linecap=\"round\" />\n <path\n d=\"M34 53.3913H46\"\n [attr.stroke]=\"disabled ? '#929292' : '#E1000F'\"\n stroke-width=\"2\"\n stroke-linecap=\"round\" />\n </svg>\n }\n\n <div class=\"edu-upload-dnd__description\">\n @if (multiple && isMobile()) {\n <p class=\"edu-upload-dnd__description--mobile\">{{ 'uploadDnd.description.mobile' | dsfrI18n }}</p>\n }\n @if (!isMobile()) {\n <p>{{ (multiple ? 'uploadDnd.description.desktopMultiple' : 'uploadDnd.description.desktop') | dsfrI18n }}</p>\n <p class=\"fr-hint-text\">{{ 'uploadDnd.description.or' | dsfrI18n }}</p>\n }\n </div>\n\n <div class=\"edu-upload-dnd__input fr-btn fr-btn--secondary\" [ngClass]=\"{ 'fr-btn--disabled': disabled }\">\n <ng-container *ngTemplateOutlet=\"templateInput\"></ng-container>\n @if (multiple) {\n <span>{{ (buttonLabel ? buttonLabel : 'uploadDnd.buttonMultiple') | dsfrI18n }}</span>\n } @else {\n <span>{{ (buttonLabel ? buttonLabel : 'uploadDnd.buttonSingle') | dsfrI18n }}</span>\n }\n </div>\n\n <p [id]=\"formatAskedUniqueId\" class=\"fr-hint-text\">\n @if (hint) {\n {{ hint }}\n } @else {\n {{ 'uploadDnd.infos.format' | dsfrI18n }} : {{ formatAsked ?? accept }}.\n {{ maxSizeInfo ?? 'uploadDnd.infos.size' | dsfrI18n }}.\n }\n </p>\n </div>\n <!--Liste des r\u00E9sultats-->\n @if (value && value.length > 0) {\n <div class=\"edu-upload-dnd__resume\">\n <p class=\"fr-sr-only\">\n {{ (value.length > 1 ? 'uploadDnd.fileList.selectedFiles' : 'uploadDnd.fileList.selectedFile') | dsfrI18n }} :\n </p>\n @if (multiple && value.length >= 1) {\n <div class=\"edu-upload-dnd__head\">\n <p>\n <span class=\"fr-icon-file-fill\" aria-hidden=\"true\"></span\n ><span class=\"edu-upload-dnd__list-length\"\n >{{ value.length }}\n {{\n (value.length > 1 ? 'uploadDnd.fileList.selectedFiles' : 'uploadDnd.fileList.selectedFile') | dsfrI18n\n }}</span\n >\n </p>\n <dsfr-button\n [label]=\"'uploadDnd.fileList.removeAll' | dsfrI18n\"\n [ariaLabel]=\"'uploadDnd.fileList.removeAllDetailed' | dsfrI18n\"\n [type]=\"'button'\"\n [variant]=\"'tertiary'\"\n size=\"SM\"\n [iconPosition]=\"'right'\"\n icon=\"fr-icon-delete-line\"\n [disabled]=\"disabled\"\n (click)=\"deleteAllFiles()\"></dsfr-button>\n </div>\n }\n <ul>\n @for (file of value; track $index) {\n <li>\n <div class=\"edu-upload-dnd__result-line\">\n <span class=\"fr-icon-file-line\" aria-hidden=\"true\"></span>\n <div>\n <p class=\"edu-upload-dnd__name\">{{ file.name }}</p>\n <p class=\"edu-upload-dnd__detail\">\n <span class=\"fr-sr-only\">Formats et poids :</span>{{ file | fileDetails: sizeUnit }}\n </p>\n </div>\n <dsfr-button\n [type]=\"'button'\"\n [tooltipMessage]=\"'Supprimer le document - ' + file.name\"\n variant=\"tertiary-no-outline\"\n size=\"SM\"\n icon=\"fr-icon-delete-line\"\n [disabled]=\"disabled\"\n (click)=\"deleteFile($index)\"></dsfr-button>\n </div>\n </li>\n }\n </ul>\n </div>\n @if (isMobile()) {\n <div class=\"edu-upload-dnd__resume--mobile\">\n <ng-container *ngTemplateOutlet=\"templateFileList\"></ng-container>\n </div>\n }\n }\n</ng-template>\n\n<!-- MARK: Template Inline -->\n<ng-template #templateInline>\n <p [id]=\"formatAskedUniqueId\" class=\"fr-hint-text\">\n @if (hint) {\n {{ hint }}\n } @else {\n {{ 'uploadDnd.infos.format' | dsfrI18n }} : {{ formatAsked ?? accept }}.\n {{ maxSizeInfo ?? 'uploadDnd.infos.size' | dsfrI18n }}.\n }\n </p>\n\n <div class=\"edu-upload-dnd__input\">\n <div class=\"edu-upload-dnd__area\">\n <ng-container *ngTemplateOutlet=\"templateInput\"></ng-container>\n <button tabindex=\"-1\" class=\"fr-btn fr-btn--secondary\" [disabled]=\"disabled\">\n {{ 'uploadDnd.inline.button' | dsfrI18n }}\n </button>\n @if (!isMobile()) {\n <span>{{ 'uploadDnd.description.or' | dsfrI18n }}</span>\n <p class=\"edu-upload-dnd__drop-zone fr-btn fr-btn--tertiary\">{{ 'uploadDnd.inline.drop' | dsfrI18n }}</p>\n }\n </div>\n <ng-container *ngTemplateOutlet=\"templateFileList\"></ng-container>\n </div>\n</ng-template>\n\n<!-- MARK: Template Input -->\n<ng-template #templateInput>\n <input\n #inputFile\n class=\"fr-upload\"\n type=\"file\"\n title=\"\"\n [multiple]=\"multiple\"\n [disabled]=\"disabled\"\n [attr.id]=\"inputId || null\"\n [attr.name]=\"name || null\"\n [attr.accept]=\"accept || null\"\n [attr.aria-describedby]=\"ariaDescribedby\"\n [attr.aria-invalid]=\"ariaInvalid || null\"\n (change)=\"onFileChange($event)\"\n (cancel)=\"onFileBrowsingCancel()\" />\n <p class=\"fr-sr-only\">\n {{\n !value || value.length === 0\n ? ('uploadDnd.fileList.noFile' | dsfrI18n)\n : 'Fichiers s\u00E9lectionn\u00E9s : ' + restitutionSelectedFiles\n }}\n </p>\n</ng-template>\n\n<!-- MARK: Template File List -->\n<ng-template #templateFileList>\n @if (value && value.length < 2) {\n <div class=\"edu-upload-dnd__resume--single\">\n <div class=\"fr-input\">\n @if (value.length === 1) {\n <span class=\"edu-upload-dnd__file-name\">{{ value[0].name }}</span>\n <span class=\"edu-upload-dnd__file-size\">{{ value[0] | fileDetails: sizeUnit }}</span>\n } @else {\n {{ 'uploadDnd.fileList.noFile' | dsfrI18n }}\n }\n </div>\n @if (value.length === 1) {\n <dsfr-button\n variant=\"secondary\"\n [type]=\"'button'\"\n [ariaLabel]=\"'uploadDnd.fileList.removeAllDetailed' | dsfrI18n\"\n [size]=\"'MD'\"\n [icon]=\"'fr-icon-delete-line'\"\n [disabled]=\"disabled\"\n (click)=\"deleteAllFiles()\"></dsfr-button>\n }\n </div>\n } @else {\n <div class=\"edu-upload-dnd__resume\" [class.edu-upload-dnd__resume--mobile]=\"isMobile()\">\n <p class=\"fr-sr-only\">{{ 'uploadDnd.fileList.selectedFiles' | dsfrI18n }} :</p>\n @if (multiple && value && value.length > 1) {\n <div class=\"edu-upload-dnd__head\">\n <p>\n <span class=\"fr-icon-file-fill\" aria-hidden=\"true\"></span\n ><span class=\"edu-upload-dnd__list-length\"\n >{{ value.length }} {{ 'uploadDnd.fileList.selectedFiles' | dsfrI18n }}</span\n >\n </p>\n <dsfr-button\n label=\"\"\n icon=\"fr-icon-delete-line\"\n size=\"SM\"\n [ariaLabel]=\"'uploadDnd.fileList.removeAllDetailed' | dsfrI18n\"\n [type]=\"'button'\"\n [variant]=\"'tertiary'\"\n [iconPosition]=\"'right'\"\n [disabled]=\"disabled\"\n (click)=\"deleteAllFiles()\"></dsfr-button>\n </div>\n }\n <ul>\n @for (file of value; track $index) {\n <li>\n <div class=\"edu-upload-dnd__result-line\">\n <span class=\"fr-icon-file-line\" aria-hidden=\"true\"></span>\n <div>\n <p>{{ file.name }}</p>\n <p class=\"edu-upload-dnd__detail\">\n <span class=\"fr-sr-only\">{{ 'uploadDnd.fileList.formatSize' | dsfrI18n }} :</span\n >{{ file | fileDetails: sizeUnit }}\n </p>\n </div>\n <dsfr-button\n [type]=\"'button'\"\n [tooltipMessage]=\"'Supprimer ce document - ' + file.name\"\n variant=\"tertiary-no-outline\"\n size=\"SM\"\n icon=\"fr-icon-delete-line\"\n [disabled]=\"disabled\"\n (click)=\"deleteFile($index)\"></dsfr-button>\n </div>\n </li>\n }\n </ul>\n </div>\n }\n</ng-template>\n", styles: [".edu-upload-dnd__container.edu-upload-dnd__container--inline label{margin-bottom:0}.edu-upload-dnd__container.edu-upload-dnd__container--inline .fr-hint-text{margin-top:.25rem}.edu-upload-dnd__container.edu-upload-dnd__container--inline .edu-upload-dnd__input{position:relative;display:flex;flex-wrap:wrap;flex-direction:row-reverse;align-items:flex-start;justify-content:flex-end;margin-top:.5rem}.edu-upload-dnd__container.edu-upload-dnd__container--inline .edu-upload-dnd__input:has(.fr-upload:focus){outline-width:0}.edu-upload-dnd__container.edu-upload-dnd__container--inline .edu-upload-dnd__input .fr-input{width:17.625rem;margin-right:1rem;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;display:flex;justify-content:space-between;align-items:baseline}.edu-upload-dnd__container.edu-upload-dnd__container--inline .edu-upload-dnd__input .edu-upload-dnd__area .fr-upload:focus+.fr-btn--secondary{outline-offset:2px;outline-color:#0a76f6;outline-width:2px;outline-style:solid}.edu-upload-dnd__container.edu-upload-dnd__container--inline .edu-upload-dnd__input .edu-upload-dnd__area:has(.fr-upload:hover){background-color:var(--hover-tint)}.edu-upload-dnd__container.edu-upload-dnd__container--inline .edu-upload-dnd__input .edu-upload-dnd__area{display:flex;flex-direction:row;align-items:center;padding:0;gap:.5rem;border:0;margin-bottom:1rem}.edu-upload-dnd__container.edu-upload-dnd__container--inline .edu-upload-dnd__input .edu-upload-dnd__drop-zone{border:1px dashed var(--border-plain-grey);color:var(--text-action-high-grey);box-shadow:none;padding:.375rem 1rem}.edu-upload-dnd__container.edu-upload-dnd__container--inline__area:has(.fr-upload:focus) .fr-btn--secondary{outline-offset:2px;outline-color:#0a76f6;outline-width:2px;outline-style:solid}.edu-upload-dnd__container.edu-upload-dnd__container--inline__input:has(.fr-upload:hover) .fr-btn--secondary{background-color:var(--hover-tint)}@media screen and (max-width: 20rem){.edu-upload-dnd__container--inline .edu-upload-dnd__input{flex-wrap:wrap}.edu-upload-dnd__container--inline .edu-upload-dnd__input .fr-input{margin-right:0;width:100%}.edu-upload-dnd__container--inline .edu-upload-dnd__input dsfr-button{padding-right:0;margin-right:0;border-right:0}.edu-upload-dnd__container--inline .edu-upload-dnd__area{margin-top:1rem;width:100%}.edu-upload-dnd__container--inline .edu-upload-dnd__area .fr-upload,.edu-upload-dnd__container--inline .edu-upload-dnd__area .fr-btn--secondary{width:100%;justify-content:center}.edu-upload-dnd__container--inline edu-upload-dnd-resume{display:block;width:100%}}\n", ".edu-upload-dnd__resume{margin-top:0;margin-right:.5rem}.edu-upload-dnd__resume--single{display:flex;width:auto;max-width:100%}.edu-upload-dnd__resume .edu-upload-dnd__head{padding:.25rem .5rem;background-color:var(--background-alt-grey)}.edu-upload-dnd__resume .edu-upload-dnd__result-line dsfr-button,.edu-upload-dnd__resume .edu-upload-dnd__head dsfr-button{padding-right:0;margin-right:0;border-right:0}.edu-upload-dnd__resume .edu-upload-dnd__result-line{padding:.25rem .5rem;align-items:flex-start;width:100%}.edu-upload-dnd__resume .edu-upload-dnd__result-line .fr-icon-file-line:before{--icon-size: 1rem}.edu-upload-dnd__resume .edu-upload-dnd__result-line div{flex-direction:column;gap:0;align-items:flex-start;flex:1;overflow:hidden;white-space:nowrap}.edu-upload-dnd__resume .edu-upload-dnd__result-line div p{font-size:.875rem}.edu-upload-dnd__resume .edu-upload-dnd__result-line .edu-upload-dnd__name{overflow:hidden;text-overflow:ellipsis}.edu-upload-dnd__resume .edu-upload-dnd__result-line .edu-upload-dnd__detail{font-size:.75rem}.edu-upload-dnd__resume ul{margin:0;padding:0;list-style:none}.edu-upload-dnd__resume ul li{margin:0;padding:0}.edu-upload-dnd__file-name{overflow:hidden;text-overflow:ellipsis}.edu-upload-dnd__file-size{font-size:.75rem}.edu-upload-dnd__container--inline .edu-upload-dnd__resume--single{width:auto}.edu-upload-dnd__container--inline .edu-upload-dnd__resume--single dsfr-button{padding-right:.5rem;margin-right:.5rem;border-right:1px solid var(--border-plain-grey)}.edu-upload-dnd__container--inline .edu-upload-dnd__resume{margin-top:0;margin-right:.5rem}.edu-upload-dnd__container--inline .edu-upload-dnd__resume .edu-upload-dnd__head{background-color:var(--background-alt-grey);padding:.25rem .5rem}.edu-upload-dnd__container--inline .edu-upload-dnd__resume .edu-upload-dnd__result-line{align-items:flex-start;padding:.5rem}.edu-upload-dnd__container--inline .edu-upload-dnd__resume .edu-upload-dnd__result-line div{flex-direction:column}@media screen and (max-width: 20rem){.edu-upload-dnd__resume{display:none}.edu-upload-dnd__resume--mobile .edu-upload-dnd__resume{display:block;width:100%;margin-top:0}.edu-upload-dnd__resume--mobile{display:flex;flex-wrap:wrap;margin-top:1rem;margin-right:0}.edu-upload-dnd__resume--mobile .fr-input{text-overflow:ellipsis;overflow:hidden;white-space:nowrap;margin-right:1rem}.edu-upload-dnd__resume--single{width:100%}.edu-upload-dnd__resume--single dsfr-button{margin-left:1rem}.edu-upload-dnd__result-line{padding:.25rem .5rem;align-items:flex-start}.edu-upload-dnd__result-line .fr-icon-file-line:before{--icon-size: 1rem}.edu-upload-dnd__result-line div{flex-direction:column;gap:0;align-items:flex-start;flex:1}.edu-upload-dnd__result-line div p{font-size:.875rem;line-height:normal;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;max-width:190px}.edu-upload-dnd__result-line dsfr-button{margin-left:0}.edu-upload-dnd__result-line .edu-upload-dnd__detail{font-size:.75rem}}\n", ".edu-upload-dnd--error,.edu-upload-dnd--valid,.edu-upload-dnd--info,.edu-upload-dnd--warning{position:relative}.edu-upload-dnd--error:before,.edu-upload-dnd--valid:before,.edu-upload-dnd--info:before,.edu-upload-dnd--warning:before{background-position:0 0;background-repeat:no-repeat;background-size:.125rem 100%;bottom:0;content:\"\";display:block;left:-.75rem;pointer-events:none;position:absolute;right:-.75rem;top:0}.edu-upload-dnd--error:before{background-image:linear-gradient(0deg,var(--border-plain-error),var(--border-plain-error))}.edu-upload-dnd--error label{color:var(--text-default-error)}.edu-upload-dnd--valid:before{background-image:linear-gradient(0deg,var(--border-plain-success),var(--border-plain-success))}.edu-upload-dnd--valid label{color:var(--text-default-success)}.edu-upload-dnd--info:before{background-image:linear-gradient(0deg,var(--border-plain-info),var(--border-plain-info))}.edu-upload-dnd--info label{color:var(--text-default-info)}.edu-upload-dnd--warning:before{background-image:linear-gradient(0deg,var(--border-plain-warning),var(--border-plain-warning))}.edu-upload-dnd--warning label{color:var(--text-default-warning)}.edu-upload-dnd__container p{margin:0;text-overflow:ellipsis}.edu-upload-dnd__container label{margin-bottom:1rem}.edu-upload-dnd__area{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:1rem 2rem;gap:.625rem;border:1px dashed var(--border-action-high-blue-france)}.edu-upload-dnd__area--disabled{border-color:var(--text-disabled-grey)}.edu-upload-dnd__description{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.38rem}.edu-upload-dnd__input .fr-upload{position:absolute;inset:0;opacity:0}.edu-upload-dnd__input:has(.fr-upload:focus){outline-offset:2px;outline-color:#0a76f6;outline-width:2px;outline-style:solid}.edu-upload-dnd__input:has(.fr-upload:hover){background-color:var(--hover-tint)}.edu-upload-dnd__resume{margin-top:1rem;margin-right:0;border:1px solid var(--border-default-grey)}.edu-upload-dnd__resume--single{display:flex;width:100%}.edu-upload-dnd__resume div{overflow:hidden;white-space:nowrap}.edu-upload-dnd__resume span{margin-right:.625rem}.edu-upload-dnd__resume ul{margin:0;padding:0;list-style:none}.edu-upload-dnd__resume ul li{margin:0;padding:0}.edu-upload-dnd__resume .edu-upload-dnd__head,.edu-upload-dnd__resume .edu-upload-dnd__result-line{padding:1rem;display:flex;align-items:center;justify-content:space-between}.edu-upload-dnd__resume .edu-upload-dnd__head{border-bottom:1px solid var(--border-plain-grey);background-color:var(--background-default-grey)}.edu-upload-dnd__resume .edu-upload-dnd__head p{overflow:hidden;white-space:nowrap}.edu-upload-dnd__resume .edu-upload-dnd__head p .edu-upload-dnd__list-length{text-overflow:ellipsis}.edu-upload-dnd__resume .edu-upload-dnd__head dsfr-button{margin-left:.5rem}.edu-upload-dnd__resume .edu-upload-dnd__result-line{background-color:var(--background-alt-grey)}.edu-upload-dnd__resume .edu-upload-dnd__result-line div{display:flex;flex:1;justify-content:space-between;flex-direction:row}.edu-upload-dnd__resume .edu-upload-dnd__result-line dsfr-button{margin-left:1rem}.edu-upload-dnd__resume .edu-upload-dnd__result-line button:hover{background-color:var(--active-tint)}.edu-upload-dnd__resume li:not(:last-child) .edu-upload-dnd__result-line{border-bottom:1px solid var(--border-default-grey)}.edu-upload-dnd__input.fr-btn.fr-btn--secondary.fr-btn--disabled{color:var(--text-disabled-grey);box-shadow:inset 0 0 0 1px var(--text-disabled-grey)}@media screen and (max-width: 20rem){.edu-upload-dnd__area{border:0;padding:0;align-items:flex-start}.edu-upload-dnd__description .edu-upload-dnd__description--mobile{color:var(--text-mention-grey)}.edu-upload-dnd .fr-hint-text{order:2}.edu-upload-dnd__input{position:relative;order:3}.edu-upload-dnd__head{padding:.5rem;width:100%}