@numueg/theme-sdk 0.3.2 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +521 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +98 -221
- package/dist/index.d.ts +98 -221
- package/dist/index.mjs +508 -6
- package/dist/index.mjs.map +1 -1
- package/dist/mount-BN2mz_wx.d.ts +225 -0
- package/dist/mount-DH9dz3dq.d.mts +225 -0
- package/dist/validation.cjs +408 -0
- package/dist/validation.cjs.map +1 -0
- package/dist/validation.d.mts +89 -0
- package/dist/validation.d.ts +89 -0
- package/dist/validation.mjs +397 -0
- package/dist/validation.mjs.map +1 -0
- package/dist/verify.cjs +200 -0
- package/dist/verify.cjs.map +1 -0
- package/dist/verify.d.mts +65 -0
- package/dist/verify.d.ts +65 -0
- package/dist/verify.mjs +191 -0
- package/dist/verify.mjs.map +1 -0
- package/package.json +11 -1
package/dist/index.cjs
CHANGED
|
@@ -6,6 +6,400 @@ var jsxRuntime = require('react/jsx-runtime');
|
|
|
6
6
|
|
|
7
7
|
// src/types/theme.ts
|
|
8
8
|
var MAX_BLOCK_DEPTH = 5;
|
|
9
|
+
|
|
10
|
+
// src/validation/index.ts
|
|
11
|
+
var THEME_CONTRACT_VERSION = 1;
|
|
12
|
+
var SDK_VERSION = "0.5.0" ;
|
|
13
|
+
var REQUIRED_TEMPLATES = [
|
|
14
|
+
"home",
|
|
15
|
+
"product",
|
|
16
|
+
"collection",
|
|
17
|
+
"cart",
|
|
18
|
+
"page",
|
|
19
|
+
"search",
|
|
20
|
+
"404"
|
|
21
|
+
];
|
|
22
|
+
var KNOWN_TEMPLATES = /* @__PURE__ */ new Set([
|
|
23
|
+
...REQUIRED_TEMPLATES,
|
|
24
|
+
"blog",
|
|
25
|
+
"article",
|
|
26
|
+
"policies",
|
|
27
|
+
"password",
|
|
28
|
+
"account",
|
|
29
|
+
"checkout"
|
|
30
|
+
]);
|
|
31
|
+
var KNOWN_SETTING_TYPES = /* @__PURE__ */ new Set([
|
|
32
|
+
"text",
|
|
33
|
+
"textarea",
|
|
34
|
+
"richtext",
|
|
35
|
+
"number",
|
|
36
|
+
"range",
|
|
37
|
+
"color",
|
|
38
|
+
"checkbox",
|
|
39
|
+
"select",
|
|
40
|
+
"radio",
|
|
41
|
+
"font",
|
|
42
|
+
"image_picker",
|
|
43
|
+
"url",
|
|
44
|
+
"product",
|
|
45
|
+
"product_list",
|
|
46
|
+
"collection",
|
|
47
|
+
"collection_list",
|
|
48
|
+
"header",
|
|
49
|
+
"paragraph",
|
|
50
|
+
"html",
|
|
51
|
+
"date",
|
|
52
|
+
"time",
|
|
53
|
+
"video_picker",
|
|
54
|
+
"color_scheme",
|
|
55
|
+
"page_picker",
|
|
56
|
+
"blog_picker",
|
|
57
|
+
"link_list_picker",
|
|
58
|
+
"variant_picker",
|
|
59
|
+
"file_upload",
|
|
60
|
+
"icon_picker",
|
|
61
|
+
"icon"
|
|
62
|
+
]);
|
|
63
|
+
var PRESENTATIONAL_SETTING_TYPES = /* @__PURE__ */ new Set([
|
|
64
|
+
"header",
|
|
65
|
+
"paragraph",
|
|
66
|
+
"html"
|
|
67
|
+
]);
|
|
68
|
+
var SECTION_TYPE_RE = /^[a-z][a-z0-9_-]*$/;
|
|
69
|
+
var THEME_ID_RE = /^[a-z0-9][a-z0-9_-]*[a-z0-9]$/;
|
|
70
|
+
var SEMVER_RE = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z-.]+)?(?:\+[0-9A-Za-z-.]+)?$/;
|
|
71
|
+
function isObject(v) {
|
|
72
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
73
|
+
}
|
|
74
|
+
function isNonEmptyString(v) {
|
|
75
|
+
return typeof v === "string" && v.trim().length > 0;
|
|
76
|
+
}
|
|
77
|
+
var IssueBag = class {
|
|
78
|
+
constructor() {
|
|
79
|
+
this.issues = [];
|
|
80
|
+
}
|
|
81
|
+
err(code, message, path) {
|
|
82
|
+
this.issues.push({ level: "error", code, message, path });
|
|
83
|
+
}
|
|
84
|
+
warn(code, message, path) {
|
|
85
|
+
this.issues.push({ level: "warning", code, message, path });
|
|
86
|
+
}
|
|
87
|
+
result() {
|
|
88
|
+
return {
|
|
89
|
+
valid: !this.issues.some((i) => i.level === "error"),
|
|
90
|
+
issues: this.issues
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
function collectPresetSectionTypes(manifest) {
|
|
95
|
+
const types = /* @__PURE__ */ new Set();
|
|
96
|
+
const presets = manifest.presets;
|
|
97
|
+
if (!isObject(presets)) return types;
|
|
98
|
+
const buckets = [presets.templates, presets.section_groups];
|
|
99
|
+
for (const bucket of buckets) {
|
|
100
|
+
if (!isObject(bucket)) continue;
|
|
101
|
+
for (const entry of Object.values(bucket)) {
|
|
102
|
+
if (!isObject(entry)) continue;
|
|
103
|
+
const sections = entry.sections;
|
|
104
|
+
const instances = Array.isArray(sections) ? sections : isObject(sections) ? Object.values(sections) : [];
|
|
105
|
+
for (const inst of instances) {
|
|
106
|
+
if (isObject(inst) && isNonEmptyString(inst.type)) types.add(inst.type);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return types;
|
|
111
|
+
}
|
|
112
|
+
function validateSettingInto(bag, setting, pathPrefix, seenIds) {
|
|
113
|
+
if (!isObject(setting)) {
|
|
114
|
+
bag.err("schema.setting.invalid", "Setting must be an object.", pathPrefix);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const type = setting.type;
|
|
118
|
+
if (!isNonEmptyString(type)) {
|
|
119
|
+
bag.err("schema.setting.type.missing", "Setting is missing a `type`.", pathPrefix);
|
|
120
|
+
} else if (!KNOWN_SETTING_TYPES.has(type)) {
|
|
121
|
+
bag.warn(
|
|
122
|
+
"schema.setting.type.unknown",
|
|
123
|
+
`Unknown setting type "${type}" \u2014 the customizer will fall back to a text input.`,
|
|
124
|
+
pathPrefix
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
const presentational = isNonEmptyString(type) && PRESENTATIONAL_SETTING_TYPES.has(type);
|
|
128
|
+
if (!presentational) {
|
|
129
|
+
if (!isNonEmptyString(setting.id)) {
|
|
130
|
+
bag.err("schema.setting.id.missing", "Setting is missing an `id`.", pathPrefix);
|
|
131
|
+
} else {
|
|
132
|
+
if (seenIds.has(setting.id)) {
|
|
133
|
+
bag.err(
|
|
134
|
+
"schema.setting.id.duplicate",
|
|
135
|
+
`Duplicate setting id "${setting.id}".`,
|
|
136
|
+
pathPrefix
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
seenIds.add(setting.id);
|
|
140
|
+
}
|
|
141
|
+
if (!isNonEmptyString(setting.label)) {
|
|
142
|
+
bag.warn("schema.setting.label.missing", "Setting has no `label`.", pathPrefix);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (type === "select" || type === "radio") {
|
|
146
|
+
const options = setting.options;
|
|
147
|
+
if (!Array.isArray(options) || options.length === 0) {
|
|
148
|
+
bag.err(
|
|
149
|
+
"schema.setting.options.missing",
|
|
150
|
+
`"${type}" setting "${String(setting.id)}" must declare a non-empty \`options\` array.`,
|
|
151
|
+
pathPrefix
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (type === "range") {
|
|
156
|
+
if (typeof setting.min !== "number" || typeof setting.max !== "number") {
|
|
157
|
+
bag.err(
|
|
158
|
+
"schema.setting.range.bounds",
|
|
159
|
+
`"range" setting "${String(setting.id)}" must declare numeric \`min\` and \`max\`.`,
|
|
160
|
+
pathPrefix
|
|
161
|
+
);
|
|
162
|
+
} else if (setting.min >= setting.max) {
|
|
163
|
+
bag.err(
|
|
164
|
+
"schema.setting.range.order",
|
|
165
|
+
`"range" setting "${String(setting.id)}" has min >= max.`,
|
|
166
|
+
pathPrefix
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
function validateSectionSchema(schema, opts = {}) {
|
|
172
|
+
const bag = new IssueBag();
|
|
173
|
+
const where = opts.filenameType ? `${opts.filenameType}.json` : "section schema";
|
|
174
|
+
if (!isObject(schema)) {
|
|
175
|
+
bag.err("schema.invalid", "Section schema must be a JSON object.", where);
|
|
176
|
+
return bag.result();
|
|
177
|
+
}
|
|
178
|
+
const type = schema.type;
|
|
179
|
+
if (!isNonEmptyString(type)) {
|
|
180
|
+
bag.err("schema.type.missing", "Section schema is missing a `type`.", where);
|
|
181
|
+
} else {
|
|
182
|
+
if (!SECTION_TYPE_RE.test(type)) {
|
|
183
|
+
bag.err(
|
|
184
|
+
"schema.type.format",
|
|
185
|
+
`Section type "${type}" must match ${SECTION_TYPE_RE} (lowercase, start with a letter).`,
|
|
186
|
+
where
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
if (opts.filenameType && type !== opts.filenameType) {
|
|
190
|
+
bag.err(
|
|
191
|
+
"schema.type.filename_mismatch",
|
|
192
|
+
`Schema type "${type}" must equal its filename "${opts.filenameType}" (component-filename = schema-type convention).`,
|
|
193
|
+
where
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
if (!isNonEmptyString(schema.name)) {
|
|
198
|
+
bag.err("schema.name.missing", "Section schema is missing a `name`.", where);
|
|
199
|
+
}
|
|
200
|
+
if (schema.settings === void 0) {
|
|
201
|
+
bag.warn("schema.settings.missing", "Section schema has no `settings`.", where);
|
|
202
|
+
} else if (!Array.isArray(schema.settings)) {
|
|
203
|
+
bag.err("schema.settings.invalid", "`settings` must be an array.", where);
|
|
204
|
+
} else {
|
|
205
|
+
const seen = /* @__PURE__ */ new Set();
|
|
206
|
+
schema.settings.forEach(
|
|
207
|
+
(s, i) => validateSettingInto(bag, s, `${where}.settings[${i}]`, seen)
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
if (schema.blocks !== void 0) {
|
|
211
|
+
if (!Array.isArray(schema.blocks)) {
|
|
212
|
+
bag.err("schema.blocks.invalid", "`blocks` must be an array.", where);
|
|
213
|
+
} else {
|
|
214
|
+
schema.blocks.forEach((b, i) => {
|
|
215
|
+
if (!isObject(b) || !isNonEmptyString(b.type)) {
|
|
216
|
+
bag.err("schema.block.type.missing", `Block[${i}] is missing a \`type\`.`, where);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
if (!SECTION_TYPE_RE.test(b.type)) {
|
|
220
|
+
bag.err(
|
|
221
|
+
"schema.block.type.format",
|
|
222
|
+
`Block type "${b.type}" must match ${SECTION_TYPE_RE}.`,
|
|
223
|
+
where
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
if (Array.isArray(b.settings)) {
|
|
227
|
+
const seen = /* @__PURE__ */ new Set();
|
|
228
|
+
b.settings.forEach(
|
|
229
|
+
(s, j) => validateSettingInto(bag, s, `${where}.blocks[${i}].settings[${j}]`, seen)
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return bag.result();
|
|
236
|
+
}
|
|
237
|
+
function validateSettingsAgainstSchema(settings, schema, pathPrefix = "settings") {
|
|
238
|
+
const bag = new IssueBag();
|
|
239
|
+
if (!isObject(settings)) {
|
|
240
|
+
bag.err("instance.settings.invalid", "Section settings must be an object.", pathPrefix);
|
|
241
|
+
return bag.result();
|
|
242
|
+
}
|
|
243
|
+
const defs = Array.isArray(schema.settings) ? schema.settings : [];
|
|
244
|
+
const byId = /* @__PURE__ */ new Map();
|
|
245
|
+
for (const d of defs) if (isNonEmptyString(d?.id)) byId.set(d.id, d);
|
|
246
|
+
for (const [key, value] of Object.entries(settings)) {
|
|
247
|
+
const def = byId.get(key);
|
|
248
|
+
if (!def) {
|
|
249
|
+
bag.warn(
|
|
250
|
+
"instance.setting.unknown",
|
|
251
|
+
`Setting "${key}" is not declared in the "${String(schema.type)}" schema.`,
|
|
252
|
+
`${pathPrefix}.${key}`
|
|
253
|
+
);
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
if (value === null || value === void 0) continue;
|
|
257
|
+
const p = `${pathPrefix}.${key}`;
|
|
258
|
+
if ((def.type === "select" || def.type === "radio") && Array.isArray(def.options)) {
|
|
259
|
+
const allowed = def.options.map((o) => o.value);
|
|
260
|
+
if (typeof value === "string" && !allowed.includes(value)) {
|
|
261
|
+
bag.err(
|
|
262
|
+
"instance.setting.option.invalid",
|
|
263
|
+
`"${key}" = "${value}" is not one of: ${allowed.join(", ")}.`,
|
|
264
|
+
p
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
if (def.type === "range" && typeof value === "number") {
|
|
269
|
+
if (typeof def.min === "number" && value < def.min) {
|
|
270
|
+
bag.err("instance.setting.range.under", `"${key}" = ${value} is below min ${def.min}.`, p);
|
|
271
|
+
}
|
|
272
|
+
if (typeof def.max === "number" && value > def.max) {
|
|
273
|
+
bag.err("instance.setting.range.over", `"${key}" = ${value} is above max ${def.max}.`, p);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
if (def.type === "checkbox" && typeof value !== "boolean") {
|
|
277
|
+
bag.warn("instance.setting.type.mismatch", `"${key}" should be a boolean.`, p);
|
|
278
|
+
}
|
|
279
|
+
if ((def.type === "number" || def.type === "range") && typeof value !== "number") {
|
|
280
|
+
bag.warn("instance.setting.type.mismatch", `"${key}" should be a number.`, p);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return bag.result();
|
|
284
|
+
}
|
|
285
|
+
function validateManifestCore(bag, m) {
|
|
286
|
+
if (!isNonEmptyString(m.id)) {
|
|
287
|
+
bag.err("manifest.id.missing", "theme.json is missing `id`.", "id");
|
|
288
|
+
} else if (!THEME_ID_RE.test(m.id)) {
|
|
289
|
+
bag.err(
|
|
290
|
+
"manifest.id.format",
|
|
291
|
+
`Theme id "${m.id}" must be lowercase alphanumeric with dashes/underscores (no leading/trailing separator).`,
|
|
292
|
+
"id"
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
const name = m.name;
|
|
296
|
+
const nameOk = isNonEmptyString(name) || isObject(name) && Object.values(name).some((v) => isNonEmptyString(v));
|
|
297
|
+
if (!nameOk) {
|
|
298
|
+
bag.err("manifest.name.missing", "theme.json is missing a non-empty `name`.", "name");
|
|
299
|
+
}
|
|
300
|
+
if (!isNonEmptyString(m.version)) {
|
|
301
|
+
bag.err("manifest.version.missing", "theme.json is missing `version`.", "version");
|
|
302
|
+
} else if (!SEMVER_RE.test(m.version)) {
|
|
303
|
+
bag.err("manifest.version.invalid", `Version "${m.version}" is not valid semver.`, "version");
|
|
304
|
+
}
|
|
305
|
+
if (!isNonEmptyString(m.author)) {
|
|
306
|
+
bag.err("manifest.author.missing", "theme.json is missing `author`.", "author");
|
|
307
|
+
}
|
|
308
|
+
if (m.min_sdk_version !== void 0 && !SEMVER_RE.test(String(m.min_sdk_version))) {
|
|
309
|
+
bag.warn("manifest.min_sdk_version.invalid", "`min_sdk_version` is not valid semver.", "min_sdk_version");
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
function validateManifest(manifest, ctx = {}) {
|
|
313
|
+
const bag = new IssueBag();
|
|
314
|
+
if (!isObject(manifest)) {
|
|
315
|
+
bag.err("manifest.invalid", "theme.json must be a JSON object.", "theme.json");
|
|
316
|
+
return bag.result();
|
|
317
|
+
}
|
|
318
|
+
validateManifestCore(bag, manifest);
|
|
319
|
+
const presets = manifest.presets;
|
|
320
|
+
if (!isObject(presets) || Object.keys(presets).length === 0) {
|
|
321
|
+
bag.warn("manifest.presets.empty", "theme.json has no presets \u2014 merchants start with an empty page.", "presets");
|
|
322
|
+
} else {
|
|
323
|
+
if (ctx.sectionTypes) {
|
|
324
|
+
for (const type of collectPresetSectionTypes(manifest)) {
|
|
325
|
+
if (!ctx.sectionTypes.has(type)) {
|
|
326
|
+
bag.err(
|
|
327
|
+
"manifest.preset.unknown_section",
|
|
328
|
+
`Preset references section type "${type}" with no schemas/sections/${type}.json.`,
|
|
329
|
+
"presets"
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
const templates = isObject(presets.templates) ? presets.templates : {};
|
|
335
|
+
for (const t of REQUIRED_TEMPLATES) {
|
|
336
|
+
if (!(t in templates)) {
|
|
337
|
+
bag.warn(
|
|
338
|
+
"manifest.template.missing",
|
|
339
|
+
`No preset for required template "${t}" \u2014 the storefront will fall back to its built-in.`,
|
|
340
|
+
`presets.templates.${t}`
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
return bag.result();
|
|
346
|
+
}
|
|
347
|
+
function validateBuiltManifest(builtManifest, importMap, opts = {}) {
|
|
348
|
+
const bag = new IssueBag();
|
|
349
|
+
if (!isObject(builtManifest)) {
|
|
350
|
+
bag.err("built.invalid", "manifest.json must be a JSON object.", "manifest.json");
|
|
351
|
+
return bag.result();
|
|
352
|
+
}
|
|
353
|
+
validateManifestCore(bag, builtManifest);
|
|
354
|
+
const schemas = builtManifest.section_schemas;
|
|
355
|
+
const shipped = new Set(isObject(schemas) ? Object.keys(schemas) : []);
|
|
356
|
+
if (!isObject(schemas)) {
|
|
357
|
+
bag.warn("built.section_schemas.missing", "manifest.json has no `section_schemas`.", "section_schemas");
|
|
358
|
+
}
|
|
359
|
+
for (const type of collectPresetSectionTypes(builtManifest)) {
|
|
360
|
+
if (!shipped.has(type)) {
|
|
361
|
+
bag.err(
|
|
362
|
+
"built.preset.unknown_section",
|
|
363
|
+
`Preset references section type "${type}" not present in section_schemas.`,
|
|
364
|
+
"presets"
|
|
365
|
+
);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
if (isObject(schemas)) {
|
|
369
|
+
for (const [type, schema] of Object.entries(schemas)) {
|
|
370
|
+
const r = validateSectionSchema(schema, { filenameType: type });
|
|
371
|
+
for (const issue of r.issues) bag.issues.push(issue);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
if (!isNonEmptyString(builtManifest.plugin_version)) {
|
|
375
|
+
bag.warn("built.plugin_version.missing", "manifest.json has no `plugin_version`.", "plugin_version");
|
|
376
|
+
}
|
|
377
|
+
if (importMap !== void 0) {
|
|
378
|
+
if (!isObject(importMap)) {
|
|
379
|
+
bag.err("importmap.invalid", "import-map.json must be a JSON object.", "import-map.json");
|
|
380
|
+
} else {
|
|
381
|
+
const cv = importMap.contract_version;
|
|
382
|
+
if (typeof cv !== "number") {
|
|
383
|
+
bag.warn(
|
|
384
|
+
"importmap.contract_version.missing",
|
|
385
|
+
"import-map.json has no numeric `contract_version` \u2014 built by an older plugin.",
|
|
386
|
+
"contract_version"
|
|
387
|
+
);
|
|
388
|
+
} else if (typeof opts.hostContractVersion === "number" && cv > opts.hostContractVersion) {
|
|
389
|
+
bag.err(
|
|
390
|
+
"importmap.contract_version.incompatible",
|
|
391
|
+
`Theme built for contract v${cv}; this platform supports up to v${opts.hostContractVersion}.`,
|
|
392
|
+
"contract_version"
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
return bag.result();
|
|
398
|
+
}
|
|
399
|
+
function mergeResults(...results) {
|
|
400
|
+
const issues = results.flatMap((r) => r.issues);
|
|
401
|
+
return { valid: !issues.some((i) => i.level === "error"), issues };
|
|
402
|
+
}
|
|
9
403
|
var ShopContext = react.createContext(null);
|
|
10
404
|
var ProductContext = react.createContext(null);
|
|
11
405
|
var CollectionContext = react.createContext(null);
|
|
@@ -1936,6 +2330,64 @@ function NuMuProvider({
|
|
|
1936
2330
|
function ProductProvider({ product, children }) {
|
|
1937
2331
|
return /* @__PURE__ */ jsxRuntime.jsx(ProductContext.Provider, { value: product, children });
|
|
1938
2332
|
}
|
|
2333
|
+
function CollectionProvider({ collection, children }) {
|
|
2334
|
+
return /* @__PURE__ */ jsxRuntime.jsx(CollectionContext.Provider, { value: collection, children });
|
|
2335
|
+
}
|
|
2336
|
+
|
|
2337
|
+
// src/utils/logoStyle.ts
|
|
2338
|
+
var LOGO_SHAPE_OPTIONS = [
|
|
2339
|
+
{ value: "none", label: "Original", label_ar: "\u0627\u0644\u0623\u0635\u0644\u064A" },
|
|
2340
|
+
{ value: "square", label: "Square", label_ar: "\u0645\u0631\u0628\u0639" },
|
|
2341
|
+
{ value: "rounded", label: "Rounded square", label_ar: "\u0645\u0631\u0628\u0639 \u0628\u0632\u0648\u0627\u064A\u0627 \u062F\u0627\u0626\u0631\u064A\u0629" },
|
|
2342
|
+
{ value: "circle", label: "Circle", label_ar: "\u062F\u0627\u0626\u0631\u0629" },
|
|
2343
|
+
{ value: "triangle", label: "Triangle", label_ar: "\u0645\u062B\u0644\u062B" }
|
|
2344
|
+
];
|
|
2345
|
+
var LOGO_SIZE_OPTIONS = [
|
|
2346
|
+
{ value: "small", label: "Small", label_ar: "\u0635\u063A\u064A\u0631" },
|
|
2347
|
+
{ value: "medium", label: "Medium", label_ar: "\u0645\u062A\u0648\u0633\u0637" },
|
|
2348
|
+
{ value: "large", label: "Large", label_ar: "\u0643\u0628\u064A\u0631" }
|
|
2349
|
+
];
|
|
2350
|
+
var SHAPED_PX = {
|
|
2351
|
+
small: { plain: 32, rounded: 48 },
|
|
2352
|
+
medium: { plain: 40, rounded: 64 },
|
|
2353
|
+
large: { plain: 56, rounded: 80 }
|
|
2354
|
+
};
|
|
2355
|
+
function normalizeSize(size) {
|
|
2356
|
+
return size === "large" || size === "medium" ? size : "small";
|
|
2357
|
+
}
|
|
2358
|
+
function logoImgStyle(shape, size) {
|
|
2359
|
+
if (!shape || shape === "none") return void 0;
|
|
2360
|
+
const s = normalizeSize(size);
|
|
2361
|
+
const isRound = shape === "circle" || shape === "rounded";
|
|
2362
|
+
const px = isRound ? SHAPED_PX[s].rounded : SHAPED_PX[s].plain;
|
|
2363
|
+
const base = {
|
|
2364
|
+
height: px,
|
|
2365
|
+
width: px,
|
|
2366
|
+
objectFit: "cover",
|
|
2367
|
+
flex: "0 0 auto"
|
|
2368
|
+
};
|
|
2369
|
+
switch (shape) {
|
|
2370
|
+
case "circle":
|
|
2371
|
+
return { ...base, borderRadius: "9999px" };
|
|
2372
|
+
case "rounded":
|
|
2373
|
+
return { ...base, borderRadius: "0.5rem" };
|
|
2374
|
+
case "triangle":
|
|
2375
|
+
return { ...base, clipPath: "polygon(50% 0%, 100% 100%, 0% 100%)" };
|
|
2376
|
+
case "square":
|
|
2377
|
+
default:
|
|
2378
|
+
return base;
|
|
2379
|
+
}
|
|
2380
|
+
}
|
|
2381
|
+
function logoStyleTokens(shape, size) {
|
|
2382
|
+
const style = logoImgStyle(shape, size);
|
|
2383
|
+
if (!style) return {};
|
|
2384
|
+
const box = `${style.height}px`;
|
|
2385
|
+
return {
|
|
2386
|
+
"--theme-logo-box": box,
|
|
2387
|
+
"--theme-logo-radius": typeof style.borderRadius === "string" ? style.borderRadius : "0",
|
|
2388
|
+
"--theme-logo-clip": typeof style.clipPath === "string" ? style.clipPath : "none"
|
|
2389
|
+
};
|
|
2390
|
+
}
|
|
1939
2391
|
|
|
1940
2392
|
// src/utils/styleTokens.ts
|
|
1941
2393
|
var COLOR_ROLE_ALIASES = {
|
|
@@ -2076,6 +2528,12 @@ function computeGlobalStyleTokens(globalSettings) {
|
|
|
2076
2528
|
pushHref(FONT_REGISTRY[value]?.href);
|
|
2077
2529
|
}
|
|
2078
2530
|
}
|
|
2531
|
+
const gs = globalSettings;
|
|
2532
|
+
const logoTokens = logoStyleTokens(
|
|
2533
|
+
typeof gs.logo_shape === "string" ? gs.logo_shape : void 0,
|
|
2534
|
+
typeof gs.logo_size === "string" ? gs.logo_size : void 0
|
|
2535
|
+
);
|
|
2536
|
+
for (const [k, v] of Object.entries(logoTokens)) cssVars[k] = v;
|
|
2079
2537
|
return { cssVars, fontHrefs };
|
|
2080
2538
|
}
|
|
2081
2539
|
function applyGlobalStyleTokens(globalSettings, el) {
|
|
@@ -2118,6 +2576,16 @@ function pickDemo(ctx, themeSettings) {
|
|
|
2118
2576
|
const t = themeSettings.templates;
|
|
2119
2577
|
return !t || Object.keys(t).length === 0;
|
|
2120
2578
|
}
|
|
2579
|
+
function wrapEntityProviders(app, pageData) {
|
|
2580
|
+
let inner = app;
|
|
2581
|
+
if (pageData.collection) {
|
|
2582
|
+
inner = /* @__PURE__ */ jsxRuntime.jsx(CollectionProvider, { collection: pageData.collection, children: inner });
|
|
2583
|
+
}
|
|
2584
|
+
if (pageData.product) {
|
|
2585
|
+
inner = /* @__PURE__ */ jsxRuntime.jsx(ProductProvider, { product: pageData.product, children: inner });
|
|
2586
|
+
}
|
|
2587
|
+
return inner;
|
|
2588
|
+
}
|
|
2121
2589
|
var ThemeMountBridge = react.forwardRef(function ThemeMountBridge2({ ctx, mountEl, renderApp }, ref) {
|
|
2122
2590
|
const [themeSettings, setThemeSettings] = react.useState(
|
|
2123
2591
|
ctx.themeSettings
|
|
@@ -2158,7 +2626,7 @@ var ThemeMountBridge = react.forwardRef(function ThemeMountBridge2({ ctx, mountE
|
|
|
2158
2626
|
initialProducts: pageData.products,
|
|
2159
2627
|
initialCollections: pageData.collections,
|
|
2160
2628
|
currentTemplate: template,
|
|
2161
|
-
children:
|
|
2629
|
+
children: wrapEntityProviders(app, pageData)
|
|
2162
2630
|
}
|
|
2163
2631
|
);
|
|
2164
2632
|
});
|
|
@@ -2194,9 +2662,6 @@ function defineThemeEntry(renderApp) {
|
|
|
2194
2662
|
createApp: (ctx) => buildThemeElement(ctx, null, renderApp)
|
|
2195
2663
|
};
|
|
2196
2664
|
}
|
|
2197
|
-
function CollectionProvider({ collection, children }) {
|
|
2198
|
-
return /* @__PURE__ */ jsxRuntime.jsx(CollectionContext.Provider, { value: collection, children });
|
|
2199
|
-
}
|
|
2200
2665
|
function Money({
|
|
2201
2666
|
amount,
|
|
2202
2667
|
currency,
|
|
@@ -2347,6 +2812,43 @@ function Image({
|
|
|
2347
2812
|
}
|
|
2348
2813
|
);
|
|
2349
2814
|
}
|
|
2815
|
+
var str = (v) => typeof v === "string" ? v : "";
|
|
2816
|
+
var NONE_HEIGHT = { small: 28, medium: 36, large: 48 };
|
|
2817
|
+
function Logo({
|
|
2818
|
+
src,
|
|
2819
|
+
alt,
|
|
2820
|
+
shape,
|
|
2821
|
+
size,
|
|
2822
|
+
className,
|
|
2823
|
+
style,
|
|
2824
|
+
fallback
|
|
2825
|
+
}) {
|
|
2826
|
+
const settings = useThemeSettings();
|
|
2827
|
+
const shop = useShop();
|
|
2828
|
+
const g = settings?.global_settings ?? {};
|
|
2829
|
+
const url = str(src) || str(g.logo_url) || shop?.logo_url || "";
|
|
2830
|
+
const resolvedShape = shape || str(g.logo_shape) || "none";
|
|
2831
|
+
const resolvedSize = size || str(g.logo_size) || "small";
|
|
2832
|
+
const altText = alt || str(g.brand_name) || shop?.name || "";
|
|
2833
|
+
if (!url) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: fallback ?? null });
|
|
2834
|
+
const shaped = resolvedShape !== "none";
|
|
2835
|
+
const imgStyle = shaped ? { ...logoImgStyle(resolvedShape, resolvedSize), ...style } : {
|
|
2836
|
+
height: NONE_HEIGHT[resolvedSize] ?? NONE_HEIGHT.small,
|
|
2837
|
+
width: "auto",
|
|
2838
|
+
objectFit: "contain",
|
|
2839
|
+
...style
|
|
2840
|
+
};
|
|
2841
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2842
|
+
"img",
|
|
2843
|
+
{
|
|
2844
|
+
src: url,
|
|
2845
|
+
alt: altText,
|
|
2846
|
+
className,
|
|
2847
|
+
style: imgStyle,
|
|
2848
|
+
loading: "eager"
|
|
2849
|
+
}
|
|
2850
|
+
);
|
|
2851
|
+
}
|
|
2350
2852
|
var ABSOLUTE_URL = /^[a-z]+:|^\/\//i;
|
|
2351
2853
|
function Link({ to, children, ...rest }) {
|
|
2352
2854
|
const shop = useShop();
|
|
@@ -3572,9 +4074,14 @@ exports.ICON_NAMES = ICON_NAMES;
|
|
|
3572
4074
|
exports.Icon = Icon;
|
|
3573
4075
|
exports.IconMap = IconMap;
|
|
3574
4076
|
exports.Image = Image;
|
|
4077
|
+
exports.KNOWN_SETTING_TYPES = KNOWN_SETTING_TYPES;
|
|
4078
|
+
exports.KNOWN_TEMPLATES = KNOWN_TEMPLATES;
|
|
4079
|
+
exports.LOGO_SHAPE_OPTIONS = LOGO_SHAPE_OPTIONS;
|
|
4080
|
+
exports.LOGO_SIZE_OPTIONS = LOGO_SIZE_OPTIONS;
|
|
3575
4081
|
exports.Link = Link;
|
|
3576
4082
|
exports.LocaleSwitcher = LocaleSwitcher;
|
|
3577
4083
|
exports.LocalizationContext = LocalizationContext;
|
|
4084
|
+
exports.Logo = Logo;
|
|
3578
4085
|
exports.MAX_BLOCK_DEPTH = MAX_BLOCK_DEPTH;
|
|
3579
4086
|
exports.Money = Money;
|
|
3580
4087
|
exports.NavigationContext = NavigationContext;
|
|
@@ -3583,10 +4090,13 @@ exports.PageContext = PageContext;
|
|
|
3583
4090
|
exports.ProductCard = ProductCard;
|
|
3584
4091
|
exports.ProductContext = ProductContext;
|
|
3585
4092
|
exports.ProductProvider = ProductProvider;
|
|
4093
|
+
exports.REQUIRED_TEMPLATES = REQUIRED_TEMPLATES;
|
|
3586
4094
|
exports.RichText = RichText;
|
|
4095
|
+
exports.SDK_VERSION = SDK_VERSION;
|
|
3587
4096
|
exports.Section = Section;
|
|
3588
4097
|
exports.SectionContext = SectionContext;
|
|
3589
4098
|
exports.ShopContext = ShopContext;
|
|
4099
|
+
exports.THEME_CONTRACT_VERSION = THEME_CONTRACT_VERSION;
|
|
3590
4100
|
exports.ThemeSettingsContext = ThemeSettingsContext;
|
|
3591
4101
|
exports.applyGlobalStyleTokens = applyGlobalStyleTokens;
|
|
3592
4102
|
exports.applyImageTransform = applyImageTransform;
|
|
@@ -3613,6 +4123,9 @@ exports.isDefinedBlock = isDefinedBlock;
|
|
|
3613
4123
|
exports.isDefinedSection = isDefinedSection;
|
|
3614
4124
|
exports.isDynamicSource = isDynamicSource;
|
|
3615
4125
|
exports.isSdkAvailable = isSdkAvailable;
|
|
4126
|
+
exports.logoImgStyle = logoImgStyle;
|
|
4127
|
+
exports.logoStyleTokens = logoStyleTokens;
|
|
4128
|
+
exports.mergeResults = mergeResults;
|
|
3616
4129
|
exports.mountTheme = mountTheme;
|
|
3617
4130
|
exports.pickTranslations = pickTranslations;
|
|
3618
4131
|
exports.registerReactSingleton = registerReactSingleton;
|
|
@@ -3664,5 +4177,9 @@ exports.useThemeSettings = useThemeSettings;
|
|
|
3664
4177
|
exports.useTranslation = useTranslation;
|
|
3665
4178
|
exports.useVariantSelection = useVariantSelection;
|
|
3666
4179
|
exports.useWishlist = useWishlist;
|
|
4180
|
+
exports.validateBuiltManifest = validateBuiltManifest;
|
|
4181
|
+
exports.validateManifest = validateManifest;
|
|
4182
|
+
exports.validateSectionSchema = validateSectionSchema;
|
|
4183
|
+
exports.validateSettingsAgainstSchema = validateSettingsAgainstSchema;
|
|
3667
4184
|
//# sourceMappingURL=index.cjs.map
|
|
3668
4185
|
//# sourceMappingURL=index.cjs.map
|