@phtngyn/cms 0.1.0-beta.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.
Files changed (120) hide show
  1. package/LICENSE +13 -0
  2. package/README.md +90 -0
  3. package/dist/studio/assets/ActivityEntryRow-D--fRvWI.js +1 -0
  4. package/dist/studio/assets/ActivityView-D-XBBUHb.js +1 -0
  5. package/dist/studio/assets/CreateDocumentDialog-CH8UH1QM.js +1 -0
  6. package/dist/studio/assets/DocumentsView-CxRpmAxt.js +34 -0
  7. package/dist/studio/assets/DropdownMenu-BSb1l7fr.js +1 -0
  8. package/dist/studio/assets/Input-DVao38h7.js +3 -0
  9. package/dist/studio/assets/MediaView-BHrPIjxB.js +1 -0
  10. package/dist/studio/assets/Modal-VNrXGa5C.js +1 -0
  11. package/dist/studio/assets/OverviewView-DfP6-mLZ.js +1 -0
  12. package/dist/studio/assets/Select-BJZIs9sY.js +1 -0
  13. package/dist/studio/assets/SettingsView-CerHe-ua.js +1 -0
  14. package/dist/studio/assets/Skeleton-CWJNi3nS.js +1 -0
  15. package/dist/studio/assets/StudioPageHeader-DP9HDAF2.js +1 -0
  16. package/dist/studio/assets/UsersView-cP3REkH2.js +1 -0
  17. package/dist/studio/assets/collaboration-BLnCzfvV.js +4 -0
  18. package/dist/studio/assets/context-dY4fNbn3.js +1 -0
  19. package/dist/studio/assets/editor-CE07wW83.js +137 -0
  20. package/dist/studio/assets/gateway-BAyQgCse.js +10 -0
  21. package/dist/studio/assets/index-CjoaPLhZ.js +28 -0
  22. package/dist/studio/assets/index-s2rPqCmP.css +2 -0
  23. package/dist/studio/assets/render-BkxbK2St.js +83 -0
  24. package/dist/studio/assets/rolldown-runtime-DK3Fl9T5.js +1 -0
  25. package/dist/studio/assets/useMediaLibrary-D7qR7aBf.js +1 -0
  26. package/dist/studio/index.html +76 -0
  27. package/package.json +75 -0
  28. package/src/Authoring.d.ts +46 -0
  29. package/src/Authoring.js +1 -0
  30. package/src/AuthoringSchema-BQ5kbhVB.js +926 -0
  31. package/src/AuthoringSchema-BQ5kbhVB.js.map +1 -0
  32. package/src/Configuration-BGYFD2N1.js +150 -0
  33. package/src/Configuration-BGYFD2N1.js.map +1 -0
  34. package/src/Configuration.d.ts +44 -0
  35. package/src/Configuration.js +9 -0
  36. package/src/Configuration.js.map +1 -0
  37. package/src/DocumentEngine-Da0kWotL.js +851 -0
  38. package/src/DocumentEngine-Da0kWotL.js.map +1 -0
  39. package/src/DocumentModel.d.ts +30 -0
  40. package/src/DocumentModel.js +15 -0
  41. package/src/DocumentModel.js.map +1 -0
  42. package/src/HttpPaths-86qLGB90.js +15 -0
  43. package/src/HttpPaths-86qLGB90.js.map +1 -0
  44. package/src/Module.d.ts +12 -0
  45. package/src/Module.js +167 -0
  46. package/src/Module.js.map +1 -0
  47. package/src/StudioHttp-BTLLooh0.js +916 -0
  48. package/src/StudioHttp-BTLLooh0.js.map +1 -0
  49. package/src/connection-ZGtL54qY.js +94 -0
  50. package/src/connection-ZGtL54qY.js.map +1 -0
  51. package/src/installation-BNKaVjni.js +9128 -0
  52. package/src/installation-BNKaVjni.js.map +1 -0
  53. package/src/internal/authoring-compiler.js +120 -0
  54. package/src/internal/authoring-compiler.js.map +1 -0
  55. package/src/internal/authoring-metadata.js +163 -0
  56. package/src/internal/authoring-metadata.js.map +1 -0
  57. package/src/internal/cms-config.js +46 -0
  58. package/src/internal/cms-config.js.map +1 -0
  59. package/src/internal/component-metadata.js +37 -0
  60. package/src/internal/component-metadata.js.map +1 -0
  61. package/src/internal/configuration.js +93 -0
  62. package/src/internal/configuration.js.map +1 -0
  63. package/src/internal/document-model.js +236 -0
  64. package/src/internal/document-model.js.map +1 -0
  65. package/src/internal/field-metadata.js +6 -0
  66. package/src/internal/field-metadata.js.map +1 -0
  67. package/src/metadata-Czvi3E4K.js +190 -0
  68. package/src/metadata-Czvi3E4K.js.map +1 -0
  69. package/src/models-Citx8jBi.js +306 -0
  70. package/src/models-Citx8jBi.js.map +1 -0
  71. package/src/models-DS5ClMsH.js +153 -0
  72. package/src/models-DS5ClMsH.js.map +1 -0
  73. package/src/runtime/api.js +9 -0
  74. package/src/runtime/api.js.map +1 -0
  75. package/src/runtime/collaboration.js +40 -0
  76. package/src/runtime/collaboration.js.map +1 -0
  77. package/src/runtime/delivery/DocumentField.js +23 -0
  78. package/src/runtime/delivery/DocumentField.js.map +1 -0
  79. package/src/runtime/delivery/DocumentRenderer.js +51 -0
  80. package/src/runtime/delivery/DocumentRenderer.js.map +1 -0
  81. package/src/runtime/delivery/DocumentScope.js +41 -0
  82. package/src/runtime/delivery/DocumentScope.js.map +1 -0
  83. package/src/runtime/delivery/document-page.js +23 -0
  84. package/src/runtime/delivery/document-page.js.map +1 -0
  85. package/src/runtime/delivery/document.js +25 -0
  86. package/src/runtime/delivery/document.js.map +1 -0
  87. package/src/runtime/delivery/preview.d.ts +11 -0
  88. package/src/runtime/delivery/preview.js +6 -0
  89. package/src/runtime/delivery/preview.js.map +1 -0
  90. package/src/runtime/delivery/types.d.ts +80 -0
  91. package/src/runtime/delivery/types.js +1 -0
  92. package/src/runtime/delivery/useDocument.d.ts +6 -0
  93. package/src/runtime/delivery/useDocument.js +20 -0
  94. package/src/runtime/delivery/useDocument.js.map +1 -0
  95. package/src/runtime/delivery/useDocumentQuery.d.ts +7 -0
  96. package/src/runtime/delivery/useDocumentQuery.js +26 -0
  97. package/src/runtime/delivery/useDocumentQuery.js.map +1 -0
  98. package/src/runtime/installation.js +3 -0
  99. package/src/runtime/plugin.js +32 -0
  100. package/src/runtime/plugin.js.map +1 -0
  101. package/src/runtime/preview/CmsStudioPreviewMarker.js +15 -0
  102. package/src/runtime/preview/CmsStudioPreviewMarker.js.map +1 -0
  103. package/src/runtime/preview/comark-document.js +38 -0
  104. package/src/runtime/preview/comark-document.js.map +1 -0
  105. package/src/runtime/preview/connection.js +3 -0
  106. package/src/runtime/preview/controller.js +247 -0
  107. package/src/runtime/preview/controller.js.map +1 -0
  108. package/src/runtime/preview/plugin.client.js +70 -0
  109. package/src/runtime/preview/plugin.client.js.map +1 -0
  110. package/src/runtime/preview/preview.css +9 -0
  111. package/src/runtime/preview/protocol.d.ts +10 -0
  112. package/src/runtime/preview/protocol.js +11 -0
  113. package/src/runtime/preview/protocol.js.map +1 -0
  114. package/src/runtime/preview/store.js +4 -0
  115. package/src/runtime/preview/targets.js +102 -0
  116. package/src/runtime/preview/targets.js.map +1 -0
  117. package/src/runtime/studio-app.js +13 -0
  118. package/src/runtime/studio-app.js.map +1 -0
  119. package/src/store-Nl4uxEXx.js +221 -0
  120. package/src/store-Nl4uxEXx.js.map +1 -0
@@ -0,0 +1,247 @@
1
+ import { V as EditorNodeId, W as RevisionNumber, z as DocumentId } from "../../models-Citx8jBi.js";
2
+ import { a as PreviewIntentId, m as RequestId } from "../../models-DS5ClMsH.js";
3
+ import { clearPreviewTargets, decoratePreviewTargets, findPreviewNodeId, nearestPreviewElement, resolvePreviewTarget } from "./targets.js";
4
+ import { Crypto, Effect, PlatformError, Schema } from "effect";
5
+
6
+ //#region src/runtime/preview/controller.ts
7
+ const browserCrypto = Crypto.make({
8
+ digest: (algorithm, data) => Effect.tryPromise({
9
+ catch: (cause) => PlatformError.systemError({
10
+ _tag: "Unknown",
11
+ cause,
12
+ description: "Could not compute digest",
13
+ method: "digest",
14
+ module: "Crypto"
15
+ }),
16
+ try: () => globalThis.crypto.subtle.digest(algorithm, Uint8Array.from(data)).then((digest) => new Uint8Array(digest))
17
+ }),
18
+ randomBytes: (size) => globalThis.crypto.getRandomValues(new Uint8Array(size))
19
+ });
20
+ const randomUuid = () => Effect.runSync(browserCrypto.randomUUIDv4.pipe(Effect.orDie));
21
+ function mountPreviewController(options) {
22
+ const { bridge, root, store, view } = options;
23
+ let active = false;
24
+ let desiredFocus;
25
+ let fallbacks = {};
26
+ let hoveredElements = [];
27
+ let mode = "edit";
28
+ let renderSequence = 0;
29
+ let revision = RevisionNumber.make(0);
30
+ let selectedElements = [];
31
+ let lastApplied = "";
32
+ let revealedIntentId = "";
33
+ const sendManifest = () => {
34
+ bridge.send({
35
+ manifest: store.manifest(),
36
+ revision,
37
+ type: "preview:manifest"
38
+ });
39
+ };
40
+ const stopManifest = store.subscribe(sendManifest);
41
+ const clearElements = (elements, attribute) => {
42
+ for (const element of elements) element.removeAttribute(attribute);
43
+ };
44
+ const sendApplied = (result) => {
45
+ if (!desiredFocus) return;
46
+ const signature = `${desiredFocus.id}:${result}`;
47
+ if (signature === lastApplied) return;
48
+ lastApplied = signature;
49
+ const applied = {
50
+ intentId: desiredFocus.id,
51
+ result,
52
+ revision,
53
+ type: "preview:applied"
54
+ };
55
+ bridge.send(desiredFocus.nodeId ? {
56
+ ...applied,
57
+ nodeId: desiredFocus.nodeId
58
+ } : applied);
59
+ };
60
+ const documentRoot = (documentId) => [...root.querySelectorAll("[data-cms-document]")].find((element) => element.getAttribute("data-cms-document") === documentId) ?? root;
61
+ const applyFocus = (reveal = false) => {
62
+ clearElements(selectedElements, "data-cms-selected");
63
+ selectedElements = [];
64
+ if (!active || mode !== "edit") return;
65
+ const intent = desiredFocus;
66
+ const nodeId = intent?.nodeId;
67
+ if (!intent || !nodeId) {
68
+ sendApplied("exact");
69
+ return;
70
+ }
71
+ const scope = documentRoot(intent.documentId);
72
+ decoratePreviewTargets(scope);
73
+ const target = resolvePreviewTarget(scope, nodeId, fallbacks);
74
+ selectedElements = target.elements;
75
+ for (const element of selectedElements) element.setAttribute("data-cms-selected", "");
76
+ const result = !target.resolvedNodeId ? "missing" : target.resolvedNodeId === nodeId ? "exact" : "fallback";
77
+ if (reveal && result !== "missing" && revealedIntentId !== intent.id) {
78
+ revealedIntentId = intent.id;
79
+ revealElement(nearestPreviewElement(selectedElements), view);
80
+ }
81
+ sendApplied(result);
82
+ };
83
+ const hoverElements = (target) => {
84
+ clearElements(hoveredElements, "data-cms-hovered");
85
+ hoveredElements = [];
86
+ if (!active || mode !== "edit" || !target) return;
87
+ const scope = target.closest("[data-cms-document]") ?? root;
88
+ const nodeId = findPreviewNodeId(scope, target);
89
+ if (!nodeId) return;
90
+ hoveredElements = resolvePreviewTarget(scope, nodeId, fallbacks).elements;
91
+ for (const element of hoveredElements) element.setAttribute("data-cms-hovered", "");
92
+ };
93
+ const settleRender = (sequence) => {
94
+ view.requestAnimationFrame(() => view.requestAnimationFrame(() => {
95
+ if (sequence !== renderSequence) return;
96
+ active = true;
97
+ decoratePreviewTargets(root);
98
+ bridge.send({
99
+ revision,
100
+ type: "preview:rendered"
101
+ });
102
+ applyFocus(desiredFocus?.reveal);
103
+ }));
104
+ };
105
+ const stopBridge = bridge.subscribe((message) => {
106
+ if (message.type === "studio:connect") {
107
+ active = true;
108
+ clearPreviewTargets(root);
109
+ decoratePreviewTargets(root);
110
+ sendManifest();
111
+ return;
112
+ }
113
+ if (message.type === "studio:mode") {
114
+ mode = message.mode;
115
+ if (mode === "browse") {
116
+ hoverElements();
117
+ clearElements(selectedElements, "data-cms-selected");
118
+ selectedElements = [];
119
+ } else {
120
+ decoratePreviewTargets(root);
121
+ applyFocus();
122
+ }
123
+ return;
124
+ }
125
+ if (message.type === "studio:navigate") {
126
+ options.navigate(message.path);
127
+ return;
128
+ }
129
+ if (message.type === "studio:focus") {
130
+ if (message.focus.revision !== revision) return;
131
+ desiredFocus = message.focus;
132
+ applyFocus(desiredFocus.reveal);
133
+ return;
134
+ }
135
+ if (message.type !== "studio:patch" || message.revision < revision) return;
136
+ revision = message.revision;
137
+ active = false;
138
+ desiredFocus = message.focus;
139
+ lastApplied = "";
140
+ const sequence = ++renderSequence;
141
+ store.patch(message.document).then((localFallbacks) => {
142
+ fallbacks = Object.assign({}, message.fallbacks, localFallbacks);
143
+ settleRender(sequence);
144
+ });
145
+ });
146
+ const handleClick = (event) => {
147
+ if (!active) return;
148
+ const target = event.target instanceof Element ? event.target : null;
149
+ if (mode === "browse") {
150
+ const link = target?.closest("a[href]");
151
+ if (!(link instanceof HTMLAnchorElement) || link.target || link.hasAttribute("download") || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
152
+ const destination = new URL(link.href, view.location.href);
153
+ if (destination.origin !== view.location.origin) return;
154
+ event.preventDefault();
155
+ options.navigate(destination.pathname);
156
+ return;
157
+ }
158
+ const scope = target?.closest("[data-cms-document]");
159
+ const documentIdValue = scope?.getAttribute("data-cms-document");
160
+ if (!target || !scope || !Schema.is(DocumentId)(documentIdValue)) return;
161
+ event.preventDefault();
162
+ event.stopPropagation();
163
+ const nodeIdValue = findPreviewNodeId(scope, target);
164
+ const nodeId = Schema.is(EditorNodeId)(nodeIdValue) ? nodeIdValue : void 0;
165
+ const field = target.closest("[data-cms-field]")?.getAttribute("data-cms-field") || void 0;
166
+ const activationFocus = {
167
+ documentId: documentIdValue,
168
+ id: PreviewIntentId.make(randomUuid()),
169
+ origin: "preview",
170
+ reveal: false,
171
+ revision
172
+ };
173
+ desiredFocus = nodeId ? {
174
+ ...activationFocus,
175
+ nodeId
176
+ } : activationFocus;
177
+ lastApplied = "";
178
+ const activation = {
179
+ documentId: desiredFocus.documentId,
180
+ requestId: RequestId.make(randomUuid()),
181
+ revision,
182
+ type: "preview:activate"
183
+ };
184
+ if (field && nodeId) bridge.send({
185
+ ...activation,
186
+ field,
187
+ nodeId
188
+ });
189
+ else if (field) bridge.send({
190
+ ...activation,
191
+ field
192
+ });
193
+ else if (nodeId) bridge.send({
194
+ ...activation,
195
+ nodeId
196
+ });
197
+ else bridge.send(activation);
198
+ applyFocus();
199
+ };
200
+ const handlePointerOver = (event) => hoverElements(event.target instanceof Element ? event.target : void 0);
201
+ const handlePointerOut = (event) => {
202
+ if (!(event.relatedTarget instanceof Element)) hoverElements();
203
+ };
204
+ let mutationQueued = false;
205
+ const observer = new MutationObserver(() => {
206
+ if (mutationQueued) return;
207
+ mutationQueued = true;
208
+ queueMicrotask(() => {
209
+ mutationQueued = false;
210
+ if (!active) return;
211
+ hoverElements();
212
+ decoratePreviewTargets(root);
213
+ if (desiredFocus) applyFocus(false);
214
+ });
215
+ });
216
+ root.addEventListener("click", handleClick, true);
217
+ root.addEventListener("pointerover", handlePointerOver, true);
218
+ root.addEventListener("pointerout", handlePointerOut, true);
219
+ observer.observe(root.documentElement, {
220
+ childList: true,
221
+ subtree: true
222
+ });
223
+ return () => {
224
+ stopBridge();
225
+ stopManifest();
226
+ observer.disconnect();
227
+ root.removeEventListener("click", handleClick, true);
228
+ root.removeEventListener("pointerover", handlePointerOver, true);
229
+ root.removeEventListener("pointerout", handlePointerOut, true);
230
+ clearPreviewTargets(root);
231
+ };
232
+ }
233
+ function revealElement(element, view) {
234
+ if (!element) return;
235
+ const rect = element.getBoundingClientRect();
236
+ const margin = Math.min(80, view.innerHeight / 5);
237
+ if (rect.top >= margin && rect.bottom <= view.innerHeight - margin) return;
238
+ element.scrollIntoView({
239
+ behavior: view.matchMedia("(prefers-reduced-motion: reduce)").matches ? "auto" : "smooth",
240
+ block: "center",
241
+ inline: "nearest"
242
+ });
243
+ }
244
+
245
+ //#endregion
246
+ export { mountPreviewController };
247
+ //# sourceMappingURL=controller.js.map
@@ -0,0 +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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"}
@@ -0,0 +1,70 @@
1
+ import { H as PublicPath } from "../../models-Citx8jBi.js";
2
+ import { s as PreviewOrigin, u as PreviewSessionId } from "../../models-DS5ClMsH.js";
3
+ import { t as openSitePreviewConnection } from "../../connection-ZGtL54qY.js";
4
+ import { documentPreviewStoreKey } from "../delivery/preview.js";
5
+ import { mountPreviewController } from "./controller.js";
6
+ import { t as createStudioPreviewStore } from "../../store-Nl4uxEXx.js";
7
+ import { Option, Schema } from "effect";
8
+ import { defineNuxtPlugin, navigateTo, useNuxtApp } from "nuxt/app";
9
+
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
+ //#region src/runtime/preview/plugin.client.ts
35
+ var plugin_client_default = defineNuxtPlugin(async () => {
36
+ const parameters = readPreviewLocation(new URL(window.location.href));
37
+ if (!parameters) return;
38
+ const route = () => Schema.decodeSync(PublicPath)(window.location.pathname);
39
+ const store = createStudioPreviewStore(route);
40
+ const nuxtApp = useNuxtApp();
41
+ nuxtApp.vueApp.provide(documentPreviewStoreKey, store);
42
+ nuxtApp.hooks.hook("page:finish", store.routeChanged);
43
+ const mount = async () => {
44
+ const connection = await openSitePreviewConnection({
45
+ editorOrigin: parameters.editorOrigin,
46
+ route: route(),
47
+ sessionId: parameters.sessionId
48
+ });
49
+ const unmount = mountPreviewController({
50
+ bridge: connection,
51
+ navigate: async (path) => {
52
+ const target = withPreviewLocation(new URL(path, window.location.origin), parameters);
53
+ await navigateTo(`${target.pathname}${target.search}${target.hash}`);
54
+ },
55
+ root: document,
56
+ store,
57
+ view: window
58
+ });
59
+ window.addEventListener("pagehide", () => {
60
+ unmount();
61
+ connection.close();
62
+ }, { once: true });
63
+ };
64
+ if (nuxtApp.isHydrating) nuxtApp.hooks.hookOnce("app:suspense:resolve", mount);
65
+ else await mount();
66
+ });
67
+
68
+ //#endregion
69
+ export { plugin_client_default as default };
70
+ //# sourceMappingURL=plugin.client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.client.js","names":["PreviewOriginSchema","PreviewSessionIdSchema"],"sources":["../../../../../../protocol/src/internal/preview/location.ts","../../../../../src/runtime/preview/plugin.client.ts"],"sourcesContent":["import { Option, Schema } from 'effect'\nimport { PreviewOrigin as PreviewOriginSchema, PreviewSessionId as PreviewSessionIdSchema } from './models'\n\nconst ENABLED_PARAMETER = '_cms_preview'\nconst EDITOR_ORIGIN_PARAMETER = '_cms_preview_editor_origin'\nconst SESSION_PARAMETER = '_cms_preview_session'\n\nconst PreviewLocationParameters = Schema.Struct({\n editorOrigin: PreviewOriginSchema,\n sessionId: PreviewSessionIdSchema,\n})\n\nexport interface PreviewLocationParameters extends Schema.Schema.Type<typeof PreviewLocationParameters> {}\n\nexport function readPreviewLocation(url: URL): PreviewLocationParameters | undefined {\n if (!url.searchParams.has(ENABLED_PARAMETER)) return undefined\n return Schema.decodeUnknownOption(PreviewLocationParameters)({\n editorOrigin: url.searchParams.get(EDITOR_ORIGIN_PARAMETER),\n sessionId: url.searchParams.get(SESSION_PARAMETER),\n }).pipe(Option.getOrUndefined)\n}\n\nexport function withPreviewLocation(url: URL, parameters: PreviewLocationParameters): URL {\n const next = new URL(url)\n next.searchParams.set(ENABLED_PARAMETER, '1')\n next.searchParams.set(EDITOR_ORIGIN_PARAMETER, parameters.editorOrigin)\n next.searchParams.set(SESSION_PARAMETER, parameters.sessionId)\n return next\n}\n\nexport function withoutPreviewLocation(url: URL): URL {\n const next = new URL(url)\n next.searchParams.delete(ENABLED_PARAMETER)\n next.searchParams.delete(EDITOR_ORIGIN_PARAMETER)\n next.searchParams.delete(SESSION_PARAMETER)\n return next\n}\n","import { defineNuxtPlugin, navigateTo, useNuxtApp } from 'nuxt/app'\nimport { PublicPath } from '@internal/protocol/Documents'\nimport { readPreviewLocation, withPreviewLocation } from '@internal/protocol/Preview'\nimport { Schema } from 'effect'\nimport { openSitePreviewConnection } from './connection'\nimport { mountPreviewController } from './controller'\nimport { createStudioPreviewStore, documentPreviewStoreKey } from './store'\n\nexport default defineNuxtPlugin(async () => {\n const parameters = readPreviewLocation(new URL(window.location.href))\n if (!parameters) return\n const route = () => Schema.decodeSync(PublicPath)(window.location.pathname)\n const store = createStudioPreviewStore(route)\n const nuxtApp = useNuxtApp()\n nuxtApp.vueApp.provide(documentPreviewStoreKey, store)\n nuxtApp.hooks.hook('page:finish', store.routeChanged)\n\n const mount = async () => {\n const connection = await openSitePreviewConnection({\n editorOrigin: parameters.editorOrigin,\n route: route(),\n sessionId: parameters.sessionId,\n })\n const unmount = mountPreviewController({\n bridge: connection,\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 window.addEventListener(\n 'pagehide',\n () => {\n unmount()\n void connection.close()\n },\n { once: true },\n )\n }\n\n if (nuxtApp.isHydrating) nuxtApp.hooks.hookOnce('app:suspense:resolve', mount)\n else await mount()\n})\n"],"mappings":";;;;;;;;;;AAGA,MAAM,oBAAoB;AAC1B,MAAM,0BAA0B;AAChC,MAAM,oBAAoB;AAE1B,MAAM,4BAA4B,OAAO,OAAO;CAC9C,cAAcA;CACd,WAAWC;AACb,CAAC;AAID,SAAgB,oBAAoB,KAAiD;CACnF,IAAI,CAAC,IAAI,aAAa,IAAI,iBAAiB,GAAG,OAAO;CACrD,OAAO,OAAO,oBAAoB,yBAAyB,CAAC,CAAC;EAC3D,cAAc,IAAI,aAAa,IAAI,uBAAuB;EAC1D,WAAW,IAAI,aAAa,IAAI,iBAAiB;CACnD,CAAC,CAAC,CAAC,KAAK,OAAO,cAAc;AAC/B;AAEA,SAAgB,oBAAoB,KAAU,YAA4C;CACxF,MAAM,OAAO,IAAI,IAAI,GAAG;CACxB,KAAK,aAAa,IAAI,mBAAmB,GAAG;CAC5C,KAAK,aAAa,IAAI,yBAAyB,WAAW,YAAY;CACtE,KAAK,aAAa,IAAI,mBAAmB,WAAW,SAAS;CAC7D,OAAO;AACT;;;;ACpBA,4BAAe,iBAAiB,YAAY;CAC1C,MAAM,aAAa,oBAAoB,IAAI,IAAI,OAAO,SAAS,IAAI,CAAC;CACpE,IAAI,CAAC,YAAY;CACjB,MAAM,cAAc,OAAO,WAAW,UAAU,CAAC,CAAC,OAAO,SAAS,QAAQ;CAC1E,MAAM,QAAQ,yBAAyB,KAAK;CAC5C,MAAM,UAAU,WAAW;CAC3B,QAAQ,OAAO,QAAQ,yBAAyB,KAAK;CACrD,QAAQ,MAAM,KAAK,eAAe,MAAM,YAAY;CAEpD,MAAM,QAAQ,YAAY;EACxB,MAAM,aAAa,MAAM,0BAA0B;GACjD,cAAc,WAAW;GACzB,OAAO,MAAM;GACb,WAAW,WAAW;EACxB,CAAC;EACD,MAAM,UAAU,uBAAuB;GACrC,QAAQ;GACR,UAAU,OAAO,SAAS;IACxB,MAAM,SAAS,oBAAoB,IAAI,IAAI,MAAM,OAAO,SAAS,MAAM,GAAG,UAAU;IACpF,MAAM,WAAW,GAAG,OAAO,WAAW,OAAO,SAAS,OAAO,MAAM;GACrE;GACA,MAAM;GACN;GACA,MAAM;EACR,CAAC;EACD,OAAO,iBACL,kBACM;GACJ,QAAQ;GACR,AAAK,WAAW,MAAM;EACxB,GACA,EAAE,MAAM,KAAK,CACf;CACF;CAEA,IAAI,QAAQ,aAAa,QAAQ,MAAM,SAAS,wBAAwB,KAAK;MACxE,MAAM,MAAM;AACnB,CAAC"}
@@ -0,0 +1,9 @@
1
+ [data-cms-preview-decorated] {
2
+ cursor: text;
3
+ outline-offset: 3px;
4
+ }
5
+
6
+ [data-cms-preview-decorated][data-cms-hovered],
7
+ [data-cms-preview-decorated][data-cms-selected] {
8
+ outline: 2px solid var(--cms-preview-accent, #3b82f6);
9
+ }
@@ -0,0 +1,10 @@
1
+ //#region src/runtime/preview/protocol.d.ts
2
+ export declare const CMS_PREVIEW_DECORATED_ATTRIBUTE = "data-cms-preview-decorated";
3
+ export declare const CMS_PREVIEW_INLINE_HOST_ATTRIBUTE = "data-cms-inline-host";
4
+ export declare const CMS_PREVIEW_NODE_ATTRIBUTE = "data-cms-node";
5
+ export declare const CMS_PREVIEW_MARKER_TAG = "cms-studio-preview-marker";
6
+ export declare const CMS_PREVIEW_TARGET_ATTRIBUTE = "data-cms-target";
7
+ export declare const CMS_PREVIEW_WRAPPER_ATTRIBUTE = "data-cms-marker";
8
+ export type CmsPreviewTargetKind = 'component' | 'native' | 'slot';
9
+ //#endregion
10
+ //# sourceMappingURL=protocol.d.ts.map
@@ -0,0 +1,11 @@
1
+ //#region src/runtime/preview/protocol.ts
2
+ const CMS_PREVIEW_DECORATED_ATTRIBUTE = "data-cms-preview-decorated";
3
+ const CMS_PREVIEW_INLINE_HOST_ATTRIBUTE = "data-cms-inline-host";
4
+ const CMS_PREVIEW_NODE_ATTRIBUTE = "data-cms-node";
5
+ const CMS_PREVIEW_MARKER_TAG = "cms-studio-preview-marker";
6
+ const CMS_PREVIEW_TARGET_ATTRIBUTE = "data-cms-target";
7
+ const CMS_PREVIEW_WRAPPER_ATTRIBUTE = "data-cms-marker";
8
+
9
+ //#endregion
10
+ export { CMS_PREVIEW_DECORATED_ATTRIBUTE, CMS_PREVIEW_INLINE_HOST_ATTRIBUTE, CMS_PREVIEW_MARKER_TAG, CMS_PREVIEW_NODE_ATTRIBUTE, CMS_PREVIEW_TARGET_ATTRIBUTE, CMS_PREVIEW_WRAPPER_ATTRIBUTE };
11
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +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;AAC/C,MAAa,oCAAoC;AACjD,MAAa,6BAA6B;AAC1C,MAAa,yBAAyB;AACtC,MAAa,+BAA+B;AAC5C,MAAa,gCAAgC"}
@@ -0,0 +1,4 @@
1
+ import { documentPreviewStoreKey } from "../delivery/preview.js";
2
+ import { t as createStudioPreviewStore } from "../../store-Nl4uxEXx.js";
3
+
4
+ export { createStudioPreviewStore, documentPreviewStoreKey };
@@ -0,0 +1,102 @@
1
+ import { CMS_PREVIEW_DECORATED_ATTRIBUTE, CMS_PREVIEW_INLINE_HOST_ATTRIBUTE, CMS_PREVIEW_NODE_ATTRIBUTE, CMS_PREVIEW_TARGET_ATTRIBUTE, CMS_PREVIEW_WRAPPER_ATTRIBUTE } from "./protocol.js";
2
+
3
+ //#region src/runtime/preview/targets.ts
4
+ const TARGET_PRIORITY = {
5
+ component: 1,
6
+ native: 3,
7
+ slot: 2
8
+ };
9
+ /** Picks the deepest authorable target represented by the clicked rendered element. */
10
+ function findPreviewNodeId(root, clicked) {
11
+ const candidates = collectPreviewTargets(root).filter((target) => target.elements.some((element) => element === clicked || element.contains(clicked)));
12
+ 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));
13
+ return candidates[0]?.id;
14
+ }
15
+ function resolvePreviewTarget(root, nodeId, fallbacks) {
16
+ const visited = /* @__PURE__ */ new Set();
17
+ const targets = collectPreviewTargets(root);
18
+ let targetId = nodeId;
19
+ while (targetId && !visited.has(targetId)) {
20
+ visited.add(targetId);
21
+ const elements = [...new Set(targets.filter((target) => target.id === targetId).flatMap((target) => target.elements))];
22
+ if (elements.length) return {
23
+ elements,
24
+ resolvedNodeId: targetId
25
+ };
26
+ targetId = fallbacks[targetId];
27
+ }
28
+ return { elements: [] };
29
+ }
30
+ function decoratePreviewTargets(root) {
31
+ for (const target of collectPreviewTargets(root)) for (const element of target.elements) element.setAttribute(CMS_PREVIEW_DECORATED_ATTRIBUTE, "");
32
+ }
33
+ function clearPreviewTargets(root) {
34
+ for (const element of root.querySelectorAll(`[${CMS_PREVIEW_DECORATED_ATTRIBUTE}], [data-cms-hovered], [data-cms-selected]`)) {
35
+ element.removeAttribute(CMS_PREVIEW_DECORATED_ATTRIBUTE);
36
+ element.removeAttribute("data-cms-hovered");
37
+ element.removeAttribute("data-cms-selected");
38
+ }
39
+ }
40
+ function nearestPreviewElement(elements) {
41
+ const viewportCenter = window.innerHeight / 2;
42
+ return [...elements].sort((left, right) => viewportDistance(left, viewportCenter) - viewportDistance(right, viewportCenter))[0];
43
+ }
44
+ function collectPreviewTargets(root) {
45
+ return [...root.querySelectorAll(`[${CMS_PREVIEW_NODE_ATTRIBUTE}]`)].flatMap((marker) => {
46
+ const id = marker.getAttribute(CMS_PREVIEW_NODE_ATTRIBUTE);
47
+ const kind = previewTargetKind(marker.getAttribute(CMS_PREVIEW_TARGET_ATTRIBUTE));
48
+ return id && kind ? [{
49
+ elements: resolveMarkerElements(marker, kind),
50
+ id,
51
+ kind
52
+ }] : [];
53
+ });
54
+ }
55
+ function resolveMarkerElements(marker, kind) {
56
+ const isWrapper = marker.hasAttribute(CMS_PREVIEW_WRAPPER_ATTRIBUTE);
57
+ if (marker.hasAttribute("data-cms-inline-host") && isConcreteElement(marker)) return [marker];
58
+ if (!isWrapper && isConcreteElement(marker)) return [marker];
59
+ const children = [...marker.children].filter(isConcreteElement);
60
+ if (isWrapper && children.length) return children;
61
+ if (isWrapper && (kind === "native" || kind === "slot")) {
62
+ const parent = marker.parentElement;
63
+ return parent && isConcreteElement(parent) ? [parent] : [];
64
+ }
65
+ return children;
66
+ }
67
+ function isConcreteElement(element) {
68
+ const view = element.ownerDocument.defaultView;
69
+ if (!view || view.getComputedStyle(element).display === "contents") return false;
70
+ return [...element.getClientRects()].some((rect) => rect.width > 0 && rect.height > 0);
71
+ }
72
+ function previewTargetKind(value) {
73
+ return value === "component" || value === "native" || value === "slot" ? value : void 0;
74
+ }
75
+ function targetDepth(target) {
76
+ return Math.max(0, ...target.elements.map(elementDepth));
77
+ }
78
+ function elementDepth(element) {
79
+ let depth = 0;
80
+ let current = element.parentElement;
81
+ while (current) {
82
+ depth++;
83
+ current = current.parentElement;
84
+ }
85
+ return depth;
86
+ }
87
+ function targetArea(target) {
88
+ return Math.min(Infinity, ...target.elements.map((element) => {
89
+ const rect = element.getBoundingClientRect();
90
+ return rect.width * rect.height;
91
+ }));
92
+ }
93
+ function viewportDistance(element, viewportCenter) {
94
+ const rect = element.getBoundingClientRect();
95
+ const visible = rect.bottom >= 0 && rect.top <= window.innerHeight;
96
+ const distance = Math.abs((rect.top + rect.bottom) / 2 - viewportCenter);
97
+ return visible ? distance : window.innerHeight + distance;
98
+ }
99
+
100
+ //#endregion
101
+ export { clearPreviewTargets, decoratePreviewTargets, findPreviewNodeId, nearestPreviewElement, resolvePreviewTarget };
102
+ //# sourceMappingURL=targets.js.map
@@ -0,0 +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\n/** Picks the deepest authorable target represented by the clicked rendered element. */\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 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 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 while (targetId && !visited.has(targetId)) {\n visited.add(targetId)\n const elements = [\n ...new Set(targets.filter((target) => target.id === targetId).flatMap((target) => target.elements)),\n ]\n if (elements.length) return { elements, resolvedNodeId: targetId }\n targetId = fallbacks[targetId]\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 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 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 if (marker.hasAttribute(CMS_PREVIEW_INLINE_HOST_ATTRIBUTE) && isConcreteElement(marker)) return [marker]\n if (!isWrapper && isConcreteElement(marker)) return [marker]\n const children = [...marker.children].filter(isConcreteElement)\n if (isWrapper && children.length) return children\n if (isWrapper && (kind === 'native' || kind === 'slot')) {\n const parent = marker.parentElement\n return parent && isConcreteElement(parent) ? [parent] : []\n }\n return children\n}\n\nfunction isConcreteElement(element: Element): boolean {\n const view = element.ownerDocument.defaultView\n if (!view || view.getComputedStyle(element).display === 'contents') return false\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 while (current) {\n depth++\n current = current.parentElement\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 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 return visible ? distance : window.innerHeight + distance\n}\n"],"mappings":";;;AAoBA,MAAM,kBAAkB;CAAE,WAAW;CAAG,QAAQ;CAAG,MAAM;AAAE;;AAG3D,SAAgB,kBAAkB,MAAkB,SAAsC;CACxF,MAAM,aAAa,sBAAsB,IAAI,CAAC,CAAC,QAAQ,WACrD,OAAO,SAAS,MAAM,YAAY,YAAY,WAAW,QAAQ,SAAS,OAAO,CAAC,CACpF;CACA,WAAW,MACR,MAAM,UACL,OAAO,MAAM,SAAS,QAAQ,IAAI,OAAO,KAAK,SAAS,QAAQ,KAC/D,YAAY,KAAK,IAAI,YAAY,IAAI,KACrC,gBAAgB,MAAM,QAAQ,gBAAgB,KAAK,SACnD,WAAW,IAAI,IAAI,WAAW,KAAK,CACvC;CACA,OAAO,WAAW,EAAE,EAAE;AACxB;AAEA,SAAgB,qBACd,MACA,QACA,WACuB;CACvB,MAAM,0BAAU,IAAI,IAAY;CAChC,MAAM,UAAU,sBAAsB,IAAI;CAC1C,IAAI,WAA+B;CACnC,OAAO,YAAY,CAAC,QAAQ,IAAI,QAAQ,GAAG;EACzC,QAAQ,IAAI,QAAQ;EACpB,MAAM,WAAW,CACf,GAAG,IAAI,IAAI,QAAQ,QAAQ,WAAW,OAAO,OAAO,QAAQ,CAAC,CAAC,SAAS,WAAW,OAAO,QAAQ,CAAC,CACpG;EACA,IAAI,SAAS,QAAQ,OAAO;GAAE;GAAU,gBAAgB;EAAS;EACjE,WAAW,UAAU;CACvB;CACA,OAAO,EAAE,UAAU,CAAC,EAAE;AACxB;AAEA,SAAgB,uBAAuB,MAAwB;CAC7D,KAAK,MAAM,UAAU,sBAAsB,IAAI,GAC7C,KAAK,MAAM,WAAW,OAAO,UAAU,QAAQ,aAAa,iCAAiC,EAAE;AAEnG;AAEA,SAAgB,oBAAoB,MAAwB;CAC1D,KAAK,MAAM,WAAW,KAAK,iBACzB,IAAI,gCAAgC,2CACtC,GAAG;EACD,QAAQ,gBAAgB,+BAA+B;EACvD,QAAQ,gBAAgB,kBAAkB;EAC1C,QAAQ,gBAAgB,mBAAmB;CAC7C;AACF;AAEA,SAAgB,sBAAsB,UAAuD;CAC3F,MAAM,iBAAiB,OAAO,cAAc;CAC5C,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAC,MAClB,MAAM,UAAU,iBAAiB,MAAM,cAAc,IAAI,iBAAiB,OAAO,cAAc,CAClG,CAAC,CAAC;AACJ;AAEA,SAAS,sBAAsB,MAAgD;CAC7E,OAAO,CAAC,GAAG,KAAK,iBAAiB,IAAI,2BAA2B,EAAE,CAAC,CAAC,CAAC,SAAS,WAAW;EACvF,MAAM,KAAK,OAAO,aAAa,0BAA0B;EACzD,MAAM,OAAO,kBAAkB,OAAO,aAAa,4BAA4B,CAAC;EAChF,OAAO,MAAM,OAAO,CAAC;GAAE,UAAU,sBAAsB,QAAQ,IAAI;GAAG;GAAI;EAAK,CAAC,IAAI,CAAC;CACvF,CAAC;AACH;AAEA,SAAS,sBAAsB,QAAiB,MAAoD;CAClG,MAAM,YAAY,OAAO,aAAa,6BAA6B;CACnE,IAAI,OAAO,mCAA8C,KAAK,kBAAkB,MAAM,GAAG,OAAO,CAAC,MAAM;CACvG,IAAI,CAAC,aAAa,kBAAkB,MAAM,GAAG,OAAO,CAAC,MAAM;CAC3D,MAAM,WAAW,CAAC,GAAG,OAAO,QAAQ,CAAC,CAAC,OAAO,iBAAiB;CAC9D,IAAI,aAAa,SAAS,QAAQ,OAAO;CACzC,IAAI,cAAc,SAAS,YAAY,SAAS,SAAS;EACvD,MAAM,SAAS,OAAO;EACtB,OAAO,UAAU,kBAAkB,MAAM,IAAI,CAAC,MAAM,IAAI,CAAC;CAC3D;CACA,OAAO;AACT;AAEA,SAAS,kBAAkB,SAA2B;CACpD,MAAM,OAAO,QAAQ,cAAc;CACnC,IAAI,CAAC,QAAQ,KAAK,iBAAiB,OAAO,CAAC,CAAC,YAAY,YAAY,OAAO;CAC3E,OAAO,CAAC,GAAG,QAAQ,eAAe,CAAC,CAAC,CAAC,MAAM,SAAS,KAAK,QAAQ,KAAK,KAAK,SAAS,CAAC;AACvF;AAEA,SAAS,kBAAkB,OAAwD;CACjF,OAAO,UAAU,eAAe,UAAU,YAAY,UAAU,SAAS,QAAQ;AACnF;AAEA,SAAS,YAAY,QAA+B;CAClD,OAAO,KAAK,IAAI,GAAG,GAAG,OAAO,SAAS,IAAI,YAAY,CAAC;AACzD;AAEA,SAAS,aAAa,SAA0B;CAC9C,IAAI,QAAQ;CACZ,IAAI,UAAU,QAAQ;CACtB,OAAO,SAAS;EACd;EACA,UAAU,QAAQ;CACpB;CACA,OAAO;AACT;AAEA,SAAS,WAAW,QAA+B;CACjD,OAAO,KAAK,IACV,UACA,GAAG,OAAO,SAAS,KAAK,YAAY;EAClC,MAAM,OAAO,QAAQ,sBAAsB;EAC3C,OAAO,KAAK,QAAQ,KAAK;CAC3B,CAAC,CACH;AACF;AAEA,SAAS,iBAAiB,SAAkB,gBAAgC;CAC1E,MAAM,OAAO,QAAQ,sBAAsB;CAC3C,MAAM,UAAU,KAAK,UAAU,KAAK,KAAK,OAAO,OAAO;CACvD,MAAM,WAAW,KAAK,KAAK,KAAK,MAAM,KAAK,UAAU,IAAI,cAAc;CACvE,OAAO,UAAU,WAAW,OAAO,cAAc;AACnD"}
@@ -0,0 +1,13 @@
1
+ import { defineEventHandler, setResponseHeader } from "h3";
2
+
3
+ //#region src/runtime/studio-app.ts
4
+ function createStudioAppHandler(shell) {
5
+ return defineEventHandler((event) => {
6
+ setResponseHeader(event, "content-type", "text/html; charset=utf-8");
7
+ return shell;
8
+ });
9
+ }
10
+
11
+ //#endregion
12
+ export { createStudioAppHandler };
13
+ //# sourceMappingURL=studio-app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"studio-app.js","names":[],"sources":["../../../../src/runtime/studio-app.ts"],"sourcesContent":["import { defineEventHandler, setResponseHeader } from 'h3'\n\nexport function createStudioAppHandler(shell: string) {\n return defineEventHandler((event) => {\n setResponseHeader(event, 'content-type', 'text/html; charset=utf-8')\n return shell\n })\n}\n"],"mappings":";;;AAEA,SAAgB,uBAAuB,OAAe;CACpD,OAAO,oBAAoB,UAAU;EACnC,kBAAkB,OAAO,gBAAgB,0BAA0B;EACnE,OAAO;CACT,CAAC;AACH"}