@bettercms-ai/types 1.24.0 → 1.26.0
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/index.d.ts +510 -211
- package/dist/index.js +490 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -13,6 +13,276 @@ interface Workspace {
|
|
|
13
13
|
updatedAt: string;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Generated by scripts/gen-dock-icon-names.mjs from the vendored icon tarball
|
|
18
|
+
* (sha256 0691620e50bdf453c2fed06224d9dc52d521574ab254a149eba47664b92fb889).
|
|
19
|
+
* Do not edit by hand: rerun the script (`--check` fails CI on drift).
|
|
20
|
+
*
|
|
21
|
+
* The closed vocabulary for `ui.icon` (field ui, fieldsets, prop ui.group). `as const` because a
|
|
22
|
+
* z.enum needs the literal tuple; a `readonly string[]` would type every string as valid.
|
|
23
|
+
*/
|
|
24
|
+
declare const DOCK_ICON_NAMES: readonly ["access-denied", "activity", "add", "add-circle", "add-comment", "add-document", "add-user", "api", "archive", "arrow-down", "arrow-left", "arrow-right", "arrow-top-right", "arrow-up", "asterisk", "bar-chart", "basket", "bell", "bill", "binary-document", "block-content", "block-element", "blockquote", "bold", "bolt", "book", "bookmark", "bookmark-filled", "bottle", "bug", "bulb-filled", "bulb-outline", "calendar", "case", "chart-upward", "checkmark", "checkmark-circle", "chevron-down", "chevron-left", "chevron-right", "chevron-up", "circle", "clipboard", "clipboard-image", "clock", "close", "close-circle", "code", "code-block", "cog", "collapse", "color-wheel", "comment", "component", "compose", "compose-sparkles", "confetti", "controls", "copy", "credit-card", "crop", "cube", "dashboard", "database", "desktop", "diamond", "document", "document-pdf", "document-remove", "document-sheet", "document-text", "document-video", "document-word", "document-zip", "documents", "dot", "double-chevron-down", "double-chevron-left", "double-chevron-right", "double-chevron-up", "double-quote", "download", "drag-handle", "drop", "earth-americas", "earth-globe", "edit", "ellipsis-horizontal", "ellipsis-vertical", "empty", "enter", "enter-right", "envelope", "equal", "error-filled", "error-outline", "error-screen", "expand", "eye-closed", "eye-open", "face-happy", "face-indifferent", "face-sad", "feedback", "filter", "folder", "generate", "github", "groq", "hash", "heart", "heart-filled", "help-circle", "highlight", "home", "ice-cream", "image", "image-remove", "images", "inbox", "info-filled", "info-outline", "inline", "inline-element", "insert-above", "insert-below", "italic", "joystick", "json", "launch", "leave", "lemon", "link", "link-removed", "linkedin", "list", "lock", "logo-js", "logo-ts", "marker", "marker-removed", "master-detail", "menu", "microphone", "microphone-slash", "mobile-device", "moon", "number", "ok-hand", "olist", "overage", "package", "panel-left", "panel-right", "pause", "pin", "pin-filled", "pin-removed", "play", "plug", "presentation", "progress-50", "progress-75", "projects", "publish", "read-only", "redo", "refresh", "remove", "remove-circle", "reset", "restore", "retrieve", "retry", "revert", "robot", "rocket", "schema", "search", "select", "share", "sort", "sparkle", "sparkles", "spinner", "split-horizontal", "split-vertical", "square", "stack", "stack-compact", "star", "star-filled", "stop", "strikethrough", "string", "sun", "sync", "tablet-device", "tag", "tags", "target", "task", "terminal", "text", "th-large", "th-list", "thumbs-down", "thumbs-up", "tiers", "timeline", "toggle-arrow-right", "token", "transfer", "translate", "trash", "trend-upward", "triangle-outline", "trolley", "truncate", "twitter", "ulist", "unarchive", "underline", "undo", "unknown", "unlink", "unlock", "unpublish", "upload", "user", "users", "versions", "video", "warning-filled", "warning-outline", "wrench"];
|
|
25
|
+
type DockIconName = (typeof DOCK_ICON_NAMES)[number];
|
|
26
|
+
declare const DOCK_ICON_NAME_SET: ReadonlySet<string>;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* ContentModel — the structured content model (schema) for a workspace.
|
|
30
|
+
* Defines which content fields are available for authors to fill in.
|
|
31
|
+
*/
|
|
32
|
+
interface ContentModel {
|
|
33
|
+
id: string;
|
|
34
|
+
workspaceId: string;
|
|
35
|
+
name: string;
|
|
36
|
+
description?: string;
|
|
37
|
+
/** 'block' models hold no entries — they are instantiable only inside a `modular` field. */
|
|
38
|
+
kind?: ContentModelKind;
|
|
39
|
+
fields: ContentModelField[];
|
|
40
|
+
/** Authoring-only field grouping for the schema builder. Never affects the API shape. */
|
|
41
|
+
fieldsets?: Fieldset[];
|
|
42
|
+
createdAt: string;
|
|
43
|
+
updatedAt: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Canonical field types. Nesting lives on `array` via `config.zones`
|
|
47
|
+
* (see {@link ArrayZoneConfig}): `group`/`repeater` are accepted as legacy input
|
|
48
|
+
* by the API but normalized to `array` + zones on write, so stored/delivered
|
|
49
|
+
* content never contains them.
|
|
50
|
+
*/
|
|
51
|
+
type ContentModelFieldType = "text" | "richtext" | "document" | "image" | "boolean" | "number" | "select" | "reference" | "multi-reference" | "multiReference" | "array" | "date" | "datetime" | "longtext" | "slug" | "email" | "phone" | "link" | "color" | "json" | "file" | "component-ref" | "modular" | "sections" | "location";
|
|
52
|
+
type ContentModelKind = "model" | "block";
|
|
53
|
+
/**
|
|
54
|
+
* How a fieldset renders in the dock. ABSENT ≡ today's flat list (V2): a legacy `{id, name}`
|
|
55
|
+
* fieldset never regroups anything.
|
|
56
|
+
* - `group` a disclosure; `row` ≤3 pairable scalars on one line; `tab` one of ≤3 top-level tabs.
|
|
57
|
+
*/
|
|
58
|
+
type FieldsetKind = "group" | "row" | "tab";
|
|
59
|
+
/** Who last shaped a path's authoring chrome. Server-owned: a client echo is discarded. */
|
|
60
|
+
type UiOrigin = "human" | "agent" | "derived";
|
|
61
|
+
/**
|
|
62
|
+
* The chrome a field had before the first agent write over a non-agent state, kept so a human
|
|
63
|
+
* can revert it. Server-owned, like {@link UiOrigin}.
|
|
64
|
+
*/
|
|
65
|
+
interface UiBefore {
|
|
66
|
+
ui?: ContentModelFieldUi;
|
|
67
|
+
fieldsetId?: string;
|
|
68
|
+
/** Index among the field's siblings at the time. */
|
|
69
|
+
position: number;
|
|
70
|
+
label?: string;
|
|
71
|
+
helpText?: string;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* A fieldset's chrome before the first agent change over a human/derived (or unstamped) state,
|
|
75
|
+
* kept so a person can revert it. `label` is the set's `name`. Server-owned, like {@link UiOrigin}:
|
|
76
|
+
* frozen while the origin stays `agent`, cleared by a human or derived change, carried by id.
|
|
77
|
+
*/
|
|
78
|
+
interface FieldsetUiBefore {
|
|
79
|
+
label: string;
|
|
80
|
+
ui: {
|
|
81
|
+
kind?: FieldsetKind;
|
|
82
|
+
tab?: string;
|
|
83
|
+
icon?: DockIconName;
|
|
84
|
+
collapsed?: boolean;
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/** A named, UI-only grouping of a model's fields. Order is the array index. */
|
|
88
|
+
interface Fieldset {
|
|
89
|
+
id: string;
|
|
90
|
+
name: string;
|
|
91
|
+
/** One line shown under the card title in the editor. Editor-only. */
|
|
92
|
+
description?: string;
|
|
93
|
+
kind?: FieldsetKind;
|
|
94
|
+
icon?: DockIconName;
|
|
95
|
+
/** A `group` that starts closed. */
|
|
96
|
+
collapsed?: boolean;
|
|
97
|
+
/** A group/row that sits inside this `kind:"tab"` fieldset. */
|
|
98
|
+
tab?: string;
|
|
99
|
+
uiOrigin?: UiOrigin;
|
|
100
|
+
uiBefore?: FieldsetUiBefore;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Nested-content config for an `array` field. A zone holds ordinary fields, and a
|
|
104
|
+
* zone field may itself be an `array` with its own zones, so nesting is recursive
|
|
105
|
+
* to any depth.
|
|
106
|
+
* - `nonRepeatable` — a single fixed block of fields (former `group`).
|
|
107
|
+
* - `repeatable` — a repeating list of field-objects (former `repeater`).
|
|
108
|
+
* Mutually exclusive with the primitive form (`config.itemType`).
|
|
109
|
+
*/
|
|
110
|
+
interface ArrayZoneConfig {
|
|
111
|
+
nonRepeatable?: ContentModelField[];
|
|
112
|
+
repeatable?: {
|
|
113
|
+
fields: ContentModelField[];
|
|
114
|
+
minItems?: number;
|
|
115
|
+
maxItems?: number;
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/** Per-type config for a field (the typed shape behind the loose `config` bag). */
|
|
119
|
+
interface FieldConfig {
|
|
120
|
+
/** primitive array: list of scalars */
|
|
121
|
+
itemType?: "text" | "number" | "date";
|
|
122
|
+
/** nested array: zoned fields (recursive) */
|
|
123
|
+
zones?: ArrayZoneConfig;
|
|
124
|
+
/** reference / multi-reference */
|
|
125
|
+
contentModelId?: string;
|
|
126
|
+
min?: number;
|
|
127
|
+
max?: number;
|
|
128
|
+
/** date / datetime */
|
|
129
|
+
includeTime?: boolean;
|
|
130
|
+
/** modular: SLUGS of the kind='block' models this field accepts. Non-empty. */
|
|
131
|
+
blockSlugs?: string[];
|
|
132
|
+
/** modular: bounds on how many block instances the field may hold. */
|
|
133
|
+
minItems?: number;
|
|
134
|
+
maxItems?: number;
|
|
135
|
+
/**
|
|
136
|
+
* sections: SLUGS of the sections an author may insert into this zone.
|
|
137
|
+
*
|
|
138
|
+
* Deliberately NOT named `blockSlugs`. That key means "kind='block' content models" and is
|
|
139
|
+
* read by ModularField; these are section-registry slugs resolved from a different place.
|
|
140
|
+
* One key meaning two things is how `blockModels`/`blockSlugs` already drifted apart in the
|
|
141
|
+
* dashboard — a distinct name costs nothing and cannot be confused at a call site.
|
|
142
|
+
*
|
|
143
|
+
* ⚠ ABSENT ≠ EMPTY:
|
|
144
|
+
* absent → UNRESTRICTED, every registry section may be inserted
|
|
145
|
+
* [] → DENY ALL, a deliberate empty restriction
|
|
146
|
+
* [a, b] → only those
|
|
147
|
+
* `[]` means DENY here to match `components.allowed_on` (migration 0190), so two adjacent
|
|
148
|
+
* allow-lists never disagree about what empty means.
|
|
149
|
+
*
|
|
150
|
+
* Absent rather than "all current slugs" because the registry GROWS — it is fed by repo
|
|
151
|
+
* pushes and project components, so materializing today's slugs at field-creation time would
|
|
152
|
+
* silently exclude every section shipped afterwards.
|
|
153
|
+
*
|
|
154
|
+
* NOT READ DIRECTLY. Insertability is this list INTERSECTED with the component's `allowedOn`
|
|
155
|
+
* (where that section may be placed), computed by one resolver so the two cannot drift.
|
|
156
|
+
*
|
|
157
|
+
* Enforced on NEW picks only. Narrowing the list later must never invalidate sections an
|
|
158
|
+
* author already placed, the same rule modular's blockSlugs and component-ref's allowlist
|
|
159
|
+
* follow.
|
|
160
|
+
*/
|
|
161
|
+
allowedSections?: string[];
|
|
162
|
+
/** Durable project-local authored Zone mode. Legacy zones omit this key. */
|
|
163
|
+
mode?: "authored-v2";
|
|
164
|
+
/** Durable Zone id. Present when `mode` is `authored-v2`. */
|
|
165
|
+
zoneId?: string;
|
|
166
|
+
/** Explicit migration acknowledgement while the legacy allowlist remains readable. */
|
|
167
|
+
legacyResolved?: boolean;
|
|
168
|
+
legacyMappings?: Record<string, string>;
|
|
169
|
+
[key: string]: unknown;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Where a field renders in the entry editor.
|
|
173
|
+
*
|
|
174
|
+
* AUTHORING ONLY — this has no delivery or storage effect. It does not change the
|
|
175
|
+
* shape of `data`, is not read by any renderer in @bettercms-ai/next or /astro, and
|
|
176
|
+
* cannot move a value onto or off a published page. It decides one thing: where the
|
|
177
|
+
* control sits while somebody is writing.
|
|
178
|
+
*
|
|
179
|
+
* Granularity is REGION-level, never interleaved between body blocks: the canvas is
|
|
180
|
+
* `[hero slots] → [free block flow] → [inline fields] → [panel fields in the drawer]`.
|
|
181
|
+
* A field cannot be positioned "between two paragraphs" — there is no coordinate space
|
|
182
|
+
* for that, and inventing one would mean mounting form controls inside the Lexical tree.
|
|
183
|
+
*
|
|
184
|
+
* - `cover` / `title` / `excerpt` / `body` — the four hero slots, rendered unlabelled
|
|
185
|
+
* and typographically native. SCHEMA-LEVEL ONLY: a per-entry override may never
|
|
186
|
+
* claim one, or one author's click renders anonymous 40px text over anonymous text
|
|
187
|
+
* on that entry alone.
|
|
188
|
+
* - `inline` — in the canvas, below the block flow, labelled.
|
|
189
|
+
* - `panel` — in the drawer.
|
|
190
|
+
*
|
|
191
|
+
* ABSENT is meaningful and is the default for every model that predates this: the
|
|
192
|
+
* editor falls back to its title-gated heuristic. Only an explicit value promotes a
|
|
193
|
+
* field past that gate.
|
|
194
|
+
*/
|
|
195
|
+
type ContentModelFieldPlacement = "cover" | "title" | "excerpt" | "body" | "inline" | "panel";
|
|
196
|
+
interface ContentModelField {
|
|
197
|
+
key: string;
|
|
198
|
+
label: string;
|
|
199
|
+
type: ContentModelFieldType;
|
|
200
|
+
required?: boolean;
|
|
201
|
+
/**
|
|
202
|
+
* No two entries of the model may hold the same value (trimmed, case-insensitive). On a
|
|
203
|
+
* repeater child, every row of every entry at that path. Scalar types only.
|
|
204
|
+
*/
|
|
205
|
+
unique?: boolean;
|
|
206
|
+
defaultValue?: unknown;
|
|
207
|
+
options?: string[];
|
|
208
|
+
/** Per-type config. For `array`: either `itemType` (primitive) or `zones` (nested). */
|
|
209
|
+
config?: FieldConfig | null;
|
|
210
|
+
/**
|
|
211
|
+
* Which fieldset this field renders under in the schema builder. Authoring-only: it is
|
|
212
|
+
* never delivered and cannot move a value — see {@link Fieldset}.
|
|
213
|
+
*/
|
|
214
|
+
fieldsetId?: string;
|
|
215
|
+
/**
|
|
216
|
+
* Authoring-only editor placement. See {@link ContentModelFieldPlacement}.
|
|
217
|
+
* Field ORDER is the array index — there is deliberately no `order` property.
|
|
218
|
+
*/
|
|
219
|
+
placement?: ContentModelFieldPlacement;
|
|
220
|
+
/**
|
|
221
|
+
* Authoring chrome — how the field PRESENTS in the editor. Never delivered, never read by a
|
|
222
|
+
* renderer, and never able to move a value; the same contract as {@link placement}.
|
|
223
|
+
*
|
|
224
|
+
* A SIBLING of `config`, not a member of it: `config` is per-type and strict on several
|
|
225
|
+
* types, and the normalizer rebuilds it wholesale for every nesting field — so a `config.ui`
|
|
226
|
+
* survives on leaves and vanishes on exactly the fields `preview` is for.
|
|
227
|
+
*
|
|
228
|
+
* `preview.title` / `preview.media` name a CHILD FIELD KEY of this field (validated on
|
|
229
|
+
* write). Still no `order`: order is the array index, per the note on {@link placement}.
|
|
230
|
+
*/
|
|
231
|
+
ui?: ContentModelFieldUi;
|
|
232
|
+
/** Server-owned provenance of this field's chrome. @see UiOrigin */
|
|
233
|
+
uiOrigin?: UiOrigin;
|
|
234
|
+
/** Server-owned revert point. @see UiBefore */
|
|
235
|
+
uiBefore?: UiBefore;
|
|
236
|
+
}
|
|
237
|
+
/** @see ContentModelField.ui */
|
|
238
|
+
interface ContentModelFieldUi {
|
|
239
|
+
/** Start this nesting field's panel collapsed. Absent ≡ the editor's own default. */
|
|
240
|
+
collapsed?: boolean;
|
|
241
|
+
/** How one item of a nesting field summarises itself when collapsed. Keys, not values. */
|
|
242
|
+
preview?: {
|
|
243
|
+
/** Child field key whose value titles the row. */
|
|
244
|
+
title?: string;
|
|
245
|
+
/** Child field key whose value is the row's second line. */
|
|
246
|
+
subtitle?: string;
|
|
247
|
+
/** Child field key whose value is the row's thumbnail. Type is not constrained. */
|
|
248
|
+
media?: string;
|
|
249
|
+
};
|
|
250
|
+
/**
|
|
251
|
+
* How the ITEMS of a nesting field are arranged. ABSENT ≡ `"list"` — every field stored
|
|
252
|
+
* before this key existed means `"list"`, so a reader must treat undefined as list and never
|
|
253
|
+
* as "unset, pick something".
|
|
254
|
+
*
|
|
255
|
+
* Same placement rule as {@link ContentModelFieldUi.preview}: nesting fields only.
|
|
256
|
+
*/
|
|
257
|
+
layout?: "list" | "grid" | "table";
|
|
258
|
+
/**
|
|
259
|
+
* Whether the items of a list may be dragged. ABSENT ≡ `true`, for the same reason — nothing
|
|
260
|
+
* stored today carries it, and everything stored today is reorderable.
|
|
261
|
+
*
|
|
262
|
+
* `false` LOCKS the order: a "three steps" band, a semantic nav, a timeline. Valid only where
|
|
263
|
+
* there is a list (a repeatable zone, a `repeater`, or `modular`), so a reader that honours it
|
|
264
|
+
* must disable the sortable behaviour, not just hide the grip — a hidden grip still reorders
|
|
265
|
+
* from the keyboard.
|
|
266
|
+
*/
|
|
267
|
+
reorderable?: boolean;
|
|
268
|
+
/**
|
|
269
|
+
* Which editor control a LEAF renders with. ABSENT ≡ the type's default (a dropdown for a
|
|
270
|
+
* `select`, a plain input for a `number`). `segmented` is valid on a single-choice `select`;
|
|
271
|
+
* `slider` on a `number` whose config.min < config.max.
|
|
272
|
+
*/
|
|
273
|
+
control?: "segmented" | "slider";
|
|
274
|
+
/** The branch row's icon. Nesting fields only. */
|
|
275
|
+
icon?: DockIconName;
|
|
276
|
+
/** What one item is called ("Slide", "Member"), 1–24 chars. Nesting fields only. */
|
|
277
|
+
itemLabel?: string;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* A field inside an array zone — identical to a top-level {@link ContentModelField}.
|
|
281
|
+
* Kept as a named alias so consumers can express "zone field" intent; recursion
|
|
282
|
+
* (an array zone field with its own `config.zones`) is supported.
|
|
283
|
+
*/
|
|
284
|
+
type ZoneField = ContentModelField;
|
|
285
|
+
|
|
16
286
|
/**
|
|
17
287
|
* Page — a published content page within a workspace.
|
|
18
288
|
*/
|
|
@@ -27,6 +297,16 @@ interface Page {
|
|
|
27
297
|
publishedAt?: string;
|
|
28
298
|
createdAt: string;
|
|
29
299
|
updatedAt: string;
|
|
300
|
+
/**
|
|
301
|
+
* The content model that holds this page's own fields (content_models.page_id), for dock
|
|
302
|
+
* writes: its optimistic version is the If-Match. `null` for a static page or a legacy row with
|
|
303
|
+
* no page_id; absent on reads that do not resolve it.
|
|
304
|
+
*/
|
|
305
|
+
backingModel?: {
|
|
306
|
+
id: string;
|
|
307
|
+
optimisticVersion: number;
|
|
308
|
+
fieldsets: Fieldset[] | null;
|
|
309
|
+
} | null;
|
|
30
310
|
}
|
|
31
311
|
|
|
32
312
|
/**
|
|
@@ -46,6 +326,44 @@ declare const SPACE_BOTTOM_TOKENS: ("section-space-none" | "section-space-small"
|
|
|
46
326
|
/** `var(--bcms-<token>,<px>)`, or "" for anything that is not a known token (closed set). */
|
|
47
327
|
declare function spaceTokenCss(token: unknown): string;
|
|
48
328
|
|
|
329
|
+
/**
|
|
330
|
+
* A button block's LOOK beyond size: its variant, an optional leading icon and an optional
|
|
331
|
+
* trailing arrow. The ONE source of the names and the icon markup: the renderer draws from it,
|
|
332
|
+
* the validation schema allow-lists from it, and the dashboard's copy is pinned to it by a
|
|
333
|
+
* parity test.
|
|
334
|
+
*
|
|
335
|
+
* <a class="bcms-btn bcms-btn-{variant}">[<svg class="bcms-btn-icon">]Text[<svg class="bcms-btn-arrow">]</a>
|
|
336
|
+
*/
|
|
337
|
+
declare const BUTTON_VARIANTS: readonly ["primary", "secondary", "tertiary", "brand", "dark", "light", "outline", "link"];
|
|
338
|
+
type ButtonVariant = (typeof BUTTON_VARIANTS)[number];
|
|
339
|
+
/** Inner markup of each icon: lucide-react 1.8.0 paths (ISC), 24×24, stroke-drawn. */
|
|
340
|
+
declare const BUTTON_ICONS: {
|
|
341
|
+
readonly "arrow-right": "<path d=\"M5 12h14\"/><path d=\"m12 5 7 7-7 7\"/>";
|
|
342
|
+
readonly "arrow-up-right": "<path d=\"M7 7h10v10\"/><path d=\"M7 17 17 7\"/>";
|
|
343
|
+
readonly "chevron-right": "<path d=\"m9 18 6-6-6-6\"/>";
|
|
344
|
+
readonly plus: "<path d=\"M5 12h14\"/><path d=\"M12 5v14\"/>";
|
|
345
|
+
readonly check: "<path d=\"M20 6 9 17l-5-5\"/>";
|
|
346
|
+
readonly download: "<path d=\"M12 15V3\"/><path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\"/><path d=\"m7 10 5 5 5-5\"/>";
|
|
347
|
+
readonly "external-link": "<path d=\"M15 3h6v6\"/><path d=\"M10 14 21 3\"/><path d=\"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\"/>";
|
|
348
|
+
readonly mail: "<path d=\"m22 7-8.991 5.727a2 2 0 0 1-2.009 0L2 7\"/><rect x=\"2\" y=\"4\" width=\"20\" height=\"16\" rx=\"2\"/>";
|
|
349
|
+
readonly phone: "<path d=\"M13.832 16.568a1 1 0 0 0 1.213-.303l.355-.465A2 2 0 0 1 17 15h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2A18 18 0 0 1 2 4a2 2 0 0 1 2-2h3a2 2 0 0 1 2 2v3a2 2 0 0 1-.8 1.6l-.468.351a1 1 0 0 0-.292 1.233 14 14 0 0 0 6.392 6.384\"/>";
|
|
350
|
+
readonly calendar: "<path d=\"M8 2v4\"/><path d=\"M16 2v4\"/><rect width=\"18\" height=\"18\" x=\"3\" y=\"4\" rx=\"2\"/><path d=\"M3 10h18\"/>";
|
|
351
|
+
readonly play: "<path d=\"M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z\"/>";
|
|
352
|
+
readonly search: "<path d=\"m21 21-4.34-4.34\"/><circle cx=\"11\" cy=\"11\" r=\"8\"/>";
|
|
353
|
+
readonly "shopping-cart": "<circle cx=\"8\" cy=\"21\" r=\"1\"/><circle cx=\"19\" cy=\"21\" r=\"1\"/><path d=\"M2.05 2.05h2l2.66 12.42a2 2 0 0 0 2 1.58h9.78a2 2 0 0 0 1.95-1.57l1.65-7.43H5.12\"/>";
|
|
354
|
+
readonly star: "<path d=\"M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z\"/>";
|
|
355
|
+
readonly sparkles: "<path d=\"M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z\"/><path d=\"M20 2v4\"/><path d=\"M22 4h-4\"/><circle cx=\"4\" cy=\"20\" r=\"2\"/>";
|
|
356
|
+
readonly zap: "<path d=\"M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z\"/>";
|
|
357
|
+
};
|
|
358
|
+
type ButtonIcon = keyof typeof BUTTON_ICONS;
|
|
359
|
+
declare const BUTTON_ICON_NAMES: [ButtonIcon, ...ButtonIcon[]];
|
|
360
|
+
/** A stored variant as it renders: anything off the list is Primary. */
|
|
361
|
+
declare function buttonVariantOf(value: unknown): ButtonVariant;
|
|
362
|
+
/** A stored icon as it renders: anything off the list is no icon. */
|
|
363
|
+
declare function buttonIconOf(value: unknown): ButtonIcon | null;
|
|
364
|
+
/** One icon as inline SVG sized to the button's text, hidden from assistive tech (the label names the button). */
|
|
365
|
+
declare function buttonIconSvg(name: ButtonIcon, cls: "bcms-btn-icon" | "bcms-btn-arrow"): string;
|
|
366
|
+
|
|
49
367
|
/**
|
|
50
368
|
* ContentBlock — a discriminated union of all CMS block types.
|
|
51
369
|
* Each block has a `type` discriminator and a `props` object
|
|
@@ -230,7 +548,16 @@ interface ImageBlock {
|
|
|
230
548
|
interface ButtonProps {
|
|
231
549
|
text: string;
|
|
232
550
|
href: string;
|
|
233
|
-
|
|
551
|
+
/** Absent or off the list ⇒ "primary". Renders `bcms-btn-{variant}`. */
|
|
552
|
+
variant?: ButtonVariant;
|
|
553
|
+
/** Padding + font-size step. Absent ⇒ "md", today's button. sm/lg render `bcms-btn-sm|lg`. */
|
|
554
|
+
size?: "sm" | "md" | "lg";
|
|
555
|
+
/** Stretch to the column's width. Absent ⇒ false. true renders `bcms-btn-full`. */
|
|
556
|
+
fullWidth?: boolean;
|
|
557
|
+
/** Draw a trailing arrow after the text. Absent ⇒ false. */
|
|
558
|
+
arrow?: boolean;
|
|
559
|
+
/** A leading icon from `BUTTON_ICONS`. Absent, null or off the list ⇒ none. */
|
|
560
|
+
icon?: ButtonIcon | null;
|
|
234
561
|
}
|
|
235
562
|
interface ButtonBlock {
|
|
236
563
|
type: "button";
|
|
@@ -404,6 +731,14 @@ interface ComponentProps {
|
|
|
404
731
|
* declaration's, because the prop holds every row.
|
|
405
732
|
*/
|
|
406
733
|
source?: Record<string, string>;
|
|
734
|
+
/**
|
|
735
|
+
* A bound placement whose page spells its fields differently from the component's props — a
|
|
736
|
+
* locale copy (`/fr`) placed on its default-locale twin's component: `{ <propKey>: "<this page's
|
|
737
|
+
* field path>" }`. Readers resolve a prop's copy through it before `bind`, since the twin's own
|
|
738
|
+
* group keys (`personnalisez-titre`) are not the component's (`customize-title`). Written only
|
|
739
|
+
* while `bind` is; dropped with it when the instance takes its copy.
|
|
740
|
+
*/
|
|
741
|
+
bindPaths?: Record<string, string>;
|
|
407
742
|
}
|
|
408
743
|
interface ComponentBlock {
|
|
409
744
|
type: "component";
|
|
@@ -631,214 +966,6 @@ declare function componentInstanceAddresses(instanceBlockId: string, props: read
|
|
|
631
966
|
/** A CSS declaration object (key → value) usable as a React `style` prop, or undefined when empty. */
|
|
632
967
|
declare function blockStyleToCss(style: BlockStyle | undefined): Record<string, string | number> | undefined;
|
|
633
968
|
|
|
634
|
-
/**
|
|
635
|
-
* ContentModel — the structured content model (schema) for a workspace.
|
|
636
|
-
* Defines which content fields are available for authors to fill in.
|
|
637
|
-
*/
|
|
638
|
-
interface ContentModel {
|
|
639
|
-
id: string;
|
|
640
|
-
workspaceId: string;
|
|
641
|
-
name: string;
|
|
642
|
-
description?: string;
|
|
643
|
-
/** 'block' models hold no entries — they are instantiable only inside a `modular` field. */
|
|
644
|
-
kind?: ContentModelKind;
|
|
645
|
-
fields: ContentModelField[];
|
|
646
|
-
/** Authoring-only field grouping for the schema builder. Never affects the API shape. */
|
|
647
|
-
fieldsets?: Fieldset[];
|
|
648
|
-
createdAt: string;
|
|
649
|
-
updatedAt: string;
|
|
650
|
-
}
|
|
651
|
-
/**
|
|
652
|
-
* Canonical field types. Nesting lives on `array` via `config.zones`
|
|
653
|
-
* (see {@link ArrayZoneConfig}): `group`/`repeater` are accepted as legacy input
|
|
654
|
-
* by the API but normalized to `array` + zones on write, so stored/delivered
|
|
655
|
-
* content never contains them.
|
|
656
|
-
*/
|
|
657
|
-
type ContentModelFieldType = "text" | "richtext" | "document" | "image" | "boolean" | "number" | "select" | "reference" | "multi-reference" | "multiReference" | "array" | "date" | "datetime" | "longtext" | "slug" | "email" | "phone" | "link" | "color" | "json" | "file" | "component-ref" | "modular" | "sections" | "location";
|
|
658
|
-
type ContentModelKind = "model" | "block";
|
|
659
|
-
/** A named, UI-only grouping of a model's fields. Order is the array index. */
|
|
660
|
-
interface Fieldset {
|
|
661
|
-
id: string;
|
|
662
|
-
name: string;
|
|
663
|
-
/** One line shown under the card title in the editor. Editor-only. */
|
|
664
|
-
description?: string;
|
|
665
|
-
}
|
|
666
|
-
/**
|
|
667
|
-
* Nested-content config for an `array` field. A zone holds ordinary fields, and a
|
|
668
|
-
* zone field may itself be an `array` with its own zones, so nesting is recursive
|
|
669
|
-
* to any depth.
|
|
670
|
-
* - `nonRepeatable` — a single fixed block of fields (former `group`).
|
|
671
|
-
* - `repeatable` — a repeating list of field-objects (former `repeater`).
|
|
672
|
-
* Mutually exclusive with the primitive form (`config.itemType`).
|
|
673
|
-
*/
|
|
674
|
-
interface ArrayZoneConfig {
|
|
675
|
-
nonRepeatable?: ContentModelField[];
|
|
676
|
-
repeatable?: {
|
|
677
|
-
fields: ContentModelField[];
|
|
678
|
-
minItems?: number;
|
|
679
|
-
maxItems?: number;
|
|
680
|
-
};
|
|
681
|
-
}
|
|
682
|
-
/** Per-type config for a field (the typed shape behind the loose `config` bag). */
|
|
683
|
-
interface FieldConfig {
|
|
684
|
-
/** primitive array: list of scalars */
|
|
685
|
-
itemType?: "text" | "number" | "date";
|
|
686
|
-
/** nested array: zoned fields (recursive) */
|
|
687
|
-
zones?: ArrayZoneConfig;
|
|
688
|
-
/** reference / multi-reference */
|
|
689
|
-
contentModelId?: string;
|
|
690
|
-
min?: number;
|
|
691
|
-
max?: number;
|
|
692
|
-
/** date / datetime */
|
|
693
|
-
includeTime?: boolean;
|
|
694
|
-
/** modular: SLUGS of the kind='block' models this field accepts. Non-empty. */
|
|
695
|
-
blockSlugs?: string[];
|
|
696
|
-
/** modular: bounds on how many block instances the field may hold. */
|
|
697
|
-
minItems?: number;
|
|
698
|
-
maxItems?: number;
|
|
699
|
-
/**
|
|
700
|
-
* sections: SLUGS of the sections an author may insert into this zone.
|
|
701
|
-
*
|
|
702
|
-
* Deliberately NOT named `blockSlugs`. That key means "kind='block' content models" and is
|
|
703
|
-
* read by ModularField; these are section-registry slugs resolved from a different place.
|
|
704
|
-
* One key meaning two things is how `blockModels`/`blockSlugs` already drifted apart in the
|
|
705
|
-
* dashboard — a distinct name costs nothing and cannot be confused at a call site.
|
|
706
|
-
*
|
|
707
|
-
* ⚠ ABSENT ≠ EMPTY:
|
|
708
|
-
* absent → UNRESTRICTED, every registry section may be inserted
|
|
709
|
-
* [] → DENY ALL, a deliberate empty restriction
|
|
710
|
-
* [a, b] → only those
|
|
711
|
-
* `[]` means DENY here to match `components.allowed_on` (migration 0190), so two adjacent
|
|
712
|
-
* allow-lists never disagree about what empty means.
|
|
713
|
-
*
|
|
714
|
-
* Absent rather than "all current slugs" because the registry GROWS — it is fed by repo
|
|
715
|
-
* pushes and project components, so materializing today's slugs at field-creation time would
|
|
716
|
-
* silently exclude every section shipped afterwards.
|
|
717
|
-
*
|
|
718
|
-
* NOT READ DIRECTLY. Insertability is this list INTERSECTED with the component's `allowedOn`
|
|
719
|
-
* (where that section may be placed), computed by one resolver so the two cannot drift.
|
|
720
|
-
*
|
|
721
|
-
* Enforced on NEW picks only. Narrowing the list later must never invalidate sections an
|
|
722
|
-
* author already placed, the same rule modular's blockSlugs and component-ref's allowlist
|
|
723
|
-
* follow.
|
|
724
|
-
*/
|
|
725
|
-
allowedSections?: string[];
|
|
726
|
-
/** Durable project-local authored Zone mode. Legacy zones omit this key. */
|
|
727
|
-
mode?: "authored-v2";
|
|
728
|
-
/** Durable Zone id. Present when `mode` is `authored-v2`. */
|
|
729
|
-
zoneId?: string;
|
|
730
|
-
/** Explicit migration acknowledgement while the legacy allowlist remains readable. */
|
|
731
|
-
legacyResolved?: boolean;
|
|
732
|
-
legacyMappings?: Record<string, string>;
|
|
733
|
-
[key: string]: unknown;
|
|
734
|
-
}
|
|
735
|
-
/**
|
|
736
|
-
* Where a field renders in the entry editor.
|
|
737
|
-
*
|
|
738
|
-
* AUTHORING ONLY — this has no delivery or storage effect. It does not change the
|
|
739
|
-
* shape of `data`, is not read by any renderer in @bettercms-ai/next or /astro, and
|
|
740
|
-
* cannot move a value onto or off a published page. It decides one thing: where the
|
|
741
|
-
* control sits while somebody is writing.
|
|
742
|
-
*
|
|
743
|
-
* Granularity is REGION-level, never interleaved between body blocks: the canvas is
|
|
744
|
-
* `[hero slots] → [free block flow] → [inline fields] → [panel fields in the drawer]`.
|
|
745
|
-
* A field cannot be positioned "between two paragraphs" — there is no coordinate space
|
|
746
|
-
* for that, and inventing one would mean mounting form controls inside the Lexical tree.
|
|
747
|
-
*
|
|
748
|
-
* - `cover` / `title` / `excerpt` / `body` — the four hero slots, rendered unlabelled
|
|
749
|
-
* and typographically native. SCHEMA-LEVEL ONLY: a per-entry override may never
|
|
750
|
-
* claim one, or one author's click renders anonymous 40px text over anonymous text
|
|
751
|
-
* on that entry alone.
|
|
752
|
-
* - `inline` — in the canvas, below the block flow, labelled.
|
|
753
|
-
* - `panel` — in the drawer.
|
|
754
|
-
*
|
|
755
|
-
* ABSENT is meaningful and is the default for every model that predates this: the
|
|
756
|
-
* editor falls back to its title-gated heuristic. Only an explicit value promotes a
|
|
757
|
-
* field past that gate.
|
|
758
|
-
*/
|
|
759
|
-
type ContentModelFieldPlacement = "cover" | "title" | "excerpt" | "body" | "inline" | "panel";
|
|
760
|
-
interface ContentModelField {
|
|
761
|
-
key: string;
|
|
762
|
-
label: string;
|
|
763
|
-
type: ContentModelFieldType;
|
|
764
|
-
required?: boolean;
|
|
765
|
-
/**
|
|
766
|
-
* No two entries of the model may hold the same value (trimmed, case-insensitive). On a
|
|
767
|
-
* repeater child, every row of every entry at that path. Scalar types only.
|
|
768
|
-
*/
|
|
769
|
-
unique?: boolean;
|
|
770
|
-
defaultValue?: unknown;
|
|
771
|
-
options?: string[];
|
|
772
|
-
/** Per-type config. For `array`: either `itemType` (primitive) or `zones` (nested). */
|
|
773
|
-
config?: FieldConfig | null;
|
|
774
|
-
/**
|
|
775
|
-
* Which fieldset this field renders under in the schema builder. Authoring-only: it is
|
|
776
|
-
* never delivered and cannot move a value — see {@link Fieldset}.
|
|
777
|
-
*/
|
|
778
|
-
fieldsetId?: string;
|
|
779
|
-
/**
|
|
780
|
-
* Authoring-only editor placement. See {@link ContentModelFieldPlacement}.
|
|
781
|
-
* Field ORDER is the array index — there is deliberately no `order` property.
|
|
782
|
-
*/
|
|
783
|
-
placement?: ContentModelFieldPlacement;
|
|
784
|
-
/**
|
|
785
|
-
* Authoring chrome — how the field PRESENTS in the editor. Never delivered, never read by a
|
|
786
|
-
* renderer, and never able to move a value; the same contract as {@link placement}.
|
|
787
|
-
*
|
|
788
|
-
* A SIBLING of `config`, not a member of it: `config` is per-type and strict on several
|
|
789
|
-
* types, and the normalizer rebuilds it wholesale for every nesting field — so a `config.ui`
|
|
790
|
-
* survives on leaves and vanishes on exactly the fields `preview` is for.
|
|
791
|
-
*
|
|
792
|
-
* `preview.title` / `preview.media` name a CHILD FIELD KEY of this field (validated on
|
|
793
|
-
* write). Still no `order`: order is the array index, per the note on {@link placement}.
|
|
794
|
-
*/
|
|
795
|
-
ui?: ContentModelFieldUi;
|
|
796
|
-
}
|
|
797
|
-
/** @see ContentModelField.ui */
|
|
798
|
-
interface ContentModelFieldUi {
|
|
799
|
-
/** Start this nesting field's panel collapsed. Absent ≡ the editor's own default. */
|
|
800
|
-
collapsed?: boolean;
|
|
801
|
-
/** How one item of a nesting field summarises itself when collapsed. Keys, not values. */
|
|
802
|
-
preview?: {
|
|
803
|
-
/** Child field key whose value titles the row. */
|
|
804
|
-
title?: string;
|
|
805
|
-
/** Child field key whose value is the row's second line. */
|
|
806
|
-
subtitle?: string;
|
|
807
|
-
/** Child field key whose value is the row's thumbnail. Type is not constrained. */
|
|
808
|
-
media?: string;
|
|
809
|
-
};
|
|
810
|
-
/**
|
|
811
|
-
* How the ITEMS of a nesting field are arranged. ABSENT ≡ `"list"` — every field stored
|
|
812
|
-
* before this key existed means `"list"`, so a reader must treat undefined as list and never
|
|
813
|
-
* as "unset, pick something".
|
|
814
|
-
*
|
|
815
|
-
* Same placement rule as {@link ContentModelFieldUi.preview}: nesting fields only.
|
|
816
|
-
*/
|
|
817
|
-
layout?: "list" | "grid" | "table";
|
|
818
|
-
/**
|
|
819
|
-
* Whether the items of a list may be dragged. ABSENT ≡ `true`, for the same reason — nothing
|
|
820
|
-
* stored today carries it, and everything stored today is reorderable.
|
|
821
|
-
*
|
|
822
|
-
* `false` LOCKS the order: a "three steps" band, a semantic nav, a timeline. Valid only where
|
|
823
|
-
* there is a list (a repeatable zone, a `repeater`, or `modular`), so a reader that honours it
|
|
824
|
-
* must disable the sortable behaviour, not just hide the grip — a hidden grip still reorders
|
|
825
|
-
* from the keyboard.
|
|
826
|
-
*/
|
|
827
|
-
reorderable?: boolean;
|
|
828
|
-
/**
|
|
829
|
-
* Which editor control a LEAF renders with. ABSENT ≡ the type's default (a dropdown for a
|
|
830
|
-
* `select`, a plain input for a `number`). `segmented` is valid on a single-choice `select`;
|
|
831
|
-
* `slider` on a `number` whose config.min < config.max.
|
|
832
|
-
*/
|
|
833
|
-
control?: "segmented" | "slider";
|
|
834
|
-
}
|
|
835
|
-
/**
|
|
836
|
-
* A field inside an array zone — identical to a top-level {@link ContentModelField}.
|
|
837
|
-
* Kept as a named alias so consumers can express "zone field" intent; recursion
|
|
838
|
-
* (an array zone field with its own `config.zones`) is supported.
|
|
839
|
-
*/
|
|
840
|
-
type ZoneField = ContentModelField;
|
|
841
|
-
|
|
842
969
|
/**
|
|
843
970
|
* Generated from lucide-react@1.8.0 dynamic icon names.
|
|
844
971
|
* Legacy CamelCase identifiers remain valid for existing Layout documents.
|
|
@@ -1339,8 +1466,28 @@ interface ComponentPropDef {
|
|
|
1339
1466
|
* `preview`/`layout` on `group`, `table` and `slot`; `reorderable` on `table` ALONE, the only
|
|
1340
1467
|
* prop type whose value is a list. The save schema refuses the rest with the valid set named.
|
|
1341
1468
|
*/
|
|
1342
|
-
ui?:
|
|
1469
|
+
ui?: ComponentPropUi;
|
|
1470
|
+
/** Server-owned provenance of this prop's chrome. @see UiOrigin */
|
|
1471
|
+
uiOrigin?: UiOrigin;
|
|
1472
|
+
/** Server-owned revert point. @see UiBefore */
|
|
1473
|
+
uiBefore?: UiBefore;
|
|
1343
1474
|
}
|
|
1475
|
+
/**
|
|
1476
|
+
* A top-level prop's dock group. Props have no fieldsets column, so the group rides inline: the
|
|
1477
|
+
* first prop to carry an `id` defines it (label, kind, icon, collapsed), later props name `{id}`.
|
|
1478
|
+
*/
|
|
1479
|
+
interface PropGroup {
|
|
1480
|
+
id: string;
|
|
1481
|
+
/** 1–32 chars. Required on the defining prop. */
|
|
1482
|
+
label?: string;
|
|
1483
|
+
kind?: Exclude<FieldsetKind, "tab">;
|
|
1484
|
+
icon?: DockIconName;
|
|
1485
|
+
collapsed?: boolean;
|
|
1486
|
+
}
|
|
1487
|
+
/** A prop's `ui`: the field-lane chrome plus its inline {@link PropGroup}. */
|
|
1488
|
+
type ComponentPropUi = ContentModelFieldUi & {
|
|
1489
|
+
group?: PropGroup;
|
|
1490
|
+
};
|
|
1344
1491
|
/** One field inside a `group` prop or a `table` row. Recursive, capped at 3 levels deep. */
|
|
1345
1492
|
interface ComponentSubField {
|
|
1346
1493
|
key: string;
|
|
@@ -1452,6 +1599,158 @@ interface DeliveryComponent {
|
|
|
1452
1599
|
props: ComponentPropDef[];
|
|
1453
1600
|
}
|
|
1454
1601
|
|
|
1602
|
+
/**
|
|
1603
|
+
* The dock's click budget, as ONE pure function both ends read (V9): the backend's next-steps
|
|
1604
|
+
* rules call it on live data, and the dashboard's reach test measures its RENDERED dock against the
|
|
1605
|
+
* golden this module emits (src/__tests__/fixtures/dock-budget.golden.json). No dependencies.
|
|
1606
|
+
*
|
|
1607
|
+
* A SCREEN is one navigation level of the dock, modelled on what the dock renders:
|
|
1608
|
+
* - `root` the lane's first screen: the page fields, a page section, or a component's props;
|
|
1609
|
+
* - `list` a repeatable's items, one branch hop below the row that opens it (a repeater, an
|
|
1610
|
+
* `array` with a repeatable zone, a `table` prop, `modular`);
|
|
1611
|
+
* - `item` one item of that list, a second hop. `modular` has no item screen: its items are
|
|
1612
|
+
* other models.
|
|
1613
|
+
* A non-repeatable zone (`group`, `array` + zones.nonRepeatable, a `group` prop) is NOT a screen.
|
|
1614
|
+
* It renders inline as a group, collapsed only when its own `ui.collapsed` is true.
|
|
1615
|
+
*
|
|
1616
|
+
* On a screen:
|
|
1617
|
+
* - fieldsets with no `kind` are FLAT (V2): members render ungrouped, in document order;
|
|
1618
|
+
* - `kind:"group"` is a disclosure placed at its first member; `collapsed` costs 1 activation;
|
|
1619
|
+
* - `kind:"row"` is ONE leaf, however many members it holds;
|
|
1620
|
+
* - `kind:"tab"`, root screens only: a strip renders only with ≥2 non-empty tabs. Tab 1 is the
|
|
1621
|
+
* first panel, each later tab costs 1 activation, untabbed fields are PINNED above the strip,
|
|
1622
|
+
* and a group/row with `tab: <id>` sits in that tab. Below the root a tab reference is flat.
|
|
1623
|
+
* - component props join a group through `ui.group`; the first prop naming an id defines it.
|
|
1624
|
+
*
|
|
1625
|
+
* Budget, per screen (DOCK_BUDGET holds the limits):
|
|
1626
|
+
* - ungroupedLeaves: rows outside any group (a leaf, a row fieldset, a branch), as the max over
|
|
1627
|
+
* panels of pinned + panel. No picker term: tabs are capped at 3, so the strip never overflows.
|
|
1628
|
+
* - maxGroupLeaves: the largest group's own rows (a nested group counts in its own entry).
|
|
1629
|
+
* - depth: branch hops from the lane's root screen.
|
|
1630
|
+
* - maxActivations: the dearest value on the screen counted from the lane's root: +1 per branch
|
|
1631
|
+
* hop, +1 per collapsed group, +1 for a non-first tab. A screen with no values costs its entry.
|
|
1632
|
+
*/
|
|
1633
|
+
declare const DOCK_BUDGET: {
|
|
1634
|
+
readonly ungrouped: 8;
|
|
1635
|
+
readonly group: 12;
|
|
1636
|
+
readonly depth: 3;
|
|
1637
|
+
readonly activations: 2;
|
|
1638
|
+
};
|
|
1639
|
+
type DockLane = "page-fields" | "page-section" | "component";
|
|
1640
|
+
interface DockBudget {
|
|
1641
|
+
ungroupedLeaves: number;
|
|
1642
|
+
maxGroupLeaves: number;
|
|
1643
|
+
depth: number;
|
|
1644
|
+
maxActivations: number;
|
|
1645
|
+
}
|
|
1646
|
+
/** One row on a screen. Keys are paths from the screen's own fields (`hero.title`). */
|
|
1647
|
+
type DockNode = {
|
|
1648
|
+
kind: "leaf";
|
|
1649
|
+
key: string;
|
|
1650
|
+
} | {
|
|
1651
|
+
kind: "row";
|
|
1652
|
+
id: string;
|
|
1653
|
+
keys: string[];
|
|
1654
|
+
} | {
|
|
1655
|
+
kind: "branch";
|
|
1656
|
+
key: string;
|
|
1657
|
+
} | {
|
|
1658
|
+
kind: "group";
|
|
1659
|
+
id: string;
|
|
1660
|
+
collapsed: boolean;
|
|
1661
|
+
nodes: DockNode[];
|
|
1662
|
+
};
|
|
1663
|
+
interface DockScreen {
|
|
1664
|
+
/** `<lane>`, then `/<branch key>` per list and `/item` per item: `page-fields/quotes/item`. */
|
|
1665
|
+
id: string;
|
|
1666
|
+
lane: DockLane;
|
|
1667
|
+
kind: "root" | "list" | "item";
|
|
1668
|
+
title: string;
|
|
1669
|
+
depth: number;
|
|
1670
|
+
/** Activations spent reaching this screen from the lane's root. */
|
|
1671
|
+
entry: number;
|
|
1672
|
+
pinned: DockNode[];
|
|
1673
|
+
/** One panel per tab, in fieldset order. Empty when no strip renders. */
|
|
1674
|
+
tabs: DockNode[][];
|
|
1675
|
+
}
|
|
1676
|
+
/** The structural subset of a model field or component prop that this module reads. */
|
|
1677
|
+
interface DockFieldLike {
|
|
1678
|
+
key: string;
|
|
1679
|
+
label?: string;
|
|
1680
|
+
type: string;
|
|
1681
|
+
fieldsetId?: string;
|
|
1682
|
+
ui?: {
|
|
1683
|
+
collapsed?: boolean;
|
|
1684
|
+
group?: DockPropGroupLike;
|
|
1685
|
+
} | null;
|
|
1686
|
+
config?: unknown;
|
|
1687
|
+
/** Legacy `group`/`repeater` children, and a component sub-field's own children. */
|
|
1688
|
+
fields?: DockFieldLike[];
|
|
1689
|
+
}
|
|
1690
|
+
interface DockFieldsetLike {
|
|
1691
|
+
id: string;
|
|
1692
|
+
name?: string;
|
|
1693
|
+
kind?: "group" | "row" | "tab";
|
|
1694
|
+
collapsed?: boolean;
|
|
1695
|
+
tab?: string;
|
|
1696
|
+
}
|
|
1697
|
+
interface DockPropGroupLike {
|
|
1698
|
+
id: string;
|
|
1699
|
+
label?: string;
|
|
1700
|
+
kind?: "group" | "row";
|
|
1701
|
+
collapsed?: boolean;
|
|
1702
|
+
}
|
|
1703
|
+
/**
|
|
1704
|
+
* Every screen of one lane, root first. Pass `props` for a component lane (its `fields` and
|
|
1705
|
+
* `fieldsets` are then ignored): a prop's `ui.group` becomes the fieldset it joins.
|
|
1706
|
+
*/
|
|
1707
|
+
declare function dockScreens(source: {
|
|
1708
|
+
fields?: DockFieldLike[] | null;
|
|
1709
|
+
fieldsets?: DockFieldsetLike[] | null;
|
|
1710
|
+
}, lane: DockLane, props?: DockFieldLike[] | null): DockScreen[];
|
|
1711
|
+
declare function dockBudget(screen: DockScreen): DockBudget;
|
|
1712
|
+
|
|
1713
|
+
/**
|
|
1714
|
+
* THE button-link pairing rule, pure: which two sibling fields render as ONE button unit (the words
|
|
1715
|
+
* on the button + where it goes). The dashboard folds them together; the backend refuses a write
|
|
1716
|
+
* that splits such a pair across fieldsets (`pair_split`). One copy, so both ends agree.
|
|
1717
|
+
*
|
|
1718
|
+
* Presentation only: a pair keeps its own keys, values and writers.
|
|
1719
|
+
*
|
|
1720
|
+
* 1. A key is split into words whatever its spelling (`hero_cta_label`, `ctaText`, `button-link`);
|
|
1721
|
+
* a dotted path counts only its last segment.
|
|
1722
|
+
* 2. The LAST word is the role: `label text title cta button btn name` are TEXT roles, `href link
|
|
1723
|
+
* url to` LINK roles. Everything before it is the STEM.
|
|
1724
|
+
* 3. A text candidate is a text-typed field (`text`, `string`) with a text role. A key that is a
|
|
1725
|
+
* button noun (`cta`, `primaryButton`) also offers its full key as a stem.
|
|
1726
|
+
* 4. A link candidate is a link-typed field (`link`, `url`), or a text-typed field with a link role
|
|
1727
|
+
* that is not a media address (`image_url`). A link-typed field whose last word is not a link
|
|
1728
|
+
* role offers both its stem and its full key.
|
|
1729
|
+
* 5. Two fields pair when their stem holds EXACTLY one text and one link candidate. Three or more
|
|
1730
|
+
* candidates on a stem: none pair. A field that would pair two ways pairs neither way.
|
|
1731
|
+
*
|
|
1732
|
+
* When the key's words say nothing, the visible LABEL is read the same way, its stems namespaced
|
|
1733
|
+
* (`label:`) so a label reading only ever meets another label reading.
|
|
1734
|
+
*/
|
|
1735
|
+
/** What the rule needs to know about one field. */
|
|
1736
|
+
interface ButtonLinkCandidate {
|
|
1737
|
+
key: string;
|
|
1738
|
+
type?: string;
|
|
1739
|
+
label?: string;
|
|
1740
|
+
/** The current value, when known: a structured value never pairs as text. */
|
|
1741
|
+
value?: unknown;
|
|
1742
|
+
}
|
|
1743
|
+
/** `hero_cta_primary_label` / `ctaText` / `primaryButton-link` → lowercase words. */
|
|
1744
|
+
declare function keyWords(key: string): string[];
|
|
1745
|
+
type Role = {
|
|
1746
|
+
role: "text" | "link";
|
|
1747
|
+
stems: string[];
|
|
1748
|
+
};
|
|
1749
|
+
/** The role one field plays, with every stem it offers, or null. */
|
|
1750
|
+
declare function candidateRole(candidate: ButtonLinkCandidate): Role | null;
|
|
1751
|
+
/** Every unambiguous pair in one sibling list, as `[textIndex, linkIndex]`, in list order. */
|
|
1752
|
+
declare function buttonLinkPairs(candidates: readonly ButtonLinkCandidate[]): Array<[number, number]>;
|
|
1753
|
+
|
|
1455
1754
|
/**
|
|
1456
1755
|
* ContentEntry — a single unit of content, representing the
|
|
1457
1756
|
* published layout of a page: a collection of ordered blocks
|
|
@@ -2052,4 +2351,4 @@ declare function regionOf<E extends {
|
|
|
2052
2351
|
el: E;
|
|
2053
2352
|
}[], el: unknown): string | null;
|
|
2054
2353
|
|
|
2055
|
-
export { type AlignToken, type ApiError, type ApiKey, type ApiKeyPermission, type ApiKeyTokenType, type ArrayZoneConfig, type AssertEqual, type AuthResponse, type AuthSession, type AuthUser, BLOCK_BINDINGS, type BetterCMSErrorCode, type BgToken, type BindingKind, type BlockBinding, type BlockHoverStyle, type BlockStyle, type BlockType, type ButtonBlock, type ButtonProps, COMPONENT_PROP_TYPES, type CanonicalInputDefinition, type CollectionBlock, type CollectionProps, type ColorToken, type ColumnsBlock, type ColumnsProps, type Component, type ComponentBlock, type ComponentCategory, type ComponentFormPropRef, type ComponentPropDef, type ComponentPropType, type ComponentProps, type ComponentSubField, type ComponentVariantGroup, type Content, type ContentBlock, type ContentEntry, type ContentModel, type ContentModelField, type ContentModelFieldType, type ContentModelFieldUi, type ContentPageResult, type ContentResponse, type ContentWidthToken, type CornerToken, DIALOG_SELECTOR, type DeepReadonly, type DeliveredLayout, type DeliveryComponent, type DeliveryEntry, type DeliveryEntrySeo, type DeliveryList, type DeliveryPage, type DerivedLocator, type ElementLike, type ExpandedBinding, FOOTER_SECTION_ID, type FieldConfig, type FontSizeToken, type FooterBlock, type FooterColumn, type FooterProps, type Form, type FormBlock, type FormField, type FormProps, type FormSubmission, type HeadingBlock, type HeadingProps, type ImageBlock, type ImageProps, LANDMARK_SELECTOR, LAYOUT_SECTION_ICONS, LAYOUT_SECTION_ICON_SET, type LandmarkChainElement, type LandmarkElement, type LayoutComponentItem, type LayoutDataDocument, type LayoutFieldDefinition, type LayoutFieldItem, type LayoutFieldType, type LayoutScalarFieldType, type LayoutSection, type LayoutSectionIcon, type LayoutSectionItem, type LayoutStructureDocument, type LayoutZone, type LocatorGrammar, MAIN_SELECTOR, type ManagementLayoutCommand, type MediaAsset, type MediaCaptionTrack, type MediaFieldValue, NAVIGATION_SECTION_ID, type NavLink, type NavbarBlock, type NavbarProps, PAGE_CONTENT_ANCHOR_ID, type Page, type PageLayoutOverrideDataDocument, type PageLayoutOverrideDocument, type PageLayoutOverrideState, type PageLayoutOverrideStructureDocument, type PageLayoutSectionOverride, type PageLayoutSectionStructureOverride, type PageMetaJson, type PageOnlyLayoutSection, type PageSectionPlacement, type PaginatedResult, type Perspective, type PortableTextDocument, type PortableTextNode, type RadiusToken, type Redirect, type ReservedLayoutSection, type ResolvedLayoutNode, type RichTextBlock, type RichTextProps, SECTION_DOCTRINE, SECTION_SPACE_TOKENS, SPACE_BOTTOM_TOKENS, SPACE_STEP_TOKENS, type SectionBlock, type SectionProps, type SectionSpaceToken, type ShadowToken, type SignInInput, type SignUpInput, type SiteSeoDefaults, type SlideItem, type SliderBlock, type SliderProps, type SpaceStepToken, type SpaceToken, type SpacerBlock, type SpacerProps, type TabItem, type TabsBlock, type TabsProps, type TextBlock, type TextProps, type ThemeToken, type VariantInputMapping, type VideoBlock, type VideoProps, type WeightToken, type Workspace, type ZoneField, blockStyleToCss, componentInstanceAddresses, componentPropTargetKey, expandBlockBindings, formatPropsAttribute, getBlockType, isBlock, isChromeLandmark, landmarkRegions, locatorFor, parsePropsAttribute, readPath, regionOf, spaceTokenCss };
|
|
2354
|
+
export { type AlignToken, type ApiError, type ApiKey, type ApiKeyPermission, type ApiKeyTokenType, type ArrayZoneConfig, type AssertEqual, type AuthResponse, type AuthSession, type AuthUser, BLOCK_BINDINGS, BUTTON_ICONS, BUTTON_ICON_NAMES, BUTTON_VARIANTS, type BetterCMSErrorCode, type BgToken, type BindingKind, type BlockBinding, type BlockHoverStyle, type BlockStyle, type BlockType, type ButtonBlock, type ButtonIcon, type ButtonLinkCandidate, type ButtonProps, type ButtonVariant, COMPONENT_PROP_TYPES, type CanonicalInputDefinition, type CollectionBlock, type CollectionProps, type ColorToken, type ColumnsBlock, type ColumnsProps, type Component, type ComponentBlock, type ComponentCategory, type ComponentFormPropRef, type ComponentPropDef, type ComponentPropType, type ComponentPropUi, type ComponentProps, type ComponentSubField, type ComponentVariantGroup, type Content, type ContentBlock, type ContentEntry, type ContentModel, type ContentModelField, type ContentModelFieldType, type ContentModelFieldUi, type ContentPageResult, type ContentResponse, type ContentWidthToken, type CornerToken, DIALOG_SELECTOR, DOCK_BUDGET, DOCK_ICON_NAMES, DOCK_ICON_NAME_SET, type DeepReadonly, type DeliveredLayout, type DeliveryComponent, type DeliveryEntry, type DeliveryEntrySeo, type DeliveryList, type DeliveryPage, type DerivedLocator, type DockBudget, type DockFieldLike, type DockFieldsetLike, type DockIconName, type DockLane, type DockNode, type DockPropGroupLike, type DockScreen, type ElementLike, type ExpandedBinding, FOOTER_SECTION_ID, type FieldConfig, type Fieldset, type FieldsetKind, type FieldsetUiBefore, type FontSizeToken, type FooterBlock, type FooterColumn, type FooterProps, type Form, type FormBlock, type FormField, type FormProps, type FormSubmission, type HeadingBlock, type HeadingProps, type ImageBlock, type ImageProps, LANDMARK_SELECTOR, LAYOUT_SECTION_ICONS, LAYOUT_SECTION_ICON_SET, type LandmarkChainElement, type LandmarkElement, type LayoutComponentItem, type LayoutDataDocument, type LayoutFieldDefinition, type LayoutFieldItem, type LayoutFieldType, type LayoutScalarFieldType, type LayoutSection, type LayoutSectionIcon, type LayoutSectionItem, type LayoutStructureDocument, type LayoutZone, type LocatorGrammar, MAIN_SELECTOR, type ManagementLayoutCommand, type MediaAsset, type MediaCaptionTrack, type MediaFieldValue, NAVIGATION_SECTION_ID, type NavLink, type NavbarBlock, type NavbarProps, PAGE_CONTENT_ANCHOR_ID, type Page, type PageLayoutOverrideDataDocument, type PageLayoutOverrideDocument, type PageLayoutOverrideState, type PageLayoutOverrideStructureDocument, type PageLayoutSectionOverride, type PageLayoutSectionStructureOverride, type PageMetaJson, type PageOnlyLayoutSection, type PageSectionPlacement, type PaginatedResult, type Perspective, type PortableTextDocument, type PortableTextNode, type PropGroup, type RadiusToken, type Redirect, type ReservedLayoutSection, type ResolvedLayoutNode, type RichTextBlock, type RichTextProps, SECTION_DOCTRINE, SECTION_SPACE_TOKENS, SPACE_BOTTOM_TOKENS, SPACE_STEP_TOKENS, type SectionBlock, type SectionProps, type SectionSpaceToken, type ShadowToken, type SignInInput, type SignUpInput, type SiteSeoDefaults, type SlideItem, type SliderBlock, type SliderProps, type SpaceStepToken, type SpaceToken, type SpacerBlock, type SpacerProps, type TabItem, type TabsBlock, type TabsProps, type TextBlock, type TextProps, type ThemeToken, type UiBefore, type UiOrigin, type VariantInputMapping, type VideoBlock, type VideoProps, type WeightToken, type Workspace, type ZoneField, blockStyleToCss, buttonIconOf, buttonIconSvg, buttonLinkPairs, buttonVariantOf, candidateRole, componentInstanceAddresses, componentPropTargetKey, dockBudget, dockScreens, expandBlockBindings, formatPropsAttribute, getBlockType, isBlock, isChromeLandmark, keyWords, landmarkRegions, locatorFor, parsePropsAttribute, readPath, regionOf, spaceTokenCss };
|