@blinkk/root-cms 3.0.5 → 3.1.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/README.md +77 -0
- package/dist/app.js +7 -4
- package/dist/browser-client/browser-client.d.ts +148 -0
- package/dist/browser-client/embed-window.d.ts +66 -0
- package/dist/browser-client/emitter.d.ts +11 -0
- package/dist/browser-client.js +377 -0
- package/dist/{chunk-RXWDB3K4.js → chunk-4VZTYUQ7.js} +1 -1
- package/dist/{chunk-N4K6ICFR.js → chunk-AFBSITEO.js} +4 -6
- package/dist/{chunk-PNLLZXVY.js → chunk-AJDMNTZQ.js} +2 -2
- package/dist/{chunk-VSPPZPMP.js → chunk-GXV4UQ6Z.js} +15 -11
- package/dist/chunk-J72JK4KR.js +8 -0
- package/dist/cli.js +2 -1
- package/dist/client.js +2 -1
- package/dist/core/client.d.ts +5 -0
- package/dist/core/plugin.d.ts +17 -0
- package/dist/core.js +4 -2
- package/dist/functions.js +4 -3
- package/dist/plugin.js +16 -4
- package/dist/shared/embed-protocol.d.ts +72 -0
- package/dist/ui/AIPage-EL6DQYII.js +1 -0
- package/dist/ui/AssetsPage-5S6PNMF6.js +1 -0
- package/dist/ui/CollectionPage-CU3VDEXA.js +1 -0
- package/dist/ui/ComparePage-FTZLYO2O.js +1 -0
- package/dist/ui/DataPage-XIXFKXDN.js +1 -0
- package/dist/ui/DataSourcePage-ORIEQH3Y.js +1 -0
- package/dist/ui/DocTranslationsPage-4OVBIPSG.js +1 -0
- package/dist/ui/DocumentPage-3JPFJF3E.js +1 -0
- package/dist/ui/EditDataSourcePage-HIGZZQJC.js +1 -0
- package/dist/ui/EditReleasePage-KUHBU2HQ.js +1 -0
- package/dist/ui/EmbeddedAIPage-CJWZE5FC.js +1 -0
- package/dist/ui/EmbeddedDocumentPage-6XQHYIAO.js +1 -0
- package/dist/ui/{ImageEditorDialog-4H665KK2.js → ImageEditorDialog-GGS4VFEA.js} +2 -2
- package/dist/ui/LogsPage-4DVGYXZY.js +1 -0
- package/dist/ui/NewDataSourcePage-7TUUE6ZL.js +1 -0
- package/dist/ui/NewReleasePage-6UT36HDW.js +1 -0
- package/dist/ui/NotFoundPage-AW6UC6II.js +1 -0
- package/dist/ui/ProjectPage-US5FJGFK.js +1 -0
- package/dist/ui/ReleasePage-W2R3DIFX.js +1 -0
- package/dist/ui/ReleasesPage-HBBUGE7D.js +1 -0
- package/dist/ui/SettingsPage-7JQQILUV.js +1 -0
- package/dist/ui/SidebarToolsPage-MIYXKHF2.js +1 -0
- package/dist/ui/TaskPage-JYUQEGRB.js +1 -0
- package/dist/ui/TasksPage-4VFQF243.js +1 -0
- package/dist/ui/TranslationsArbPage-AJLM5VSD.js +2 -0
- package/dist/ui/TranslationsEditPage-RTTGTIGI.js +1 -0
- package/dist/ui/{TranslationsPage-WIDVSTYF.js → TranslationsPage-HPYAJQ4Q.js} +31 -31
- package/dist/ui/{ai-tools-5E5ELLZX.js → ai-tools-4DWMFQS6.js} +1 -1
- package/dist/ui/{chunk-JYFLU7DM.js → chunk-2KSMCQ6H.js} +2 -2
- package/dist/ui/{chunk-HKINZLMW.js → chunk-344GZOGG.js} +45 -45
- package/dist/ui/{chunk-CGCKJFL4.js → chunk-3E6CASIN.js} +1 -1
- package/dist/ui/chunk-3T4ZWQR4.js +7 -0
- package/dist/ui/chunk-4ISFTE2G.js +5 -0
- package/dist/ui/chunk-5AVRMJVW.js +1 -0
- package/dist/ui/chunk-764W6634.js +1 -0
- package/dist/ui/chunk-76ZGLKLT.js +1 -0
- package/dist/ui/{chunk-SKEP5WYH.js → chunk-7SK47HHZ.js} +3 -3
- package/dist/ui/chunk-AZCGXQTL.js +1 -0
- package/dist/ui/{chunk-W3BJ2EZX.js → chunk-B6M55OFE.js} +1 -1
- package/dist/ui/{chunk-KYDOSLTO.js → chunk-CAY5NM4Z.js} +1 -1
- package/dist/ui/{chunk-4KE2SZKH.js → chunk-D3UIZHRK.js} +1 -1
- package/dist/ui/chunk-E76ECIOX.js +81 -0
- package/dist/ui/chunk-FBSBL476.js +1 -0
- package/dist/ui/chunk-FFHV5S6A.js +1 -0
- package/dist/ui/{chunk-X2WHBGTP.js → chunk-FJLNXXE3.js} +1 -1
- package/dist/ui/chunk-FSVNOZ6F.js +1 -0
- package/dist/ui/{chunk-BZIRGB4W.js → chunk-GDXNSFLE.js} +1 -1
- package/dist/ui/{chunk-C5NH23G4.js → chunk-GQ5IRK43.js} +1 -1
- package/dist/ui/{chunk-DEGMKEHP.js → chunk-GU24U5RM.js} +1 -1
- package/dist/ui/{chunk-HRGYNHZ3.js → chunk-HARRKJFZ.js} +1 -1
- package/dist/ui/{chunk-PHBMVORG.js → chunk-HO3W4RVG.js} +1 -1
- package/dist/ui/{chunk-62UWGWON.js → chunk-J5E457OI.js} +1 -1
- package/dist/ui/{chunk-W3HIZQ4Z.js → chunk-JS6TK4OP.js} +1 -1
- package/dist/ui/{chunk-54DVDYU6.js → chunk-JTIQBW33.js} +1 -1
- package/dist/ui/{chunk-ORXEMIQC.js → chunk-KRNQ6L35.js} +1 -1
- package/dist/ui/chunk-LROR6N3B.js +7 -0
- package/dist/ui/{chunk-NZHF733K.js.LEGAL.txt → chunk-LROR6N3B.js.LEGAL.txt} +6 -1
- package/dist/ui/{chunk-E2RCCK2T.js → chunk-M3T56ZRP.js} +1 -1
- package/dist/ui/chunk-MXGHX55S.js +141 -0
- package/dist/ui/{chunk-KFAZBEPV.js → chunk-MZTOPPWQ.js} +1 -1
- package/dist/ui/{chunk-JHBAMPGB.js → chunk-N3JSLTMV.js} +1 -1
- package/dist/ui/{chunk-L4RHGQUG.js → chunk-NSOTG64N.js} +1 -1
- package/dist/ui/{chunk-HLMBCVRX.js → chunk-O5P3CPJ4.js} +1 -1
- package/dist/ui/chunk-OWQL5DVE.js +1 -0
- package/dist/ui/{chunk-P3NETZZP.js → chunk-OXVYTSIZ.js} +1 -1
- package/dist/ui/chunk-P2Z66DHV.js +1 -0
- package/dist/ui/chunk-QEE7XS6O.js +1 -0
- package/dist/ui/chunk-QHJOTXYB.js +1 -0
- package/dist/ui/{chunk-3IYZCUPI.js → chunk-R6B3W5AJ.js} +1 -1
- package/dist/ui/{chunk-QGBR3J2Y.js → chunk-RAXWL656.js} +1 -1
- package/dist/ui/chunk-SRX7EWL4.js +1 -0
- package/dist/ui/chunk-TDUBSLEC.js +1 -0
- package/dist/ui/chunk-TFB3VGWP.js +1 -0
- package/dist/ui/{chunk-767BAQ53.js → chunk-U7PWJV6F.js} +1 -1
- package/dist/ui/{chunk-PWKJDYE2.js → chunk-UUVAD4U4.js} +1 -1
- package/dist/ui/chunk-V4CTOC6E.js +1 -0
- package/dist/ui/{chunk-EGEB6N4J.js → chunk-VD6G5NV4.js} +11 -11
- package/dist/ui/chunk-W5DOO6ID.js +1 -0
- package/dist/ui/{chunk-HHMG665Z.js → chunk-WFQU7V3W.js} +1 -1
- package/dist/ui/{chunk-SQRKKWRG.js → chunk-WKF7CSWS.js} +1 -1
- package/dist/ui/{chunk-4W73RW5I.js → chunk-WXT7LTQM.js} +1 -1
- package/dist/ui/{chunk-VMT7JFAM.js → chunk-XT5FNJCX.js} +1 -1
- package/dist/ui/chunk-YLSRRNSE.js +1 -0
- package/dist/ui/chunk-ZN2Y5OUF.js +3 -0
- package/dist/ui/gcs-ECSDFCIU.js +1 -0
- package/dist/ui/ui.css +1 -1
- package/dist/ui/ui.js +1 -1
- package/package.json +14 -10
- package/dist/ui/AIPage-F3NNYM5E.js +0 -1
- package/dist/ui/AssetsPage-DZQHAENZ.js +0 -1
- package/dist/ui/CollectionPage-WVVG62NR.js +0 -1
- package/dist/ui/ComparePage-CRDHP45W.js +0 -1
- package/dist/ui/DataPage-WMLBCPGF.js +0 -1
- package/dist/ui/DataSourcePage-POZAQFPU.js +0 -1
- package/dist/ui/DocTranslationsPage-UR5D2RF2.js +0 -1
- package/dist/ui/DocumentPage-SQ7ROBMC.js +0 -1
- package/dist/ui/EditDataSourcePage-PUA2AJ4C.js +0 -1
- package/dist/ui/EditReleasePage-CENP46EO.js +0 -1
- package/dist/ui/LogsPage-FZRN6MBJ.js +0 -1
- package/dist/ui/NewDataSourcePage-FTILYFJY.js +0 -1
- package/dist/ui/NewReleasePage-MHJC66KK.js +0 -1
- package/dist/ui/NotFoundPage-EP2OE4JV.js +0 -1
- package/dist/ui/ProjectPage-6J7QCG75.js +0 -1
- package/dist/ui/ReleasePage-IZ3DNGT4.js +0 -1
- package/dist/ui/ReleasesPage-RWFOJ5VG.js +0 -1
- package/dist/ui/SettingsPage-M4SIDBTI.js +0 -1
- package/dist/ui/SidebarToolsPage-GAX3XJ7W.js +0 -1
- package/dist/ui/TaskPage-UCATTNZ5.js +0 -1
- package/dist/ui/TasksPage-4AQLQ4IT.js +0 -1
- package/dist/ui/TranslationsArbPage-JGQGATCS.js +0 -2
- package/dist/ui/TranslationsEditPage-7AGZGHKS.js +0 -1
- package/dist/ui/chunk-7MTDTPYB.js +0 -1
- package/dist/ui/chunk-7UIUAHC4.js +0 -1
- package/dist/ui/chunk-AEWL2RWR.js +0 -141
- package/dist/ui/chunk-AFWBSIPL.js +0 -1
- package/dist/ui/chunk-AL3TN2KI.js +0 -1
- package/dist/ui/chunk-DUJYIOLE.js +0 -5
- package/dist/ui/chunk-I6ICVKEC.js +0 -1
- package/dist/ui/chunk-JKCZGT6B.js +0 -1
- package/dist/ui/chunk-JZFTZ4X4.js +0 -87
- package/dist/ui/chunk-KKEWCXVV.js +0 -1
- package/dist/ui/chunk-NZHF733K.js +0 -7
- package/dist/ui/chunk-ONTGW2VA.js +0 -1
- package/dist/ui/chunk-P4U2LUTF.js +0 -1
- package/dist/ui/chunk-PJA7YP4A.js +0 -1
- package/dist/ui/chunk-RSVO46S3.js +0 -1
- package/dist/ui/chunk-TJBVMFNQ.js +0 -1
- package/dist/ui/chunk-XOQ3KDSR.js +0 -3
- package/dist/ui/chunk-YFA6U2CV.js +0 -1
- package/dist/ui/gcs-L33FIRZU.js +0 -1
- /package/dist/ui/{ImageEditorDialog-4H665KK2.js.LEGAL.txt → ImageEditorDialog-GGS4VFEA.js.LEGAL.txt} +0 -0
- /package/dist/ui/{chunk-SKEP5WYH.js.LEGAL.txt → chunk-7SK47HHZ.js.LEGAL.txt} +0 -0
- /package/dist/ui/{chunk-JZFTZ4X4.js.LEGAL.txt → chunk-E76ECIOX.js.LEGAL.txt} +0 -0
- /package/dist/ui/{chunk-AEWL2RWR.js.LEGAL.txt → chunk-MXGHX55S.js.LEGAL.txt} +0 -0
- /package/dist/ui/{chunk-EGEB6N4J.js.LEGAL.txt → chunk-VD6G5NV4.js.LEGAL.txt} +0 -0
- /package/dist/ui/{prerender-Q4YSDCPB.js → prerender-M47IWV5Q.js} +0 -0
package/README.md
CHANGED
|
@@ -92,3 +92,80 @@ This is convenient for granting access to a whole workspace, but be aware:
|
|
|
92
92
|
that grants access to anyone with a Google account.
|
|
93
93
|
- Prefer explicit per-email grants for `ADMIN` and `EDITOR`; reserve the
|
|
94
94
|
wildcard for `CONTRIBUTOR` or `VIEWER` if you use it at all.
|
|
95
|
+
|
|
96
|
+
# Embedding the CMS (`@blinkk/root-cms/browser-client`)
|
|
97
|
+
|
|
98
|
+
`@blinkk/root-cms/browser-client` is a dependency-free, framework-agnostic
|
|
99
|
+
browser library for embedding Root CMS into another site. It wraps the
|
|
100
|
+
underlying iframe/postMessage wiring behind a typed API, so the wire protocol
|
|
101
|
+
can evolve without breaking your integration.
|
|
102
|
+
|
|
103
|
+
For pop-up/iframe embedding (the doc editor and Root AI), the embedding page's
|
|
104
|
+
origin must be allowlisted in the CMS plugin config:
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
// root.config.ts
|
|
108
|
+
cmsPlugin({
|
|
109
|
+
// ...
|
|
110
|
+
allowedIframeOrigins: ['https://app.example.com'],
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Headless doc editor (pop-up or iframe)
|
|
115
|
+
|
|
116
|
+
Opens `/cms/embed/content/<collection>/<slug>`, a minimal version of the doc
|
|
117
|
+
editor with explicit (non-auto) saving. In `popup` mode, call from a user
|
|
118
|
+
gesture (e.g. a click handler) to avoid pop-up blockers. Closing the editor
|
|
119
|
+
discards unsaved changes.
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
import {RootCMSBrowserClient} from '@blinkk/root-cms/browser-client';
|
|
123
|
+
|
|
124
|
+
const root = new RootCMSBrowserClient({cmsOrigin: 'https://cms.example.com'});
|
|
125
|
+
|
|
126
|
+
const editor = root.openEditor('Pages/about', {
|
|
127
|
+
mode: 'popup', // or 'iframe' (pass `container`)
|
|
128
|
+
deeplink: 'hero.title', // optional: field to scroll to on load
|
|
129
|
+
});
|
|
130
|
+
editor.on('ready', () => console.log('editor loaded'));
|
|
131
|
+
editor.on('saved', () => location.reload());
|
|
132
|
+
editor.on('published', () => editor.closeAndReload());
|
|
133
|
+
editor.on('close', () => console.log('editor closed'));
|
|
134
|
+
editor.focusField('hero.image'); // scroll the editor to a field
|
|
135
|
+
editor.reload();
|
|
136
|
+
editor.close(); // or editor.closeAndReload()
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Headless Root AI (pop-up or iframe)
|
|
140
|
+
|
|
141
|
+
Opens `/cms/embed/ai`, the compact Root AI chat, optionally with a doc as
|
|
142
|
+
context:
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
const ai = root.openRootAI({docId: 'Pages/about', mode: 'popup'});
|
|
146
|
+
ai.on('ready', () => console.log('chat loaded'));
|
|
147
|
+
ai.close();
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Field focus from the in-CMS preview pane ("click to edit")
|
|
151
|
+
|
|
152
|
+
When your site is rendered inside the CMS preview pane, use a
|
|
153
|
+
`PreviewConnection` to focus editor fields from the page and to highlight page
|
|
154
|
+
nodes when the editor requests it. The preview pane is same-origin with the
|
|
155
|
+
CMS, so no config is needed and the connection is inert when the page is not
|
|
156
|
+
embedded:
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
import {RootCMSBrowserClient} from '@blinkk/root-cms/browser-client';
|
|
160
|
+
|
|
161
|
+
const preview = RootCMSBrowserClient.connectPreview();
|
|
162
|
+
if (preview.isEmbedded) {
|
|
163
|
+
// "Click to edit": focus the field in the doc editor.
|
|
164
|
+
el.addEventListener('click', () => preview.focusField('hero.title'));
|
|
165
|
+
// Highlight page nodes when the editor hovers/focuses a field.
|
|
166
|
+
preview.on('highlight', ({deepKey, scroll}) => {
|
|
167
|
+
clearHighlights();
|
|
168
|
+
if (deepKey) highlightNode(deepKey, {scroll});
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
```
|
package/dist/app.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getServerVersion,
|
|
3
3
|
serializeAiConfig
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
6
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-GXV4UQ6Z.js";
|
|
5
|
+
import "./chunk-4VZTYUQ7.js";
|
|
6
|
+
import "./chunk-AFBSITEO.js";
|
|
7
|
+
import "./chunk-J72JK4KR.js";
|
|
7
8
|
import {
|
|
8
9
|
getCollectionSchema,
|
|
9
10
|
getProjectSchemas
|
|
@@ -149,7 +150,9 @@ async function renderApp(req, res, options) {
|
|
|
149
150
|
hasImport: isFunction(t.onImport),
|
|
150
151
|
hasExport: isFunction(t.onExport)
|
|
151
152
|
})),
|
|
152
|
-
defaultOneOfVariant: cmsConfig.defaultOneOfVariant || "dropdown"
|
|
153
|
+
defaultOneOfVariant: cmsConfig.defaultOneOfVariant || "dropdown",
|
|
154
|
+
excludeLocalesFromTranslations: cmsConfig.excludeLocalesFromTranslations || [],
|
|
155
|
+
allowedIframeOrigins: cmsConfig.allowedIframeOrigins || []
|
|
153
156
|
};
|
|
154
157
|
const projectName = cmsConfig.name || cmsConfig.id || "";
|
|
155
158
|
const title = getCmsTitle(projectName, cmsConfig.minimalBranding);
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser client for embedding Root CMS into another site, exported as
|
|
3
|
+
* `@blinkk/root-cms/browser-client`. Framework-agnostic and dependency-free.
|
|
4
|
+
*
|
|
5
|
+
* Covers three scenarios:
|
|
6
|
+
* - Opening the headless doc editor in a pop-up or iframe
|
|
7
|
+
* ({@link RootCMSBrowserClient.openEditor}).
|
|
8
|
+
* - Opening the headless Root AI chat in a pop-up or iframe
|
|
9
|
+
* ({@link RootCMSBrowserClient.openRootAI}).
|
|
10
|
+
* - Communicating with the doc editor from a site rendered inside the in-CMS
|
|
11
|
+
* preview pane ({@link RootCMSBrowserClient.connectPreview}).
|
|
12
|
+
*
|
|
13
|
+
* The first two require the embedding page's origin to be listed in the
|
|
14
|
+
* `allowedIframeOrigins` option of the CMS plugin config.
|
|
15
|
+
*/
|
|
16
|
+
import { EmbedWindow, EmbedWindowEvents } from './embed-window.js';
|
|
17
|
+
export { SaveState } from '../shared/embed-protocol.js';
|
|
18
|
+
export type { HighlightNodeMessage, RootEmbedMessage, ScrollToDeeplinkMessage, } from '../shared/embed-protocol.js';
|
|
19
|
+
export type { EmbedWindowEvents } from './embed-window.js';
|
|
20
|
+
export interface RootCMSBrowserClientOptions {
|
|
21
|
+
/** Origin of the Root CMS server, e.g. `https://cms.example.com`. */
|
|
22
|
+
cmsOrigin: string;
|
|
23
|
+
}
|
|
24
|
+
export interface OpenEditorOptions {
|
|
25
|
+
/** How to open the editor. Defaults to `popup`. */
|
|
26
|
+
mode?: 'popup' | 'iframe';
|
|
27
|
+
/** Container the iframe is appended to. Required when mode is `iframe`. */
|
|
28
|
+
container?: HTMLElement;
|
|
29
|
+
/** Deep key of a field to scroll to on load, e.g. `hero.title`. */
|
|
30
|
+
deeplink?: string;
|
|
31
|
+
/** Pop-up window width. Defaults to 480. */
|
|
32
|
+
width?: number;
|
|
33
|
+
/** Pop-up window height. Defaults to 720. */
|
|
34
|
+
height?: number;
|
|
35
|
+
}
|
|
36
|
+
export interface OpenRootAIOptions extends Omit<OpenEditorOptions, 'deeplink'> {
|
|
37
|
+
/** Doc to provide as context to the AI chat, e.g. `Pages/about`. */
|
|
38
|
+
docId?: string;
|
|
39
|
+
}
|
|
40
|
+
/** Events emitted by {@link EmbeddedEditor}. */
|
|
41
|
+
export type EditorEvents = EmbedWindowEvents;
|
|
42
|
+
/** Events emitted by {@link EmbeddedAI}. */
|
|
43
|
+
export type AIEvents = Pick<EmbedWindowEvents, 'ready' | 'error' | 'close'>;
|
|
44
|
+
/** Event emitted when the doc editor requests a field highlight. */
|
|
45
|
+
export interface PreviewHighlightEvent {
|
|
46
|
+
/** Deep key of the field to highlight, or `null` to clear highlights. */
|
|
47
|
+
deepKey: string | null;
|
|
48
|
+
/** Whether to scroll the highlighted node into view. */
|
|
49
|
+
scroll: boolean;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Handle to a headless doc editor opened via {@link RootCMSBrowserClient.openEditor}.
|
|
53
|
+
*
|
|
54
|
+
* Note: the embedded editor does not autosave; closing it discards any
|
|
55
|
+
* unsaved changes.
|
|
56
|
+
*/
|
|
57
|
+
export declare class EmbeddedEditor {
|
|
58
|
+
/** The doc being edited, e.g. `Pages/about`. */
|
|
59
|
+
readonly docId: string;
|
|
60
|
+
private embedWindow;
|
|
61
|
+
constructor(docId: string, embedWindow: EmbedWindow);
|
|
62
|
+
/** The iframe element (iframe mode only). */
|
|
63
|
+
get element(): HTMLIFrameElement | null;
|
|
64
|
+
/** The pop-up window (popup mode only). */
|
|
65
|
+
get window(): Window | null;
|
|
66
|
+
/** Subscribes to an editor event. Returns an unsubscribe function. */
|
|
67
|
+
on<K extends keyof EditorEvents>(type: K, cb: (payload: EditorEvents[K]) => void): () => void;
|
|
68
|
+
/** Scrolls the editor to (focuses) a field, e.g. `hero.title`. */
|
|
69
|
+
focusField(deepKey: string): void;
|
|
70
|
+
/** Reloads the embedded editor. */
|
|
71
|
+
reload(): void;
|
|
72
|
+
/** Closes the embedded editor, discarding any unsaved changes. */
|
|
73
|
+
close(): void;
|
|
74
|
+
/** Closes the embedded editor and reloads the host page. */
|
|
75
|
+
closeAndReload(): void;
|
|
76
|
+
}
|
|
77
|
+
/** Handle to a headless Root AI chat opened via {@link RootCMSBrowserClient.openRootAI}. */
|
|
78
|
+
export declare class EmbeddedAI {
|
|
79
|
+
private embedWindow;
|
|
80
|
+
constructor(embedWindow: EmbedWindow);
|
|
81
|
+
/** The iframe element (iframe mode only). */
|
|
82
|
+
get element(): HTMLIFrameElement | null;
|
|
83
|
+
/** The pop-up window (popup mode only). */
|
|
84
|
+
get window(): Window | null;
|
|
85
|
+
/** Subscribes to an event. Returns an unsubscribe function. */
|
|
86
|
+
on<K extends keyof AIEvents>(type: K, cb: (payload: AIEvents[K]) => void): () => void;
|
|
87
|
+
/** Reloads the embedded chat (starts a fresh chat). */
|
|
88
|
+
reload(): void;
|
|
89
|
+
/** Closes the embedded chat. */
|
|
90
|
+
close(): void;
|
|
91
|
+
/** Closes the embedded chat and reloads the host page. */
|
|
92
|
+
closeAndReload(): void;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Channel between a site rendered inside the in-CMS preview pane and the doc
|
|
96
|
+
* editor that frames it. The preview iframe is same-origin with the CMS, so
|
|
97
|
+
* no configuration is needed. Safe to construct unconditionally: outside the
|
|
98
|
+
* preview pane the connection is inert (`isEmbedded` is false).
|
|
99
|
+
*/
|
|
100
|
+
export declare class PreviewConnection {
|
|
101
|
+
/** Whether this page is rendered inside the in-CMS preview pane. */
|
|
102
|
+
readonly isEmbedded: boolean;
|
|
103
|
+
private emitter;
|
|
104
|
+
constructor();
|
|
105
|
+
/**
|
|
106
|
+
* Requests that the doc editor scroll to (focus) a field, e.g.
|
|
107
|
+
* `hero.title`. Used to implement "click to edit".
|
|
108
|
+
*/
|
|
109
|
+
focusField(deepKey: string): void;
|
|
110
|
+
/**
|
|
111
|
+
* Subscribes to field highlight requests from the doc editor (sent when the
|
|
112
|
+
* user hovers/focuses a field). Returns an unsubscribe function.
|
|
113
|
+
*/
|
|
114
|
+
on(type: 'highlight', cb: (event: PreviewHighlightEvent) => void): () => void;
|
|
115
|
+
/** Removes the message listener and all subscriptions. */
|
|
116
|
+
disconnect(): void;
|
|
117
|
+
private onMessage;
|
|
118
|
+
}
|
|
119
|
+
/** Client for embedding Root CMS into another site. */
|
|
120
|
+
export declare class RootCMSBrowserClient {
|
|
121
|
+
/** Normalized origin of the Root CMS server. */
|
|
122
|
+
readonly cmsOrigin: string;
|
|
123
|
+
constructor(options: RootCMSBrowserClientOptions);
|
|
124
|
+
/**
|
|
125
|
+
* Opens the headless doc editor for a doc (e.g. `Pages/about`) in a pop-up
|
|
126
|
+
* or iframe. In popup mode, call from a user gesture (e.g. a click handler)
|
|
127
|
+
* to avoid pop-up blockers.
|
|
128
|
+
*
|
|
129
|
+
* The slug portion of the docId is normalized the same way the CMS
|
|
130
|
+
* normalizes slugs, so a URL-like path also works, e.g. `Pages/about/foo`
|
|
131
|
+
* -> `Pages/about--foo`.
|
|
132
|
+
*/
|
|
133
|
+
openEditor(docId: string, options?: OpenEditorOptions): EmbeddedEditor;
|
|
134
|
+
/**
|
|
135
|
+
* Opens the headless Root AI chat in a pop-up or iframe, optionally with a
|
|
136
|
+
* doc as context. In popup mode, call from a user gesture (e.g. a click
|
|
137
|
+
* handler) to avoid pop-up blockers.
|
|
138
|
+
*/
|
|
139
|
+
openRootAI(options?: OpenRootAIOptions): EmbeddedAI;
|
|
140
|
+
/**
|
|
141
|
+
* Connects to the doc editor from a site rendered inside the in-CMS preview
|
|
142
|
+
* pane, enabling "click to edit" ({@link PreviewConnection.focusField}) and
|
|
143
|
+
* field highlighting (`on('highlight', ...)`).
|
|
144
|
+
*/
|
|
145
|
+
static connectPreview(): PreviewConnection;
|
|
146
|
+
/** Returns whether this page is rendered inside the in-CMS preview pane. */
|
|
147
|
+
static isInPreviewIframe(): boolean;
|
|
148
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { SaveState } from '../shared/embed-protocol.js';
|
|
2
|
+
/** Events emitted by an embedded CMS window (iframe or pop-up). */
|
|
3
|
+
export interface EmbedWindowEvents {
|
|
4
|
+
/** The embedded page finished loading. */
|
|
5
|
+
ready: {
|
|
6
|
+
docId?: string;
|
|
7
|
+
};
|
|
8
|
+
/** The doc was saved. */
|
|
9
|
+
saved: {
|
|
10
|
+
docId?: string;
|
|
11
|
+
saveState?: SaveState;
|
|
12
|
+
};
|
|
13
|
+
/** The doc was published. */
|
|
14
|
+
published: {
|
|
15
|
+
docId?: string;
|
|
16
|
+
publishedAt?: number;
|
|
17
|
+
};
|
|
18
|
+
/** An error occurred (e.g. the pop-up was blocked). */
|
|
19
|
+
error: {
|
|
20
|
+
error?: string;
|
|
21
|
+
};
|
|
22
|
+
/** The embedded window was closed (via `close()` or by the user). */
|
|
23
|
+
close: void;
|
|
24
|
+
}
|
|
25
|
+
export interface EmbedWindowOptions {
|
|
26
|
+
/** How to open the embedded page. Defaults to `popup`. */
|
|
27
|
+
mode?: 'popup' | 'iframe';
|
|
28
|
+
/** Container the iframe is appended to. Required when mode is `iframe`. */
|
|
29
|
+
container?: HTMLElement;
|
|
30
|
+
/** Pop-up window width. Defaults to 480. */
|
|
31
|
+
width?: number;
|
|
32
|
+
/** Pop-up window height. Defaults to 720. */
|
|
33
|
+
height?: number;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Internal plumbing shared by the embedded doc editor and Root AI handles.
|
|
37
|
+
* Owns the iframe-or-popup lifecycle: opening, message routing (with origin
|
|
38
|
+
* and source validation), outbound message buffering until `ready`, reload,
|
|
39
|
+
* and close detection.
|
|
40
|
+
*/
|
|
41
|
+
export declare class EmbedWindow {
|
|
42
|
+
/** The iframe element (iframe mode only). */
|
|
43
|
+
readonly element: HTMLIFrameElement | null;
|
|
44
|
+
/** The pop-up window (popup mode only). */
|
|
45
|
+
readonly window: Window | null;
|
|
46
|
+
private url;
|
|
47
|
+
private cmsOrigin;
|
|
48
|
+
private emitter;
|
|
49
|
+
private ready;
|
|
50
|
+
private closed;
|
|
51
|
+
private outbox;
|
|
52
|
+
private pollTimer;
|
|
53
|
+
constructor(url: string, cmsOrigin: string, options?: EmbedWindowOptions);
|
|
54
|
+
on<K extends keyof EmbedWindowEvents>(type: K, cb: (payload: EmbedWindowEvents[K]) => void): () => void;
|
|
55
|
+
/**
|
|
56
|
+
* Posts a message to the embedded window, targeted at the CMS origin.
|
|
57
|
+
* Messages are buffered until the embedded page signals `ready`.
|
|
58
|
+
*/
|
|
59
|
+
post(message: unknown): void;
|
|
60
|
+
/** Reloads the embedded page. */
|
|
61
|
+
reload(): void;
|
|
62
|
+
/** Closes the embedded window. Safe to call multiple times. */
|
|
63
|
+
close(): void;
|
|
64
|
+
private contentWindow;
|
|
65
|
+
private onMessage;
|
|
66
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
type Listener<T> = (payload: T) => void;
|
|
2
|
+
/** Minimal typed event emitter. */
|
|
3
|
+
export declare class Emitter<Events extends Record<string, any>> {
|
|
4
|
+
private listeners;
|
|
5
|
+
/** Subscribes to an event. Returns an unsubscribe function. */
|
|
6
|
+
on<K extends keyof Events>(type: K, cb: Listener<Events[K]>): () => void;
|
|
7
|
+
off<K extends keyof Events>(type: K, cb: Listener<Events[K]>): void;
|
|
8
|
+
emit<K extends keyof Events>(type: K, payload: Events[K]): void;
|
|
9
|
+
removeAll(): void;
|
|
10
|
+
}
|
|
11
|
+
export {};
|