Skip to content

Panneaux de configuration personnalisés

Une application hôte peut remplacer le panneau de propriétés interne pour un type de champ précis, sans modifier le layer.

La prop publique config-panels reçoit un registre ordonné de composants Vue. Le premier panneau correspondant au champ sélectionné est utilisé.

Contrat public

ts
import type {
  QFormBuilderConfigPanelProps,
  QFormBuilderConfigPanelRegistry,
} from '@vevedh/qform-builder-layer/types'

Chaque définition contient :

PropriétéTypeRôle
keystringIdentifiant stable du panneau.
componentComponentComposant Vue rendu dans le drawer droit.
matchstring | (field) => booleanCorrespondance sur $formkit, $el, qformKind, configPanel ou prédicat personnalisé.
prioritynumberPriorité optionnelle. La valeur la plus élevée gagne.

Le composant reçoit les props suivantes :

ts
export interface QFormBuilderConfigPanelProps {
  field: BuilderSchemaField
  builderId: string
  updateField: (patch: Partial<BuilderSchemaField>) => void
  close: () => void
}

updateField() doit être utilisé pour appliquer les modifications. Il met à jour le schéma contrôlé, l’historique et l’autosave du builder.

Composant de panneau

vue
<script setup lang="ts">
import type { QFormBuilderConfigPanelProps } from '@vevedh/qform-builder-layer/types'

const props = defineProps<QFormBuilderConfigPanelProps>()

const label = computed({
  get: () => String(props.field.label || ''),
  set: value => props.updateField({ label: value }),
})

const placeholder = computed({
  get: () => String(props.field.placeholder || ''),
  set: value => props.updateField({ placeholder: value }),
})
</script>

<template>
  <q-list separator>
    <q-item-label header>Configuration métier</q-item-label>

    <q-item>
      <q-item-section class="q-gutter-md">
        <q-input v-model="label" filled dense label="Libellé" />
        <q-input v-model="placeholder" filled dense label="Texte indicatif" />
      </q-item-section>
    </q-item>

    <q-item>
      <q-item-section side>
        <q-btn flat no-caps label="Fermer" @click="close" />
      </q-item-section>
    </q-item>
  </q-list>
</template>

Enregistrement dans FormBuilder

vue
<script setup lang="ts">
import { markRaw } from 'vue'
import type { QFormBuilderConfigPanelRegistry } from '@vevedh/qform-builder-layer/types'
import BusinessTextFieldPanel from '~/components/forms/BusinessTextFieldPanel.vue'

const configPanels: QFormBuilderConfigPanelRegistry = [
  {
    key: 'business-text-field',
    component: markRaw(BusinessTextFieldPanel),
    match: field => field.$formkit === 'q-input' && field.inputType === 'text',
    priority: 100,
  },
]
</script>

<template>
  <FormBuilder
    builder-id="business-form"
    :config-panels="configPanels"
  />
</template>

Bonnes pratiques

  • Utiliser une key stable et unique.
  • Utiliser markRaw() pour éviter que Vue rende la définition du composant réactive.
  • Ne jamais modifier directement field : passer par updateField().
  • Garder les règles métier et les appels réseau dans un store ou un repository, pas dans le panneau.
  • Utiliser un prédicat étroit pour éviter de remplacer involontairement plusieurs familles de champs.

QForm Builder — layer Nuxt 4, Quasar et FormKit pour formulaires dynamiques.