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