<div class="rtds-file is-loading" 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-esempio.pdf</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: 50%" aria-valuenow="50" aria-valuemin="0" aria-valuemax="100">
            </div>
        </div>

        <p class="rtds-file__status" aria-live="polite">

            <span class="rtds-sr-only">

                Caricamento file in corso: documento-esempio.pdf -

            </span>

            <span class="rtds-file__weight rtds-text-xs rtds-font-medium">1.2MB</span>

        </p>

    </div>
    <!-- Azioni in base allo stato -->

    <!-- Loading: solo pulsante cancella -->
    <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-esempio.pdf
        </span>

    </button>

</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-esempio.pdf",
  "size": "1.2MB",
  "status": "is-loading",
  "progress": 50,
  "id": "1"
}
  • Content:
    /**
     * 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);
    }
    
  • URL: /components/raw/file/file.built.css
  • Filesystem Path: components/08-servizi/file/file.built.css
  • Size: 2.4 KB
  • Content:
    /**
     * 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;
        }
    
    }
  • URL: /components/raw/file/file.css
  • Filesystem Path: components/08-servizi/file/file.css
  • Size: 995 Bytes

Componente File

Componente per la rappresentazione di un singolo file con diversi stati di caricamento e azioni disponibili.

Descrizione

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.

Stati Supportati

1. Loading

  • Utilizzo: File in fase di caricamento
  • Elementi: Icona file + info + progress bar + pulsante cancella (X)
  • Azioni: Annulla caricamento

2. Loading Error

  • Utilizzo: Errore durante il caricamento
  • Elementi: Icona file + info + icona errore (!) + progress bar + pulsante cancella (X) + messaggio errore
  • Azioni: Rimuovi file con errore

3. Loading Completed

  • Utilizzo: Caricamento completato con successo
  • Elementi: Icona file + info + icona check + progress bar al 100% + pulsante cancella (X)
  • Azioni: Rimuovi file

4. Download

  • Utilizzo: File già disponibile per download
  • Elementi: Icona file + info + pulsante scarica + pulsante elimina (cestino)
  • Azioni: Scarica file, Elimina file

Parametri

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)

  • Descrizione: Nome del file
  • Obbligatorio: Sì
  • Esempio: "documento.pdf"

size (string)

  • Descrizione: Dimensione del file
  • Obbligatorio: No
  • Esempio: "1.2MB"

status (string)

  • Descrizione: Stato del file
  • Valori: loading, loading-error, loading-completed, download
  • Obbligatorio: Sì

progress (number)

  • Descrizione: Percentuale di avanzamento (0-100)
  • Obbligatorio: Solo per stati loading
  • Esempio: 65

errorMessage (string)

  • Descrizione: Messaggio di errore
  • Obbligatorio: Solo per loading-error
  • Esempio: "File troppo grande"

Struttura HTML

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>

Utilizzo nel Componente Upload

Il componente è progettato per essere utilizzato dentro il componente Upload

Accessibilità

WCAG 2.1

Livello AA — criteri pertinenti:

  • 4.1.2 Nome, ruolo, valore — tutti i pulsanti azione hanno label descrittive che includono il nome del file; la progress bar espone role="progressbar" con aria-valuenow, aria-valuemin, aria-valuemax
  • 1.3.1 Informazioni e correlazioni — il paragrafo di stato ha aria-live="polite" per annunciare aggiornamenti dinamici al file
  • 4.1.3 Messaggi di stato — il paragrafo rtds-file__status con aria-live="polite" comunica i cambiamenti di stato ai dispositivi assistivi senza spostare il focus

Struttura e semantica

  • Il componente è renderizzato come <div class="rtds-file [status]"> — contenitore non semantico; il contesto semantico è fornito dai testi nascosti e dalle label dei pulsanti
  • Il nome del file è un <p> — non è un heading; il contesto semantico è nel testo del pulsante azione che include il nome del file
  • Il paragrafo rtds-file__status ha aria-live="polite" — gli aggiornamenti di stato (dimensione, errore) vengono annunciati automaticamente agli screen reader

Attributi ARIA

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)

Gestione del focus

  • Focus visibile: lo stile :focus-visible è sempre visibile e non viene rimosso via CSS

Screen reader

  • Il paragrafo rtds-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)
  • I pulsanti azione includono il nome del file nella label (es. “Annulla caricamento file documento.pdf”) — evita ambiguità quando più file sono presenti nella lista
  • L’icona di errore (outline--exclamation-circle) e quella di completamento (outline--check-circle) sono decorative — hanno aria-hidden="true" tramite il componente @icon
  • Il progressbar è nel DOM solo negli stati loading — viene rimosso dal DOM (non solo nascosto) quando lo stato è is-download

Icone Utilizzate

  • outline--document-text: Icona file
  • outline--x-mark: Pulsante cancella/rimuovi
  • outline--exclamation-triangle: Stato errore
  • outline--check: Stato completato
  • outline--arrow-down-tray: Pulsante scarica
  • outline--trash: Pulsante elimina

CSS

Il 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 download

Note di Sviluppo

  • Nessun JavaScript: Componente puramente visuale
  • CSS condiviso: Usa gli stili del componente Upload
  • Icone modulari: Utilizza il sistema di icone esistente
  • Flessibile: Facilmente estendibile per nuovi stati

Integrazione

Per integrare funzionalità:

  1. Aggiungi event listeners ai pulsanti
  2. Gestisci azioni (scarica, elimina, cancella)
  3. Aggiorna stato dinamicamente
  4. Mantieni accessibilità durante cambiamenti