Field Kit

En esta página

El tipo de campo json de EmDash almacena datos estructurados arbitrarios, pero el editor predeterminado es una entrada de texto de una sola línea donde debe escribir JSON sin formato a mano. Field Kit es un plugin de primera parte que incluye cuatro widgets componibles para campos json, configurados completamente mediante options de seed — sin necesidad de React para los creadores de sitios.

Instalación

npm i @emdash-cms/plugin-field-kit

Registre el plugin en 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()],
		}),
	],
});

Luego adjunte un widget a cualquier campo json configurando widget como field-kit:<name>:

{
	"slug": "ingredients",
	"type": "json",
	"widget": "field-kit:list",
	"options": { "fields": [...] }
}

Widgets

WidgetUsar paraValor almacenado
object-formFormulario en línea para objetos JSON planos{ key: value, ... }
listEditor de array ordenado con agregar / eliminar / reordenar[{ ... }, ...]
gridMatriz de filas × columnas{ rowKey: { colKey: value } }
tagsEntrada de chip/tag de forma libre["tag1", "tag2"]

Si a un widget le faltan sus options requeridas (por ejemplo, fields para object-form/list, o rows/columns para grid), el editor muestra una advertencia en línea “Widget mal configurado” en lugar de una entrada rota — útil mientras se itera en esquemas de seed.

object-form

Renderiza un grupo de subcampos tipados que se almacenan como un solo objeto JSON. Bueno para datos estructurados de forma fija como datos nutricionales o información de contacto.

{
	"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" }
		]
	}
}

Valor almacenado: { "calories": 250, "protein": 12.5, "fat": 8, "carbs": 30 }.

OpciónTipoPredeterminadoDescripción
fieldsSubFieldDef[](requerido)Definiciones de subcampos — ver Subcampos.
collapsedbooleanfalseRenderizar el grupo colapsado por defecto.
helpTextstringTexto de ayuda mostrado debajo del widget.

list

Un editor de array ordenado con controles de agregar, eliminar y reordenar. Cada fila es un objeto JSON cuya forma está definida por fields. El encabezado de la fila muestra un resumen renderizado desde una plantilla tipo 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" }
		]
	}
}

Valor almacenado:

[
	{ "name": "Flour", "amount": "500g", "optional": false },
	{ "name": "Butter", "amount": "200g", "optional": false }
]
OpciónTipoPredeterminadoDescripción
fieldsSubFieldDef[](requerido)Definiciones de subcampos para cada fila.
itemLabelstring"Item"Etiqueta singular para una fila (usada en el botón “Agregar” y títulos de fila de respaldo).
minnumberNúmero mínimo de elementos. Por debajo de esto, el botón de eliminar se oculta.
maxnumberNúmero máximo de elementos. En este recuento, el botón de agregar se oculta.
sortablebooleantrueMostrar botones de reordenar arriba/abajo.
summarystringPlantilla Mustache renderizada como título de fila colapsada. Ver Plantillas de resumen.
helpTextstringTexto de ayuda mostrado debajo del widget.

grid

Una matriz bidimensional de filas × columnas. Cada celda puede ser un interruptor, entrada de texto, entrada numérica o selección. Útil para matrices como disponibilidad estacional, tablas de precios o comparaciones de características.

{
	"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" }
		]
	}
}

Valor almacenado:

{
	"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 }
}
OpciónTipoPredeterminadoDescripción
rowsGridAxisDef[](requerido)Definiciones de fila: { key, label, image? }.
columnsGridAxisDef[](requerido)Definiciones de columna: { key, label, image? }.
cell"toggle" | "text" | "number" | "select""toggle"Tipo de entrada de celda, aplicado uniformemente a cada celda.
cellOptionsstring[] | Array<{ label, value }>[]Requerido cuando cell es "select".
helpTextstringTexto de ayuda mostrado debajo del widget.

tags

Una entrada tipo chip para arrays de strings. Admite una lista fija de suggestions, valores personalizados de forma libre (conmutable), transformaciones de mayúsculas/minúsculas y un max opcional.

{
	"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"]
	}
}

Valor almacenado: ["vegan", "gluten-free"].

Presione Enter o , para confirmar una etiqueta. Backspace en una entrada vacía elimina la última etiqueta. Las etiquetas duplicadas se ignoran silenciosamente.

OpciónTipoPredeterminadoDescripción
placeholderstring"Add..."Marcador de posición de entrada mostrado cuando no hay etiquetas presentes.
maxnumberNúmero máximo de etiquetas. La entrada se oculta en el límite.
suggestionsstring[][]Sugerencias de autocompletar mostradas mediante una <datalist>.
allowCustombooleantrueCuando es false, solo se pueden agregar valores de suggestions.
transform"none" | "lowercase" | "uppercase" | "trim""none"Normalizar etiquetas a medida que se agregan.
helpTextstringTexto de ayuda mostrado debajo del widget.

Subcampos

object-form y list aceptan un array options.fields de definiciones de subcampos tipados. Cada entrada tiene una key (la clave del objeto JSON en la que escribe), un label, un type y extras específicos del tipo.

Tipo de subcampoSe renderiza comoExtras notables
textEntrada de una sola líneaplaceholder
textareaEntrada de varias líneasrows (predeterminado 3), placeholder
numberEntrada numéricamin, max, step, prefix, suffix, placeholder
booleanInterruptor
selectDesplegableoptions: string[] | Array<{ label, value }>, placeholder
dateEntrada de fecha
colorSelector de color nativo emparejado con entrada de texto hexadecimal
urlEntrada de URL (HTML5 type="url")placeholder

Props comunes en cada subcampo: required, helpText, defaultValue.

Plantillas de resumen

El widget list renderiza cada fila colapsada usando una plantilla tipo Mustache en options.summary. {{key}} se reemplaza con el valor de la fila para esa clave (convertido a string). Los valores falsy vuelven a "{itemLabel} {n}".

"summary": "{{name}} — {{amount}}"

Renderiza filas como Flour — 500g. La plantilla es una sustitución de string simple — sin HTML, sin expresiones anidadas.

Durabilidad de datos

Los widgets de Field Kit almacenan JSON simple en la columna existente del campo. No hay tablas específicas del plugin, ni claves foráneas, ni mutación de esquema. Si elimina @emdash-cms/plugin-field-kit de su configuración, los datos permanecen válidos — solo la UI de edición vuelve a la entrada de texto json predeterminada.

Esto se aplica incluso cuando cambia la forma del widget: las claves desconocidas en los objetos almacenados se conservan en la próxima escritura, por lo que puede evolucionar un esquema sin perder datos capturados bajo un conjunto de campos más antiguo.

Ver también