@weaverse/next 0.1.0-alpha.7 → 0.1.0-alpha.9
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.d.mts +265 -9
- package/dist/index.d.ts +265 -9
- package/dist/index.js +437 -22
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +431 -25
- package/dist/index.mjs.map +1 -1
- package/dist/{seo-B9yNko4W.d.mts → seo-Dos9t22_.d.mts} +84 -2
- package/dist/{seo-B9yNko4W.d.ts → seo-Dos9t22_.d.ts} +84 -2
- package/dist/server.d.mts +2 -2
- package/dist/server.d.ts +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -27,13 +27,84 @@ function generateDataFromSchema(schema) {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
// src/item.ts
|
|
30
|
+
function flattenItemData(update) {
|
|
31
|
+
let { data, ...rest } = update;
|
|
32
|
+
if (!(data && typeof data === "object" && !Array.isArray(data))) {
|
|
33
|
+
return rest;
|
|
34
|
+
}
|
|
35
|
+
return { ...data, ...rest };
|
|
36
|
+
}
|
|
37
|
+
var deferredItemUpdates = null;
|
|
38
|
+
function collectDeferredItemUpdates(create) {
|
|
39
|
+
let previousQueue = deferredItemUpdates;
|
|
40
|
+
let queue = /* @__PURE__ */ new Set();
|
|
41
|
+
deferredItemUpdates = queue;
|
|
42
|
+
try {
|
|
43
|
+
return [create(), [...queue]];
|
|
44
|
+
} finally {
|
|
45
|
+
deferredItemUpdates = previousQueue;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
30
48
|
var WeaverseNextItem = class extends react.WeaverseItemStore {
|
|
49
|
+
/**
|
|
50
|
+
* Cached merged snapshot (base `_store` + translations). Reset whenever the
|
|
51
|
+
* `_store` ref or the item's translation entry ref changes, so
|
|
52
|
+
* `useSyncExternalStore` sees a stable object between unrelated re-renders.
|
|
53
|
+
*/
|
|
54
|
+
_cachedSnapshot = null;
|
|
55
|
+
_snapshotStoreRef = null;
|
|
56
|
+
_snapshotTranslationRef = null;
|
|
31
57
|
constructor(initialData, weaverse) {
|
|
32
58
|
super(initialData, weaverse);
|
|
33
|
-
let { data, ...rest } = initialData;
|
|
34
59
|
let schemaData = generateDataFromSchema(this.Element?.schema);
|
|
35
|
-
Object.assign(this._store, schemaData,
|
|
60
|
+
Object.assign(this._store, schemaData, flattenItemData(initialData));
|
|
36
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Flatten nested `data` on updates exactly like the constructor does. Core's
|
|
64
|
+
* `initProject()` calls `setData(item)` when a new runtime serves a page
|
|
65
|
+
* whose item instances already exist (e.g. locale/client navigation), and
|
|
66
|
+
* the inherited shallow merge would leave stale top-level props behind.
|
|
67
|
+
* Assigning through the inherited `data` setter swaps the `_store` ref,
|
|
68
|
+
* which invalidates the memoized snapshot below. The subscriber emit is
|
|
69
|
+
* queued instead of fired when a render-phase deferral is active (see
|
|
70
|
+
* `collectDeferredItemUpdates`).
|
|
71
|
+
*/
|
|
72
|
+
setData = (update) => {
|
|
73
|
+
this.data = flattenItemData(update);
|
|
74
|
+
if (deferredItemUpdates) {
|
|
75
|
+
deferredItemUpdates.add(this);
|
|
76
|
+
} else {
|
|
77
|
+
this.triggerUpdate();
|
|
78
|
+
}
|
|
79
|
+
return this.data;
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Overlay item-level translations onto the base store when the runtime is in
|
|
83
|
+
* translation mode. Mirrors Hydrogen's `WeaverseHydrogenItem.getSnapShot()`:
|
|
84
|
+
* memoized by `_store` ref + translation entry ref so the returned object is
|
|
85
|
+
* referentially stable, and a fast path that returns the base store untouched
|
|
86
|
+
* when the item has no translations.
|
|
87
|
+
*/
|
|
88
|
+
getSnapShot = () => {
|
|
89
|
+
let base = this._store;
|
|
90
|
+
let translations = this.weaverse.translationMap[this._id];
|
|
91
|
+
if (!translations) {
|
|
92
|
+
return base;
|
|
93
|
+
}
|
|
94
|
+
if (this._cachedSnapshot && this._snapshotStoreRef === base && this._snapshotTranslationRef === translations) {
|
|
95
|
+
return this._cachedSnapshot;
|
|
96
|
+
}
|
|
97
|
+
let merged = { ...base };
|
|
98
|
+
for (let [key, entry] of Object.entries(translations)) {
|
|
99
|
+
if (entry.translatedValue !== void 0) {
|
|
100
|
+
merged[key] = entry.translatedValue;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
this._cachedSnapshot = merged;
|
|
104
|
+
this._snapshotStoreRef = base;
|
|
105
|
+
this._snapshotTranslationRef = translations;
|
|
106
|
+
return merged;
|
|
107
|
+
};
|
|
37
108
|
};
|
|
38
109
|
function ensureNextItemConstructor() {
|
|
39
110
|
if (!react.Weaverse.ItemConstructor || react.Weaverse.ItemConstructor === react.WeaverseItemStore || react.Weaverse.ItemConstructor === WeaverseNextItem) {
|
|
@@ -158,9 +229,136 @@ function createWeaverseNextThemeSettingsStore(options = {}) {
|
|
|
158
229
|
};
|
|
159
230
|
return store;
|
|
160
231
|
}
|
|
232
|
+
function getNestedKey(obj, path, fallback) {
|
|
233
|
+
let keys = path.split(".");
|
|
234
|
+
let current = obj;
|
|
235
|
+
for (let key of keys) {
|
|
236
|
+
if (current == null || typeof current !== "object") {
|
|
237
|
+
return fallback;
|
|
238
|
+
}
|
|
239
|
+
current = current[key];
|
|
240
|
+
}
|
|
241
|
+
if (typeof current === "string") {
|
|
242
|
+
return current;
|
|
243
|
+
}
|
|
244
|
+
return fallback;
|
|
245
|
+
}
|
|
246
|
+
function interpolate(template, variables) {
|
|
247
|
+
if (!variables) {
|
|
248
|
+
return template;
|
|
249
|
+
}
|
|
250
|
+
return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
|
|
251
|
+
let value = variables[key];
|
|
252
|
+
return value === void 0 ? match : String(value);
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
var TranslationContext = react$1.createContext(null);
|
|
256
|
+
TranslationContext.displayName = "WeaverseNextTranslationContext";
|
|
257
|
+
function createTranslate(sources) {
|
|
258
|
+
let { staticContent, merchantOverrides, designOverrides, externalT } = sources;
|
|
259
|
+
return (key, variables) => {
|
|
260
|
+
if (externalT) {
|
|
261
|
+
let external = externalT(key, variables);
|
|
262
|
+
if (external && external !== key) {
|
|
263
|
+
return external;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
let design = designOverrides && Object.hasOwn(designOverrides, key) ? designOverrides[key] : void 0;
|
|
267
|
+
let override = merchantOverrides ? getNestedKey(merchantOverrides, key) : void 0;
|
|
268
|
+
let staticValue = getNestedKey(staticContent, key);
|
|
269
|
+
let raw = design ?? override ?? staticValue ?? key;
|
|
270
|
+
return interpolate(raw, variables);
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
var EMPTY = {};
|
|
274
|
+
var NOOP_SUBSCRIBE = () => () => {
|
|
275
|
+
};
|
|
276
|
+
var NOOP_SNAPSHOT = () => EMPTY;
|
|
277
|
+
function TranslationProvider({
|
|
278
|
+
staticContent,
|
|
279
|
+
merchantOverrides,
|
|
280
|
+
t: externalT,
|
|
281
|
+
translationStore,
|
|
282
|
+
themeTextStore,
|
|
283
|
+
children
|
|
284
|
+
}) {
|
|
285
|
+
let store = translationStore ?? themeTextStore ?? null;
|
|
286
|
+
let designOverrides = react.useSafeExternalStore(
|
|
287
|
+
store?.subscribe ?? NOOP_SUBSCRIBE,
|
|
288
|
+
store?.getSnapshot ?? NOOP_SNAPSHOT,
|
|
289
|
+
store?.getServerSnapshot ?? NOOP_SNAPSHOT
|
|
290
|
+
);
|
|
291
|
+
let value = react$1.useMemo(
|
|
292
|
+
() => ({
|
|
293
|
+
t: createTranslate({
|
|
294
|
+
staticContent,
|
|
295
|
+
merchantOverrides,
|
|
296
|
+
designOverrides,
|
|
297
|
+
externalT
|
|
298
|
+
}),
|
|
299
|
+
translationStore: store,
|
|
300
|
+
// Deprecated alias — same instance, kept for backward compatibility.
|
|
301
|
+
themeTextStore: store,
|
|
302
|
+
merchantOverrides: merchantOverrides ?? null
|
|
303
|
+
}),
|
|
304
|
+
[staticContent, merchantOverrides, designOverrides, externalT, store]
|
|
305
|
+
);
|
|
306
|
+
return /* @__PURE__ */ jsxRuntime.jsx(TranslationContext.Provider, { value, children });
|
|
307
|
+
}
|
|
308
|
+
function useTranslation() {
|
|
309
|
+
let ctx = react$1.useContext(TranslationContext);
|
|
310
|
+
if (!ctx) {
|
|
311
|
+
throw new Error(
|
|
312
|
+
"useTranslation must be used within <TranslationProvider>. Wrap your app with <WeaverseNextRootProvider>."
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
return ctx;
|
|
316
|
+
}
|
|
317
|
+
var ThemeTextProvider = TranslationProvider;
|
|
318
|
+
var useThemeText = useTranslation;
|
|
319
|
+
|
|
320
|
+
// src/translation-store.ts
|
|
321
|
+
var TranslationStore = class {
|
|
322
|
+
overrides = {};
|
|
323
|
+
listeners = /* @__PURE__ */ new Set();
|
|
324
|
+
setOverrides = (overrides) => {
|
|
325
|
+
this.overrides = { ...overrides };
|
|
326
|
+
this.emit();
|
|
327
|
+
};
|
|
328
|
+
updateOverrides = (newOverrides) => {
|
|
329
|
+
this.overrides = { ...this.overrides, ...newOverrides };
|
|
330
|
+
this.emit();
|
|
331
|
+
};
|
|
332
|
+
getSnapshot = () => this.overrides;
|
|
333
|
+
getServerSnapshot = () => this.overrides;
|
|
334
|
+
subscribe = (callback) => {
|
|
335
|
+
this.listeners.add(callback);
|
|
336
|
+
return () => {
|
|
337
|
+
this.listeners.delete(callback);
|
|
338
|
+
};
|
|
339
|
+
};
|
|
340
|
+
emit = () => {
|
|
341
|
+
for (const listener of Array.from(this.listeners)) {
|
|
342
|
+
try {
|
|
343
|
+
listener();
|
|
344
|
+
} catch (error) {
|
|
345
|
+
console.error("TranslationStore: Listener error", error);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
};
|
|
350
|
+
var ThemeTextStore = TranslationStore;
|
|
161
351
|
var WeaverseNextRootContext = react$1.createContext(null);
|
|
162
352
|
function WeaverseNextRootProvider(props) {
|
|
163
|
-
let {
|
|
353
|
+
let {
|
|
354
|
+
children,
|
|
355
|
+
initialThemeSettings,
|
|
356
|
+
merchantOverrides,
|
|
357
|
+
staticContent,
|
|
358
|
+
t,
|
|
359
|
+
themeSchema,
|
|
360
|
+
publicEnv
|
|
361
|
+
} = props;
|
|
164
362
|
let storeRef = react$1.useRef(null);
|
|
165
363
|
if (!storeRef.current) {
|
|
166
364
|
storeRef.current = createWeaverseNextThemeSettingsStore({
|
|
@@ -170,6 +368,11 @@ function WeaverseNextRootProvider(props) {
|
|
|
170
368
|
});
|
|
171
369
|
}
|
|
172
370
|
let themeSettingsStore = storeRef.current;
|
|
371
|
+
let translationStoreRef = react$1.useRef(null);
|
|
372
|
+
if (!translationStoreRef.current) {
|
|
373
|
+
translationStoreRef.current = new TranslationStore();
|
|
374
|
+
}
|
|
375
|
+
let translationStore = translationStoreRef.current;
|
|
173
376
|
let appliedThemeSettingsRef = react$1.useRef(initialThemeSettings);
|
|
174
377
|
react$1.useEffect(() => {
|
|
175
378
|
if (initialThemeSettings && appliedThemeSettingsRef.current !== initialThemeSettings) {
|
|
@@ -177,25 +380,59 @@ function WeaverseNextRootProvider(props) {
|
|
|
177
380
|
appliedThemeSettingsRef.current = initialThemeSettings;
|
|
178
381
|
}
|
|
179
382
|
}, [initialThemeSettings, themeSettingsStore]);
|
|
383
|
+
let resolvedStaticContent = staticContent ?? getSchemaStaticContent(themeSchema);
|
|
180
384
|
let rootContextValue = react$1.useMemo(
|
|
181
|
-
() => ({
|
|
182
|
-
|
|
385
|
+
() => ({
|
|
386
|
+
merchantOverrides,
|
|
387
|
+
staticContent: resolvedStaticContent,
|
|
388
|
+
themeSettingsStore,
|
|
389
|
+
translationStore
|
|
390
|
+
}),
|
|
391
|
+
[
|
|
392
|
+
merchantOverrides,
|
|
393
|
+
resolvedStaticContent,
|
|
394
|
+
themeSettingsStore,
|
|
395
|
+
translationStore
|
|
396
|
+
]
|
|
183
397
|
);
|
|
184
398
|
let contextValue = react$1.useMemo(
|
|
185
399
|
() => ({
|
|
400
|
+
merchantOverrides,
|
|
186
401
|
themeSettings: themeSettingsStore.getSnapshot(),
|
|
187
|
-
themeSettingsStore
|
|
402
|
+
themeSettingsStore,
|
|
403
|
+
translationStore
|
|
188
404
|
}),
|
|
189
|
-
[themeSettingsStore]
|
|
405
|
+
[merchantOverrides, themeSettingsStore, translationStore]
|
|
190
406
|
);
|
|
191
|
-
return /* @__PURE__ */ jsxRuntime.jsx(WeaverseNextRootContext.Provider, { value: rootContextValue, children: /* @__PURE__ */ jsxRuntime.jsx(WeaverseNextContext.Provider, { value: contextValue, children
|
|
407
|
+
return /* @__PURE__ */ jsxRuntime.jsx(WeaverseNextRootContext.Provider, { value: rootContextValue, children: /* @__PURE__ */ jsxRuntime.jsx(WeaverseNextContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
408
|
+
TranslationProvider,
|
|
409
|
+
{
|
|
410
|
+
merchantOverrides,
|
|
411
|
+
staticContent: resolvedStaticContent,
|
|
412
|
+
t,
|
|
413
|
+
translationStore,
|
|
414
|
+
children
|
|
415
|
+
}
|
|
416
|
+
) }) });
|
|
192
417
|
}
|
|
193
418
|
var EMPTY_THEME_SETTINGS = {};
|
|
419
|
+
var EMPTY_STATIC_CONTENT = {};
|
|
420
|
+
function getSchemaStaticContent(schema) {
|
|
421
|
+
let i18n = schema?.i18n;
|
|
422
|
+
return i18n?.staticContent ?? EMPTY_STATIC_CONTENT;
|
|
423
|
+
}
|
|
194
424
|
var WeaverseNextContext = react$1.createContext(null);
|
|
195
425
|
function WeaverseNextProvider(props) {
|
|
196
426
|
let { children, client, rootData, pageData, commerce, themeSettings } = props;
|
|
197
427
|
let rootContext = react$1.useContext(WeaverseNextRootContext);
|
|
198
428
|
let themeSettingsValue = themeSettings ?? client?.themeSettings ?? EMPTY_THEME_SETTINGS;
|
|
429
|
+
let ownTranslationStoreRef = react$1.useRef(null);
|
|
430
|
+
if (!(rootContext || ownTranslationStoreRef.current)) {
|
|
431
|
+
ownTranslationStoreRef.current = new TranslationStore();
|
|
432
|
+
}
|
|
433
|
+
let translationStore = rootContext?.translationStore ?? ownTranslationStoreRef.current;
|
|
434
|
+
let staticContent = props.staticContent ?? rootContext?.staticContent ?? getSchemaStaticContent(client?.themeSchema);
|
|
435
|
+
let merchantOverrides = props.merchantOverrides ?? rootContext?.merchantOverrides;
|
|
199
436
|
let ownThemeSettingsStore = react$1.useMemo(() => {
|
|
200
437
|
if (rootContext) {
|
|
201
438
|
return null;
|
|
@@ -219,12 +456,31 @@ function WeaverseNextProvider(props) {
|
|
|
219
456
|
rootData,
|
|
220
457
|
pageData,
|
|
221
458
|
commerce: commerce ?? client?.commerce,
|
|
459
|
+
merchantOverrides,
|
|
222
460
|
themeSettings: themeSettingsStore.getSnapshot(),
|
|
223
|
-
themeSettingsStore
|
|
461
|
+
themeSettingsStore,
|
|
462
|
+
translationStore
|
|
224
463
|
}),
|
|
225
|
-
[
|
|
464
|
+
[
|
|
465
|
+
client,
|
|
466
|
+
rootData,
|
|
467
|
+
pageData,
|
|
468
|
+
commerce,
|
|
469
|
+
merchantOverrides,
|
|
470
|
+
themeSettingsStore,
|
|
471
|
+
translationStore
|
|
472
|
+
]
|
|
226
473
|
);
|
|
227
|
-
return /* @__PURE__ */ jsxRuntime.jsx(WeaverseNextContext.Provider, { value, children
|
|
474
|
+
return /* @__PURE__ */ jsxRuntime.jsx(WeaverseNextContext.Provider, { value, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
475
|
+
TranslationProvider,
|
|
476
|
+
{
|
|
477
|
+
merchantOverrides,
|
|
478
|
+
staticContent,
|
|
479
|
+
t: props.t,
|
|
480
|
+
translationStore,
|
|
481
|
+
children
|
|
482
|
+
}
|
|
483
|
+
) });
|
|
228
484
|
}
|
|
229
485
|
|
|
230
486
|
// src/hooks.ts
|
|
@@ -452,9 +708,31 @@ var WeaverseNextRuntime = class extends react.Weaverse {
|
|
|
452
708
|
isPreviewMode;
|
|
453
709
|
isRevisionPreview;
|
|
454
710
|
sectionType;
|
|
711
|
+
// ─── Item-level translation sidecar (design mode only) ─────────────
|
|
712
|
+
/**
|
|
713
|
+
* Translation map received from Builder in design mode, keyed by item ID.
|
|
714
|
+
* `WeaverseNextItem.getSnapShot()` overlays these onto the data handed to
|
|
715
|
+
* components, so translations render without mutating the base `_store`.
|
|
716
|
+
*/
|
|
455
717
|
translationMap = {};
|
|
456
|
-
translationLocale =
|
|
457
|
-
translationLanguageId =
|
|
718
|
+
translationLocale = String();
|
|
719
|
+
translationLanguageId = String();
|
|
720
|
+
/**
|
|
721
|
+
* Fresh page data captured while React was rendering. Runtime reuse happens
|
|
722
|
+
* inside the renderer's render phase (`useMemo`), where applying it through
|
|
723
|
+
* `setProjectData()` would emit item updates to `useSyncExternalStore`
|
|
724
|
+
* subscribers mid-render. The renderer applies it post-commit via
|
|
725
|
+
* `flushRenderPhaseUpdates()`. Never set on design-mode runtimes — the live
|
|
726
|
+
* Studio tree owns the page data there.
|
|
727
|
+
*/
|
|
728
|
+
pendingProjectData;
|
|
729
|
+
/**
|
|
730
|
+
* Reused item instances whose data was refreshed while this runtime was
|
|
731
|
+
* constructed during render (core `initProject()` calls `setData()` on
|
|
732
|
+
* them). Their data is already fresh; only the subscriber notification was
|
|
733
|
+
* deferred to `flushRenderPhaseUpdates()`.
|
|
734
|
+
*/
|
|
735
|
+
pendingItemUpdates = [];
|
|
458
736
|
constructor(config) {
|
|
459
737
|
let { client, data } = config;
|
|
460
738
|
let page = getRenderablePage(data);
|
|
@@ -476,7 +754,9 @@ var WeaverseNextRuntime = class extends react.Weaverse {
|
|
|
476
754
|
this.isPreviewMode = requestContext?.isPreviewMode ?? false;
|
|
477
755
|
this.isRevisionPreview = requestContext?.isRevisionPreview ?? false;
|
|
478
756
|
this.sectionType = requestContext?.sectionType;
|
|
757
|
+
let translationStore = config.translationStore ?? new TranslationStore();
|
|
479
758
|
this.internal = {
|
|
759
|
+
merchantOverrides: config.merchantOverrides,
|
|
480
760
|
navigate: config.navigate,
|
|
481
761
|
pageAssignment: data.pageAssignment,
|
|
482
762
|
project: data.project,
|
|
@@ -484,17 +764,119 @@ var WeaverseNextRuntime = class extends react.Weaverse {
|
|
|
484
764
|
themeSettingsStore: config.themeSettingsStore ?? createWeaverseNextThemeSettingsStore({
|
|
485
765
|
schema: client?.themeSchema,
|
|
486
766
|
settings: client?.themeSettings
|
|
487
|
-
})
|
|
767
|
+
}),
|
|
768
|
+
translationStore,
|
|
769
|
+
themeTextStore: translationStore
|
|
488
770
|
};
|
|
771
|
+
this.extractTranslationSidecar();
|
|
489
772
|
}
|
|
490
|
-
|
|
773
|
+
/**
|
|
774
|
+
* Pull `translationMap` / `translationLocale` / `translationLanguageId` off
|
|
775
|
+
* the current page data (Builder attaches them in design mode). Unlike
|
|
776
|
+
* Hydrogen, this also clears the sidecar to defaults when the new page data
|
|
777
|
+
* carries none, so a reused runtime / project-data swap can't leave a stale
|
|
778
|
+
* map overlaying the fresh tree.
|
|
779
|
+
*/
|
|
780
|
+
extractTranslationSidecar = () => {
|
|
781
|
+
let pageData = this.data;
|
|
782
|
+
let translationMap = pageData?.translationMap;
|
|
783
|
+
if (translationMap) {
|
|
784
|
+
this.translationMap = translationMap;
|
|
785
|
+
this.translationLocale = pageData?.translationLocale || "";
|
|
786
|
+
this.translationLanguageId = pageData?.translationLanguageId || "";
|
|
787
|
+
} else {
|
|
788
|
+
this.translationMap = {};
|
|
789
|
+
this.translationLocale = "";
|
|
790
|
+
this.translationLanguageId = "";
|
|
791
|
+
}
|
|
792
|
+
};
|
|
793
|
+
/**
|
|
794
|
+
* Replace the translation sidecar (Builder pushes this when translation data
|
|
795
|
+
* arrives or the active language changes) and refresh every item so their
|
|
796
|
+
* merged snapshots recompute.
|
|
797
|
+
*/
|
|
491
798
|
setTranslationSidecar = (map = {}, locale = "", languageId = "") => {
|
|
492
799
|
this.translationMap = map;
|
|
493
800
|
this.translationLocale = locale;
|
|
494
801
|
this.translationLanguageId = languageId;
|
|
802
|
+
this.refreshAllItems();
|
|
803
|
+
};
|
|
804
|
+
/**
|
|
805
|
+
* Update a single translatable field for one item. Assigns a new per-item
|
|
806
|
+
* entry object so `WeaverseNextItem.getSnapShot()`'s translation-ref cache
|
|
807
|
+
* invalidates, then triggers only that item's subscribers.
|
|
808
|
+
*/
|
|
809
|
+
updateTranslation = (itemId, key, originalValue, translatedValue) => {
|
|
810
|
+
if (!this.translationMap[itemId]) {
|
|
811
|
+
this.translationMap[itemId] = {};
|
|
812
|
+
}
|
|
813
|
+
this.translationMap[itemId] = {
|
|
814
|
+
...this.translationMap[itemId],
|
|
815
|
+
[key]: { originalValue, translatedValue }
|
|
816
|
+
};
|
|
817
|
+
let instance = this.itemInstances.get(itemId);
|
|
818
|
+
if (instance) {
|
|
819
|
+
instance.triggerUpdate();
|
|
820
|
+
}
|
|
821
|
+
};
|
|
822
|
+
/**
|
|
823
|
+
* Collect translation changes for the save flow. Returns `undefined` unless
|
|
824
|
+
* both the locale and language ID are set and at least one entry exists;
|
|
825
|
+
* each entry key is namespaced as `data.<field>` to match Builder.
|
|
826
|
+
*/
|
|
827
|
+
getTranslationChanges = () => {
|
|
828
|
+
let languageId = this.translationLanguageId;
|
|
829
|
+
if (!(this.translationLocale && languageId)) {
|
|
830
|
+
return;
|
|
831
|
+
}
|
|
832
|
+
let entries = [];
|
|
833
|
+
for (let [itemId, fields] of Object.entries(this.translationMap)) {
|
|
834
|
+
for (let [key, entry] of Object.entries(fields)) {
|
|
835
|
+
entries.push({
|
|
836
|
+
itemId,
|
|
837
|
+
key: `data.${key}`,
|
|
838
|
+
originalValue: entry.originalValue,
|
|
839
|
+
translatedValue: entry.translatedValue
|
|
840
|
+
});
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
if (entries.length === 0) {
|
|
844
|
+
return;
|
|
845
|
+
}
|
|
846
|
+
return { languageId, entries };
|
|
847
|
+
};
|
|
848
|
+
/**
|
|
849
|
+
* Re-extract the translation sidecar whenever project data is replaced (route
|
|
850
|
+
* change / non-design reuse), before rebuilding item stores. Takes the
|
|
851
|
+
* renderable page shape (`rootId` resolved) that `getRenderablePage()` and
|
|
852
|
+
* the reuse branch pass in.
|
|
853
|
+
*/
|
|
854
|
+
setProjectData = (data) => {
|
|
855
|
+
this.data = data;
|
|
856
|
+
this.extractTranslationSidecar();
|
|
857
|
+
this.initProject();
|
|
858
|
+
};
|
|
859
|
+
/**
|
|
860
|
+
* Apply updates deferred off the render phase: swap in any pending page data
|
|
861
|
+
* captured on runtime reuse, then notify items whose data was refreshed
|
|
862
|
+
* during construction. The renderer calls this from a layout effect right
|
|
863
|
+
* after commit, so subscribers re-render before paint (no content flash) and
|
|
864
|
+
* without React's setState-in-render warning.
|
|
865
|
+
*/
|
|
866
|
+
flushRenderPhaseUpdates = () => {
|
|
867
|
+
let pendingData = this.pendingProjectData;
|
|
868
|
+
if (pendingData) {
|
|
869
|
+
this.pendingProjectData = void 0;
|
|
870
|
+
this.setProjectData(pendingData);
|
|
871
|
+
}
|
|
872
|
+
let pendingItems = this.pendingItemUpdates;
|
|
873
|
+
if (pendingItems.length > 0) {
|
|
874
|
+
this.pendingItemUpdates = [];
|
|
875
|
+
for (let item of pendingItems) {
|
|
876
|
+
item.triggerUpdate();
|
|
877
|
+
}
|
|
878
|
+
}
|
|
495
879
|
};
|
|
496
|
-
updateTranslation = () => void 0;
|
|
497
|
-
getTranslationChanges = () => void 0;
|
|
498
880
|
};
|
|
499
881
|
function createWeaverseNextRuntime(config) {
|
|
500
882
|
let requestInfo = buildWeaverseNextRequestInfo(config.client?.requestContext);
|
|
@@ -504,8 +886,10 @@ function createWeaverseNextRuntime(config) {
|
|
|
504
886
|
let requestKey = getRuntimeKey(page.id, requestInfo);
|
|
505
887
|
if (existing?.__weaverseNextRequestKey === requestKey) {
|
|
506
888
|
let nextIsDesignMode = config.client?.requestContext?.isDesignMode ?? false;
|
|
507
|
-
if (
|
|
508
|
-
existing.
|
|
889
|
+
if (existing.isDesignMode || nextIsDesignMode) {
|
|
890
|
+
existing.pendingProjectData = void 0;
|
|
891
|
+
} else {
|
|
892
|
+
existing.pendingProjectData = page;
|
|
509
893
|
}
|
|
510
894
|
existing.__weaverseNextLatestData = page;
|
|
511
895
|
existing.dataContext = resolveDataContext(config);
|
|
@@ -528,10 +912,18 @@ function createWeaverseNextRuntime(config) {
|
|
|
528
912
|
if (config.themeSettingsStore) {
|
|
529
913
|
existing.internal.themeSettingsStore = config.themeSettingsStore;
|
|
530
914
|
}
|
|
915
|
+
if (config.translationStore) {
|
|
916
|
+
existing.internal.translationStore = config.translationStore;
|
|
917
|
+
existing.internal.themeTextStore = config.translationStore;
|
|
918
|
+
}
|
|
919
|
+
existing.internal.merchantOverrides = config.merchantOverrides;
|
|
531
920
|
registerRuntime(existing);
|
|
532
921
|
return existing;
|
|
533
922
|
}
|
|
534
|
-
let runtime =
|
|
923
|
+
let [runtime, refreshedItems] = collectDeferredItemUpdates(
|
|
924
|
+
() => new WeaverseNextRuntime(config)
|
|
925
|
+
);
|
|
926
|
+
runtime.pendingItemUpdates = refreshedItems;
|
|
535
927
|
runtime.__weaverseNextRequestKey = requestKey;
|
|
536
928
|
runtime.__weaverseNextLatestData = page;
|
|
537
929
|
registerRuntime(runtime);
|
|
@@ -684,6 +1076,7 @@ function WeaverseNextStudio(props) {
|
|
|
684
1076
|
);
|
|
685
1077
|
}
|
|
686
1078
|
var EMPTY_DATA_CONTEXT = {};
|
|
1079
|
+
var useIsomorphicLayoutEffect = typeof window === "undefined" ? react$1.useEffect : react$1.useLayoutEffect;
|
|
687
1080
|
function getRenderablePage2(data) {
|
|
688
1081
|
let page = data?.page;
|
|
689
1082
|
if (!page) {
|
|
@@ -706,9 +1099,22 @@ var WeaverseNextRenderer = react$1.memo(function WeaverseNextRendererComponent(p
|
|
|
706
1099
|
client,
|
|
707
1100
|
data: { ...data, page },
|
|
708
1101
|
dataContext,
|
|
709
|
-
|
|
1102
|
+
merchantOverrides: context?.merchantOverrides,
|
|
1103
|
+
themeSettingsStore: context?.themeSettingsStore,
|
|
1104
|
+
translationStore: context?.translationStore
|
|
710
1105
|
});
|
|
711
|
-
}, [
|
|
1106
|
+
}, [
|
|
1107
|
+
client,
|
|
1108
|
+
page,
|
|
1109
|
+
data,
|
|
1110
|
+
dataContext,
|
|
1111
|
+
context?.merchantOverrides,
|
|
1112
|
+
context?.themeSettingsStore,
|
|
1113
|
+
context?.translationStore
|
|
1114
|
+
]);
|
|
1115
|
+
useIsomorphicLayoutEffect(() => {
|
|
1116
|
+
weaverse?.flushRenderPhaseUpdates();
|
|
1117
|
+
}, [weaverse]);
|
|
712
1118
|
if (!weaverse) {
|
|
713
1119
|
return null;
|
|
714
1120
|
}
|
|
@@ -916,6 +1322,10 @@ Object.defineProperty(exports, "createSchema", {
|
|
|
916
1322
|
get: function () { return schema.createSchema; }
|
|
917
1323
|
});
|
|
918
1324
|
exports.DEFAULT_REVALIDATE_ENDPOINT = DEFAULT_REVALIDATE_ENDPOINT;
|
|
1325
|
+
exports.ThemeTextProvider = ThemeTextProvider;
|
|
1326
|
+
exports.ThemeTextStore = ThemeTextStore;
|
|
1327
|
+
exports.TranslationProvider = TranslationProvider;
|
|
1328
|
+
exports.TranslationStore = TranslationStore;
|
|
919
1329
|
exports.WeaverseNextProvider = WeaverseNextProvider;
|
|
920
1330
|
exports.WeaverseNextRenderer = WeaverseNextRenderer;
|
|
921
1331
|
exports.WeaverseNextRootProvider = WeaverseNextRootProvider;
|
|
@@ -925,17 +1335,22 @@ exports.WeaverseNextStudioBridge = WeaverseNextStudioBridge;
|
|
|
925
1335
|
exports.WeaverseNextStudioConnect = WeaverseNextStudioConnect;
|
|
926
1336
|
exports.bindWeaverseNextStudioRuntime = bindWeaverseNextStudioRuntime;
|
|
927
1337
|
exports.buildWeaverseNextRequestInfo = buildWeaverseNextRequestInfo;
|
|
1338
|
+
exports.createTranslate = createTranslate;
|
|
928
1339
|
exports.createWeaverseNextClient = createWeaverseNextClient;
|
|
929
1340
|
exports.createWeaverseNextRuntime = createWeaverseNextRuntime;
|
|
930
1341
|
exports.createWeaverseNextStudioInternals = createWeaverseNextStudioInternals;
|
|
931
1342
|
exports.createWeaverseNextThemeSettingsStore = createWeaverseNextThemeSettingsStore;
|
|
932
1343
|
exports.formatWeaverseNextSeoMetadata = formatWeaverseNextSeoMetadata;
|
|
1344
|
+
exports.getNestedKey = getNestedKey;
|
|
933
1345
|
exports.getWeaverseNextSeoMetadata = getWeaverseNextSeoMetadata;
|
|
1346
|
+
exports.interpolate = interpolate;
|
|
934
1347
|
exports.loadWeaverseNextStudioScript = loadWeaverseNextStudioScript;
|
|
935
1348
|
exports.resolveWeaverseNextStudioScriptSrc = resolveWeaverseNextStudioScriptSrc;
|
|
936
1349
|
exports.revalidateWeaverseNextItem = revalidateWeaverseNextItem;
|
|
937
1350
|
exports.runWeaverseComponentLoaders = runWeaverseComponentLoaders;
|
|
938
1351
|
exports.useThemeSettings = useThemeSettings;
|
|
1352
|
+
exports.useThemeText = useThemeText;
|
|
1353
|
+
exports.useTranslation = useTranslation;
|
|
939
1354
|
exports.useWeaverseCommerce = useWeaverseCommerce;
|
|
940
1355
|
exports.useWeaverseNextStudioInternals = useWeaverseNextStudioInternals;
|
|
941
1356
|
exports.useWeaversePageData = useWeaversePageData;
|