@phtngyn/cms 0.1.0-beta.0 → 0.1.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/README.md +72 -1
  2. package/package.json +5 -5
  3. package/src/Authoring.d.ts +13 -1
  4. package/src/{AuthoringSchema-BQ5kbhVB.js → Configuration-DyKo0sLS.js} +595 -367
  5. package/src/Configuration-DyKo0sLS.js.map +1 -0
  6. package/src/{DocumentEngine-Da0kWotL.js → DocumentEngine-DYObwMDY.js} +44 -66
  7. package/src/DocumentEngine-DYObwMDY.js.map +1 -0
  8. package/src/DocumentModel.d.ts +4 -0
  9. package/src/DocumentModel.js.map +1 -1
  10. package/src/{HttpPaths-86qLGB90.js → HttpPaths-BbS21Jy8.js} +4 -2
  11. package/src/{HttpPaths-86qLGB90.js.map → HttpPaths-BbS21Jy8.js.map} +1 -1
  12. package/src/Module.js +27 -76
  13. package/src/Module.js.map +1 -1
  14. package/src/{StudioHttp-BTLLooh0.js → StudioHttp-jR2-bc01.js} +44 -242
  15. package/src/StudioHttp-jR2-bc01.js.map +1 -0
  16. package/src/{connection-ZGtL54qY.js → connection-CBTY-TzB.js} +3 -3
  17. package/src/{connection-ZGtL54qY.js.map → connection-CBTY-TzB.js.map} +1 -1
  18. package/src/{installation-BNKaVjni.js → installation-DeuBiFRE.js} +488 -236
  19. package/src/installation-DeuBiFRE.js.map +1 -0
  20. package/src/internal/authoring-catalog.js +147 -0
  21. package/src/internal/authoring-catalog.js.map +1 -0
  22. package/src/internal/authoring-compiler.js +2 -1
  23. package/src/internal/authoring-compiler.js.map +1 -1
  24. package/src/internal/authoring-metadata.js +67 -48
  25. package/src/internal/authoring-metadata.js.map +1 -1
  26. package/src/internal/configuration.js +5 -6
  27. package/src/internal/configuration.js.map +1 -1
  28. package/src/internal/document-model.js +3 -2
  29. package/src/internal/document-model.js.map +1 -1
  30. package/src/internal/studio-app.js +66 -0
  31. package/src/internal/studio-app.js.map +1 -0
  32. package/src/location-DtYv2aes.js +36 -0
  33. package/src/location-DtYv2aes.js.map +1 -0
  34. package/src/{metadata-Czvi3E4K.js → metadata-DE1Mc2td.js} +2 -2
  35. package/src/{metadata-Czvi3E4K.js.map → metadata-DE1Mc2td.js.map} +1 -1
  36. package/src/{models-Citx8jBi.js → models-BkMgeaOL.js} +252 -3
  37. package/src/models-BkMgeaOL.js.map +1 -0
  38. package/src/{models-DS5ClMsH.js → models-C3witQBK.js} +8 -31
  39. package/src/models-C3witQBK.js.map +1 -0
  40. package/src/runtime/blocks.js +17 -0
  41. package/src/runtime/blocks.js.map +1 -0
  42. package/src/runtime/collaboration.js +9 -4
  43. package/src/runtime/collaboration.js.map +1 -1
  44. package/src/runtime/delivery/DocumentRenderer.js +6 -3
  45. package/src/runtime/delivery/DocumentRenderer.js.map +1 -1
  46. package/src/runtime/delivery/blocks.js +6 -0
  47. package/src/runtime/delivery/blocks.js.map +1 -0
  48. package/src/runtime/delivery/context.js +12 -0
  49. package/src/runtime/delivery/context.js.map +1 -0
  50. package/src/runtime/delivery/document-page.js +5 -3
  51. package/src/runtime/delivery/document-page.js.map +1 -1
  52. package/src/runtime/delivery/document.js +18 -2
  53. package/src/runtime/delivery/document.js.map +1 -1
  54. package/src/runtime/delivery/error.js +11 -0
  55. package/src/runtime/delivery/error.js.map +1 -0
  56. package/src/runtime/delivery/plugin.js +21 -0
  57. package/src/runtime/delivery/plugin.js.map +1 -0
  58. package/src/runtime/delivery/useDocument.js +6 -3
  59. package/src/runtime/delivery/useDocument.js.map +1 -1
  60. package/src/runtime/delivery/useDocumentQuery.js +6 -3
  61. package/src/runtime/delivery/useDocumentQuery.js.map +1 -1
  62. package/src/runtime/installation.js +1 -1
  63. package/src/runtime/plugin.js +3 -3
  64. package/src/runtime/plugin.js.map +1 -1
  65. package/src/runtime/preview/connection.js +1 -1
  66. package/src/runtime/preview/controller.js +29 -10
  67. package/src/runtime/preview/controller.js.map +1 -1
  68. package/src/runtime/preview/overlay.js +65 -0
  69. package/src/runtime/preview/overlay.js.map +1 -0
  70. package/src/runtime/preview/plugin.client.js +21 -34
  71. package/src/runtime/preview/plugin.client.js.map +1 -1
  72. package/src/runtime/preview/preview.css +72 -4
  73. package/src/runtime/preview/store.js +1 -1
  74. package/src/runtime/studio-app.js +5 -1
  75. package/src/runtime/studio-app.js.map +1 -1
  76. package/src/runtime/studio-entry.js +36 -0
  77. package/src/runtime/studio-entry.js.map +1 -0
  78. package/src/runtime/studio-navigation.js +11 -0
  79. package/src/runtime/studio-navigation.js.map +1 -0
  80. package/src/{store-Nl4uxEXx.js → store-CfFFx9Ua.js} +3 -3
  81. package/src/{store-Nl4uxEXx.js.map → store-CfFFx9Ua.js.map} +1 -1
  82. package/studio/CreateDocumentDialog--L9lTfx6.js +256 -0
  83. package/studio/collaboration-DUuu678R.js +4565 -0
  84. package/studio/documentPlanning-BXX04Woe.js +28989 -0
  85. package/studio/dom-to-image-more.min-D6jGGdrW.js +877 -0
  86. package/studio/editor-PexnXkJY.js +30817 -0
  87. package/studio/host.css +3 -0
  88. package/studio/host.js +44179 -0
  89. package/studio/rolldown-runtime-B0aSnxlc.js +20 -0
  90. package/dist/studio/assets/ActivityEntryRow-D--fRvWI.js +0 -1
  91. package/dist/studio/assets/ActivityView-D-XBBUHb.js +0 -1
  92. package/dist/studio/assets/CreateDocumentDialog-CH8UH1QM.js +0 -1
  93. package/dist/studio/assets/DocumentsView-CxRpmAxt.js +0 -34
  94. package/dist/studio/assets/DropdownMenu-BSb1l7fr.js +0 -1
  95. package/dist/studio/assets/Input-DVao38h7.js +0 -3
  96. package/dist/studio/assets/MediaView-BHrPIjxB.js +0 -1
  97. package/dist/studio/assets/Modal-VNrXGa5C.js +0 -1
  98. package/dist/studio/assets/OverviewView-DfP6-mLZ.js +0 -1
  99. package/dist/studio/assets/Select-BJZIs9sY.js +0 -1
  100. package/dist/studio/assets/SettingsView-CerHe-ua.js +0 -1
  101. package/dist/studio/assets/Skeleton-CWJNi3nS.js +0 -1
  102. package/dist/studio/assets/StudioPageHeader-DP9HDAF2.js +0 -1
  103. package/dist/studio/assets/UsersView-cP3REkH2.js +0 -1
  104. package/dist/studio/assets/collaboration-BLnCzfvV.js +0 -4
  105. package/dist/studio/assets/context-dY4fNbn3.js +0 -1
  106. package/dist/studio/assets/editor-CE07wW83.js +0 -137
  107. package/dist/studio/assets/gateway-BAyQgCse.js +0 -10
  108. package/dist/studio/assets/index-CjoaPLhZ.js +0 -28
  109. package/dist/studio/assets/index-s2rPqCmP.css +0 -2
  110. package/dist/studio/assets/render-BkxbK2St.js +0 -83
  111. package/dist/studio/assets/rolldown-runtime-DK3Fl9T5.js +0 -1
  112. package/dist/studio/assets/useMediaLibrary-D7qR7aBf.js +0 -1
  113. package/dist/studio/index.html +0 -76
  114. package/src/AuthoringSchema-BQ5kbhVB.js.map +0 -1
  115. package/src/Configuration-BGYFD2N1.js +0 -150
  116. package/src/Configuration-BGYFD2N1.js.map +0 -1
  117. package/src/DocumentEngine-Da0kWotL.js.map +0 -1
  118. package/src/StudioHttp-BTLLooh0.js.map +0 -1
  119. package/src/installation-BNKaVjni.js.map +0 -1
  120. package/src/internal/component-metadata.js +0 -37
  121. package/src/internal/component-metadata.js.map +0 -1
  122. package/src/models-Citx8jBi.js.map +0 -1
  123. package/src/models-DS5ClMsH.js.map +0 -1
@@ -1,5 +1,6 @@
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 { St as RevisionNumber, gt as DocumentId, pt as RequestId, vt as EditorNodeId } from "../../models-BkMgeaOL.js";
2
+ import { r as PreviewIntentId } from "../../models-C3witQBK.js";
3
+ import { mountPreviewOverlay } from "./overlay.js";
3
4
  import { clearPreviewTargets, decoratePreviewTargets, findPreviewNodeId, nearestPreviewElement, resolvePreviewTarget } from "./targets.js";
4
5
  import { Crypto, Effect, PlatformError, Schema } from "effect";
5
6
 
@@ -20,6 +21,8 @@ const browserCrypto = Crypto.make({
20
21
  const randomUuid = () => Effect.runSync(browserCrypto.randomUUIDv4.pipe(Effect.orDie));
21
22
  function mountPreviewController(options) {
22
23
  const { bridge, root, store, view } = options;
24
+ const selection = mountPreviewOverlay(root, view);
25
+ const hover = mountPreviewOverlay(root, view, "hover");
23
26
  let active = false;
24
27
  let desiredFocus;
25
28
  let fallbacks = {};
@@ -61,10 +64,14 @@ function mountPreviewController(options) {
61
64
  const applyFocus = (reveal = false) => {
62
65
  clearElements(selectedElements, "data-cms-selected");
63
66
  selectedElements = [];
64
- if (!active || mode !== "edit") return;
67
+ if (!active || mode !== "edit") {
68
+ selection.set([]);
69
+ return;
70
+ }
65
71
  const intent = desiredFocus;
66
72
  const nodeId = intent?.nodeId;
67
73
  if (!intent || !nodeId) {
74
+ selection.set([]);
68
75
  sendApplied("exact");
69
76
  return;
70
77
  }
@@ -72,6 +79,7 @@ function mountPreviewController(options) {
72
79
  decoratePreviewTargets(scope);
73
80
  const target = resolvePreviewTarget(scope, nodeId, fallbacks);
74
81
  selectedElements = target.elements;
82
+ selection.set(selectedElements);
75
83
  for (const element of selectedElements) element.setAttribute("data-cms-selected", "");
76
84
  const result = !target.resolvedNodeId ? "missing" : target.resolvedNodeId === nodeId ? "exact" : "fallback";
77
85
  if (reveal && result !== "missing" && revealedIntentId !== intent.id) {
@@ -83,12 +91,19 @@ function mountPreviewController(options) {
83
91
  const hoverElements = (target) => {
84
92
  clearElements(hoveredElements, "data-cms-hovered");
85
93
  hoveredElements = [];
86
- if (!active || mode !== "edit" || !target) return;
94
+ if (!active || mode !== "edit" || !target) {
95
+ hover.set([]);
96
+ return;
97
+ }
87
98
  const scope = target.closest("[data-cms-document]") ?? root;
88
99
  const nodeId = findPreviewNodeId(scope, target);
89
- if (!nodeId) return;
100
+ if (!nodeId) {
101
+ hover.set([]);
102
+ return;
103
+ }
90
104
  hoveredElements = resolvePreviewTarget(scope, nodeId, fallbacks).elements;
91
105
  for (const element of hoveredElements) element.setAttribute("data-cms-hovered", "");
106
+ hover.set(hoveredElements);
92
107
  };
93
108
  const settleRender = (sequence) => {
94
109
  view.requestAnimationFrame(() => view.requestAnimationFrame(() => {
@@ -116,6 +131,7 @@ function mountPreviewController(options) {
116
131
  hoverElements();
117
132
  clearElements(selectedElements, "data-cms-selected");
118
133
  selectedElements = [];
134
+ selection.set([]);
119
135
  } else {
120
136
  decoratePreviewTargets(root);
121
137
  applyFocus();
@@ -152,7 +168,8 @@ function mountPreviewController(options) {
152
168
  const destination = new URL(link.href, view.location.href);
153
169
  if (destination.origin !== view.location.origin) return;
154
170
  event.preventDefault();
155
- options.navigate(destination.pathname);
171
+ event.stopPropagation();
172
+ options.navigate(`${destination.pathname}${destination.search}${destination.hash}`);
156
173
  return;
157
174
  }
158
175
  const scope = target?.closest("[data-cms-document]");
@@ -202,7 +219,8 @@ function mountPreviewController(options) {
202
219
  if (!(event.relatedTarget instanceof Element)) hoverElements();
203
220
  };
204
221
  let mutationQueued = false;
205
- const observer = new MutationObserver(() => {
222
+ const observer = new MutationObserver((records) => {
223
+ if (records.every((record) => record.target instanceof Element && record.target.closest("[data-cms-preview-overlay]"))) return;
206
224
  if (mutationQueued) return;
207
225
  mutationQueued = true;
208
226
  queueMicrotask(() => {
@@ -224,6 +242,8 @@ function mountPreviewController(options) {
224
242
  stopBridge();
225
243
  stopManifest();
226
244
  observer.disconnect();
245
+ selection.destroy();
246
+ hover.destroy();
227
247
  root.removeEventListener("click", handleClick, true);
228
248
  root.removeEventListener("pointerover", handlePointerOver, true);
229
249
  root.removeEventListener("pointerout", handlePointerOut, true);
@@ -233,10 +253,9 @@ function mountPreviewController(options) {
233
253
  function revealElement(element, view) {
234
254
  if (!element) return;
235
255
  const rect = element.getBoundingClientRect();
236
- const margin = Math.min(80, view.innerHeight / 5);
237
- if (rect.top >= margin && rect.bottom <= view.innerHeight - margin) return;
256
+ if (rect.bottom > 0 && rect.top < view.innerHeight && rect.right > 0 && rect.left < view.innerWidth) return;
238
257
  element.scrollIntoView({
239
- behavior: view.matchMedia("(prefers-reduced-motion: reduce)").matches ? "auto" : "smooth",
258
+ behavior: "instant",
240
259
  block: "center",
241
260
  inline: "nearest"
242
261
  });
@@ -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: '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 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 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') {\n selection.set([])\n return\n }\n const intent = desiredFocus\n const nodeId = intent?.nodeId\n if (!intent || !nodeId) {\n selection.set([])\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 selection.set(selectedElements)\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) {\n hover.set([])\n return\n }\n const scope = target.closest('[data-cms-document]') ?? root\n const nodeId = findPreviewNodeId(scope, target)\n if (!nodeId) {\n hover.set([])\n return\n }\n hoveredElements = resolvePreviewTarget(scope, nodeId, fallbacks).elements\n for (const element of hoveredElements) element.setAttribute('data-cms-hovered', '')\n hover.set(hoveredElements)\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 selection.set([])\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 event.stopPropagation()\n void options.navigate(`${destination.pathname}${destination.search}${destination.hash}`)\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((records) => {\n if (\n records.every((record) => record.target instanceof Element && record.target.closest('[data-cms-preview-overlay]'))\n )\n return\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 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 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 for (const [index, element] of targets.entries()) {\n const outline = outlines[index]\n if (!outline) continue\n const rect = element.getBoundingClientRect()\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 outline.hidden = !visible\n outline.toggleAttribute('data-cms-selection-label', kind === 'selection' && visible && !labelled)\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 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 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 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 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;EACf,KAAK,MAAM,CAAC,OAAO,YAAY,QAAQ,QAAQ,GAAG;GAChD,MAAM,UAAU,SAAS;GACzB,IAAI,CAAC,SAAS;GACd,MAAM,OAAO,QAAQ,sBAAsB;GAC3C,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;GACnB,QAAQ,SAAS,CAAC;GAClB,QAAQ,gBAAgB,4BAA4B,SAAS,eAAe,WAAW,CAAC,QAAQ;GAChG,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;EACA,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;GAC1G,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;IACvG,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;IAEF,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,38 +1,15 @@
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";
1
+ import { yt as PublicPath } from "../../models-BkMgeaOL.js";
2
+ import { t as openSitePreviewConnection } from "../../connection-CBTY-TzB.js";
3
+ import { n as readPreviewLocation, r as withPreviewLocation } from "../../location-DtYv2aes.js";
5
4
  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
- }
5
+ import { t as createStudioPreviewStore } from "../../store-CfFFx9Ua.js";
6
+ import { documentPreviewStoreKey } from "../delivery/preview.js";
7
+ import { Schema } from "effect";
8
+ import { defineNuxtPlugin, navigateTo, onNuxtReady, useNuxtApp, useState } from "nuxt/app";
9
+ import { watch } from "vue";
32
10
 
33
- //#endregion
34
11
  //#region src/runtime/preview/plugin.client.ts
35
- var plugin_client_default = defineNuxtPlugin(async () => {
12
+ var plugin_client_default = defineNuxtPlugin(() => {
36
13
  const parameters = readPreviewLocation(new URL(window.location.href));
37
14
  if (!parameters) return;
38
15
  const route = () => Schema.decodeSync(PublicPath)(window.location.pathname);
@@ -40,12 +17,21 @@ var plugin_client_default = defineNuxtPlugin(async () => {
40
17
  const nuxtApp = useNuxtApp();
41
18
  nuxtApp.vueApp.provide(documentPreviewStoreKey, store);
42
19
  nuxtApp.hooks.hook("page:finish", store.routeChanged);
20
+ const error = useState("cms:preview-error", () => null);
43
21
  const mount = async () => {
44
22
  const connection = await openSitePreviewConnection({
45
23
  editorOrigin: parameters.editorOrigin,
46
24
  route: route(),
47
25
  sessionId: parameters.sessionId
48
26
  });
27
+ const sendError = () => connection.send({
28
+ type: "preview:error",
29
+ message: error.value
30
+ });
31
+ const stopError = watch(error, sendError, { immediate: true });
32
+ const stopConnect = connection.subscribe((message) => {
33
+ if (message.type === "studio:connect") sendError();
34
+ });
49
35
  const unmount = mountPreviewController({
50
36
  bridge: connection,
51
37
  navigate: async (path) => {
@@ -57,12 +43,13 @@ var plugin_client_default = defineNuxtPlugin(async () => {
57
43
  view: window
58
44
  });
59
45
  window.addEventListener("pagehide", () => {
46
+ stopError();
47
+ stopConnect();
60
48
  unmount();
61
49
  connection.close();
62
50
  }, { once: true });
63
51
  };
64
- if (nuxtApp.isHydrating) nuxtApp.hooks.hookOnce("app:suspense:resolve", mount);
65
- else await mount();
52
+ onNuxtReady(mount);
66
53
  });
67
54
 
68
55
  //#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 { defineNuxtPlugin, navigateTo, onNuxtReady, useNuxtApp, useState } from 'nuxt/app'\nimport { watch } from 'vue'\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(() => {\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 error = useState<string | null>('cms:preview-error', () => null)\n const mount = async () => {\n const connection = await openSitePreviewConnection({\n editorOrigin: parameters.editorOrigin,\n route: route(),\n sessionId: parameters.sessionId,\n })\n const sendError = () => connection.send({ type: 'preview:error', message: error.value })\n const stopError = watch(error, sendError, { immediate: true })\n const stopConnect = connection.subscribe((message) => {\n if (message.type === 'studio:connect') sendError()\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 stopError()\n stopConnect()\n unmount()\n void connection.close()\n },\n { once: true },\n )\n }\n\n onNuxtReady(mount)\n})\n"],"mappings":";;;;;;;;;;;AASA,4BAAe,uBAAuB;CACpC,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,SAAwB,2BAA2B,IAAI;CACrE,MAAM,QAAQ,YAAY;EACxB,MAAM,aAAa,MAAM,0BAA0B;GACjD,cAAc,WAAW;GACzB,OAAO,MAAM;GACb,WAAW,WAAW;EACxB,CAAC;EACD,MAAM,kBAAkB,WAAW,KAAK;GAAE,MAAM;GAAiB,SAAS,MAAM;EAAM,CAAC;EACvF,MAAM,YAAY,MAAM,OAAO,WAAW,EAAE,WAAW,KAAK,CAAC;EAC7D,MAAM,cAAc,WAAW,WAAW,YAAY;GACpD,IAAI,QAAQ,SAAS,kBAAkB,UAAU;EACnD,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,UAAU;GACV,YAAY;GACZ,QAAQ;GACR,AAAK,WAAW,MAAM;EACxB,GACA,EAAE,MAAM,KAAK,CACf;CACF;CAEA,YAAY,KAAK;AACnB,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,4 +1,4 @@
1
+ import { t as createStudioPreviewStore } from "../../store-CfFFx9Ua.js";
1
2
  import { documentPreviewStoreKey } from "../delivery/preview.js";
2
- import { t as createStudioPreviewStore } from "../../store-Nl4uxEXx.js";
3
3
 
4
4
  export { createStudioPreviewStore, documentPreviewStoreKey };
@@ -1,9 +1,13 @@
1
1
  import { defineEventHandler, setResponseHeader } from "h3";
2
2
 
3
3
  //#region src/runtime/studio-app.ts
4
- function createStudioAppHandler(shell) {
4
+ function createStudioAppHandler(entryUrl, hmrUrl) {
5
+ const escape = (value) => value.replaceAll("&", "&amp;").replaceAll("\"", "&quot;").replaceAll("<", "&lt;");
6
+ const script = (url) => `<script type="module" src="${escape(url)}"><\/script>`;
7
+ const shell = `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>CMS Studio</title></head><body><div id="cms-studio"></div>${hmrUrl ? script(hmrUrl) : ""}${script(entryUrl)}</body></html>`;
5
8
  return defineEventHandler((event) => {
6
9
  setResponseHeader(event, "content-type", "text/html; charset=utf-8");
10
+ setResponseHeader(event, "cache-control", "no-store");
7
11
  return shell;
8
12
  });
9
13
  }
@@ -1 +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"}
1
+ {"version":3,"file":"studio-app.js","names":[],"sources":["../../../../src/runtime/studio-app.ts"],"sourcesContent":["import { defineEventHandler, setResponseHeader } from 'h3'\n\nexport function createStudioAppHandler(entryUrl: string, hmrUrl?: string) {\n const escape = (value: string) => value.replaceAll('&', '&amp;').replaceAll('\"', '&quot;').replaceAll('<', '&lt;')\n const script = (url: string) => `<script type=\"module\" src=\"${escape(url)}\"></script>`\n const shell = `<!doctype html><html lang=\"en\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><title>CMS Studio</title></head><body><div id=\"cms-studio\"></div>${hmrUrl ? script(hmrUrl) : ''}${script(entryUrl)}</body></html>`\n return defineEventHandler((event) => {\n setResponseHeader(event, 'content-type', 'text/html; charset=utf-8')\n setResponseHeader(event, 'cache-control', 'no-store')\n return shell\n })\n}\n"],"mappings":";;;AAEA,SAAgB,uBAAuB,UAAkB,QAAiB;CACxE,MAAM,UAAU,UAAkB,MAAM,WAAW,KAAK,OAAO,CAAC,CAAC,WAAW,MAAK,QAAQ,CAAC,CAAC,WAAW,KAAK,MAAM;CACjH,MAAM,UAAU,QAAgB,8BAA8B,OAAO,GAAG,EAAE;CAC1E,MAAM,QAAQ,mMAAmM,SAAS,OAAO,MAAM,IAAI,KAAK,OAAO,QAAQ,EAAE;CACjQ,OAAO,oBAAoB,UAAU;EACnC,kBAAkB,OAAO,gBAAgB,0BAA0B;EACnE,kBAAkB,OAAO,iBAAiB,UAAU;EACpD,OAAO;CACT,CAAC;AACH"}
@@ -0,0 +1,36 @@
1
+ import { mountStudio } from "#cms/studio";
2
+ import catalog from "#cms/authoring";
3
+ import stylesheet from "#cms/studio-styles";
4
+
5
+ //#region src/runtime/studio-entry.ts
6
+ const root = document.getElementById("cms-studio");
7
+ if (!root) throw new Error("CMS Studio root is missing.");
8
+ let currentCatalog = catalog;
9
+ let studio;
10
+ const link = document.createElement("link");
11
+ link.rel = "stylesheet";
12
+ link.href = stylesheet;
13
+ link.onload = () => {
14
+ studio = mountStudio(root, currentCatalog);
15
+ };
16
+ link.onerror = () => {
17
+ root.textContent = "CMS Studio styles could not load. Reload this page to retry.";
18
+ };
19
+ document.head.append(link);
20
+ if (import.meta.hot) {
21
+ import.meta.hot.accept("#cms/authoring", (module) => {
22
+ if (!module) return;
23
+ currentCatalog = module.default;
24
+ studio?.updateAuthoring(currentCatalog);
25
+ });
26
+ import.meta.hot.dispose(() => {
27
+ link.onload = null;
28
+ link.onerror = null;
29
+ studio?.unmount();
30
+ link.remove();
31
+ });
32
+ }
33
+
34
+ //#endregion
35
+ export { };
36
+ //# sourceMappingURL=studio-entry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"studio-entry.js","names":[],"sources":["../../../../src/runtime/studio-entry.ts"],"sourcesContent":["import { mountStudio } from '#cms/studio'\nimport catalog from '#cms/authoring'\nimport stylesheet from '#cms/studio-styles'\n\nconst root = document.getElementById('cms-studio')\nif (!root) throw new Error('CMS Studio root is missing.')\nlet currentCatalog = catalog\nlet studio: ReturnType<typeof mountStudio> | undefined\nconst link = document.createElement('link')\nlink.rel = 'stylesheet'\nlink.href = stylesheet\nlink.onload = () => {\n studio = mountStudio(root, currentCatalog)\n}\nlink.onerror = () => {\n root.textContent = 'CMS Studio styles could not load. Reload this page to retry.'\n}\ndocument.head.append(link)\nif (import.meta.hot) {\n import.meta.hot.accept('#cms/authoring', (module) => {\n if (!module) return\n currentCatalog = module.default\n studio?.updateAuthoring(currentCatalog)\n })\n import.meta.hot.dispose(() => {\n link.onload = null\n link.onerror = null\n studio?.unmount()\n link.remove()\n })\n}\n"],"mappings":";;;;;AAIA,MAAM,OAAO,SAAS,eAAe,YAAY;AACjD,IAAI,CAAC,MAAM,MAAM,IAAI,MAAM,6BAA6B;AACxD,IAAI,iBAAiB;AACrB,IAAI;AACJ,MAAM,OAAO,SAAS,cAAc,MAAM;AAC1C,KAAK,MAAM;AACX,KAAK,OAAO;AACZ,KAAK,eAAe;CAClB,SAAS,YAAY,MAAM,cAAc;AAC3C;AACA,KAAK,gBAAgB;CACnB,KAAK,cAAc;AACrB;AACA,SAAS,KAAK,OAAO,IAAI;AACzB,IAAI,YAAY,KAAK;CACnB,YAAY,IAAI,OAAO,mBAAmB,WAAW;EACnD,IAAI,CAAC,QAAQ;EACb,iBAAiB,OAAO;EACxB,QAAQ,gBAAgB,cAAc;CACxC,CAAC;CACD,YAAY,IAAI,cAAc;EAC5B,KAAK,SAAS;EACd,KAAK,UAAU;EACf,QAAQ,QAAQ;EAChB,KAAK,OAAO;CACd,CAAC;AACH"}
@@ -0,0 +1,11 @@
1
+ import { l as STUDIO_APP_PATH, u as STUDIO_BASE_PATH } from "../HttpPaths-BbS21Jy8.js";
2
+ import { defineNuxtRouteMiddleware, navigateTo } from "nuxt/app";
3
+
4
+ //#region src/runtime/studio-navigation.ts
5
+ var studio_navigation_default = defineNuxtRouteMiddleware((to) => {
6
+ if (to.path === "/_cms" || to.path === STUDIO_APP_PATH || to.path.startsWith(`${STUDIO_APP_PATH}/`)) return navigateTo(to.fullPath, { external: true });
7
+ });
8
+
9
+ //#endregion
10
+ export { studio_navigation_default as default };
11
+ //# sourceMappingURL=studio-navigation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"studio-navigation.js","names":[],"sources":["../../../../src/runtime/studio-navigation.ts"],"sourcesContent":["import { defineNuxtRouteMiddleware, navigateTo } from 'nuxt/app'\nimport { STUDIO_APP_PATH, STUDIO_BASE_PATH } from '@internal/protocol/HttpPaths'\n\nexport default defineNuxtRouteMiddleware((to) => {\n if (to.path === STUDIO_BASE_PATH || to.path === STUDIO_APP_PATH || to.path.startsWith(`${STUDIO_APP_PATH}/`)) {\n return navigateTo(to.fullPath, { external: true })\n }\n})\n"],"mappings":";;;;AAGA,gCAAe,2BAA2B,OAAO;CAC/C,IAAI,GAAG,oBAA6B,GAAG,SAAS,mBAAmB,GAAG,KAAK,WAAW,GAAG,gBAAgB,EAAE,GACzG,OAAO,WAAW,GAAG,UAAU,EAAE,UAAU,KAAK,CAAC;AAErD,CAAC"}
@@ -1,5 +1,5 @@
1
- import { H as PublicPath, P as CollectionName, n as CmsMarkdownDocument, z as DocumentId } from "./models-Citx8jBi.js";
2
- import { l as mutableJson, n as editorMetadata, u as mutableJsonObject } from "./metadata-Czvi3E4K.js";
1
+ import { gt as DocumentId, n as CmsMarkdownDocument, ut as CollectionName, yt as PublicPath } from "./models-BkMgeaOL.js";
2
+ import { l as mutableJson, n as editorMetadata, u as mutableJsonObject } from "./metadata-DE1Mc2td.js";
3
3
  import { CMS_PREVIEW_INLINE_HOST_ATTRIBUTE, CMS_PREVIEW_MARKER_TAG, CMS_PREVIEW_NODE_ATTRIBUTE, CMS_PREVIEW_TARGET_ATTRIBUTE, CMS_PREVIEW_WRAPPER_ATTRIBUTE } from "./runtime/preview/protocol.js";
4
4
  import { toPreviewRenderDocument } from "./runtime/preview/comark-document.js";
5
5
  import { Predicate, Result, Schema } from "effect";
@@ -218,4 +218,4 @@ function createPreviewDocument(body) {
218
218
 
219
219
  //#endregion
220
220
  export { createStudioPreviewStore as t };
221
- //# sourceMappingURL=store-Nl4uxEXx.js.map
221
+ //# sourceMappingURL=store-CfFFx9Ua.js.map