Le type de champ json d’EmDash stocke des données structurées arbitraires, mais l’éditeur par défaut est une saisie de texte sur une seule ligne où vous devez taper du JSON brut à la main. Field Kit est un plugin de première partie qui fournit quatre widgets composables pour les champs json, entièrement configurés via les options de seed — aucun React requis pour les créateurs de sites.
Installation
npm i @emdash-cms/plugin-field-kit
Enregistrez le plugin dans astro.config.mjs :
import { defineConfig } from "astro/config";
import emdash from "emdash";
import { fieldKitPlugin } from "@emdash-cms/plugin-field-kit";
export default defineConfig({
integrations: [
emdash({
plugins: [fieldKitPlugin()],
}),
],
});
Ensuite, attachez un widget à n’importe quel champ json en définissant widget sur field-kit:<name> :
{
"slug": "ingredients",
"type": "json",
"widget": "field-kit:list",
"options": { "fields": [...] }
}
Widgets
| Widget | Utiliser pour | Valeur stockée |
|---|---|---|
object-form | Formulaire en ligne pour objets JSON plats | { key: value, ... } |
list | Éditeur de tableau ordonné avec ajouter / supprimer / réorganiser | [{ ... }, ...] |
grid | Matrice lignes × colonnes | { rowKey: { colKey: value } } |
tags | Saisie de chip/tag en forme libre | ["tag1", "tag2"] |
Si un widget manque ses options requises (par exemple fields pour object-form/list, ou rows/columns pour grid), l’éditeur affiche un avertissement en ligne “Widget mal configuré” au lieu d’une saisie cassée — utile lors de l’itération sur les schémas de seed.
object-form
Affiche un groupe de sous-champs typés qui sont stockés comme un seul objet JSON. Bon pour les données structurées de forme fixe comme les valeurs nutritionnelles ou les informations de contact.
{
"slug": "nutrition",
"type": "json",
"widget": "field-kit:object-form",
"options": {
"collapsed": false,
"fields": [
{ "key": "calories", "label": "Calories", "type": "number", "suffix": "kcal" },
{ "key": "protein", "label": "Protein", "type": "number", "suffix": "g" },
{ "key": "fat", "label": "Fat", "type": "number", "suffix": "g" },
{ "key": "carbs", "label": "Carbs", "type": "number", "suffix": "g" }
]
}
}
Valeur stockée : { "calories": 250, "protein": 12.5, "fat": 8, "carbs": 30 }.
| Option | Type | Par défaut | Description |
|---|---|---|---|
fields | SubFieldDef[] | (requis) | Définitions de sous-champs — voir Sous-champs. |
collapsed | boolean | false | Afficher le groupe réduit par défaut. |
helpText | string | — | Texte d’aide affiché sous le widget. |
list
Un éditeur de tableau ordonné avec des contrôles d’ajout, de suppression et de réorganisation. Chaque ligne est un objet JSON dont la forme est définie par fields. L’en-tête de ligne affiche un résumé rendu à partir d’un modèle de type Mustache.
{
"slug": "ingredients",
"type": "json",
"widget": "field-kit:list",
"options": {
"itemLabel": "Ingredient",
"min": 1,
"max": 50,
"sortable": true,
"summary": "{{name}} — {{amount}}",
"fields": [
{ "key": "name", "label": "Name", "type": "text", "required": true },
{ "key": "amount", "label": "Amount", "type": "text" },
{ "key": "optional", "label": "Optional", "type": "boolean" }
]
}
}
Valeur stockée :
[
{ "name": "Flour", "amount": "500g", "optional": false },
{ "name": "Butter", "amount": "200g", "optional": false }
]
| Option | Type | Par défaut | Description |
|---|---|---|---|
fields | SubFieldDef[] | (requis) | Définitions de sous-champs pour chaque ligne. |
itemLabel | string | "Item" | Étiquette au singulier pour une ligne (utilisée dans le bouton “Ajouter” et les titres de ligne de secours). |
min | number | — | Nombre minimum d’éléments. En dessous, le bouton de suppression est masqué. |
max | number | — | Nombre maximum d’éléments. À ce nombre, le bouton d’ajout est masqué. |
sortable | boolean | true | Afficher les boutons de réorganisation haut/bas. |
summary | string | — | Modèle Mustache rendu comme titre de ligne réduite. Voir Modèles de résumé. |
helpText | string | — | Texte d’aide affiché sous le widget. |
grid
Une matrice bidimensionnelle de lignes × colonnes. Chaque cellule peut être un interrupteur, une saisie de texte, une saisie numérique ou une sélection. Utile pour les matrices comme la disponibilité saisonnière, les tableaux de prix ou les comparaisons de fonctionnalités.
{
"slug": "availability",
"type": "json",
"widget": "field-kit:grid",
"options": {
"cell": "toggle",
"rows": [
{ "key": "berries", "label": "Berries" },
{ "key": "stoneFruit", "label": "Stone fruit" },
{ "key": "citrus", "label": "Citrus" }
],
"columns": [
{ "key": "spring", "label": "Spring" },
{ "key": "summer", "label": "Summer" },
{ "key": "autumn", "label": "Autumn" },
{ "key": "winter", "label": "Winter" }
]
}
}
Valeur stockée :
{
"berries": { "spring": false, "summer": true, "autumn": false, "winter": false },
"stoneFruit": { "spring": false, "summer": true, "autumn": true, "winter": false },
"citrus": { "spring": false, "summer": false, "autumn": true, "winter": true }
}
| Option | Type | Par défaut | Description |
|---|---|---|---|
rows | GridAxisDef[] | (requis) | Définitions de lignes : { key, label, image? }. |
columns | GridAxisDef[] | (requis) | Définitions de colonnes : { key, label, image? }. |
cell | "toggle" | "text" | "number" | "select" | "toggle" | Type de saisie de cellule, appliqué uniformément à chaque cellule. |
cellOptions | string[] | Array<{ label, value }> | [] | Requis lorsque cell est "select". |
helpText | string | — | Texte d’aide affiché sous le widget. |
tags
Une saisie de type chip pour les tableaux de chaînes. Prend en charge une liste fixe de suggestions, des valeurs personnalisées en forme libre (basculables), des transformations de casse et un max optionnel.
{
"slug": "keywords",
"type": "json",
"widget": "field-kit:tags",
"options": {
"placeholder": "Add a keyword…",
"max": 10,
"transform": "lowercase",
"allowCustom": true,
"suggestions": ["vegan", "vegetarian", "gluten-free", "dairy-free", "nut-free"]
}
}
Valeur stockée : ["vegan", "gluten-free"].
Appuyez sur Enter ou , pour valider une étiquette. Backspace sur une saisie vide supprime la dernière étiquette. Les étiquettes en double sont silencieusement ignorées.
| Option | Type | Par défaut | Description |
|---|---|---|---|
placeholder | string | "Add..." | Espace réservé de saisie affiché lorsqu’il n’y a pas d’étiquettes présentes. |
max | number | — | Nombre maximum d’étiquettes. La saisie est masquée à la limite. |
suggestions | string[] | [] | Suggestions d’autocomplétion affichées via une <datalist>. |
allowCustom | boolean | true | Lorsque false, seules les valeurs de suggestions peuvent être ajoutées. |
transform | "none" | "lowercase" | "uppercase" | "trim" | "none" | Normaliser les étiquettes au fur et à mesure qu’elles sont ajoutées. |
helpText | string | — | Texte d’aide affiché sous le widget. |
Sous-champs
object-form et list acceptent un tableau options.fields de définitions de sous-champs typés. Chaque entrée a une key (la clé d’objet JSON dans laquelle elle écrit), un label, un type et des extras spécifiques au type.
| Type de sous-champ | Rendu en tant que | Extras notables |
|---|---|---|
text | Saisie sur une seule ligne | placeholder |
textarea | Saisie sur plusieurs lignes | rows (par défaut 3), placeholder |
number | Saisie numérique | min, max, step, prefix, suffix, placeholder |
boolean | Interrupteur | — |
select | Liste déroulante | options: string[] | Array<{ label, value }>, placeholder |
date | Saisie de date | — |
color | Sélecteur de couleur natif associé à une saisie de texte hexadécimal | — |
url | Saisie d’URL (HTML5 type="url") | placeholder |
Props communes sur chaque sous-champ : required, helpText, defaultValue.
Modèles de résumé
Le widget list affiche chaque ligne réduite à l’aide d’un modèle de type Mustache dans options.summary. {{key}} est remplacé par la valeur de la ligne pour cette clé (convertie en chaîne). Les valeurs falsy reviennent à "{itemLabel} {n}".
"summary": "{{name}} — {{amount}}"
Affiche les lignes comme Flour — 500g. Le modèle est une simple substitution de chaîne — pas de HTML, pas d’expressions imbriquées.
Durabilité des données
Les widgets Field Kit stockent du JSON simple dans la colonne existante du champ. Il n’y a pas de tables spécifiques au plugin, pas de clés étrangères, pas de mutation de schéma. Si vous supprimez @emdash-cms/plugin-field-kit de votre configuration, les données restent valides — seule l’interface utilisateur d’édition revient à la saisie de texte json par défaut.
Cela s’applique même lorsque vous modifiez la forme du widget : les clés inconnues sur les objets stockés sont préservées lors de la prochaine écriture, vous pouvez donc faire évoluer un schéma sans perdre les données capturées sous un ensemble de champs plus ancien.
Voir aussi
- Aperçu des plugins — comment fonctionnent les plugins EmDash.
- Choisir un format de plugin — écrivez vos propres widgets de champ si Field Kit ne convient pas.
- Discussion #571 — la proposition qui a conduit à ce plugin.