EmDash 的 json 字段类型存储任意结构化数据,默认通过接受原始 JSON 的单行文本输入进行编辑。Field Kit 是一个官方插件,为 json 字段提供四个可组合的小部件,完全通过 seed options 进行配置,因此网站构建者可以仅使用 seed schema 来使用它们。
安装
从 npm 安装包:
npm i @emdash-cms/plugin-field-kit
以下配置注册插件:
import { defineConfig } from "astro/config";
import emdash from "emdash/astro";
import { fieldKitPlugin } from "@emdash-cms/plugin-field-kit";
export default defineConfig({
integrations: [
emdash({
plugins: [fieldKitPlugin()],
}),
],
});
通过将 widget 设置为 field-kit:<name> 来将小部件附加到任何 json 字段。以下字段定义使用 list 小部件:
{
"slug": "ingredients",
"type": "json",
"widget": "field-kit:list",
"options": { "fields": [...] }
}
小部件
| 小部件 | 用途 | 存储的值 |
|---|---|---|
object-form | 扁平 JSON 对象的内联表单 | { key: value, ... } |
list | 带有添加/删除/重新排序的有序数组编辑器 | [{ ... }, ...] |
grid | 行×列矩阵 | { rowKey: { colKey: value } } |
tags | 自由形式的芯片/标签输入 | ["tag1", "tag2"] |
如果小部件缺少其必需的 options(例如 object-form/list 的 fields,或 grid 的 rows/columns),编辑器会呈现内联”小部件配置错误”警告,而不是损坏的输入 — 在迭代 seed schema 时很有用。
object-form
呈现作为单个 JSON 对象存储的类型化子字段组。适用于固定形状的结构化数据,如营养信息或联系信息。以下字段定义配置营养对象:
{
"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" }
]
}
}
存储的值:{ "calories": 250, "protein": 12.5, "fat": 8, "carbs": 30 }。
| 选项 | 类型 | 默认值 | 描述 |
|---|---|---|---|
fields | SubFieldDef[] | (必需) | 子字段定义 — 请参阅子字段。 |
collapsed | boolean | false | 默认折叠组。 |
helpText | string | — | 显示在小部件下方的帮助文本。 |
list
具有添加、删除和重新排序控件的有序数组编辑器。每行是一个 JSON 对象,其形状由 fields 定义。行标题显示从 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" }
]
}
}
存储的值是行对象数组:
[
{ "name": "Flour", "amount": "500g", "optional": false },
{ "name": "Butter", "amount": "200g", "optional": false }
]
| 选项 | 类型 | 默认值 | 描述 |
|---|---|---|---|
fields | SubFieldDef[] | (必需) | 每行的子字段定义。 |
itemLabel | string | "Item" | 行的单数标签(用于”添加”按钮和后备行标题)。 |
min | number | — | 最小项目数。低于此数字时,删除按钮隐藏。 |
max | number | — | 最大项目数。达到此计数时,添加按钮隐藏。 |
sortable | boolean | true | 显示上/下重新排序按钮。 |
summary | string | — | 作为折叠行标题呈现的 Mustache 模板。请参阅摘要模板。 |
helpText | string | — | 显示在小部件下方的帮助文本。 |
grid
行×列的二维矩阵。每个单元格可以是切换、文本输入、数字输入或选择。适用于季节性可用性、价格表或功能比较等矩阵。以下字段定义配置季节性可用性网格:
{
"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" }
]
}
}
存储的值是按行键入,然后按列键入的对象:
{
"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 }
}
| 选项 | 类型 | 默认值 | 描述 |
|---|---|---|---|
rows | GridAxisDef[] | (必需) | 行定义:{ key, label, image? }。 |
columns | GridAxisDef[] | (必需) | 列定义:{ key, label, image? }。 |
cell | "toggle" | "text" | "number" | "select" | "toggle" | 单元格输入类型,统一应用于每个单元格。 |
cellOptions | string[] | Array<{ label, value }> | [] | 当 cell 为 "select" 时必需。 |
helpText | string | — | 显示在小部件下方的帮助文本。 |
tags
字符串数组的芯片样式输入。支持固定的 suggestions 列表、自由形式的自定义值(可切换)、大小写转换和可选的 max。以下字段定义配置关键字标签输入:
{
"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"]
}
}
存储的值:["vegan", "gluten-free"]。
按 Enter 或 , 提交标签。在空输入上按 Backspace 删除最后一个标签。重复的标签会被静默忽略。
| 选项 | 类型 | 默认值 | 描述 |
|---|---|---|---|
placeholder | string | "Add..." | 没有标签时显示的输入占位符。 |
max | number | — | 最大标签数。达到限制时输入隐藏。 |
suggestions | string[] | [] | 通过 <datalist> 显示的自动完成建议。 |
allowCustom | boolean | true | 当为 false 时,只能添加 suggestions 中的值。 |
transform | "none" | "lowercase" | "uppercase" | "trim" | "none" | 在添加标签时对其进行规范化。 |
helpText | string | — | 显示在小部件下方的帮助文本。 |
子字段
object-form 和 list 接受类型化子字段定义的 options.fields 数组。每个条目都有一个 key(它写入的 JSON 对象键)、一个 label、一个 type 和类型特定的额外项。
| 子字段类型 | 呈现为 | 值得注意的额外项 |
|---|---|---|
text | 单行输入 | placeholder |
textarea | 多行输入 | rows(默认 3)、placeholder |
number | 数字输入 | min、max、step、prefix、suffix、placeholder |
boolean | 切换开关 | — |
select | 下拉菜单 | options: string[] | Array<{ label, value }>、placeholder |
date | 日期输入 | — |
color | 与十六进制文本输入配对的原生颜色选择器 | — |
url | URL 输入(HTML5 type="url") | placeholder |
每个子字段的通用属性:required、helpText、defaultValue。
摘要模板
list 小部件使用 options.summary 中的 Mustache 样式模板呈现每个折叠的行。{{key}} 被替换为该键的行值(强制转换为字符串)。假值回退到 "{itemLabel} {n}"。以下模板组合两个键:
"summary": "{{name}} — {{amount}}"
呈现如 Flour — 500g 的行。模板是简单的字符串替换 — 没有 HTML,没有嵌套表达式。
数据持久性
Field Kit 小部件将纯 JSON 存储在字段的现有列中,仅使用该列。如果从配置中删除 @emdash-cms/plugin-field-kit,数据仍然有效 — 字段恢复为默认的 json 文本输入。
即使更改小部件形状,这也适用:存储对象上的未知键在下次写入时会被保留,因此您可以在不丢失在较旧字段集下捕获的数据的情况下演化 schema。