<div class="rtds-file is-loading-error" id="file-1">
<!-- Icona del file -->
<svg class="rtds-icon rtds-fill-current rtds-w-6 rtds-h-6 md:rtds-w-8 md:rtds-h-8 rtds-file__icon rtds-flex-shrink-0" aria-hidden="true" focusable="false" role="img">
<use href="../../icons.svg#outline--document-text" />
</svg>
<div class="rtds-file__info">
<!-- Informazioni del file -->
<p class="rtds-file__name rtds-text-sm rtds-font-bold rtds-mb-1">documento-errore.docx</p>
<!-- Barra di progresso (per stati loading) -->
<div class="rtds-file__progress">
<div class="rtds-file__progress-bar" role="progressbar" style="--file-progress-bar-width: 30%" aria-valuenow="30" aria-valuemin="0" aria-valuemax="100">
</div>
</div>
<p class="rtds-file__status" aria-live="polite">
<span class="rtds-sr-only">
Errore caricamento file: documento-errore.docx -
</span>
<span class="rtds-file__weight rtds-text-xs rtds-font-medium">15MB</span>
<!-- Messaggio di errore -->
<span class="rtds-file__error rtds-text-xs rtds-font-bold rtds-content-error">
File troppo grande. Dimensione massima: 10MB
</span>
</p>
</div>
<!-- Azioni in base allo stato -->
<!-- Loading Error: icona errore + pulsante cancella -->
<div class="rtds-flex rtds-items-center rtds-gap-2">
<svg class="rtds-icon rtds-fill-current rtds-w-6 rtds-h-6 rtds-text-error" aria-hidden="true" focusable="false" role="img">
<use href="../../icons.svg#outline--exclamation-circle" />
</svg>
<button type="button" class="rtds-btn
rtds-btn--icon rtds-btn--outlined rtds-border-none rtds-flex-shrink-0 rtds-content-01"><svg class="rtds-icon rtds-fill-current rtds-w-6 rtds-h-6" aria-hidden="true" focusable="false" role="img">
<use href="../../icons.svg#outline--x-circle" />
</svg>
<span class="rtds-sr-only">
Annulla caricamento file documento-errore.docx
</span>
</button>
</div>
</div>
<div class="rtds-file {{ status }}" id="file-{{ id }}">
<!-- Icona del file -->
{% render '@icon', {
id: 'outline--document-text',
size: 'rtds-w-6 rtds-h-6 md:rtds-w-8 md:rtds-h-8',
classes: 'rtds-file__icon rtds-flex-shrink-0'
}, true %}
<div class="rtds-file__info">
<!-- Informazioni del file -->
<p class="rtds-file__name rtds-text-sm rtds-font-bold rtds-mb-1">{{ name }}</p>
<!-- Barra di progresso (per stati loading) -->
{% if (status == 'is-loading' or status == 'is-loading-error' or status == 'is-loading-completed') and progress %}
<div class="rtds-file__progress">
<div class="rtds-file__progress-bar"
role="progressbar"
style="--file-progress-bar-width: {{ progress }}%"
aria-valuenow="{{ progress }}"
aria-valuemin="0"
aria-valuemax="100">
</div>
</div>
{% endif %}
{% if size or errorMessage or status != 'is-download' %}
<p class="rtds-file__status" aria-live="polite">
<span class="rtds-sr-only">
{% if status == 'is-loading' %}
Caricamento file in corso: {{ name }} -
{% elif status == 'is-loading-error' %}
Errore caricamento file: {{ name }} -
{% elif status == 'is-loading-completed' %}
Caricamento file completato: {{ name }} -
{% endif %}
</span>
{% if size %}
<span class="rtds-file__weight rtds-text-xs rtds-font-medium">{{ size }}</span>
{% endif %}
{% if status == 'is-loading-error' and errorMessage %}
<!-- Messaggio di errore -->
<span class="rtds-file__error rtds-text-xs rtds-font-bold rtds-content-error">
{{ errorMessage }}
</span>
{% endif %}
</p>
{% endif %}
</div>
<!-- Azioni in base allo stato -->
{% if status == 'is-loading' %}
<!-- Loading: solo pulsante cancella -->
{% render '@button--icon',
{
label: 'Annulla caricamento file ' + name,
icon: 'outline--x-circle',
iconSize: 'rtds-w-6 rtds-h-6',
classes: 'rtds-btn--outlined rtds-border-none rtds-flex-shrink-0 rtds-content-01'
},
true %}
{% elif status == 'is-loading-error' %}
<!-- Loading Error: icona errore + pulsante cancella -->
<div class="rtds-flex rtds-items-center rtds-gap-2">
{% render '@icon', {
id: 'outline--exclamation-circle',
size: 'rtds-w-6 rtds-h-6',
classes: 'rtds-text-error'
}, true %}
{% render '@button--icon',
{
label: 'Annulla caricamento file ' + name,
icon: 'outline--x-circle',
iconSize: 'rtds-w-6 rtds-h-6',
classes: 'rtds-btn--outlined rtds-border-none rtds-flex-shrink-0 rtds-content-01'
},
true %}
</div>
{% elif status == 'is-loading-completed' %}
<!-- Loading Completed: icona check + pulsante cancella -->
<div class="rtds-flex rtds-items-center rtds-gap-2">
{% render '@icon', {
id: 'outline--check-circle',
size: 'rtds-w-6 rtds-h-6',
classes: 'rtds-text-success'
}, true %}
{% render '@button--icon',
{
label: 'Annulla caricamento file ' + name,
icon: 'outline--x-circle',
iconSize: 'rtds-w-6 rtds-h-6',
classes: 'rtds-btn--outlined rtds-border-none rtds-flex-shrink-0 rtds-content-01'
},
true %}
</div>
{% elif status == 'is-download' %}
<!-- Download: pulsante scarica + pulsante elimina -->
<div class="rtds-flex rtds-items-center rtds-gap-2">
{% render '@button--icon',
{
label: 'Scarica il file ' + name,
icon: 'outline--arrow-down-tray',
iconSize: 'rtds-w-6 rtds-h-6',
classes: 'rtds-btn--outlined rtds-border-none rtds-flex-shrink-0 rtds-content-01'
},
true %}
{% render '@button--icon',
{
label: 'Elimina il file ' + name,
icon: 'outline--trash',
iconSize: 'rtds-w-6 rtds-h-6',
classes: 'rtds-btn--outlined rtds-border-none rtds-flex-shrink-0 rtds-content-01'
},
true %}
</div>
{% endif %}
</div>
{
"name": "documento-errore.docx",
"size": "15MB",
"status": "is-loading-error",
"progress": 30,
"id": "1",
"errorMessage": "File troppo grande. Dimensione massima: 10MB"
}
/**
* FILE COMPONENT
* Componente per il caricamento file - FILE SINGOLO
*/
.rtds-file {
gap: var(--spacing-3);
padding-top: var(--spacing-2);
padding-bottom: var(--spacing-2);
border-color: var(--color-border-gray-01);
display: flex;
align-items: center;
padding-left: var(--spacing-4);
padding-right: var(--spacing-4);
border-radius: 0.5rem;
border-width: 1px;
}
.rtds-file__info {
flex: 1 1 0%;
}
.rtds-file:where(.is-loading-error) {
background-image: var(--gradient-03);
}
/* Progress bar */
body.rtds-file__progress .rtds-primary-navigation__backdrop,
:root.rtds-file__progress .rtds-primary-navigation__backdrop {
position: fixed;
right: var(--spacing-0);
bottom: var(--spacing-0);
left: var(--spacing-0);
z-index: 10;
}
@media (min-width: 1024px) {
body.rtds-file__progress .rtds-primary-navigation__backdrop,
:root.rtds-file__progress .rtds-primary-navigation__backdrop {
display: none;
}
}
body.rtds-file__progress .rtds-primary-navigation__backdrop,
:root.rtds-file__progress .rtds-primary-navigation__backdrop {
position: fixed;
right: var(--spacing-0);
bottom: var(--spacing-0);
left: var(--spacing-0);
z-index: 10;
}
@media (min-width: 1024px) {
body.rtds-file__progress .rtds-primary-navigation__backdrop,
:root.rtds-file__progress .rtds-primary-navigation__backdrop {
display: none;
}
}
.rtds-file__progress {
height: var(--spacing-1);
background-color: var(--color-background-03);
border-radius: 0.5rem;
overflow: hidden;
}
.rtds-file__progress-bar {
--_file-progress-bar-width: var(--file-progress-bar-width, 0%);
height: 100%;
width: var(--_file-progress-bar-width);
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
background-color: var(--color-background-secondary);
border-radius: 0.5rem;
transition-property: all;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
}
:where(.is-loading-completed) .rtds-file__progress-bar {
background-color: var(--color-success);
}
:where(.is-loading-error) .rtds-file__progress-bar {
background-color: var(--color-error);
}
/**
* FILE COMPONENT
* Componente per il caricamento file - FILE SINGOLO
*/
@layer components {
.rtds-file {
@apply rtds-flex rtds-items-center rtds-gap-3 rtds-py-2 rtds-px-4 rtds-border rtds-border-gray-01 rtds-rounded-lg;
}
.rtds-file__info {
@apply rtds-flex-1;
}
.rtds-file:where(.is-loading-error) {
@apply rtds-bg-gradient-03;
}
/* Progress bar */
.rtds-file__progress {
@apply rtds-h-1 rtds-background-03 rtds-rounded-lg rtds-overflow-hidden;
}
.rtds-file__progress-bar {
--_file-progress-bar-width: var(--file-progress-bar-width, 0%);
@apply rtds-h-full rtds-background-secondary rtds-rounded-lg rtds-transition-all rtds-duration-300 rtds-ease-out rtds-w-[--_file-progress-bar-width];
}
:where(.is-loading-completed) .rtds-file__progress-bar {
@apply rtds-bg-success;
}
:where(.is-loading-error) .rtds-file__progress-bar {
@apply rtds-bg-error;
}
}
Componente per la rappresentazione di un singolo file con diversi stati di caricamento e azioni disponibili.
Il componente File rappresenta un singolo elemento file con stato specifico. È progettato per essere utilizzato all’interno di liste di file e supporta diversi stati operativi con azioni appropriate per ciascuno.
Contesto di sviluppo Fractal/Nunjucks — Questa sezione riguarda esclusivamente i parametri del context .config.yml usati durante lo sviluppo nella libreria. Non descrive attributi HTML da usare nei temi o ambienti di implementazione.
name (string)"documento.pdf"size (string)"1.2MB"status (string)loading, loading-error, loading-completed, downloadprogress (number)65errorMessage (string)loading-error"File troppo grande"Il componente genera un elemento <li> con le classi CSS appropriate:
<li class="rtds-upload__file [status]">
<!-- Icona file -->
<!-- Informazioni file -->
<!-- Azioni (pulsanti) -->
<!-- Progress bar (se necessario) -->
<!-- Messaggio errore (se necessario) -->
</li>Il componente è progettato per essere utilizzato dentro il componente Upload
Livello AA — criteri pertinenti:
role="progressbar" con aria-valuenow, aria-valuemin, aria-valuemaxaria-live="polite" per annunciare aggiornamenti dinamici al filertds-file__status con aria-live="polite" comunica i cambiamenti di stato ai dispositivi assistivi senza spostare il focus<div class="rtds-file [status]"> — contenitore non semantico; il contesto semantico è fornito dai testi nascosti e dalle label dei pulsanti<p> — non è un heading; il contesto semantico è nel testo del pulsante azione che include il nome del filertds-file__status ha aria-live="polite" — gli aggiornamenti di stato (dimensione, errore) vengono annunciati automaticamente agli screen reader| Attributo | Valori | Condizione |
|---|---|---|
role="progressbar" |
progressbar |
Sul div della barra di progresso — negli stati is-loading, is-loading-error, is-loading-completed |
aria-valuenow |
numero (0–100) | Sul progressbar — valore corrente dell’avanzamento |
aria-valuemin |
0 |
Sul progressbar |
aria-valuemax |
100 |
Sul progressbar |
aria-live="polite" |
polite |
Sul paragrafo rtds-file__status — annuncia aggiornamenti di stato senza interrompere |
| Tasto | Azione |
|---|---|
Tab / Shift+Tab |
Sposta il focus tra i pulsanti azione disponibili per lo stato corrente |
Enter / Space |
Attiva il pulsante focalizzato (annulla, scarica o elimina) |
:focus-visible è sempre visibile e non viene rimosso via CSSrtds-file__status contiene un <span class="rtds-sr-only"> con testo contestuale dipendente dallo stato: “Caricamento file in corso: [nome]”, “Errore caricamento file: [nome]”, “Caricamento file completato: [nome]” — fornisce contesto immediato prima dei dati (dimensione, messaggio di errore)outline--exclamation-circle) e quella di completamento (outline--check-circle) sono decorative — hanno aria-hidden="true" tramite il componente @iconis-downloadoutline--document-text: Icona fileoutline--x-mark: Pulsante cancella/rimuovioutline--exclamation-triangle: Stato erroreoutline--check: Stato completatooutline--arrow-down-tray: Pulsante scaricaoutline--trash: Pulsante eliminaIl componente utilizza le stesse classi CSS del componente Upload:
.rtds-upload__file: Container principale.rtds-upload__file.loading: Stato caricamento.rtds-upload__file.loading-error: Stato errore.rtds-upload__file.loading-completed: Stato completato.rtds-upload__file.download: Stato downloadPer integrare funzionalità: