@phtngyn/cms 0.1.0-beta.0 → 0.1.0-beta.2
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 +260 -6
- package/package.json +31 -16
- package/src/Authoring.d.ts +13 -1
- package/src/Configuration-Br7tE9Qt.d.ts +68 -0
- package/src/{AuthoringSchema-BQ5kbhVB.js → Configuration-CA_jvQKG.js} +599 -492
- package/src/Configuration-CA_jvQKG.js.map +1 -0
- package/src/Configuration.d.ts +2 -44
- package/src/Configuration.js +0 -1
- package/src/Configuration.js.map +1 -1
- package/src/{DocumentEngine-Da0kWotL.js → DocumentEngine-CgiBQU4g.js} +110 -84
- package/src/DocumentEngine-CgiBQU4g.js.map +1 -0
- package/src/DocumentModel-BB9igGC7.d.ts +34 -0
- package/src/DocumentModel.d.ts +2 -30
- package/src/DocumentModel.js +13 -3
- package/src/DocumentModel.js.map +1 -1
- package/src/Forms-BsJMev5_.d.ts +74 -0
- package/src/Forms-CfcI3tPU.js +79 -0
- package/src/Forms-CfcI3tPU.js.map +1 -0
- package/src/Forms-DxbkU3_5.js +367 -0
- package/src/Forms-DxbkU3_5.js.map +1 -0
- package/src/Forms.d.ts +35 -0
- package/src/Forms.js +13 -0
- package/src/Forms.js.map +1 -0
- package/src/HttpPaths-c9nLZ9H2.js +21 -0
- package/src/HttpPaths-c9nLZ9H2.js.map +1 -0
- package/src/I18n-DZK4CkJF.d.ts +21 -0
- package/src/I18n.d.ts +2 -0
- package/src/I18n.js +1 -0
- package/src/Module.js +78 -81
- package/src/Module.js.map +1 -1
- package/src/S3MediaObjects-JKMAWyVB.js +2664 -0
- package/src/S3MediaObjects-JKMAWyVB.js.map +1 -0
- package/src/Seed.d.ts +6 -0
- package/src/Seed.js +34 -0
- package/src/Seed.js.map +1 -0
- package/src/Seo-402YumpT.d.ts +198 -0
- package/src/{connection-ZGtL54qY.js → connection-B-iz0Y9Y.js} +5 -7
- package/src/connection-B-iz0Y9Y.js.map +1 -0
- package/src/{installation-BNKaVjni.js → installation-DgF2M1gL.js} +1162 -2147
- package/src/installation-DgF2M1gL.js.map +1 -0
- package/src/internal/authoring-catalog.js +153 -0
- package/src/internal/authoring-catalog.js.map +1 -0
- package/src/internal/authoring-compiler.js +2 -2
- package/src/internal/authoring-compiler.js.map +1 -1
- package/src/internal/authoring-metadata.js +68 -49
- package/src/internal/authoring-metadata.js.map +1 -1
- package/src/internal/cms-config.js +0 -1
- package/src/internal/cms-config.js.map +1 -1
- package/src/internal/configuration.js +25 -13
- package/src/internal/configuration.js.map +1 -1
- package/src/internal/document-model.js +66 -20
- package/src/internal/document-model.js.map +1 -1
- package/src/internal/form-capabilities.js +12 -0
- package/src/internal/form-capabilities.js.map +1 -0
- package/src/internal/i18n.js +47 -0
- package/src/internal/i18n.js.map +1 -0
- package/src/internal/studio-app.js +66 -0
- package/src/internal/studio-app.js.map +1 -0
- package/src/location-CFKTeK1K.js +35 -0
- package/src/location-CFKTeK1K.js.map +1 -0
- package/src/{metadata-Czvi3E4K.js → metadata-BEZPWh-3.js} +3 -72
- package/src/metadata-BEZPWh-3.js.map +1 -0
- package/src/{models-DS5ClMsH.js → models-BWm1pTAf.js} +9 -31
- package/src/models-BWm1pTAf.js.map +1 -0
- package/src/models-DwYioyNV.js +726 -0
- package/src/models-DwYioyNV.js.map +1 -0
- package/src/runtime/blocks.js +30 -0
- package/src/runtime/blocks.js.map +1 -0
- package/src/runtime/collaboration.js +9 -4
- package/src/runtime/collaboration.js.map +1 -1
- package/src/runtime/delivery/DocumentRenderer.js +10 -4
- package/src/runtime/delivery/DocumentRenderer.js.map +1 -1
- package/src/runtime/delivery/blocks.js +8 -0
- package/src/runtime/delivery/blocks.js.map +1 -0
- package/src/runtime/delivery/context.js +12 -0
- package/src/runtime/delivery/context.js.map +1 -0
- package/src/runtime/delivery/document-page.js +14 -12
- package/src/runtime/delivery/document-page.js.map +1 -1
- package/src/runtime/delivery/document.js +21 -3
- package/src/runtime/delivery/document.js.map +1 -1
- package/src/runtime/delivery/error.js +11 -0
- package/src/runtime/delivery/error.js.map +1 -0
- package/src/runtime/delivery/plugin.js +41 -0
- package/src/runtime/delivery/plugin.js.map +1 -0
- package/src/runtime/delivery/types.d.ts +5 -0
- package/src/runtime/delivery/useCmsDocumentSeo.d.ts +56 -0
- package/src/runtime/delivery/useCmsDocumentSeo.js +99 -0
- package/src/runtime/delivery/useCmsDocumentSeo.js.map +1 -0
- package/src/runtime/delivery/useDocument.js +5 -2
- package/src/runtime/delivery/useDocument.js.map +1 -1
- package/src/runtime/delivery/useDocumentQuery.js +5 -2
- package/src/runtime/delivery/useDocumentQuery.js.map +1 -1
- package/src/runtime/forms/document.js +38 -0
- package/src/runtime/forms/document.js.map +1 -0
- package/src/runtime/forms/useCmsForm.js +149 -0
- package/src/runtime/forms/useCmsForm.js.map +1 -0
- package/src/runtime/i18n/translator.js +22 -0
- package/src/runtime/i18n/translator.js.map +1 -0
- package/src/runtime/i18n/useCmsI18n.d.ts +9 -0
- package/src/runtime/i18n/useCmsI18n.js +29 -0
- package/src/runtime/i18n/useCmsI18n.js.map +1 -0
- package/src/runtime/installation.js +1 -1
- package/src/runtime/plugin.js +3 -3
- package/src/runtime/plugin.js.map +1 -1
- package/src/runtime/preview/comark-document.js +0 -1
- package/src/runtime/preview/comark-document.js.map +1 -1
- package/src/runtime/preview/connection.js +1 -1
- package/src/runtime/preview/controller.js +37 -11
- package/src/runtime/preview/controller.js.map +1 -1
- package/src/runtime/preview/overlay.js +65 -0
- package/src/runtime/preview/overlay.js.map +1 -0
- package/src/runtime/preview/plugin.client.js +59 -61
- package/src/runtime/preview/plugin.client.js.map +1 -1
- package/src/runtime/preview/preview.css +72 -4
- package/src/runtime/preview/protocol.js.map +1 -1
- package/src/runtime/preview/store.js +1 -1
- package/src/runtime/preview/targets.js +0 -1
- package/src/runtime/preview/targets.js.map +1 -1
- package/src/runtime/sitemap-entries.js +17 -0
- package/src/runtime/sitemap-entries.js.map +1 -0
- package/src/runtime/sitemap.js +24 -0
- package/src/runtime/sitemap.js.map +1 -0
- package/src/runtime/studio-app.js +5 -1
- package/src/runtime/studio-app.js.map +1 -1
- package/src/runtime/studio-entry.js +36 -0
- package/src/runtime/studio-entry.js.map +1 -0
- package/src/runtime/studio-navigation.js +11 -0
- package/src/runtime/studio-navigation.js.map +1 -0
- package/src/scalars-B2lgGUnj.js +26 -0
- package/src/scalars-B2lgGUnj.js.map +1 -0
- package/src/{store-Nl4uxEXx.js → store-DjJs3I7k.js} +12 -7
- package/src/store-DjJs3I7k.js.map +1 -0
- package/studio/CreateDocumentDialog-CTeIFlPb.js +256 -0
- package/studio/collaboration-DcK2F6v9.js +4566 -0
- package/studio/documentPlanning-Bfv-d7OU.js +29820 -0
- package/studio/dom-to-image-more.min-D6jGGdrW.js +877 -0
- package/studio/editor-Bzlh3zXt.js +30827 -0
- package/studio/host.css +3 -0
- package/studio/host.js +46614 -0
- package/studio/rolldown-runtime-B0aSnxlc.js +20 -0
- package/dist/studio/assets/ActivityEntryRow-D--fRvWI.js +0 -1
- package/dist/studio/assets/ActivityView-D-XBBUHb.js +0 -1
- package/dist/studio/assets/CreateDocumentDialog-CH8UH1QM.js +0 -1
- package/dist/studio/assets/DocumentsView-CxRpmAxt.js +0 -34
- package/dist/studio/assets/DropdownMenu-BSb1l7fr.js +0 -1
- package/dist/studio/assets/Input-DVao38h7.js +0 -3
- package/dist/studio/assets/MediaView-BHrPIjxB.js +0 -1
- package/dist/studio/assets/Modal-VNrXGa5C.js +0 -1
- package/dist/studio/assets/OverviewView-DfP6-mLZ.js +0 -1
- package/dist/studio/assets/Select-BJZIs9sY.js +0 -1
- package/dist/studio/assets/SettingsView-CerHe-ua.js +0 -1
- package/dist/studio/assets/Skeleton-CWJNi3nS.js +0 -1
- package/dist/studio/assets/StudioPageHeader-DP9HDAF2.js +0 -1
- package/dist/studio/assets/UsersView-cP3REkH2.js +0 -1
- package/dist/studio/assets/collaboration-BLnCzfvV.js +0 -4
- package/dist/studio/assets/context-dY4fNbn3.js +0 -1
- package/dist/studio/assets/editor-CE07wW83.js +0 -137
- package/dist/studio/assets/gateway-BAyQgCse.js +0 -10
- package/dist/studio/assets/index-CjoaPLhZ.js +0 -28
- package/dist/studio/assets/index-s2rPqCmP.css +0 -2
- package/dist/studio/assets/render-BkxbK2St.js +0 -83
- package/dist/studio/assets/rolldown-runtime-DK3Fl9T5.js +0 -1
- package/dist/studio/assets/useMediaLibrary-D7qR7aBf.js +0 -1
- package/dist/studio/index.html +0 -76
- package/src/AuthoringSchema-BQ5kbhVB.js.map +0 -1
- package/src/Configuration-BGYFD2N1.js +0 -150
- package/src/Configuration-BGYFD2N1.js.map +0 -1
- package/src/DocumentEngine-Da0kWotL.js.map +0 -1
- package/src/HttpPaths-86qLGB90.js +0 -15
- package/src/HttpPaths-86qLGB90.js.map +0 -1
- package/src/StudioHttp-BTLLooh0.js +0 -916
- package/src/StudioHttp-BTLLooh0.js.map +0 -1
- package/src/connection-ZGtL54qY.js.map +0 -1
- package/src/installation-BNKaVjni.js.map +0 -1
- package/src/internal/component-metadata.js +0 -37
- package/src/internal/component-metadata.js.map +0 -1
- package/src/metadata-Czvi3E4K.js.map +0 -1
- package/src/models-Citx8jBi.js +0 -306
- package/src/models-Citx8jBi.js.map +0 -1
- package/src/models-DS5ClMsH.js.map +0 -1
- package/src/store-Nl4uxEXx.js.map +0 -1
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { a as EditorNodeId, l as RevisionNumber, r as DocumentId } from "../../scalars-B2lgGUnj.js";
|
|
2
|
+
import { kt as RequestId } from "../../models-DwYioyNV.js";
|
|
3
|
+
import { r as PreviewIntentId } from "../../models-BWm1pTAf.js";
|
|
4
|
+
import { mountPreviewOverlay } from "./overlay.js";
|
|
3
5
|
import { clearPreviewTargets, decoratePreviewTargets, findPreviewNodeId, nearestPreviewElement, resolvePreviewTarget } from "./targets.js";
|
|
4
6
|
import { Crypto, Effect, PlatformError, Schema } from "effect";
|
|
5
7
|
|
|
@@ -7,7 +9,7 @@ import { Crypto, Effect, PlatformError, Schema } from "effect";
|
|
|
7
9
|
const browserCrypto = Crypto.make({
|
|
8
10
|
digest: (algorithm, data) => Effect.tryPromise({
|
|
9
11
|
catch: (cause) => PlatformError.systemError({
|
|
10
|
-
_tag:
|
|
12
|
+
_tag: unknownSystemErrorTag,
|
|
11
13
|
cause,
|
|
12
14
|
description: "Could not compute digest",
|
|
13
15
|
method: "digest",
|
|
@@ -17,9 +19,12 @@ const browserCrypto = Crypto.make({
|
|
|
17
19
|
}),
|
|
18
20
|
randomBytes: (size) => globalThis.crypto.getRandomValues(new Uint8Array(size))
|
|
19
21
|
});
|
|
22
|
+
const unknownSystemErrorTag = "Unknown";
|
|
20
23
|
const randomUuid = () => Effect.runSync(browserCrypto.randomUUIDv4.pipe(Effect.orDie));
|
|
21
24
|
function mountPreviewController(options) {
|
|
22
25
|
const { bridge, root, store, view } = options;
|
|
26
|
+
const selection = mountPreviewOverlay(root, view);
|
|
27
|
+
const hover = mountPreviewOverlay(root, view, "hover");
|
|
23
28
|
let active = false;
|
|
24
29
|
let desiredFocus;
|
|
25
30
|
let fallbacks = {};
|
|
@@ -61,10 +66,14 @@ function mountPreviewController(options) {
|
|
|
61
66
|
const applyFocus = (reveal = false) => {
|
|
62
67
|
clearElements(selectedElements, "data-cms-selected");
|
|
63
68
|
selectedElements = [];
|
|
64
|
-
if (!active || mode !== "edit")
|
|
69
|
+
if (!active || mode !== "edit") {
|
|
70
|
+
selection.set([]);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
65
73
|
const intent = desiredFocus;
|
|
66
74
|
const nodeId = intent?.nodeId;
|
|
67
75
|
if (!intent || !nodeId) {
|
|
76
|
+
selection.set([]);
|
|
68
77
|
sendApplied("exact");
|
|
69
78
|
return;
|
|
70
79
|
}
|
|
@@ -72,6 +81,7 @@ function mountPreviewController(options) {
|
|
|
72
81
|
decoratePreviewTargets(scope);
|
|
73
82
|
const target = resolvePreviewTarget(scope, nodeId, fallbacks);
|
|
74
83
|
selectedElements = target.elements;
|
|
84
|
+
selection.set(selectedElements);
|
|
75
85
|
for (const element of selectedElements) element.setAttribute("data-cms-selected", "");
|
|
76
86
|
const result = !target.resolvedNodeId ? "missing" : target.resolvedNodeId === nodeId ? "exact" : "fallback";
|
|
77
87
|
if (reveal && result !== "missing" && revealedIntentId !== intent.id) {
|
|
@@ -83,12 +93,19 @@ function mountPreviewController(options) {
|
|
|
83
93
|
const hoverElements = (target) => {
|
|
84
94
|
clearElements(hoveredElements, "data-cms-hovered");
|
|
85
95
|
hoveredElements = [];
|
|
86
|
-
if (!active || mode !== "edit" || !target)
|
|
96
|
+
if (!active || mode !== "edit" || !target) {
|
|
97
|
+
hover.set([]);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
87
100
|
const scope = target.closest("[data-cms-document]") ?? root;
|
|
88
101
|
const nodeId = findPreviewNodeId(scope, target);
|
|
89
|
-
if (!nodeId)
|
|
102
|
+
if (!nodeId) {
|
|
103
|
+
hover.set([]);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
90
106
|
hoveredElements = resolvePreviewTarget(scope, nodeId, fallbacks).elements;
|
|
91
107
|
for (const element of hoveredElements) element.setAttribute("data-cms-hovered", "");
|
|
108
|
+
hover.set(hoveredElements);
|
|
92
109
|
};
|
|
93
110
|
const settleRender = (sequence) => {
|
|
94
111
|
view.requestAnimationFrame(() => view.requestAnimationFrame(() => {
|
|
@@ -116,6 +133,7 @@ function mountPreviewController(options) {
|
|
|
116
133
|
hoverElements();
|
|
117
134
|
clearElements(selectedElements, "data-cms-selected");
|
|
118
135
|
selectedElements = [];
|
|
136
|
+
selection.set([]);
|
|
119
137
|
} else {
|
|
120
138
|
decoratePreviewTargets(root);
|
|
121
139
|
applyFocus();
|
|
@@ -139,8 +157,13 @@ function mountPreviewController(options) {
|
|
|
139
157
|
lastApplied = "";
|
|
140
158
|
const sequence = ++renderSequence;
|
|
141
159
|
store.patch(message.document).then((localFallbacks) => {
|
|
160
|
+
if (sequence !== renderSequence) return;
|
|
161
|
+
options.onPatchError(null);
|
|
142
162
|
fallbacks = Object.assign({}, message.fallbacks, localFallbacks);
|
|
143
163
|
settleRender(sequence);
|
|
164
|
+
}, () => {
|
|
165
|
+
if (sequence !== renderSequence) return;
|
|
166
|
+
options.onPatchError("Preview could not apply this update.");
|
|
144
167
|
});
|
|
145
168
|
});
|
|
146
169
|
const handleClick = (event) => {
|
|
@@ -152,7 +175,8 @@ function mountPreviewController(options) {
|
|
|
152
175
|
const destination = new URL(link.href, view.location.href);
|
|
153
176
|
if (destination.origin !== view.location.origin) return;
|
|
154
177
|
event.preventDefault();
|
|
155
|
-
|
|
178
|
+
event.stopPropagation();
|
|
179
|
+
options.navigate(`${destination.pathname}${destination.search}${destination.hash}`);
|
|
156
180
|
return;
|
|
157
181
|
}
|
|
158
182
|
const scope = target?.closest("[data-cms-document]");
|
|
@@ -202,7 +226,8 @@ function mountPreviewController(options) {
|
|
|
202
226
|
if (!(event.relatedTarget instanceof Element)) hoverElements();
|
|
203
227
|
};
|
|
204
228
|
let mutationQueued = false;
|
|
205
|
-
const observer = new MutationObserver(() => {
|
|
229
|
+
const observer = new MutationObserver((records) => {
|
|
230
|
+
if (records.every((record) => record.target instanceof Element && record.target.closest("[data-cms-preview-overlay]"))) return;
|
|
206
231
|
if (mutationQueued) return;
|
|
207
232
|
mutationQueued = true;
|
|
208
233
|
queueMicrotask(() => {
|
|
@@ -224,6 +249,8 @@ function mountPreviewController(options) {
|
|
|
224
249
|
stopBridge();
|
|
225
250
|
stopManifest();
|
|
226
251
|
observer.disconnect();
|
|
252
|
+
selection.destroy();
|
|
253
|
+
hover.destroy();
|
|
227
254
|
root.removeEventListener("click", handleClick, true);
|
|
228
255
|
root.removeEventListener("pointerover", handlePointerOver, true);
|
|
229
256
|
root.removeEventListener("pointerout", handlePointerOut, true);
|
|
@@ -233,10 +260,9 @@ function mountPreviewController(options) {
|
|
|
233
260
|
function revealElement(element, view) {
|
|
234
261
|
if (!element) return;
|
|
235
262
|
const rect = element.getBoundingClientRect();
|
|
236
|
-
|
|
237
|
-
if (rect.top >= margin && rect.bottom <= view.innerHeight - margin) return;
|
|
263
|
+
if (rect.bottom > 0 && rect.top < view.innerHeight && rect.right > 0 && rect.left < view.innerWidth) return;
|
|
238
264
|
element.scrollIntoView({
|
|
239
|
-
behavior:
|
|
265
|
+
behavior: "instant",
|
|
240
266
|
block: "center",
|
|
241
267
|
inline: "nearest"
|
|
242
268
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controller.js","names":[],"sources":["../../../../../src/runtime/preview/controller.ts"],"sourcesContent":["import type { DocumentPreviewFocusIntent, PreviewSiteBridge, StudioPreviewPayload } from '@internal/protocol/Preview'\nimport type { StudioPreviewStore } from './store'\nimport { DocumentId, EditorNodeId, RevisionNumber } from '@internal/protocol/Documents'\nimport { RequestId } from '@internal/protocol/Identity'\nimport { PreviewIntentId } from '@internal/protocol/Preview'\nimport { Crypto, Effect, PlatformError, Schema } from 'effect'\nimport {\n clearPreviewTargets,\n decoratePreviewTargets,\n findPreviewNodeId,\n nearestPreviewElement,\n resolvePreviewTarget,\n} from './targets'\n\nconst browserCrypto = Crypto.make({\n digest: (algorithm, data) =>\n Effect.tryPromise({\n catch: (cause) =>\n PlatformError.systemError({\n _tag: 'Unknown',\n cause,\n description: 'Could not compute digest',\n method: 'digest',\n module: 'Crypto',\n }),\n try: () =>\n globalThis.crypto.subtle.digest(algorithm, Uint8Array.from(data)).then((digest) => new Uint8Array(digest)),\n }),\n randomBytes: (size) => globalThis.crypto.getRandomValues(new Uint8Array(size)),\n})\n\nconst randomUuid = (): string => Effect.runSync(browserCrypto.randomUUIDv4.pipe(Effect.orDie))\n\nexport function mountPreviewController(options: {\n readonly bridge: PreviewSiteBridge\n readonly navigate: (path: string) => Promise<void> | void\n readonly root: Document\n readonly store: StudioPreviewStore\n readonly view: Window\n}): () => void {\n type PreviewFallbacks = Extract<StudioPreviewPayload, { readonly type: 'studio:patch' }>['fallbacks']\n const { bridge, root, store, view } = options\n let active = false\n let desiredFocus: DocumentPreviewFocusIntent | undefined\n let fallbacks: PreviewFallbacks = {}\n let hoveredElements: ReadonlyArray<Element> = []\n let mode: 'browse' | 'edit' = 'edit'\n let renderSequence = 0\n let revision = RevisionNumber.make(0)\n let selectedElements: ReadonlyArray<Element> = []\n let lastApplied = ''\n let revealedIntentId = ''\n\n const sendManifest = (): void => {\n bridge.send({ manifest: store.manifest(), revision, type: 'preview:manifest' })\n }\n const stopManifest = store.subscribe(sendManifest)\n const clearElements = (elements: ReadonlyArray<Element>, attribute: string): void => {\n for (const element of elements) element.removeAttribute(attribute)\n }\n const sendApplied = (result: 'exact' | 'fallback' | 'missing'): void => {\n if (!desiredFocus) return\n const signature = `${desiredFocus.id}:${result}`\n if (signature === lastApplied) return\n lastApplied = signature\n const applied = {\n intentId: desiredFocus.id,\n result,\n revision,\n type: 'preview:applied',\n } as const\n bridge.send(desiredFocus.nodeId ? { ...applied, nodeId: desiredFocus.nodeId } : applied)\n }\n const documentRoot = (documentId: string): ParentNode =>\n [...root.querySelectorAll('[data-cms-document]')].find(\n (element) => element.getAttribute('data-cms-document') === documentId,\n ) ?? root\n const applyFocus = (reveal = false): void => {\n clearElements(selectedElements, 'data-cms-selected')\n selectedElements = []\n if (!active || mode !== 'edit') return\n const intent = desiredFocus\n const nodeId = intent?.nodeId\n if (!intent || !nodeId) {\n sendApplied('exact')\n return\n }\n const scope = documentRoot(intent.documentId)\n decoratePreviewTargets(scope)\n const target = resolvePreviewTarget(scope, nodeId, fallbacks)\n selectedElements = target.elements\n for (const element of selectedElements) element.setAttribute('data-cms-selected', '')\n const result = !target.resolvedNodeId ? 'missing' : target.resolvedNodeId === nodeId ? 'exact' : 'fallback'\n if (reveal && result !== 'missing' && revealedIntentId !== intent.id) {\n revealedIntentId = intent.id\n revealElement(nearestPreviewElement(selectedElements), view)\n }\n sendApplied(result)\n }\n const hoverElements = (target?: Element): void => {\n clearElements(hoveredElements, 'data-cms-hovered')\n hoveredElements = []\n if (!active || mode !== 'edit' || !target) return\n const scope = target.closest('[data-cms-document]') ?? root\n const nodeId = findPreviewNodeId(scope, target)\n if (!nodeId) return\n hoveredElements = resolvePreviewTarget(scope, nodeId, fallbacks).elements\n for (const element of hoveredElements) element.setAttribute('data-cms-hovered', '')\n }\n const settleRender = (sequence: number): void => {\n view.requestAnimationFrame(() =>\n view.requestAnimationFrame(() => {\n if (sequence !== renderSequence) return\n active = true\n decoratePreviewTargets(root)\n bridge.send({ revision, type: 'preview:rendered' })\n applyFocus(desiredFocus?.reveal)\n }),\n )\n }\n\n const stopBridge = bridge.subscribe((message) => {\n if (message.type === 'studio:connect') {\n active = true\n clearPreviewTargets(root)\n decoratePreviewTargets(root)\n sendManifest()\n return\n }\n if (message.type === 'studio:mode') {\n mode = message.mode\n if (mode === 'browse') {\n hoverElements()\n clearElements(selectedElements, 'data-cms-selected')\n selectedElements = []\n } else {\n decoratePreviewTargets(root)\n applyFocus()\n }\n return\n }\n if (message.type === 'studio:navigate') {\n void options.navigate(message.path)\n return\n }\n if (message.type === 'studio:focus') {\n if (message.focus.revision !== revision) return\n desiredFocus = message.focus\n applyFocus(desiredFocus.reveal)\n return\n }\n if (message.type !== 'studio:patch' || message.revision < revision) return\n revision = message.revision\n active = false\n desiredFocus = message.focus\n lastApplied = ''\n const sequence = ++renderSequence\n void store.patch(message.document).then((localFallbacks) => {\n fallbacks = Object.assign({}, message.fallbacks, localFallbacks)\n settleRender(sequence)\n })\n })\n\n const handleClick = (event: MouseEvent) => {\n if (!active) return\n const target = event.target instanceof Element ? event.target : null\n if (mode === 'browse') {\n const link = target?.closest('a[href]')\n if (\n !(link instanceof HTMLAnchorElement) ||\n link.target ||\n link.hasAttribute('download') ||\n event.metaKey ||\n event.ctrlKey ||\n event.shiftKey ||\n event.altKey\n )\n return\n const destination = new URL(link.href, view.location.href)\n if (destination.origin !== view.location.origin) return\n event.preventDefault()\n void options.navigate(destination.pathname)\n return\n }\n const scope = target?.closest('[data-cms-document]')\n const documentIdValue = scope?.getAttribute('data-cms-document')\n if (!target || !scope || !Schema.is(DocumentId)(documentIdValue)) return\n event.preventDefault()\n event.stopPropagation()\n const nodeIdValue = findPreviewNodeId(scope, target)\n const nodeId = Schema.is(EditorNodeId)(nodeIdValue) ? nodeIdValue : undefined\n const field = target.closest('[data-cms-field]')?.getAttribute('data-cms-field') || undefined\n const activationFocus = {\n documentId: documentIdValue,\n id: PreviewIntentId.make(randomUuid()),\n origin: 'preview',\n reveal: false,\n revision,\n } as const\n desiredFocus = nodeId ? { ...activationFocus, nodeId } : activationFocus\n lastApplied = ''\n const activation = {\n documentId: desiredFocus.documentId,\n requestId: RequestId.make(randomUuid()),\n revision,\n type: 'preview:activate',\n } as const\n if (field && nodeId) bridge.send({ ...activation, field, nodeId })\n else if (field) bridge.send({ ...activation, field })\n else if (nodeId) bridge.send({ ...activation, nodeId })\n else bridge.send(activation)\n applyFocus()\n }\n const handlePointerOver = (event: PointerEvent) =>\n hoverElements(event.target instanceof Element ? event.target : undefined)\n const handlePointerOut = (event: PointerEvent) => {\n if (!(event.relatedTarget instanceof Element)) hoverElements()\n }\n let mutationQueued = false\n const observer = new MutationObserver(() => {\n if (mutationQueued) return\n mutationQueued = true\n queueMicrotask(() => {\n mutationQueued = false\n if (!active) return\n hoverElements()\n decoratePreviewTargets(root)\n if (desiredFocus) applyFocus(false)\n })\n })\n\n root.addEventListener('click', handleClick, true)\n root.addEventListener('pointerover', handlePointerOver, true)\n root.addEventListener('pointerout', handlePointerOut, true)\n observer.observe(root.documentElement, { childList: true, subtree: true })\n\n return () => {\n stopBridge()\n stopManifest()\n observer.disconnect()\n root.removeEventListener('click', handleClick, true)\n root.removeEventListener('pointerover', handlePointerOver, true)\n root.removeEventListener('pointerout', handlePointerOut, true)\n clearPreviewTargets(root)\n }\n}\n\nfunction revealElement(element: Element | undefined, view: Window): void {\n if (!element) return\n const rect = element.getBoundingClientRect()\n const margin = Math.min(80, view.innerHeight / 5)\n if (rect.top >= margin && rect.bottom <= view.innerHeight - margin) return\n element.scrollIntoView({\n behavior: view.matchMedia('(prefers-reduced-motion: reduce)').matches ? 'auto' : 'smooth',\n block: 'center',\n inline: 'nearest',\n })\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"controller.js","names":[],"sources":["../../../../../src/runtime/preview/controller.ts"],"sourcesContent":["import type { DocumentPreviewFocusIntent, PreviewSiteBridge, StudioPreviewPayload } from '@internal/protocol/Preview'\nimport type { StudioPreviewStore } from './store'\nimport { DocumentId, EditorNodeId, RevisionNumber } from '@internal/protocol/Documents'\nimport { RequestId } from '@internal/protocol/Identity'\nimport { PreviewIntentId } from '@internal/protocol/Preview'\nimport { Crypto, Effect, PlatformError, Schema } from 'effect'\nimport { mountPreviewOverlay } from './overlay'\nimport {\n clearPreviewTargets,\n decoratePreviewTargets,\n findPreviewNodeId,\n nearestPreviewElement,\n resolvePreviewTarget,\n} from './targets'\n\nconst browserCrypto = Crypto.make({\n digest: (algorithm, data) =>\n Effect.tryPromise({\n catch: (cause) =>\n PlatformError.systemError({\n _tag: unknownSystemErrorTag,\n cause,\n description: 'Could not compute digest',\n method: 'digest',\n module: 'Crypto',\n }),\n try: () =>\n globalThis.crypto.subtle.digest(algorithm, Uint8Array.from(data)).then((digest) => new Uint8Array(digest)),\n }),\n randomBytes: (size) => globalThis.crypto.getRandomValues(new Uint8Array(size)),\n})\n\nconst unknownSystemErrorTag: PlatformError.SystemErrorTag = 'Unknown'\n\nconst randomUuid = (): string => Effect.runSync(browserCrypto.randomUUIDv4.pipe(Effect.orDie))\n\nexport function mountPreviewController(options: {\n readonly bridge: PreviewSiteBridge\n readonly navigate: (path: string) => Promise<void> | void\n readonly onPatchError: (message: string | null) => void\n readonly root: Document\n readonly store: StudioPreviewStore\n readonly view: Window\n}): () => void {\n type PreviewFallbacks = Extract<StudioPreviewPayload, { readonly type: 'studio:patch' }>['fallbacks']\n\n const { bridge, root, store, view } = options\n const selection = mountPreviewOverlay(root, view)\n const hover = mountPreviewOverlay(root, view, 'hover')\n let active = false\n let desiredFocus: DocumentPreviewFocusIntent | undefined\n let fallbacks: PreviewFallbacks = {}\n let hoveredElements: ReadonlyArray<Element> = []\n let mode: 'browse' | 'edit' = 'edit'\n let renderSequence = 0\n let revision = RevisionNumber.make(0)\n let selectedElements: ReadonlyArray<Element> = []\n let lastApplied = ''\n let revealedIntentId = ''\n\n const sendManifest = (): void => {\n bridge.send({ manifest: store.manifest(), revision, type: 'preview:manifest' })\n }\n\n const stopManifest = store.subscribe(sendManifest)\n\n const clearElements = (elements: ReadonlyArray<Element>, attribute: string): void => {\n for (const element of elements) element.removeAttribute(attribute)\n }\n\n const sendApplied = (result: 'exact' | 'fallback' | 'missing'): void => {\n if (!desiredFocus) return\n const signature = `${desiredFocus.id}:${result}`\n\n if (signature === lastApplied) return\n lastApplied = signature\n\n const applied = {\n intentId: desiredFocus.id,\n result,\n revision,\n type: 'preview:applied',\n } as const\n\n bridge.send(desiredFocus.nodeId ? { ...applied, nodeId: desiredFocus.nodeId } : applied)\n }\n\n const documentRoot = (documentId: string): ParentNode =>\n [...root.querySelectorAll('[data-cms-document]')].find(\n (element) => element.getAttribute('data-cms-document') === documentId,\n ) ?? root\n\n const applyFocus = (reveal = false): void => {\n clearElements(selectedElements, 'data-cms-selected')\n selectedElements = []\n\n if (!active || mode !== 'edit') {\n selection.set([])\n\n return\n }\n\n const intent = desiredFocus\n const nodeId = intent?.nodeId\n\n if (!intent || !nodeId) {\n selection.set([])\n sendApplied('exact')\n\n return\n }\n\n const scope = documentRoot(intent.documentId)\n decoratePreviewTargets(scope)\n const target = resolvePreviewTarget(scope, nodeId, fallbacks)\n selectedElements = target.elements\n selection.set(selectedElements)\n\n for (const element of selectedElements) element.setAttribute('data-cms-selected', '')\n const result = !target.resolvedNodeId ? 'missing' : target.resolvedNodeId === nodeId ? 'exact' : 'fallback'\n\n if (reveal && result !== 'missing' && revealedIntentId !== intent.id) {\n revealedIntentId = intent.id\n revealElement(nearestPreviewElement(selectedElements), view)\n }\n\n sendApplied(result)\n }\n\n const hoverElements = (target?: Element): void => {\n clearElements(hoveredElements, 'data-cms-hovered')\n hoveredElements = []\n\n if (!active || mode !== 'edit' || !target) {\n hover.set([])\n\n return\n }\n\n const scope = target.closest('[data-cms-document]') ?? root\n const nodeId = findPreviewNodeId(scope, target)\n\n if (!nodeId) {\n hover.set([])\n\n return\n }\n\n hoveredElements = resolvePreviewTarget(scope, nodeId, fallbacks).elements\n\n for (const element of hoveredElements) element.setAttribute('data-cms-hovered', '')\n hover.set(hoveredElements)\n }\n\n const settleRender = (sequence: number): void => {\n view.requestAnimationFrame(() =>\n view.requestAnimationFrame(() => {\n if (sequence !== renderSequence) return\n active = true\n decoratePreviewTargets(root)\n bridge.send({ revision, type: 'preview:rendered' })\n applyFocus(desiredFocus?.reveal)\n }),\n )\n }\n\n const stopBridge = bridge.subscribe((message) => {\n if (message.type === 'studio:connect') {\n active = true\n clearPreviewTargets(root)\n decoratePreviewTargets(root)\n sendManifest()\n\n return\n }\n\n if (message.type === 'studio:mode') {\n mode = message.mode\n\n if (mode === 'browse') {\n hoverElements()\n clearElements(selectedElements, 'data-cms-selected')\n selectedElements = []\n selection.set([])\n } else {\n decoratePreviewTargets(root)\n applyFocus()\n }\n\n return\n }\n\n if (message.type === 'studio:navigate') {\n void options.navigate(message.path)\n\n return\n }\n\n if (message.type === 'studio:focus') {\n if (message.focus.revision !== revision) return\n desiredFocus = message.focus\n applyFocus(desiredFocus.reveal)\n\n return\n }\n\n if (message.type !== 'studio:patch' || message.revision < revision) return\n revision = message.revision\n active = false\n desiredFocus = message.focus\n lastApplied = ''\n const sequence = ++renderSequence\n void store.patch(message.document).then(\n (localFallbacks) => {\n if (sequence !== renderSequence) return\n options.onPatchError(null)\n fallbacks = Object.assign({}, message.fallbacks, localFallbacks)\n settleRender(sequence)\n },\n () => {\n if (sequence !== renderSequence) return\n options.onPatchError('Preview could not apply this update.')\n },\n )\n })\n\n const handleClick = (event: MouseEvent) => {\n if (!active) return\n const target = event.target instanceof Element ? event.target : null\n\n if (mode === 'browse') {\n const link = target?.closest('a[href]')\n\n if (\n !(link instanceof HTMLAnchorElement) ||\n link.target ||\n link.hasAttribute('download') ||\n event.metaKey ||\n event.ctrlKey ||\n event.shiftKey ||\n event.altKey\n )\n return\n const destination = new URL(link.href, view.location.href)\n\n if (destination.origin !== view.location.origin) return\n event.preventDefault()\n event.stopPropagation()\n void options.navigate(`${destination.pathname}${destination.search}${destination.hash}`)\n\n return\n }\n\n const scope = target?.closest('[data-cms-document]')\n const documentIdValue = scope?.getAttribute('data-cms-document')\n\n if (!target || !scope || !Schema.is(DocumentId)(documentIdValue)) return\n event.preventDefault()\n event.stopPropagation()\n const nodeIdValue = findPreviewNodeId(scope, target)\n const nodeId = Schema.is(EditorNodeId)(nodeIdValue) ? nodeIdValue : undefined\n const field = target.closest('[data-cms-field]')?.getAttribute('data-cms-field') || undefined\n\n const activationFocus = {\n documentId: documentIdValue,\n id: PreviewIntentId.make(randomUuid()),\n origin: 'preview',\n reveal: false,\n revision,\n } as const\n\n desiredFocus = nodeId ? { ...activationFocus, nodeId } : activationFocus\n lastApplied = ''\n\n const activation = {\n documentId: desiredFocus.documentId,\n requestId: RequestId.make(randomUuid()),\n revision,\n type: 'preview:activate',\n } as const\n\n if (field && nodeId) bridge.send({ ...activation, field, nodeId })\n else if (field) bridge.send({ ...activation, field })\n else if (nodeId) bridge.send({ ...activation, nodeId })\n else bridge.send(activation)\n applyFocus()\n }\n\n const handlePointerOver = (event: PointerEvent) =>\n hoverElements(event.target instanceof Element ? event.target : undefined)\n\n const handlePointerOut = (event: PointerEvent) => {\n if (!(event.relatedTarget instanceof Element)) hoverElements()\n }\n\n let mutationQueued = false\n\n const observer = new MutationObserver((records) => {\n if (\n records.every((record) => record.target instanceof Element && record.target.closest('[data-cms-preview-overlay]'))\n )\n return\n\n if (mutationQueued) return\n mutationQueued = true\n queueMicrotask(() => {\n mutationQueued = false\n\n if (!active) return\n hoverElements()\n decoratePreviewTargets(root)\n\n if (desiredFocus) applyFocus(false)\n })\n })\n\n root.addEventListener('click', handleClick, true)\n root.addEventListener('pointerover', handlePointerOver, true)\n root.addEventListener('pointerout', handlePointerOut, true)\n observer.observe(root.documentElement, { childList: true, subtree: true })\n\n return () => {\n stopBridge()\n stopManifest()\n observer.disconnect()\n selection.destroy()\n hover.destroy()\n root.removeEventListener('click', handleClick, true)\n root.removeEventListener('pointerover', handlePointerOver, true)\n root.removeEventListener('pointerout', handlePointerOut, true)\n clearPreviewTargets(root)\n }\n}\n\nfunction revealElement(element: Element | undefined, view: Window): void {\n if (!element) return\n const rect = element.getBoundingClientRect()\n\n if (rect.bottom > 0 && rect.top < view.innerHeight && rect.right > 0 && rect.left < view.innerWidth) return\n element.scrollIntoView({\n behavior: 'instant',\n block: 'center',\n inline: 'nearest',\n })\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
//#region src/runtime/preview/overlay.ts
|
|
2
|
+
/** Preview-only chrome stays separate from the website's layout and element styles. */
|
|
3
|
+
function mountPreviewOverlay(root, view, kind = "selection") {
|
|
4
|
+
const host = root.createElement("div");
|
|
5
|
+
host.setAttribute("data-cms-preview-overlay", "");
|
|
6
|
+
host.setAttribute("aria-hidden", "true");
|
|
7
|
+
root.documentElement.append(host);
|
|
8
|
+
let targets = [];
|
|
9
|
+
let outlines = [];
|
|
10
|
+
let frame = 0;
|
|
11
|
+
const position = () => {
|
|
12
|
+
let labelled = false;
|
|
13
|
+
for (const [index, element] of targets.entries()) {
|
|
14
|
+
const outline = outlines[index];
|
|
15
|
+
if (!outline) continue;
|
|
16
|
+
const rect = element.getBoundingClientRect();
|
|
17
|
+
const visible = element.isConnected && (kind !== "hover" || !element.hasAttribute("data-cms-selected")) && rect.width > 0 && rect.height > 0 && rect.bottom > 0 && rect.top < view.innerHeight && rect.right > 0 && rect.left < view.innerWidth;
|
|
18
|
+
outline.hidden = !visible;
|
|
19
|
+
outline.toggleAttribute("data-cms-selection-label", kind === "selection" && visible && !labelled);
|
|
20
|
+
if (!visible) continue;
|
|
21
|
+
labelled = true;
|
|
22
|
+
const left = Math.max(2, rect.left - 3);
|
|
23
|
+
const right = Math.min(view.innerWidth - 2, rect.right + 3);
|
|
24
|
+
outline.style.left = `${left}px`;
|
|
25
|
+
outline.style.top = `${rect.top - 3}px`;
|
|
26
|
+
outline.style.width = `${Math.max(0, right - left)}px`;
|
|
27
|
+
outline.style.height = `${rect.height + 6}px`;
|
|
28
|
+
outline.style.setProperty("--cms-label-left", `${Math.max(0, Math.min(view.innerWidth - 76, left) - left)}px`);
|
|
29
|
+
outline.style.setProperty("--cms-label-top", `${Math.max(4 - rect.top, rect.top >= 30 ? -26 : 4)}px`);
|
|
30
|
+
}
|
|
31
|
+
frame = targets.length ? view.requestAnimationFrame(position) : 0;
|
|
32
|
+
};
|
|
33
|
+
return {
|
|
34
|
+
set(elements) {
|
|
35
|
+
if (elements.length === targets.length && elements.every((element, index) => element === targets[index])) return;
|
|
36
|
+
if (frame) view.cancelAnimationFrame(frame);
|
|
37
|
+
targets = elements;
|
|
38
|
+
outlines = elements.map(() => {
|
|
39
|
+
const outline = root.createElement("div");
|
|
40
|
+
outline.setAttribute(kind === "selection" ? "data-cms-selection-outline" : "data-cms-hover-outline", "");
|
|
41
|
+
if (kind === "hover") for (const corner of [
|
|
42
|
+
"top-left",
|
|
43
|
+
"top-right",
|
|
44
|
+
"bottom-right",
|
|
45
|
+
"bottom-left"
|
|
46
|
+
]) {
|
|
47
|
+
const mark = root.createElement("span");
|
|
48
|
+
mark.setAttribute("data-cms-hover-corner", corner);
|
|
49
|
+
outline.append(mark);
|
|
50
|
+
}
|
|
51
|
+
return outline;
|
|
52
|
+
});
|
|
53
|
+
host.replaceChildren(...outlines);
|
|
54
|
+
position();
|
|
55
|
+
},
|
|
56
|
+
destroy() {
|
|
57
|
+
if (frame) view.cancelAnimationFrame(frame);
|
|
58
|
+
host.remove();
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
//#endregion
|
|
64
|
+
export { mountPreviewOverlay };
|
|
65
|
+
//# sourceMappingURL=overlay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overlay.js","names":[],"sources":["../../../../../src/runtime/preview/overlay.ts"],"sourcesContent":["/** Preview-only chrome stays separate from the website's layout and element styles. */\nexport function mountPreviewOverlay(root: Document, view: Window, kind: 'selection' | 'hover' = 'selection') {\n const host = root.createElement('div')\n host.setAttribute('data-cms-preview-overlay', '')\n host.setAttribute('aria-hidden', 'true')\n root.documentElement.append(host)\n let targets: ReadonlyArray<Element> = []\n let outlines: Array<HTMLElement> = []\n let frame = 0\n\n const position = (): void => {\n let labelled = false\n\n for (const [index, element] of targets.entries()) {\n const outline = outlines[index]\n\n if (!outline) continue\n const rect = element.getBoundingClientRect()\n\n const visible =\n element.isConnected &&\n (kind !== 'hover' || !element.hasAttribute('data-cms-selected')) &&\n rect.width > 0 &&\n rect.height > 0 &&\n rect.bottom > 0 &&\n rect.top < view.innerHeight &&\n rect.right > 0 &&\n rect.left < view.innerWidth\n\n outline.hidden = !visible\n outline.toggleAttribute('data-cms-selection-label', kind === 'selection' && visible && !labelled)\n\n if (!visible) continue\n labelled = true\n const left = Math.max(2, rect.left - 3)\n const right = Math.min(view.innerWidth - 2, rect.right + 3)\n outline.style.left = `${left}px`\n outline.style.top = `${rect.top - 3}px`\n outline.style.width = `${Math.max(0, right - left)}px`\n outline.style.height = `${rect.height + 6}px`\n outline.style.setProperty('--cms-label-left', `${Math.max(0, Math.min(view.innerWidth - 76, left) - left)}px`)\n outline.style.setProperty('--cms-label-top', `${Math.max(4 - rect.top, rect.top >= 30 ? -26 : 4)}px`)\n }\n\n frame = targets.length ? view.requestAnimationFrame(position) : 0\n }\n\n return {\n set(elements: ReadonlyArray<Element>): void {\n if (elements.length === targets.length && elements.every((element, index) => element === targets[index])) return\n\n if (frame) view.cancelAnimationFrame(frame)\n targets = elements\n outlines = elements.map(() => {\n const outline = root.createElement('div')\n outline.setAttribute(kind === 'selection' ? 'data-cms-selection-outline' : 'data-cms-hover-outline', '')\n\n if (kind === 'hover') {\n for (const corner of ['top-left', 'top-right', 'bottom-right', 'bottom-left']) {\n const mark = root.createElement('span')\n mark.setAttribute('data-cms-hover-corner', corner)\n outline.append(mark)\n }\n }\n\n return outline\n })\n host.replaceChildren(...outlines)\n position()\n },\n destroy(): void {\n if (frame) view.cancelAnimationFrame(frame)\n host.remove()\n },\n }\n}\n"],"mappings":";;AACA,SAAgB,oBAAoB,MAAgB,MAAc,OAA8B,aAAa;CAC3G,MAAM,OAAO,KAAK,cAAc,KAAK;CACrC,KAAK,aAAa,4BAA4B,EAAE;CAChD,KAAK,aAAa,eAAe,MAAM;CACvC,KAAK,gBAAgB,OAAO,IAAI;CAChC,IAAI,UAAkC,CAAC;CACvC,IAAI,WAA+B,CAAC;CACpC,IAAI,QAAQ;CAEZ,MAAM,iBAAuB;EAC3B,IAAI,WAAW;EAEf,KAAK,MAAM,CAAC,OAAO,YAAY,QAAQ,QAAQ,GAAG;GAChD,MAAM,UAAU,SAAS;GAEzB,IAAI,CAAC,SAAS;GACd,MAAM,OAAO,QAAQ,sBAAsB;GAE3C,MAAM,UACJ,QAAQ,gBACP,SAAS,WAAW,CAAC,QAAQ,aAAa,mBAAmB,MAC9D,KAAK,QAAQ,KACb,KAAK,SAAS,KACd,KAAK,SAAS,KACd,KAAK,MAAM,KAAK,eAChB,KAAK,QAAQ,KACb,KAAK,OAAO,KAAK;GAEnB,QAAQ,SAAS,CAAC;GAClB,QAAQ,gBAAgB,4BAA4B,SAAS,eAAe,WAAW,CAAC,QAAQ;GAEhG,IAAI,CAAC,SAAS;GACd,WAAW;GACX,MAAM,OAAO,KAAK,IAAI,GAAG,KAAK,OAAO,CAAC;GACtC,MAAM,QAAQ,KAAK,IAAI,KAAK,aAAa,GAAG,KAAK,QAAQ,CAAC;GAC1D,QAAQ,MAAM,OAAO,GAAG,KAAK;GAC7B,QAAQ,MAAM,MAAM,GAAG,KAAK,MAAM,EAAE;GACpC,QAAQ,MAAM,QAAQ,GAAG,KAAK,IAAI,GAAG,QAAQ,IAAI,EAAE;GACnD,QAAQ,MAAM,SAAS,GAAG,KAAK,SAAS,EAAE;GAC1C,QAAQ,MAAM,YAAY,oBAAoB,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,aAAa,IAAI,IAAI,IAAI,IAAI,EAAE,GAAG;GAC7G,QAAQ,MAAM,YAAY,mBAAmB,GAAG,KAAK,IAAI,IAAI,KAAK,KAAK,KAAK,OAAO,KAAK,MAAM,CAAC,EAAE,GAAG;EACtG;EAEA,QAAQ,QAAQ,SAAS,KAAK,sBAAsB,QAAQ,IAAI;CAClE;CAEA,OAAO;EACL,IAAI,UAAwC;GAC1C,IAAI,SAAS,WAAW,QAAQ,UAAU,SAAS,OAAO,SAAS,UAAU,YAAY,QAAQ,MAAM,GAAG;GAE1G,IAAI,OAAO,KAAK,qBAAqB,KAAK;GAC1C,UAAU;GACV,WAAW,SAAS,UAAU;IAC5B,MAAM,UAAU,KAAK,cAAc,KAAK;IACxC,QAAQ,aAAa,SAAS,cAAc,+BAA+B,0BAA0B,EAAE;IAEvG,IAAI,SAAS,SACX,KAAK,MAAM,UAAU;KAAC;KAAY;KAAa;KAAgB;IAAa,GAAG;KAC7E,MAAM,OAAO,KAAK,cAAc,MAAM;KACtC,KAAK,aAAa,yBAAyB,MAAM;KACjD,QAAQ,OAAO,IAAI;IACrB;IAGF,OAAO;GACT,CAAC;GACD,KAAK,gBAAgB,GAAG,QAAQ;GAChC,SAAS;EACX;EACA,UAAgB;GACd,IAAI,OAAO,KAAK,qBAAqB,KAAK;GAC1C,KAAK,OAAO;EACd;CACF;AACF"}
|
|
@@ -1,68 +1,66 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { o as PublicPath } from "../../scalars-B2lgGUnj.js";
|
|
2
|
+
import { t as openSitePreviewConnection } from "../../connection-B-iz0Y9Y.js";
|
|
3
|
+
import { n as readPreviewLocation, r as withPreviewLocation } from "../../location-CFKTeK1K.js";
|
|
4
|
+
import { formComponentsKey } from "../delivery/blocks.js";
|
|
4
5
|
import { documentPreviewStoreKey } from "../delivery/preview.js";
|
|
5
6
|
import { mountPreviewController } from "./controller.js";
|
|
6
|
-
import { t as createStudioPreviewStore } from "../../store-
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { t as createStudioPreviewStore } from "../../store-DjJs3I7k.js";
|
|
8
|
+
import { Result, Schema } from "effect";
|
|
9
|
+
import { inject, watch } from "vue";
|
|
10
|
+
import { defineNuxtPlugin, navigateTo, onNuxtReady, useNuxtApp, useState } from "nuxt/app";
|
|
9
11
|
|
|
10
|
-
//#region ../protocol/src/internal/preview/location.ts
|
|
11
|
-
const ENABLED_PARAMETER = "_cms_preview";
|
|
12
|
-
const EDITOR_ORIGIN_PARAMETER = "_cms_preview_editor_origin";
|
|
13
|
-
const SESSION_PARAMETER = "_cms_preview_session";
|
|
14
|
-
const PreviewLocationParameters = Schema.Struct({
|
|
15
|
-
editorOrigin: PreviewOrigin,
|
|
16
|
-
sessionId: PreviewSessionId
|
|
17
|
-
});
|
|
18
|
-
function readPreviewLocation(url) {
|
|
19
|
-
if (!url.searchParams.has(ENABLED_PARAMETER)) return void 0;
|
|
20
|
-
return Schema.decodeUnknownOption(PreviewLocationParameters)({
|
|
21
|
-
editorOrigin: url.searchParams.get(EDITOR_ORIGIN_PARAMETER),
|
|
22
|
-
sessionId: url.searchParams.get(SESSION_PARAMETER)
|
|
23
|
-
}).pipe(Option.getOrUndefined);
|
|
24
|
-
}
|
|
25
|
-
function withPreviewLocation(url, parameters) {
|
|
26
|
-
const next = new URL(url);
|
|
27
|
-
next.searchParams.set(ENABLED_PARAMETER, "1");
|
|
28
|
-
next.searchParams.set(EDITOR_ORIGIN_PARAMETER, parameters.editorOrigin);
|
|
29
|
-
next.searchParams.set(SESSION_PARAMETER, parameters.sessionId);
|
|
30
|
-
return next;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
//#endregion
|
|
34
12
|
//#region src/runtime/preview/plugin.client.ts
|
|
35
|
-
var plugin_client_default = defineNuxtPlugin(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
13
|
+
var plugin_client_default = defineNuxtPlugin({
|
|
14
|
+
name: "cms-preview",
|
|
15
|
+
dependsOn: ["cms-blocks"],
|
|
16
|
+
setup: () => {
|
|
17
|
+
const parameters = readPreviewLocation(new URL(window.location.href));
|
|
18
|
+
if (!parameters) return;
|
|
19
|
+
const route = () => Result.getOrThrow(Schema.decodeResult(PublicPath)(window.location.pathname));
|
|
20
|
+
const forms = inject(formComponentsKey);
|
|
21
|
+
const store = createStudioPreviewStore(route, () => forms?.value ?? []);
|
|
22
|
+
const nuxtApp = useNuxtApp();
|
|
23
|
+
nuxtApp.vueApp.provide(documentPreviewStoreKey, store);
|
|
24
|
+
nuxtApp.hooks.hook("page:finish", store.routeChanged);
|
|
25
|
+
const error = useState("cms:preview-error", () => null);
|
|
26
|
+
let patchError = null;
|
|
27
|
+
const mount = async () => {
|
|
28
|
+
const connection = await openSitePreviewConnection({
|
|
29
|
+
editorOrigin: parameters.editorOrigin,
|
|
30
|
+
route: route(),
|
|
31
|
+
sessionId: parameters.sessionId
|
|
32
|
+
});
|
|
33
|
+
const sendError = () => connection.send({
|
|
34
|
+
type: "preview:error",
|
|
35
|
+
message: error.value ?? patchError
|
|
36
|
+
});
|
|
37
|
+
const stopError = watch(error, sendError, { immediate: true });
|
|
38
|
+
const stopConnect = connection.subscribe((message) => {
|
|
39
|
+
if (message.type === "studio:connect") sendError();
|
|
40
|
+
});
|
|
41
|
+
const unmount = mountPreviewController({
|
|
42
|
+
bridge: connection,
|
|
43
|
+
onPatchError: (message) => {
|
|
44
|
+
patchError = message;
|
|
45
|
+
sendError();
|
|
46
|
+
},
|
|
47
|
+
navigate: async (path) => {
|
|
48
|
+
const target = withPreviewLocation(new URL(path, window.location.origin), parameters);
|
|
49
|
+
await navigateTo(`${target.pathname}${target.search}${target.hash}`);
|
|
50
|
+
},
|
|
51
|
+
root: document,
|
|
52
|
+
store,
|
|
53
|
+
view: window
|
|
54
|
+
});
|
|
55
|
+
window.addEventListener("pagehide", () => {
|
|
56
|
+
stopError();
|
|
57
|
+
stopConnect();
|
|
58
|
+
unmount();
|
|
59
|
+
connection.close();
|
|
60
|
+
}, { once: true });
|
|
61
|
+
};
|
|
62
|
+
onNuxtReady(mount);
|
|
63
|
+
}
|
|
66
64
|
});
|
|
67
65
|
|
|
68
66
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.client.js","names":[
|
|
1
|
+
{"version":3,"file":"plugin.client.js","names":[],"sources":["../../../../../src/runtime/preview/plugin.client.ts"],"sourcesContent":["import { formComponentsKey } from '../delivery/blocks'\nimport { defineNuxtPlugin, navigateTo, onNuxtReady, useNuxtApp, useState } from 'nuxt/app'\nimport { inject, watch } from 'vue'\nimport { PublicPath } from '@internal/protocol/Documents'\nimport { readPreviewLocation, withPreviewLocation } from '@internal/protocol/Preview'\nimport { Result, Schema } from 'effect'\nimport { openSitePreviewConnection } from './connection'\nimport { mountPreviewController } from './controller'\nimport { createStudioPreviewStore, documentPreviewStoreKey } from './store'\n\nexport default defineNuxtPlugin({\n name: 'cms-preview',\n dependsOn: ['cms-blocks'],\n setup: () => {\n const parameters = readPreviewLocation(new URL(window.location.href))\n\n if (!parameters) return\n const route = () => Result.getOrThrow(Schema.decodeResult(PublicPath)(window.location.pathname))\n const forms = inject(formComponentsKey)\n const store = createStudioPreviewStore(route, () => forms?.value ?? [])\n const nuxtApp = useNuxtApp()\n nuxtApp.vueApp.provide(documentPreviewStoreKey, store)\n nuxtApp.hooks.hook('page:finish', store.routeChanged)\n\n const error = useState<string | null>('cms:preview-error', () => null)\n let patchError: string | null = null\n\n const mount = async () => {\n const connection = await openSitePreviewConnection({\n editorOrigin: parameters.editorOrigin,\n route: route(),\n sessionId: parameters.sessionId,\n })\n\n const sendError = () => connection.send({ type: 'preview:error', message: error.value ?? patchError })\n const stopError = watch(error, sendError, { immediate: true })\n\n const stopConnect = connection.subscribe((message) => {\n if (message.type === 'studio:connect') sendError()\n })\n\n const unmount = mountPreviewController({\n bridge: connection,\n onPatchError: (message) => {\n patchError = message\n sendError()\n },\n navigate: async (path) => {\n const target = withPreviewLocation(new URL(path, window.location.origin), parameters)\n await navigateTo(`${target.pathname}${target.search}${target.hash}`)\n },\n root: document,\n store,\n view: window,\n })\n\n window.addEventListener(\n 'pagehide',\n () => {\n stopError()\n stopConnect()\n unmount()\n void connection.close()\n },\n { once: true },\n )\n }\n\n onNuxtReady(mount)\n },\n})\n"],"mappings":";;;;;;;;;;;;AAUA,4BAAe,iBAAiB;CAC9B,MAAM;CACN,WAAW,CAAC,YAAY;CACxB,aAAa;EACX,MAAM,aAAa,oBAAoB,IAAI,IAAI,OAAO,SAAS,IAAI,CAAC;EAEpE,IAAI,CAAC,YAAY;EACjB,MAAM,cAAc,OAAO,WAAW,OAAO,aAAa,UAAU,CAAC,CAAC,OAAO,SAAS,QAAQ,CAAC;EAC/F,MAAM,QAAQ,OAAO,iBAAiB;EACtC,MAAM,QAAQ,yBAAyB,aAAa,OAAO,SAAS,CAAC,CAAC;EACtE,MAAM,UAAU,WAAW;EAC3B,QAAQ,OAAO,QAAQ,yBAAyB,KAAK;EACrD,QAAQ,MAAM,KAAK,eAAe,MAAM,YAAY;EAEpD,MAAM,QAAQ,SAAwB,2BAA2B,IAAI;EACrE,IAAI,aAA4B;EAEhC,MAAM,QAAQ,YAAY;GACxB,MAAM,aAAa,MAAM,0BAA0B;IACjD,cAAc,WAAW;IACzB,OAAO,MAAM;IACb,WAAW,WAAW;GACxB,CAAC;GAED,MAAM,kBAAkB,WAAW,KAAK;IAAE,MAAM;IAAiB,SAAS,MAAM,SAAS;GAAW,CAAC;GACrG,MAAM,YAAY,MAAM,OAAO,WAAW,EAAE,WAAW,KAAK,CAAC;GAE7D,MAAM,cAAc,WAAW,WAAW,YAAY;IACpD,IAAI,QAAQ,SAAS,kBAAkB,UAAU;GACnD,CAAC;GAED,MAAM,UAAU,uBAAuB;IACrC,QAAQ;IACR,eAAe,YAAY;KACzB,aAAa;KACb,UAAU;IACZ;IACA,UAAU,OAAO,SAAS;KACxB,MAAM,SAAS,oBAAoB,IAAI,IAAI,MAAM,OAAO,SAAS,MAAM,GAAG,UAAU;KACpF,MAAM,WAAW,GAAG,OAAO,WAAW,OAAO,SAAS,OAAO,MAAM;IACrE;IACA,MAAM;IACN;IACA,MAAM;GACR,CAAC;GAED,OAAO,iBACL,kBACM;IACJ,UAAU;IACV,YAAY;IACZ,QAAQ;IACR,AAAK,WAAW,MAAM;GACxB,GACA,EAAE,MAAM,KAAK,CACf;EACF;EAEA,YAAY,KAAK;CACnB;AACF,CAAC"}
|
|
@@ -1,9 +1,77 @@
|
|
|
1
1
|
[data-cms-preview-decorated] {
|
|
2
2
|
cursor: text;
|
|
3
|
-
outline-offset: 3px;
|
|
4
3
|
}
|
|
5
4
|
|
|
6
|
-
[data-cms-preview-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
[data-cms-preview-overlay] {
|
|
6
|
+
pointer-events: none !important;
|
|
7
|
+
position: fixed;
|
|
8
|
+
inset: 0;
|
|
9
|
+
z-index: 2147483647;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
[data-cms-selection-outline],
|
|
13
|
+
[data-cms-hover-outline] {
|
|
14
|
+
all: initial;
|
|
15
|
+
box-sizing: border-box;
|
|
16
|
+
position: fixed;
|
|
17
|
+
pointer-events: none !important;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
[data-cms-selection-outline] {
|
|
21
|
+
border: 1px solid #fff;
|
|
22
|
+
outline: 1px solid #171717;
|
|
23
|
+
border-radius: 3px;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
[data-cms-selection-outline][hidden],
|
|
27
|
+
[data-cms-hover-outline][hidden] {
|
|
28
|
+
display: none;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
[data-cms-selection-label]::after {
|
|
32
|
+
content: 'Editing';
|
|
33
|
+
position: absolute;
|
|
34
|
+
left: var(--cms-label-left, 0px);
|
|
35
|
+
top: var(--cms-label-top, -26px);
|
|
36
|
+
padding: 3px 7px;
|
|
37
|
+
border: 1px solid #fff;
|
|
38
|
+
border-radius: 4px;
|
|
39
|
+
background: #171717;
|
|
40
|
+
color: #fff;
|
|
41
|
+
font:
|
|
42
|
+
500 11px/16px system-ui,
|
|
43
|
+
sans-serif;
|
|
44
|
+
white-space: nowrap;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
[data-cms-hover-corner] {
|
|
48
|
+
all: initial;
|
|
49
|
+
box-sizing: border-box;
|
|
50
|
+
position: absolute;
|
|
51
|
+
width: min(12px, 40%);
|
|
52
|
+
height: min(12px, 40%);
|
|
53
|
+
border-top: 2px solid #fff;
|
|
54
|
+
border-left: 2px solid #fff;
|
|
55
|
+
pointer-events: none !important;
|
|
56
|
+
filter: drop-shadow(1px 0 #171717) drop-shadow(-1px 0 #171717) drop-shadow(0 1px #171717) drop-shadow(0 -1px #171717);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
[data-cms-hover-corner='top-left'] {
|
|
60
|
+
top: 0;
|
|
61
|
+
left: 0;
|
|
62
|
+
}
|
|
63
|
+
[data-cms-hover-corner='top-right'] {
|
|
64
|
+
top: 0;
|
|
65
|
+
right: 0;
|
|
66
|
+
transform: rotate(90deg);
|
|
67
|
+
}
|
|
68
|
+
[data-cms-hover-corner='bottom-right'] {
|
|
69
|
+
bottom: 0;
|
|
70
|
+
right: 0;
|
|
71
|
+
transform: rotate(180deg);
|
|
72
|
+
}
|
|
73
|
+
[data-cms-hover-corner='bottom-left'] {
|
|
74
|
+
bottom: 0;
|
|
75
|
+
left: 0;
|
|
76
|
+
transform: rotate(270deg);
|
|
9
77
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.js","names":[],"sources":["../../../../../src/runtime/preview/protocol.ts"],"sourcesContent":["export const CMS_PREVIEW_DECORATED_ATTRIBUTE = 'data-cms-preview-decorated'\nexport const CMS_PREVIEW_INLINE_HOST_ATTRIBUTE = 'data-cms-inline-host'\nexport const CMS_PREVIEW_NODE_ATTRIBUTE = 'data-cms-node'\nexport const CMS_PREVIEW_MARKER_TAG = 'cms-studio-preview-marker'\nexport const CMS_PREVIEW_TARGET_ATTRIBUTE = 'data-cms-target'\nexport const CMS_PREVIEW_WRAPPER_ATTRIBUTE = 'data-cms-marker'\n\nexport type CmsPreviewTargetKind = 'component' | 'native' | 'slot'\n"],"mappings":";AAAA,MAAa,kCAAkC;
|
|
1
|
+
{"version":3,"file":"protocol.js","names":[],"sources":["../../../../../src/runtime/preview/protocol.ts"],"sourcesContent":["export const CMS_PREVIEW_DECORATED_ATTRIBUTE = 'data-cms-preview-decorated'\n\nexport const CMS_PREVIEW_INLINE_HOST_ATTRIBUTE = 'data-cms-inline-host'\n\nexport const CMS_PREVIEW_NODE_ATTRIBUTE = 'data-cms-node'\n\nexport const CMS_PREVIEW_MARKER_TAG = 'cms-studio-preview-marker'\n\nexport const CMS_PREVIEW_TARGET_ATTRIBUTE = 'data-cms-target'\n\nexport const CMS_PREVIEW_WRAPPER_ATTRIBUTE = 'data-cms-marker'\n\nexport type CmsPreviewTargetKind = 'component' | 'native' | 'slot'\n"],"mappings":";AAAA,MAAa,kCAAkC;AAE/C,MAAa,oCAAoC;AAEjD,MAAa,6BAA6B;AAE1C,MAAa,yBAAyB;AAEtC,MAAa,+BAA+B;AAE5C,MAAa,gCAAgC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { documentPreviewStoreKey } from "../delivery/preview.js";
|
|
2
|
-
import { t as createStudioPreviewStore } from "../../store-
|
|
2
|
+
import { t as createStudioPreviewStore } from "../../store-DjJs3I7k.js";
|
|
3
3
|
|
|
4
4
|
export { createStudioPreviewStore, documentPreviewStoreKey };
|
|
@@ -6,7 +6,6 @@ const TARGET_PRIORITY = {
|
|
|
6
6
|
native: 3,
|
|
7
7
|
slot: 2
|
|
8
8
|
};
|
|
9
|
-
/** Picks the deepest authorable target represented by the clicked rendered element. */
|
|
10
9
|
function findPreviewNodeId(root, clicked) {
|
|
11
10
|
const candidates = collectPreviewTargets(root).filter((target) => target.elements.some((element) => element === clicked || element.contains(clicked)));
|
|
12
11
|
candidates.sort((left, right) => Number(right.kind === "native") - Number(left.kind === "native") || targetDepth(right) - targetDepth(left) || TARGET_PRIORITY[right.kind] - TARGET_PRIORITY[left.kind] || targetArea(left) - targetArea(right));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"targets.js","names":[],"sources":["../../../../../src/runtime/preview/targets.ts"],"sourcesContent":["import type { CmsPreviewTargetKind } from './protocol'\nimport {\n CMS_PREVIEW_DECORATED_ATTRIBUTE,\n CMS_PREVIEW_INLINE_HOST_ATTRIBUTE,\n CMS_PREVIEW_NODE_ATTRIBUTE,\n CMS_PREVIEW_TARGET_ATTRIBUTE,\n CMS_PREVIEW_WRAPPER_ATTRIBUTE,\n} from './protocol'\n\ninterface PreviewTarget {\n readonly elements: ReadonlyArray<Element>\n readonly id: string\n readonly kind: CmsPreviewTargetKind\n}\n\nexport interface ResolvedPreviewTarget {\n readonly elements: ReadonlyArray<Element>\n readonly resolvedNodeId?: string\n}\n\nconst TARGET_PRIORITY = { component: 1, native: 3, slot: 2 } satisfies Record<CmsPreviewTargetKind, number>\n\
|
|
1
|
+
{"version":3,"file":"targets.js","names":[],"sources":["../../../../../src/runtime/preview/targets.ts"],"sourcesContent":["import type { CmsPreviewTargetKind } from './protocol'\nimport {\n CMS_PREVIEW_DECORATED_ATTRIBUTE,\n CMS_PREVIEW_INLINE_HOST_ATTRIBUTE,\n CMS_PREVIEW_NODE_ATTRIBUTE,\n CMS_PREVIEW_TARGET_ATTRIBUTE,\n CMS_PREVIEW_WRAPPER_ATTRIBUTE,\n} from './protocol'\n\ninterface PreviewTarget {\n readonly elements: ReadonlyArray<Element>\n readonly id: string\n readonly kind: CmsPreviewTargetKind\n}\n\nexport interface ResolvedPreviewTarget {\n readonly elements: ReadonlyArray<Element>\n readonly resolvedNodeId?: string\n}\n\nconst TARGET_PRIORITY = { component: 1, native: 3, slot: 2 } satisfies Record<CmsPreviewTargetKind, number>\n\nexport function findPreviewNodeId(root: ParentNode, clicked: Element): string | undefined {\n const candidates = collectPreviewTargets(root).filter((target) =>\n target.elements.some((element) => element === clicked || element.contains(clicked)),\n )\n\n candidates.sort(\n (left, right) =>\n Number(right.kind === 'native') - Number(left.kind === 'native') ||\n targetDepth(right) - targetDepth(left) ||\n TARGET_PRIORITY[right.kind] - TARGET_PRIORITY[left.kind] ||\n targetArea(left) - targetArea(right),\n )\n\n return candidates[0]?.id\n}\n\nexport function resolvePreviewTarget(\n root: ParentNode,\n nodeId: string,\n fallbacks: Readonly<Record<string, string>>,\n): ResolvedPreviewTarget {\n const visited = new Set<string>()\n const targets = collectPreviewTargets(root)\n let targetId: string | undefined = nodeId\n\n while (targetId && !visited.has(targetId)) {\n visited.add(targetId)\n\n const elements = [\n ...new Set(targets.filter((target) => target.id === targetId).flatMap((target) => target.elements)),\n ]\n\n if (elements.length) return { elements, resolvedNodeId: targetId }\n targetId = fallbacks[targetId]\n }\n\n return { elements: [] }\n}\n\nexport function decoratePreviewTargets(root: ParentNode): void {\n for (const target of collectPreviewTargets(root)) {\n for (const element of target.elements) element.setAttribute(CMS_PREVIEW_DECORATED_ATTRIBUTE, '')\n }\n}\n\nexport function clearPreviewTargets(root: ParentNode): void {\n for (const element of root.querySelectorAll(\n `[${CMS_PREVIEW_DECORATED_ATTRIBUTE}], [data-cms-hovered], [data-cms-selected]`,\n )) {\n element.removeAttribute(CMS_PREVIEW_DECORATED_ATTRIBUTE)\n element.removeAttribute('data-cms-hovered')\n element.removeAttribute('data-cms-selected')\n }\n}\n\nexport function nearestPreviewElement(elements: ReadonlyArray<Element>): Element | undefined {\n const viewportCenter = window.innerHeight / 2\n\n return [...elements].sort(\n (left, right) => viewportDistance(left, viewportCenter) - viewportDistance(right, viewportCenter),\n )[0]\n}\n\nfunction collectPreviewTargets(root: ParentNode): ReadonlyArray<PreviewTarget> {\n return [...root.querySelectorAll(`[${CMS_PREVIEW_NODE_ATTRIBUTE}]`)].flatMap((marker) => {\n const id = marker.getAttribute(CMS_PREVIEW_NODE_ATTRIBUTE)\n const kind = previewTargetKind(marker.getAttribute(CMS_PREVIEW_TARGET_ATTRIBUTE))\n\n return id && kind ? [{ elements: resolveMarkerElements(marker, kind), id, kind }] : []\n })\n}\n\nfunction resolveMarkerElements(marker: Element, kind: CmsPreviewTargetKind): ReadonlyArray<Element> {\n const isWrapper = marker.hasAttribute(CMS_PREVIEW_WRAPPER_ATTRIBUTE)\n\n if (marker.hasAttribute(CMS_PREVIEW_INLINE_HOST_ATTRIBUTE) && isConcreteElement(marker)) return [marker]\n\n if (!isWrapper && isConcreteElement(marker)) return [marker]\n const children = [...marker.children].filter(isConcreteElement)\n\n if (isWrapper && children.length) return children\n\n if (isWrapper && (kind === 'native' || kind === 'slot')) {\n const parent = marker.parentElement\n\n return parent && isConcreteElement(parent) ? [parent] : []\n }\n\n return children\n}\n\nfunction isConcreteElement(element: Element): boolean {\n const view = element.ownerDocument.defaultView\n\n if (!view || view.getComputedStyle(element).display === 'contents') return false\n\n return [...element.getClientRects()].some((rect) => rect.width > 0 && rect.height > 0)\n}\n\nfunction previewTargetKind(value: string | null): CmsPreviewTargetKind | undefined {\n return value === 'component' || value === 'native' || value === 'slot' ? value : undefined\n}\n\nfunction targetDepth(target: PreviewTarget): number {\n return Math.max(0, ...target.elements.map(elementDepth))\n}\n\nfunction elementDepth(element: Element): number {\n let depth = 0\n let current = element.parentElement\n\n while (current) {\n depth++\n current = current.parentElement\n }\n\n return depth\n}\n\nfunction targetArea(target: PreviewTarget): number {\n return Math.min(\n Infinity,\n ...target.elements.map((element) => {\n const rect = element.getBoundingClientRect()\n\n return rect.width * rect.height\n }),\n )\n}\n\nfunction viewportDistance(element: Element, viewportCenter: number): number {\n const rect = element.getBoundingClientRect()\n const visible = rect.bottom >= 0 && rect.top <= window.innerHeight\n const distance = Math.abs((rect.top + rect.bottom) / 2 - viewportCenter)\n\n return visible ? distance : window.innerHeight + distance\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { DateTime } from "effect";
|
|
2
|
+
|
|
3
|
+
//#region src/runtime/sitemap-entries.ts
|
|
4
|
+
function toNuxtSitemapEntries(entries) {
|
|
5
|
+
return entries.map((entry) => ({
|
|
6
|
+
loc: entry.loc,
|
|
7
|
+
lastmod: DateTime.formatIso(entry.lastmod),
|
|
8
|
+
...entry.alternatives ? { alternatives: entry.alternatives.map((alternative) => ({
|
|
9
|
+
href: alternative.loc,
|
|
10
|
+
hreflang: alternative.locale
|
|
11
|
+
})) } : void 0
|
|
12
|
+
}));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
//#endregion
|
|
16
|
+
export { toNuxtSitemapEntries };
|
|
17
|
+
//# sourceMappingURL=sitemap-entries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sitemap-entries.js","names":[],"sources":["../../../../src/runtime/sitemap-entries.ts"],"sourcesContent":["import type { SitemapEntry } from '@internal/protocol/Seo'\nimport { DateTime } from 'effect'\n\nexport interface NuxtSitemapEntry {\n readonly loc: string\n readonly lastmod: string\n readonly alternatives?: ReadonlyArray<{\n readonly hreflang: string\n readonly href: string\n }>\n}\n\nexport function toNuxtSitemapEntries(entries: ReadonlyArray<SitemapEntry>): ReadonlyArray<NuxtSitemapEntry> {\n return entries.map((entry) => ({\n loc: entry.loc,\n lastmod: DateTime.formatIso(entry.lastmod),\n ...(entry.alternatives\n ? {\n alternatives: entry.alternatives.map((alternative) => ({\n href: alternative.loc,\n hreflang: alternative.locale,\n })),\n }\n : undefined),\n }))\n}\n"],"mappings":";;;AAYA,SAAgB,qBAAqB,SAAuE;CAC1G,OAAO,QAAQ,KAAK,WAAW;EAC7B,KAAK,MAAM;EACX,SAAS,SAAS,UAAU,MAAM,OAAO;EACzC,GAAI,MAAM,eACN,EACE,cAAc,MAAM,aAAa,KAAK,iBAAiB;GACrD,MAAM,YAAY;GAClB,UAAU,YAAY;EACxB,EAAE,EACJ,IACA;CACN,EAAE;AACJ"}
|