@kotao/storefront 0.2.5 → 0.2.7

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 (70) hide show
  1. package/README.md +57 -2
  2. package/dist/bridge-CfNBWu0H.d.ts +260 -0
  3. package/dist/cart-documents-BLavRDiu.d.ts +89 -0
  4. package/dist/cart-documents.d.ts +1 -2
  5. package/dist/cart-documents.js +1 -1
  6. package/dist/{chunk-M7BPQ54D.js → chunk-2MRB6SMP.js} +4 -3
  7. package/dist/chunk-2MRB6SMP.js.map +1 -0
  8. package/dist/chunk-CKGI3Y7L.js +19 -0
  9. package/dist/chunk-CKGI3Y7L.js.map +1 -0
  10. package/dist/{chunk-GGOZELAA.js → chunk-DTKLAOKR.js} +231 -165
  11. package/dist/chunk-DTKLAOKR.js.map +1 -0
  12. package/dist/{chunk-MCIFKJQK.js → chunk-R4N565GX.js} +5 -2
  13. package/dist/chunk-R4N565GX.js.map +1 -0
  14. package/dist/chunk-RFKLO6TD.js +1594 -0
  15. package/dist/chunk-RFKLO6TD.js.map +1 -0
  16. package/dist/{chunk-XMTWFJCZ.js → chunk-RFM27BKZ.js} +31 -7
  17. package/dist/chunk-RFM27BKZ.js.map +1 -0
  18. package/dist/{chunk-MYDKIJRH.js → chunk-SVMYFYIA.js} +2 -2
  19. package/dist/{chunk-MYDKIJRH.js.map → chunk-SVMYFYIA.js.map} +1 -1
  20. package/dist/{chunk-H3D7BAOL.js → chunk-VOTBNOWH.js} +21 -3
  21. package/dist/chunk-VOTBNOWH.js.map +1 -0
  22. package/dist/{chunk-PXVDVUFX.js → chunk-W74FGUZH.js} +10 -3
  23. package/dist/chunk-W74FGUZH.js.map +1 -0
  24. package/dist/{chunk-2IWNUDSZ.js → chunk-WNXI3MPM.js} +2 -2
  25. package/dist/chunk-WNXI3MPM.js.map +1 -0
  26. package/dist/chunk-XXNCFWXT.js +2118 -0
  27. package/dist/chunk-XXNCFWXT.js.map +1 -0
  28. package/dist/{client-bsiNPHBi.d.ts → client-CwOPPpFF.d.ts} +11 -1
  29. package/dist/{createCartHandler-C4RrPwSG.d.ts → createCartHandler-7DdKB-GF.d.ts} +1 -1
  30. package/dist/custom-css-Bl7Ur3-H.d.ts +6 -0
  31. package/dist/editor.d.ts +57 -104
  32. package/dist/editor.js +270 -1
  33. package/dist/editor.js.map +1 -1
  34. package/dist/events-react.d.ts +4 -2
  35. package/dist/events-react.js +6 -4
  36. package/dist/events-react.js.map +1 -1
  37. package/dist/events.d.ts +3 -3
  38. package/dist/events.js +1 -1
  39. package/dist/{fetch-M3Y-fQrW.d.ts → fetch-Bq_cc8_G.d.ts} +5 -0
  40. package/dist/hydrogen-CqDMW3YC.d.ts +259 -0
  41. package/dist/index.d.ts +75 -51
  42. package/dist/index.js +19 -15
  43. package/dist/index.js.map +1 -1
  44. package/dist/react-router.d.ts +40 -9
  45. package/dist/react-router.js +16 -7
  46. package/dist/react-router.js.map +1 -1
  47. package/dist/react.d.ts +79 -11
  48. package/dist/react.js +279 -10
  49. package/dist/react.js.map +1 -1
  50. package/dist/{routing-sEonP93J.d.ts → routing-Bz3Cg0BW.d.ts} +36 -6
  51. package/dist/seo.d.ts +7 -4
  52. package/dist/seo.js +2 -2
  53. package/dist/settings.d.ts +14 -4
  54. package/dist/settings.js +2 -2
  55. package/dist/{shop-BJSvtmnV.d.ts → shop-CnrnSAJw.d.ts} +33 -6
  56. package/dist/{store-CtCWHI8H.d.ts → store-ZzoBbWir.d.ts} +1 -1
  57. package/dist/storefront-api-types.d.ts +12 -0
  58. package/dist/{types-BDhHWZsP.d.ts → types-BkY0yET-.d.ts} +3 -3
  59. package/dist/{types-bcbQzx87.d.ts → types-DZX8ScsJ.d.ts} +2 -0
  60. package/package.json +4 -4
  61. package/dist/cart-documents-CwwRTvm8.d.ts +0 -21
  62. package/dist/chunk-2IWNUDSZ.js.map +0 -1
  63. package/dist/chunk-GGOZELAA.js.map +0 -1
  64. package/dist/chunk-H3D7BAOL.js.map +0 -1
  65. package/dist/chunk-M7BPQ54D.js.map +0 -1
  66. package/dist/chunk-MCIFKJQK.js.map +0 -1
  67. package/dist/chunk-PXVDVUFX.js.map +0 -1
  68. package/dist/chunk-PXZ737N3.js +0 -439
  69. package/dist/chunk-PXZ737N3.js.map +0 -1
  70. package/dist/chunk-XMTWFJCZ.js.map +0 -1
@@ -0,0 +1,1594 @@
1
+ // src/editor/bridge.ts
2
+ var HOST_SOURCE = "kotao:workspaces-editor";
3
+ var PREVIEW_SOURCE = "kotao:storefront-preview";
4
+ var VISUAL_READY_REQUEST_ID = /^[A-Za-z0-9_-]{1,128}$/u;
5
+ function isReservedSectionId(sectionId) {
6
+ return sectionId.startsWith("theme:");
7
+ }
8
+ function isRecord(value) {
9
+ return typeof value === "object" && value !== null && !Array.isArray(value);
10
+ }
11
+ function isSettings(value) {
12
+ return isRecord(value);
13
+ }
14
+ function isOptionalSettings(value) {
15
+ return value === void 0 || isSettings(value);
16
+ }
17
+ function isBlockId(value) {
18
+ return typeof value === "string" && value.length > 0;
19
+ }
20
+ function isResolvedBlock(value) {
21
+ return isRecord(value) && (value.id === void 0 || isBlockId(value.id)) && typeof value.type === "string" && isSettings(value.settings);
22
+ }
23
+ function isResolvedSection(value) {
24
+ if (!isRecord(value)) return false;
25
+ return typeof value.id === "string" && typeof value.type === "string" && isSettings(value.settings) && Array.isArray(value.blocks) && value.blocks.every(isResolvedBlock);
26
+ }
27
+ function isValuesDocument(value) {
28
+ return isRecord(value) && typeof value.shopId === "string" && value.shopId.length > 0 && isResolvedSectionArray(value.sections);
29
+ }
30
+ function isSettingOption(value) {
31
+ return isRecord(value) && typeof value.value === "string" && typeof value.label === "string";
32
+ }
33
+ function isOptionalString(value) {
34
+ return value === void 0 || typeof value === "string";
35
+ }
36
+ function isOptionalFiniteNumber(value) {
37
+ return value === void 0 || typeof value === "number" && Number.isFinite(value);
38
+ }
39
+ function isOptionalPositiveInteger(value) {
40
+ return value === void 0 || typeof value === "number" && Number.isInteger(value) && value > 0;
41
+ }
42
+ function isSettingInput(value) {
43
+ if (!isRecord(value) || typeof value.type !== "string" || typeof value.name !== "string" || typeof value.label !== "string") {
44
+ return false;
45
+ }
46
+ return isOptionalString(value.placeholder) && isOptionalString(value.helpText) && isOptionalString(value.group) && isOptionalString(value.unit) && isOptionalFiniteNumber(value.min) && isOptionalFiniteNumber(value.max) && isOptionalFiniteNumber(value.step) && (value.options === void 0 || Array.isArray(value.options) && value.options.every(isSettingOption));
47
+ }
48
+ function isBlockSchema(value) {
49
+ return isRecord(value) && typeof value.type === "string" && typeof value.label === "string" && Array.isArray(value.settings) && value.settings.every(isSettingInput) && isOptionalPositiveInteger(value.limit);
50
+ }
51
+ function isSectionPresetBlock(value) {
52
+ return isRecord(value) && typeof value.type === "string" && isOptionalSettings(value.settings);
53
+ }
54
+ function isSectionPreset(value) {
55
+ return isRecord(value) && typeof value.name === "string" && isOptionalSettings(value.settings) && (value.blocks === void 0 || Array.isArray(value.blocks) && value.blocks.every(isSectionPresetBlock));
56
+ }
57
+ function isSectionSchema(value) {
58
+ return isRecord(value) && typeof value.type === "string" && typeof value.label === "string" && Array.isArray(value.settings) && value.settings.every(isSettingInput) && isOptionalPositiveInteger(value.maxBlocks) && (value.blocks === void 0 || Array.isArray(value.blocks) && value.blocks.every(isBlockSchema)) && (value.presets === void 0 || Array.isArray(value.presets) && value.presets.every(isSectionPreset));
59
+ }
60
+ function isResolvedSectionArray(value) {
61
+ return Array.isArray(value) && value.every(isResolvedSection);
62
+ }
63
+ function isSectionSchemaRecord(value) {
64
+ return isRecord(value) && Object.values(value).every(isSectionSchema);
65
+ }
66
+ function isSettingInputArray(value) {
67
+ return Array.isArray(value) && value.every(isSettingInput);
68
+ }
69
+ function isThemeStyle(value) {
70
+ return isRecord(value) && typeof value.name === "string" && isSettings(value.settings);
71
+ }
72
+ function isThemeStyleArray(value) {
73
+ return Array.isArray(value) && value.every(isThemeStyle);
74
+ }
75
+ function validValuesDocuments(value) {
76
+ if (!isRecord(value)) return void 0;
77
+ const documents = {};
78
+ for (const [handle, document] of Object.entries(value)) {
79
+ if (isValuesDocument(document)) documents[handle] = document;
80
+ }
81
+ return documents;
82
+ }
83
+ function isSelectionScope(value) {
84
+ return isRecord(value) && (value.kind === "template" || value.kind === "sectionGroup") && typeof value.handle === "string" && value.handle.trim() !== "";
85
+ }
86
+ function isHttpsUrl(value) {
87
+ if (typeof value !== "string") return false;
88
+ try {
89
+ const url = new URL(value);
90
+ return url.protocol === "https:" && url.username === "" && url.password === "";
91
+ } catch {
92
+ return false;
93
+ }
94
+ }
95
+ function isBareHttpOrigin(value) {
96
+ if (typeof value !== "string") return false;
97
+ try {
98
+ const url = new URL(value);
99
+ return (url.protocol === "https:" || url.protocol === "http:") && url.username === "" && url.password === "" && url.pathname === "/" && url.search === "" && url.hash === "";
100
+ } catch {
101
+ return false;
102
+ }
103
+ }
104
+ function isAppExtensionPreview(value) {
105
+ if (!isRecord(value) || value.kind !== "app_embed" && value.kind !== "app_section" && value.kind !== "app_block" || typeof value.instanceId !== "string" || typeof value.appId !== "string" || typeof value.appName !== "string" || typeof value.extensionId !== "string" || typeof value.extensionName !== "string" || typeof value.version !== "string" || !isHttpsUrl(value.entrypointUrl) || !Array.isArray(value.stylesheetUrls) || !value.stylesheetUrls.every(isHttpsUrl) || !Array.isArray(value.capabilities) || !value.capabilities.every((capability) => typeof capability === "string") || !Array.isArray(value.allowedOrigins) || !value.allowedOrigins.every(isBareHttpOrigin) || !isSettings(value.settings) || typeof value.position !== "number" || !Number.isInteger(value.position) || value.position < 0) {
106
+ return false;
107
+ }
108
+ if (value.kind === "app_embed") {
109
+ return value.embedLocation === "head" || value.embedLocation === "body_start" || value.embedLocation === "body_end";
110
+ }
111
+ if (value.kind === "app_section") {
112
+ return isRecord(value.target) && (value.target.kind === "template" || value.target.kind === "section_group") && typeof value.target.handle === "string" && value.target.handle !== "";
113
+ }
114
+ return typeof value.templateHandle === "string" && isBlockId(value.sectionInstanceId);
115
+ }
116
+ function parseHostMessage(data, shopId) {
117
+ if (!isRecord(data) || data.source !== HOST_SOURCE || data.shopId !== shopId) return null;
118
+ switch (data.type) {
119
+ case "editor.ready.request":
120
+ return {
121
+ source: HOST_SOURCE,
122
+ type: "editor.ready.request",
123
+ shopId
124
+ };
125
+ case "editor.visual-ready.request":
126
+ return typeof data.requestId === "string" && VISUAL_READY_REQUEST_ID.test(data.requestId) ? {
127
+ source: HOST_SOURCE,
128
+ type: "editor.visual-ready.request",
129
+ shopId,
130
+ requestId: data.requestId
131
+ } : null;
132
+ case "section.hover":
133
+ case "section.activate":
134
+ if (data.sectionId !== null && (typeof data.sectionId !== "string" || isReservedSectionId(data.sectionId))) {
135
+ return null;
136
+ }
137
+ if (data.blockId !== void 0 && (data.type !== "section.activate" || !isBlockId(data.blockId))) {
138
+ return null;
139
+ }
140
+ return {
141
+ source: HOST_SOURCE,
142
+ type: data.type,
143
+ shopId,
144
+ sectionId: data.sectionId,
145
+ ...data.blockId !== void 0 ? { blockId: data.blockId } : {}
146
+ };
147
+ case "inspector.set":
148
+ return typeof data.enabled === "boolean" ? { source: HOST_SOURCE, type: "inspector.set", shopId, enabled: data.enabled } : null;
149
+ case "settings.patchSection":
150
+ return typeof data.sectionId === "string" && !isReservedSectionId(data.sectionId) && isSettings(data.settings) ? {
151
+ source: HOST_SOURCE,
152
+ type: "settings.patchSection",
153
+ shopId,
154
+ sectionId: data.sectionId,
155
+ settings: data.settings
156
+ } : null;
157
+ case "settings.patchGlobal":
158
+ return isSettings(data.settings) ? { source: HOST_SOURCE, type: "settings.patchGlobal", shopId, settings: data.settings } : null;
159
+ case "sections.insert":
160
+ return isResolvedSection(data.section) && !isReservedSectionId(data.section.id) ? {
161
+ source: HOST_SOURCE,
162
+ type: "sections.insert",
163
+ shopId,
164
+ section: data.section,
165
+ ...typeof data.index === "number" ? { index: data.index } : {}
166
+ } : null;
167
+ case "sections.remove":
168
+ return typeof data.sectionId === "string" && !isReservedSectionId(data.sectionId) ? {
169
+ source: HOST_SOURCE,
170
+ type: "sections.remove",
171
+ shopId,
172
+ sectionId: data.sectionId
173
+ } : null;
174
+ case "sections.reorder":
175
+ return typeof data.sectionId === "string" && !isReservedSectionId(data.sectionId) && typeof data.index === "number" ? {
176
+ source: HOST_SOURCE,
177
+ type: "sections.reorder",
178
+ shopId,
179
+ sectionId: data.sectionId,
180
+ index: data.index
181
+ } : null;
182
+ case "settings.patchBlock":
183
+ return typeof data.sectionId === "string" && !isReservedSectionId(data.sectionId) && isBlockId(data.blockId) && isSettings(data.settings) ? {
184
+ source: HOST_SOURCE,
185
+ type: "settings.patchBlock",
186
+ shopId,
187
+ sectionId: data.sectionId,
188
+ blockId: data.blockId,
189
+ settings: data.settings
190
+ } : null;
191
+ case "blocks.insert":
192
+ return typeof data.sectionId === "string" && !isReservedSectionId(data.sectionId) && isResolvedBlock(data.block) ? {
193
+ source: HOST_SOURCE,
194
+ type: "blocks.insert",
195
+ shopId,
196
+ sectionId: data.sectionId,
197
+ block: data.block,
198
+ ...typeof data.index === "number" ? { index: data.index } : {}
199
+ } : null;
200
+ case "blocks.remove":
201
+ return typeof data.sectionId === "string" && !isReservedSectionId(data.sectionId) && isBlockId(data.blockId) ? {
202
+ source: HOST_SOURCE,
203
+ type: "blocks.remove",
204
+ shopId,
205
+ sectionId: data.sectionId,
206
+ blockId: data.blockId
207
+ } : null;
208
+ case "blocks.reorder":
209
+ return typeof data.sectionId === "string" && !isReservedSectionId(data.sectionId) && isBlockId(data.blockId) && typeof data.index === "number" ? {
210
+ source: HOST_SOURCE,
211
+ type: "blocks.reorder",
212
+ shopId,
213
+ sectionId: data.sectionId,
214
+ blockId: data.blockId,
215
+ index: data.index
216
+ } : null;
217
+ case "template.replace":
218
+ return typeof data.handle === "string" && isValuesDocument(data.document) ? {
219
+ source: HOST_SOURCE,
220
+ type: "template.replace",
221
+ shopId,
222
+ handle: data.handle,
223
+ document: data.document
224
+ } : null;
225
+ case "sectionGroup.replace":
226
+ return typeof data.handle === "string" && data.handle.trim() !== "" && isValuesDocument(data.document) ? {
227
+ source: HOST_SOURCE,
228
+ type: "sectionGroup.replace",
229
+ shopId,
230
+ handle: data.handle,
231
+ document: data.document
232
+ } : null;
233
+ case "appExtensions.replace":
234
+ return Array.isArray(data.extensions) && data.extensions.every(isAppExtensionPreview) ? {
235
+ source: HOST_SOURCE,
236
+ type: "appExtensions.replace",
237
+ shopId,
238
+ extensions: data.extensions
239
+ } : null;
240
+ default:
241
+ return null;
242
+ }
243
+ }
244
+ function parsePreviewSelection(data, shopId) {
245
+ if (!isRecord(data) || data.source !== PREVIEW_SOURCE || data.shopId !== shopId) return null;
246
+ if (data.type !== "section.select" || typeof data.sectionId !== "string") return null;
247
+ if (data.blockId !== void 0 && !isBlockId(data.blockId)) return null;
248
+ if (data.block !== void 0 && !isResolvedBlock(data.block)) return null;
249
+ if (data.block !== void 0 && data.blockId === void 0) return null;
250
+ if (data.section !== void 0 && !isResolvedSection(data.section)) return null;
251
+ if (data.sections !== void 0 && !isResolvedSectionArray(data.sections)) return null;
252
+ if (data.schema !== void 0 && !isSectionSchema(data.schema)) return null;
253
+ if (data.schemas !== void 0 && !isSectionSchemaRecord(data.schemas)) return null;
254
+ if (data.scope !== void 0 && !isSelectionScope(data.scope)) return null;
255
+ return {
256
+ source: PREVIEW_SOURCE,
257
+ type: "section.select",
258
+ shopId,
259
+ sectionId: data.sectionId,
260
+ ...data.blockId !== void 0 ? { blockId: data.blockId } : {},
261
+ ...data.block !== void 0 ? { block: data.block } : {},
262
+ ...data.scope !== void 0 ? { scope: data.scope } : {},
263
+ ...data.section !== void 0 ? { section: data.section } : {},
264
+ ...data.sections !== void 0 ? { sections: data.sections } : {},
265
+ ...data.schema !== void 0 ? { schema: data.schema } : {},
266
+ ...data.schemas !== void 0 ? { schemas: data.schemas } : {}
267
+ };
268
+ }
269
+ var SECTION_CANVAS_ACTIONS = /* @__PURE__ */ new Set([
270
+ "section.addBefore",
271
+ "section.addAfter",
272
+ "section.duplicate",
273
+ "section.toggleVisibility",
274
+ "section.moveUp",
275
+ "section.moveDown",
276
+ "section.remove"
277
+ ]);
278
+ var BLOCK_CANVAS_ACTIONS = /* @__PURE__ */ new Set([
279
+ "block.duplicate",
280
+ "block.toggleVisibility",
281
+ "block.moveUp",
282
+ "block.moveDown",
283
+ "block.remove"
284
+ ]);
285
+ function parsePreviewCanvasAction(data, shopId) {
286
+ if (!isRecord(data) || data.source !== PREVIEW_SOURCE || data.shopId !== shopId) return null;
287
+ if (data.type !== "editor.action" || typeof data.action !== "string" || typeof data.sectionId !== "string" || data.sectionId === "" || isReservedSectionId(data.sectionId)) {
288
+ return null;
289
+ }
290
+ if (data.scope !== void 0 && !isSelectionScope(data.scope)) return null;
291
+ if (SECTION_CANVAS_ACTIONS.has(data.action)) {
292
+ if (data.blockId !== void 0) return null;
293
+ return {
294
+ source: PREVIEW_SOURCE,
295
+ type: "editor.action",
296
+ shopId,
297
+ action: data.action,
298
+ sectionId: data.sectionId,
299
+ ...data.scope !== void 0 ? { scope: data.scope } : {}
300
+ };
301
+ }
302
+ if (BLOCK_CANVAS_ACTIONS.has(data.action) && isBlockId(data.blockId)) {
303
+ return {
304
+ source: PREVIEW_SOURCE,
305
+ type: "editor.action",
306
+ shopId,
307
+ action: data.action,
308
+ sectionId: data.sectionId,
309
+ blockId: data.blockId,
310
+ ...data.scope !== void 0 ? { scope: data.scope } : {}
311
+ };
312
+ }
313
+ return null;
314
+ }
315
+ function parsePreviewHover(data, shopId) {
316
+ if (!isRecord(data) || data.source !== PREVIEW_SOURCE || data.shopId !== shopId) return null;
317
+ if (data.type !== "section.hover") return null;
318
+ if (data.sectionId !== null && (typeof data.sectionId !== "string" || isReservedSectionId(data.sectionId))) {
319
+ return null;
320
+ }
321
+ return {
322
+ source: PREVIEW_SOURCE,
323
+ type: "section.hover",
324
+ shopId,
325
+ sectionId: data.sectionId
326
+ };
327
+ }
328
+ function parsePreviewReady(data, shopId) {
329
+ if (!isRecord(data) || data.source !== PREVIEW_SOURCE || data.shopId !== shopId) return null;
330
+ if (data.type !== "editor.ready" || !isResolvedSectionArray(data.sections)) return null;
331
+ if (data.visualReadyProtocol !== void 0 && data.visualReadyProtocol !== 1) return null;
332
+ if (data.global !== void 0 && !isSettings(data.global)) return null;
333
+ if (data.schemas !== void 0 && !isSectionSchemaRecord(data.schemas)) return null;
334
+ if (data.globalInputs !== void 0 && !isSettingInputArray(data.globalInputs)) return null;
335
+ if (data.themeStyles !== void 0 && !isThemeStyleArray(data.themeStyles)) return null;
336
+ const templates = data.templates === void 0 ? void 0 : validValuesDocuments(data.templates);
337
+ const sectionGroups = data.sectionGroups === void 0 ? void 0 : validValuesDocuments(data.sectionGroups);
338
+ return {
339
+ source: PREVIEW_SOURCE,
340
+ type: "editor.ready",
341
+ shopId,
342
+ sections: data.sections,
343
+ ...data.visualReadyProtocol === 1 ? { visualReadyProtocol: 1 } : {},
344
+ ...data.global !== void 0 ? { global: data.global } : {},
345
+ ...data.schemas !== void 0 ? { schemas: data.schemas } : {},
346
+ ...data.globalInputs !== void 0 ? { globalInputs: data.globalInputs } : {},
347
+ ...data.themeStyles !== void 0 ? { themeStyles: data.themeStyles } : {},
348
+ ...templates !== void 0 ? { templates } : {},
349
+ ...sectionGroups !== void 0 ? { sectionGroups } : {}
350
+ };
351
+ }
352
+ function parsePreviewVisualReady(data, shopId) {
353
+ if (!isRecord(data) || data.source !== PREVIEW_SOURCE || data.shopId !== shopId) return null;
354
+ if (data.type !== "editor.visual-ready" || typeof data.requestId !== "string" || !VISUAL_READY_REQUEST_ID.test(data.requestId)) {
355
+ return null;
356
+ }
357
+ return {
358
+ source: PREVIEW_SOURCE,
359
+ type: "editor.visual-ready",
360
+ shopId,
361
+ requestId: data.requestId
362
+ };
363
+ }
364
+ function parsePreviewNavigation(data, shopId, previewOrigin) {
365
+ if (!isRecord(data) || data.source !== PREVIEW_SOURCE || data.shopId !== shopId) return null;
366
+ if (data.type !== "preview.navigate" || typeof data.href !== "string" || data.href.trim() === "") {
367
+ return null;
368
+ }
369
+ try {
370
+ const href = new URL(data.href);
371
+ if (href.protocol !== "https:" && href.protocol !== "http:" || href.username !== "" || href.password !== "" || href.origin !== previewOrigin) {
372
+ return null;
373
+ }
374
+ } catch {
375
+ return null;
376
+ }
377
+ return { source: PREVIEW_SOURCE, type: "preview.navigate", shopId, href: data.href };
378
+ }
379
+ function postHostMessage(target, previewOrigin, message) {
380
+ target.postMessage(message, previewOrigin);
381
+ }
382
+ var EDITOR_AFFORDANCE_STYLE_ID = "kotao-storefront-editor-affordances";
383
+ var EDITOR_CANVAS_ID = "kotao-storefront-editor-canvas";
384
+ var EDITOR_AFFORDANCE_CSS = `
385
+ html[data-kotao-editor="true"] [id^="shopify-section-"] {
386
+ cursor: pointer;
387
+ position: relative;
388
+ }
389
+ html[data-kotao-editor="true"] [id^="shopify-section-"][data-kotao-editor-hovered="true"] {
390
+ outline: 2px solid #2c6ecb !important;
391
+ outline-offset: -2px;
392
+ }
393
+ html[data-kotao-editor="true"] [id^="shopify-section-"][data-kotao-editor-selected="true"] {
394
+ outline: 2px solid #005bd3 !important;
395
+ outline-offset: -2px;
396
+ }
397
+ html[data-kotao-editor="true"] [id^="shopify-section-"][data-kotao-editor-hovered="true"]::before {
398
+ content: attr(data-kotao-editor-label);
399
+ position: absolute;
400
+ z-index: 2147483646;
401
+ inset-block-start: 0;
402
+ inset-inline-start: 0;
403
+ max-width: calc(100% - 16px);
404
+ padding: 5px 9px;
405
+ border-radius: 0 0 6px 0;
406
+ background: #005bd3;
407
+ color: #fff;
408
+ font: 600 12px/1.25 ui-sans-serif, system-ui, sans-serif;
409
+ letter-spacing: 0;
410
+ white-space: nowrap;
411
+ overflow: hidden;
412
+ text-overflow: ellipsis;
413
+ pointer-events: none;
414
+ }
415
+ html[data-kotao-editor="true"] [data-kotao-editor-block-hovered="true"],
416
+ html[data-kotao-editor="true"] [data-kotao-editor-block-selected="true"] {
417
+ position: relative;
418
+ outline: 2px solid #005bd3 !important;
419
+ outline-offset: -2px;
420
+ }
421
+ #${EDITOR_CANVAS_ID} {
422
+ position: fixed;
423
+ z-index: 2147483647;
424
+ display: none;
425
+ align-items: center;
426
+ max-width: calc(100vw - 16px);
427
+ height: 38px;
428
+ overflow: hidden;
429
+ border: 1px solid rgba(255, 255, 255, .22);
430
+ border-radius: 8px;
431
+ background: #202223;
432
+ color: #fff;
433
+ box-shadow: 0 4px 18px rgba(0, 0, 0, .28);
434
+ font: 600 12px/1 ui-sans-serif, system-ui, sans-serif;
435
+ letter-spacing: 0;
436
+ }
437
+ #${EDITOR_CANVAS_ID}[data-visible="true"] { display: flex; }
438
+ #${EDITOR_CANVAS_ID} [data-kotao-editor-canvas-label] {
439
+ min-width: 0;
440
+ max-width: 180px;
441
+ overflow: hidden;
442
+ padding: 0 10px;
443
+ text-overflow: ellipsis;
444
+ white-space: nowrap;
445
+ }
446
+ #${EDITOR_CANVAS_ID} [data-kotao-editor-canvas-actions] {
447
+ display: flex;
448
+ align-self: stretch;
449
+ border-inline-start: 1px solid rgba(255, 255, 255, .18);
450
+ }
451
+ #${EDITOR_CANVAS_ID} button {
452
+ display: inline-flex;
453
+ width: 36px;
454
+ align-items: center;
455
+ justify-content: center;
456
+ border: 0;
457
+ border-inline-end: 1px solid rgba(255, 255, 255, .12);
458
+ background: transparent;
459
+ color: inherit;
460
+ cursor: pointer;
461
+ font: 600 14px/1 ui-sans-serif, system-ui, sans-serif;
462
+ }
463
+ #${EDITOR_CANVAS_ID} button:hover,
464
+ #${EDITOR_CANVAS_ID} button:focus-visible {
465
+ outline: 0;
466
+ background: #3b82f6;
467
+ }
468
+ #${EDITOR_CANVAS_ID} button:focus-visible { box-shadow: inset 0 0 0 2px #fff; }
469
+ #${EDITOR_CANVAS_ID} button[data-destructive="true"]:hover,
470
+ #${EDITOR_CANVAS_ID} button[data-destructive="true"]:focus-visible { background: #d72c0d; }
471
+ #${EDITOR_CANVAS_ID} button:disabled { cursor: not-allowed; opacity: .38; }
472
+ `;
473
+ function positionStorefrontEditorCanvasToolbar(anchor, toolbar, viewport) {
474
+ const gap = 8;
475
+ const maxLeft = Math.max(gap, viewport.width - toolbar.width - gap);
476
+ const left = Math.min(Math.max(anchor.left, gap), maxLeft);
477
+ const placement = anchor.top >= toolbar.height + gap * 2 ? "above" : "below";
478
+ const requestedTop = placement === "above" ? anchor.top - toolbar.height - gap : anchor.bottom + gap;
479
+ const maxTop = Math.max(gap, viewport.height - toolbar.height - gap);
480
+ return {
481
+ left: Math.round(left),
482
+ top: Math.round(Math.min(Math.max(requestedTop, gap), maxTop)),
483
+ placement
484
+ };
485
+ }
486
+ function defaultEditorDocument() {
487
+ const candidate = globalThis.document;
488
+ if (!isRecord(candidate)) return void 0;
489
+ if (typeof candidate.addEventListener !== "function" || typeof candidate.removeEventListener !== "function" || typeof candidate.getElementById !== "function" || typeof candidate.createElement !== "function" || !isRecord(candidate.documentElement)) {
490
+ return void 0;
491
+ }
492
+ return candidate;
493
+ }
494
+ function appExtensionFrameDocument(extension) {
495
+ const assetOrigin = new URL(extension.entrypointUrl).origin;
496
+ const connectSources = extension.capabilities.includes("network:fetch") ? extension.allowedOrigins.join(" ") : "'none'";
497
+ const csp = [
498
+ "default-src 'none'",
499
+ `script-src ${assetOrigin}`,
500
+ `style-src ${assetOrigin}`,
501
+ `connect-src ${connectSources}`,
502
+ `img-src data: ${assetOrigin} ${extension.allowedOrigins.join(" ")}`.trim(),
503
+ `font-src ${assetOrigin}`
504
+ ].join("; ");
505
+ const styles = extension.stylesheetUrls.map((url) => `<link rel="stylesheet" href="${htmlAttribute(url)}">`).join("");
506
+ return [
507
+ '<!doctype html><html><head><meta charset="utf-8">',
508
+ `<meta http-equiv="Content-Security-Policy" content="${htmlAttribute(csp)}">`,
509
+ '<meta name="viewport" content="width=device-width,initial-scale=1">',
510
+ styles,
511
+ '</head><body><div id="kotao-app-root"></div>',
512
+ `<script type="module" src="${htmlAttribute(extension.entrypointUrl)}"></script>`,
513
+ "</body></html>"
514
+ ].join("");
515
+ }
516
+ function replaceAppExtensionPreviewFrames(editorDocument, extensions) {
517
+ if (editorDocument === void 0) return;
518
+ const document = editorDocument;
519
+ if (typeof document.querySelectorAll !== "function" || typeof document.createElement !== "function") {
520
+ return;
521
+ }
522
+ for (const element of document.querySelectorAll("[data-kotao-editor-app-extension]")) {
523
+ element.remove?.();
524
+ }
525
+ const sectionElements = () => [...document.querySelectorAll('[data-section-id], [id^="shopify-section-"]')].filter(
526
+ (element) => !element.hasAttribute("data-kotao-editor-app-extension")
527
+ );
528
+ const sectionById = (id) => sectionElements().find(
529
+ (element) => element.getAttribute("data-section-id") === id || element.id === `shopify-section-${id}`
530
+ ) ?? null;
531
+ for (const extension of extensions) {
532
+ if (extension.settings.disabled === true) continue;
533
+ const frame = document.createElement("iframe");
534
+ frame.dataset.kotaoAppExtension = extension.instanceId;
535
+ frame.dataset.kotaoAppId = extension.appId;
536
+ frame.title = `${extension.appName} \u2014 ${extension.extensionName}`;
537
+ frame.setAttribute("sandbox", "allow-scripts");
538
+ frame.setAttribute("referrerpolicy", "no-referrer");
539
+ frame.loading = "lazy";
540
+ frame.name = JSON.stringify({
541
+ instanceId: extension.instanceId,
542
+ appId: extension.appId,
543
+ extensionId: extension.extensionId,
544
+ version: extension.version,
545
+ capabilities: extension.capabilities,
546
+ allowedOrigins: extension.allowedOrigins,
547
+ settings: extension.settings,
548
+ context: extension.capabilities.includes("storefront:context:read") ? {
549
+ templateHandle: extension.templateHandle ?? extension.target?.handle ?? null,
550
+ sectionInstanceId: extension.sectionInstanceId ?? null
551
+ } : null
552
+ });
553
+ frame.srcdoc = appExtensionFrameDocument(extension);
554
+ if (extension.kind === "app_embed") {
555
+ frame.setAttribute("data-kotao-editor-app-extension", "true");
556
+ frame.hidden = true;
557
+ const parent = extension.embedLocation === "head" ? document.head : document.body;
558
+ if (extension.embedLocation === "body_start") parent.prepend(frame);
559
+ else parent.append(frame);
560
+ continue;
561
+ }
562
+ frame.style.cssText = "display:block;width:100%;min-height:1px;border:0";
563
+ if (extension.kind === "app_block") {
564
+ const section = sectionById(extension.sectionInstanceId ?? "");
565
+ if (section === null) continue;
566
+ frame.setAttribute("data-kotao-editor-app-extension", "true");
567
+ frame.setAttribute("data-block-id", extension.instanceId);
568
+ section.append(frame);
569
+ continue;
570
+ }
571
+ const wrapper = document.createElement("div");
572
+ wrapper.id = `shopify-section-${extension.instanceId}`;
573
+ wrapper.setAttribute("data-section-id", extension.instanceId);
574
+ wrapper.setAttribute("data-kotao-editor-app-extension", "true");
575
+ wrapper.append(frame);
576
+ if (extension.target?.kind === "section_group") {
577
+ const group = [...document.querySelectorAll("[data-section-group]")].find(
578
+ (element) => element.getAttribute("data-section-group") === extension.target?.handle
579
+ );
580
+ if (group !== void 0) group.append(wrapper);
581
+ else if (extension.target.handle.includes("header")) document.body.prepend(wrapper);
582
+ else document.body.append(wrapper);
583
+ continue;
584
+ }
585
+ const sections = sectionElements();
586
+ const target = sections[Math.min(extension.position, sections.length - 1)];
587
+ if (target !== void 0 && extension.position < sections.length) target.before(wrapper);
588
+ else (document.querySelector("main") ?? document.body).append(wrapper);
589
+ }
590
+ }
591
+ function sectionElementFromTarget(target) {
592
+ if (!isRecord(target) || typeof target.closest !== "function") return null;
593
+ const element = target.closest('[id^="shopify-section-"]');
594
+ if (!isRecord(element) || typeof element.id !== "string") return null;
595
+ if (!element.id.startsWith("shopify-section-")) return null;
596
+ return element;
597
+ }
598
+ function blockElementFromTarget(target) {
599
+ if (!isRecord(target) || typeof target.closest !== "function") return null;
600
+ const element = target.closest(
601
+ '[data-block-id], [data-shopify-editor-block], [id^="shopify-block-"]'
602
+ );
603
+ if (!isRecord(element) || typeof element.id !== "string") return null;
604
+ return element;
605
+ }
606
+ function blockIdForElement(element) {
607
+ const direct = element.getAttribute?.("data-block-id");
608
+ if (direct) return direct;
609
+ const serialized = element.getAttribute?.("data-shopify-editor-block");
610
+ if (serialized) {
611
+ try {
612
+ const value = JSON.parse(serialized);
613
+ if (isRecord(value) && isBlockId(value.id)) return value.id;
614
+ } catch {
615
+ }
616
+ }
617
+ return element.id.startsWith("shopify-block-") ? element.id.slice("shopify-block-".length) : null;
618
+ }
619
+ function findBlockElement(document, blockId) {
620
+ const candidates = document.querySelectorAll?.(
621
+ '[data-block-id], [data-shopify-editor-block], [id^="shopify-block-"]'
622
+ );
623
+ return candidates?.find((element) => blockIdForElement(element) === blockId) ?? null;
624
+ }
625
+ function isModifiedClick(event) {
626
+ return event.metaKey === true || event.ctrlKey === true || event.shiftKey === true || event.altKey === true;
627
+ }
628
+ function anchorElementFromTarget(target) {
629
+ if (!isRecord(target) || typeof target.closest !== "function") return null;
630
+ const anchor = target.closest("a[href]");
631
+ if (!isRecord(anchor) || typeof anchor.getAttribute !== "function") return null;
632
+ return anchor;
633
+ }
634
+ function classifyAnchorClick(event, anchor, document) {
635
+ const download = anchor.getAttribute?.("download");
636
+ if (event.defaultPrevented === true || event.button !== void 0 && event.button !== 0 || isModifiedClick(event) || anchor.getAttribute?.("target")?.toLowerCase() === "_blank" || download !== null && download !== void 0) {
637
+ return null;
638
+ }
639
+ const rawHref = anchor.getAttribute?.("href");
640
+ const location = document.defaultView?.location;
641
+ if (typeof rawHref !== "string" || rawHref.trim() === "" || location === void 0) return null;
642
+ const hasFragmentDelimiter = rawHref.includes("#");
643
+ let href;
644
+ let current;
645
+ try {
646
+ href = new URL(rawHref, location.href);
647
+ current = new URL(location.href);
648
+ } catch {
649
+ return { kind: "unsafe" };
650
+ }
651
+ if (href.protocol === "javascript:" || href.protocol === "data:") return { kind: "unsafe" };
652
+ if (href.protocol === "mailto:" || href.protocol === "tel:") return { kind: "scheme" };
653
+ if (href.protocol !== "https:" && href.protocol !== "http:") return { kind: "unsafe" };
654
+ if (href.origin === location.origin && href.pathname === current.pathname && href.search === current.search && (href.hash !== "" || hasFragmentDelimiter)) {
655
+ return { kind: "hash" };
656
+ }
657
+ return href.origin === location.origin ? { kind: "internal", href: href.href } : { kind: "external", href: href.href };
658
+ }
659
+ function htmlAttribute(value) {
660
+ return value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("<", "&lt;");
661
+ }
662
+ var SECTION_CANVAS_BUTTONS = [
663
+ { action: "section.addBefore", label: "Add section above", glyph: "+\u2191" },
664
+ { action: "section.moveUp", label: "Move section up", glyph: "\u2191" },
665
+ { action: "section.moveDown", label: "Move section down", glyph: "\u2193" },
666
+ { action: "section.duplicate", label: "Duplicate section", glyph: "\u29C9" },
667
+ { action: "section.toggleVisibility", label: "Hide or show section", glyph: "\u25C9" },
668
+ { action: "section.remove", label: "Delete section", glyph: "\u232B", destructive: true },
669
+ { action: "section.addAfter", label: "Add section below", glyph: "+\u2193" }
670
+ ];
671
+ var BLOCK_CANVAS_BUTTONS = [
672
+ { action: "block.moveUp", label: "Move block up", glyph: "\u2191" },
673
+ { action: "block.moveDown", label: "Move block down", glyph: "\u2193" },
674
+ { action: "block.duplicate", label: "Duplicate block", glyph: "\u29C9" },
675
+ { action: "block.toggleVisibility", label: "Hide or show block", glyph: "\u25C9" },
676
+ { action: "block.remove", label: "Delete block", glyph: "\u232B", destructive: true }
677
+ ];
678
+ function canvasToolbarHtml(label, block, state) {
679
+ const buttons = block ? BLOCK_CANVAS_BUTTONS : SECTION_CANVAS_BUTTONS;
680
+ return `<span data-kotao-editor-canvas-label>${htmlAttribute(label)}</span><span data-kotao-editor-canvas-actions>${buttons.map(({ action, destructive, glyph, label: staticLabel }) => {
681
+ const actionLabel = action.endsWith("toggleVisibility") ? `${state.hidden ? "Show" : "Hide"} ${block ? "block" : "section"}` : staticLabel;
682
+ const disabled = action.endsWith("moveUp") && !state.canMoveUp || action.endsWith("moveDown") && !state.canMoveDown || action.endsWith("duplicate") && !state.canDuplicate || action.startsWith("section.add") && !state.canAddSection;
683
+ return `<button type="button" data-kotao-editor-action="${action}"${destructive ? ' data-destructive="true"' : ""}${disabled ? " disabled" : ""} aria-label="${htmlAttribute(actionLabel)}" title="${htmlAttribute(actionLabel)}">${glyph}</button>`;
684
+ }).join("")}</span>`;
685
+ }
686
+ function createEditorAffordances({
687
+ document,
688
+ labelForBlock,
689
+ labelForSection,
690
+ onCanvasAction,
691
+ onHoverSection,
692
+ onNavigate,
693
+ onSelect,
694
+ stateForSelection
695
+ }) {
696
+ let hoveredElement = null;
697
+ let hoveredBlockElement = null;
698
+ let selectedElement = null;
699
+ let selectedBlockElement = null;
700
+ let selectedSectionId = null;
701
+ let selectedBlockId = null;
702
+ let ownedStyle = null;
703
+ let ownedToolbar = null;
704
+ let inspectorEnabled = true;
705
+ const setElementState = (kind, sectionId) => {
706
+ const previous = kind === "hovered" ? hoveredElement : selectedElement;
707
+ previous?.removeAttribute(`data-kotao-editor-${kind}`);
708
+ if (sectionId === null) return null;
709
+ const element = document.getElementById(`shopify-section-${sectionId}`);
710
+ if (element === null || !("setAttribute" in element)) return null;
711
+ const sectionElement = element;
712
+ sectionElement.setAttribute(`data-kotao-editor-${kind}`, "true");
713
+ sectionElement.setAttribute("data-kotao-editor-label", labelForSection(sectionId));
714
+ return sectionElement;
715
+ };
716
+ const setHovered = (sectionId) => {
717
+ if (!inspectorEnabled && sectionId !== null) return;
718
+ hoveredElement = setElementState("hovered", sectionId);
719
+ };
720
+ const clearHovered = () => {
721
+ hoveredBlockElement?.removeAttribute("data-kotao-editor-block-hovered");
722
+ hoveredBlockElement = null;
723
+ setHovered(null);
724
+ };
725
+ const positionToolbar = () => {
726
+ const anchor = selectedBlockElement ?? selectedElement;
727
+ const anchorRect = anchor?.getBoundingClientRect?.();
728
+ if (ownedToolbar === null || anchorRect === void 0) return;
729
+ const toolbarRect = ownedToolbar.getBoundingClientRect?.() ?? {
730
+ width: 420,
731
+ height: 38
732
+ };
733
+ const position = positionStorefrontEditorCanvasToolbar(anchorRect, toolbarRect, {
734
+ width: document.defaultView?.innerWidth ?? 1024,
735
+ height: document.defaultView?.innerHeight ?? 768
736
+ });
737
+ ownedToolbar.setAttribute("style", `left:${position.left}px;top:${position.top}px`);
738
+ ownedToolbar.setAttribute("data-placement", position.placement);
739
+ };
740
+ const renderToolbar = () => {
741
+ if (ownedToolbar === null) return;
742
+ if (selectedSectionId === null) {
743
+ ownedToolbar.removeAttribute("data-visible");
744
+ return;
745
+ }
746
+ const isBlock = selectedBlockId !== null;
747
+ if (selectedBlockId !== null) {
748
+ ownedToolbar.innerHTML = canvasToolbarHtml(
749
+ labelForBlock(selectedSectionId, selectedBlockId),
750
+ true,
751
+ stateForSelection(selectedSectionId, selectedBlockId)
752
+ );
753
+ } else {
754
+ ownedToolbar.innerHTML = canvasToolbarHtml(
755
+ labelForSection(selectedSectionId),
756
+ false,
757
+ stateForSelection(selectedSectionId)
758
+ );
759
+ }
760
+ ownedToolbar.setAttribute("data-visible", "true");
761
+ ownedToolbar.setAttribute("aria-label", isBlock ? "Block actions" : "Section actions");
762
+ positionToolbar();
763
+ };
764
+ const setSelected = (sectionId, blockId) => {
765
+ if (!inspectorEnabled && sectionId !== null) return;
766
+ selectedBlockElement?.removeAttribute("data-kotao-editor-block-selected");
767
+ selectedBlockElement = null;
768
+ selectedBlockId = blockId ?? null;
769
+ selectedSectionId = sectionId;
770
+ selectedElement = setElementState("selected", sectionId);
771
+ if (sectionId !== null && blockId !== void 0) {
772
+ selectedBlockElement = findBlockElement(document, blockId);
773
+ selectedBlockElement?.setAttribute("data-kotao-editor-block-selected", "true");
774
+ selectedBlockElement?.setAttribute(
775
+ "data-kotao-editor-label",
776
+ labelForBlock(sectionId, blockId)
777
+ );
778
+ }
779
+ renderToolbar();
780
+ };
781
+ const onPointerOver = (event) => {
782
+ if (!inspectorEnabled) return;
783
+ const element = sectionElementFromTarget(event.target);
784
+ if (element === null) return;
785
+ const sectionId = element.id.slice("shopify-section-".length);
786
+ if (sectionId === "" || isReservedSectionId(sectionId)) return;
787
+ const nextBlockElement = blockElementFromTarget(event.target);
788
+ if (element === hoveredElement && nextBlockElement === hoveredBlockElement) return;
789
+ hoveredBlockElement?.removeAttribute("data-kotao-editor-block-hovered");
790
+ hoveredBlockElement = nextBlockElement;
791
+ const blockId = hoveredBlockElement ? blockIdForElement(hoveredBlockElement) : null;
792
+ if (hoveredBlockElement !== null && blockId !== null) {
793
+ hoveredBlockElement.setAttribute("data-kotao-editor-block-hovered", "true");
794
+ hoveredBlockElement.setAttribute("data-kotao-editor-label", labelForBlock(sectionId, blockId));
795
+ }
796
+ if (element !== hoveredElement) {
797
+ setHovered(sectionId);
798
+ onHoverSection(sectionId);
799
+ }
800
+ };
801
+ const onPointerOut = (event) => {
802
+ if (!inspectorEnabled) return;
803
+ if (hoveredElement === null) return;
804
+ const nextElement = sectionElementFromTarget(event.relatedTarget);
805
+ if (nextElement === hoveredElement || hoveredElement.contains(event.relatedTarget)) return;
806
+ clearHovered();
807
+ onHoverSection(null);
808
+ };
809
+ const onClick = (event) => {
810
+ if (isRecord(event.target) && typeof event.target.closest === "function") {
811
+ const canvas = event.target.closest(`#${EDITOR_CANVAS_ID}`);
812
+ if (canvas !== null) return;
813
+ }
814
+ const anchor = anchorElementFromTarget(event.target);
815
+ if (anchor !== null) {
816
+ const disposition = classifyAnchorClick(event, anchor, document);
817
+ if (disposition === null) return;
818
+ if (inspectorEnabled) {
819
+ event.preventDefault?.();
820
+ event.stopPropagation?.();
821
+ } else {
822
+ switch (disposition.kind) {
823
+ case "internal":
824
+ event.preventDefault?.();
825
+ event.stopPropagation?.();
826
+ onNavigate(disposition.href);
827
+ break;
828
+ case "external":
829
+ event.preventDefault?.();
830
+ event.stopPropagation?.();
831
+ document.defaultView?.open?.(disposition.href, "_blank", "noopener,noreferrer");
832
+ break;
833
+ case "unsafe":
834
+ event.preventDefault?.();
835
+ event.stopPropagation?.();
836
+ break;
837
+ }
838
+ return;
839
+ }
840
+ } else if (!inspectorEnabled) {
841
+ return;
842
+ }
843
+ const section = sectionElementFromTarget(event.target);
844
+ if (section === null) return;
845
+ const sectionId = section.id.slice("shopify-section-".length);
846
+ if (sectionId === "" || isReservedSectionId(sectionId)) return;
847
+ const block = blockElementFromTarget(event.target);
848
+ const blockId = block === null ? null : blockIdForElement(block);
849
+ setSelected(sectionId, blockId ?? void 0);
850
+ onSelect(sectionId, blockId ?? void 0);
851
+ };
852
+ const onToolbarClick = (event) => {
853
+ if (!isRecord(event.target) || typeof event.target.closest !== "function") return;
854
+ const button = event.target.closest("[data-kotao-editor-action]");
855
+ if (!isRecord(button) || typeof button.getAttribute !== "function") return;
856
+ const action = button.getAttribute("data-kotao-editor-action");
857
+ if (typeof action !== "string" || selectedSectionId === null) return;
858
+ event.preventDefault?.();
859
+ event.stopPropagation?.();
860
+ if (SECTION_CANVAS_ACTIONS.has(action)) {
861
+ onCanvasAction({
862
+ action,
863
+ sectionId: selectedSectionId
864
+ });
865
+ return;
866
+ }
867
+ if (selectedBlockId !== null && BLOCK_CANVAS_ACTIONS.has(action)) {
868
+ onCanvasAction({
869
+ action,
870
+ sectionId: selectedSectionId,
871
+ blockId: selectedBlockId
872
+ });
873
+ }
874
+ };
875
+ document.documentElement.setAttribute("data-kotao-editor", "true");
876
+ if (document.getElementById(EDITOR_AFFORDANCE_STYLE_ID) === null && document.head !== void 0) {
877
+ ownedStyle = document.createElement("style");
878
+ ownedStyle.id = EDITOR_AFFORDANCE_STYLE_ID;
879
+ ownedStyle.textContent = EDITOR_AFFORDANCE_CSS;
880
+ document.head.appendChild(ownedStyle);
881
+ }
882
+ if (document.body !== void 0) {
883
+ ownedToolbar = document.createElement("div");
884
+ ownedToolbar.id = EDITOR_CANVAS_ID;
885
+ ownedToolbar.setAttribute("role", "toolbar");
886
+ ownedToolbar.setAttribute("data-kotao-editor-canvas", "true");
887
+ ownedToolbar.addEventListener?.("click", onToolbarClick);
888
+ document.body.appendChild(ownedToolbar);
889
+ }
890
+ document.addEventListener("pointerover", onPointerOver, true);
891
+ document.addEventListener("pointerout", onPointerOut, true);
892
+ document.addEventListener("click", onClick, true);
893
+ document.defaultView?.addEventListener?.("scroll", positionToolbar, true);
894
+ document.defaultView?.addEventListener?.("resize", positionToolbar);
895
+ return {
896
+ setHovered,
897
+ setSelected,
898
+ setInspectorEnabled(enabled) {
899
+ inspectorEnabled = enabled;
900
+ if (!enabled) {
901
+ clearHovered();
902
+ setSelected(null);
903
+ }
904
+ },
905
+ dispose() {
906
+ clearHovered();
907
+ setSelected(null);
908
+ document.documentElement.removeAttribute("data-kotao-editor");
909
+ document.removeEventListener("pointerover", onPointerOver, true);
910
+ document.removeEventListener("pointerout", onPointerOut, true);
911
+ document.removeEventListener("click", onClick, true);
912
+ document.defaultView?.removeEventListener?.("scroll", positionToolbar, true);
913
+ document.defaultView?.removeEventListener?.("resize", positionToolbar);
914
+ ownedToolbar?.removeEventListener?.("click", onToolbarClick);
915
+ ownedToolbar?.remove?.();
916
+ ownedStyle?.remove();
917
+ }
918
+ };
919
+ }
920
+ function createStorefrontEditorBridge({
921
+ adminOrigin,
922
+ document: editorDocument,
923
+ globalInputs,
924
+ themeStyles,
925
+ schemas,
926
+ sectionGroups,
927
+ shopId,
928
+ store,
929
+ target,
930
+ templates,
931
+ transport
932
+ }) {
933
+ const postHoverSection = (sectionId) => {
934
+ if (sectionId !== null && isReservedSectionId(sectionId)) return;
935
+ const message = {
936
+ source: PREVIEW_SOURCE,
937
+ type: "section.hover",
938
+ shopId,
939
+ sectionId
940
+ };
941
+ target.postMessage(message, adminOrigin);
942
+ };
943
+ const labelForSection = (sectionId) => {
944
+ const snapshot = store.getSnapshot();
945
+ const documents = [
946
+ snapshot.sections,
947
+ ...Object.values(snapshot.sectionGroups ?? {}).flatMap(
948
+ (document) => document === void 0 ? [] : [document.sections]
949
+ ),
950
+ ...Object.values(snapshot.templates ?? {}).flatMap(
951
+ (document) => document === void 0 ? [] : [document.sections]
952
+ )
953
+ ];
954
+ const section = documents.flatMap((document) => document).find((candidate) => candidate.id === sectionId);
955
+ return section === void 0 ? sectionId : schemas?.[section.type]?.label ?? section.type;
956
+ };
957
+ const labelForBlock = (sectionId, blockId) => {
958
+ const snapshot = store.getSnapshot();
959
+ const documents = [
960
+ snapshot.sections,
961
+ ...Object.values(snapshot.sectionGroups ?? {}).flatMap(
962
+ (document) => document === void 0 ? [] : [document.sections]
963
+ ),
964
+ ...Object.values(snapshot.templates ?? {}).flatMap(
965
+ (document) => document === void 0 ? [] : [document.sections]
966
+ )
967
+ ];
968
+ const section = documents.flatMap((document) => document).find((candidate) => candidate.id === sectionId);
969
+ const block = section?.blocks.find((candidate) => candidate.id === blockId);
970
+ const schema = section === void 0 ? void 0 : schemas?.[section.type];
971
+ return block === void 0 ? blockId : schema?.blocks?.find((candidate) => candidate.type === block.type)?.label ?? block.type;
972
+ };
973
+ const stateForSelection = (sectionId, blockId) => {
974
+ const snapshot = store.getSnapshot();
975
+ const documents = [
976
+ snapshot.sections,
977
+ ...Object.values(snapshot.sectionGroups ?? {}).flatMap(
978
+ (document) => document === void 0 ? [] : [document.sections]
979
+ ),
980
+ ...Object.values(snapshot.templates ?? {}).flatMap(
981
+ (document) => document === void 0 ? [] : [document.sections]
982
+ )
983
+ ];
984
+ const sections = documents.find(
985
+ (document) => document.some((candidate) => candidate.id === sectionId)
986
+ );
987
+ const sectionIndex = sections?.findIndex((candidate) => candidate.id === sectionId) ?? -1;
988
+ const section = sectionIndex === -1 ? void 0 : sections?.[sectionIndex];
989
+ const canAddSection = Object.values(schemas ?? {}).some(
990
+ (schema) => (schema.presets?.length ?? 0) > 0
991
+ );
992
+ if (blockId === void 0) {
993
+ return {
994
+ canAddSection,
995
+ canDuplicate: section !== void 0,
996
+ canMoveDown: sections !== void 0 && sectionIndex < sections.length - 1,
997
+ canMoveUp: sectionIndex > 0,
998
+ hidden: section?.settings.disabled === true
999
+ };
1000
+ }
1001
+ const blockIndex = section?.blocks.findIndex((candidate) => candidate.id === blockId) ?? -1;
1002
+ const block = blockIndex === -1 ? void 0 : section?.blocks[blockIndex];
1003
+ const sectionSchema = section === void 0 ? void 0 : schemas?.[section.type];
1004
+ const blockSchema = block ? sectionSchema?.blocks?.find((candidate) => candidate.type === block.type) : void 0;
1005
+ const underSectionLimit = section !== void 0 && (sectionSchema?.maxBlocks === void 0 || section.blocks.length < sectionSchema.maxBlocks);
1006
+ const underBlockLimit = block !== void 0 && (blockSchema?.limit === void 0 || (section?.blocks.filter((candidate) => candidate.type === block.type).length ?? 0) < blockSchema.limit);
1007
+ return {
1008
+ canAddSection,
1009
+ canDuplicate: sectionSchema !== void 0 && blockSchema !== void 0 && underSectionLimit && underBlockLimit,
1010
+ canMoveDown: section !== void 0 && blockIndex !== -1 && blockIndex < section.blocks.length - 1,
1011
+ canMoveUp: blockIndex > 0,
1012
+ hidden: block?.settings.disabled === true
1013
+ };
1014
+ };
1015
+ const postSelection = (sectionId, blockId) => {
1016
+ if (isReservedSectionId(sectionId)) return;
1017
+ const snapshot = store.getSnapshot();
1018
+ let sections = snapshot.sections;
1019
+ let section = sections.find((candidate) => candidate.id === sectionId);
1020
+ let scope;
1021
+ if (section === void 0) {
1022
+ for (const [handle, document] of Object.entries(snapshot.sectionGroups ?? {})) {
1023
+ const candidate = document?.sections.find((item) => item.id === sectionId);
1024
+ if (candidate === void 0) continue;
1025
+ section = candidate;
1026
+ sections = document.sections;
1027
+ scope = { kind: "sectionGroup", handle };
1028
+ break;
1029
+ }
1030
+ }
1031
+ if (section === void 0) {
1032
+ for (const [handle, document] of Object.entries(snapshot.templates ?? {})) {
1033
+ const candidate = document?.sections.find((item) => item.id === sectionId);
1034
+ if (candidate === void 0) continue;
1035
+ section = candidate;
1036
+ sections = document.sections;
1037
+ scope = { kind: "template", handle };
1038
+ break;
1039
+ }
1040
+ }
1041
+ const block = blockId === void 0 ? void 0 : section?.blocks.find((item) => item.id === blockId);
1042
+ if (blockId !== void 0 && block === void 0) return;
1043
+ const schema = section !== void 0 ? schemas?.[section.type] : void 0;
1044
+ const message = {
1045
+ source: PREVIEW_SOURCE,
1046
+ type: "section.select",
1047
+ shopId,
1048
+ sectionId,
1049
+ ...blockId !== void 0 ? { blockId } : {},
1050
+ ...block !== void 0 ? { block } : {},
1051
+ ...scope !== void 0 ? { scope } : {},
1052
+ ...section !== void 0 ? { section } : {},
1053
+ sections,
1054
+ ...schema !== void 0 ? { schema } : {},
1055
+ ...schemas !== void 0 ? { schemas } : {}
1056
+ };
1057
+ target.postMessage(message, adminOrigin);
1058
+ };
1059
+ const postCanvasAction = (action) => {
1060
+ const message = {
1061
+ source: PREVIEW_SOURCE,
1062
+ type: "editor.action",
1063
+ shopId,
1064
+ ...action
1065
+ };
1066
+ target.postMessage(message, adminOrigin);
1067
+ };
1068
+ const postNavigation = (href) => {
1069
+ const message = {
1070
+ source: PREVIEW_SOURCE,
1071
+ type: "preview.navigate",
1072
+ shopId,
1073
+ href
1074
+ };
1075
+ target.postMessage(message, adminOrigin);
1076
+ };
1077
+ const resolvedDocument = editorDocument ?? defaultEditorDocument();
1078
+ let disposed = false;
1079
+ const pendingAnimationFrames = /* @__PURE__ */ new Set();
1080
+ const affordances = resolvedDocument === void 0 ? null : createEditorAffordances({
1081
+ document: resolvedDocument,
1082
+ labelForBlock,
1083
+ labelForSection,
1084
+ onCanvasAction: postCanvasAction,
1085
+ onHoverSection: postHoverSection,
1086
+ onNavigate: postNavigation,
1087
+ onSelect: postSelection,
1088
+ stateForSelection
1089
+ });
1090
+ const postReady = () => {
1091
+ const snapshot = store.getSnapshot();
1092
+ const message = {
1093
+ source: PREVIEW_SOURCE,
1094
+ type: "editor.ready",
1095
+ shopId,
1096
+ sections: snapshot.sections,
1097
+ visualReadyProtocol: 1,
1098
+ global: snapshot.global,
1099
+ ...schemas !== void 0 ? { schemas } : {},
1100
+ ...globalInputs !== void 0 ? { globalInputs } : {},
1101
+ ...themeStyles !== void 0 ? { themeStyles } : {},
1102
+ ...templates !== void 0 ? { templates } : {},
1103
+ ...sectionGroups !== void 0 ? { sectionGroups } : {}
1104
+ };
1105
+ target.postMessage(message, adminOrigin);
1106
+ };
1107
+ const postVisualReadyAfterPaint = (requestId) => {
1108
+ const view = resolvedDocument?.defaultView;
1109
+ const requestAnimationFrame = view?.requestAnimationFrame?.bind(view);
1110
+ if (requestAnimationFrame === void 0) {
1111
+ queueMicrotask(() => {
1112
+ queueMicrotask(() => {
1113
+ if (disposed) return;
1114
+ target.postMessage(
1115
+ {
1116
+ source: PREVIEW_SOURCE,
1117
+ type: "editor.visual-ready",
1118
+ shopId,
1119
+ requestId
1120
+ },
1121
+ adminOrigin
1122
+ );
1123
+ });
1124
+ });
1125
+ return;
1126
+ }
1127
+ const firstFrame = requestAnimationFrame(() => {
1128
+ pendingAnimationFrames.delete(firstFrame);
1129
+ if (disposed) return;
1130
+ const secondFrame = requestAnimationFrame(() => {
1131
+ pendingAnimationFrames.delete(secondFrame);
1132
+ if (disposed) return;
1133
+ target.postMessage(
1134
+ {
1135
+ source: PREVIEW_SOURCE,
1136
+ type: "editor.visual-ready",
1137
+ shopId,
1138
+ requestId
1139
+ },
1140
+ adminOrigin
1141
+ );
1142
+ });
1143
+ pendingAnimationFrames.add(secondFrame);
1144
+ });
1145
+ pendingAnimationFrames.add(firstFrame);
1146
+ };
1147
+ const onMessage = (event) => {
1148
+ if (event.origin !== adminOrigin) return;
1149
+ if (event.source !== target) return;
1150
+ const message = parseHostMessage(event.data, shopId);
1151
+ if (message === null) return;
1152
+ switch (message.type) {
1153
+ case "editor.ready.request":
1154
+ postReady();
1155
+ break;
1156
+ case "editor.visual-ready.request":
1157
+ postVisualReadyAfterPaint(message.requestId);
1158
+ break;
1159
+ case "section.hover":
1160
+ affordances?.setHovered(message.sectionId);
1161
+ break;
1162
+ case "section.activate":
1163
+ affordances?.setSelected(message.sectionId, message.blockId);
1164
+ break;
1165
+ case "inspector.set":
1166
+ affordances?.setInspectorEnabled(message.enabled);
1167
+ break;
1168
+ case "settings.patchSection":
1169
+ store.patchSection(message.sectionId, message.settings);
1170
+ break;
1171
+ case "settings.patchGlobal":
1172
+ store.patchGlobal(message.settings);
1173
+ break;
1174
+ case "sections.insert":
1175
+ store.insertSection(message.section, message.index);
1176
+ break;
1177
+ case "sections.remove":
1178
+ store.removeSection(message.sectionId);
1179
+ break;
1180
+ case "sections.reorder":
1181
+ store.moveSection(message.sectionId, message.index);
1182
+ break;
1183
+ case "settings.patchBlock":
1184
+ store.patchBlock(message.sectionId, message.blockId, message.settings);
1185
+ break;
1186
+ case "blocks.insert":
1187
+ store.insertBlock(message.sectionId, message.block, message.index);
1188
+ break;
1189
+ case "blocks.remove":
1190
+ store.removeBlock(message.sectionId, message.blockId);
1191
+ break;
1192
+ case "blocks.reorder":
1193
+ store.moveBlock(message.sectionId, message.blockId, message.index);
1194
+ break;
1195
+ case "template.replace":
1196
+ store.replaceSections(message.document.sections);
1197
+ break;
1198
+ case "sectionGroup.replace":
1199
+ store.replaceSectionGroup(message.handle, message.document);
1200
+ break;
1201
+ case "appExtensions.replace":
1202
+ replaceAppExtensionPreviewFrames(resolvedDocument, message.extensions);
1203
+ break;
1204
+ }
1205
+ };
1206
+ transport.addEventListener("message", onMessage);
1207
+ return {
1208
+ ready: postReady,
1209
+ hoverSection: (sectionId) => {
1210
+ if (sectionId !== null && isReservedSectionId(sectionId)) return;
1211
+ affordances?.setHovered(sectionId);
1212
+ postHoverSection(sectionId);
1213
+ },
1214
+ selectSection: (sectionId) => {
1215
+ if (isReservedSectionId(sectionId)) return;
1216
+ affordances?.setSelected(sectionId);
1217
+ postSelection(sectionId);
1218
+ },
1219
+ selectBlock: (sectionId, blockId) => {
1220
+ if (isReservedSectionId(sectionId) || !isBlockId(blockId)) return;
1221
+ affordances?.setSelected(sectionId, blockId);
1222
+ postSelection(sectionId, blockId);
1223
+ },
1224
+ dispose: () => {
1225
+ disposed = true;
1226
+ for (const requestId of pendingAnimationFrames) {
1227
+ resolvedDocument?.defaultView?.cancelAnimationFrame?.(requestId);
1228
+ }
1229
+ pendingAnimationFrames.clear();
1230
+ replaceAppExtensionPreviewFrames(resolvedDocument, []);
1231
+ affordances?.dispose();
1232
+ transport.removeEventListener("message", onMessage);
1233
+ }
1234
+ };
1235
+ }
1236
+ function createStorefrontEditorHostBridge({
1237
+ onCanvasAction,
1238
+ onHoverSection,
1239
+ onNavigate,
1240
+ onReady,
1241
+ onSelectSection,
1242
+ onVisualReady,
1243
+ previewOrigin,
1244
+ resolveTarget,
1245
+ shopId,
1246
+ target,
1247
+ transport
1248
+ }) {
1249
+ const currentTarget = () => resolveTarget?.() ?? target;
1250
+ const onMessage = (event) => {
1251
+ if (event.origin !== previewOrigin) return;
1252
+ const expectedTarget = currentTarget();
1253
+ if (event.source !== expectedTarget) return;
1254
+ const visualReady = parsePreviewVisualReady(event.data, shopId);
1255
+ if (visualReady !== null) {
1256
+ onVisualReady?.(visualReady.requestId);
1257
+ return;
1258
+ }
1259
+ const navigation = parsePreviewNavigation(event.data, shopId, previewOrigin);
1260
+ if (navigation !== null) {
1261
+ onNavigate?.({ href: navigation.href });
1262
+ return;
1263
+ }
1264
+ const ready = parsePreviewReady(event.data, shopId);
1265
+ if (ready !== null) {
1266
+ onReady?.({
1267
+ sections: ready.sections,
1268
+ ...ready.visualReadyProtocol === 1 ? { visualReadyProtocol: 1 } : {},
1269
+ ...ready.global !== void 0 ? { global: ready.global } : {},
1270
+ ...ready.schemas !== void 0 ? { schemas: ready.schemas } : {},
1271
+ ...ready.globalInputs !== void 0 ? { globalInputs: ready.globalInputs } : {},
1272
+ ...ready.themeStyles !== void 0 ? { themeStyles: ready.themeStyles } : {},
1273
+ ...ready.templates !== void 0 ? { templates: ready.templates } : {},
1274
+ ...ready.sectionGroups !== void 0 ? { sectionGroups: ready.sectionGroups } : {}
1275
+ });
1276
+ return;
1277
+ }
1278
+ const hover = parsePreviewHover(event.data, shopId);
1279
+ if (hover !== null) {
1280
+ onHoverSection?.(hover.sectionId);
1281
+ return;
1282
+ }
1283
+ const canvasAction = parsePreviewCanvasAction(event.data, shopId);
1284
+ if (canvasAction !== null) {
1285
+ onCanvasAction?.(
1286
+ canvasAction.blockId === void 0 ? {
1287
+ action: canvasAction.action,
1288
+ sectionId: canvasAction.sectionId,
1289
+ ...canvasAction.scope !== void 0 ? { scope: canvasAction.scope } : {}
1290
+ } : {
1291
+ action: canvasAction.action,
1292
+ sectionId: canvasAction.sectionId,
1293
+ blockId: canvasAction.blockId,
1294
+ ...canvasAction.scope !== void 0 ? { scope: canvasAction.scope } : {}
1295
+ }
1296
+ );
1297
+ return;
1298
+ }
1299
+ const message = parsePreviewSelection(event.data, shopId);
1300
+ if (message === null || isReservedSectionId(message.sectionId)) return;
1301
+ onSelectSection({
1302
+ sectionId: message.sectionId,
1303
+ ...message.blockId !== void 0 ? { blockId: message.blockId } : {},
1304
+ ...message.block !== void 0 ? { block: message.block } : {},
1305
+ ...message.scope !== void 0 ? { scope: message.scope } : {},
1306
+ ...message.section !== void 0 ? { section: message.section } : {},
1307
+ ...message.sections !== void 0 ? { sections: message.sections } : {},
1308
+ ...message.schema !== void 0 ? { schema: message.schema } : {},
1309
+ ...message.schemas !== void 0 ? { schemas: message.schemas } : {}
1310
+ });
1311
+ };
1312
+ transport.addEventListener("message", onMessage);
1313
+ return {
1314
+ requestReady: () => {
1315
+ postHostMessage(currentTarget(), previewOrigin, {
1316
+ source: HOST_SOURCE,
1317
+ type: "editor.ready.request",
1318
+ shopId
1319
+ });
1320
+ },
1321
+ requestVisualReady: (requestId) => {
1322
+ if (!VISUAL_READY_REQUEST_ID.test(requestId)) return;
1323
+ postHostMessage(currentTarget(), previewOrigin, {
1324
+ source: HOST_SOURCE,
1325
+ type: "editor.visual-ready.request",
1326
+ shopId,
1327
+ requestId
1328
+ });
1329
+ },
1330
+ hoverSection: (sectionId) => {
1331
+ if (sectionId !== null && isReservedSectionId(sectionId)) return;
1332
+ postHostMessage(currentTarget(), previewOrigin, {
1333
+ source: HOST_SOURCE,
1334
+ type: "section.hover",
1335
+ shopId,
1336
+ sectionId
1337
+ });
1338
+ },
1339
+ activateSection: (sectionId, blockId) => {
1340
+ if (sectionId !== null && isReservedSectionId(sectionId)) return;
1341
+ if (blockId !== void 0 && !isBlockId(blockId)) return;
1342
+ postHostMessage(currentTarget(), previewOrigin, {
1343
+ source: HOST_SOURCE,
1344
+ type: "section.activate",
1345
+ shopId,
1346
+ sectionId,
1347
+ ...blockId !== void 0 ? { blockId } : {}
1348
+ });
1349
+ },
1350
+ patchSection: (sectionId, settings) => {
1351
+ if (isReservedSectionId(sectionId)) return;
1352
+ postHostMessage(currentTarget(), previewOrigin, {
1353
+ source: HOST_SOURCE,
1354
+ type: "settings.patchSection",
1355
+ shopId,
1356
+ sectionId,
1357
+ settings
1358
+ });
1359
+ },
1360
+ patchGlobal: (settings) => {
1361
+ postHostMessage(currentTarget(), previewOrigin, {
1362
+ source: HOST_SOURCE,
1363
+ type: "settings.patchGlobal",
1364
+ shopId,
1365
+ settings
1366
+ });
1367
+ },
1368
+ insertSection: (section, index) => {
1369
+ if (isReservedSectionId(section.id)) return;
1370
+ postHostMessage(currentTarget(), previewOrigin, {
1371
+ source: HOST_SOURCE,
1372
+ type: "sections.insert",
1373
+ shopId,
1374
+ section,
1375
+ ...index !== void 0 ? { index } : {}
1376
+ });
1377
+ },
1378
+ removeSection: (sectionId) => {
1379
+ if (isReservedSectionId(sectionId)) return;
1380
+ postHostMessage(currentTarget(), previewOrigin, {
1381
+ source: HOST_SOURCE,
1382
+ type: "sections.remove",
1383
+ shopId,
1384
+ sectionId
1385
+ });
1386
+ },
1387
+ reorderSection: (sectionId, index) => {
1388
+ if (isReservedSectionId(sectionId)) return;
1389
+ postHostMessage(currentTarget(), previewOrigin, {
1390
+ source: HOST_SOURCE,
1391
+ type: "sections.reorder",
1392
+ shopId,
1393
+ sectionId,
1394
+ index
1395
+ });
1396
+ },
1397
+ patchBlock: (sectionId, blockId, settings) => {
1398
+ if (isReservedSectionId(sectionId)) return;
1399
+ postHostMessage(currentTarget(), previewOrigin, {
1400
+ source: HOST_SOURCE,
1401
+ type: "settings.patchBlock",
1402
+ shopId,
1403
+ sectionId,
1404
+ blockId,
1405
+ settings
1406
+ });
1407
+ },
1408
+ insertBlock: (sectionId, block, index) => {
1409
+ if (isReservedSectionId(sectionId)) return;
1410
+ postHostMessage(currentTarget(), previewOrigin, {
1411
+ source: HOST_SOURCE,
1412
+ type: "blocks.insert",
1413
+ shopId,
1414
+ sectionId,
1415
+ block,
1416
+ ...index !== void 0 ? { index } : {}
1417
+ });
1418
+ },
1419
+ removeBlock: (sectionId, blockId) => {
1420
+ if (isReservedSectionId(sectionId)) return;
1421
+ postHostMessage(currentTarget(), previewOrigin, {
1422
+ source: HOST_SOURCE,
1423
+ type: "blocks.remove",
1424
+ shopId,
1425
+ sectionId,
1426
+ blockId
1427
+ });
1428
+ },
1429
+ reorderBlock: (sectionId, blockId, index) => {
1430
+ if (isReservedSectionId(sectionId)) return;
1431
+ postHostMessage(currentTarget(), previewOrigin, {
1432
+ source: HOST_SOURCE,
1433
+ type: "blocks.reorder",
1434
+ shopId,
1435
+ sectionId,
1436
+ blockId,
1437
+ index
1438
+ });
1439
+ },
1440
+ replaceTemplate: (handle, document) => {
1441
+ postHostMessage(currentTarget(), previewOrigin, {
1442
+ source: HOST_SOURCE,
1443
+ type: "template.replace",
1444
+ shopId,
1445
+ handle,
1446
+ document
1447
+ });
1448
+ },
1449
+ replaceSectionGroup: (handle, document) => {
1450
+ if (handle.trim() === "") return;
1451
+ postHostMessage(currentTarget(), previewOrigin, {
1452
+ source: HOST_SOURCE,
1453
+ type: "sectionGroup.replace",
1454
+ shopId,
1455
+ handle,
1456
+ document
1457
+ });
1458
+ },
1459
+ replaceAppExtensions: (extensions) => {
1460
+ postHostMessage(currentTarget(), previewOrigin, {
1461
+ source: HOST_SOURCE,
1462
+ type: "appExtensions.replace",
1463
+ shopId,
1464
+ extensions
1465
+ });
1466
+ },
1467
+ setInspectorEnabled: (enabled) => {
1468
+ postHostMessage(currentTarget(), previewOrigin, {
1469
+ source: HOST_SOURCE,
1470
+ type: "inspector.set",
1471
+ shopId,
1472
+ enabled
1473
+ });
1474
+ },
1475
+ dispose: () => {
1476
+ transport.removeEventListener("message", onMessage);
1477
+ }
1478
+ };
1479
+ }
1480
+
1481
+ // src/editor/custom-css.ts
1482
+ var STOREFRONT_SECTION_CUSTOM_CSS_SETTING = "__kotaoCustomCss";
1483
+ var CSS_GROUP_AT_RULE = /^@(?:media|supports|container|layer|scope)\b/iu;
1484
+ function rawCss(value) {
1485
+ const css = Array.isArray(value) ? value.filter((entry) => typeof entry === "string").join("\n") : typeof value === "string" ? value : "";
1486
+ return css.replace(/\/\*[\s\S]*?\*\//gu, "").replace(/<\/style/giu, "").trim();
1487
+ }
1488
+ function splitTopLevelSelectors(selectorList) {
1489
+ const selectors = [];
1490
+ let parentheses = 0;
1491
+ let brackets = 0;
1492
+ let quote = null;
1493
+ let current = "";
1494
+ for (let index = 0; index < selectorList.length; index += 1) {
1495
+ const character = selectorList[index] ?? "";
1496
+ if (quote !== null) {
1497
+ current += character;
1498
+ if (character === "\\") {
1499
+ current += selectorList[index + 1] ?? "";
1500
+ index += 1;
1501
+ } else if (character === quote) quote = null;
1502
+ continue;
1503
+ }
1504
+ if (character === '"' || character === "'") quote = character;
1505
+ else if (character === "(") parentheses += 1;
1506
+ else if (character === ")") parentheses = Math.max(0, parentheses - 1);
1507
+ else if (character === "[") brackets += 1;
1508
+ else if (character === "]") brackets = Math.max(0, brackets - 1);
1509
+ if (character === "," && parentheses === 0 && brackets === 0) {
1510
+ selectors.push(current);
1511
+ current = "";
1512
+ } else current += character;
1513
+ }
1514
+ selectors.push(current);
1515
+ return selectors;
1516
+ }
1517
+ function splitTopLevelRules(css) {
1518
+ const rules = [];
1519
+ let prelude = "";
1520
+ let quote = null;
1521
+ for (let index = 0; index < css.length; index += 1) {
1522
+ const character = css[index] ?? "";
1523
+ if (quote !== null) {
1524
+ prelude += character;
1525
+ if (character === "\\") {
1526
+ prelude += css[index + 1] ?? "";
1527
+ index += 1;
1528
+ } else if (character === quote) quote = null;
1529
+ continue;
1530
+ }
1531
+ if (character === '"' || character === "'") {
1532
+ quote = character;
1533
+ prelude += character;
1534
+ continue;
1535
+ }
1536
+ if (character === "{") {
1537
+ let depth = 1;
1538
+ let body = "";
1539
+ let bodyQuote = null;
1540
+ index += 1;
1541
+ for (; index < css.length; index += 1) {
1542
+ const nested = css[index] ?? "";
1543
+ if (bodyQuote !== null) {
1544
+ body += nested;
1545
+ if (nested === "\\") {
1546
+ body += css[index + 1] ?? "";
1547
+ index += 1;
1548
+ } else if (nested === bodyQuote) bodyQuote = null;
1549
+ continue;
1550
+ }
1551
+ if (nested === '"' || nested === "'") {
1552
+ bodyQuote = nested;
1553
+ body += nested;
1554
+ } else if (nested === "{") {
1555
+ depth += 1;
1556
+ body += nested;
1557
+ } else if (nested === "}") {
1558
+ depth -= 1;
1559
+ if (depth === 0) break;
1560
+ body += nested;
1561
+ } else body += nested;
1562
+ }
1563
+ rules.push({ prelude: prelude.trim(), body });
1564
+ prelude = "";
1565
+ } else if (character === ";") {
1566
+ if (prelude.trim() !== "") rules.push({ prelude: prelude.trim(), body: null });
1567
+ prelude = "";
1568
+ } else prelude += character;
1569
+ }
1570
+ if (prelude.trim() !== "") rules.push({ prelude: prelude.trim(), body: null });
1571
+ return rules;
1572
+ }
1573
+ function scopeRules(css, scope) {
1574
+ return splitTopLevelRules(css).map(({ prelude, body }) => {
1575
+ if (body === null) return `${prelude};`;
1576
+ if (prelude.startsWith("@")) {
1577
+ return CSS_GROUP_AT_RULE.test(prelude) ? `${prelude} {
1578
+ ${scopeRules(body, scope)}
1579
+ }` : `${prelude} {${body}}`;
1580
+ }
1581
+ const selectors = splitTopLevelSelectors(prelude).map((selector) => selector.trim()).filter(Boolean).map(
1582
+ (selector) => selector.includes("&") ? selector.replaceAll("&", scope) : `${scope} ${selector}`
1583
+ ).join(", ");
1584
+ return selectors === "" ? "" : `${selectors} {${body}}`;
1585
+ }).filter(Boolean).join("\n");
1586
+ }
1587
+ function scopeStorefrontSectionCss(value, sectionId) {
1588
+ const css = rawCss(value);
1589
+ return css === "" ? "" : scopeRules(css, `#shopify-section-${sectionId}`).trim();
1590
+ }
1591
+
1592
+ export { STOREFRONT_SECTION_CUSTOM_CSS_SETTING, createStorefrontEditorBridge, createStorefrontEditorHostBridge, positionStorefrontEditorCanvasToolbar, scopeStorefrontSectionCss };
1593
+ //# sourceMappingURL=chunk-RFKLO6TD.js.map
1594
+ //# sourceMappingURL=chunk-RFKLO6TD.js.map