@bettercms-ai/kit 2.0.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/lossy.d.ts +12 -4
- package/dist/adapters/lossy.js +19 -8
- package/dist/adapters/lossy.js.map +1 -1
- package/dist/adapters/prod-types.d.ts +46 -14
- package/dist/adapters/prod-types.js +37 -35
- package/dist/adapters/prod-types.js.map +1 -1
- package/dist/adapters/schema.d.ts +39 -0
- package/dist/adapters/schema.js +281 -82
- package/dist/adapters/schema.js.map +1 -1
- package/dist/context.d.ts +39 -0
- package/dist/context.js +40 -1
- package/dist/context.js.map +1 -1
- package/dist/controls/form-picker-register.d.ts +7 -1
- package/dist/controls/form-picker-register.js +1 -5
- package/dist/controls/form-picker-register.js.map +1 -1
- package/dist/controls/icon.d.ts +1 -1
- package/dist/controls/icon.js +1 -1
- package/dist/controls/icon.js.map +1 -1
- package/dist/controls/link.d.ts +11 -4
- package/dist/controls/link.js +120 -202
- package/dist/controls/link.js.map +1 -1
- package/dist/controls/location.js +3 -8
- package/dist/controls/location.js.map +1 -1
- package/dist/controls/media.d.ts +0 -14
- package/dist/controls/media.js +52 -95
- package/dist/controls/media.js.map +1 -1
- package/dist/controls/reference-services.d.ts +23 -2
- package/dist/controls/reference.d.ts +2 -2
- package/dist/controls/reference.js +79 -28
- package/dist/controls/reference.js.map +1 -1
- package/dist/controls/rich-text/article-shell.d.ts +145 -0
- package/dist/controls/rich-text/article-shell.js +514 -0
- package/dist/controls/rich-text/article-shell.js.map +1 -0
- package/dist/controls/rich-text/author.d.ts +25 -0
- package/dist/controls/rich-text/author.js +107 -0
- package/dist/controls/rich-text/author.js.map +1 -0
- package/dist/controls/rich-text/blocks.d.ts +19 -2
- package/dist/controls/rich-text/blocks.js +275 -638
- package/dist/controls/rich-text/blocks.js.map +1 -1
- package/dist/controls/rich-text/button.d.ts +23 -0
- package/dist/controls/rich-text/button.js +81 -0
- package/dist/controls/rich-text/button.js.map +1 -0
- package/dist/controls/rich-text/catalog.d.ts +2 -5
- package/dist/controls/rich-text/catalog.js +121 -7
- package/dist/controls/rich-text/catalog.js.map +1 -1
- package/dist/controls/rich-text/checklist.d.ts +24 -0
- package/dist/controls/rich-text/checklist.js +115 -0
- package/dist/controls/rich-text/checklist.js.map +1 -0
- package/dist/controls/rich-text/codec.d.ts +15 -1
- package/dist/controls/rich-text/codec.js +11 -1
- package/dist/controls/rich-text/codec.js.map +1 -1
- package/dist/controls/rich-text/columns.d.ts +41 -0
- package/dist/controls/rich-text/columns.js +181 -0
- package/dist/controls/rich-text/columns.js.map +1 -0
- package/dist/controls/rich-text/control.js +1 -0
- package/dist/controls/rich-text/control.js.map +1 -1
- package/dist/controls/rich-text/dom.d.ts +84 -4
- package/dist/controls/rich-text/dom.js +171 -10
- package/dist/controls/rich-text/dom.js.map +1 -1
- package/dist/controls/rich-text/editor.d.ts +4 -2
- package/dist/controls/rich-text/editor.js +199 -26
- package/dist/controls/rich-text/editor.js.map +1 -1
- package/dist/controls/rich-text/embed.d.ts +28 -0
- package/dist/controls/rich-text/embed.js +210 -0
- package/dist/controls/rich-text/embed.js.map +1 -0
- package/dist/controls/rich-text/footnote.d.ts +41 -0
- package/dist/controls/rich-text/footnote.js +185 -0
- package/dist/controls/rich-text/footnote.js.map +1 -0
- package/dist/controls/rich-text/gallery.d.ts +28 -0
- package/dist/controls/rich-text/gallery.js +167 -0
- package/dist/controls/rich-text/gallery.js.map +1 -0
- package/dist/controls/rich-text/link-form.d.ts +13 -1
- package/dist/controls/rich-text/link-form.js +41 -7
- package/dist/controls/rich-text/link-form.js.map +1 -1
- package/dist/controls/rich-text/ops.js +6 -0
- package/dist/controls/rich-text/ops.js.map +1 -1
- package/dist/controls/rich-text/related.d.ts +49 -0
- package/dist/controls/rich-text/related.js +233 -0
- package/dist/controls/rich-text/related.js.map +1 -0
- package/dist/controls/rich-text/toc.d.ts +47 -0
- package/dist/controls/rich-text/toc.js +160 -0
- package/dist/controls/rich-text/toc.js.map +1 -0
- package/dist/controls/slot-register.d.ts +6 -1
- package/dist/controls/slot-register.js +1 -4
- package/dist/controls/slot-register.js.map +1 -1
- package/dist/core/core.d.ts +11 -3
- package/dist/core/core.js +24 -6
- package/dist/core/core.js.map +1 -1
- package/dist/core/facets.d.ts +16 -0
- package/dist/core/facets.js +17 -1
- package/dist/core/facets.js.map +1 -1
- package/dist/core/index.js +2 -2
- package/dist/index.js +16 -5
- package/dist/index.js.map +1 -1
- package/dist/ledgers/exclusions.v1.js +141 -0
- package/dist/ledgers/exclusions.v1.js.map +1 -0
- package/dist/library/coverage.d.ts +13 -1
- package/dist/library/coverage.js +12 -1
- package/dist/library/coverage.js.map +1 -1
- package/dist/library/kit-catalog.json +156 -153
- package/dist/schema/types.d.ts +17 -0
- package/dist/schema/types.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/testing/coverage-extras.d.ts +8 -0
- package/dist/testing/coverage-extras.js +44 -0
- package/dist/testing/coverage-extras.js.map +1 -0
- package/dist/testing/exclusions.d.ts +30 -0
- package/dist/testing/exclusions.js +13 -0
- package/dist/testing/exclusions.js.map +1 -0
- package/dist/ui/autocomplete.d.ts +29 -1
- package/dist/ui/autocomplete.js +102 -47
- package/dist/ui/autocomplete.js.map +1 -1
- package/dist/ui/button.js +3 -5
- package/dist/ui/button.js.map +1 -1
- package/dist/ui/index.js +2 -2
- package/dist/ui/overlay.d.ts +4 -1
- package/dist/ui/overlay.js +2 -1
- package/dist/ui/overlay.js.map +1 -1
- package/dist/ui/toast.js +1 -1
- package/package.json +8 -2
package/dist/schema/types.d.ts
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* - Every field has the same chrome: label · help · required · validation · counter · ⋯ menu · presence · comments.
|
|
11
11
|
* - Blocks can contain blocks (slots) → complex layouts (tabs, columns, bento, mega menus, carousels).
|
|
12
12
|
*/
|
|
13
|
+
import type { RichTextFeature } from "@bettercms-ai/types";
|
|
13
14
|
import type { Cap } from "./sources";
|
|
14
15
|
import type { TableFieldOptions } from "./table";
|
|
15
16
|
export type PrimitiveType = "string" | "text" | "richtext" | "number" | "boolean" | "slug" | "url" | "email" | "date" | "datetime" | "color" | "select" | "multiselect" | "tags" | "image" | "file" | "video" | "icon" | "link" | "button" | "reference" | "code" | "json" | "geopoint" | "rating" | "table";
|
|
@@ -105,6 +106,8 @@ export interface FieldSchema {
|
|
|
105
106
|
reference?: {
|
|
106
107
|
to: string[];
|
|
107
108
|
filter?: string;
|
|
109
|
+
noun?: string;
|
|
110
|
+
excludeId?: string;
|
|
108
111
|
};
|
|
109
112
|
numeric?: {
|
|
110
113
|
unit?: string;
|
|
@@ -156,6 +159,20 @@ export interface FieldSchema {
|
|
|
156
159
|
/** code: the field's own language and the only languages its picker offers (prod config.language / languages). */
|
|
157
160
|
language?: string;
|
|
158
161
|
languages?: string[];
|
|
162
|
+
/**
|
|
163
|
+
* richtext / document: the blocks and marks the field offers, from types RICHTEXT_FEATURES (prod config.features).
|
|
164
|
+
* Absent = all of them, as V2's rich text offers (normV2 folds the full set to absent). A schema read from JSON may
|
|
165
|
+
* hold an alias (`headings`) or an unknown name: the adapter expands the one and names the other.
|
|
166
|
+
*/
|
|
167
|
+
features?: RichTextFeature[];
|
|
168
|
+
/**
|
|
169
|
+
* richtext / document: the content models its related posts and author bios draw from (prod config.references,
|
|
170
|
+
* plan RT8), by id. posts absent: the entry's own collection; authors absent: no author bio is offered.
|
|
171
|
+
*/
|
|
172
|
+
references?: {
|
|
173
|
+
posts?: string;
|
|
174
|
+
authors?: string;
|
|
175
|
+
};
|
|
159
176
|
}
|
|
160
177
|
/** D58: the caps that let someone see / change one field. */
|
|
161
178
|
export interface FieldAccess {
|
package/dist/schema/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","names":[],"sources":["../../src/schema/types.ts"],"sourcesContent":["/**\n * BETTERCMS SCHEMA — the long-term contract for every editable thing (blocks, pages, entries, globals).\n * One schema language → one form engine (`@/components/kit`) → used by BOTH the Visuals inspector and the\n * Content document editor. Modelled on Sanity's schema (types, fieldsets, groups, previews, validation,\n * conditional fields) plus BetterCMS's block slots for nested layouts.\n *\n * Design principles (CPO D8):\n * - Scales to deep nesting without inline-accordion soup: arrays render compact preview rows; opening an item\n * DRILLS IN (panel slides, breadcrumb grows). Small objects may render inline; lightweight settings open in a POPOVER.\n * - Every field has the same chrome: label · help · required · validation · counter · ⋯ menu · presence · comments.\n * - Blocks can contain blocks (slots) → complex layouts (tabs, columns, bento, mega menus, carousels).\n */\n\nimport type { Cap } from \"./sources\";\nimport type { TableFieldOptions } from \"./table\";\n\nexport type PrimitiveType =\n | \"string\" // single line\n | \"text\" // multi line, auto-grow\n | \"richtext\" // portable-text style rich text\n | \"number\"\n | \"boolean\"\n | \"slug\"\n | \"url\"\n | \"email\"\n | \"date\"\n | \"datetime\"\n | \"color\"\n | \"select\" // options: single\n | \"multiselect\"\n | \"tags\"\n | \"image\"\n | \"file\"\n | \"video\"\n | \"icon\" // icon picker (Tabler name)\n | \"link\" // url | page ref + target + rel (one unit)\n | \"button\" // label + link + style (one unit — founder rule)\n | \"reference\" // to a collection entry / page / form\n | \"code\"\n | \"json\"\n | \"geopoint\"\n | \"rating\"\n | \"table\"; // typed columns × keyed rows (CPO D42) — value: TableValue (src/schema/table.ts)\n\nexport type CompoundType =\n | \"object\" // nested fields\n | \"array\" // list of `of` (objects, primitives or references)\n | \"slot\"; // list of nested BLOCKS (block-in-block layouts)\n\nexport type SchemaType = PrimitiveType | CompoundType;\n\nexport interface Option {\n value: string;\n label: string;\n icon?: string;\n description?: string;\n}\n\nexport interface Validation {\n required?: boolean;\n min?: number; // chars for strings, items for arrays, value for numbers\n max?: number;\n /** soft limit: warning (amber) instead of error — e.g. SEO title 60 */\n recommendedMax?: number;\n pattern?: string;\n patternMessage?: string;\n unique?: boolean;\n}\n\n/** How a compound field is edited when opened. */\nexport type OpenMode =\n | \"inline\" // render fields in place (small objects, ≤3 primitives)\n | \"drill\" // slide the panel to a child view; breadcrumb grows (default for array items & objects)\n | \"popover\" // anchored popover (link settings, image crop/alt, small option sets)\n | \"dialog\"; // centered modal for heavy editors (rich text full screen, code, table)\n\nexport interface PreviewConfig {\n /** dotted paths into the item value */\n title?: string;\n subtitle?: string;\n media?: string;\n /** Fallback label, e.g. \"Untitled question\" */\n fallback?: string;\n /** Tabler icon name (kebab-case, e.g. \"help-circle\") shown when there is no media. */\n icon?: string;\n}\n\n/** A condition's operator. Absent: `equals` reads as is / is one of, `notEmpty` as has a value. */\nexport type ConditionOp = \"is\" | \"isNot\" | \"in\" | \"notIn\" | \"empty\" | \"notEmpty\" | \"gt\" | \"lt\";\n\n/**\n * \"Show only when\" (V2 types.ts). The field shows only while the rule holds:\n * - `field` names a key beside it (default), in the object that holds those fields (`scope: \"parent\"`) or at the top of\n * the component or CMS item (`scope: \"root\"`). `_variant` is the component's variant (its first variant when unset).\n * - `op` + `value` (is · is not · is one of · is not one of · is empty · has a value · more than · less than). The legacy\n * `equals` / `notEmpty` forms still read the same.\n * - `also`: more rules, combined by `match` (\"all\", the default, or \"any\").\n */\nexport interface Condition {\n field: string;\n equals?: unknown | unknown[];\n notEmpty?: boolean;\n op?: ConditionOp;\n value?: unknown;\n scope?: \"parent\" | \"root\";\n also?: Condition[];\n match?: \"all\" | \"any\";\n}\n\nexport interface FieldSchema {\n name: string; // key in the value object\n title: string; // label (sentence case)\n type: SchemaType;\n /** Help text under the label (CPO D39). Unset → a house convention from `@/schema/help` may apply; \"\" = none. */\n description?: string;\n /** Longer explanation behind the ⓘ next to the label (tooltip). Use when one line can't carry it. */\n helpMore?: string;\n placeholder?: string;\n initialValue?: unknown;\n validation?: Validation;\n options?: Option[]; // select / multiselect / radio-like\n layout?: \"dropdown\" | \"radio\" | \"segmented\" | \"cards\" | \"switch\" | \"checkbox\" | \"slider\" | \"grid\" | \"list\";\n /** compound */\n fields?: FieldSchema[]; // object\n of?: FieldSchema[] | { type: \"block\"; allow?: string[] }; // array items / slot allowed block types\n openMode?: OpenMode;\n preview?: PreviewConfig;\n /** organisation */\n fieldset?: string; // groups fields into a collapsible fieldset\n group?: string; // which tab (Content / Media / Settings / SEO…)\n /** behaviour */\n hidden?: Condition | boolean;\n /** true = never editable in the form (computed or system values). Who may see or change a field is `access`. */\n readOnly?: boolean;\n /** Archived (V2 types.ts): kept in the schema and its values stay stored, but no form renders it. Schema editors show it. */\n archived?: boolean;\n /**\n * D58 field-level access. `view` missing → everyone who can open the form sees it; `edit` missing → the form's own\n * rule (the host's content.edit). A field the lens can't `view` is not rendered; one it can't `edit` renders as plain\n * text. Fields in the `seo` group default to `{ edit: \"seo.edit\" }`.\n */\n access?: FieldAccess;\n localized?: boolean;\n advanced?: boolean; // tucked into the \"Advanced\" fieldset by default (calm UX)\n ai?: boolean; // show the AI assist sparkle\n reference?: { to: string[]; filter?: string }; // reference targets (collection ids, \"page\", \"form\")\n numeric?: { unit?: string; step?: number; min?: number; max?: number }; // number / slider\n /** number: a developer-controlled SCALE (tokens or a stepped range) with an optional custom escape hatch (CPO D41).\n * Value shape → `ScaleValue`. Takes precedence over `layout: \"slider\"` + `numeric` (which still work, fixed-only). */\n scale?: ScaleSchema;\n /** table: column types allowed, developer-locked columns, row limits, caption rule, JSON-LD offered (CPO D42). */\n table?: TableFieldOptions;\n\n /* ── additive (Block Kit v1) ─────────────────────────────────────────── */\n /** Tabler icon name (kebab-case) used on rows, crumbs and the block picker. */\n icon?: string;\n /** text: minimum visible rows. */\n rows?: number;\n /** Value is synced from a global block (\"Navigation\") — edits apply everywhere it is used. */\n synced?: { from: string };\n /** slot: per-child layout settings stored on each child under `_settings` (e.g. bento span). */\n slotSettings?: FieldSchema[];\n /** array: singular noun for \"Add {noun}\" and empty states (\"question\"). Defaults from the item title. */\n itemNoun?: string;\n /** array: how rows render. \"grid\" = tiles (good for images / logos). */\n arrayLayout?: \"list\" | \"grid\";\n /** Help line shown under a field the lens can see but not change (\"Set by the developer in code.\"). Never a key or a lock. */\n lockReason?: string;\n /**\n * Host-only, never persisted: the list's ORDER is set by the site's code (identity rule 36). The rows stay editable;\n * drag and Move up / down are off and the grip slot shows a lock (V2 content/editor/page-sections.tsx:31,155).\n */\n orderLocked?: boolean;\n /** link / image / button: store a plain string (href or URL) instead of the object — for legacy data. */\n valueShape?: \"string\" | \"object\";\n /** image: an inline-SVG icon, which takes SVG files only (prod `config.media: \"icon\"`). */\n svgOnly?: boolean;\n /**\n * A link LABEL's href: the sibling it links with (prod `config.linkHref`), as the owner answered the editable plan's\n * `link-pair` question where the names do not say (`title` + `to`). Read first by `linkLabelHref`.\n */\n linkHref?: string;\n /**\n * date / datetime: time zone handling (CPO D43). true = the editor picks a zone (defaults to the site's) · \"site\" = always\n * the site's zone · \"fixed:<IANA>\" = always that zone · false = no zone. Default: true for datetime, false for date.\n * Zoned values store ISO with offset + the IANA zone: \"2026-10-14T09:00:00+05:30[Asia/Kolkata]\" (RFC 9557).\n */\n timezone?: boolean | \"site\" | `fixed:${string}`;\n /** code: the field's own language and the only languages its picker offers (prod config.language / languages). */\n language?: string;\n languages?: string[];\n}\n\n/** D58: the caps that let someone see / change one field. */\nexport interface FieldAccess {\n view?: Cap;\n edit?: Cap;\n}\n/** Developer-owned values (anchors, custom CSS, ids): only people who can change the schema edit them. */\nexport const DEV_FIELD: FieldAccess = { edit: \"schema.manage\" };\n/** Developer-only settings: hidden unless you can see the schema. */\nexport const DEV_ONLY_FIELD: FieldAccess = { view: \"schema.view\", edit: \"schema.manage\" };\n\n/* ── Scales (CPO D41) ─────────────────────────────────────────────────── */\nexport type ScaleUnit = \"px\" | \"%\" | \"rem\" | \"em\" | \"vw\" | \"vh\";\n\n/** One allowed value of a token scale. `value` is what is stored; `label` is the short readout (\"XL\"). */\nexport interface ScaleStep {\n value: string;\n label: string;\n /** Long name for screen readers and tooltips (\"Extra large\"). Defaults to `label`. */\n title?: string;\n /** Resolved size in px, shown as \"XL · 48px\" and used to place custom values on the track. */\n px?: number;\n /** Resolved CSS when it isn't px (e.g. \"100vh\", \"var(--space-xl)\"). */\n css?: string;\n}\n\n/** A stepped numeric range (continuous with snapping). The stored value is a bare number in `defaultUnit`. */\nexport interface ScaleRange {\n min: number;\n max: number;\n step?: number;\n}\n\n/** Bounds for the custom escape hatch. min / max may be one number or per unit ({ px: 0, \"%\": 0 }). */\nexport interface ScaleCustom {\n min?: number | Partial<Record<ScaleUnit, number>>;\n max?: number | Partial<Record<ScaleUnit, number>>;\n /** Units the editor may type. Defaults to the scale's `units`. */\n units?: ScaleUnit[];\n /** Arrow-key nudge (Shift ×10, Alt ×0.1). Default 1. */\n step?: number;\n}\n\nexport interface ScaleSchema {\n /** Token steps (S M L XL 2XL) or a numeric range ({ min, max, step }). */\n steps: ScaleStep[] | ScaleRange;\n /** Units of the scale; the first is the default. A range with no units is unitless. */\n units?: ScaleUnit[];\n defaultUnit?: ScaleUnit;\n /** false (default) = fixed only: the editor can pick only the allowed values. true / object = fixed + custom. */\n allowCustom?: boolean | ScaleCustom;\n /** Quick picks in the unit menu when custom is allowed (\"50%\", \"100vh\"). */\n presets?: { label?: string; value: ScaleValue }[];\n}\n\n/**\n * How a scale value is STORED — three shapes, told apart by `typeof`, so tokens and custom values never collide and\n * older data (bare token strings, bare numbers) is already valid:\n * - token → the step's value string (\"xl\")\n * - range → a bare number in the default unit (15 → 15%)\n * - custom → an object ({ value: 200, unit: \"px\" })\n */\nexport type ScaleValue = string | number | ScaleCustomValue;\nexport interface ScaleCustomValue {\n value: number;\n unit: ScaleUnit;\n}\n\nexport interface Fieldset {\n name: string;\n title: string;\n description?: string;\n collapsed?: boolean; // collapsed by default\n columns?: 1 | 2; // short fields side by side\n /** CPO D45: the header toggles the section (default true). false = a static heading for 2–3 fields that are always needed. */\n collapsible?: boolean;\n /**\n * CPO D45: \"breakpoints\" = the members are objects, one per screen size (desktop · tablet · phone), shown as ONE group with a\n * segmented switcher instead of three stacked groups. Sibling objects named desktop / laptop / tablet / mobile / phone get\n * this automatically.\n */\n layout?: \"stack\" | \"breakpoints\";\n}\n\nexport interface FieldGroup {\n name: string;\n title: string;\n icon?: string;\n default?: boolean;\n}\n\n/** A developer-defined layout of a block (swap without losing content). */\nexport interface BlockVariant {\n id: string;\n name: string;\n description?: string;\n}\n\n/** A document/block type. */\nexport interface TypeSchema {\n name: string; // e.g. \"hero\", \"journalStory\"\n title: string;\n kind: \"block\" | \"page\" | \"entry\" | \"global\" | \"object\";\n icon?: string;\n description?: string;\n fields: FieldSchema[];\n fieldsets?: Fieldset[];\n groups?: FieldGroup[];\n preview?: PreviewConfig;\n /* ── additive (Block Kit v1) ── */\n /** Block variants (layouts) — shown as a chip on slot rows and a switcher in the block frame. */\n variants?: BlockVariant[];\n /** Block picker category (\"Layout\", \"Content\", \"Media\"…). */\n category?: string;\n /**\n * kind \"block\" only (CPO D55): where the block fits. \"inline\" = it fits a text column, so a rich-text body lists it in\n * the Insert menu's Article group. \"section\" (default) = page-width, reachable in a body only through More components.\n * \"page\" = a whole page or a feed of other content; never inside a body.\n */\n placement?: \"inline\" | \"section\" | \"page\";\n /** Starting value for a new instance (block added to a slot, new document). */\n initialValue?: Record<string, unknown>;\n}\n\n/** Every array item / slot child carries a stable key. Slot children also carry their block type. */\nexport interface KeyedItem {\n _key?: string;\n /** item type name (arrays with several `of` types) or block type (slots) */\n _type?: string;\n}\n/** A block inside a slot: its own props at the root, plus variant and per-slot layout settings. */\nexport interface SlotChild extends KeyedItem {\n _type: string;\n _variant?: string;\n _settings?: Record<string, unknown>;\n [prop: string]: unknown;\n}\n\n/** Path from the root document/block to the field being edited, e.g. [\"items\", 1, \"answer\"] */\nexport type FieldPath = (string | number)[];\n\n/** One crumb in the inspector/editor breadcrumb (drill-in navigation stack). */\nexport interface Crumb {\n path: FieldPath;\n title: string;\n icon?: string;\n /** tableGroup / tableRow / tableColumn: a table field's rows and columns drill like array items (D50) */\n kind: \"root\" | \"object\" | \"item\" | \"block\" | \"button\" | \"history\" | \"tableGroup\" | \"tableRow\" | \"tableColumn\";\n}\n\n/** Reserved path segment: the field's version history as a stacked panel, e.g. [\"title\", \"@history\"]. */\nexport const HISTORY_SEGMENT = \"@history\";\n"],"mappings":";;AAuMA,IAAa,YAAyB,EAAE,MAAM,gBAAgB;;AAE9D,IAAa,iBAA8B;CAAE,MAAM;CAAe,MAAM;AAAgB;;AA8IxF,IAAa,kBAAkB"}
|
|
1
|
+
{"version":3,"file":"types.js","names":[],"sources":["../../src/schema/types.ts"],"sourcesContent":["/**\n * BETTERCMS SCHEMA — the long-term contract for every editable thing (blocks, pages, entries, globals).\n * One schema language → one form engine (`@/components/kit`) → used by BOTH the Visuals inspector and the\n * Content document editor. Modelled on Sanity's schema (types, fieldsets, groups, previews, validation,\n * conditional fields) plus BetterCMS's block slots for nested layouts.\n *\n * Design principles (CPO D8):\n * - Scales to deep nesting without inline-accordion soup: arrays render compact preview rows; opening an item\n * DRILLS IN (panel slides, breadcrumb grows). Small objects may render inline; lightweight settings open in a POPOVER.\n * - Every field has the same chrome: label · help · required · validation · counter · ⋯ menu · presence · comments.\n * - Blocks can contain blocks (slots) → complex layouts (tabs, columns, bento, mega menus, carousels).\n */\n\nimport type { RichTextFeature } from \"@bettercms-ai/types\";\nimport type { Cap } from \"./sources\";\nimport type { TableFieldOptions } from \"./table\";\n\nexport type PrimitiveType =\n | \"string\" // single line\n | \"text\" // multi line, auto-grow\n | \"richtext\" // portable-text style rich text\n | \"number\"\n | \"boolean\"\n | \"slug\"\n | \"url\"\n | \"email\"\n | \"date\"\n | \"datetime\"\n | \"color\"\n | \"select\" // options: single\n | \"multiselect\"\n | \"tags\"\n | \"image\"\n | \"file\"\n | \"video\"\n | \"icon\" // icon picker (Tabler name)\n | \"link\" // url | page ref + target + rel (one unit)\n | \"button\" // label + link + style (one unit — founder rule)\n | \"reference\" // to a collection entry / page / form\n | \"code\"\n | \"json\"\n | \"geopoint\"\n | \"rating\"\n | \"table\"; // typed columns × keyed rows (CPO D42) — value: TableValue (src/schema/table.ts)\n\nexport type CompoundType =\n | \"object\" // nested fields\n | \"array\" // list of `of` (objects, primitives or references)\n | \"slot\"; // list of nested BLOCKS (block-in-block layouts)\n\nexport type SchemaType = PrimitiveType | CompoundType;\n\nexport interface Option {\n value: string;\n label: string;\n icon?: string;\n description?: string;\n}\n\nexport interface Validation {\n required?: boolean;\n min?: number; // chars for strings, items for arrays, value for numbers\n max?: number;\n /** soft limit: warning (amber) instead of error — e.g. SEO title 60 */\n recommendedMax?: number;\n pattern?: string;\n patternMessage?: string;\n unique?: boolean;\n}\n\n/** How a compound field is edited when opened. */\nexport type OpenMode =\n | \"inline\" // render fields in place (small objects, ≤3 primitives)\n | \"drill\" // slide the panel to a child view; breadcrumb grows (default for array items & objects)\n | \"popover\" // anchored popover (link settings, image crop/alt, small option sets)\n | \"dialog\"; // centered modal for heavy editors (rich text full screen, code, table)\n\nexport interface PreviewConfig {\n /** dotted paths into the item value */\n title?: string;\n subtitle?: string;\n media?: string;\n /** Fallback label, e.g. \"Untitled question\" */\n fallback?: string;\n /** Tabler icon name (kebab-case, e.g. \"help-circle\") shown when there is no media. */\n icon?: string;\n}\n\n/** A condition's operator. Absent: `equals` reads as is / is one of, `notEmpty` as has a value. */\nexport type ConditionOp = \"is\" | \"isNot\" | \"in\" | \"notIn\" | \"empty\" | \"notEmpty\" | \"gt\" | \"lt\";\n\n/**\n * \"Show only when\" (V2 types.ts). The field shows only while the rule holds:\n * - `field` names a key beside it (default), in the object that holds those fields (`scope: \"parent\"`) or at the top of\n * the component or CMS item (`scope: \"root\"`). `_variant` is the component's variant (its first variant when unset).\n * - `op` + `value` (is · is not · is one of · is not one of · is empty · has a value · more than · less than). The legacy\n * `equals` / `notEmpty` forms still read the same.\n * - `also`: more rules, combined by `match` (\"all\", the default, or \"any\").\n */\nexport interface Condition {\n field: string;\n equals?: unknown | unknown[];\n notEmpty?: boolean;\n op?: ConditionOp;\n value?: unknown;\n scope?: \"parent\" | \"root\";\n also?: Condition[];\n match?: \"all\" | \"any\";\n}\n\nexport interface FieldSchema {\n name: string; // key in the value object\n title: string; // label (sentence case)\n type: SchemaType;\n /** Help text under the label (CPO D39). Unset → a house convention from `@/schema/help` may apply; \"\" = none. */\n description?: string;\n /** Longer explanation behind the ⓘ next to the label (tooltip). Use when one line can't carry it. */\n helpMore?: string;\n placeholder?: string;\n initialValue?: unknown;\n validation?: Validation;\n options?: Option[]; // select / multiselect / radio-like\n layout?: \"dropdown\" | \"radio\" | \"segmented\" | \"cards\" | \"switch\" | \"checkbox\" | \"slider\" | \"grid\" | \"list\";\n /** compound */\n fields?: FieldSchema[]; // object\n of?: FieldSchema[] | { type: \"block\"; allow?: string[] }; // array items / slot allowed block types\n openMode?: OpenMode;\n preview?: PreviewConfig;\n /** organisation */\n fieldset?: string; // groups fields into a collapsible fieldset\n group?: string; // which tab (Content / Media / Settings / SEO…)\n /** behaviour */\n hidden?: Condition | boolean;\n /** true = never editable in the form (computed or system values). Who may see or change a field is `access`. */\n readOnly?: boolean;\n /** Archived (V2 types.ts): kept in the schema and its values stay stored, but no form renders it. Schema editors show it. */\n archived?: boolean;\n /**\n * D58 field-level access. `view` missing → everyone who can open the form sees it; `edit` missing → the form's own\n * rule (the host's content.edit). A field the lens can't `view` is not rendered; one it can't `edit` renders as plain\n * text. Fields in the `seo` group default to `{ edit: \"seo.edit\" }`.\n */\n access?: FieldAccess;\n localized?: boolean;\n advanced?: boolean; // tucked into the \"Advanced\" fieldset by default (calm UX)\n ai?: boolean; // show the AI assist sparkle\n // reference targets (collection ids, \"page\", \"form\"); `noun`: what the picker calls one (\"author\": \"Select an author\",\n // \"Create new author\"), else the target's (\"CMS item\", \"page\", …)\n // `excludeId`: a record this picker never lists (the entry a rich-text island sits in, which its own form cannot see)\n reference?: { to: string[]; filter?: string; noun?: string; excludeId?: string };\n numeric?: { unit?: string; step?: number; min?: number; max?: number }; // number / slider\n /** number: a developer-controlled SCALE (tokens or a stepped range) with an optional custom escape hatch (CPO D41).\n * Value shape → `ScaleValue`. Takes precedence over `layout: \"slider\"` + `numeric` (which still work, fixed-only). */\n scale?: ScaleSchema;\n /** table: column types allowed, developer-locked columns, row limits, caption rule, JSON-LD offered (CPO D42). */\n table?: TableFieldOptions;\n\n /* ── additive (Block Kit v1) ─────────────────────────────────────────── */\n /** Tabler icon name (kebab-case) used on rows, crumbs and the block picker. */\n icon?: string;\n /** text: minimum visible rows. */\n rows?: number;\n /** Value is synced from a global block (\"Navigation\") — edits apply everywhere it is used. */\n synced?: { from: string };\n /** slot: per-child layout settings stored on each child under `_settings` (e.g. bento span). */\n slotSettings?: FieldSchema[];\n /** array: singular noun for \"Add {noun}\" and empty states (\"question\"). Defaults from the item title. */\n itemNoun?: string;\n /** array: how rows render. \"grid\" = tiles (good for images / logos). */\n arrayLayout?: \"list\" | \"grid\";\n /** Help line shown under a field the lens can see but not change (\"Set by the developer in code.\"). Never a key or a lock. */\n lockReason?: string;\n /**\n * Host-only, never persisted: the list's ORDER is set by the site's code (identity rule 36). The rows stay editable;\n * drag and Move up / down are off and the grip slot shows a lock (V2 content/editor/page-sections.tsx:31,155).\n */\n orderLocked?: boolean;\n /** link / image / button: store a plain string (href or URL) instead of the object — for legacy data. */\n valueShape?: \"string\" | \"object\";\n /** image: an inline-SVG icon, which takes SVG files only (prod `config.media: \"icon\"`). */\n svgOnly?: boolean;\n /**\n * A link LABEL's href: the sibling it links with (prod `config.linkHref`), as the owner answered the editable plan's\n * `link-pair` question where the names do not say (`title` + `to`). Read first by `linkLabelHref`.\n */\n linkHref?: string;\n /**\n * date / datetime: time zone handling (CPO D43). true = the editor picks a zone (defaults to the site's) · \"site\" = always\n * the site's zone · \"fixed:<IANA>\" = always that zone · false = no zone. Default: true for datetime, false for date.\n * Zoned values store ISO with offset + the IANA zone: \"2026-10-14T09:00:00+05:30[Asia/Kolkata]\" (RFC 9557).\n */\n timezone?: boolean | \"site\" | `fixed:${string}`;\n /** code: the field's own language and the only languages its picker offers (prod config.language / languages). */\n language?: string;\n languages?: string[];\n /**\n * richtext / document: the blocks and marks the field offers, from types RICHTEXT_FEATURES (prod config.features).\n * Absent = all of them, as V2's rich text offers (normV2 folds the full set to absent). A schema read from JSON may\n * hold an alias (`headings`) or an unknown name: the adapter expands the one and names the other.\n */\n features?: RichTextFeature[];\n /**\n * richtext / document: the content models its related posts and author bios draw from (prod config.references,\n * plan RT8), by id. posts absent: the entry's own collection; authors absent: no author bio is offered.\n */\n references?: { posts?: string; authors?: string };\n}\n\n/** D58: the caps that let someone see / change one field. */\nexport interface FieldAccess {\n view?: Cap;\n edit?: Cap;\n}\n/** Developer-owned values (anchors, custom CSS, ids): only people who can change the schema edit them. */\nexport const DEV_FIELD: FieldAccess = { edit: \"schema.manage\" };\n/** Developer-only settings: hidden unless you can see the schema. */\nexport const DEV_ONLY_FIELD: FieldAccess = { view: \"schema.view\", edit: \"schema.manage\" };\n\n/* ── Scales (CPO D41) ─────────────────────────────────────────────────── */\nexport type ScaleUnit = \"px\" | \"%\" | \"rem\" | \"em\" | \"vw\" | \"vh\";\n\n/** One allowed value of a token scale. `value` is what is stored; `label` is the short readout (\"XL\"). */\nexport interface ScaleStep {\n value: string;\n label: string;\n /** Long name for screen readers and tooltips (\"Extra large\"). Defaults to `label`. */\n title?: string;\n /** Resolved size in px, shown as \"XL · 48px\" and used to place custom values on the track. */\n px?: number;\n /** Resolved CSS when it isn't px (e.g. \"100vh\", \"var(--space-xl)\"). */\n css?: string;\n}\n\n/** A stepped numeric range (continuous with snapping). The stored value is a bare number in `defaultUnit`. */\nexport interface ScaleRange {\n min: number;\n max: number;\n step?: number;\n}\n\n/** Bounds for the custom escape hatch. min / max may be one number or per unit ({ px: 0, \"%\": 0 }). */\nexport interface ScaleCustom {\n min?: number | Partial<Record<ScaleUnit, number>>;\n max?: number | Partial<Record<ScaleUnit, number>>;\n /** Units the editor may type. Defaults to the scale's `units`. */\n units?: ScaleUnit[];\n /** Arrow-key nudge (Shift ×10, Alt ×0.1). Default 1. */\n step?: number;\n}\n\nexport interface ScaleSchema {\n /** Token steps (S M L XL 2XL) or a numeric range ({ min, max, step }). */\n steps: ScaleStep[] | ScaleRange;\n /** Units of the scale; the first is the default. A range with no units is unitless. */\n units?: ScaleUnit[];\n defaultUnit?: ScaleUnit;\n /** false (default) = fixed only: the editor can pick only the allowed values. true / object = fixed + custom. */\n allowCustom?: boolean | ScaleCustom;\n /** Quick picks in the unit menu when custom is allowed (\"50%\", \"100vh\"). */\n presets?: { label?: string; value: ScaleValue }[];\n}\n\n/**\n * How a scale value is STORED — three shapes, told apart by `typeof`, so tokens and custom values never collide and\n * older data (bare token strings, bare numbers) is already valid:\n * - token → the step's value string (\"xl\")\n * - range → a bare number in the default unit (15 → 15%)\n * - custom → an object ({ value: 200, unit: \"px\" })\n */\nexport type ScaleValue = string | number | ScaleCustomValue;\nexport interface ScaleCustomValue {\n value: number;\n unit: ScaleUnit;\n}\n\nexport interface Fieldset {\n name: string;\n title: string;\n description?: string;\n collapsed?: boolean; // collapsed by default\n columns?: 1 | 2; // short fields side by side\n /** CPO D45: the header toggles the section (default true). false = a static heading for 2–3 fields that are always needed. */\n collapsible?: boolean;\n /**\n * CPO D45: \"breakpoints\" = the members are objects, one per screen size (desktop · tablet · phone), shown as ONE group with a\n * segmented switcher instead of three stacked groups. Sibling objects named desktop / laptop / tablet / mobile / phone get\n * this automatically.\n */\n layout?: \"stack\" | \"breakpoints\";\n}\n\nexport interface FieldGroup {\n name: string;\n title: string;\n icon?: string;\n default?: boolean;\n}\n\n/** A developer-defined layout of a block (swap without losing content). */\nexport interface BlockVariant {\n id: string;\n name: string;\n description?: string;\n}\n\n/** A document/block type. */\nexport interface TypeSchema {\n name: string; // e.g. \"hero\", \"journalStory\"\n title: string;\n kind: \"block\" | \"page\" | \"entry\" | \"global\" | \"object\";\n icon?: string;\n description?: string;\n fields: FieldSchema[];\n fieldsets?: Fieldset[];\n groups?: FieldGroup[];\n preview?: PreviewConfig;\n /* ── additive (Block Kit v1) ── */\n /** Block variants (layouts) — shown as a chip on slot rows and a switcher in the block frame. */\n variants?: BlockVariant[];\n /** Block picker category (\"Layout\", \"Content\", \"Media\"…). */\n category?: string;\n /**\n * kind \"block\" only (CPO D55): where the block fits. \"inline\" = it fits a text column, so a rich-text body lists it in\n * the Insert menu's Article group. \"section\" (default) = page-width, reachable in a body only through More components.\n * \"page\" = a whole page or a feed of other content; never inside a body.\n */\n placement?: \"inline\" | \"section\" | \"page\";\n /** Starting value for a new instance (block added to a slot, new document). */\n initialValue?: Record<string, unknown>;\n}\n\n/** Every array item / slot child carries a stable key. Slot children also carry their block type. */\nexport interface KeyedItem {\n _key?: string;\n /** item type name (arrays with several `of` types) or block type (slots) */\n _type?: string;\n}\n/** A block inside a slot: its own props at the root, plus variant and per-slot layout settings. */\nexport interface SlotChild extends KeyedItem {\n _type: string;\n _variant?: string;\n _settings?: Record<string, unknown>;\n [prop: string]: unknown;\n}\n\n/** Path from the root document/block to the field being edited, e.g. [\"items\", 1, \"answer\"] */\nexport type FieldPath = (string | number)[];\n\n/** One crumb in the inspector/editor breadcrumb (drill-in navigation stack). */\nexport interface Crumb {\n path: FieldPath;\n title: string;\n icon?: string;\n /** tableGroup / tableRow / tableColumn: a table field's rows and columns drill like array items (D50) */\n kind: \"root\" | \"object\" | \"item\" | \"block\" | \"button\" | \"history\" | \"tableGroup\" | \"tableRow\" | \"tableColumn\";\n}\n\n/** Reserved path segment: the field's version history as a stacked panel, e.g. [\"title\", \"@history\"]. */\nexport const HISTORY_SEGMENT = \"@history\";\n"],"mappings":";;AAsNA,IAAa,YAAyB,EAAE,MAAM,gBAAgB;;AAE9D,IAAa,iBAA8B;CAAE,MAAM;CAAe,MAAM;AAAgB;;AA8IxF,IAAa,kBAAkB"}
|