Components

FormSectionRow

Componente interno per il rendering di righe e campi di una sezione form, con validazione inline e modalità inplace.

Panoramica

FormSectionRow è un componente interno che gestisce il rendering dinamico di righe e campi all'interno di una sezione di DynamicFormLayouts. Non è destinato all'uso diretto nelle applicazioni: viene utilizzato automaticamente da DynamicFormLayouts e DynamicFormDrawerWithTable.

Gestisce:

  • Rendering dinamico del componente corretto in base al type del campo
  • Validazione on-blur con messaggi tradotti
  • Modalità inplace con conferma/annulla per editing inline
  • Visibilità e disabilitazione condizionale dei campi
  • Propagazione dello stato di validazione alla sezione parent
  • Supporto span per campi che occupano più colonne

Caratteristiche tecniche

Mappatura tipo → componente

Il rendering avviene tramite componentMap, che mappa ogni type al componente Vue corrispondente. Tutti i tipi supportati da DynamicFormLayouts sono disponibili (es. 'text', 'date', 'selectremote', 'tiptap', ecc.).

Modalità inplace

Quando un campo ha inplace: true nello schema, FormSectionRow avvolge il componente in un componente Inplace di @pzeta/vue-components:

  1. L'utente vede il valore corrente come testo cliccabile
  2. Al click, appare il componente di editing con i pulsanti Conferma/Annulla
  3. Conferma: emette fieldCommit con il nuovo valore
  4. Annulla: ripristina il valore originale tramite un secondo fieldCommit

I valori temporanei durante l'editing inplace sono separati dai valori del form, evitando modifiche accidentali.

Visualizzazione testo in modalità inplace

Il metodo getInplaceDisplayText gestisce automaticamente diversi tipi di valore:

  • Stringa/numero: visualizzazione diretta
  • Array: elementi uniti da virgola (estrae label/name dagli oggetti)
  • Booleano: tradotto in "Sì"/"No"
  • Date: formattato con toLocaleDateString()
  • Oggetto: estrae label, name o value
  • Vuoto: mostra il placeholder del campo o "Click to edit"

Utilizzo (da DynamicFormLayouts)

<!-- Uso interno in DynamicFormLayouts -->
<FormSectionRow
  :section="sezione"
  :section-index="0"
  :form-data="formData"
  :dev-mode="false"
  @field-commit="handleFieldCommit"
  @section-validation-change="handleValidation"
/>

Anteprima — modalità inplace

Con inplace: true il campo mostra il valore corrente come testo cliccabile; al click appare il componente di editing con Conferma/Annulla.

Props

PropTipoDefaultDescrizione
sectionSectionDefinitionDefinizione della sezione con righe e campi
sectionIndexnumberIndice della sezione nel form (passato negli eventi e nello scope dei slot section-before/after del parent)
formDataRecord<string, unknown>Dati correnti del form
validbooleantrueStato di validità iniziale
devModebooleanfalseAbilita informazioni di debug
crossFieldErrorsRecord<string, string>{}Mappa { fieldName → messaggio } di errori cross-field calcolati dal parent (chiavi i18n o testo custom). Sommati agli errori locali on-blur
isEditbooleanfalseModalità modifica del form contenitore. Quando false (insert) la validazione on-blur dei campi è disattivata — UX più morbida durante la prima compilazione. Il pulsante save resta disabled grazie a isFormValid live calcolato dal parent

Tipi correlati

Vedi DynamicFormLayouts → Schema FormSchema per la struttura completa di SectionDefinition, RowDefinition, FieldDefinition (incluse help reattivo, transform, onChange, disabled/visible come FieldVisibility).

Metodi esposti

MetodoFirmaDescrizione
validateAll()() => booleanValida tutti i campi visibili e non disabilitati; ritorna true se tutti validi
fieldErrorsRef<Record<string, string>>Mappa degli errori di validazione correnti
<FormSectionRow ref="sectionRowRef" ... />

// Validazione manuale prima del submit
const tuttoValido = sectionRowRef.value?.validateAll()

Eventi

EventoPayloadDescrizione
fieldCommit(fieldName: string, value: unknown)Campo aggiornato (standard, conferma inplace, oppure singola chiave di una transform.write patch). Il parent persiste il valore in formData
fieldChange(fieldName: string, value: unknown, formData: Record<string, unknown>)Emesso dopo fieldCommit con lo snapshot post-commit del formData. Il parent può forwardarlo come evento globale per logiche trasversali (telemetria, autosave)
sectionValidationChange(sectionIndex: number, isValid: boolean)Cambio stato validazione della sezione (calcolata live sui valori correnti, non dipende da blur/validateAll)
buttonClick(fieldName: string, action: string, value: unknown)Click su campo di tipo button

Layout griglia

Quando almeno un campo della riga ha span esplicito, la riga usa una griglia a 12 colonne; altrimenti viene generata una grid con una colonna per ciascun campo (comportamento storico):

// Almeno un span esplicito → grid a 12 colonne
row.fields.some(f => typeof f.span === 'number')
  ? 'grid-template-columns: repeat(12, minmax(0, 1fr))'
  : `grid-template-columns: repeat(${row.fields.length}, minmax(0, 1fr))`

Lo span è applicato come stile inline gridColumn: span N / span N (non come classe col-span-N) per evitare problemi di Tailwind purge sulle classi generate a runtime:

// Campo che occupa 6 colonne su 12
{ name: 'descrizione', type: 'text', span: 6 }
// Stile inline: grid-column: span 6 / span 6

Quando nessun campo ha span, la grid usa repeat(N, 1fr) con N = numero di campi, e i campi non ricevono alcuno stile gridColumn (occupano una cella ciascuno).

Per campi senza span in una riga dove altri lo hanno, lo span auto è floor(12 / N). Lo span è clampato in [1, 12].

Nota: FormSectionRow è un componente di implementazione interna. Per configurare la struttura del form, modificare lo schema passato a DynamicFormLayouts o DynamicFormDrawerWithTable.