@weaverse/hydrogen 5.11.0 → 5.12.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.mjs CHANGED
@@ -48,12 +48,12 @@ function getNestedKey(obj, path, fallback) {
48
48
  return fallback;
49
49
  }
50
50
  function interpolate(template, variables) {
51
- if (!variables || Object.keys(variables).length === 0) {
51
+ if (!variables) {
52
52
  return template;
53
53
  }
54
54
  return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
55
55
  const value = variables[key];
56
- return value !== void 0 ? String(value) : match;
56
+ return value === void 0 ? match : String(value);
57
57
  });
58
58
  }
59
59
  var ThemeTextContext = createContext(null);
@@ -501,6 +501,13 @@ function usePixel(context) {
501
501
  }, []);
502
502
  }
503
503
  var WeaverseHydrogenItem = class extends WeaverseItemStore {
504
+ /**
505
+ * Cached merged snapshot (base + translations).
506
+ * Reset to `null` whenever `_store` or the item's translation entry changes.
507
+ */
508
+ _cachedSnapshot = null;
509
+ _snapshotStoreRef = null;
510
+ _snapshotTranslationRef = null;
504
511
  constructor(initialData, weaverse) {
505
512
  super(initialData, weaverse);
506
513
  const { data, ...rest } = initialData;
@@ -514,6 +521,32 @@ var WeaverseHydrogenItem = class extends WeaverseItemStore {
514
521
  get Element() {
515
522
  return super.Element;
516
523
  }
524
+ /**
525
+ * Override getSnapShot to merge translation data when in translation mode.
526
+ * Memoizes the result: returns the same object reference as long as
527
+ * both `_store` and the translation entry haven't changed.
528
+ * This is critical for `useSyncExternalStore` stability.
529
+ */
530
+ getSnapShot = () => {
531
+ const base = this._store;
532
+ const translations = this.weaverse.translationMap?.[this._id];
533
+ if (!translations) {
534
+ return base;
535
+ }
536
+ if (this._cachedSnapshot && this._snapshotStoreRef === base && this._snapshotTranslationRef === translations) {
537
+ return this._cachedSnapshot;
538
+ }
539
+ const merged = { ...base };
540
+ for (const [key, entry] of Object.entries(translations)) {
541
+ if (entry.translatedValue !== void 0) {
542
+ merged[key] = entry.translatedValue;
543
+ }
544
+ }
545
+ this._cachedSnapshot = merged;
546
+ this._snapshotStoreRef = base;
547
+ this._snapshotTranslationRef = translations;
548
+ return merged;
549
+ };
517
550
  };
518
551
  Weaverse.ItemConstructor = WeaverseHydrogenItem;
519
552
  var WeaverseHydrogen = class extends Weaverse {
@@ -529,8 +562,16 @@ var WeaverseHydrogen = class extends Weaverse {
529
562
  isPreviewMode;
530
563
  isRevisionPreview;
531
564
  sectionType;
532
- static itemInstances;
533
- static elementRegistry;
565
+ // ─── Translation sidecar (design mode only) ────────────────────────
566
+ /**
567
+ * Translation map received from the builder in design mode.
568
+ * Keyed by item ID, each entry maps field names to translated values.
569
+ * `WeaverseHydrogenItem.getSnapShot()` merges these into the data
570
+ * returned to components, so translations render without monkey-patching.
571
+ */
572
+ translationMap = {};
573
+ translationLocale = "";
574
+ translationLanguageId = "";
534
575
  constructor(params) {
535
576
  const { internal, pageId, requestInfo, ...coreParams } = params;
536
577
  super({ ...coreParams });
@@ -546,7 +587,82 @@ var WeaverseHydrogen = class extends Weaverse {
546
587
  this.isPreviewMode = params.isPreviewMode ?? false;
547
588
  this.isRevisionPreview = params.isRevisionPreview ?? false;
548
589
  this.sectionType = params.sectionType || "";
590
+ this.extractTranslationSidecar();
549
591
  }
592
+ /**
593
+ * Extract translation sidecar data from `this.data` (the page data).
594
+ * The builder attaches `translationMap`, `translationLocale`, and
595
+ * `translationLanguageId` to the page data in design mode.
596
+ */
597
+ extractTranslationSidecar = () => {
598
+ const pageData = this.data;
599
+ if (pageData?.translationMap) {
600
+ this.translationMap = pageData.translationMap;
601
+ this.translationLocale = pageData.translationLocale || "";
602
+ this.translationLanguageId = pageData.translationLanguageId || "";
603
+ }
604
+ };
605
+ /**
606
+ * Set the translation sidecar data.
607
+ * Called by the studio bridge when translation data arrives or changes.
608
+ * Triggers a re-render of all items so translated snapshots are recalculated.
609
+ */
610
+ setTranslationSidecar = (translationMap, locale, languageId) => {
611
+ this.translationMap = translationMap;
612
+ this.translationLocale = locale;
613
+ this.translationLanguageId = languageId;
614
+ this.refreshAllItems();
615
+ };
616
+ /**
617
+ * Update a single translation entry for a specific item field.
618
+ * Used by the studio bridge when the user edits a translatable field.
619
+ */
620
+ updateTranslation = (itemId, key, originalValue, translatedValue) => {
621
+ if (!this.translationMap[itemId]) {
622
+ this.translationMap[itemId] = {};
623
+ }
624
+ this.translationMap[itemId] = {
625
+ ...this.translationMap[itemId],
626
+ [key]: { originalValue, translatedValue }
627
+ };
628
+ const instance = this.itemInstances.get(itemId);
629
+ if (instance) {
630
+ instance.triggerUpdate();
631
+ }
632
+ };
633
+ /**
634
+ * Collect all translation changes across all weaverse instances.
635
+ * Used by the save flow to persist translation edits.
636
+ */
637
+ getTranslationChanges = () => {
638
+ const entries = [];
639
+ const languageId = this.translationLanguageId;
640
+ if (!(this.translationLocale && languageId)) {
641
+ return void 0;
642
+ }
643
+ for (const [itemId, fields] of Object.entries(this.translationMap)) {
644
+ for (const [key, entry] of Object.entries(fields)) {
645
+ entries.push({
646
+ itemId,
647
+ key: `data.${key}`,
648
+ originalValue: entry.originalValue,
649
+ translatedValue: entry.translatedValue
650
+ });
651
+ }
652
+ }
653
+ if (entries.length === 0) {
654
+ return void 0;
655
+ }
656
+ return { languageId, entries };
657
+ };
658
+ /**
659
+ * Override setProjectData to re-extract translation sidecar from new page data.
660
+ */
661
+ setProjectData = (data) => {
662
+ this.data = data;
663
+ this.extractTranslationSidecar();
664
+ this.initProject();
665
+ };
550
666
  };
551
667
  function createWeaverseInstance(params) {
552
668
  if (isBrowser) {
@@ -1097,7 +1213,7 @@ var WeaverseClient = class {
1097
1213
  type: typeof result,
1098
1214
  isString: typeof result === "string",
1099
1215
  length: typeof result === "string" ? result.length : "N/A",
1100
- preview: typeof result === "string" ? `${result.substring(0, 50)}...` : String(result)
1216
+ preview: typeof result === "string" ? `${result.slice(0, 50)}...` : String(result)
1101
1217
  }
1102
1218
  );
1103
1219
  result = { theme: defaultThemeSettings };