@shop-on/theme-react 0.4.0 → 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.
@@ -1,19 +1,20 @@
1
1
  import { escapeAttrValue, scopeCustomCss } from "./custom-css.js";
2
2
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import { createContext, createElement, useContext, useEffect } from "react";
4
- import { collectTypes, selectRenderableChildren, selectRenderableSections } from "@shop-on/theme-contract";
4
+ import { MAX_APP_BLOCK_CONTAINER_DEPTH, collectTypes, selectRenderableChildren, selectRenderableSections } from "@shop-on/theme-contract";
5
5
  import { rootRouteId, useMatch } from "@tanstack/react-router";
6
6
  //#region src/template-renderer.tsx
7
7
  const EMPTY_BLOCK_PATH = [];
8
8
  const SectionIdContext = createContext(void 0);
9
9
  const BlockPathContext = createContext(EMPTY_BLOCK_PATH);
10
+ const BlockDepthContext = createContext(void 0);
10
11
  const appScriptPromises = /* @__PURE__ */ new Map();
11
12
  function loadAppScript(src) {
12
13
  const cached = appScriptPromises.get(src);
13
14
  if (cached) return cached;
14
15
  const p = new Promise((resolve, reject) => {
15
16
  if (typeof window === "undefined") return resolve();
16
- const existing = document.querySelector(`script[data-app-bundle="${src}"]`);
17
+ const existing = document.querySelector(`script[data-app-bundle="${CSS.escape(src)}"]`);
17
18
  if (existing) {
18
19
  existing.addEventListener("load", () => resolve(), { once: true });
19
20
  existing.addEventListener("error", () => reject(/* @__PURE__ */ new Error("app-script-load-failed")), { once: true });
@@ -46,21 +47,31 @@ function useShopHandle() {
46
47
  select: (match) => shopHandleOf(match.loaderData)
47
48
  });
48
49
  }
49
- function DefaultAppSection({ section, sectionId }) {
50
- const { tag, scriptUrl } = section;
51
- const settings = section.settings ?? {};
50
+ function AppElement({ tag, scriptUrl, settings, kind, instanceId }) {
52
51
  const shopHandle = useShopHandle();
53
52
  useEffect(() => {
54
53
  if (scriptUrl) loadAppScript(scriptUrl).catch(() => {});
55
54
  }, [scriptUrl]);
56
- if (!tag) return null;
57
55
  return createElement(tag, {
58
- "data-settings": JSON.stringify(settings),
59
- "data-app-section-id": sectionId,
56
+ "data-settings": JSON.stringify(settings ?? {}),
57
+ [`data-app-${kind}-id`]: instanceId,
60
58
  "data-shop-handle": shopHandle,
61
59
  suppressHydrationWarning: true
62
60
  });
63
61
  }
62
+ function DefaultAppSection({ section, sectionId }) {
63
+ if (!section.tag) return null;
64
+ return /* @__PURE__ */ jsx(AppElement, {
65
+ tag: section.tag,
66
+ scriptUrl: section.scriptUrl,
67
+ settings: section.settings,
68
+ kind: "section",
69
+ instanceId: sectionId
70
+ });
71
+ }
72
+ function mountsAppBlock(block, depth) {
73
+ return !!block.id && depth !== void 0 && depth <= MAX_APP_BLOCK_CONTAINER_DEPTH && !block.static && !!block.tag && block.type.startsWith("app-");
74
+ }
64
75
  /** `collectTypes` over every template, merged. */
65
76
  function collectTemplateTypes(templates) {
66
77
  const sections = /* @__PURE__ */ new Set();
@@ -109,6 +120,7 @@ function createTemplateRenderer(loaders, opts) {
109
120
  async function preloadBlocks(args) {
110
121
  const types = /* @__PURE__ */ new Set();
111
122
  const visit = (b) => {
123
+ if (b.source === "app") return;
112
124
  types.add(b.type);
113
125
  if (b.blocks) for (const child of Object.values(b.blocks)) visit(child);
114
126
  };
@@ -143,9 +155,12 @@ function createTemplateRenderer(loaders, opts) {
143
155
  style: { display: "contents" },
144
156
  children: /* @__PURE__ */ jsx(SectionIdContext.Provider, {
145
157
  value: instanceId,
146
- children: /* @__PURE__ */ jsxs(BlockPathContext.Provider, {
158
+ children: /* @__PURE__ */ jsx(BlockPathContext.Provider, {
147
159
  value: EMPTY_BLOCK_PATH,
148
- children: [sectionCss ? /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: sectionCss } }) : null, renderSectionBody(section, instanceId, groupType, blocks, staticBlocks)]
160
+ children: /* @__PURE__ */ jsxs(BlockDepthContext.Provider, {
161
+ value: 0,
162
+ children: [sectionCss ? /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: sectionCss } }) : null, renderSectionBody(section, instanceId, groupType, blocks, staticBlocks)]
163
+ })
149
164
  })
150
165
  })
151
166
  }, instanceId);
@@ -182,14 +197,23 @@ function createTemplateRenderer(loaders, opts) {
182
197
  children: renderSections(template.sections, template.order)
183
198
  });
184
199
  }
200
+ function renderThemeBlock(block) {
201
+ const BlockComponent = resolveBlock(block.type);
202
+ return /* @__PURE__ */ jsx(BlockComponent, {
203
+ ...block.settings,
204
+ blockId: block.id,
205
+ blocks: selectRenderableChildren(block)
206
+ });
207
+ }
185
208
  function BlockRenderer({ blocks, parentBlockId }) {
186
209
  const sectionId = useContext(SectionIdContext);
187
210
  const inheritedPath = useContext(BlockPathContext);
188
211
  const containerPath = inheritedPath.length > 0 ? inheritedPath : parentBlockId ? [parentBlockId] : EMPTY_BLOCK_PATH;
212
+ const depth = useContext(BlockDepthContext);
189
213
  return /* @__PURE__ */ jsx(Fragment, { children: blocks.map((block, i) => {
190
214
  if (block.disabled) return null;
191
- const BlockComponent = resolveBlock(block.type);
192
- const children = selectRenderableChildren(block);
215
+ const isApp = block.source === "app";
216
+ if (isApp && !mountsAppBlock(block, depth)) return null;
193
217
  const key = block.id ?? `${block.type}-${i}`;
194
218
  const ownPath = block.id ? [...containerPath, block.id] : containerPath;
195
219
  const blockCss = block.id && sectionId ? scopeCustomCss(`[data-editor-section-id="${escapeAttrValue(sectionId)}"] ${containerPath.map((seg) => `[data-editor-block-id="${escapeAttrValue(seg)}"] `).join("")}[data-editor-block-id="${escapeAttrValue(block.id)}"]`, block.custom_css) : null;
@@ -197,12 +221,17 @@ function createTemplateRenderer(loaders, opts) {
197
221
  "data-editor-block-id": block.id || void 0,
198
222
  className: `block-${block.type.replace(/^_/, "")}`,
199
223
  style: { display: "contents" },
200
- children: [blockCss ? /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: blockCss } }) : null, /* @__PURE__ */ jsx(BlockPathContext.Provider, {
224
+ children: [blockCss ? /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: blockCss } }) : null, isApp ? /* @__PURE__ */ jsx(AppElement, {
225
+ tag: block.tag,
226
+ scriptUrl: block.scriptUrl,
227
+ settings: block.settings,
228
+ kind: "block",
229
+ instanceId: block.id
230
+ }) : /* @__PURE__ */ jsx(BlockPathContext.Provider, {
201
231
  value: ownPath,
202
- children: /* @__PURE__ */ jsx(BlockComponent, {
203
- ...block.settings,
204
- blockId: block.id,
205
- blocks: children
232
+ children: /* @__PURE__ */ jsx(BlockDepthContext.Provider, {
233
+ value: depth === void 0 ? void 0 : depth + 1,
234
+ children: renderThemeBlock(block)
206
235
  })
207
236
  })]
208
237
  }, key);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shop-on/theme-react",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "license": "SEE LICENSE IN dist/LICENSE.md",
5
5
  "files": [
6
6
  "dist"
@@ -31,8 +31,8 @@
31
31
  "./package.json": "./package.json"
32
32
  },
33
33
  "dependencies": {
34
- "@shop-on/theme-contract": "0.4.0",
35
- "@shop-on/theme-runtime": "0.4.0"
34
+ "@shop-on/theme-contract": "0.5.0",
35
+ "@shop-on/theme-runtime": "0.5.0"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@tanstack/react-router": "1.170.45",