@shop-on/theme-contract 0.0.0-stage → 0.1.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/LICENSE.md +39 -0
- package/dist/block-path.d.ts +32 -0
- package/dist/block-path.js +52 -0
- package/dist/color-palette.d.ts +48 -0
- package/dist/color-palette.js +143 -0
- package/dist/document.d.ts +115 -0
- package/dist/document.js +297 -0
- package/dist/editor-keys.d.ts +35 -0
- package/dist/editor-keys.js +80 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +11 -0
- package/dist/metafield-binding.d.ts +134 -0
- package/dist/metafield-binding.js +587 -0
- package/dist/metaobject-gid.d.ts +10 -0
- package/dist/metaobject-gid.js +16 -0
- package/dist/node-id.d.ts +9 -0
- package/dist/node-id.js +27 -0
- package/dist/preset-listing.d.ts +22 -0
- package/dist/preset-listing.js +42 -0
- package/dist/resolvers.d.ts +72 -0
- package/dist/resolvers.js +133 -0
- package/dist/richtext.d.ts +4 -0
- package/dist/richtext.js +30 -0
- package/dist/schemas.d.ts +482 -0
- package/dist/schemas.js +154 -0
- package/package.json +23 -3
- package/README.md +0 -3
package/dist/LICENSE.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Cody Theme Development License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Cody LLC. All rights reserved except as granted below.
|
|
4
|
+
|
|
5
|
+
"The Software" is this package, its source, and its documentation. "The
|
|
6
|
+
Platform" is Cody, the commerce platform operated by Cody LLC.
|
|
7
|
+
|
|
8
|
+
## 1. Grant
|
|
9
|
+
|
|
10
|
+
You may use, copy and modify the Software, and distribute modified copies, solely
|
|
11
|
+
to develop, test, and distribute themes, apps and other extensions that run on
|
|
12
|
+
the Platform.
|
|
13
|
+
|
|
14
|
+
## 2. Restrictions
|
|
15
|
+
|
|
16
|
+
You may not:
|
|
17
|
+
|
|
18
|
+
1. use the Software, or anything derived from it, with any commerce platform,
|
|
19
|
+
storefront or hosting service other than the Platform;
|
|
20
|
+
2. use the Software to build a product that competes with the Platform;
|
|
21
|
+
3. sublicense the Software, or distribute it other than as part of a theme,
|
|
22
|
+
app or extension for the Platform;
|
|
23
|
+
4. remove or alter this license or any copyright notice in the Software.
|
|
24
|
+
|
|
25
|
+
## 3. Your work
|
|
26
|
+
|
|
27
|
+
Themes, apps and extensions you build with the Software are yours. The parts of
|
|
28
|
+
the Software they include stay under this license.
|
|
29
|
+
|
|
30
|
+
## 4. Termination
|
|
31
|
+
|
|
32
|
+
This license ends automatically if you break any of its terms. You must then
|
|
33
|
+
stop using the Software and delete your copies of it.
|
|
34
|
+
|
|
35
|
+
## 5. No warranty
|
|
36
|
+
|
|
37
|
+
The Software is provided "as is", without warranty of any kind. Cody LLC is not
|
|
38
|
+
liable for any claim, damages or other liability arising from the Software or
|
|
39
|
+
its use.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
//#region src/block-path.d.ts
|
|
2
|
+
export declare const BLOCK_PATH_SEPARATOR = ".";
|
|
3
|
+
export declare function joinBlockPath(path: readonly string[]): string;
|
|
4
|
+
export declare function splitBlockPath(value: string | null | undefined): string[];
|
|
5
|
+
export declare function blockPathsEqual(a: readonly string[] | undefined, b: readonly string[] | undefined): boolean;
|
|
6
|
+
/** True when `prefix` names `path` itself or one of its ancestors. */
|
|
7
|
+
export declare function isBlockPathPrefix(prefix: readonly string[], path: readonly string[]): boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Coerce an untrusted wire value into a block path. Accepts the modern
|
|
10
|
+
* `string[]` and dotted-`string` forms, plus the legacy single
|
|
11
|
+
* `parentBlockId` (normalized to a one-segment path) that older bundled
|
|
12
|
+
* theme-react bridges still emit. Anything else yields `[]`.
|
|
13
|
+
*/
|
|
14
|
+
export declare function normalizeBlockPath(value: unknown, legacyParentBlockId?: unknown): string[];
|
|
15
|
+
/** The block type a container's `blocks` map holds — recovered from the
|
|
16
|
+
* section/block type the caller passed, so the resolved container keeps its
|
|
17
|
+
* real type (`type`, `settings`, `custom_css`, …) instead of a structural
|
|
18
|
+
* stand-in. */
|
|
19
|
+
type BlocksOf<S> = S extends {
|
|
20
|
+
blocks?: Record<string, infer B> | undefined;
|
|
21
|
+
} ? B : never;
|
|
22
|
+
/**
|
|
23
|
+
* Walk `path` hop by hop from the section and return the container it names —
|
|
24
|
+
* the section itself for an empty path, otherwise the block at the end of the
|
|
25
|
+
* chain. Returns `undefined` the instant a hop is missing, so callers can fail
|
|
26
|
+
* loudly (`container_not_found`) instead of silently writing nowhere.
|
|
27
|
+
*/
|
|
28
|
+
export declare function resolveContainerAtPath<S extends {
|
|
29
|
+
blocks?: Record<string, unknown>;
|
|
30
|
+
}>(section: S | undefined, path: readonly string[]): S | BlocksOf<S> | undefined;
|
|
31
|
+
//#endregion
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
//#region src/block-path.ts
|
|
2
|
+
const BLOCK_PATH_SEPARATOR = ".";
|
|
3
|
+
function joinBlockPath(path) {
|
|
4
|
+
return path.join(".");
|
|
5
|
+
}
|
|
6
|
+
function splitBlockPath(value) {
|
|
7
|
+
if (!value) return [];
|
|
8
|
+
return value.split(".").filter((seg) => seg !== "");
|
|
9
|
+
}
|
|
10
|
+
function blockPathsEqual(a, b) {
|
|
11
|
+
const left = a ?? [];
|
|
12
|
+
const right = b ?? [];
|
|
13
|
+
if (left.length !== right.length) return false;
|
|
14
|
+
for (let i = 0; i < left.length; i++) if (left[i] !== right[i]) return false;
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
/** True when `prefix` names `path` itself or one of its ancestors. */
|
|
18
|
+
function isBlockPathPrefix(prefix, path) {
|
|
19
|
+
if (prefix.length > path.length) return false;
|
|
20
|
+
for (let i = 0; i < prefix.length; i++) if (prefix[i] !== path[i]) return false;
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Coerce an untrusted wire value into a block path. Accepts the modern
|
|
25
|
+
* `string[]` and dotted-`string` forms, plus the legacy single
|
|
26
|
+
* `parentBlockId` (normalized to a one-segment path) that older bundled
|
|
27
|
+
* theme-react bridges still emit. Anything else yields `[]`.
|
|
28
|
+
*/
|
|
29
|
+
function normalizeBlockPath(value, legacyParentBlockId) {
|
|
30
|
+
if (Array.isArray(value)) return value.filter((seg) => typeof seg === "string" && seg !== "");
|
|
31
|
+
if (typeof value === "string") return splitBlockPath(value);
|
|
32
|
+
if (typeof legacyParentBlockId === "string" && legacyParentBlockId !== "") return [legacyParentBlockId];
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Walk `path` hop by hop from the section and return the container it names —
|
|
37
|
+
* the section itself for an empty path, otherwise the block at the end of the
|
|
38
|
+
* chain. Returns `undefined` the instant a hop is missing, so callers can fail
|
|
39
|
+
* loudly (`container_not_found`) instead of silently writing nowhere.
|
|
40
|
+
*/
|
|
41
|
+
function resolveContainerAtPath(section, path) {
|
|
42
|
+
if (!section) return void 0;
|
|
43
|
+
if (path.length === 0) return section;
|
|
44
|
+
let node = section.blocks?.[path[0]];
|
|
45
|
+
for (let i = 1; i < path.length; i++) {
|
|
46
|
+
if (!node) return void 0;
|
|
47
|
+
node = node.blocks?.[path[i]];
|
|
48
|
+
}
|
|
49
|
+
return node;
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
52
|
+
export { BLOCK_PATH_SEPARATOR, blockPathsEqual, isBlockPathPrefix, joinBlockPath, normalizeBlockPath, resolveContainerAtPath, splitBlockPath };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
//#region src/color-palette.d.ts
|
|
2
|
+
export declare const PALETTE_GROUP_TYPE = "color_palette_group";
|
|
3
|
+
export declare const PALETTE_PREFIX = "color_palette.";
|
|
4
|
+
export declare const PALETTE_REF_PREFIX = "palette:";
|
|
5
|
+
/** Shopify's bounds: a palette holds at least 2 and at most 20 colors. */
|
|
6
|
+
export declare const MIN_PALETTE_COLORS = 2;
|
|
7
|
+
export declare const MAX_PALETTE_COLORS = 20;
|
|
8
|
+
/** Substituted when a `palette:` ref points at a color that no longer exists
|
|
9
|
+
* (hand-edited JSON, a half-applied migration). Mid-gray keeps the surface
|
|
10
|
+
* legible; leaving the raw ref in place would emit invalid CSS and blank the
|
|
11
|
+
* declaration unpredictably. */
|
|
12
|
+
export declare const PALETTE_FALLBACK_COLOR = "#808080";
|
|
13
|
+
export interface PaletteColor {
|
|
14
|
+
id: string;
|
|
15
|
+
label: string;
|
|
16
|
+
value: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function paletteKey(id: string, field: "label" | "value"): string;
|
|
19
|
+
export declare function paletteRef(id: string): string;
|
|
20
|
+
/** `"palette:brand"` → `"brand"`. Anything else (including a hex literal, a
|
|
21
|
+
* non-string, or a ref with an unsafe id) → `null`. */
|
|
22
|
+
export declare function parsePaletteRef(value: unknown): string | null;
|
|
23
|
+
export declare function comparePaletteIds(a: string, b: string): number;
|
|
24
|
+
/** Every palette color defined in a flat theme-settings map, ordered
|
|
25
|
+
* `palette_1`, `palette_2`, … then any non-numeric ids alphabetically. */
|
|
26
|
+
export declare function parsePalette(settings: Record<string, unknown>): PaletteColor[];
|
|
27
|
+
/** Palette id → literal color, the lookup table every resolver takes. */
|
|
28
|
+
export declare function paletteValues(settings: Record<string, unknown>): Record<string, string>;
|
|
29
|
+
/** A single value: `palette:<id>` → its literal (or the neutral fallback);
|
|
30
|
+
* everything else passes through untouched. */
|
|
31
|
+
export declare function resolvePaletteValue(value: unknown, palette: Record<string, string>): unknown;
|
|
32
|
+
/**
|
|
33
|
+
* Replace every `palette:<id>` ref inside a template / section-group document
|
|
34
|
+
* (section settings, block settings, nested block settings) with its literal
|
|
35
|
+
* color. Structurally shared: untouched branches keep their identity, and a
|
|
36
|
+
* document with no refs is returned as-is.
|
|
37
|
+
*/
|
|
38
|
+
export declare function resolvePaletteRefs<T>(document: T, palette: Record<string, string>): T;
|
|
39
|
+
/** Cheap pre-check so callers can skip loading the palette (and, in the loader,
|
|
40
|
+
* an extra settings fetch) for the overwhelmingly common ref-free document. */
|
|
41
|
+
export declare function hasPaletteRefs(node: unknown): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* The flat theme-settings map resolves against ITSELF — palette definitions and
|
|
44
|
+
* the settings that reference them live in the same document. `color_palette.*`
|
|
45
|
+
* keys are skipped so a definition can never chain into another definition.
|
|
46
|
+
*/
|
|
47
|
+
export declare function resolveThemeSettingsPalette(settings: Record<string, unknown>): Record<string, unknown>;
|
|
48
|
+
//#endregion
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
//#region src/color-palette.ts
|
|
2
|
+
const PALETTE_GROUP_TYPE = "color_palette_group";
|
|
3
|
+
const PALETTE_PREFIX = "color_palette.";
|
|
4
|
+
const PALETTE_REF_PREFIX = "palette:";
|
|
5
|
+
/** Shopify's bounds: a palette holds at least 2 and at most 20 colors. */
|
|
6
|
+
const MIN_PALETTE_COLORS = 2;
|
|
7
|
+
const MAX_PALETTE_COLORS = 20;
|
|
8
|
+
/** Substituted when a `palette:` ref points at a color that no longer exists
|
|
9
|
+
* (hand-edited JSON, a half-applied migration). Mid-gray keeps the surface
|
|
10
|
+
* legible; leaving the raw ref in place would emit invalid CSS and blank the
|
|
11
|
+
* declaration unpredictably. */
|
|
12
|
+
const PALETTE_FALLBACK_COLOR = "#808080";
|
|
13
|
+
const PALETTE_ID_RE = /^[a-zA-Z0-9_-]+$/;
|
|
14
|
+
const NUMERIC_SUFFIX_RE = /^palette_(\d+)$/;
|
|
15
|
+
function paletteKey(id, field) {
|
|
16
|
+
return `${PALETTE_PREFIX}${id}.${field}`;
|
|
17
|
+
}
|
|
18
|
+
function paletteRef(id) {
|
|
19
|
+
return `${PALETTE_REF_PREFIX}${id}`;
|
|
20
|
+
}
|
|
21
|
+
/** `"palette:brand"` → `"brand"`. Anything else (including a hex literal, a
|
|
22
|
+
* non-string, or a ref with an unsafe id) → `null`. */
|
|
23
|
+
function parsePaletteRef(value) {
|
|
24
|
+
if (typeof value !== "string" || !value.startsWith("palette:")) return null;
|
|
25
|
+
const id = value.slice(8);
|
|
26
|
+
return PALETTE_ID_RE.test(id) ? id : null;
|
|
27
|
+
}
|
|
28
|
+
function comparePaletteIds(a, b) {
|
|
29
|
+
const ma = a.match(NUMERIC_SUFFIX_RE);
|
|
30
|
+
const mb = b.match(NUMERIC_SUFFIX_RE);
|
|
31
|
+
if (ma && mb) return Number.parseInt(ma[1], 10) - Number.parseInt(mb[1], 10);
|
|
32
|
+
if (ma) return -1;
|
|
33
|
+
if (mb) return 1;
|
|
34
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
35
|
+
}
|
|
36
|
+
/** Every palette color defined in a flat theme-settings map, ordered
|
|
37
|
+
* `palette_1`, `palette_2`, … then any non-numeric ids alphabetically. */
|
|
38
|
+
function parsePalette(settings) {
|
|
39
|
+
const byId = {};
|
|
40
|
+
for (const [key, raw] of Object.entries(settings)) {
|
|
41
|
+
if (!key.startsWith("color_palette.") || typeof raw !== "string") continue;
|
|
42
|
+
const rest = key.slice(14);
|
|
43
|
+
const dot = rest.indexOf(".");
|
|
44
|
+
if (dot === -1) continue;
|
|
45
|
+
const id = rest.slice(0, dot);
|
|
46
|
+
const field = rest.slice(dot + 1);
|
|
47
|
+
if (!PALETTE_ID_RE.test(id)) continue;
|
|
48
|
+
if (field !== "label" && field !== "value") continue;
|
|
49
|
+
(byId[id] ??= {})[field] = raw;
|
|
50
|
+
}
|
|
51
|
+
return Object.entries(byId).filter(([, parts]) => typeof parts.value === "string").map(([id, parts]) => ({
|
|
52
|
+
id,
|
|
53
|
+
label: parts.label || id,
|
|
54
|
+
value: parts.value
|
|
55
|
+
})).sort((a, b) => comparePaletteIds(a.id, b.id));
|
|
56
|
+
}
|
|
57
|
+
/** Palette id → literal color, the lookup table every resolver takes. */
|
|
58
|
+
function paletteValues(settings) {
|
|
59
|
+
const out = {};
|
|
60
|
+
for (const color of parsePalette(settings)) out[color.id] = color.value;
|
|
61
|
+
return out;
|
|
62
|
+
}
|
|
63
|
+
/** A single value: `palette:<id>` → its literal (or the neutral fallback);
|
|
64
|
+
* everything else passes through untouched. */
|
|
65
|
+
function resolvePaletteValue(value, palette) {
|
|
66
|
+
const id = parsePaletteRef(value);
|
|
67
|
+
if (id === null) return value;
|
|
68
|
+
return palette[id] ?? "#808080";
|
|
69
|
+
}
|
|
70
|
+
function isPlainObject(v) {
|
|
71
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
72
|
+
}
|
|
73
|
+
function resolveSettingsMap(settings, palette) {
|
|
74
|
+
let changed = false;
|
|
75
|
+
const out = {};
|
|
76
|
+
for (const [key, value] of Object.entries(settings)) {
|
|
77
|
+
const next = resolvePaletteValue(value, palette);
|
|
78
|
+
if (next !== value) changed = true;
|
|
79
|
+
out[key] = next;
|
|
80
|
+
}
|
|
81
|
+
return changed ? out : settings;
|
|
82
|
+
}
|
|
83
|
+
function resolveNode(node, palette) {
|
|
84
|
+
if (Array.isArray(node)) {
|
|
85
|
+
let changed = false;
|
|
86
|
+
const out = node.map((item) => {
|
|
87
|
+
const next = resolveNode(item, palette);
|
|
88
|
+
if (next !== item) changed = true;
|
|
89
|
+
return next;
|
|
90
|
+
});
|
|
91
|
+
return changed ? out : node;
|
|
92
|
+
}
|
|
93
|
+
if (!isPlainObject(node)) return node;
|
|
94
|
+
let changed = false;
|
|
95
|
+
const out = {};
|
|
96
|
+
for (const [key, value] of Object.entries(node)) {
|
|
97
|
+
const next = key === "settings" && isPlainObject(value) ? resolveSettingsMap(value, palette) : resolveNode(value, palette);
|
|
98
|
+
if (next !== value) changed = true;
|
|
99
|
+
out[key] = next;
|
|
100
|
+
}
|
|
101
|
+
return changed ? out : node;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Replace every `palette:<id>` ref inside a template / section-group document
|
|
105
|
+
* (section settings, block settings, nested block settings) with its literal
|
|
106
|
+
* color. Structurally shared: untouched branches keep their identity, and a
|
|
107
|
+
* document with no refs is returned as-is.
|
|
108
|
+
*/
|
|
109
|
+
function resolvePaletteRefs(document, palette) {
|
|
110
|
+
return resolveNode(document, palette);
|
|
111
|
+
}
|
|
112
|
+
/** Cheap pre-check so callers can skip loading the palette (and, in the loader,
|
|
113
|
+
* an extra settings fetch) for the overwhelmingly common ref-free document. */
|
|
114
|
+
function hasPaletteRefs(node) {
|
|
115
|
+
if (Array.isArray(node)) return node.some((item) => hasPaletteRefs(item));
|
|
116
|
+
if (!isPlainObject(node)) return false;
|
|
117
|
+
for (const [key, value] of Object.entries(node)) {
|
|
118
|
+
if (key === "settings" && isPlainObject(value)) {
|
|
119
|
+
for (const inner of Object.values(value)) if (parsePaletteRef(inner) !== null) return true;
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (hasPaletteRefs(value)) return true;
|
|
123
|
+
}
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* The flat theme-settings map resolves against ITSELF — palette definitions and
|
|
128
|
+
* the settings that reference them live in the same document. `color_palette.*`
|
|
129
|
+
* keys are skipped so a definition can never chain into another definition.
|
|
130
|
+
*/
|
|
131
|
+
function resolveThemeSettingsPalette(settings) {
|
|
132
|
+
const palette = paletteValues(settings);
|
|
133
|
+
let changed = false;
|
|
134
|
+
const out = {};
|
|
135
|
+
for (const [key, value] of Object.entries(settings)) {
|
|
136
|
+
const next = key.startsWith("color_palette.") ? value : resolvePaletteValue(value, palette);
|
|
137
|
+
if (next !== value) changed = true;
|
|
138
|
+
out[key] = next;
|
|
139
|
+
}
|
|
140
|
+
return changed ? out : settings;
|
|
141
|
+
}
|
|
142
|
+
//#endregion
|
|
143
|
+
export { MAX_PALETTE_COLORS, MIN_PALETTE_COLORS, PALETTE_FALLBACK_COLOR, PALETTE_GROUP_TYPE, PALETTE_PREFIX, PALETTE_REF_PREFIX, comparePaletteIds, hasPaletteRefs, paletteKey, paletteRef, paletteValues, parsePalette, parsePaletteRef, resolvePaletteRefs, resolvePaletteValue, resolveThemeSettingsPalette };
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { BlockDefinition, SchemaSetting, TemplateBlock, TemplateSection } from "./schemas.js";
|
|
2
|
+
//#region src/document.d.ts
|
|
3
|
+
export interface SelectedSection {
|
|
4
|
+
instanceId: string;
|
|
5
|
+
section: TemplateSection;
|
|
6
|
+
blocks: TemplateBlock[];
|
|
7
|
+
staticBlocks: Record<string, TemplateBlock>;
|
|
8
|
+
}
|
|
9
|
+
export interface TemplateShape {
|
|
10
|
+
layout?: string;
|
|
11
|
+
sections: Record<string, TemplateSection>;
|
|
12
|
+
order: string[];
|
|
13
|
+
section_groups?: Record<string, {
|
|
14
|
+
sections: Record<string, TemplateSection>;
|
|
15
|
+
order: string[];
|
|
16
|
+
}>;
|
|
17
|
+
}
|
|
18
|
+
export interface CollectedTypes {
|
|
19
|
+
sections: Set<string>;
|
|
20
|
+
blocks: Set<string>;
|
|
21
|
+
layouts: Set<string>;
|
|
22
|
+
}
|
|
23
|
+
export declare function defaultSettings(schemaDefs?: SchemaSetting[]): Record<string, unknown>;
|
|
24
|
+
export declare function staticChildId(childType: string, parentType: string): string;
|
|
25
|
+
export declare function staticBlockId(type: string): string;
|
|
26
|
+
export declare function buildStaticChildren(args: {
|
|
27
|
+
parentType: string;
|
|
28
|
+
childDefs: BlockDefinition[];
|
|
29
|
+
getBlockSchema: (type: string) => {
|
|
30
|
+
settings?: SchemaSetting[];
|
|
31
|
+
blocks?: BlockDefinition[];
|
|
32
|
+
} | undefined;
|
|
33
|
+
}): {
|
|
34
|
+
blocks: Record<string, TemplateBlock>;
|
|
35
|
+
block_order: string[];
|
|
36
|
+
};
|
|
37
|
+
type BlockSchemaLike = {
|
|
38
|
+
settings?: SchemaSetting[];
|
|
39
|
+
blocks?: BlockDefinition[];
|
|
40
|
+
} | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* Build a fresh block instance the way a merchant adding it should get it:
|
|
43
|
+
* schema defaults → its schema's static children → its first preset overlaid.
|
|
44
|
+
* The preset is Horizon's block `presets[0]` — the one Shopify applies when a
|
|
45
|
+
* block is added — so a container arrives with the content it ships with (an
|
|
46
|
+
* accordion with its rows, a recommendations block with its heading and card
|
|
47
|
+
* fields) rather than as an empty frame. Same inputs contract as
|
|
48
|
+
* `buildSectionInstance`: schemas already t:-resolved, `idFor` injected.
|
|
49
|
+
*/
|
|
50
|
+
export declare function buildBlockInstance(args: {
|
|
51
|
+
type: string;
|
|
52
|
+
getBlockSchema: (type: string) => BlockSchemaLike;
|
|
53
|
+
preset?: {
|
|
54
|
+
settings?: Record<string, unknown>;
|
|
55
|
+
blocks?: BlockDefinition[];
|
|
56
|
+
};
|
|
57
|
+
idFor: (type: string) => string;
|
|
58
|
+
}): TemplateBlock;
|
|
59
|
+
/**
|
|
60
|
+
* Build a fresh section instance from its schema: schema/preset defaults →
|
|
61
|
+
* seeded static blocks → preset overlay. Shared by the admin editor's
|
|
62
|
+
* `addSection` and the storefront's standalone section-preview route so both
|
|
63
|
+
* produce identical instances.
|
|
64
|
+
*
|
|
65
|
+
* Inputs must be **already t:-resolved** — the admin gets resolved schemas from
|
|
66
|
+
* the orchestrator's editor-loader; the storefront resolves on-disk before
|
|
67
|
+
* calling. `idFor` is injected (admin mints a random suffix; the preview route
|
|
68
|
+
* uses a deterministic counter) so callers control id stability.
|
|
69
|
+
*/
|
|
70
|
+
export declare function buildSectionInstance(args: {
|
|
71
|
+
type: string;
|
|
72
|
+
sectionSchema: {
|
|
73
|
+
settings?: SchemaSetting[];
|
|
74
|
+
blocks?: BlockDefinition[];
|
|
75
|
+
} | undefined;
|
|
76
|
+
getBlockSchema: (type: string) => BlockSchemaLike;
|
|
77
|
+
preset?: {
|
|
78
|
+
settings?: Record<string, unknown>;
|
|
79
|
+
blocks?: BlockDefinition[];
|
|
80
|
+
};
|
|
81
|
+
idFor: (type: string) => string;
|
|
82
|
+
}): TemplateSection & {
|
|
83
|
+
blocks: Record<string, TemplateBlock>;
|
|
84
|
+
block_order: string[];
|
|
85
|
+
};
|
|
86
|
+
export declare function selectRenderableSections(sections: Record<string, TemplateSection>, order: string[]): SelectedSection[];
|
|
87
|
+
export declare function selectRenderableChildren(block: TemplateBlock): TemplateBlock[];
|
|
88
|
+
export declare function collectTypes(template: TemplateShape): CollectedTypes;
|
|
89
|
+
type BlockNode = {
|
|
90
|
+
static?: boolean;
|
|
91
|
+
blocks?: Record<string, BlockNode>;
|
|
92
|
+
block_order?: string[];
|
|
93
|
+
} & Record<string, unknown>;
|
|
94
|
+
type BlockContainer = {
|
|
95
|
+
blocks?: Record<string, BlockNode>;
|
|
96
|
+
block_order?: string[];
|
|
97
|
+
} & Record<string, unknown>;
|
|
98
|
+
export declare function stripStaticFromBlockOrder(container: BlockContainer): number;
|
|
99
|
+
export type SeedMissingStaticsReport = {
|
|
100
|
+
added: Array<{
|
|
101
|
+
sectionId: string;
|
|
102
|
+
blockPath: string;
|
|
103
|
+
}>;
|
|
104
|
+
reordered: Array<{
|
|
105
|
+
sectionId: string;
|
|
106
|
+
containerPath: string;
|
|
107
|
+
}>;
|
|
108
|
+
};
|
|
109
|
+
export declare function seedMissingStatics(oldTemplate: {
|
|
110
|
+
sections: Record<string, TemplateSection>;
|
|
111
|
+
}, freshTemplate: {
|
|
112
|
+
sections: Record<string, TemplateSection>;
|
|
113
|
+
}): SeedMissingStaticsReport;
|
|
114
|
+
//#endregion
|
|
115
|
+
export {};
|