@levo-so/site-runtime 0.2.2 → 0.3.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/CollectionField-CzS-34zx.js +270 -0
- package/DateTimeWidget-C1jHOtz7.js +255 -0
- package/Dialog-CzVhHLEY.js +145 -0
- package/KBChatWidget-D7F9LRwI.js +1078 -0
- package/{PhoneWidget-vtDO9CFq.js → PhoneWidget-_nw97rkI.js} +5 -5
- package/{Popover-B76-bN-a.js → Popover-q5dL7y0W.js} +1 -1
- package/PopupRenderer-Bncp54gB-DuCULkBK.js +3514 -0
- package/RichTextWidget-D-mGlES0.js +758 -0
- package/ThemeProvider-BQmIB5tr.js +116 -0
- package/Tooltip-BIgrpetu.js +67 -0
- package/VerifyButton-BkP98H17.js +191 -0
- package/dist-CJknSbJK.js +80 -0
- package/dist-DBbiX2ST.js +3556 -0
- package/es-iCqKQf1c.js +455 -0
- package/index.d.ts +201 -13
- package/index.js +976 -4246
- package/inlineBaseTheme-DS-AfUHi.js +9 -0
- package/inlineCollectionTheme-D2w17LHX.js +86 -0
- package/kbChat-AUJxjURc.js +168 -0
- package/nodeAlignment-Cn6xNtOP.js +166 -0
- package/package.json +15 -3
- package/pillChrome-AhXOWXIb.js +20 -0
- package/popups.d.ts +47 -0
- package/popups.js +5 -0
- package/rolldown-runtime-CAFD8bLK.js +11 -0
- package/styles.css +1 -1
- package/theme.cssm-2YTdd8Yh.js +15 -0
- package/DateTimeWidget-CARoq7bQ.js +0 -254
- package/RichTextWidget-CafZBEKI.js +0 -912
- package/ThemeProvider-Cm2jJC7a.js +0 -381
- package/Tooltip-Bx-BfR7T.js +0 -78
- package/VerifyButton-D1Mwk04d.js +0 -299
- /package/{CollectionInput-5QMoXahu.js → CollectionInput-B1qV4QEH.js} +0 -0
package/index.d.ts
CHANGED
|
@@ -4,6 +4,27 @@ import { ILevoInsights } from '@levo-so/insights';
|
|
|
4
4
|
import { JSX } from 'react/jsx-runtime';
|
|
5
5
|
import { LevoQuery } from '@levo-so/core';
|
|
6
6
|
|
|
7
|
+
/** Color-mode preference. `system` follows the OS `prefers-color-scheme`. */
|
|
8
|
+
export declare type ColorMode = "dark" | "light" | "system";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Site-wide light/dark color mode for a generated Studio site. This does NOT define the
|
|
12
|
+
* theme (colors/tokens live in `theme.css`) — it only toggles a `light`/`dark` class on
|
|
13
|
+
* `<html>`; `theme.css` keys its dark token overrides off `.dark` (via `@custom-variant
|
|
14
|
+
* dark`), so every semantic utility (`bg-page`, `text-ink`, …) flips with zero page changes.
|
|
15
|
+
*
|
|
16
|
+
* Mounted once from the scaffold's `__root` (wrapping the page) — deliberately NOT from
|
|
17
|
+
* `LevoSiteProvider`: that one returns bare children on an unwired site (no `api_url`), and
|
|
18
|
+
* light/dark can't depend on whether a backend is stamped. `defaultMode` is also a per-site
|
|
19
|
+
* design decision the generated site owns, not something the runtime should pick.
|
|
20
|
+
*
|
|
21
|
+
* SSR-safe: the initial
|
|
22
|
+
* render uses `defaultMode` and emits only the `ScriptOnce` guard; the stored preference is
|
|
23
|
+
* read and applied post-mount. Put `suppressHydrationWarning` on `<html>` since the guard
|
|
24
|
+
* mutates it before hydration.
|
|
25
|
+
*/
|
|
26
|
+
export declare const ColorModeProvider: React.FC<IColorModeProviderProps>;
|
|
27
|
+
|
|
7
28
|
/**
|
|
8
29
|
* Build the site's `levoHead` from its `site.json`. Each route passes its OWN imported
|
|
9
30
|
* meta file (`head: levoHead(meta)`) — no path matching anywhere; the import IS the
|
|
@@ -24,8 +45,11 @@ export declare const createLevoHead: (site: ISiteJson) => (meta?: IPlatformMetaF
|
|
|
24
45
|
* `levoHead`'s dynamic config reads for per-record heads. An empty `dataSources` ({})
|
|
25
46
|
* resolves to an empty map. Context is typed structurally (just `queryClient`) so the
|
|
26
47
|
* scaffold's router types never enter the package.
|
|
48
|
+
*
|
|
49
|
+
* Takes the raw `site.json` — same single input as `createLevoHead` and
|
|
50
|
+
* `LevoSiteProvider` — and derives the client config itself.
|
|
27
51
|
*/
|
|
28
|
-
export declare const createLevoLoader: (
|
|
52
|
+
export declare const createLevoLoader: (site: ISiteJson) => (sources: ILevoDataSources) => ({ context, params, }: {
|
|
29
53
|
context: {
|
|
30
54
|
queryClient: IQueryClientLike;
|
|
31
55
|
};
|
|
@@ -41,6 +65,27 @@ export declare const createLevoLoader: (config: ILevoSiteConfig) => (sources: IL
|
|
|
41
65
|
*/
|
|
42
66
|
export declare const createSiteClient: (config?: ILevoSiteConfig) => ILevoClient | null;
|
|
43
67
|
|
|
68
|
+
export declare interface IColorModeProviderProps {
|
|
69
|
+
children: React.ReactNode;
|
|
70
|
+
/** Fallback when nothing is stored yet. */
|
|
71
|
+
defaultMode?: ColorMode;
|
|
72
|
+
/** localStorage key the preference is persisted under. */
|
|
73
|
+
storageKey?: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export declare interface IColorModeState {
|
|
77
|
+
/** The stored preference (`system` before it resolves to light/dark). */
|
|
78
|
+
mode: ColorMode;
|
|
79
|
+
/**
|
|
80
|
+
* The mode actually in effect — `system` already resolved against the OS. Use this to
|
|
81
|
+
* render a two-state toggle so no site has to re-implement the media query. Before mount
|
|
82
|
+
* it reflects `defaultMode` (with `system` read as light), matching what the server sent.
|
|
83
|
+
*/
|
|
84
|
+
resolvedMode: ResolvedColorMode;
|
|
85
|
+
/** Persist a new preference and re-apply it immediately. */
|
|
86
|
+
setMode: (mode: ColorMode) => void;
|
|
87
|
+
}
|
|
88
|
+
|
|
44
89
|
export declare interface IComposedHead {
|
|
45
90
|
meta: IHeadEntry[];
|
|
46
91
|
links: IHeadEntry[];
|
|
@@ -96,6 +141,16 @@ export declare type IEditorToPreview = {
|
|
|
96
141
|
} | {
|
|
97
142
|
type: "clear-staged";
|
|
98
143
|
stageId?: string;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Rasterize the CURRENTLY selected element to a PNG data URL (reply:
|
|
147
|
+
* `capture-result`). Selection-state based — no locator round-trip — so it also
|
|
148
|
+
* works for unstamped elements and never suffers stale-locator misses. The editor
|
|
149
|
+
* attaches the result to the chat so the model can see what the user selected.
|
|
150
|
+
*/
|
|
151
|
+
| {
|
|
152
|
+
type: "capture-selected";
|
|
153
|
+
requestId: string;
|
|
99
154
|
};
|
|
100
155
|
|
|
101
156
|
/** A nested element locator — `file:line:col` + occurrence index. Never top-level. */
|
|
@@ -136,6 +191,11 @@ export declare interface ILayersNode {
|
|
|
136
191
|
children: ILayersNode[];
|
|
137
192
|
}
|
|
138
193
|
|
|
194
|
+
export declare interface ILevoChatProps {
|
|
195
|
+
/** The site's root `site.json` — all chat props are derived from it. */
|
|
196
|
+
site: ISiteJson;
|
|
197
|
+
}
|
|
198
|
+
|
|
139
199
|
/** The shape a page exports so its route loader can prefetch every binding it renders. */
|
|
140
200
|
export declare type ILevoDataSources = Record<string, ILevoSourceDef>;
|
|
141
201
|
|
|
@@ -231,6 +291,14 @@ declare interface ILevoFormTheme {
|
|
|
231
291
|
gap?: string;
|
|
232
292
|
}
|
|
233
293
|
|
|
294
|
+
export declare interface ILevoPopupsProps {
|
|
295
|
+
/**
|
|
296
|
+
* The site's id (`site.json` `id`) — scopes the active-popups fetch. Absent → the
|
|
297
|
+
* workspace-wide active popups are returned.
|
|
298
|
+
*/
|
|
299
|
+
siteId?: string;
|
|
300
|
+
}
|
|
301
|
+
|
|
234
302
|
/** A single-record binding — one collection record / blog post / event by `slug` (a detail page). */
|
|
235
303
|
export declare interface ILevoRecordConfig {
|
|
236
304
|
module: "collection" | "blog" | "event";
|
|
@@ -437,6 +505,37 @@ export declare type IPreviewToEditor = {
|
|
|
437
505
|
} | {
|
|
438
506
|
type: "highlight-miss";
|
|
439
507
|
element: IElementLocator;
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Reply to `capture-selected`. `dataUrl` is a `data:image/png;base64,…` render of the
|
|
511
|
+
* selected element, or null with `error` set ("no-selection", "capture-failed") —
|
|
512
|
+
* always sent, so the editor's pending request settles instead of timing out.
|
|
513
|
+
*/
|
|
514
|
+
| {
|
|
515
|
+
type: "capture-result";
|
|
516
|
+
requestId: string;
|
|
517
|
+
dataUrl: string | null;
|
|
518
|
+
error?: string;
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* A select-mode marquee drag finished. `rect` is the dragged area (viewport coords at
|
|
522
|
+
* capture time), `elements` the topmost source-stamped elements substantially inside
|
|
523
|
+
* it (capped — `truncated` set when over the cap), `dataUrl` a PNG render of exactly
|
|
524
|
+
* that area (null when rasterizing failed; the element list is still useful alone).
|
|
525
|
+
* Unlike `capture-selected` this is push-based: one drag = one deliberate intent, so
|
|
526
|
+
* the runtime captures immediately instead of waiting for an editor request.
|
|
527
|
+
*/
|
|
528
|
+
| {
|
|
529
|
+
type: "region-selected";
|
|
530
|
+
rect: {
|
|
531
|
+
x: number;
|
|
532
|
+
y: number;
|
|
533
|
+
width: number;
|
|
534
|
+
height: number;
|
|
535
|
+
};
|
|
536
|
+
elements: IRegionElement[];
|
|
537
|
+
truncated: boolean;
|
|
538
|
+
dataUrl: string | null;
|
|
440
539
|
};
|
|
441
540
|
|
|
442
541
|
/**
|
|
@@ -452,6 +551,20 @@ export declare interface IQueryClientLike {
|
|
|
452
551
|
}) => Promise<unknown>;
|
|
453
552
|
}
|
|
454
553
|
|
|
554
|
+
/**
|
|
555
|
+
* One element inside a drag-selected region — the lean sibling of
|
|
556
|
+
* {@link ISelectedElement}: just enough for the AI to locate it (`source`/`index`)
|
|
557
|
+
* and for the editor to label it. Only source-stamped elements make the list.
|
|
558
|
+
*/
|
|
559
|
+
export declare interface IRegionElement {
|
|
560
|
+
source: string;
|
|
561
|
+
index: number;
|
|
562
|
+
tag: string;
|
|
563
|
+
label: string;
|
|
564
|
+
/** Direct display text, truncated. Omitted for non-text containers. */
|
|
565
|
+
text?: string;
|
|
566
|
+
}
|
|
567
|
+
|
|
455
568
|
/** The element-selected payload — see `selectedPayload`. */
|
|
456
569
|
export declare interface ISelectedElement {
|
|
457
570
|
tag: string;
|
|
@@ -485,17 +598,47 @@ export declare interface ISelectedElement {
|
|
|
485
598
|
};
|
|
486
599
|
}
|
|
487
600
|
|
|
488
|
-
/**
|
|
601
|
+
/**
|
|
602
|
+
* The project's root `site.json` — the ONE input to the whole runtime. The platform stamps
|
|
603
|
+
* it at provision and re-syncs it on settings saves; the scaffold shim imports it and hands
|
|
604
|
+
* the same object to every factory (`createLevoHead`, `createLevoLoader`,
|
|
605
|
+
* `<LevoSiteProvider site>`).
|
|
606
|
+
*
|
|
607
|
+
* It lives in its own leaf module because four modules read it (client, scaffold, provider,
|
|
608
|
+
* chat) and every one of them sits at a different depth of the import graph — hanging the
|
|
609
|
+
* type off any of them makes the graph cyclic.
|
|
610
|
+
*
|
|
611
|
+
* Every field is optional on purpose: a site provisioned before a given block shipped is
|
|
612
|
+
* missing it entirely, and the runtime must degrade (inert client, hidden widget) rather
|
|
613
|
+
* than crash.
|
|
614
|
+
*/
|
|
489
615
|
export declare interface ISiteJson {
|
|
490
616
|
id?: string;
|
|
491
617
|
workspace_id?: string;
|
|
618
|
+
/** Site slug — tags the visitor-chat "Powered by" link's utm_source. */
|
|
619
|
+
slug?: string;
|
|
492
620
|
name?: string;
|
|
493
621
|
description?: string;
|
|
494
622
|
/** The site's live URL host (with or without protocol) — feeds auto-canonicals. */
|
|
495
623
|
domain?: string;
|
|
624
|
+
/**
|
|
625
|
+
* Favicon media object. Its `.location` becomes the site's `<link rel="icon">` and the
|
|
626
|
+
* visitor-chat header icon. Absent → the site keeps the starter's default `favicon.ico`.
|
|
627
|
+
*/
|
|
628
|
+
icon?: {
|
|
629
|
+
location?: string;
|
|
630
|
+
} | null;
|
|
496
631
|
settings?: {
|
|
497
632
|
head_code?: string;
|
|
498
633
|
};
|
|
634
|
+
/**
|
|
635
|
+
* Workspace feature flags stamped into the site. `branding` gates the visitor-chat
|
|
636
|
+
* "Powered by levo.so" attribution — same flag as the "Made with Levo" page badge.
|
|
637
|
+
* Absent (not yet stamped) → coerced false → attribution hidden (white-label-safe).
|
|
638
|
+
*/
|
|
639
|
+
feature_flag?: {
|
|
640
|
+
branding?: boolean;
|
|
641
|
+
};
|
|
499
642
|
levo?: {
|
|
500
643
|
api_url?: string;
|
|
501
644
|
insights_url?: string | null;
|
|
@@ -507,6 +650,11 @@ export declare interface ISiteJson {
|
|
|
507
650
|
export declare interface ISiteMeta extends IPageMeta {
|
|
508
651
|
/** "%s · Acme" — %s is the page title. Applied only when the page provides a title. */
|
|
509
652
|
titleTemplate?: string;
|
|
653
|
+
/**
|
|
654
|
+
* Favicon URL → `<link rel="icon">`. Site-level only (a per-page favicon isn't a thing),
|
|
655
|
+
* which is why it lives here rather than on `IPageMeta`.
|
|
656
|
+
*/
|
|
657
|
+
icon?: string;
|
|
510
658
|
}
|
|
511
659
|
|
|
512
660
|
export declare type IStagedEntry = IStagedStyleEntry | IStagedTextEntry | IStagedImageEntry;
|
|
@@ -544,13 +692,22 @@ export declare interface ITextChangedElement {
|
|
|
544
692
|
occurrences: number;
|
|
545
693
|
}
|
|
546
694
|
|
|
695
|
+
/**
|
|
696
|
+
* Drops the site's AI chat widget onto every page, wired from `site.json`. Mounted once
|
|
697
|
+
* from the scaffold's `__root` (via the `SiteChat` shim) alongside `<Inspector />`. Self-
|
|
698
|
+
* gates: renders nothing until the workspace resolves a servable active agent, so an
|
|
699
|
+
* unwired or agent-less site paints no launcher. `apiBaseUrl` is intentionally left at the
|
|
700
|
+
* KBChat default (the same-origin `/.levo` proxy) — the serving layer owns that route.
|
|
701
|
+
*/
|
|
702
|
+
export declare const LevoChat: React.FC<ILevoChatProps>;
|
|
703
|
+
|
|
547
704
|
/**
|
|
548
705
|
* Self-contained event registration widget for generated Studio v3 sites — ticket
|
|
549
706
|
* selection, coupons, attendee details, payment (Razorpay by default; Stripe Embedded
|
|
550
707
|
* Checkout when the booking API returns `provider: "stripe"`), and a booking confirmation.
|
|
551
708
|
*
|
|
552
709
|
* The AI drops this onto an event page and NEVER rebuilds the flow: it owns the entire
|
|
553
|
-
* booking + payment path against the Levo event API. The site client (`
|
|
710
|
+
* booking + payment path against the Levo event API. The site client (`useLevoClient`)
|
|
554
711
|
* auto-stamps the workspace on every request, so no auth/workspace wiring is needed.
|
|
555
712
|
* `external` turns it into a plain link out to a third-party ticketing URL.
|
|
556
713
|
*/
|
|
@@ -578,13 +735,32 @@ export declare const LevoEventRegister: ({ eventID, title, external, buttonText,
|
|
|
578
735
|
export declare const LevoForm: React.FC<ILevoFormProps>;
|
|
579
736
|
|
|
580
737
|
/**
|
|
581
|
-
* Mounts the
|
|
582
|
-
*
|
|
583
|
-
*
|
|
584
|
-
*
|
|
738
|
+
* Mounts the site's popups, wired from `site.json`. Rendered once from the scaffold's
|
|
739
|
+
* `__root` (via the `SitePopups` shim), inside `<LevoSiteProvider>` — `PopupLoader` reads
|
|
740
|
+
* the Levo client through `useLevo()`, which that provider mounts. The library handles
|
|
741
|
+
* everything else: it fetches active popups, evaluates page/referrer targeting against the
|
|
742
|
+
* current URL, lazy-loads the renderer only when popups exist, and self-hides otherwise.
|
|
743
|
+
*
|
|
744
|
+
* No `pageId` is threaded: that is a studio DB page id with no equivalent in a code-routed
|
|
745
|
+
* site, so page-bound rules don't apply here — site-wide and URL-path targeting (the
|
|
746
|
+
* `is_all_pages` / `contains` / `begins_with` matchers) do.
|
|
747
|
+
*/
|
|
748
|
+
export declare const LevoPopups: React.FC<ILevoPopupsProps>;
|
|
749
|
+
|
|
750
|
+
/**
|
|
751
|
+
* Mounts the Levo client + insights for a generated site, and the site-wide overlays that
|
|
752
|
+
* ride on top of it (AI chat + popups). Rendered once from the scaffold's `__root` (via the
|
|
753
|
+
* env-reading shim); SSR-safe — construction guards its window/document reads, and
|
|
754
|
+
* `insights.init()` (client-side only by contract) runs in an effect after mount.
|
|
755
|
+
*
|
|
756
|
+
* Takes the raw `site.json` and derives everything from it: the data client's config, and
|
|
757
|
+
* the site-wide overlays' metadata (workspace/name/slug/icon/branding for chat, id for
|
|
758
|
+
* popups). The overlays render only on a wired site, so they always have a client in scope;
|
|
759
|
+
* each is client-only, lazy, and self-hiding, so they add nothing to the initial page. Omit
|
|
760
|
+
* `site` to mount a bare (null) client context.
|
|
585
761
|
*/
|
|
586
762
|
export declare const LevoSiteProvider: React.FC<{
|
|
587
|
-
|
|
763
|
+
site?: ISiteJson;
|
|
588
764
|
children: React.ReactNode;
|
|
589
765
|
}>;
|
|
590
766
|
|
|
@@ -623,7 +799,7 @@ export declare const parseRawHead: (raw: string) => IComposedHead;
|
|
|
623
799
|
/**
|
|
624
800
|
* Prefetch every binding a page declares into the router's QueryClient — call it (awaited)
|
|
625
801
|
* from the route `loader` so SSR renders fully-populated HTML. Builds its own client from
|
|
626
|
-
* the site config (loaders run outside React, so
|
|
802
|
+
* the site config (loaders run outside React, so the client context isn't available). Record
|
|
627
803
|
* bindings pull their slug from the route `params` (`$slug`). Resilient: a single failed
|
|
628
804
|
* source resolves to null so it doesn't blank the whole page — the hook surfaces that
|
|
629
805
|
* binding's error while the rest render.
|
|
@@ -642,13 +818,21 @@ export declare const prefetchLevoSources: ({ queryClient, config, sources, param
|
|
|
642
818
|
params?: Record<string, string>;
|
|
643
819
|
}) => Promise<Record<string, unknown>>;
|
|
644
820
|
|
|
821
|
+
/** What `system` resolves to — the class actually on `<html>`. */
|
|
822
|
+
export declare type ResolvedColorMode = "dark" | "light";
|
|
823
|
+
|
|
645
824
|
/**
|
|
646
|
-
* The site's Levo client config from its `site.json
|
|
647
|
-
*
|
|
648
|
-
*
|
|
825
|
+
* The site's Levo client config from its `site.json` — the only place that mapping lives, so
|
|
826
|
+
* the provider and the SSR route loader can't drift apart.
|
|
827
|
+
*
|
|
828
|
+
* The `?.` on `levo` is load-bearing: a site provisioned before the block shipped degrades to
|
|
829
|
+
* an inert client, never a crash.
|
|
649
830
|
*/
|
|
650
831
|
export declare const siteConfigFromJson: (site: ISiteJson) => ILevoSiteConfig;
|
|
651
832
|
|
|
833
|
+
/** Read/set the current color mode. Throws outside a `<ColorModeProvider>`. */
|
|
834
|
+
export declare function useColorMode(): IColorModeState;
|
|
835
|
+
|
|
652
836
|
/**
|
|
653
837
|
* Load a collection's SCHEMA so `LevoForm` can render its fields. Like the other hooks the
|
|
654
838
|
* config is a static literal (the editor binding); it reads the warm cache the route loader
|
|
@@ -669,7 +853,11 @@ export declare const useLevoRecord: <T = Record<string, unknown>>(config: ILevoR
|
|
|
669
853
|
|
|
670
854
|
/**
|
|
671
855
|
* The site's Levo client, or `null` when the site isn't wired to a Levo backend yet
|
|
672
|
-
* (no `
|
|
856
|
+
* (no `api_url` in `site.json` — e.g. not stamped at provision). Consumers no-op on null.
|
|
857
|
+
*
|
|
858
|
+
* Site-facing alias only. This package's own components call `@levo-so/react`'s
|
|
859
|
+
* `useLevoClient()` directly so that nothing internal imports THIS module — which keeps the
|
|
860
|
+
* provider, and the chat/popup widgets it mounts, off the SSR route-loader's import path.
|
|
673
861
|
*
|
|
674
862
|
* Explicit return type on purpose: inference would inline core-internal names
|
|
675
863
|
* (`IPageContext`) that the rolled-up d.ts doesn't export → TS4023 on declaration emit.
|