@numueg/theme-sdk 0.1.2 → 0.2.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-CGx6FNqb.d.ts → entities-iiuRSPpk.d.mts} +1 -3
- package/dist/{index-zSb0FIyh.d.mts → entities-iiuRSPpk.d.ts} +1 -3
- package/dist/index.cjs +763 -43
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +493 -38
- package/dist/index.d.ts +493 -38
- package/dist/index.mjs +747 -45
- package/dist/index.mjs.map +1 -1
- package/dist/normalize.d.mts +1 -1
- package/dist/normalize.d.ts +1 -1
- package/dist/theme-D0QybTQS.d.mts +197 -0
- package/dist/theme-D0QybTQS.d.ts +197 -0
- package/dist/types.d.mts +2 -2
- package/dist/types.d.ts +2 -2
- package/dist/v2-compat.cjs +248 -0
- package/dist/v2-compat.cjs.map +1 -0
- package/dist/v2-compat.d.mts +129 -0
- package/dist/v2-compat.d.ts +129 -0
- package/dist/v2-compat.mjs +242 -0
- package/dist/v2-compat.mjs.map +1 -0
- package/package.json +12 -1
- package/dist/theme-NWJAU9jd.d.mts +0 -128
- package/dist/theme-NWJAU9jd.d.ts +0 -128
package/dist/normalize.d.mts
CHANGED
package/dist/normalize.d.ts
CHANGED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/** V3 Theme Settings — the canonical data shape */
|
|
2
|
+
interface ThemeSettingsV3 {
|
|
3
|
+
schema_version: 3;
|
|
4
|
+
theme_id: string;
|
|
5
|
+
global_settings: Record<string, any>;
|
|
6
|
+
templates: Record<string, PageTemplate>;
|
|
7
|
+
section_groups: Record<string, SectionGroup>;
|
|
8
|
+
external_theme?: ExternalThemeMetadata | null;
|
|
9
|
+
}
|
|
10
|
+
interface PageTemplate {
|
|
11
|
+
name: string;
|
|
12
|
+
sections: Record<string, SectionInstance>;
|
|
13
|
+
order: string[];
|
|
14
|
+
}
|
|
15
|
+
interface SectionGroup {
|
|
16
|
+
name: string;
|
|
17
|
+
sections: Record<string, SectionInstance>;
|
|
18
|
+
order: string[];
|
|
19
|
+
}
|
|
20
|
+
interface SectionInstance {
|
|
21
|
+
type: string;
|
|
22
|
+
settings: Record<string, any>;
|
|
23
|
+
disabled?: boolean;
|
|
24
|
+
blocks?: Record<string, BlockInstance>;
|
|
25
|
+
block_order?: string[];
|
|
26
|
+
}
|
|
27
|
+
interface BlockInstance {
|
|
28
|
+
type: string;
|
|
29
|
+
settings: Record<string, any>;
|
|
30
|
+
disabled?: boolean;
|
|
31
|
+
/** Nested child blocks (blocks-in-blocks): a block can hold its own
|
|
32
|
+
* block container — e.g. a footer "column" holding "link" blocks, or
|
|
33
|
+
* a mega-menu. Same shape as a section's block container, so the
|
|
34
|
+
* render/editor walk is uniform at any depth. Optional + absent on
|
|
35
|
+
* leaf blocks, so pre-nesting payloads load unchanged. */
|
|
36
|
+
blocks?: Record<string, BlockInstance>;
|
|
37
|
+
block_order?: string[];
|
|
38
|
+
}
|
|
39
|
+
interface ExternalThemeMetadata {
|
|
40
|
+
bundle_url: string;
|
|
41
|
+
css_url?: string | null;
|
|
42
|
+
mode?: string;
|
|
43
|
+
settings_schema?: Record<string, any> | null;
|
|
44
|
+
section_schemas?: Record<string, any> | null;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Live mount handle returned by a V3 theme bundle's `mount(el, ctx)`.
|
|
48
|
+
*
|
|
49
|
+
* Two shapes accepted by the host:
|
|
50
|
+
*
|
|
51
|
+
* 1. **Legacy** — `mount(el, ctx): () => void`
|
|
52
|
+
* The bundle returns only a cleanup function. Every host-side
|
|
53
|
+
* themeSettings change forces a full unmount + remount, which is
|
|
54
|
+
* expensive but always correct. Hosts must keep supporting this
|
|
55
|
+
* for older bundles built against pre-0.2 SDK versions.
|
|
56
|
+
*
|
|
57
|
+
* 2. **Wave 3+** — `mount(el, ctx): MountResult`
|
|
58
|
+
* The bundle returns an object with `cleanup` + an `applyDraft`
|
|
59
|
+
* method that takes a fresh `ThemeSettingsV3` and re-renders the
|
|
60
|
+
* bundle's React tree in-place (no createRoot churn). This is the
|
|
61
|
+
* fast path used by the customizer's live preview — a keystroke
|
|
62
|
+
* in the dashboard becomes a single React reconciliation in the
|
|
63
|
+
* iframe, typically < 16 ms.
|
|
64
|
+
*
|
|
65
|
+
* Hosts feature-detect by checking `typeof handle === "function"`
|
|
66
|
+
* (legacy) vs `typeof handle === "object" && handle.cleanup`
|
|
67
|
+
* (Wave 3+). Theme authors should prefer the MountResult shape — the
|
|
68
|
+
* `numuTheme` plugin's typings will flag the missing applyDraft once
|
|
69
|
+
* the editor's live-preview path requires it.
|
|
70
|
+
*/
|
|
71
|
+
interface MountResult {
|
|
72
|
+
/** Unmount the bundle's React tree and release any resources. */
|
|
73
|
+
cleanup: () => void;
|
|
74
|
+
/**
|
|
75
|
+
* Apply a fresh draft (e.g. from the customizer iframe's
|
|
76
|
+
* `numu:theme:update` postMessage) without tearing down the tree.
|
|
77
|
+
* Implementations typically forward the value to a useState setter
|
|
78
|
+
* inside a wrapper that renders `<NuMuProvider themeSettings={...}>`.
|
|
79
|
+
*
|
|
80
|
+
* Safe to call repeatedly; the bundle is expected to dedup
|
|
81
|
+
* reference-equal calls on its own. Returns nothing — selection /
|
|
82
|
+
* navigation echo back via postMessage.
|
|
83
|
+
*/
|
|
84
|
+
applyDraft: (next: ThemeSettingsV3) => void;
|
|
85
|
+
}
|
|
86
|
+
/** Section schema for customizer form generation */
|
|
87
|
+
interface SectionSchema {
|
|
88
|
+
type: string;
|
|
89
|
+
name: string;
|
|
90
|
+
name_ar?: string;
|
|
91
|
+
tag?: string;
|
|
92
|
+
class?: string;
|
|
93
|
+
limit?: number;
|
|
94
|
+
settings: SettingDefinition[];
|
|
95
|
+
blocks?: BlockSchema[];
|
|
96
|
+
max_blocks?: number;
|
|
97
|
+
presets?: SectionPreset[];
|
|
98
|
+
}
|
|
99
|
+
interface BlockSchema {
|
|
100
|
+
type: string;
|
|
101
|
+
name: string;
|
|
102
|
+
name_ar?: string;
|
|
103
|
+
limit?: number;
|
|
104
|
+
settings: SettingDefinition[];
|
|
105
|
+
/** Child block types this block accepts (recursive). When present,
|
|
106
|
+
* the customizer lets merchants add/remove/reorder these inside the
|
|
107
|
+
* block, up to `max_blocks`. Enables footer columns, mega-menus,
|
|
108
|
+
* multi-column layouts. The host caps practical nesting depth
|
|
109
|
+
* (MAX_BLOCK_DEPTH). */
|
|
110
|
+
blocks?: BlockSchema[];
|
|
111
|
+
max_blocks?: number;
|
|
112
|
+
}
|
|
113
|
+
/** Max nesting depth the customizer allows for blocks-in-blocks. Depth
|
|
114
|
+
* 1 = a top-level block in a section; a block at this depth can't take
|
|
115
|
+
* children. Generous (below Shopify's 8) and cheap to raise. Kept in
|
|
116
|
+
* sync with the merchant hub's MAX_BLOCK_DEPTH. */
|
|
117
|
+
declare const MAX_BLOCK_DEPTH = 5;
|
|
118
|
+
/**
|
|
119
|
+
* Setting types the V3 customizer renders. Themes can declare any
|
|
120
|
+
* string here; unknown types fall through to a plain text input. The
|
|
121
|
+
* union below documents the canonical set so theme authors get
|
|
122
|
+
* autocomplete and TypeScript errors on typos.
|
|
123
|
+
*/
|
|
124
|
+
type SettingType = "text" | "textarea" | "richtext" | "number" | "range" | "color" | "checkbox" | "select" | "radio" | "font" | "image_picker" | "url" | "product" | "product_list" | "collection" | "collection_list" | "header" | "paragraph" | "html" | "date" | "time" | "video_picker" | "color_scheme" | "page_picker" | "blog_picker" | "link_list_picker" | "variant_picker" | "file_upload" | "icon_picker" | "icon";
|
|
125
|
+
/**
|
|
126
|
+
* `visible_if` — conditional visibility expression evaluated against
|
|
127
|
+
* sibling settings in the same schema. Two flavors:
|
|
128
|
+
*
|
|
129
|
+
* - String DSL: `"settings.show_button == true && settings.layout != 'minimal'"`
|
|
130
|
+
* - Object form: `{ show_button: true, layout: ["full", "split"] }`
|
|
131
|
+
*
|
|
132
|
+
* Evaluator lives in the merchant hub: any setting whose expression is
|
|
133
|
+
* falsy is skipped from the rendered form.
|
|
134
|
+
*/
|
|
135
|
+
type VisibleIf = string | Record<string, unknown>;
|
|
136
|
+
interface SettingDefinition {
|
|
137
|
+
type: SettingType | (string & {});
|
|
138
|
+
id: string;
|
|
139
|
+
label: string;
|
|
140
|
+
label_ar?: string;
|
|
141
|
+
default?: any;
|
|
142
|
+
info?: string;
|
|
143
|
+
info_ar?: string;
|
|
144
|
+
placeholder?: string;
|
|
145
|
+
options?: {
|
|
146
|
+
value: string;
|
|
147
|
+
label: string;
|
|
148
|
+
label_ar?: string;
|
|
149
|
+
}[];
|
|
150
|
+
min?: number;
|
|
151
|
+
max?: number;
|
|
152
|
+
step?: number;
|
|
153
|
+
unit?: string;
|
|
154
|
+
/** Hide this setting unless the expression evaluates truthy. */
|
|
155
|
+
visible_if?: VisibleIf;
|
|
156
|
+
}
|
|
157
|
+
interface PresetBlock {
|
|
158
|
+
type: string;
|
|
159
|
+
settings?: Record<string, any>;
|
|
160
|
+
/** Nested starter blocks materialized when the preset is applied
|
|
161
|
+
* (recursive). Lets a preset ship, e.g., a footer column already
|
|
162
|
+
* populated with link blocks. */
|
|
163
|
+
blocks?: PresetBlock[];
|
|
164
|
+
}
|
|
165
|
+
interface SectionPreset {
|
|
166
|
+
name: string;
|
|
167
|
+
/** Localized names so the Add Section dialog reads in the editor's
|
|
168
|
+
* current locale. Falls back to `name` when the locale is missing. */
|
|
169
|
+
locales?: {
|
|
170
|
+
en?: {
|
|
171
|
+
name?: string;
|
|
172
|
+
};
|
|
173
|
+
ar?: {
|
|
174
|
+
name?: string;
|
|
175
|
+
};
|
|
176
|
+
};
|
|
177
|
+
settings?: Record<string, any>;
|
|
178
|
+
blocks?: PresetBlock[];
|
|
179
|
+
}
|
|
180
|
+
/** Section component props */
|
|
181
|
+
interface SectionProps {
|
|
182
|
+
settings: Record<string, any>;
|
|
183
|
+
blocks?: Record<string, BlockInstance>;
|
|
184
|
+
blockOrder?: string[];
|
|
185
|
+
storeData?: any;
|
|
186
|
+
}
|
|
187
|
+
/** Block component props */
|
|
188
|
+
interface BlockProps {
|
|
189
|
+
settings: Record<string, any>;
|
|
190
|
+
/** Child block instances when this block nests others (footer column,
|
|
191
|
+
* mega-menu, …). Mirror the section→block render: map `blockOrder`
|
|
192
|
+
* and look each id up in `blocks`, wrapping each child in `<Block>`. */
|
|
193
|
+
blocks?: Record<string, BlockInstance>;
|
|
194
|
+
blockOrder?: string[];
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export { type BlockInstance as B, type ExternalThemeMetadata as E, type MountResult as M, type PageTemplate as P, type SectionGroup as S, type ThemeSettingsV3 as T, type BlockProps as a, type BlockSchema as b, type SectionInstance as c, type SectionPreset as d, type SectionProps as e, type SectionSchema as f, type SettingDefinition as g, MAX_BLOCK_DEPTH as h, type PresetBlock as i };
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/** V3 Theme Settings — the canonical data shape */
|
|
2
|
+
interface ThemeSettingsV3 {
|
|
3
|
+
schema_version: 3;
|
|
4
|
+
theme_id: string;
|
|
5
|
+
global_settings: Record<string, any>;
|
|
6
|
+
templates: Record<string, PageTemplate>;
|
|
7
|
+
section_groups: Record<string, SectionGroup>;
|
|
8
|
+
external_theme?: ExternalThemeMetadata | null;
|
|
9
|
+
}
|
|
10
|
+
interface PageTemplate {
|
|
11
|
+
name: string;
|
|
12
|
+
sections: Record<string, SectionInstance>;
|
|
13
|
+
order: string[];
|
|
14
|
+
}
|
|
15
|
+
interface SectionGroup {
|
|
16
|
+
name: string;
|
|
17
|
+
sections: Record<string, SectionInstance>;
|
|
18
|
+
order: string[];
|
|
19
|
+
}
|
|
20
|
+
interface SectionInstance {
|
|
21
|
+
type: string;
|
|
22
|
+
settings: Record<string, any>;
|
|
23
|
+
disabled?: boolean;
|
|
24
|
+
blocks?: Record<string, BlockInstance>;
|
|
25
|
+
block_order?: string[];
|
|
26
|
+
}
|
|
27
|
+
interface BlockInstance {
|
|
28
|
+
type: string;
|
|
29
|
+
settings: Record<string, any>;
|
|
30
|
+
disabled?: boolean;
|
|
31
|
+
/** Nested child blocks (blocks-in-blocks): a block can hold its own
|
|
32
|
+
* block container — e.g. a footer "column" holding "link" blocks, or
|
|
33
|
+
* a mega-menu. Same shape as a section's block container, so the
|
|
34
|
+
* render/editor walk is uniform at any depth. Optional + absent on
|
|
35
|
+
* leaf blocks, so pre-nesting payloads load unchanged. */
|
|
36
|
+
blocks?: Record<string, BlockInstance>;
|
|
37
|
+
block_order?: string[];
|
|
38
|
+
}
|
|
39
|
+
interface ExternalThemeMetadata {
|
|
40
|
+
bundle_url: string;
|
|
41
|
+
css_url?: string | null;
|
|
42
|
+
mode?: string;
|
|
43
|
+
settings_schema?: Record<string, any> | null;
|
|
44
|
+
section_schemas?: Record<string, any> | null;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Live mount handle returned by a V3 theme bundle's `mount(el, ctx)`.
|
|
48
|
+
*
|
|
49
|
+
* Two shapes accepted by the host:
|
|
50
|
+
*
|
|
51
|
+
* 1. **Legacy** — `mount(el, ctx): () => void`
|
|
52
|
+
* The bundle returns only a cleanup function. Every host-side
|
|
53
|
+
* themeSettings change forces a full unmount + remount, which is
|
|
54
|
+
* expensive but always correct. Hosts must keep supporting this
|
|
55
|
+
* for older bundles built against pre-0.2 SDK versions.
|
|
56
|
+
*
|
|
57
|
+
* 2. **Wave 3+** — `mount(el, ctx): MountResult`
|
|
58
|
+
* The bundle returns an object with `cleanup` + an `applyDraft`
|
|
59
|
+
* method that takes a fresh `ThemeSettingsV3` and re-renders the
|
|
60
|
+
* bundle's React tree in-place (no createRoot churn). This is the
|
|
61
|
+
* fast path used by the customizer's live preview — a keystroke
|
|
62
|
+
* in the dashboard becomes a single React reconciliation in the
|
|
63
|
+
* iframe, typically < 16 ms.
|
|
64
|
+
*
|
|
65
|
+
* Hosts feature-detect by checking `typeof handle === "function"`
|
|
66
|
+
* (legacy) vs `typeof handle === "object" && handle.cleanup`
|
|
67
|
+
* (Wave 3+). Theme authors should prefer the MountResult shape — the
|
|
68
|
+
* `numuTheme` plugin's typings will flag the missing applyDraft once
|
|
69
|
+
* the editor's live-preview path requires it.
|
|
70
|
+
*/
|
|
71
|
+
interface MountResult {
|
|
72
|
+
/** Unmount the bundle's React tree and release any resources. */
|
|
73
|
+
cleanup: () => void;
|
|
74
|
+
/**
|
|
75
|
+
* Apply a fresh draft (e.g. from the customizer iframe's
|
|
76
|
+
* `numu:theme:update` postMessage) without tearing down the tree.
|
|
77
|
+
* Implementations typically forward the value to a useState setter
|
|
78
|
+
* inside a wrapper that renders `<NuMuProvider themeSettings={...}>`.
|
|
79
|
+
*
|
|
80
|
+
* Safe to call repeatedly; the bundle is expected to dedup
|
|
81
|
+
* reference-equal calls on its own. Returns nothing — selection /
|
|
82
|
+
* navigation echo back via postMessage.
|
|
83
|
+
*/
|
|
84
|
+
applyDraft: (next: ThemeSettingsV3) => void;
|
|
85
|
+
}
|
|
86
|
+
/** Section schema for customizer form generation */
|
|
87
|
+
interface SectionSchema {
|
|
88
|
+
type: string;
|
|
89
|
+
name: string;
|
|
90
|
+
name_ar?: string;
|
|
91
|
+
tag?: string;
|
|
92
|
+
class?: string;
|
|
93
|
+
limit?: number;
|
|
94
|
+
settings: SettingDefinition[];
|
|
95
|
+
blocks?: BlockSchema[];
|
|
96
|
+
max_blocks?: number;
|
|
97
|
+
presets?: SectionPreset[];
|
|
98
|
+
}
|
|
99
|
+
interface BlockSchema {
|
|
100
|
+
type: string;
|
|
101
|
+
name: string;
|
|
102
|
+
name_ar?: string;
|
|
103
|
+
limit?: number;
|
|
104
|
+
settings: SettingDefinition[];
|
|
105
|
+
/** Child block types this block accepts (recursive). When present,
|
|
106
|
+
* the customizer lets merchants add/remove/reorder these inside the
|
|
107
|
+
* block, up to `max_blocks`. Enables footer columns, mega-menus,
|
|
108
|
+
* multi-column layouts. The host caps practical nesting depth
|
|
109
|
+
* (MAX_BLOCK_DEPTH). */
|
|
110
|
+
blocks?: BlockSchema[];
|
|
111
|
+
max_blocks?: number;
|
|
112
|
+
}
|
|
113
|
+
/** Max nesting depth the customizer allows for blocks-in-blocks. Depth
|
|
114
|
+
* 1 = a top-level block in a section; a block at this depth can't take
|
|
115
|
+
* children. Generous (below Shopify's 8) and cheap to raise. Kept in
|
|
116
|
+
* sync with the merchant hub's MAX_BLOCK_DEPTH. */
|
|
117
|
+
declare const MAX_BLOCK_DEPTH = 5;
|
|
118
|
+
/**
|
|
119
|
+
* Setting types the V3 customizer renders. Themes can declare any
|
|
120
|
+
* string here; unknown types fall through to a plain text input. The
|
|
121
|
+
* union below documents the canonical set so theme authors get
|
|
122
|
+
* autocomplete and TypeScript errors on typos.
|
|
123
|
+
*/
|
|
124
|
+
type SettingType = "text" | "textarea" | "richtext" | "number" | "range" | "color" | "checkbox" | "select" | "radio" | "font" | "image_picker" | "url" | "product" | "product_list" | "collection" | "collection_list" | "header" | "paragraph" | "html" | "date" | "time" | "video_picker" | "color_scheme" | "page_picker" | "blog_picker" | "link_list_picker" | "variant_picker" | "file_upload" | "icon_picker" | "icon";
|
|
125
|
+
/**
|
|
126
|
+
* `visible_if` — conditional visibility expression evaluated against
|
|
127
|
+
* sibling settings in the same schema. Two flavors:
|
|
128
|
+
*
|
|
129
|
+
* - String DSL: `"settings.show_button == true && settings.layout != 'minimal'"`
|
|
130
|
+
* - Object form: `{ show_button: true, layout: ["full", "split"] }`
|
|
131
|
+
*
|
|
132
|
+
* Evaluator lives in the merchant hub: any setting whose expression is
|
|
133
|
+
* falsy is skipped from the rendered form.
|
|
134
|
+
*/
|
|
135
|
+
type VisibleIf = string | Record<string, unknown>;
|
|
136
|
+
interface SettingDefinition {
|
|
137
|
+
type: SettingType | (string & {});
|
|
138
|
+
id: string;
|
|
139
|
+
label: string;
|
|
140
|
+
label_ar?: string;
|
|
141
|
+
default?: any;
|
|
142
|
+
info?: string;
|
|
143
|
+
info_ar?: string;
|
|
144
|
+
placeholder?: string;
|
|
145
|
+
options?: {
|
|
146
|
+
value: string;
|
|
147
|
+
label: string;
|
|
148
|
+
label_ar?: string;
|
|
149
|
+
}[];
|
|
150
|
+
min?: number;
|
|
151
|
+
max?: number;
|
|
152
|
+
step?: number;
|
|
153
|
+
unit?: string;
|
|
154
|
+
/** Hide this setting unless the expression evaluates truthy. */
|
|
155
|
+
visible_if?: VisibleIf;
|
|
156
|
+
}
|
|
157
|
+
interface PresetBlock {
|
|
158
|
+
type: string;
|
|
159
|
+
settings?: Record<string, any>;
|
|
160
|
+
/** Nested starter blocks materialized when the preset is applied
|
|
161
|
+
* (recursive). Lets a preset ship, e.g., a footer column already
|
|
162
|
+
* populated with link blocks. */
|
|
163
|
+
blocks?: PresetBlock[];
|
|
164
|
+
}
|
|
165
|
+
interface SectionPreset {
|
|
166
|
+
name: string;
|
|
167
|
+
/** Localized names so the Add Section dialog reads in the editor's
|
|
168
|
+
* current locale. Falls back to `name` when the locale is missing. */
|
|
169
|
+
locales?: {
|
|
170
|
+
en?: {
|
|
171
|
+
name?: string;
|
|
172
|
+
};
|
|
173
|
+
ar?: {
|
|
174
|
+
name?: string;
|
|
175
|
+
};
|
|
176
|
+
};
|
|
177
|
+
settings?: Record<string, any>;
|
|
178
|
+
blocks?: PresetBlock[];
|
|
179
|
+
}
|
|
180
|
+
/** Section component props */
|
|
181
|
+
interface SectionProps {
|
|
182
|
+
settings: Record<string, any>;
|
|
183
|
+
blocks?: Record<string, BlockInstance>;
|
|
184
|
+
blockOrder?: string[];
|
|
185
|
+
storeData?: any;
|
|
186
|
+
}
|
|
187
|
+
/** Block component props */
|
|
188
|
+
interface BlockProps {
|
|
189
|
+
settings: Record<string, any>;
|
|
190
|
+
/** Child block instances when this block nests others (footer column,
|
|
191
|
+
* mega-menu, …). Mirror the section→block render: map `blockOrder`
|
|
192
|
+
* and look each id up in `blocks`, wrapping each child in `<Block>`. */
|
|
193
|
+
blocks?: Record<string, BlockInstance>;
|
|
194
|
+
blockOrder?: string[];
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export { type BlockInstance as B, type ExternalThemeMetadata as E, type MountResult as M, type PageTemplate as P, type SectionGroup as S, type ThemeSettingsV3 as T, type BlockProps as a, type BlockSchema as b, type SectionInstance as c, type SectionPreset as d, type SectionProps as e, type SectionSchema as f, type SettingDefinition as g, MAX_BLOCK_DEPTH as h, type PresetBlock as i };
|
package/dist/types.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { A as Address,
|
|
2
|
-
export {
|
|
1
|
+
export { A as Address, C as Cart, a as CartItem, b as Collection, c as Customer, O as Order, d as OrderItem, P as Page, e as Product, f as ProductImage, g as ProductVariant, S as Store } from './entities-iiuRSPpk.mjs';
|
|
2
|
+
export { B as BlockInstance, a as BlockProps, b as BlockSchema, E as ExternalThemeMetadata, P as PageTemplate, S as SectionGroup, c as SectionInstance, d as SectionPreset, e as SectionProps, f as SectionSchema, g as SettingDefinition, T as ThemeSettingsV3 } from './theme-D0QybTQS.mjs';
|
package/dist/types.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { A as Address,
|
|
2
|
-
export {
|
|
1
|
+
export { A as Address, C as Cart, a as CartItem, b as Collection, c as Customer, O as Order, d as OrderItem, P as Page, e as Product, f as ProductImage, g as ProductVariant, S as Store } from './entities-iiuRSPpk.js';
|
|
2
|
+
export { B as BlockInstance, a as BlockProps, b as BlockSchema, E as ExternalThemeMetadata, P as PageTemplate, S as SectionGroup, c as SectionInstance, d as SectionPreset, e as SectionProps, f as SectionSchema, g as SettingDefinition, T as ThemeSettingsV3 } from './theme-D0QybTQS.js';
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('react');
|
|
4
|
+
|
|
5
|
+
var ShopContext = react.createContext(null);
|
|
6
|
+
react.createContext(null);
|
|
7
|
+
react.createContext(null);
|
|
8
|
+
react.createContext(null);
|
|
9
|
+
var CustomerContext = react.createContext(null);
|
|
10
|
+
var ThemeSettingsContext = react.createContext(null);
|
|
11
|
+
var LocalizationContext = react.createContext(null);
|
|
12
|
+
var PageContext = react.createContext(null);
|
|
13
|
+
react.createContext("home");
|
|
14
|
+
react.createContext(
|
|
15
|
+
{}
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
// src/hooks/usePage.ts
|
|
19
|
+
function usePage() {
|
|
20
|
+
return react.useContext(PageContext);
|
|
21
|
+
}
|
|
22
|
+
function useLocalization() {
|
|
23
|
+
const ctx = react.useContext(LocalizationContext);
|
|
24
|
+
if (!ctx) throw new Error("useLocalization must be used within NuMuProvider");
|
|
25
|
+
return ctx;
|
|
26
|
+
}
|
|
27
|
+
function useLocale() {
|
|
28
|
+
const { locale } = useLocalization();
|
|
29
|
+
return locale;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// src/hooks/useShop.ts
|
|
33
|
+
var DEFAULT_PROTOCOL = typeof window !== "undefined" ? window.location.protocol.replace(":", "") : "https";
|
|
34
|
+
function resolveDomain(store) {
|
|
35
|
+
if (store.domain) return store.domain;
|
|
36
|
+
if (store.subdomain) {
|
|
37
|
+
const platform = typeof window !== "undefined" && window.__NUMU_PLATFORM_DOMAIN || "numueg.app";
|
|
38
|
+
return `${store.subdomain}.${platform}`;
|
|
39
|
+
}
|
|
40
|
+
return store.slug;
|
|
41
|
+
}
|
|
42
|
+
function useShop() {
|
|
43
|
+
const ctx = react.useContext(ShopContext);
|
|
44
|
+
if (!ctx) throw new Error("useShop must be used within NuMuProvider");
|
|
45
|
+
const locale = useLocale();
|
|
46
|
+
return react.useMemo(() => {
|
|
47
|
+
const domain = resolveDomain(ctx);
|
|
48
|
+
const settings = ctx.settings;
|
|
49
|
+
const localePrefixEnabled = Boolean(
|
|
50
|
+
settings && settings.locale_url_prefix_enabled
|
|
51
|
+
);
|
|
52
|
+
const defaultLocale = ctx.default_language || "en";
|
|
53
|
+
const prefixedLocales = settings?.locale_url_prefix_locales || null;
|
|
54
|
+
const shouldPrefix = (l) => {
|
|
55
|
+
if (!localePrefixEnabled) return false;
|
|
56
|
+
if (prefixedLocales) return prefixedLocales.includes(l);
|
|
57
|
+
return l !== defaultLocale;
|
|
58
|
+
};
|
|
59
|
+
const formatUrl = (path) => {
|
|
60
|
+
if (!path) return `${DEFAULT_PROTOCOL}://${domain}/`;
|
|
61
|
+
if (/^https?:\/\//i.test(path)) return path;
|
|
62
|
+
if (path.startsWith("//")) return `${DEFAULT_PROTOCOL}:${path}`;
|
|
63
|
+
let normalized = path.startsWith("/") ? path : `/${path}`;
|
|
64
|
+
if (locale && shouldPrefix(locale)) {
|
|
65
|
+
const prefix = `/${locale}/`;
|
|
66
|
+
const root = `/${locale}`;
|
|
67
|
+
if (normalized !== root && !normalized.startsWith(prefix)) {
|
|
68
|
+
normalized = `${root}${normalized}`;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return `${DEFAULT_PROTOCOL}://${domain}${normalized}`;
|
|
72
|
+
};
|
|
73
|
+
return { ...ctx, domain, formatUrl };
|
|
74
|
+
}, [ctx, locale]);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// src/hooks/useProducts.ts
|
|
78
|
+
function useProducts(opts = {}) {
|
|
79
|
+
const { limit, fetchIfMissing = false } = opts;
|
|
80
|
+
const page = usePage();
|
|
81
|
+
const shop = useShop();
|
|
82
|
+
const initial = page?.data?.products ?? null;
|
|
83
|
+
const [products, setProducts] = react.useState(initial ?? []);
|
|
84
|
+
const [loading, setLoading] = react.useState(
|
|
85
|
+
initial == null && fetchIfMissing
|
|
86
|
+
);
|
|
87
|
+
const [error, setError] = react.useState(null);
|
|
88
|
+
react.useEffect(() => {
|
|
89
|
+
if (initial != null) return;
|
|
90
|
+
if (!fetchIfMissing) return;
|
|
91
|
+
if (!shop?.id) return;
|
|
92
|
+
let cancelled = false;
|
|
93
|
+
(async () => {
|
|
94
|
+
try {
|
|
95
|
+
const params = new URLSearchParams({ store_id: shop.id });
|
|
96
|
+
if (limit) params.set("limit", String(limit));
|
|
97
|
+
const res = await fetch(`/api/products?${params.toString()}`);
|
|
98
|
+
if (!res.ok) throw new Error(`/api/products \u2192 ${res.status}`);
|
|
99
|
+
const data = await res.json();
|
|
100
|
+
if (cancelled) return;
|
|
101
|
+
setProducts(data.products ?? []);
|
|
102
|
+
setLoading(false);
|
|
103
|
+
} catch (err) {
|
|
104
|
+
if (cancelled) return;
|
|
105
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
106
|
+
setLoading(false);
|
|
107
|
+
}
|
|
108
|
+
})();
|
|
109
|
+
return () => {
|
|
110
|
+
cancelled = true;
|
|
111
|
+
};
|
|
112
|
+
}, [initial, fetchIfMissing, limit, shop?.id]);
|
|
113
|
+
const sliced = limit != null ? products.slice(0, limit) : products;
|
|
114
|
+
return { products: sliced, loading, error };
|
|
115
|
+
}
|
|
116
|
+
function useCollections(opts = {}) {
|
|
117
|
+
const { limit, fetchIfMissing = false } = opts;
|
|
118
|
+
const page = usePage();
|
|
119
|
+
const shop = useShop();
|
|
120
|
+
const initial = page?.data?.collections ?? null;
|
|
121
|
+
const [collections, setCollections] = react.useState(initial ?? []);
|
|
122
|
+
const [loading, setLoading] = react.useState(
|
|
123
|
+
initial == null && fetchIfMissing
|
|
124
|
+
);
|
|
125
|
+
const [error, setError] = react.useState(null);
|
|
126
|
+
react.useEffect(() => {
|
|
127
|
+
if (initial != null) return;
|
|
128
|
+
if (!fetchIfMissing) return;
|
|
129
|
+
if (!shop?.id) return;
|
|
130
|
+
let cancelled = false;
|
|
131
|
+
(async () => {
|
|
132
|
+
try {
|
|
133
|
+
const params = new URLSearchParams({ store_id: shop.id });
|
|
134
|
+
const res = await fetch(`/api/collections?${params.toString()}`);
|
|
135
|
+
if (!res.ok) throw new Error(`/api/collections \u2192 ${res.status}`);
|
|
136
|
+
const data = await res.json();
|
|
137
|
+
if (cancelled) return;
|
|
138
|
+
setCollections(data.collections ?? []);
|
|
139
|
+
setLoading(false);
|
|
140
|
+
} catch (err) {
|
|
141
|
+
if (cancelled) return;
|
|
142
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
143
|
+
setLoading(false);
|
|
144
|
+
}
|
|
145
|
+
})();
|
|
146
|
+
return () => {
|
|
147
|
+
cancelled = true;
|
|
148
|
+
};
|
|
149
|
+
}, [initial, fetchIfMissing, shop?.id]);
|
|
150
|
+
const sliced = limit != null ? collections.slice(0, limit) : collections;
|
|
151
|
+
return { collections: sliced, loading, error };
|
|
152
|
+
}
|
|
153
|
+
function useCustomer() {
|
|
154
|
+
return react.useContext(CustomerContext);
|
|
155
|
+
}
|
|
156
|
+
function useThemeSettings() {
|
|
157
|
+
const ctx = react.useContext(ThemeSettingsContext);
|
|
158
|
+
if (!ctx) throw new Error("useThemeSettings must be used within NuMuProvider");
|
|
159
|
+
return ctx;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// src/v2-compat.ts
|
|
163
|
+
function useV2Products() {
|
|
164
|
+
const { products, loading } = useProducts();
|
|
165
|
+
return react.useMemo(
|
|
166
|
+
() => ({
|
|
167
|
+
products,
|
|
168
|
+
loading
|
|
169
|
+
}),
|
|
170
|
+
[products, loading]
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
function collectionToV2Category(c) {
|
|
174
|
+
return {
|
|
175
|
+
id: c.id,
|
|
176
|
+
name: c.name,
|
|
177
|
+
slug: c.slug,
|
|
178
|
+
image_url: c.image_url ?? null,
|
|
179
|
+
description: c.description ?? null
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
function useV2Categories() {
|
|
183
|
+
const { collections, loading } = useCollections();
|
|
184
|
+
return react.useMemo(
|
|
185
|
+
() => ({
|
|
186
|
+
categories: collections.map(collectionToV2Category),
|
|
187
|
+
loading
|
|
188
|
+
}),
|
|
189
|
+
[collections, loading]
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
function useV2Auth() {
|
|
193
|
+
const customer = useCustomer();
|
|
194
|
+
return react.useMemo(
|
|
195
|
+
() => ({
|
|
196
|
+
user: customer,
|
|
197
|
+
isAuthenticated: customer !== null
|
|
198
|
+
}),
|
|
199
|
+
[customer]
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
function useV2Language() {
|
|
203
|
+
const { locale, direction, translations, setLocale } = useLocalization();
|
|
204
|
+
const normalisedLocale = locale === "ar" ? "ar" : "en";
|
|
205
|
+
return react.useMemo(
|
|
206
|
+
() => ({
|
|
207
|
+
language: normalisedLocale,
|
|
208
|
+
direction,
|
|
209
|
+
setLanguage: (next) => setLocale(next),
|
|
210
|
+
t: (key, fallback) => translations[key] ?? fallback ?? key
|
|
211
|
+
}),
|
|
212
|
+
[normalisedLocale, direction, translations, setLocale]
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
function useV2Theme() {
|
|
216
|
+
const settings = useThemeSettings();
|
|
217
|
+
return react.useMemo(() => {
|
|
218
|
+
const g = settings.global_settings ?? {};
|
|
219
|
+
const get = (key) => {
|
|
220
|
+
const v = g[key];
|
|
221
|
+
return typeof v === "string" ? v : void 0;
|
|
222
|
+
};
|
|
223
|
+
return {
|
|
224
|
+
themeSettings: {
|
|
225
|
+
theme: {
|
|
226
|
+
primary_color: get("primary_color"),
|
|
227
|
+
accent_color: get("accent_color"),
|
|
228
|
+
background_color: get("background_color"),
|
|
229
|
+
text_color: get("text_color"),
|
|
230
|
+
heading_font: get("heading_font"),
|
|
231
|
+
...g
|
|
232
|
+
},
|
|
233
|
+
identity: {
|
|
234
|
+
logo_url: get("logo_url"),
|
|
235
|
+
store_name: get("store_name")
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
}, [settings]);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
exports.useV2Auth = useV2Auth;
|
|
243
|
+
exports.useV2Categories = useV2Categories;
|
|
244
|
+
exports.useV2Language = useV2Language;
|
|
245
|
+
exports.useV2Products = useV2Products;
|
|
246
|
+
exports.useV2Theme = useV2Theme;
|
|
247
|
+
//# sourceMappingURL=v2-compat.cjs.map
|
|
248
|
+
//# sourceMappingURL=v2-compat.cjs.map
|