@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.
Files changed (181) hide show
  1. package/README.md +260 -6
  2. package/package.json +31 -16
  3. package/src/Authoring.d.ts +13 -1
  4. package/src/Configuration-Br7tE9Qt.d.ts +68 -0
  5. package/src/{AuthoringSchema-BQ5kbhVB.js → Configuration-CA_jvQKG.js} +599 -492
  6. package/src/Configuration-CA_jvQKG.js.map +1 -0
  7. package/src/Configuration.d.ts +2 -44
  8. package/src/Configuration.js +0 -1
  9. package/src/Configuration.js.map +1 -1
  10. package/src/{DocumentEngine-Da0kWotL.js → DocumentEngine-CgiBQU4g.js} +110 -84
  11. package/src/DocumentEngine-CgiBQU4g.js.map +1 -0
  12. package/src/DocumentModel-BB9igGC7.d.ts +34 -0
  13. package/src/DocumentModel.d.ts +2 -30
  14. package/src/DocumentModel.js +13 -3
  15. package/src/DocumentModel.js.map +1 -1
  16. package/src/Forms-BsJMev5_.d.ts +74 -0
  17. package/src/Forms-CfcI3tPU.js +79 -0
  18. package/src/Forms-CfcI3tPU.js.map +1 -0
  19. package/src/Forms-DxbkU3_5.js +367 -0
  20. package/src/Forms-DxbkU3_5.js.map +1 -0
  21. package/src/Forms.d.ts +35 -0
  22. package/src/Forms.js +13 -0
  23. package/src/Forms.js.map +1 -0
  24. package/src/HttpPaths-c9nLZ9H2.js +21 -0
  25. package/src/HttpPaths-c9nLZ9H2.js.map +1 -0
  26. package/src/I18n-DZK4CkJF.d.ts +21 -0
  27. package/src/I18n.d.ts +2 -0
  28. package/src/I18n.js +1 -0
  29. package/src/Module.js +78 -81
  30. package/src/Module.js.map +1 -1
  31. package/src/S3MediaObjects-JKMAWyVB.js +2664 -0
  32. package/src/S3MediaObjects-JKMAWyVB.js.map +1 -0
  33. package/src/Seed.d.ts +6 -0
  34. package/src/Seed.js +34 -0
  35. package/src/Seed.js.map +1 -0
  36. package/src/Seo-402YumpT.d.ts +198 -0
  37. package/src/{connection-ZGtL54qY.js → connection-B-iz0Y9Y.js} +5 -7
  38. package/src/connection-B-iz0Y9Y.js.map +1 -0
  39. package/src/{installation-BNKaVjni.js → installation-DgF2M1gL.js} +1162 -2147
  40. package/src/installation-DgF2M1gL.js.map +1 -0
  41. package/src/internal/authoring-catalog.js +153 -0
  42. package/src/internal/authoring-catalog.js.map +1 -0
  43. package/src/internal/authoring-compiler.js +2 -2
  44. package/src/internal/authoring-compiler.js.map +1 -1
  45. package/src/internal/authoring-metadata.js +68 -49
  46. package/src/internal/authoring-metadata.js.map +1 -1
  47. package/src/internal/cms-config.js +0 -1
  48. package/src/internal/cms-config.js.map +1 -1
  49. package/src/internal/configuration.js +25 -13
  50. package/src/internal/configuration.js.map +1 -1
  51. package/src/internal/document-model.js +66 -20
  52. package/src/internal/document-model.js.map +1 -1
  53. package/src/internal/form-capabilities.js +12 -0
  54. package/src/internal/form-capabilities.js.map +1 -0
  55. package/src/internal/i18n.js +47 -0
  56. package/src/internal/i18n.js.map +1 -0
  57. package/src/internal/studio-app.js +66 -0
  58. package/src/internal/studio-app.js.map +1 -0
  59. package/src/location-CFKTeK1K.js +35 -0
  60. package/src/location-CFKTeK1K.js.map +1 -0
  61. package/src/{metadata-Czvi3E4K.js → metadata-BEZPWh-3.js} +3 -72
  62. package/src/metadata-BEZPWh-3.js.map +1 -0
  63. package/src/{models-DS5ClMsH.js → models-BWm1pTAf.js} +9 -31
  64. package/src/models-BWm1pTAf.js.map +1 -0
  65. package/src/models-DwYioyNV.js +726 -0
  66. package/src/models-DwYioyNV.js.map +1 -0
  67. package/src/runtime/blocks.js +30 -0
  68. package/src/runtime/blocks.js.map +1 -0
  69. package/src/runtime/collaboration.js +9 -4
  70. package/src/runtime/collaboration.js.map +1 -1
  71. package/src/runtime/delivery/DocumentRenderer.js +10 -4
  72. package/src/runtime/delivery/DocumentRenderer.js.map +1 -1
  73. package/src/runtime/delivery/blocks.js +8 -0
  74. package/src/runtime/delivery/blocks.js.map +1 -0
  75. package/src/runtime/delivery/context.js +12 -0
  76. package/src/runtime/delivery/context.js.map +1 -0
  77. package/src/runtime/delivery/document-page.js +14 -12
  78. package/src/runtime/delivery/document-page.js.map +1 -1
  79. package/src/runtime/delivery/document.js +21 -3
  80. package/src/runtime/delivery/document.js.map +1 -1
  81. package/src/runtime/delivery/error.js +11 -0
  82. package/src/runtime/delivery/error.js.map +1 -0
  83. package/src/runtime/delivery/plugin.js +41 -0
  84. package/src/runtime/delivery/plugin.js.map +1 -0
  85. package/src/runtime/delivery/types.d.ts +5 -0
  86. package/src/runtime/delivery/useCmsDocumentSeo.d.ts +56 -0
  87. package/src/runtime/delivery/useCmsDocumentSeo.js +99 -0
  88. package/src/runtime/delivery/useCmsDocumentSeo.js.map +1 -0
  89. package/src/runtime/delivery/useDocument.js +5 -2
  90. package/src/runtime/delivery/useDocument.js.map +1 -1
  91. package/src/runtime/delivery/useDocumentQuery.js +5 -2
  92. package/src/runtime/delivery/useDocumentQuery.js.map +1 -1
  93. package/src/runtime/forms/document.js +38 -0
  94. package/src/runtime/forms/document.js.map +1 -0
  95. package/src/runtime/forms/useCmsForm.js +149 -0
  96. package/src/runtime/forms/useCmsForm.js.map +1 -0
  97. package/src/runtime/i18n/translator.js +22 -0
  98. package/src/runtime/i18n/translator.js.map +1 -0
  99. package/src/runtime/i18n/useCmsI18n.d.ts +9 -0
  100. package/src/runtime/i18n/useCmsI18n.js +29 -0
  101. package/src/runtime/i18n/useCmsI18n.js.map +1 -0
  102. package/src/runtime/installation.js +1 -1
  103. package/src/runtime/plugin.js +3 -3
  104. package/src/runtime/plugin.js.map +1 -1
  105. package/src/runtime/preview/comark-document.js +0 -1
  106. package/src/runtime/preview/comark-document.js.map +1 -1
  107. package/src/runtime/preview/connection.js +1 -1
  108. package/src/runtime/preview/controller.js +37 -11
  109. package/src/runtime/preview/controller.js.map +1 -1
  110. package/src/runtime/preview/overlay.js +65 -0
  111. package/src/runtime/preview/overlay.js.map +1 -0
  112. package/src/runtime/preview/plugin.client.js +59 -61
  113. package/src/runtime/preview/plugin.client.js.map +1 -1
  114. package/src/runtime/preview/preview.css +72 -4
  115. package/src/runtime/preview/protocol.js.map +1 -1
  116. package/src/runtime/preview/store.js +1 -1
  117. package/src/runtime/preview/targets.js +0 -1
  118. package/src/runtime/preview/targets.js.map +1 -1
  119. package/src/runtime/sitemap-entries.js +17 -0
  120. package/src/runtime/sitemap-entries.js.map +1 -0
  121. package/src/runtime/sitemap.js +24 -0
  122. package/src/runtime/sitemap.js.map +1 -0
  123. package/src/runtime/studio-app.js +5 -1
  124. package/src/runtime/studio-app.js.map +1 -1
  125. package/src/runtime/studio-entry.js +36 -0
  126. package/src/runtime/studio-entry.js.map +1 -0
  127. package/src/runtime/studio-navigation.js +11 -0
  128. package/src/runtime/studio-navigation.js.map +1 -0
  129. package/src/scalars-B2lgGUnj.js +26 -0
  130. package/src/scalars-B2lgGUnj.js.map +1 -0
  131. package/src/{store-Nl4uxEXx.js → store-DjJs3I7k.js} +12 -7
  132. package/src/store-DjJs3I7k.js.map +1 -0
  133. package/studio/CreateDocumentDialog-CTeIFlPb.js +256 -0
  134. package/studio/collaboration-DcK2F6v9.js +4566 -0
  135. package/studio/documentPlanning-Bfv-d7OU.js +29820 -0
  136. package/studio/dom-to-image-more.min-D6jGGdrW.js +877 -0
  137. package/studio/editor-Bzlh3zXt.js +30827 -0
  138. package/studio/host.css +3 -0
  139. package/studio/host.js +46614 -0
  140. package/studio/rolldown-runtime-B0aSnxlc.js +20 -0
  141. package/dist/studio/assets/ActivityEntryRow-D--fRvWI.js +0 -1
  142. package/dist/studio/assets/ActivityView-D-XBBUHb.js +0 -1
  143. package/dist/studio/assets/CreateDocumentDialog-CH8UH1QM.js +0 -1
  144. package/dist/studio/assets/DocumentsView-CxRpmAxt.js +0 -34
  145. package/dist/studio/assets/DropdownMenu-BSb1l7fr.js +0 -1
  146. package/dist/studio/assets/Input-DVao38h7.js +0 -3
  147. package/dist/studio/assets/MediaView-BHrPIjxB.js +0 -1
  148. package/dist/studio/assets/Modal-VNrXGa5C.js +0 -1
  149. package/dist/studio/assets/OverviewView-DfP6-mLZ.js +0 -1
  150. package/dist/studio/assets/Select-BJZIs9sY.js +0 -1
  151. package/dist/studio/assets/SettingsView-CerHe-ua.js +0 -1
  152. package/dist/studio/assets/Skeleton-CWJNi3nS.js +0 -1
  153. package/dist/studio/assets/StudioPageHeader-DP9HDAF2.js +0 -1
  154. package/dist/studio/assets/UsersView-cP3REkH2.js +0 -1
  155. package/dist/studio/assets/collaboration-BLnCzfvV.js +0 -4
  156. package/dist/studio/assets/context-dY4fNbn3.js +0 -1
  157. package/dist/studio/assets/editor-CE07wW83.js +0 -137
  158. package/dist/studio/assets/gateway-BAyQgCse.js +0 -10
  159. package/dist/studio/assets/index-CjoaPLhZ.js +0 -28
  160. package/dist/studio/assets/index-s2rPqCmP.css +0 -2
  161. package/dist/studio/assets/render-BkxbK2St.js +0 -83
  162. package/dist/studio/assets/rolldown-runtime-DK3Fl9T5.js +0 -1
  163. package/dist/studio/assets/useMediaLibrary-D7qR7aBf.js +0 -1
  164. package/dist/studio/index.html +0 -76
  165. package/src/AuthoringSchema-BQ5kbhVB.js.map +0 -1
  166. package/src/Configuration-BGYFD2N1.js +0 -150
  167. package/src/Configuration-BGYFD2N1.js.map +0 -1
  168. package/src/DocumentEngine-Da0kWotL.js.map +0 -1
  169. package/src/HttpPaths-86qLGB90.js +0 -15
  170. package/src/HttpPaths-86qLGB90.js.map +0 -1
  171. package/src/StudioHttp-BTLLooh0.js +0 -916
  172. package/src/StudioHttp-BTLLooh0.js.map +0 -1
  173. package/src/connection-ZGtL54qY.js.map +0 -1
  174. package/src/installation-BNKaVjni.js.map +0 -1
  175. package/src/internal/component-metadata.js +0 -37
  176. package/src/internal/component-metadata.js.map +0 -1
  177. package/src/metadata-Czvi3E4K.js.map +0 -1
  178. package/src/models-Citx8jBi.js +0 -306
  179. package/src/models-Citx8jBi.js.map +0 -1
  180. package/src/models-DS5ClMsH.js.map +0 -1
  181. package/src/store-Nl4uxEXx.js.map +0 -1
@@ -1,5 +1,7 @@
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";
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: "Unknown",
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") return;
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) return;
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) return;
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
- options.navigate(destination.pathname);
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
- const margin = Math.min(80, view.innerHeight / 5);
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: view.matchMedia("(prefers-reduced-motion: reduce)").matches ? "auto" : "smooth",
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 { 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";
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-Nl4uxEXx.js";
7
- import { Option, Schema } from "effect";
8
- import { defineNuxtPlugin, navigateTo, useNuxtApp } from "nuxt/app";
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(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();
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":["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"}
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-decorated][data-cms-hovered],
7
- [data-cms-preview-decorated][data-cms-selected] {
8
- outline: 2px solid var(--cms-preview-accent, #3b82f6);
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;AAC/C,MAAa,oCAAoC;AACjD,MAAa,6BAA6B;AAC1C,MAAa,yBAAyB;AACtC,MAAa,+BAA+B;AAC5C,MAAa,gCAAgC"}
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-Nl4uxEXx.js";
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\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":"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"}
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"}