@weaverse/hydrogen 5.11.1 → 5.12.1
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 +113 -6
- package/dist/index.d.ts +113 -6
- package/dist/index.js +199 -6
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +199 -7
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -58,12 +58,39 @@ function interpolate(template, variables) {
|
|
|
58
58
|
}
|
|
59
59
|
var ThemeTextContext = createContext(null);
|
|
60
60
|
ThemeTextContext.displayName = "WeaverseThemeTextContext";
|
|
61
|
+
function unflattenKeys(flat) {
|
|
62
|
+
const result = {};
|
|
63
|
+
for (const [dotPath, value] of Object.entries(flat)) {
|
|
64
|
+
const keys = dotPath.split(".");
|
|
65
|
+
let current = result;
|
|
66
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
67
|
+
const k = keys[i];
|
|
68
|
+
if (!(k in current) || typeof current[k] !== "object") {
|
|
69
|
+
current[k] = {};
|
|
70
|
+
}
|
|
71
|
+
current = current[k];
|
|
72
|
+
}
|
|
73
|
+
current[keys[keys.length - 1]] = value;
|
|
74
|
+
}
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
var EMPTY = {};
|
|
78
|
+
var NOOP_SUBSCRIBE = () => () => {
|
|
79
|
+
};
|
|
80
|
+
var NOOP_SNAPSHOT = () => EMPTY;
|
|
61
81
|
function ThemeTextProvider({
|
|
62
82
|
staticContent,
|
|
63
83
|
merchantOverrides,
|
|
64
84
|
t: externalT,
|
|
85
|
+
themeTextStore,
|
|
65
86
|
children
|
|
66
87
|
}) {
|
|
88
|
+
const designOverrides = useSafeExternalStore(
|
|
89
|
+
themeTextStore?.subscribe ?? NOOP_SUBSCRIBE,
|
|
90
|
+
themeTextStore?.getSnapshot ?? NOOP_SNAPSHOT,
|
|
91
|
+
themeTextStore?.getServerSnapshot ?? NOOP_SNAPSHOT
|
|
92
|
+
);
|
|
93
|
+
const mergedOverrides = designOverrides !== EMPTY && Object.keys(designOverrides).length > 0 ? { ...merchantOverrides, ...unflattenKeys(designOverrides) } : merchantOverrides;
|
|
67
94
|
const value = useMemo(() => {
|
|
68
95
|
const t = (key, variables) => {
|
|
69
96
|
if (externalT) {
|
|
@@ -72,13 +99,23 @@ function ThemeTextProvider({
|
|
|
72
99
|
return external;
|
|
73
100
|
}
|
|
74
101
|
}
|
|
75
|
-
const override =
|
|
102
|
+
const override = mergedOverrides ? getNestedKey(mergedOverrides, key) : void 0;
|
|
76
103
|
const staticValue = getNestedKey(staticContent, key);
|
|
77
104
|
const raw = override ?? staticValue ?? key;
|
|
78
105
|
return interpolate(raw, variables);
|
|
79
106
|
};
|
|
80
|
-
return {
|
|
81
|
-
|
|
107
|
+
return {
|
|
108
|
+
t,
|
|
109
|
+
themeTextStore: themeTextStore ?? null,
|
|
110
|
+
merchantOverrides: merchantOverrides ?? null
|
|
111
|
+
};
|
|
112
|
+
}, [
|
|
113
|
+
staticContent,
|
|
114
|
+
merchantOverrides,
|
|
115
|
+
mergedOverrides,
|
|
116
|
+
externalT,
|
|
117
|
+
themeTextStore
|
|
118
|
+
]);
|
|
82
119
|
return /* @__PURE__ */ jsx(ThemeTextContext.Provider, { value, children });
|
|
83
120
|
}
|
|
84
121
|
function useThemeText() {
|
|
@@ -349,6 +386,37 @@ function getPreviewData(type, components, weaverseHost) {
|
|
|
349
386
|
}
|
|
350
387
|
};
|
|
351
388
|
}
|
|
389
|
+
|
|
390
|
+
// src/utils/theme-text-store.ts
|
|
391
|
+
var ThemeTextStore = class {
|
|
392
|
+
overrides = {};
|
|
393
|
+
listeners = /* @__PURE__ */ new Set();
|
|
394
|
+
setOverrides = (overrides) => {
|
|
395
|
+
this.overrides = { ...overrides };
|
|
396
|
+
this.emit();
|
|
397
|
+
};
|
|
398
|
+
updateOverrides = (newOverrides) => {
|
|
399
|
+
this.overrides = { ...this.overrides, ...newOverrides };
|
|
400
|
+
this.emit();
|
|
401
|
+
};
|
|
402
|
+
getSnapshot = () => this.overrides;
|
|
403
|
+
getServerSnapshot = () => this.overrides;
|
|
404
|
+
subscribe = (callback) => {
|
|
405
|
+
this.listeners.add(callback);
|
|
406
|
+
return () => {
|
|
407
|
+
this.listeners.delete(callback);
|
|
408
|
+
};
|
|
409
|
+
};
|
|
410
|
+
emit = () => {
|
|
411
|
+
for (const listener of Array.from(this.listeners)) {
|
|
412
|
+
try {
|
|
413
|
+
listener();
|
|
414
|
+
} catch (error) {
|
|
415
|
+
console.error("ThemeTextStore: Listener error", error);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
};
|
|
419
|
+
};
|
|
352
420
|
var ThemeSettingsStore = class {
|
|
353
421
|
settings = {};
|
|
354
422
|
schema;
|
|
@@ -459,6 +527,7 @@ function useStudio(weaverse) {
|
|
|
459
527
|
let { pathname, search } = useLocation();
|
|
460
528
|
let navigate = useNavigate();
|
|
461
529
|
let themeSettingsStore = useThemeSettingsStore();
|
|
530
|
+
let { themeTextStore, merchantOverrides } = useThemeText();
|
|
462
531
|
let {
|
|
463
532
|
isDesignMode,
|
|
464
533
|
weaverseHost,
|
|
@@ -476,7 +545,9 @@ function useStudio(weaverse) {
|
|
|
476
545
|
...weaverse.internal,
|
|
477
546
|
navigate,
|
|
478
547
|
revalidate,
|
|
479
|
-
|
|
548
|
+
merchantOverrides,
|
|
549
|
+
themeSettingsStore,
|
|
550
|
+
themeTextStore
|
|
480
551
|
};
|
|
481
552
|
let studioSrc = `${weaverseHost}/static/studio/hydrogen/index.js?v=${weaverseVersion}`;
|
|
482
553
|
loadScript(studioSrc).then(() => {
|
|
@@ -501,6 +572,13 @@ function usePixel(context) {
|
|
|
501
572
|
}, []);
|
|
502
573
|
}
|
|
503
574
|
var WeaverseHydrogenItem = class extends WeaverseItemStore {
|
|
575
|
+
/**
|
|
576
|
+
* Cached merged snapshot (base + translations).
|
|
577
|
+
* Reset to `null` whenever `_store` or the item's translation entry changes.
|
|
578
|
+
*/
|
|
579
|
+
_cachedSnapshot = null;
|
|
580
|
+
_snapshotStoreRef = null;
|
|
581
|
+
_snapshotTranslationRef = null;
|
|
504
582
|
constructor(initialData, weaverse) {
|
|
505
583
|
super(initialData, weaverse);
|
|
506
584
|
const { data, ...rest } = initialData;
|
|
@@ -514,6 +592,32 @@ var WeaverseHydrogenItem = class extends WeaverseItemStore {
|
|
|
514
592
|
get Element() {
|
|
515
593
|
return super.Element;
|
|
516
594
|
}
|
|
595
|
+
/**
|
|
596
|
+
* Override getSnapShot to merge translation data when in translation mode.
|
|
597
|
+
* Memoizes the result: returns the same object reference as long as
|
|
598
|
+
* both `_store` and the translation entry haven't changed.
|
|
599
|
+
* This is critical for `useSyncExternalStore` stability.
|
|
600
|
+
*/
|
|
601
|
+
getSnapShot = () => {
|
|
602
|
+
const base = this._store;
|
|
603
|
+
const translations = this.weaverse.translationMap?.[this._id];
|
|
604
|
+
if (!translations) {
|
|
605
|
+
return base;
|
|
606
|
+
}
|
|
607
|
+
if (this._cachedSnapshot && this._snapshotStoreRef === base && this._snapshotTranslationRef === translations) {
|
|
608
|
+
return this._cachedSnapshot;
|
|
609
|
+
}
|
|
610
|
+
const merged = { ...base };
|
|
611
|
+
for (const [key, entry] of Object.entries(translations)) {
|
|
612
|
+
if (entry.translatedValue !== void 0) {
|
|
613
|
+
merged[key] = entry.translatedValue;
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
this._cachedSnapshot = merged;
|
|
617
|
+
this._snapshotStoreRef = base;
|
|
618
|
+
this._snapshotTranslationRef = translations;
|
|
619
|
+
return merged;
|
|
620
|
+
};
|
|
517
621
|
};
|
|
518
622
|
Weaverse.ItemConstructor = WeaverseHydrogenItem;
|
|
519
623
|
var WeaverseHydrogen = class extends Weaverse {
|
|
@@ -529,8 +633,16 @@ var WeaverseHydrogen = class extends Weaverse {
|
|
|
529
633
|
isPreviewMode;
|
|
530
634
|
isRevisionPreview;
|
|
531
635
|
sectionType;
|
|
532
|
-
|
|
533
|
-
|
|
636
|
+
// ─── Translation sidecar (design mode only) ────────────────────────
|
|
637
|
+
/**
|
|
638
|
+
* Translation map received from the builder in design mode.
|
|
639
|
+
* Keyed by item ID, each entry maps field names to translated values.
|
|
640
|
+
* `WeaverseHydrogenItem.getSnapShot()` merges these into the data
|
|
641
|
+
* returned to components, so translations render without monkey-patching.
|
|
642
|
+
*/
|
|
643
|
+
translationMap = {};
|
|
644
|
+
translationLocale = "";
|
|
645
|
+
translationLanguageId = "";
|
|
534
646
|
constructor(params) {
|
|
535
647
|
const { internal, pageId, requestInfo, ...coreParams } = params;
|
|
536
648
|
super({ ...coreParams });
|
|
@@ -546,7 +658,82 @@ var WeaverseHydrogen = class extends Weaverse {
|
|
|
546
658
|
this.isPreviewMode = params.isPreviewMode ?? false;
|
|
547
659
|
this.isRevisionPreview = params.isRevisionPreview ?? false;
|
|
548
660
|
this.sectionType = params.sectionType || "";
|
|
661
|
+
this.extractTranslationSidecar();
|
|
549
662
|
}
|
|
663
|
+
/**
|
|
664
|
+
* Extract translation sidecar data from `this.data` (the page data).
|
|
665
|
+
* The builder attaches `translationMap`, `translationLocale`, and
|
|
666
|
+
* `translationLanguageId` to the page data in design mode.
|
|
667
|
+
*/
|
|
668
|
+
extractTranslationSidecar = () => {
|
|
669
|
+
const pageData = this.data;
|
|
670
|
+
if (pageData?.translationMap) {
|
|
671
|
+
this.translationMap = pageData.translationMap;
|
|
672
|
+
this.translationLocale = pageData.translationLocale || "";
|
|
673
|
+
this.translationLanguageId = pageData.translationLanguageId || "";
|
|
674
|
+
}
|
|
675
|
+
};
|
|
676
|
+
/**
|
|
677
|
+
* Set the translation sidecar data.
|
|
678
|
+
* Called by the studio bridge when translation data arrives or changes.
|
|
679
|
+
* Triggers a re-render of all items so translated snapshots are recalculated.
|
|
680
|
+
*/
|
|
681
|
+
setTranslationSidecar = (translationMap, locale, languageId) => {
|
|
682
|
+
this.translationMap = translationMap;
|
|
683
|
+
this.translationLocale = locale;
|
|
684
|
+
this.translationLanguageId = languageId;
|
|
685
|
+
this.refreshAllItems();
|
|
686
|
+
};
|
|
687
|
+
/**
|
|
688
|
+
* Update a single translation entry for a specific item field.
|
|
689
|
+
* Used by the studio bridge when the user edits a translatable field.
|
|
690
|
+
*/
|
|
691
|
+
updateTranslation = (itemId, key, originalValue, translatedValue) => {
|
|
692
|
+
if (!this.translationMap[itemId]) {
|
|
693
|
+
this.translationMap[itemId] = {};
|
|
694
|
+
}
|
|
695
|
+
this.translationMap[itemId] = {
|
|
696
|
+
...this.translationMap[itemId],
|
|
697
|
+
[key]: { originalValue, translatedValue }
|
|
698
|
+
};
|
|
699
|
+
const instance = this.itemInstances.get(itemId);
|
|
700
|
+
if (instance) {
|
|
701
|
+
instance.triggerUpdate();
|
|
702
|
+
}
|
|
703
|
+
};
|
|
704
|
+
/**
|
|
705
|
+
* Collect all translation changes across all weaverse instances.
|
|
706
|
+
* Used by the save flow to persist translation edits.
|
|
707
|
+
*/
|
|
708
|
+
getTranslationChanges = () => {
|
|
709
|
+
const entries = [];
|
|
710
|
+
const languageId = this.translationLanguageId;
|
|
711
|
+
if (!(this.translationLocale && languageId)) {
|
|
712
|
+
return void 0;
|
|
713
|
+
}
|
|
714
|
+
for (const [itemId, fields] of Object.entries(this.translationMap)) {
|
|
715
|
+
for (const [key, entry] of Object.entries(fields)) {
|
|
716
|
+
entries.push({
|
|
717
|
+
itemId,
|
|
718
|
+
key: `data.${key}`,
|
|
719
|
+
originalValue: entry.originalValue,
|
|
720
|
+
translatedValue: entry.translatedValue
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
if (entries.length === 0) {
|
|
725
|
+
return void 0;
|
|
726
|
+
}
|
|
727
|
+
return { languageId, entries };
|
|
728
|
+
};
|
|
729
|
+
/**
|
|
730
|
+
* Override setProjectData to re-extract translation sidecar from new page data.
|
|
731
|
+
*/
|
|
732
|
+
setProjectData = (data) => {
|
|
733
|
+
this.data = data;
|
|
734
|
+
this.extractTranslationSidecar();
|
|
735
|
+
this.initProject();
|
|
736
|
+
};
|
|
550
737
|
};
|
|
551
738
|
function createWeaverseInstance(params) {
|
|
552
739
|
if (isBrowser) {
|
|
@@ -645,12 +832,17 @@ function withWeaverse(Component, options) {
|
|
|
645
832
|
return (props) => {
|
|
646
833
|
const themeSettingsStore = useCreateThemeSettingsStore();
|
|
647
834
|
const themeTextData = useThemeTextData();
|
|
835
|
+
const themeTextStoreRef = useRef(null);
|
|
836
|
+
if (!themeTextStoreRef.current) {
|
|
837
|
+
themeTextStoreRef.current = new ThemeTextStore();
|
|
838
|
+
}
|
|
648
839
|
return /* @__PURE__ */ jsx(ThemeSettingsStoreContext.Provider, { value: themeSettingsStore, children: /* @__PURE__ */ jsx(
|
|
649
840
|
ThemeTextProvider,
|
|
650
841
|
{
|
|
651
842
|
merchantOverrides: themeTextData.merchantOverrides,
|
|
652
843
|
staticContent: themeTextData.staticContent,
|
|
653
844
|
t: options?.t,
|
|
845
|
+
themeTextStore: themeTextStoreRef.current,
|
|
654
846
|
children: /* @__PURE__ */ jsx(Component, { ...props })
|
|
655
847
|
}
|
|
656
848
|
) });
|
|
@@ -1442,6 +1634,6 @@ var IMAGES_PLACEHOLDERS = {
|
|
|
1442
1634
|
product_18: "https://cdn.shopify.com/s/files/1/0838/0052/3057/files/fpo-product-watch-2-1024x1024.svg"
|
|
1443
1635
|
};
|
|
1444
1636
|
|
|
1445
|
-
export { IMAGES_PLACEHOLDERS, ThemeTextProvider, WeaverseClient, WeaverseError, WeaverseHydrogen, WeaverseHydrogenItem, WeaverseHydrogenRoot, createWeaverseDataContext, defaultComponents, generateDataFromSchema, getNestedKey, getPreviewData, getRequestQueries, getSelectedProductOptions, getWeaverseConfigs, hasError, hasWeaverseStudio, interpolate, isFetchProjectPayload, isProjectIdFunction, isThemeSettingsResponse, isValidHydrogenSchema, isWithCacheFetchResponse, registerComponent, useThemeSettings, useThemeText, useWeaverseDataContext, withWeaverse };
|
|
1637
|
+
export { IMAGES_PLACEHOLDERS, ThemeTextProvider, ThemeTextStore, WeaverseClient, WeaverseError, WeaverseHydrogen, WeaverseHydrogenItem, WeaverseHydrogenRoot, createWeaverseDataContext, defaultComponents, generateDataFromSchema, getNestedKey, getPreviewData, getRequestQueries, getSelectedProductOptions, getWeaverseConfigs, hasError, hasWeaverseStudio, interpolate, isFetchProjectPayload, isProjectIdFunction, isThemeSettingsResponse, isValidHydrogenSchema, isWithCacheFetchResponse, registerComponent, useThemeSettings, useThemeText, useWeaverseDataContext, withWeaverse };
|
|
1446
1638
|
//# sourceMappingURL=index.mjs.map
|
|
1447
1639
|
//# sourceMappingURL=index.mjs.map
|