@levo-so/site-runtime 0.1.113 → 0.2.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/CollectionInput-5QMoXahu.js +147 -0
- package/DateTimeWidget-CARoq7bQ.js +254 -0
- package/PhoneWidget-vtDO9CFq.js +99 -0
- package/Popover-B76-bN-a.js +57 -0
- package/RichTextWidget-CafZBEKI.js +912 -0
- package/ThemeProvider-Cm2jJC7a.js +381 -0
- package/Tooltip-Bx-BfR7T.js +78 -0
- package/VerifyButton-D1Mwk04d.js +299 -0
- package/index.d.ts +674 -0
- package/index.js +5752 -0
- package/package.json +63 -31
- package/styles.css +2 -0
- package/README.md +0 -93
- package/dist/LevoSiteProvider.d.ts +0 -25
- package/dist/LevoSiteProvider.js +0 -23
- package/dist/client.d.ts +0 -26
- package/dist/client.js +0 -14
- package/dist/data/index.d.ts +0 -101
- package/dist/data/index.js +0 -79
- package/dist/index.d.ts +0 -26
- package/dist/index.js +0 -6
- package/dist/inspector/dom.d.ts +0 -56
- package/dist/inspector/dom.js +0 -224
- package/dist/inspector/editorChannel.d.ts +0 -7
- package/dist/inspector/editorChannel.js +0 -19
- package/dist/inspector/historyWatcher.d.ts +0 -8
- package/dist/inspector/historyWatcher.js +0 -24
- package/dist/inspector/index.d.ts +0 -2
- package/dist/inspector/index.js +0 -191
- package/dist/inspector/messageRouter.d.ts +0 -38
- package/dist/inspector/messageRouter.js +0 -134
- package/dist/inspector/originalsStash.d.ts +0 -12
- package/dist/inspector/originalsStash.js +0 -24
- package/dist/inspector/protocol.d.ts +0 -180
- package/dist/inspector/stagedOverrides.d.ts +0 -28
- package/dist/inspector/stagedOverrides.js +0 -60
- package/dist/inspector/textEditController.d.ts +0 -24
- package/dist/inspector/textEditController.js +0 -62
- package/dist/pageHead.d.ts +0 -75
- package/dist/pageHead.js +0 -102
package/index.d.ts
ADDED
|
@@ -0,0 +1,674 @@
|
|
|
1
|
+
import { ILemaCollection } from '@levo-so/core';
|
|
2
|
+
import { ILevoClient } from '@levo-so/core';
|
|
3
|
+
import { ILevoInsights } from '@levo-so/insights';
|
|
4
|
+
import { JSX } from 'react/jsx-runtime';
|
|
5
|
+
import { LevoQuery } from '@levo-so/core';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Build the site's `levoHead` from its `site.json`. Each route passes its OWN imported
|
|
9
|
+
* meta file (`head: levoHead(meta)`) — no path matching anywhere; the import IS the
|
|
10
|
+
* pairing. The argument default lets a meta-less route render pure site defaults.
|
|
11
|
+
*
|
|
12
|
+
* Dynamic (`$slug`) routes pass a second argument naming the record fields that feed the
|
|
13
|
+
* head (`head: levoHead(meta, { source: "post", title: "title", … })`), so every slug
|
|
14
|
+
* gets its own title/description/share image instead of the route's shared static meta.
|
|
15
|
+
* Pages that set no `canonical` get a self-referencing one derived from the site domain
|
|
16
|
+
* + request path (og:url follows it in pageHead) — per-slug correct on dynamic routes.
|
|
17
|
+
*/
|
|
18
|
+
export declare const createLevoHead: (site: ISiteJson) => (meta?: IPlatformMetaFile, dynamic?: ILevoDynamicHead) => (ctx?: IHeadCtx) => IComposedHead;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Build the one-line route loader (`loader: levoLoader(dataSources)`): prefetch the
|
|
22
|
+
* page's declared data sources on the server so SSR ships fully-rendered HTML, and
|
|
23
|
+
* return them keyed by source key — that map is the route's `loaderData`, which
|
|
24
|
+
* `levoHead`'s dynamic config reads for per-record heads. An empty `dataSources` ({})
|
|
25
|
+
* resolves to an empty map. Context is typed structurally (just `queryClient`) so the
|
|
26
|
+
* scaffold's router types never enter the package.
|
|
27
|
+
*/
|
|
28
|
+
export declare const createLevoLoader: (config: ILevoSiteConfig) => (sources: ILevoDataSources) => ({ context, params, }: {
|
|
29
|
+
context: {
|
|
30
|
+
queryClient: IQueryClientLike;
|
|
31
|
+
};
|
|
32
|
+
params?: Record<string, string>;
|
|
33
|
+
}) => Promise<Record<string, unknown>>;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Build the site's core Levo client from config, or `null` when the site isn't wired to a
|
|
37
|
+
* backend yet (no `apiUrl`). SSR-safe — `createLevoClient` guards its window/document reads.
|
|
38
|
+
*
|
|
39
|
+
* Explicit return type on purpose: inference would inline core-internal names its rolled-up
|
|
40
|
+
* d.ts doesn't export → TS4023 on declaration emit.
|
|
41
|
+
*/
|
|
42
|
+
export declare const createSiteClient: (config?: ILevoSiteConfig) => ILevoClient | null;
|
|
43
|
+
|
|
44
|
+
export declare interface IComposedHead {
|
|
45
|
+
meta: IHeadEntry[];
|
|
46
|
+
links: IHeadEntry[];
|
|
47
|
+
scripts: IHeadEntry[];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Editor → preview (received by `onMessage`; dashboard's `IOutboundMessage`). */
|
|
51
|
+
export declare type IEditorToPreview = {
|
|
52
|
+
type: "set-inspect";
|
|
53
|
+
enabled: boolean;
|
|
54
|
+
} | {
|
|
55
|
+
type: "set-text-edit";
|
|
56
|
+
enabled: boolean;
|
|
57
|
+
} | {
|
|
58
|
+
type: "clear-selection";
|
|
59
|
+
} | {
|
|
60
|
+
type: "select-element";
|
|
61
|
+
element: IElementLocator;
|
|
62
|
+
} | {
|
|
63
|
+
type: "edit-element";
|
|
64
|
+
element: IElementLocator;
|
|
65
|
+
} | {
|
|
66
|
+
type: "highlight-element";
|
|
67
|
+
element: IElementLocator;
|
|
68
|
+
} | {
|
|
69
|
+
type: "clear-highlight";
|
|
70
|
+
} | {
|
|
71
|
+
type: "request-layers";
|
|
72
|
+
} | {
|
|
73
|
+
type: "request-sources";
|
|
74
|
+
} | {
|
|
75
|
+
type: "revert-text";
|
|
76
|
+
element: IElementLocator;
|
|
77
|
+
} | {
|
|
78
|
+
type: "navigate";
|
|
79
|
+
route: string;
|
|
80
|
+
} | {
|
|
81
|
+
type: "stage-style";
|
|
82
|
+
stageId: string;
|
|
83
|
+
element: IElementLocator;
|
|
84
|
+
styles: Record<string, string>;
|
|
85
|
+
media?: string;
|
|
86
|
+
} | {
|
|
87
|
+
type: "stage-text";
|
|
88
|
+
stageId: string;
|
|
89
|
+
element: IElementLocator;
|
|
90
|
+
value: string;
|
|
91
|
+
} | {
|
|
92
|
+
type: "clear-staged";
|
|
93
|
+
stageId?: string;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
/** A nested element locator — `file:line:col` + occurrence index. Never top-level. */
|
|
97
|
+
export declare interface IElementLocator {
|
|
98
|
+
source: string;
|
|
99
|
+
index?: number;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* The slice of the router's head-fn context we read. Structural on purpose (like
|
|
104
|
+
* IQueryClientLike) so the package never depends on the router's types: `loaderData` is
|
|
105
|
+
* the loader's return value — `prefetchLevoSources`' source-keyed map — and
|
|
106
|
+
* `match.pathname` is the request path. Both read defensively; absent = skipped.
|
|
107
|
+
*/
|
|
108
|
+
declare interface IHeadCtx {
|
|
109
|
+
loaderData?: unknown;
|
|
110
|
+
match?: {
|
|
111
|
+
pathname?: string;
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
declare interface IHeadEntry {
|
|
116
|
+
[attr: string]: string | undefined;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export declare type IHistoryFn = History["pushState"];
|
|
120
|
+
|
|
121
|
+
export declare interface ILayersNode {
|
|
122
|
+
tag: string;
|
|
123
|
+
source?: string;
|
|
124
|
+
index?: number;
|
|
125
|
+
text?: string;
|
|
126
|
+
/** The element carries the `hidden` utility (display:none) — a reachability hint the
|
|
127
|
+
* Layers panel surfaces. Live + class-based, so it covers component internals too
|
|
128
|
+
* (the dashboard no longer parses JSX for this). Present only when true. */
|
|
129
|
+
hidden?: boolean;
|
|
130
|
+
childCount: number;
|
|
131
|
+
children: ILayersNode[];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** The shape a page exports so its route loader can prefetch every binding it renders. */
|
|
135
|
+
export declare type ILevoDataSources = Record<string, ILevoSourceDef>;
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Per-record head config for a dynamic (`$slug`) route — `levoHead`'s optional second
|
|
139
|
+
* argument. A static literal (AI/editor-written, next to the route's meta import); each
|
|
140
|
+
* field names a FIELD on the loaded record (the `dataSources` entry named by `source`).
|
|
141
|
+
* At request time the record's values override the static meta file per-field, so every
|
|
142
|
+
* slug ships its own title, description, and share image.
|
|
143
|
+
*/
|
|
144
|
+
export declare interface ILevoDynamicHead {
|
|
145
|
+
/** Key in the page's `dataSources` whose loaded record feeds the head. */
|
|
146
|
+
source: string;
|
|
147
|
+
/** Record field holding the page title (the site name is appended automatically). */
|
|
148
|
+
title?: string;
|
|
149
|
+
/** Record field holding the description. */
|
|
150
|
+
description?: string;
|
|
151
|
+
/** Record field holding the share image (platform image object or URL). */
|
|
152
|
+
image?: string;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* A form binding — the fields + submit for a collection. `LevoForm` renders it (the schema
|
|
157
|
+
* drives which inputs appear); submissions go to the collection. Forms only bind to
|
|
158
|
+
* collections, so there's no `module` variance — but it's kept for symmetry with the other
|
|
159
|
+
* configs and so the editor binding reads uniformly.
|
|
160
|
+
*/
|
|
161
|
+
export declare interface ILevoFormConfig {
|
|
162
|
+
module: "collection";
|
|
163
|
+
/** Collection key. */
|
|
164
|
+
identifier: string;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export declare interface ILevoFormProps {
|
|
168
|
+
/** The form binding. Declare it in the page's `dataSources` (`mode: "form"`) so the route loader prefetches the schema SSR, then pass that entry here. */
|
|
169
|
+
source: ILevoFormConfig;
|
|
170
|
+
/** Submit-button label. */
|
|
171
|
+
submitLabel?: string;
|
|
172
|
+
/** Field keys to hide from the rendered form (matched against field key/id, recursively into nested fields). */
|
|
173
|
+
hiddenFields?: string[];
|
|
174
|
+
/** Layout: all fields at once, one-at-a-time (Typeform), or stepped by section. */
|
|
175
|
+
formVariant?: "default" | "single-field" | "steps" | "steps-2";
|
|
176
|
+
/** Success-screen copy + the post-submit action (show a message, let them submit another, or redirect). */
|
|
177
|
+
successConfig?: {
|
|
178
|
+
title?: string;
|
|
179
|
+
message?: string;
|
|
180
|
+
action?: {
|
|
181
|
+
type: "none" | "submit_another" | "redirect";
|
|
182
|
+
value?: string;
|
|
183
|
+
};
|
|
184
|
+
};
|
|
185
|
+
/** Brand the form. Optional — defaults to the site theme; only override the few colors you want to diverge. */
|
|
186
|
+
theme?: ILevoFormTheme;
|
|
187
|
+
className?: string;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export declare interface ILevoFormResult {
|
|
191
|
+
/** The collection schema (`sections[].fields[]`) the form renders. null until loaded / unwired. */
|
|
192
|
+
schema: ILemaCollection | null;
|
|
193
|
+
isLoading: boolean;
|
|
194
|
+
error: string | null;
|
|
195
|
+
/** Spread onto the form container — stamps the editor binding. */
|
|
196
|
+
bind: {
|
|
197
|
+
"data-levo-source": string;
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Per-form color/radius overrides. Every value is any CSS color/length — pass a site token
|
|
203
|
+
* (`"var(--color-brand)"`) or a literal (`"#0ea5e9"`). Omitted keys fall through to the site
|
|
204
|
+
* theme (see `DEFAULT_FORM_TOKENS`), so a form auto-matches the brand without any theme prop.
|
|
205
|
+
*/
|
|
206
|
+
declare interface ILevoFormTheme {
|
|
207
|
+
colors?: Partial<{
|
|
208
|
+
/** Buttons, focus accents. */
|
|
209
|
+
primary: string;
|
|
210
|
+
/** Text/icon on `primary`. */
|
|
211
|
+
primaryForeground: string;
|
|
212
|
+
/** Body text. */
|
|
213
|
+
foreground: string;
|
|
214
|
+
/** Field + card backgrounds. */
|
|
215
|
+
input: string;
|
|
216
|
+
/** Field borders + dividers. */
|
|
217
|
+
border: string;
|
|
218
|
+
/** Focus ring. */
|
|
219
|
+
ring: string;
|
|
220
|
+
/** Error text + invalid fields. */
|
|
221
|
+
destructive: string;
|
|
222
|
+
}>;
|
|
223
|
+
/** Corner radius for inputs/buttons (default: the site's `--radius-token`). */
|
|
224
|
+
radius?: string;
|
|
225
|
+
/** Vertical space between fields (default: `1.5rem`). Tighten with `"1rem"`, open up with `"2rem"`. */
|
|
226
|
+
gap?: string;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/** A single-record binding — one collection record / blog post / event by `slug` (a detail page). */
|
|
230
|
+
export declare interface ILevoRecordConfig {
|
|
231
|
+
module: "collection" | "blog" | "event";
|
|
232
|
+
/** Collection key / blog key / event series id. Round-tripped; the event single endpoint is flat (slug only). */
|
|
233
|
+
identifier: string;
|
|
234
|
+
/**
|
|
235
|
+
* Reserved for field projection. The slug endpoints return the whole record today, so
|
|
236
|
+
* this is round-tripped through the binding but not yet sent to the API.
|
|
237
|
+
*/
|
|
238
|
+
query?: Pick<LevoQuery.FindQuery, "select" | "include">;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export declare interface ILevoRecordResult<T = Record<string, unknown>> {
|
|
242
|
+
data: T | null;
|
|
243
|
+
isLoading: boolean;
|
|
244
|
+
error: string | null;
|
|
245
|
+
bind: {
|
|
246
|
+
"data-levo-source": string;
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/** Site-level Levo config — the scaffold shim fills this from Vite env. */
|
|
251
|
+
export declare interface ILevoSiteConfig {
|
|
252
|
+
/** Origin of the Levo public API / proxy the site's data calls go through. */
|
|
253
|
+
apiUrl?: string;
|
|
254
|
+
/** The site's workspace id (`W…`). Invalid/absent → client runs workspace-less. */
|
|
255
|
+
workspace?: string;
|
|
256
|
+
/** The site's id, stamped onto analytics events. */
|
|
257
|
+
siteId?: string;
|
|
258
|
+
/**
|
|
259
|
+
* Analytics reverse-proxy URL. Absent/null → identity + DOM trackers still run
|
|
260
|
+
* (popup triggers work) but nothing is sent — queued events are dropped.
|
|
261
|
+
*/
|
|
262
|
+
insightsUrl?: string | null;
|
|
263
|
+
/** Forwarded to the client's APP_MODE; defaults to "production". */
|
|
264
|
+
appMode?: string;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/** A list binding — collection records, blog posts, or events matching `query`. */
|
|
268
|
+
export declare interface ILevoSourceConfig {
|
|
269
|
+
/** "collection" | "blog" | "event". Community has no core client module yet. */
|
|
270
|
+
module: "collection" | "blog" | "event";
|
|
271
|
+
/** Collection key / blog key / event series id. */
|
|
272
|
+
identifier: string;
|
|
273
|
+
/** where / sort / limit / page / search. `limit: -1` = all. */
|
|
274
|
+
query?: LevoQuery.FindQuery;
|
|
275
|
+
/** Reserved (blog sub-module identifiers etc.); round-tripped through the binding. */
|
|
276
|
+
options?: Record<string, unknown>;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* One entry in a page's `dataSources` export — a list, record, or form binding, discriminated
|
|
281
|
+
* by `mode`. The route loader reads these to prefetch; the page passes each to its hook. `mode`
|
|
282
|
+
* is optional for lists (the default); required for records (so the loader uses the route slug)
|
|
283
|
+
* and forms (so the loader prefetches the collection schema instead of content).
|
|
284
|
+
*/
|
|
285
|
+
export declare type ILevoSourceDef = (ILevoSourceConfig & {
|
|
286
|
+
mode?: "list";
|
|
287
|
+
}) | (ILevoRecordConfig & {
|
|
288
|
+
mode: "record";
|
|
289
|
+
}) | (ILevoFormConfig & {
|
|
290
|
+
mode: "form";
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
export declare interface ILevoSourceResult<T = Record<string, unknown>> {
|
|
294
|
+
/** null until loaded, on error, and on an unwired site. */
|
|
295
|
+
data: T[] | null;
|
|
296
|
+
meta: {
|
|
297
|
+
total: number;
|
|
298
|
+
pages: number;
|
|
299
|
+
} | null;
|
|
300
|
+
isLoading: boolean;
|
|
301
|
+
error: string | null;
|
|
302
|
+
/** Spread onto the container that renders the list — stamps the editor binding. */
|
|
303
|
+
bind: {
|
|
304
|
+
"data-levo-source": string;
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
export declare function Inspector(): null;
|
|
309
|
+
|
|
310
|
+
/** One page's head metadata. Every field optional — site defaults fill gaps per-field. */
|
|
311
|
+
export declare interface IPageMeta {
|
|
312
|
+
title?: string;
|
|
313
|
+
description?: string;
|
|
314
|
+
/** Absolute URL. Rendered as `<link rel="canonical">`. */
|
|
315
|
+
canonical?: string;
|
|
316
|
+
/** e.g. "index,follow" / "noindex,nofollow". */
|
|
317
|
+
robots?: string;
|
|
318
|
+
og?: {
|
|
319
|
+
title?: string;
|
|
320
|
+
description?: string;
|
|
321
|
+
image?: string;
|
|
322
|
+
/** Absolute share URL. Falls back to `canonical` when unset. */
|
|
323
|
+
url?: string;
|
|
324
|
+
/** Defaults to "website" when any og field is present. */
|
|
325
|
+
type?: string;
|
|
326
|
+
};
|
|
327
|
+
twitter?: {
|
|
328
|
+
/** Defaults to "summary_large_image" when any twitter field is present. */
|
|
329
|
+
card?: string;
|
|
330
|
+
title?: string;
|
|
331
|
+
description?: string;
|
|
332
|
+
image?: string;
|
|
333
|
+
};
|
|
334
|
+
/** JSON-LD object(s) — each becomes a `<script type="application/ld+json">`. */
|
|
335
|
+
ldJson?: Record<string, unknown> | Array<Record<string, unknown>>;
|
|
336
|
+
/**
|
|
337
|
+
* Raw head snippet for THIS page. v1 supports `<script>`, `<meta>` and `<link>` tags
|
|
338
|
+
* only (the analytics / verification / preload cases) — anything else is dropped by
|
|
339
|
+
* `parseRawHead`, since arbitrary markup can't be expressed as document metadata.
|
|
340
|
+
*/
|
|
341
|
+
customHead?: string;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* One platform-data binding found on the page — a `data-levo-source` container. Emitted in
|
|
346
|
+
* `sources-list` (reply to `request-sources`) so the editor's page-level Data manager can list
|
|
347
|
+
* every binding without a selection. `element` is the container's own `data-tsd-source` locator
|
|
348
|
+
* (a data edit targets the hook call site); `config` is the parsed binding, omitted when the
|
|
349
|
+
* attribute is malformed JSON.
|
|
350
|
+
*/
|
|
351
|
+
export declare interface IPageSource {
|
|
352
|
+
raw: string;
|
|
353
|
+
config?: unknown;
|
|
354
|
+
element: IElementLocator;
|
|
355
|
+
tag: string;
|
|
356
|
+
label: string;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
export declare interface IPatchedHistoryFn {
|
|
360
|
+
(this: History, ...args: Parameters<IHistoryFn>): ReturnType<IHistoryFn>;
|
|
361
|
+
__inspectorPatched?: boolean;
|
|
362
|
+
__orig?: IHistoryFn;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/** The full `meta/<route>.json` shape: page identity (platform-owned) + the SEO object. */
|
|
366
|
+
export declare interface IPlatformMetaFile {
|
|
367
|
+
title?: string;
|
|
368
|
+
description?: string;
|
|
369
|
+
meta?: IPlatformPageMeta;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/** The platform's per-page SEO object — the `meta` key of `meta/<route>.json`. */
|
|
373
|
+
export declare interface IPlatformPageMeta {
|
|
374
|
+
meta_title?: string;
|
|
375
|
+
meta_description?: string;
|
|
376
|
+
keywords?: string;
|
|
377
|
+
og_title?: string;
|
|
378
|
+
og_description?: string;
|
|
379
|
+
/** Plain URL string, or the platform media object (older rows) — `.location` is read. */
|
|
380
|
+
og_image?: string | {
|
|
381
|
+
location?: string;
|
|
382
|
+
} | null;
|
|
383
|
+
og_url?: string;
|
|
384
|
+
canonical?: string;
|
|
385
|
+
twitter_card?: string;
|
|
386
|
+
/** JSON-LD structured data — rendered as an `application/ld+json` script tag. */
|
|
387
|
+
ld_json?: Record<string, unknown> | Array<Record<string, unknown>>;
|
|
388
|
+
/** Page-scoped raw head snippet — script/meta/link tags only. */
|
|
389
|
+
head_code?: string;
|
|
390
|
+
disable_indexing?: boolean;
|
|
391
|
+
robots?: string;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/** Preview → editor (emitted by `send`; dashboard's `IInboundMessage`). */
|
|
395
|
+
export declare type IPreviewToEditor = {
|
|
396
|
+
type: "ready";
|
|
397
|
+
} | {
|
|
398
|
+
type: "inspect-state";
|
|
399
|
+
enabled: boolean;
|
|
400
|
+
} | {
|
|
401
|
+
type: "text-edit-state";
|
|
402
|
+
enabled: boolean;
|
|
403
|
+
} | {
|
|
404
|
+
type: "element-selected";
|
|
405
|
+
element: ISelectedElement;
|
|
406
|
+
} | {
|
|
407
|
+
type: "element-text-changed";
|
|
408
|
+
element: ITextChangedElement;
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* `route` is the pathname (always present). `file` is the route's repo-relative source
|
|
412
|
+
* file (e.g. `src/routes/pricing.tsx`, no leading slash, no `:line:col`) — reserved:
|
|
413
|
+
* the runtime doesn't emit it yet; the dashboard falls back to url → file mapping.
|
|
414
|
+
*/
|
|
415
|
+
| {
|
|
416
|
+
type: "route";
|
|
417
|
+
route: string;
|
|
418
|
+
file?: string;
|
|
419
|
+
} | {
|
|
420
|
+
type: "staged-ack";
|
|
421
|
+
stageId: string;
|
|
422
|
+
} | {
|
|
423
|
+
type: "layers-tree";
|
|
424
|
+
tree: ILayersNode;
|
|
425
|
+
truncated: boolean;
|
|
426
|
+
} | {
|
|
427
|
+
type: "sources-list";
|
|
428
|
+
sources: IPageSource[];
|
|
429
|
+
} | {
|
|
430
|
+
type: "select-miss";
|
|
431
|
+
element: IElementLocator;
|
|
432
|
+
} | {
|
|
433
|
+
type: "highlight-miss";
|
|
434
|
+
element: IElementLocator;
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* The minimal QueryClient surface `prefetchLevoSources` needs. Structural on purpose — a
|
|
439
|
+
* branded `QueryClient` type in the public API would clash whenever the consuming site
|
|
440
|
+
* resolves a different `@tanstack/react-query` copy/version than the one this package was
|
|
441
|
+
* built against (peer dep). Any real QueryClient satisfies this.
|
|
442
|
+
*/
|
|
443
|
+
export declare interface IQueryClientLike {
|
|
444
|
+
ensureQueryData: (options: {
|
|
445
|
+
queryKey: readonly unknown[];
|
|
446
|
+
queryFn: () => Promise<unknown>;
|
|
447
|
+
}) => Promise<unknown>;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/** The element-selected payload — see `selectedPayload`. */
|
|
451
|
+
export declare interface ISelectedElement {
|
|
452
|
+
tag: string;
|
|
453
|
+
classes: string;
|
|
454
|
+
text: string;
|
|
455
|
+
label: string;
|
|
456
|
+
path: string;
|
|
457
|
+
/** null when the element carries no `data-tsd-source` stamp. */
|
|
458
|
+
source: string | null;
|
|
459
|
+
index: number;
|
|
460
|
+
occurrences: number;
|
|
461
|
+
ancestors: {
|
|
462
|
+
tag: string;
|
|
463
|
+
text: string;
|
|
464
|
+
source?: string;
|
|
465
|
+
}[];
|
|
466
|
+
/** Whole normalized textContent — present ONLY for text-mode-editable nodes. */
|
|
467
|
+
fullText?: string;
|
|
468
|
+
/**
|
|
469
|
+
* The nearest `data-levo-source` binding container above the selection (inclusive) — a
|
|
470
|
+
* platform-data-bound region (`useLevoSource`/`useLevoRecord`). Present only when the
|
|
471
|
+
* selection sits inside one. `config` is the parsed binding ({mode, module, identifier,
|
|
472
|
+
* query,…}), omitted when the attribute is malformed JSON. `element` is the binding
|
|
473
|
+
* CONTAINER's own locator, so a data edit targets the hook call site — not the clicked
|
|
474
|
+
* child. Lets the editor's "Integrate" dialog open pre-filled without parsing JSX.
|
|
475
|
+
*/
|
|
476
|
+
sourceBinding?: {
|
|
477
|
+
raw: string;
|
|
478
|
+
config?: unknown;
|
|
479
|
+
element: IElementLocator;
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/** The slice of the project's root `site.json` the runtime reads. */
|
|
484
|
+
export declare interface ISiteJson {
|
|
485
|
+
id?: string;
|
|
486
|
+
workspace_id?: string;
|
|
487
|
+
name?: string;
|
|
488
|
+
description?: string;
|
|
489
|
+
/** The site's live URL host (with or without protocol) — feeds auto-canonicals. */
|
|
490
|
+
domain?: string;
|
|
491
|
+
settings?: {
|
|
492
|
+
head_code?: string;
|
|
493
|
+
};
|
|
494
|
+
levo?: {
|
|
495
|
+
api_url?: string;
|
|
496
|
+
insights_url?: string | null;
|
|
497
|
+
app_mode?: string;
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/** Site-wide defaults + site-wide raw head, from `src/pages/_site.meta.ts`. */
|
|
502
|
+
export declare interface ISiteMeta extends IPageMeta {
|
|
503
|
+
/** "%s · Acme" — %s is the page title. Applied only when the page provides a title. */
|
|
504
|
+
titleTemplate?: string;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
export declare type IStagedEntry = IStagedStyleEntry | IStagedTextEntry;
|
|
508
|
+
|
|
509
|
+
export declare interface IStagedStyleEntry {
|
|
510
|
+
kind: "style";
|
|
511
|
+
source: string;
|
|
512
|
+
index: number;
|
|
513
|
+
styles: Record<string, string>;
|
|
514
|
+
media?: string;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
export declare interface IStagedTextEntry {
|
|
518
|
+
kind: "text";
|
|
519
|
+
source: string;
|
|
520
|
+
index: number;
|
|
521
|
+
value: string;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/** The element-text-changed payload — see `commit`. */
|
|
525
|
+
export declare interface ITextChangedElement {
|
|
526
|
+
source: string | null;
|
|
527
|
+
index: number;
|
|
528
|
+
tag: string;
|
|
529
|
+
value: string;
|
|
530
|
+
previous?: string;
|
|
531
|
+
occurrences: number;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Self-contained event registration widget for generated Studio v3 sites — ticket
|
|
536
|
+
* selection, coupons, attendee details, payment (Razorpay by default; Stripe Embedded
|
|
537
|
+
* Checkout when the booking API returns `provider: "stripe"`), and a booking confirmation.
|
|
538
|
+
*
|
|
539
|
+
* The AI drops this onto an event page and NEVER rebuilds the flow: it owns the entire
|
|
540
|
+
* booking + payment path against the Levo event API. The site client (`useLevoSite`)
|
|
541
|
+
* auto-stamps the workspace on every request, so no auth/workspace wiring is needed.
|
|
542
|
+
* `external` turns it into a plain link out to a third-party ticketing URL.
|
|
543
|
+
*/
|
|
544
|
+
export declare const LevoEventRegister: ({ eventID, title, external, buttonText, }: {
|
|
545
|
+
/** Event id (or slug the single-event endpoint resolves). */
|
|
546
|
+
eventID: string;
|
|
547
|
+
/** Event name, shown in the modal header. */
|
|
548
|
+
title?: string;
|
|
549
|
+
/** External ticketing URL — when set, renders a link out instead of the modal flow. */
|
|
550
|
+
external?: string;
|
|
551
|
+
buttonText?: string;
|
|
552
|
+
}) => JSX.Element;
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* A collection-backed form for generated Studio v3 sites — renders the collection's fields
|
|
556
|
+
* (from its SSR-prefetched schema) and submits entries into that collection. The AI drops it
|
|
557
|
+
* in and never rebuilds the form engine.
|
|
558
|
+
*
|
|
559
|
+
* Colors follow the site theme (`src/styles/theme.css`) by default, so a form matches the
|
|
560
|
+
* brand out of the box; `theme` overrides per form. `CollectionFormRenderer` resolves its
|
|
561
|
+
* client via `@levo-so/react`'s `useLevo()` — the same context `LevoSiteProvider` mounts at
|
|
562
|
+
* the site root, so no per-form provider is needed. Declare the form in the page's
|
|
563
|
+
* `dataSources` as `mode: "form"` so the loader prefetches the schema (no field-flash, SSR-safe).
|
|
564
|
+
*/
|
|
565
|
+
export declare const LevoForm: React.FC<ILevoFormProps>;
|
|
566
|
+
|
|
567
|
+
/**
|
|
568
|
+
* Mounts the Levo client + insights for a generated site. Rendered once from the
|
|
569
|
+
* scaffold's `__root` (via the env-reading shim); SSR-safe — construction guards its
|
|
570
|
+
* window/document reads, and `insights.init()` (client-side only by contract) runs in
|
|
571
|
+
* an effect after mount.
|
|
572
|
+
*/
|
|
573
|
+
export declare const LevoSiteProvider: React.FC<{
|
|
574
|
+
config?: ILevoSiteConfig;
|
|
575
|
+
children: React.ReactNode;
|
|
576
|
+
}>;
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* Renders a page's metadata as document tags. Pages include it anywhere in their JSX —
|
|
580
|
+
* React 19 hoists <title>/<meta>/<link> into <head> (SSR too); scripts render in place
|
|
581
|
+
* (see the file header caveat). The studio wires this automatically on a page's first
|
|
582
|
+
* meta save:
|
|
583
|
+
*
|
|
584
|
+
* import meta from "./about.meta";
|
|
585
|
+
* import siteMeta from "./_site.meta";
|
|
586
|
+
* import { PageHead } from "../lib/pageHead";
|
|
587
|
+
* …
|
|
588
|
+
* <PageHead meta={meta} site={siteMeta} />
|
|
589
|
+
*/
|
|
590
|
+
export declare function PageHead({ meta, site }: {
|
|
591
|
+
meta?: IPageMeta;
|
|
592
|
+
site?: ISiteMeta;
|
|
593
|
+
}): JSX.Element;
|
|
594
|
+
|
|
595
|
+
/**
|
|
596
|
+
* Compose one page's document metadata from its sidecar + the site defaults. Page
|
|
597
|
+
* values win per-FIELD (an empty page og.title still inherits the site og.title).
|
|
598
|
+
* The object shape doubles as a TanStack Start route `head()` result for when the
|
|
599
|
+
* scaffold wires routes directly.
|
|
600
|
+
*/
|
|
601
|
+
export declare const pageHead: (meta?: IPageMeta, site?: ISiteMeta) => IComposedHead;
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* Tolerant extraction of `<script>` / `<meta>` / `<link>` tags from a raw head snippet.
|
|
605
|
+
* Unsupported tags are DROPPED (documented v1 limitation) — silently at runtime; the
|
|
606
|
+
* editor warns at save time.
|
|
607
|
+
*/
|
|
608
|
+
export declare const parseRawHead: (raw: string) => IComposedHead;
|
|
609
|
+
|
|
610
|
+
/**
|
|
611
|
+
* Prefetch every binding a page declares into the router's QueryClient — call it (awaited)
|
|
612
|
+
* from the route `loader` so SSR renders fully-populated HTML. Builds its own client from
|
|
613
|
+
* the site config (loaders run outside React, so `useLevoSite` isn't available). Record
|
|
614
|
+
* bindings pull their slug from the route `params` (`$slug`). Resilient: a single failed
|
|
615
|
+
* source resolves to null so it doesn't blank the whole page — the hook surfaces that
|
|
616
|
+
* binding's error while the rest render.
|
|
617
|
+
*
|
|
618
|
+
* Returns the fetched values keyed by source key (records as the record object, lists as
|
|
619
|
+
* `{data, meta}`). The route loader returns this map, making it the route's `loaderData` —
|
|
620
|
+
* which `levoHead`'s dynamic config reads for per-record titles/descriptions/share images.
|
|
621
|
+
*/
|
|
622
|
+
export declare const prefetchLevoSources: ({ queryClient, config, sources, params, }: {
|
|
623
|
+
queryClient: IQueryClientLike;
|
|
624
|
+
/** Site env config — same object the LevoSiteProvider receives. */
|
|
625
|
+
config: ILevoSiteConfig | undefined;
|
|
626
|
+
/** The page's `dataSources` export (undefined = page has none). */
|
|
627
|
+
sources: ILevoDataSources | undefined;
|
|
628
|
+
/** Route params; record bindings read `params.slug`. */
|
|
629
|
+
params?: Record<string, string>;
|
|
630
|
+
}) => Promise<Record<string, unknown>>;
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* The site's Levo client config from its `site.json`. The platform stamps that file at
|
|
634
|
+
* provision and re-syncs it on settings saves; the `?.` on `levo` is load-bearing — a
|
|
635
|
+
* site provisioned before the block shipped degrades to an inert client, never a crash.
|
|
636
|
+
*/
|
|
637
|
+
export declare const siteConfigFromJson: (site: ISiteJson) => ILevoSiteConfig;
|
|
638
|
+
|
|
639
|
+
/**
|
|
640
|
+
* Load a collection's SCHEMA so `LevoForm` can render its fields. Like the other hooks the
|
|
641
|
+
* config is a static literal (the editor binding); it reads the warm cache the route loader
|
|
642
|
+
* filled via `prefetchLevoSources`, so a form declared in `dataSources` renders SSR with no
|
|
643
|
+
* fetch flash. `schema` is null until loaded and on an unwired site.
|
|
644
|
+
*/
|
|
645
|
+
export declare const useLevoForm: (config: ILevoFormConfig) => ILevoFormResult;
|
|
646
|
+
|
|
647
|
+
/** The site's insights (analytics/track), or `null` on an unwired site. */
|
|
648
|
+
export declare const useLevoInsights: () => ILevoInsights | null;
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* Render ONE record by slug — a detail page. `slug` is a RUNTIME arg (the page's route
|
|
652
|
+
* param), kept OUT of the config literal so the binding stays static and editable. No slug
|
|
653
|
+
* (or unwired site) → inert. `data` null after load = not found: render a friendly fallback.
|
|
654
|
+
*/
|
|
655
|
+
export declare const useLevoRecord: <T = Record<string, unknown>>(config: ILevoRecordConfig, slug: string | undefined) => ILevoRecordResult<T>;
|
|
656
|
+
|
|
657
|
+
/**
|
|
658
|
+
* The site's Levo client, or `null` when the site isn't wired to a Levo backend yet
|
|
659
|
+
* (no `apiUrl` in config — e.g. env not injected at provision). Consumers no-op on null.
|
|
660
|
+
*
|
|
661
|
+
* Explicit return type on purpose: inference would inline core-internal names
|
|
662
|
+
* (`IPageContext`) that the rolled-up d.ts doesn't export → TS4023 on declaration emit.
|
|
663
|
+
*/
|
|
664
|
+
export declare const useLevoSite: () => ILevoClient | null;
|
|
665
|
+
|
|
666
|
+
/**
|
|
667
|
+
* Render a LIST of platform content. The config is a static literal (the editor rewrites
|
|
668
|
+
* it). Reads the router QueryClient: if the route loader prefetched this binding, the first
|
|
669
|
+
* render has data (SSR ships it); otherwise it fetches client-side. Always render a loading
|
|
670
|
+
* and an empty state — `data` is null before the first load and on unwired sites.
|
|
671
|
+
*/
|
|
672
|
+
export declare const useLevoSource: <T = Record<string, unknown>>(config: ILevoSourceConfig) => ILevoSourceResult<T>;
|
|
673
|
+
|
|
674
|
+
export { }
|