@weaverse/hydrogen 5.9.5 → 5.10.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.mjs CHANGED
@@ -4,8 +4,8 @@ export { isBrowser, isIframe, useChildInstances, useItemInstance, useParentInsta
4
4
  import { createSchema, isValidSchema } from '@weaverse/schema';
5
5
  export * from '@weaverse/schema';
6
6
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
+ import { createContext, memo, useMemo, Suspense, useEffect, useContext } from 'react';
7
8
  import { useMatches, Await, useRevalidator, useNavigation, useLocation, useNavigate, useRouteLoaderData } from 'react-router';
8
- import { memo, useMemo, Suspense, createContext, useEffect } from 'react';
9
9
  import { ErrorBoundary } from 'react-error-boundary';
10
10
 
11
11
  // src/index.ts
@@ -33,6 +33,63 @@ var defaultComponents = [
33
33
  schema
34
34
  }
35
35
  ];
36
+ function getNestedKey(obj, path, fallback) {
37
+ const keys = path.split(".");
38
+ let current = obj;
39
+ for (const key of keys) {
40
+ if (current == null || typeof current !== "object") {
41
+ return fallback;
42
+ }
43
+ current = current[key];
44
+ }
45
+ if (typeof current === "string") {
46
+ return current;
47
+ }
48
+ return fallback;
49
+ }
50
+ function interpolate(template, variables) {
51
+ if (!variables || Object.keys(variables).length === 0) {
52
+ return template;
53
+ }
54
+ return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
55
+ const value = variables[key];
56
+ return value !== void 0 ? String(value) : match;
57
+ });
58
+ }
59
+ var ThemeTextContext = createContext(null);
60
+ ThemeTextContext.displayName = "WeaverseThemeTextContext";
61
+ function ThemeTextProvider({
62
+ staticContent,
63
+ merchantOverrides,
64
+ t: externalT,
65
+ children
66
+ }) {
67
+ const value = useMemo(() => {
68
+ const t = (key, variables) => {
69
+ if (externalT) {
70
+ const external = externalT(key, variables);
71
+ if (external && external !== key) {
72
+ return external;
73
+ }
74
+ }
75
+ const override = merchantOverrides ? getNestedKey(merchantOverrides, key) : void 0;
76
+ const staticValue = getNestedKey(staticContent, key);
77
+ const raw = override ?? staticValue ?? key;
78
+ return interpolate(raw, variables);
79
+ };
80
+ return { t };
81
+ }, [staticContent, merchantOverrides, externalT]);
82
+ return /* @__PURE__ */ jsx(ThemeTextContext.Provider, { value, children });
83
+ }
84
+ function useThemeText() {
85
+ const ctx = useContext(ThemeTextContext);
86
+ if (!ctx) {
87
+ throw new Error(
88
+ "useThemeText must be used within <ThemeTextProvider>. Wrap your app with withWeaverse()."
89
+ );
90
+ }
91
+ return ctx;
92
+ }
36
93
  function createFlatDataContext(matches) {
37
94
  const context = {};
38
95
  for (const match of matches) {
@@ -562,10 +619,27 @@ var WeaverseHydrogenRoot = memo(
562
619
  );
563
620
  var ThemeSettingsProvider = createContext(null);
564
621
  ThemeSettingsProvider.displayName = "WeaverseThemeSettingsProvider";
565
- function withWeaverse(Component) {
622
+ function withWeaverse(Component, options) {
566
623
  return (props) => {
567
- const { settings } = useThemeSettingsStore();
568
- return /* @__PURE__ */ jsx(ThemeSettingsProvider.Provider, { value: settings, children: /* @__PURE__ */ jsx(Component, { ...props }) });
624
+ const themeSettingsStore = useThemeSettingsStore();
625
+ const { settings } = themeSettingsStore;
626
+ const themeTextData = useThemeTextData();
627
+ return /* @__PURE__ */ jsx(ThemeSettingsProvider.Provider, { value: settings, children: /* @__PURE__ */ jsx(
628
+ ThemeTextProvider,
629
+ {
630
+ merchantOverrides: themeTextData.merchantOverrides,
631
+ staticContent: themeTextData.staticContent,
632
+ t: options?.t,
633
+ children: /* @__PURE__ */ jsx(Component, { ...props })
634
+ }
635
+ ) });
636
+ };
637
+ }
638
+ function useThemeTextData() {
639
+ const data = useRouteLoaderData("root");
640
+ return {
641
+ staticContent: data?.weaverseTheme?.staticContent ?? {},
642
+ merchantOverrides: data?.weaverseTheme?.merchantOverrides
569
643
  };
570
644
  }
571
645
  function useThemeSettings() {
@@ -981,41 +1055,52 @@ var WeaverseClient = class {
981
1055
  }
982
1056
  const url = this.getApiUrl("project_configs");
983
1057
  const body = JSON.stringify({ isDesignMode, projectId });
984
- let data = await this.fetchWithCache(url, {
985
- method: "POST",
986
- strategy,
987
- body,
988
- headers: {
989
- "Content-Type": "application/json",
990
- Accept: "application/json",
991
- "Accept-Encoding": "gzip, deflate, br"
992
- }
993
- });
994
- if (typeof data !== "object" || data === null) {
1058
+ const [data, merchantOverrides] = await Promise.all([
1059
+ this.fetchWithCache(url, {
1060
+ method: "POST",
1061
+ strategy,
1062
+ body,
1063
+ headers: {
1064
+ "Content-Type": "application/json",
1065
+ Accept: "application/json",
1066
+ "Accept-Encoding": "gzip, deflate, br"
1067
+ }
1068
+ }),
1069
+ this.fetchMerchantOverrides(strategy)
1070
+ ]);
1071
+ let result = data;
1072
+ if (typeof result !== "object" || result === null) {
995
1073
  console.warn(
996
1074
  "Invalid theme settings response format, using defaults:",
997
1075
  {
998
- type: typeof data,
999
- isString: typeof data === "string",
1000
- length: typeof data === "string" ? data.length : "N/A",
1001
- preview: typeof data === "string" ? `${data.substring(0, 50)}...` : String(data)
1076
+ type: typeof result,
1077
+ isString: typeof result === "string",
1078
+ length: typeof result === "string" ? result.length : "N/A",
1079
+ preview: typeof result === "string" ? `${result.substring(0, 50)}...` : String(result)
1002
1080
  }
1003
1081
  );
1004
- data = { theme: defaultThemeSettings };
1082
+ result = { theme: defaultThemeSettings };
1005
1083
  }
1006
1084
  if (this.themeSchema?.settings || this.themeSchema?.inspector) {
1007
- if (!data.theme || typeof data.theme !== "object") {
1008
- data.theme = defaultThemeSettings;
1085
+ if (!result.theme || typeof result.theme !== "object") {
1086
+ result.theme = defaultThemeSettings;
1009
1087
  } else {
1010
- data.theme = {
1088
+ result.theme = {
1011
1089
  ...defaultThemeSettings,
1012
- ...data.theme
1090
+ ...result.theme
1013
1091
  };
1014
1092
  }
1015
1093
  }
1094
+ const staticContent = this.themeSchema?.i18n?.staticContent;
1095
+ if (staticContent) {
1096
+ result.staticContent = staticContent;
1097
+ }
1098
+ if (merchantOverrides) {
1099
+ result.merchantOverrides = merchantOverrides;
1100
+ }
1016
1101
  if (this.configs.isDesignMode) {
1017
- data = {
1018
- ...data,
1102
+ result = {
1103
+ ...result,
1019
1104
  schema: this.themeSchema && typeof this.themeSchema === "object" ? {
1020
1105
  ...this.themeSchema,
1021
1106
  settings: this.themeSchema?.settings?.map((group) => ({
@@ -1034,18 +1119,57 @@ var WeaverseClient = class {
1034
1119
  publicEnv: this.configs.publicEnv
1035
1120
  };
1036
1121
  }
1037
- return data;
1122
+ return result;
1038
1123
  } catch (error) {
1039
1124
  const errorMessage = "Unable to load theme settings";
1040
1125
  const errorDetails = this.extractErrorMessage(error);
1041
1126
  console.error(errorMessage, errorDetails);
1042
1127
  return {
1043
1128
  theme: defaultThemeSettings,
1129
+ staticContent: this.themeSchema?.i18n?.staticContent,
1044
1130
  _error: errorDetails,
1045
1131
  _loadFailed: true
1046
1132
  };
1047
1133
  }
1048
1134
  };
1135
+ /**
1136
+ * Fetch locale-specific merchant overrides from the translation API.
1137
+ * Returns a nested JSON object with translated values.
1138
+ * Falls back to empty object on error to avoid blocking theme rendering.
1139
+ */
1140
+ fetchMerchantOverrides = async (strategy) => {
1141
+ try {
1142
+ const { projectId, weaverseHost } = this.configs;
1143
+ const i18n = this.storefront.i18n;
1144
+ if (!(projectId && weaverseHost)) {
1145
+ return void 0;
1146
+ }
1147
+ const language = (i18n?.language || "en").toLowerCase();
1148
+ const country = (i18n?.country || "us").toLowerCase();
1149
+ const locale = `${language}-${country}`;
1150
+ const url = `${weaverseHost}/api/translation/static?projectId=${projectId}&locale=${locale}`;
1151
+ const overrides = await this.fetchWithCache(
1152
+ url,
1153
+ {
1154
+ method: "GET",
1155
+ strategy,
1156
+ headers: {
1157
+ Accept: "application/json"
1158
+ }
1159
+ }
1160
+ );
1161
+ if (typeof overrides === "object" && overrides !== null) {
1162
+ return overrides;
1163
+ }
1164
+ return void 0;
1165
+ } catch (error) {
1166
+ console.warn(
1167
+ "Unable to load merchant overrides, using theme defaults:",
1168
+ this.extractErrorMessage(error)
1169
+ );
1170
+ return void 0;
1171
+ }
1172
+ };
1049
1173
  /**
1050
1174
  * Generate fallback page with default structure when page data is unavailable.
1051
1175
  * Used internally when API returns no page or when page needs default content.
@@ -1297,6 +1421,6 @@ var IMAGES_PLACEHOLDERS = {
1297
1421
  product_18: "https://cdn.shopify.com/s/files/1/0838/0052/3057/files/fpo-product-watch-2-1024x1024.svg"
1298
1422
  };
1299
1423
 
1300
- export { IMAGES_PLACEHOLDERS, WeaverseClient, WeaverseError, WeaverseHydrogen, WeaverseHydrogenItem, WeaverseHydrogenRoot, createWeaverseDataContext, defaultComponents, generateDataFromSchema, getPreviewData, getRequestQueries, getSelectedProductOptions, getWeaverseConfigs, hasError, hasWeaverseStudio, isFetchProjectPayload, isProjectIdFunction, isThemeSettingsResponse, isValidHydrogenSchema, isWithCacheFetchResponse, registerComponent, useThemeSettings, useWeaverseDataContext, withWeaverse };
1424
+ 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 };
1301
1425
  //# sourceMappingURL=index.mjs.map
1302
1426
  //# sourceMappingURL=index.mjs.map