@weaverse/next 0.1.0-alpha.1 → 0.1.0-alpha.11
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/README.md +521 -108
- package/dist/{chunk-SS6QUKYY.mjs → chunk-XXGMPTWH.mjs} +74 -4
- package/dist/chunk-XXGMPTWH.mjs.map +1 -0
- package/dist/index.d.mts +423 -16
- package/dist/index.d.ts +423 -16
- package/dist/index.js +678 -45
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +588 -46
- package/dist/index.mjs.map +1 -1
- package/dist/{types-DvEeLX6L.d.mts → seo-CgO21rLg.d.mts} +205 -9
- package/dist/{types-DvEeLX6L.d.ts → seo-CgO21rLg.d.ts} +205 -9
- package/dist/server.d.mts +43 -4
- package/dist/server.d.ts +43 -4
- package/dist/server.js +248 -18
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +177 -19
- package/dist/server.mjs.map +1 -1
- package/package.json +8 -3
- package/dist/chunk-SS6QUKYY.mjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,19 +1,91 @@
|
|
|
1
|
-
import { buildWeaverseNextRequestInfo, generateDataFromSchema } from './chunk-
|
|
2
|
-
export { buildWeaverseNextRequestInfo, runWeaverseComponentLoaders } from './chunk-
|
|
3
|
-
import { WeaverseRoot, Weaverse, WeaverseItemStore } from '@weaverse/react';
|
|
1
|
+
import { buildWeaverseNextRequestInfo, generateDataFromSchema } from './chunk-XXGMPTWH.mjs';
|
|
2
|
+
export { buildWeaverseNextRequestInfo, formatWeaverseNextSeoMetadata, generateDataFromSchema, getWeaverseNextSeoMetadata, runWeaverseComponentLoaders } from './chunk-XXGMPTWH.mjs';
|
|
3
|
+
import { WeaverseRoot, Weaverse, WeaverseItemStore, useSafeExternalStore } from '@weaverse/react';
|
|
4
4
|
export { isBrowser, isIframe, useChildInstances, useItemInstance, useParentInstance, useWeaverse } from '@weaverse/react';
|
|
5
5
|
import { createSchema } from '@weaverse/schema';
|
|
6
|
-
export
|
|
6
|
+
export * from '@weaverse/schema';
|
|
7
7
|
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
8
|
-
import { createContext, memo, useContext, useMemo,
|
|
8
|
+
import { createContext, memo, useContext, useMemo, useEffect, useLayoutEffect, useRef, useSyncExternalStore } from 'react';
|
|
9
|
+
import { useRouter } from 'next/navigation';
|
|
9
10
|
|
|
11
|
+
function flattenItemData(update) {
|
|
12
|
+
let { data, ...rest } = update;
|
|
13
|
+
if (!(data && typeof data === "object" && !Array.isArray(data))) {
|
|
14
|
+
return rest;
|
|
15
|
+
}
|
|
16
|
+
return { ...data, ...rest };
|
|
17
|
+
}
|
|
18
|
+
var deferredItemUpdates = null;
|
|
19
|
+
function collectDeferredItemUpdates(create) {
|
|
20
|
+
let previousQueue = deferredItemUpdates;
|
|
21
|
+
let queue = /* @__PURE__ */ new Set();
|
|
22
|
+
deferredItemUpdates = queue;
|
|
23
|
+
try {
|
|
24
|
+
return [create(), [...queue]];
|
|
25
|
+
} finally {
|
|
26
|
+
deferredItemUpdates = previousQueue;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
10
29
|
var WeaverseNextItem = class extends WeaverseItemStore {
|
|
30
|
+
/**
|
|
31
|
+
* Cached merged snapshot (base `_store` + translations). Reset whenever the
|
|
32
|
+
* `_store` ref or the item's translation entry ref changes, so
|
|
33
|
+
* `useSyncExternalStore` sees a stable object between unrelated re-renders.
|
|
34
|
+
*/
|
|
35
|
+
_cachedSnapshot = null;
|
|
36
|
+
_snapshotStoreRef = null;
|
|
37
|
+
_snapshotTranslationRef = null;
|
|
11
38
|
constructor(initialData, weaverse) {
|
|
12
39
|
super(initialData, weaverse);
|
|
13
|
-
let { data, ...rest } = initialData;
|
|
14
40
|
let schemaData = generateDataFromSchema(this.Element?.schema);
|
|
15
|
-
Object.assign(this._store, schemaData,
|
|
41
|
+
Object.assign(this._store, schemaData, flattenItemData(initialData));
|
|
16
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Flatten nested `data` on updates exactly like the constructor does. Core's
|
|
45
|
+
* `initProject()` calls `setData(item)` when a new runtime serves a page
|
|
46
|
+
* whose item instances already exist (e.g. locale/client navigation), and
|
|
47
|
+
* the inherited shallow merge would leave stale top-level props behind.
|
|
48
|
+
* Assigning through the inherited `data` setter swaps the `_store` ref,
|
|
49
|
+
* which invalidates the memoized snapshot below. The subscriber emit is
|
|
50
|
+
* queued instead of fired when a render-phase deferral is active (see
|
|
51
|
+
* `collectDeferredItemUpdates`).
|
|
52
|
+
*/
|
|
53
|
+
setData = (update) => {
|
|
54
|
+
this.data = flattenItemData(update);
|
|
55
|
+
if (deferredItemUpdates) {
|
|
56
|
+
deferredItemUpdates.add(this);
|
|
57
|
+
} else {
|
|
58
|
+
this.triggerUpdate();
|
|
59
|
+
}
|
|
60
|
+
return this.data;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Overlay item-level translations onto the base store when the runtime is in
|
|
64
|
+
* translation mode. Mirrors Hydrogen's `WeaverseHydrogenItem.getSnapShot()`:
|
|
65
|
+
* memoized by `_store` ref + translation entry ref so the returned object is
|
|
66
|
+
* referentially stable, and a fast path that returns the base store untouched
|
|
67
|
+
* when the item has no translations.
|
|
68
|
+
*/
|
|
69
|
+
getSnapShot = () => {
|
|
70
|
+
let base = this._store;
|
|
71
|
+
let translations = this.weaverse.translationMap[this._id];
|
|
72
|
+
if (!translations) {
|
|
73
|
+
return base;
|
|
74
|
+
}
|
|
75
|
+
if (this._cachedSnapshot && this._snapshotStoreRef === base && this._snapshotTranslationRef === translations) {
|
|
76
|
+
return this._cachedSnapshot;
|
|
77
|
+
}
|
|
78
|
+
let merged = { ...base };
|
|
79
|
+
for (let [key, entry] of Object.entries(translations)) {
|
|
80
|
+
if (entry.translatedValue !== void 0) {
|
|
81
|
+
merged[key] = entry.translatedValue;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
this._cachedSnapshot = merged;
|
|
85
|
+
this._snapshotStoreRef = base;
|
|
86
|
+
this._snapshotTranslationRef = translations;
|
|
87
|
+
return merged;
|
|
88
|
+
};
|
|
17
89
|
};
|
|
18
90
|
function ensureNextItemConstructor() {
|
|
19
91
|
if (!Weaverse.ItemConstructor || Weaverse.ItemConstructor === WeaverseItemStore || Weaverse.ItemConstructor === WeaverseNextItem) {
|
|
@@ -138,30 +210,258 @@ function createWeaverseNextThemeSettingsStore(options = {}) {
|
|
|
138
210
|
};
|
|
139
211
|
return store;
|
|
140
212
|
}
|
|
213
|
+
function getNestedKey(obj, path, fallback) {
|
|
214
|
+
let keys = path.split(".");
|
|
215
|
+
let current = obj;
|
|
216
|
+
for (let key of keys) {
|
|
217
|
+
if (current == null || typeof current !== "object") {
|
|
218
|
+
return fallback;
|
|
219
|
+
}
|
|
220
|
+
current = current[key];
|
|
221
|
+
}
|
|
222
|
+
if (typeof current === "string") {
|
|
223
|
+
return current;
|
|
224
|
+
}
|
|
225
|
+
return fallback;
|
|
226
|
+
}
|
|
227
|
+
function interpolate(template, variables) {
|
|
228
|
+
if (!variables) {
|
|
229
|
+
return template;
|
|
230
|
+
}
|
|
231
|
+
return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
|
|
232
|
+
let value = variables[key];
|
|
233
|
+
return value === void 0 ? match : String(value);
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
var TranslationContext = createContext(null);
|
|
237
|
+
TranslationContext.displayName = "WeaverseNextTranslationContext";
|
|
238
|
+
function createTranslate(sources) {
|
|
239
|
+
let { staticContent, merchantOverrides, designOverrides, externalT } = sources;
|
|
240
|
+
return (key, variables) => {
|
|
241
|
+
if (externalT) {
|
|
242
|
+
let external = externalT(key, variables);
|
|
243
|
+
if (external && external !== key) {
|
|
244
|
+
return external;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
let design = designOverrides && Object.hasOwn(designOverrides, key) ? designOverrides[key] : void 0;
|
|
248
|
+
let override = merchantOverrides ? getNestedKey(merchantOverrides, key) : void 0;
|
|
249
|
+
let staticValue = getNestedKey(staticContent, key);
|
|
250
|
+
let raw = design ?? override ?? staticValue ?? key;
|
|
251
|
+
return interpolate(raw, variables);
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
var EMPTY = {};
|
|
255
|
+
var NOOP_SUBSCRIBE = () => () => {
|
|
256
|
+
};
|
|
257
|
+
var NOOP_SNAPSHOT = () => EMPTY;
|
|
258
|
+
function TranslationProvider({
|
|
259
|
+
staticContent,
|
|
260
|
+
merchantOverrides,
|
|
261
|
+
t: externalT,
|
|
262
|
+
translationStore,
|
|
263
|
+
themeTextStore,
|
|
264
|
+
children
|
|
265
|
+
}) {
|
|
266
|
+
let store = translationStore ?? themeTextStore ?? null;
|
|
267
|
+
let designOverrides = useSafeExternalStore(
|
|
268
|
+
store?.subscribe ?? NOOP_SUBSCRIBE,
|
|
269
|
+
store?.getSnapshot ?? NOOP_SNAPSHOT,
|
|
270
|
+
store?.getServerSnapshot ?? NOOP_SNAPSHOT
|
|
271
|
+
);
|
|
272
|
+
let value = useMemo(
|
|
273
|
+
() => ({
|
|
274
|
+
t: createTranslate({
|
|
275
|
+
staticContent,
|
|
276
|
+
merchantOverrides,
|
|
277
|
+
designOverrides,
|
|
278
|
+
externalT
|
|
279
|
+
}),
|
|
280
|
+
translationStore: store,
|
|
281
|
+
// Deprecated alias — same instance, kept for backward compatibility.
|
|
282
|
+
themeTextStore: store,
|
|
283
|
+
merchantOverrides: merchantOverrides ?? null
|
|
284
|
+
}),
|
|
285
|
+
[staticContent, merchantOverrides, designOverrides, externalT, store]
|
|
286
|
+
);
|
|
287
|
+
return /* @__PURE__ */ jsx(TranslationContext.Provider, { value, children });
|
|
288
|
+
}
|
|
289
|
+
function useTranslation() {
|
|
290
|
+
let ctx = useContext(TranslationContext);
|
|
291
|
+
if (!ctx) {
|
|
292
|
+
throw new Error(
|
|
293
|
+
"useTranslation must be used within <TranslationProvider>. Wrap your app with <WeaverseNextRootProvider>."
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
return ctx;
|
|
297
|
+
}
|
|
298
|
+
var ThemeTextProvider = TranslationProvider;
|
|
299
|
+
var useThemeText = useTranslation;
|
|
300
|
+
|
|
301
|
+
// src/translation-store.ts
|
|
302
|
+
var TranslationStore = class {
|
|
303
|
+
overrides = {};
|
|
304
|
+
listeners = /* @__PURE__ */ new Set();
|
|
305
|
+
setOverrides = (overrides) => {
|
|
306
|
+
this.overrides = { ...overrides };
|
|
307
|
+
this.emit();
|
|
308
|
+
};
|
|
309
|
+
updateOverrides = (newOverrides) => {
|
|
310
|
+
this.overrides = { ...this.overrides, ...newOverrides };
|
|
311
|
+
this.emit();
|
|
312
|
+
};
|
|
313
|
+
getSnapshot = () => this.overrides;
|
|
314
|
+
getServerSnapshot = () => this.overrides;
|
|
315
|
+
subscribe = (callback) => {
|
|
316
|
+
this.listeners.add(callback);
|
|
317
|
+
return () => {
|
|
318
|
+
this.listeners.delete(callback);
|
|
319
|
+
};
|
|
320
|
+
};
|
|
321
|
+
emit = () => {
|
|
322
|
+
for (const listener of Array.from(this.listeners)) {
|
|
323
|
+
try {
|
|
324
|
+
listener();
|
|
325
|
+
} catch (error) {
|
|
326
|
+
console.error("TranslationStore: Listener error", error);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
};
|
|
331
|
+
var ThemeTextStore = TranslationStore;
|
|
332
|
+
var WeaverseNextRootContext = createContext(null);
|
|
333
|
+
function WeaverseNextRootProvider(props) {
|
|
334
|
+
let {
|
|
335
|
+
children,
|
|
336
|
+
initialThemeSettings,
|
|
337
|
+
merchantOverrides,
|
|
338
|
+
staticContent,
|
|
339
|
+
t,
|
|
340
|
+
themeSchema,
|
|
341
|
+
publicEnv
|
|
342
|
+
} = props;
|
|
343
|
+
let storeRef = useRef(null);
|
|
344
|
+
if (!storeRef.current) {
|
|
345
|
+
storeRef.current = createWeaverseNextThemeSettingsStore({
|
|
346
|
+
publicEnv,
|
|
347
|
+
schema: themeSchema,
|
|
348
|
+
settings: initialThemeSettings
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
let themeSettingsStore = storeRef.current;
|
|
352
|
+
let translationStoreRef = useRef(null);
|
|
353
|
+
if (!translationStoreRef.current) {
|
|
354
|
+
translationStoreRef.current = new TranslationStore();
|
|
355
|
+
}
|
|
356
|
+
let translationStore = translationStoreRef.current;
|
|
357
|
+
let appliedThemeSettingsRef = useRef(initialThemeSettings);
|
|
358
|
+
useEffect(() => {
|
|
359
|
+
if (initialThemeSettings && appliedThemeSettingsRef.current !== initialThemeSettings) {
|
|
360
|
+
themeSettingsStore.updateThemeSettings(initialThemeSettings);
|
|
361
|
+
appliedThemeSettingsRef.current = initialThemeSettings;
|
|
362
|
+
}
|
|
363
|
+
}, [initialThemeSettings, themeSettingsStore]);
|
|
364
|
+
let resolvedStaticContent = staticContent ?? getSchemaStaticContent(themeSchema);
|
|
365
|
+
let rootContextValue = useMemo(
|
|
366
|
+
() => ({
|
|
367
|
+
merchantOverrides,
|
|
368
|
+
staticContent: resolvedStaticContent,
|
|
369
|
+
themeSettingsStore,
|
|
370
|
+
translationStore
|
|
371
|
+
}),
|
|
372
|
+
[
|
|
373
|
+
merchantOverrides,
|
|
374
|
+
resolvedStaticContent,
|
|
375
|
+
themeSettingsStore,
|
|
376
|
+
translationStore
|
|
377
|
+
]
|
|
378
|
+
);
|
|
379
|
+
let contextValue = useMemo(
|
|
380
|
+
() => ({
|
|
381
|
+
merchantOverrides,
|
|
382
|
+
themeSettings: themeSettingsStore.getSnapshot(),
|
|
383
|
+
themeSettingsStore,
|
|
384
|
+
translationStore
|
|
385
|
+
}),
|
|
386
|
+
[merchantOverrides, themeSettingsStore, translationStore]
|
|
387
|
+
);
|
|
388
|
+
return /* @__PURE__ */ jsx(WeaverseNextRootContext.Provider, { value: rootContextValue, children: /* @__PURE__ */ jsx(WeaverseNextContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(
|
|
389
|
+
TranslationProvider,
|
|
390
|
+
{
|
|
391
|
+
merchantOverrides,
|
|
392
|
+
staticContent: resolvedStaticContent,
|
|
393
|
+
t,
|
|
394
|
+
translationStore,
|
|
395
|
+
children
|
|
396
|
+
}
|
|
397
|
+
) }) });
|
|
398
|
+
}
|
|
141
399
|
var EMPTY_THEME_SETTINGS = {};
|
|
400
|
+
var EMPTY_STATIC_CONTENT = {};
|
|
401
|
+
function getSchemaStaticContent(schema) {
|
|
402
|
+
let i18n = schema?.i18n;
|
|
403
|
+
return i18n?.staticContent ?? EMPTY_STATIC_CONTENT;
|
|
404
|
+
}
|
|
142
405
|
var WeaverseNextContext = createContext(null);
|
|
143
406
|
function WeaverseNextProvider(props) {
|
|
144
407
|
let { children, client, rootData, pageData, commerce, themeSettings } = props;
|
|
408
|
+
let rootContext = useContext(WeaverseNextRootContext);
|
|
145
409
|
let themeSettingsValue = themeSettings ?? client?.themeSettings ?? EMPTY_THEME_SETTINGS;
|
|
146
|
-
let
|
|
147
|
-
|
|
410
|
+
let ownTranslationStoreRef = useRef(null);
|
|
411
|
+
if (!(rootContext || ownTranslationStoreRef.current)) {
|
|
412
|
+
ownTranslationStoreRef.current = new TranslationStore();
|
|
413
|
+
}
|
|
414
|
+
let translationStore = rootContext?.translationStore ?? ownTranslationStoreRef.current;
|
|
415
|
+
let staticContent = props.staticContent ?? rootContext?.staticContent ?? getSchemaStaticContent(client?.themeSchema);
|
|
416
|
+
let merchantOverrides = props.merchantOverrides ?? rootContext?.merchantOverrides;
|
|
417
|
+
let ownThemeSettingsStore = useMemo(() => {
|
|
418
|
+
if (rootContext) {
|
|
419
|
+
return null;
|
|
420
|
+
}
|
|
421
|
+
return createWeaverseNextThemeSettingsStore({
|
|
148
422
|
schema: client?.themeSchema,
|
|
149
423
|
settings: themeSettingsValue
|
|
150
|
-
})
|
|
151
|
-
|
|
152
|
-
|
|
424
|
+
});
|
|
425
|
+
}, [rootContext, client?.themeSchema, themeSettingsValue]);
|
|
426
|
+
let themeSettingsStore = rootContext?.themeSettingsStore ?? ownThemeSettingsStore;
|
|
427
|
+
let mergedIntoRootRef = useRef(void 0);
|
|
428
|
+
useEffect(() => {
|
|
429
|
+
if (rootContext && themeSettingsValue !== EMPTY_THEME_SETTINGS && mergedIntoRootRef.current !== themeSettingsValue) {
|
|
430
|
+
rootContext.themeSettingsStore.updateThemeSettings(themeSettingsValue);
|
|
431
|
+
mergedIntoRootRef.current = themeSettingsValue;
|
|
432
|
+
}
|
|
433
|
+
}, [rootContext, themeSettingsValue]);
|
|
153
434
|
let value = useMemo(
|
|
154
435
|
() => ({
|
|
155
436
|
client,
|
|
156
437
|
rootData,
|
|
157
438
|
pageData,
|
|
158
439
|
commerce: commerce ?? client?.commerce,
|
|
440
|
+
merchantOverrides,
|
|
159
441
|
themeSettings: themeSettingsStore.getSnapshot(),
|
|
160
|
-
themeSettingsStore
|
|
442
|
+
themeSettingsStore,
|
|
443
|
+
translationStore
|
|
161
444
|
}),
|
|
162
|
-
[
|
|
445
|
+
[
|
|
446
|
+
client,
|
|
447
|
+
rootData,
|
|
448
|
+
pageData,
|
|
449
|
+
commerce,
|
|
450
|
+
merchantOverrides,
|
|
451
|
+
themeSettingsStore,
|
|
452
|
+
translationStore
|
|
453
|
+
]
|
|
163
454
|
);
|
|
164
|
-
return /* @__PURE__ */ jsx(WeaverseNextContext.Provider, { value, children
|
|
455
|
+
return /* @__PURE__ */ jsx(WeaverseNextContext.Provider, { value, children: /* @__PURE__ */ jsx(
|
|
456
|
+
TranslationProvider,
|
|
457
|
+
{
|
|
458
|
+
merchantOverrides,
|
|
459
|
+
staticContent,
|
|
460
|
+
t: props.t,
|
|
461
|
+
translationStore,
|
|
462
|
+
children
|
|
463
|
+
}
|
|
464
|
+
) });
|
|
165
465
|
}
|
|
166
466
|
|
|
167
467
|
// src/hooks.ts
|
|
@@ -245,9 +545,31 @@ var WeaverseNextRuntime = class extends Weaverse {
|
|
|
245
545
|
isPreviewMode;
|
|
246
546
|
isRevisionPreview;
|
|
247
547
|
sectionType;
|
|
548
|
+
// ─── Item-level translation sidecar (design mode only) ─────────────
|
|
549
|
+
/**
|
|
550
|
+
* Translation map received from Builder in design mode, keyed by item ID.
|
|
551
|
+
* `WeaverseNextItem.getSnapShot()` overlays these onto the data handed to
|
|
552
|
+
* components, so translations render without mutating the base `_store`.
|
|
553
|
+
*/
|
|
248
554
|
translationMap = {};
|
|
249
|
-
translationLocale =
|
|
250
|
-
translationLanguageId =
|
|
555
|
+
translationLocale = String();
|
|
556
|
+
translationLanguageId = String();
|
|
557
|
+
/**
|
|
558
|
+
* Fresh page data captured while React was rendering. Runtime reuse happens
|
|
559
|
+
* inside the renderer's render phase (`useMemo`), where applying it through
|
|
560
|
+
* `setProjectData()` would emit item updates to `useSyncExternalStore`
|
|
561
|
+
* subscribers mid-render. The renderer applies it post-commit via
|
|
562
|
+
* `flushRenderPhaseUpdates()`. Never set on design-mode runtimes — the live
|
|
563
|
+
* Studio tree owns the page data there.
|
|
564
|
+
*/
|
|
565
|
+
pendingProjectData;
|
|
566
|
+
/**
|
|
567
|
+
* Reused item instances whose data was refreshed while this runtime was
|
|
568
|
+
* constructed during render (core `initProject()` calls `setData()` on
|
|
569
|
+
* them). Their data is already fresh; only the subscriber notification was
|
|
570
|
+
* deferred to `flushRenderPhaseUpdates()`.
|
|
571
|
+
*/
|
|
572
|
+
pendingItemUpdates = [];
|
|
251
573
|
constructor(config) {
|
|
252
574
|
let { client, data } = config;
|
|
253
575
|
let page = getRenderablePage(data);
|
|
@@ -269,7 +591,9 @@ var WeaverseNextRuntime = class extends Weaverse {
|
|
|
269
591
|
this.isPreviewMode = requestContext?.isPreviewMode ?? false;
|
|
270
592
|
this.isRevisionPreview = requestContext?.isRevisionPreview ?? false;
|
|
271
593
|
this.sectionType = requestContext?.sectionType;
|
|
594
|
+
let translationStore = config.translationStore ?? new TranslationStore();
|
|
272
595
|
this.internal = {
|
|
596
|
+
merchantOverrides: config.merchantOverrides,
|
|
273
597
|
navigate: config.navigate,
|
|
274
598
|
pageAssignment: data.pageAssignment,
|
|
275
599
|
project: data.project,
|
|
@@ -277,17 +601,119 @@ var WeaverseNextRuntime = class extends Weaverse {
|
|
|
277
601
|
themeSettingsStore: config.themeSettingsStore ?? createWeaverseNextThemeSettingsStore({
|
|
278
602
|
schema: client?.themeSchema,
|
|
279
603
|
settings: client?.themeSettings
|
|
280
|
-
})
|
|
604
|
+
}),
|
|
605
|
+
translationStore,
|
|
606
|
+
themeTextStore: translationStore
|
|
281
607
|
};
|
|
608
|
+
this.extractTranslationSidecar();
|
|
282
609
|
}
|
|
283
|
-
|
|
610
|
+
/**
|
|
611
|
+
* Pull `translationMap` / `translationLocale` / `translationLanguageId` off
|
|
612
|
+
* the current page data (Builder attaches them in design mode). Unlike
|
|
613
|
+
* Hydrogen, this also clears the sidecar to defaults when the new page data
|
|
614
|
+
* carries none, so a reused runtime / project-data swap can't leave a stale
|
|
615
|
+
* map overlaying the fresh tree.
|
|
616
|
+
*/
|
|
617
|
+
extractTranslationSidecar = () => {
|
|
618
|
+
let pageData = this.data;
|
|
619
|
+
let translationMap = pageData?.translationMap;
|
|
620
|
+
if (translationMap) {
|
|
621
|
+
this.translationMap = translationMap;
|
|
622
|
+
this.translationLocale = pageData?.translationLocale || "";
|
|
623
|
+
this.translationLanguageId = pageData?.translationLanguageId || "";
|
|
624
|
+
} else {
|
|
625
|
+
this.translationMap = {};
|
|
626
|
+
this.translationLocale = "";
|
|
627
|
+
this.translationLanguageId = "";
|
|
628
|
+
}
|
|
629
|
+
};
|
|
630
|
+
/**
|
|
631
|
+
* Replace the translation sidecar (Builder pushes this when translation data
|
|
632
|
+
* arrives or the active language changes) and refresh every item so their
|
|
633
|
+
* merged snapshots recompute.
|
|
634
|
+
*/
|
|
284
635
|
setTranslationSidecar = (map = {}, locale = "", languageId = "") => {
|
|
285
636
|
this.translationMap = map;
|
|
286
637
|
this.translationLocale = locale;
|
|
287
638
|
this.translationLanguageId = languageId;
|
|
639
|
+
this.refreshAllItems();
|
|
640
|
+
};
|
|
641
|
+
/**
|
|
642
|
+
* Update a single translatable field for one item. Assigns a new per-item
|
|
643
|
+
* entry object so `WeaverseNextItem.getSnapShot()`'s translation-ref cache
|
|
644
|
+
* invalidates, then triggers only that item's subscribers.
|
|
645
|
+
*/
|
|
646
|
+
updateTranslation = (itemId, key, originalValue, translatedValue) => {
|
|
647
|
+
if (!this.translationMap[itemId]) {
|
|
648
|
+
this.translationMap[itemId] = {};
|
|
649
|
+
}
|
|
650
|
+
this.translationMap[itemId] = {
|
|
651
|
+
...this.translationMap[itemId],
|
|
652
|
+
[key]: { originalValue, translatedValue }
|
|
653
|
+
};
|
|
654
|
+
let instance = this.itemInstances.get(itemId);
|
|
655
|
+
if (instance) {
|
|
656
|
+
instance.triggerUpdate();
|
|
657
|
+
}
|
|
658
|
+
};
|
|
659
|
+
/**
|
|
660
|
+
* Collect translation changes for the save flow. Returns `undefined` unless
|
|
661
|
+
* both the locale and language ID are set and at least one entry exists;
|
|
662
|
+
* each entry key is namespaced as `data.<field>` to match Builder.
|
|
663
|
+
*/
|
|
664
|
+
getTranslationChanges = () => {
|
|
665
|
+
let languageId = this.translationLanguageId;
|
|
666
|
+
if (!(this.translationLocale && languageId)) {
|
|
667
|
+
return;
|
|
668
|
+
}
|
|
669
|
+
let entries = [];
|
|
670
|
+
for (let [itemId, fields] of Object.entries(this.translationMap)) {
|
|
671
|
+
for (let [key, entry] of Object.entries(fields)) {
|
|
672
|
+
entries.push({
|
|
673
|
+
itemId,
|
|
674
|
+
key: `data.${key}`,
|
|
675
|
+
originalValue: entry.originalValue,
|
|
676
|
+
translatedValue: entry.translatedValue
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
if (entries.length === 0) {
|
|
681
|
+
return;
|
|
682
|
+
}
|
|
683
|
+
return { languageId, entries };
|
|
684
|
+
};
|
|
685
|
+
/**
|
|
686
|
+
* Re-extract the translation sidecar whenever project data is replaced (route
|
|
687
|
+
* change / non-design reuse), before rebuilding item stores. Takes the
|
|
688
|
+
* renderable page shape (`rootId` resolved) that `getRenderablePage()` and
|
|
689
|
+
* the reuse branch pass in.
|
|
690
|
+
*/
|
|
691
|
+
setProjectData = (data) => {
|
|
692
|
+
this.data = data;
|
|
693
|
+
this.extractTranslationSidecar();
|
|
694
|
+
this.initProject();
|
|
695
|
+
};
|
|
696
|
+
/**
|
|
697
|
+
* Apply updates deferred off the render phase: swap in any pending page data
|
|
698
|
+
* captured on runtime reuse, then notify items whose data was refreshed
|
|
699
|
+
* during construction. The renderer calls this from a layout effect right
|
|
700
|
+
* after commit, so subscribers re-render before paint (no content flash) and
|
|
701
|
+
* without React's setState-in-render warning.
|
|
702
|
+
*/
|
|
703
|
+
flushRenderPhaseUpdates = () => {
|
|
704
|
+
let pendingData = this.pendingProjectData;
|
|
705
|
+
if (pendingData) {
|
|
706
|
+
this.pendingProjectData = void 0;
|
|
707
|
+
this.setProjectData(pendingData);
|
|
708
|
+
}
|
|
709
|
+
let pendingItems = this.pendingItemUpdates;
|
|
710
|
+
if (pendingItems.length > 0) {
|
|
711
|
+
this.pendingItemUpdates = [];
|
|
712
|
+
for (let item of pendingItems) {
|
|
713
|
+
item.triggerUpdate();
|
|
714
|
+
}
|
|
715
|
+
}
|
|
288
716
|
};
|
|
289
|
-
updateTranslation = () => void 0;
|
|
290
|
-
getTranslationChanges = () => void 0;
|
|
291
717
|
};
|
|
292
718
|
function createWeaverseNextRuntime(config) {
|
|
293
719
|
let requestInfo = buildWeaverseNextRequestInfo(config.client?.requestContext);
|
|
@@ -297,9 +723,12 @@ function createWeaverseNextRuntime(config) {
|
|
|
297
723
|
let requestKey = getRuntimeKey(page.id, requestInfo);
|
|
298
724
|
if (existing?.__weaverseNextRequestKey === requestKey) {
|
|
299
725
|
let nextIsDesignMode = config.client?.requestContext?.isDesignMode ?? false;
|
|
300
|
-
if (
|
|
301
|
-
existing.
|
|
726
|
+
if (existing.isDesignMode || nextIsDesignMode) {
|
|
727
|
+
existing.pendingProjectData = void 0;
|
|
728
|
+
} else {
|
|
729
|
+
existing.pendingProjectData = page;
|
|
302
730
|
}
|
|
731
|
+
existing.__weaverseNextLatestData = page;
|
|
303
732
|
existing.dataContext = resolveDataContext(config);
|
|
304
733
|
existing.requestInfo = requestInfo;
|
|
305
734
|
existing.projectId = resolveProjectId(config.client, config.data, page.id);
|
|
@@ -320,11 +749,20 @@ function createWeaverseNextRuntime(config) {
|
|
|
320
749
|
if (config.themeSettingsStore) {
|
|
321
750
|
existing.internal.themeSettingsStore = config.themeSettingsStore;
|
|
322
751
|
}
|
|
752
|
+
if (config.translationStore) {
|
|
753
|
+
existing.internal.translationStore = config.translationStore;
|
|
754
|
+
existing.internal.themeTextStore = config.translationStore;
|
|
755
|
+
}
|
|
756
|
+
existing.internal.merchantOverrides = config.merchantOverrides;
|
|
323
757
|
registerRuntime(existing);
|
|
324
758
|
return existing;
|
|
325
759
|
}
|
|
326
|
-
let runtime =
|
|
760
|
+
let [runtime, refreshedItems] = collectDeferredItemUpdates(
|
|
761
|
+
() => new WeaverseNextRuntime(config)
|
|
762
|
+
);
|
|
763
|
+
runtime.pendingItemUpdates = refreshedItems;
|
|
327
764
|
runtime.__weaverseNextRequestKey = requestKey;
|
|
765
|
+
runtime.__weaverseNextLatestData = page;
|
|
328
766
|
registerRuntime(runtime);
|
|
329
767
|
return runtime;
|
|
330
768
|
}
|
|
@@ -337,22 +775,48 @@ function bindWeaverseNextStudioRuntime(runtime) {
|
|
|
337
775
|
return false;
|
|
338
776
|
}
|
|
339
777
|
let boundRuntime = runtime;
|
|
340
|
-
|
|
778
|
+
let activeRuntime = studio.weaverse;
|
|
779
|
+
let activeRequestInfo = activeRuntime?.requestInfo;
|
|
780
|
+
let isActiveUrl = !activeRequestInfo || activeRequestInfo.pathname === runtime.requestInfo.pathname && activeRequestInfo.search === runtime.requestInfo.search;
|
|
781
|
+
if (!(boundRuntime.__weaverseNextStudioBound && isActiveUrl)) {
|
|
341
782
|
studio.init?.(runtime);
|
|
342
783
|
boundRuntime.__weaverseNextStudioBound = true;
|
|
343
784
|
return true;
|
|
344
785
|
}
|
|
345
786
|
studio.refreshStudio?.({
|
|
346
|
-
data: runtime.data,
|
|
787
|
+
data: boundRuntime.__weaverseNextLatestData ?? runtime.data,
|
|
347
788
|
pageId: runtime.pageId,
|
|
348
789
|
requestInfo: runtime.requestInfo
|
|
349
790
|
});
|
|
350
791
|
return true;
|
|
351
792
|
}
|
|
793
|
+
|
|
794
|
+
// src/revalidate-item.ts
|
|
795
|
+
var DEFAULT_REVALIDATE_ENDPOINT = "/api/weaverse/revalidate";
|
|
796
|
+
async function revalidateWeaverseNextItem(runtime, draftItem, endpoint = DEFAULT_REVALIDATE_ENDPOINT) {
|
|
797
|
+
let instance = runtime.itemInstances.get(draftItem.id);
|
|
798
|
+
if (!instance) {
|
|
799
|
+
throw new Error(
|
|
800
|
+
`[weaverse-next] No live item instance for "${draftItem.id}".`
|
|
801
|
+
);
|
|
802
|
+
}
|
|
803
|
+
let response = await fetch(endpoint, {
|
|
804
|
+
method: "POST",
|
|
805
|
+
headers: { "Content-Type": "application/json" },
|
|
806
|
+
body: JSON.stringify({ draftItem })
|
|
807
|
+
});
|
|
808
|
+
if (!response.ok) {
|
|
809
|
+
throw new Error(
|
|
810
|
+
`[weaverse-next] Revalidate endpoint responded ${response.status}.`
|
|
811
|
+
);
|
|
812
|
+
}
|
|
813
|
+
let { loaderData } = await response.json();
|
|
814
|
+
instance.setData({ loaderData: loaderData ?? null });
|
|
815
|
+
}
|
|
352
816
|
var STUDIO_BIND_RETRY_INTERVAL_MS = 50;
|
|
353
817
|
var STUDIO_BIND_MAX_ATTEMPTS = 100;
|
|
354
818
|
function WeaverseNextStudioBridge(props) {
|
|
355
|
-
let { runtime, navigate, revalidate } = props;
|
|
819
|
+
let { runtime, navigate, revalidate, revalidateItem } = props;
|
|
356
820
|
let lastRuntimeRef = useRef(runtime);
|
|
357
821
|
let lastRuntimeDataRef = useRef(runtime.data);
|
|
358
822
|
let lastRequestInfoRef = useRef(runtime.requestInfo);
|
|
@@ -363,6 +827,9 @@ function WeaverseNextStudioBridge(props) {
|
|
|
363
827
|
if (revalidate) {
|
|
364
828
|
runtime.internal.revalidate = revalidate;
|
|
365
829
|
}
|
|
830
|
+
if (revalidateItem) {
|
|
831
|
+
runtime.internal.revalidateItem = revalidateItem;
|
|
832
|
+
}
|
|
366
833
|
if (bindWeaverseNextStudioRuntime(runtime) || !runtime.isDesignMode) {
|
|
367
834
|
return;
|
|
368
835
|
}
|
|
@@ -374,7 +841,7 @@ function WeaverseNextStudioBridge(props) {
|
|
|
374
841
|
}
|
|
375
842
|
}, STUDIO_BIND_RETRY_INTERVAL_MS);
|
|
376
843
|
return () => window.clearInterval(interval);
|
|
377
|
-
}, [runtime, navigate, revalidate]);
|
|
844
|
+
}, [runtime, navigate, revalidate, revalidateItem]);
|
|
378
845
|
useEffect(() => {
|
|
379
846
|
if (lastRuntimeRef.current !== runtime) {
|
|
380
847
|
lastRuntimeRef.current = runtime;
|
|
@@ -391,7 +858,65 @@ function WeaverseNextStudioBridge(props) {
|
|
|
391
858
|
}, [runtime, runtime.data, runtime.requestInfo]);
|
|
392
859
|
return null;
|
|
393
860
|
}
|
|
861
|
+
|
|
862
|
+
// src/studio-router.ts
|
|
863
|
+
function shouldResetScroll(options) {
|
|
864
|
+
if (!options || typeof options !== "object") {
|
|
865
|
+
return true;
|
|
866
|
+
}
|
|
867
|
+
return !options.preventScrollReset;
|
|
868
|
+
}
|
|
869
|
+
function createWeaverseNextStudioInternals(router, options = {}) {
|
|
870
|
+
return {
|
|
871
|
+
navigate: (to, navigateOptions) => {
|
|
872
|
+
let scroll = shouldResetScroll(navigateOptions);
|
|
873
|
+
if (options.replace) {
|
|
874
|
+
router.replace(to, { scroll });
|
|
875
|
+
} else {
|
|
876
|
+
router.push(to, { scroll });
|
|
877
|
+
}
|
|
878
|
+
},
|
|
879
|
+
revalidate: () => {
|
|
880
|
+
router.refresh();
|
|
881
|
+
}
|
|
882
|
+
};
|
|
883
|
+
}
|
|
884
|
+
function useWeaverseNextStudioInternals(options) {
|
|
885
|
+
let router = useRouter();
|
|
886
|
+
let ref = useRef(null);
|
|
887
|
+
if (!ref.current || ref.current.router !== router || ref.current.replace !== options?.replace) {
|
|
888
|
+
ref.current = {
|
|
889
|
+
internals: createWeaverseNextStudioInternals(router, options),
|
|
890
|
+
replace: options?.replace,
|
|
891
|
+
router
|
|
892
|
+
};
|
|
893
|
+
}
|
|
894
|
+
return ref.current.internals;
|
|
895
|
+
}
|
|
896
|
+
function WeaverseNextStudio(props) {
|
|
897
|
+
let { runtime, replace, revalidateEndpoint } = props;
|
|
898
|
+
let { navigate, revalidate } = useWeaverseNextStudioInternals({ replace });
|
|
899
|
+
let endpoint = revalidateEndpoint ?? DEFAULT_REVALIDATE_ENDPOINT;
|
|
900
|
+
let revalidateItemRef = useRef(null);
|
|
901
|
+
if (revalidateItemRef.current?.endpoint !== endpoint || revalidateItemRef.current.runtime !== runtime) {
|
|
902
|
+
revalidateItemRef.current = {
|
|
903
|
+
endpoint,
|
|
904
|
+
revalidateItem: (draftItem) => revalidateWeaverseNextItem(runtime, draftItem, endpoint),
|
|
905
|
+
runtime
|
|
906
|
+
};
|
|
907
|
+
}
|
|
908
|
+
return /* @__PURE__ */ jsx(
|
|
909
|
+
WeaverseNextStudioBridge,
|
|
910
|
+
{
|
|
911
|
+
navigate,
|
|
912
|
+
revalidate,
|
|
913
|
+
revalidateItem: revalidateItemRef.current.revalidateItem,
|
|
914
|
+
runtime
|
|
915
|
+
}
|
|
916
|
+
);
|
|
917
|
+
}
|
|
394
918
|
var EMPTY_DATA_CONTEXT = {};
|
|
919
|
+
var useIsomorphicLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect;
|
|
395
920
|
function getRenderablePage2(data) {
|
|
396
921
|
let page = data?.page;
|
|
397
922
|
if (!page) {
|
|
@@ -414,15 +939,28 @@ var WeaverseNextRenderer = memo(function WeaverseNextRendererComponent(props) {
|
|
|
414
939
|
client,
|
|
415
940
|
data: { ...data, page },
|
|
416
941
|
dataContext,
|
|
417
|
-
|
|
942
|
+
merchantOverrides: context?.merchantOverrides,
|
|
943
|
+
themeSettingsStore: context?.themeSettingsStore,
|
|
944
|
+
translationStore: context?.translationStore
|
|
418
945
|
});
|
|
419
|
-
}, [
|
|
946
|
+
}, [
|
|
947
|
+
client,
|
|
948
|
+
page,
|
|
949
|
+
data,
|
|
950
|
+
dataContext,
|
|
951
|
+
context?.merchantOverrides,
|
|
952
|
+
context?.themeSettingsStore,
|
|
953
|
+
context?.translationStore
|
|
954
|
+
]);
|
|
955
|
+
useIsomorphicLayoutEffect(() => {
|
|
956
|
+
weaverse?.flushRenderPhaseUpdates();
|
|
957
|
+
}, [weaverse]);
|
|
420
958
|
if (!weaverse) {
|
|
421
959
|
return null;
|
|
422
960
|
}
|
|
423
961
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
424
962
|
/* @__PURE__ */ jsx(WeaverseRoot, { context: weaverse }),
|
|
425
|
-
/* @__PURE__ */ jsx(
|
|
963
|
+
/* @__PURE__ */ jsx(WeaverseNextStudio, { runtime: weaverse })
|
|
426
964
|
] });
|
|
427
965
|
});
|
|
428
966
|
|
|
@@ -489,10 +1027,9 @@ function resolveWeaverseNextStudioScriptSrc(context, options = {}) {
|
|
|
489
1027
|
if (!isTrustedStudioOrigin(origin, storefrontHostname)) {
|
|
490
1028
|
return null;
|
|
491
1029
|
}
|
|
492
|
-
let framework = options.framework ?? "hydrogen";
|
|
493
1030
|
let bundle = isDesignMode ? "index.js" : "preview.js";
|
|
494
1031
|
let version = last(searchParams, "weaverseVersion");
|
|
495
|
-
let url = `${origin}/static/studio/${
|
|
1032
|
+
let url = `${origin}/static/studio/next/${bundle}`;
|
|
496
1033
|
return version ? `${url}?v=${encodeURIComponent(version)}` : url;
|
|
497
1034
|
}
|
|
498
1035
|
|
|
@@ -516,25 +1053,30 @@ function loadScript(src) {
|
|
|
516
1053
|
document.head.appendChild(script);
|
|
517
1054
|
loadedScriptSrcs.add(src);
|
|
518
1055
|
}
|
|
1056
|
+
function loadWeaverseNextStudioScript(context, options = {}) {
|
|
1057
|
+
let resolvedContext = context;
|
|
1058
|
+
if (!resolvedContext && typeof window !== "undefined") {
|
|
1059
|
+
resolvedContext = {
|
|
1060
|
+
searchParams: new URLSearchParams(window.location.search),
|
|
1061
|
+
url: window.location.href
|
|
1062
|
+
};
|
|
1063
|
+
}
|
|
1064
|
+
let src = resolveWeaverseNextStudioScriptSrc(resolvedContext, {
|
|
1065
|
+
storefrontHostname: options.storefrontHostname ?? (typeof window === "undefined" ? void 0 : window.location.hostname)
|
|
1066
|
+
});
|
|
1067
|
+
if (src) {
|
|
1068
|
+
loadScript(src);
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
519
1071
|
function WeaverseNextStudioConnect(props) {
|
|
520
1072
|
useEffect(() => {
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
context = {
|
|
524
|
-
searchParams: new URLSearchParams(window.location.search),
|
|
525
|
-
url: window.location.href
|
|
526
|
-
};
|
|
527
|
-
}
|
|
528
|
-
let src = resolveWeaverseNextStudioScriptSrc(context, {
|
|
529
|
-
storefrontHostname: props.storefrontHostname ?? (typeof window === "undefined" ? void 0 : window.location.hostname)
|
|
1073
|
+
loadWeaverseNextStudioScript(props.context, {
|
|
1074
|
+
storefrontHostname: props.storefrontHostname
|
|
530
1075
|
});
|
|
531
|
-
if (src) {
|
|
532
|
-
loadScript(src);
|
|
533
|
-
}
|
|
534
1076
|
}, [props.context, props.storefrontHostname]);
|
|
535
1077
|
return null;
|
|
536
1078
|
}
|
|
537
1079
|
|
|
538
|
-
export { WeaverseNextProvider, WeaverseNextRenderer, WeaverseNextRuntime, WeaverseNextStudioBridge, WeaverseNextStudioConnect, bindWeaverseNextStudioRuntime, createWeaverseNextClient, createWeaverseNextRuntime, createWeaverseNextThemeSettingsStore, resolveWeaverseNextStudioScriptSrc, useThemeSettings, useWeaverseCommerce, useWeaversePageData, useWeaverseRootData };
|
|
1080
|
+
export { DEFAULT_REVALIDATE_ENDPOINT, ThemeTextProvider, ThemeTextStore, TranslationProvider, TranslationStore, WeaverseNextProvider, WeaverseNextRenderer, WeaverseNextRootProvider, WeaverseNextRuntime, WeaverseNextStudio, WeaverseNextStudioBridge, WeaverseNextStudioConnect, bindWeaverseNextStudioRuntime, createTranslate, createWeaverseNextClient, createWeaverseNextRuntime, createWeaverseNextStudioInternals, createWeaverseNextThemeSettingsStore, getNestedKey, interpolate, loadWeaverseNextStudioScript, resolveWeaverseNextStudioScriptSrc, revalidateWeaverseNextItem, useThemeSettings, useThemeText, useTranslation, useWeaverseCommerce, useWeaverseNextStudioInternals, useWeaversePageData, useWeaverseRootData };
|
|
539
1081
|
//# sourceMappingURL=index.mjs.map
|
|
540
1082
|
//# sourceMappingURL=index.mjs.map
|