@foxpixel/react 0.2.2 → 0.2.3

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
@@ -124,7 +124,8 @@ function FoxPixelProvider({ children, config = {}, queryClient }) {
124
124
  const value = useMemo(() => ({
125
125
  client,
126
126
  config,
127
- queryClient: queryClient ?? null
127
+ queryClient: queryClient ?? null,
128
+ locale: config?.locale
128
129
  }), [client, config, queryClient]);
129
130
  return /* @__PURE__ */ jsx(FoxPixelContext.Provider, { value, children });
130
131
  }
@@ -399,19 +400,18 @@ function useEditModeMessaging() {
399
400
  if (!queryClient) return;
400
401
  const { type, payload } = event.data || {};
401
402
  if (type !== "FOXPIXEL_CONTENT_UPDATED" || !payload?.contentKey) return;
402
- const { contentKey, newValue } = payload;
403
+ const { contentKey, newValue, locale } = payload;
404
+ const cacheKey2 = locale != null && locale !== "" ? [SITE_CONTENT_QUERY_KEY, contentKey, locale] : [SITE_CONTENT_QUERY_KEY, contentKey];
403
405
  if (typeof newValue === "string") {
404
406
  queryClient.setQueryData(
405
- [SITE_CONTENT_QUERY_KEY, contentKey],
407
+ cacheKey2,
406
408
  (prev) => ({
407
409
  value: newValue,
408
410
  contentType: prev?.contentType ?? "TEXT"
409
411
  })
410
412
  );
411
413
  }
412
- queryClient.invalidateQueries({
413
- queryKey: [SITE_CONTENT_QUERY_KEY, contentKey]
414
- });
414
+ queryClient.invalidateQueries({ queryKey: cacheKey2 });
415
415
  };
416
416
  window.addEventListener("message", handleMessage);
417
417
  return () => window.removeEventListener("message", handleMessage);
@@ -421,20 +421,19 @@ function useEditModeMessaging() {
421
421
  function useSendEditRequest() {
422
422
  const isEditMode = useEditMode();
423
423
  return useCallback2(
424
- (contentKey, currentValue, contentType = "text", section, description) => {
424
+ (contentKey, currentValue, contentType = "text", section, description, locale) => {
425
425
  if (!isEditMode) return;
426
426
  if (typeof window !== "undefined" && window.parent !== window) {
427
+ const payload = {
428
+ contentKey,
429
+ currentValue,
430
+ contentType,
431
+ section,
432
+ description
433
+ };
434
+ if (locale != null && locale !== "") payload.locale = locale;
427
435
  window.parent.postMessage(
428
- {
429
- type: "FOXPIXEL_EDIT_CONTENT",
430
- payload: {
431
- contentKey,
432
- currentValue,
433
- contentType,
434
- section,
435
- description
436
- }
437
- },
436
+ { type: "FOXPIXEL_EDIT_CONTENT", payload },
438
437
  "*"
439
438
  );
440
439
  }
@@ -445,20 +444,23 @@ function useSendEditRequest() {
445
444
 
446
445
  // src/hooks/useSiteContentQuery.ts
447
446
  import { useState as useState6, useEffect as useEffect6, useRef } from "react";
448
- function getCached(queryClient, contentKey) {
449
- const data = queryClient.getQueryData([
450
- SITE_CONTENT_QUERY_KEY,
451
- contentKey
452
- ]);
447
+ function queryKey(contentKey, locale) {
448
+ return locale != null && locale !== "" ? [SITE_CONTENT_QUERY_KEY, contentKey, locale] : [SITE_CONTENT_QUERY_KEY, contentKey];
449
+ }
450
+ function getCached(queryClient, contentKey, locale) {
451
+ const data = queryClient.getQueryData(
452
+ queryKey(contentKey, locale)
453
+ );
453
454
  if (data == null) return void 0;
454
455
  return { value: data.value ?? "", contentType: data.contentType ?? "TEXT" };
455
456
  }
456
457
  function useSiteContentQuery(contentKey, options) {
457
- const { defaultValue } = options;
458
+ const { defaultValue, locale } = options;
459
+ const loc = locale != null && locale !== "" ? locale : void 0;
458
460
  const { client, queryClient } = useFoxPixelContext();
459
461
  const [state, setState] = useState6(() => {
460
462
  if (queryClient) {
461
- const cached = getCached(queryClient, contentKey);
463
+ const cached = getCached(queryClient, contentKey, loc);
462
464
  if (cached) {
463
465
  return { value: cached.value, isLoading: false, contentType: cached.contentType };
464
466
  }
@@ -467,18 +469,20 @@ function useSiteContentQuery(contentKey, options) {
467
469
  });
468
470
  const contentKeyRef = useRef(contentKey);
469
471
  contentKeyRef.current = contentKey;
472
+ const localeRef = useRef(loc);
473
+ localeRef.current = loc;
470
474
  useEffect6(() => {
471
475
  if (!queryClient) {
472
476
  setState((s) => ({ ...s, value: defaultValue, isLoading: false }));
473
477
  return;
474
478
  }
475
479
  const key = contentKeyRef.current;
476
- const queryKey = [SITE_CONTENT_QUERY_KEY, key];
480
+ const locCurrent = localeRef.current;
481
+ const qKey = queryKey(key, locCurrent);
477
482
  const queryFn = async () => {
478
483
  try {
479
- const content = await client.get(
480
- `/api/site/content/${encodeURIComponent(key)}`
481
- );
484
+ const url = `/api/site/content/${encodeURIComponent(key)}` + (locCurrent ? `?locale=${encodeURIComponent(locCurrent)}` : "");
485
+ const content = await client.get(url);
482
486
  if (!content) return null;
483
487
  return {
484
488
  value: content.value ?? "",
@@ -492,7 +496,7 @@ function useSiteContentQuery(contentKey, options) {
492
496
  };
493
497
  let cancelled = false;
494
498
  queryClient.fetchQuery({
495
- queryKey,
499
+ queryKey: qKey,
496
500
  queryFn,
497
501
  staleTime: 1e3 * 60 * 5,
498
502
  retry: 1
@@ -508,8 +512,11 @@ function useSiteContentQuery(contentKey, options) {
508
512
  setState((s) => ({ ...s, value: defaultValue, isLoading: false }));
509
513
  });
510
514
  const unsub = queryClient.getQueryCache().subscribe((event) => {
511
- if (event?.type === "updated" && event?.query?.queryKey[1] === key) {
512
- const cached = getCached(queryClient, key);
515
+ const q = event?.query;
516
+ const keyMatch = q?.queryKey?.[1] === key;
517
+ const locMatch = (q?.queryKey?.[2] ?? void 0) === locCurrent;
518
+ if (event?.type === "updated" && q && keyMatch && locMatch) {
519
+ const cached = getCached(queryClient, key, locCurrent);
513
520
  if (cached && !cancelled) {
514
521
  setState({
515
522
  value: cached.value,
@@ -523,7 +530,7 @@ function useSiteContentQuery(contentKey, options) {
523
530
  cancelled = true;
524
531
  unsub();
525
532
  };
526
- }, [queryClient, contentKey, defaultValue, client]);
533
+ }, [queryClient, contentKey, defaultValue, client, loc]);
527
534
  return state;
528
535
  }
529
536
 
@@ -601,13 +608,17 @@ function Editable({
601
608
  defaultValue,
602
609
  as = "span",
603
610
  multiline = false,
604
- className
611
+ className,
612
+ locale: localeProp
605
613
  }) {
606
614
  const [isHovered, setIsHovered] = useState7(false);
615
+ const { locale: contextLocale } = useFoxPixelContext();
616
+ const locale = localeProp ?? contextLocale;
607
617
  const isEditMode = useEditModeMessaging();
608
618
  const sendEditRequest = useSendEditRequest();
609
619
  const { value, isLoading, contentType } = useSiteContentQuery(contentKey, {
610
- defaultValue
620
+ defaultValue,
621
+ locale
611
622
  });
612
623
  const section = contentKey.includes(".") ? contentKey.split(".")[0] : void 0;
613
624
  useEffect7(() => {
@@ -625,11 +636,13 @@ function Editable({
625
636
  contentKey,
626
637
  value,
627
638
  contentType?.toLowerCase() || "text",
628
- section
639
+ section,
640
+ void 0,
641
+ locale
629
642
  );
630
643
  }
631
644
  },
632
- [isEditMode, contentKey, value, contentType, section, sendEditRequest]
645
+ [isEditMode, contentKey, value, contentType, section, sendEditRequest, locale]
633
646
  );
634
647
  if (isLoading) {
635
648
  return createElement(as, {
@@ -702,13 +715,17 @@ function EditableHTML({
702
715
  contentKey,
703
716
  defaultValue,
704
717
  as = "div",
705
- className
718
+ className,
719
+ locale: localeProp
706
720
  }) {
707
721
  const [isHovered, setIsHovered] = useState7(false);
722
+ const { locale: contextLocale } = useFoxPixelContext();
723
+ const locale = localeProp ?? contextLocale;
708
724
  const isEditMode = useEditModeMessaging();
709
725
  const sendEditRequest = useSendEditRequest();
710
726
  const { value, isLoading } = useSiteContentQuery(contentKey, {
711
- defaultValue
727
+ defaultValue,
728
+ locale
712
729
  });
713
730
  const section = contentKey.includes(".") ? contentKey.split(".")[0] : void 0;
714
731
  useEffect7(() => {
@@ -722,10 +739,10 @@ function EditableHTML({
722
739
  if (isEditMode) {
723
740
  e.preventDefault();
724
741
  e.stopPropagation();
725
- sendEditRequest(contentKey, value, "html", section);
742
+ sendEditRequest(contentKey, value, "html", section, void 0, locale);
726
743
  }
727
744
  },
728
- [isEditMode, contentKey, value, section, sendEditRequest]
745
+ [isEditMode, contentKey, value, section, sendEditRequest, locale]
729
746
  );
730
747
  if (isLoading) {
731
748
  return createElement(as, {
@@ -774,13 +791,17 @@ function EditableImage({
774
791
  className,
775
792
  width,
776
793
  height,
777
- priority = false
794
+ priority = false,
795
+ locale: localeProp
778
796
  }) {
779
797
  const [isHovered, setIsHovered] = useState7(false);
798
+ const { locale: contextLocale } = useFoxPixelContext();
799
+ const locale = localeProp ?? contextLocale;
780
800
  const isEditMode = useEditModeMessaging();
781
801
  const sendEditRequest = useSendEditRequest();
782
802
  const { value: src, isLoading } = useSiteContentQuery(contentKey, {
783
- defaultValue
803
+ defaultValue,
804
+ locale
784
805
  });
785
806
  const section = contentKey.includes(".") ? contentKey.split(".")[0] : void 0;
786
807
  useEffect7(() => {
@@ -794,10 +815,10 @@ function EditableImage({
794
815
  if (isEditMode) {
795
816
  e.preventDefault();
796
817
  e.stopPropagation();
797
- sendEditRequest(contentKey, src, "image", section);
818
+ sendEditRequest(contentKey, src, "image", section, void 0, locale);
798
819
  }
799
820
  },
800
- [isEditMode, contentKey, src, section, sendEditRequest]
821
+ [isEditMode, contentKey, src, section, sendEditRequest, locale]
801
822
  );
802
823
  if (isLoading) {
803
824
  return /* @__PURE__ */ jsx6(
@@ -943,20 +964,20 @@ function useContactCapture() {
943
964
  // src/hooks/useSiteContent.ts
944
965
  import { useState as useState11, useEffect as useEffect9, useCallback as useCallback4 } from "react";
945
966
  function useSiteContent(contentKey, options = {}) {
946
- const { defaultValue = "", fetchOnMount = true } = options;
967
+ const { defaultValue = "", fetchOnMount = true, locale } = options;
947
968
  const { client } = useFoxPixelContext();
948
969
  const { user, hasPermission } = useAuth();
949
970
  const [data, setData] = useState11(null);
950
971
  const [isLoading, setIsLoading] = useState11(fetchOnMount);
951
972
  const [error, setError] = useState11(null);
952
973
  const canEdit = user !== null && hasPermission("site:content:update");
974
+ const queryLocale = locale != null && locale !== "" ? locale : void 0;
953
975
  const fetchContent = useCallback4(async () => {
954
976
  try {
955
977
  setIsLoading(true);
956
978
  setError(null);
957
- const content = await client.get(
958
- `/api/site/content/${encodeURIComponent(contentKey)}`
959
- );
979
+ const url = `/api/site/content/${encodeURIComponent(contentKey)}` + (queryLocale ? `?locale=${encodeURIComponent(queryLocale)}` : "");
980
+ const content = await client.get(url);
960
981
  setData(content);
961
982
  } catch (err) {
962
983
  if (err?.status === 404) {
@@ -967,20 +988,22 @@ function useSiteContent(contentKey, options = {}) {
967
988
  } finally {
968
989
  setIsLoading(false);
969
990
  }
970
- }, [client, contentKey]);
991
+ }, [client, contentKey, queryLocale]);
971
992
  const updateContent = useCallback4(async (newValue) => {
972
993
  try {
973
994
  setError(null);
995
+ const body = { value: newValue };
996
+ if (queryLocale) body.locale = queryLocale;
974
997
  const updated = await client.put(
975
998
  `/api/site/content/${encodeURIComponent(contentKey)}`,
976
- { value: newValue }
999
+ body
977
1000
  );
978
1001
  setData(updated);
979
1002
  } catch (err) {
980
1003
  setError(err);
981
1004
  throw err;
982
1005
  }
983
- }, [client, contentKey]);
1006
+ }, [client, contentKey, queryLocale]);
984
1007
  useEffect9(() => {
985
1008
  if (fetchOnMount) {
986
1009
  fetchContent();
@@ -998,11 +1021,12 @@ function useSiteContent(contentKey, options = {}) {
998
1021
  };
999
1022
  }
1000
1023
  function useSiteContents(contentKeys, options = {}) {
1001
- const { defaults = {} } = options;
1024
+ const { defaults = {}, locale } = options;
1002
1025
  const { client } = useFoxPixelContext();
1003
1026
  const [data, setData] = useState11({});
1004
1027
  const [isLoading, setIsLoading] = useState11(true);
1005
1028
  const [error, setError] = useState11(null);
1029
+ const body = locale != null && locale !== "" ? { keys: contentKeys, locale } : contentKeys;
1006
1030
  const fetchContents = useCallback4(async () => {
1007
1031
  if (contentKeys.length === 0) {
1008
1032
  setData({});
@@ -1014,7 +1038,7 @@ function useSiteContents(contentKeys, options = {}) {
1014
1038
  setError(null);
1015
1039
  const contents = await client.post(
1016
1040
  "/api/site/content/batch",
1017
- contentKeys
1041
+ body
1018
1042
  );
1019
1043
  setData(contents);
1020
1044
  } catch (err) {
@@ -1022,7 +1046,7 @@ function useSiteContents(contentKeys, options = {}) {
1022
1046
  } finally {
1023
1047
  setIsLoading(false);
1024
1048
  }
1025
- }, [client, contentKeys.join(",")]);
1049
+ }, [client, contentKeys.join(","), locale]);
1026
1050
  useEffect9(() => {
1027
1051
  fetchContents();
1028
1052
  }, [fetchContents]);
@@ -1041,25 +1065,25 @@ function useSiteContents(contentKeys, options = {}) {
1041
1065
  refetch: fetchContents
1042
1066
  };
1043
1067
  }
1044
- function useSiteContentSection(section) {
1068
+ function useSiteContentSection(section, options = {}) {
1069
+ const { locale } = options;
1045
1070
  const { client } = useFoxPixelContext();
1046
1071
  const [contents, setContents] = useState11([]);
1047
1072
  const [isLoading, setIsLoading] = useState11(true);
1048
1073
  const [error, setError] = useState11(null);
1074
+ const url = `/api/site/content/section/${encodeURIComponent(section)}` + (locale != null && locale !== "" ? `?locale=${encodeURIComponent(locale)}` : "");
1049
1075
  const fetchContents = useCallback4(async () => {
1050
1076
  try {
1051
1077
  setIsLoading(true);
1052
1078
  setError(null);
1053
- const data = await client.get(
1054
- `/api/site/content/section/${encodeURIComponent(section)}`
1055
- );
1079
+ const data = await client.get(url);
1056
1080
  setContents(data);
1057
1081
  } catch (err) {
1058
1082
  setError(err);
1059
1083
  } finally {
1060
1084
  setIsLoading(false);
1061
1085
  }
1062
- }, [client, section]);
1086
+ }, [client, section, locale]);
1063
1087
  useEffect9(() => {
1064
1088
  fetchContents();
1065
1089
  }, [fetchContents]);
@@ -1072,33 +1096,39 @@ function useSiteContentSection(section) {
1072
1096
  }
1073
1097
 
1074
1098
  // src/prefetchSiteContent.ts
1099
+ function cacheKey(contentKey, locale) {
1100
+ return locale != null && locale !== "" ? [SITE_CONTENT_QUERY_KEY, contentKey, locale] : [SITE_CONTENT_QUERY_KEY, contentKey];
1101
+ }
1075
1102
  async function prefetchSiteContent(queryClient, options) {
1076
- const { apiUrl, apiKey, tenantId, contentKeys } = options;
1103
+ const { apiUrl, apiKey, tenantId, contentKeys, locale } = options;
1077
1104
  const client = new FoxPixelHttpClient({ apiUrl, apiKey, tenantId });
1078
- await Promise.all(
1079
- contentKeys.map(async (contentKey) => {
1080
- try {
1081
- const content = await client.get(
1082
- `/api/site/content/${encodeURIComponent(contentKey)}`
1083
- );
1084
- queryClient.setQueryData(
1085
- [SITE_CONTENT_QUERY_KEY, contentKey],
1086
- {
1087
- value: content?.value ?? "",
1088
- contentType: content?.contentType ?? "TEXT"
1105
+ const locales = locale == null ? [void 0] : Array.isArray(locale) ? locale : [locale];
1106
+ const tasks = [];
1107
+ for (const contentKey of contentKeys) {
1108
+ for (const loc of locales) {
1109
+ tasks.push(
1110
+ (async () => {
1111
+ try {
1112
+ const url = `/api/site/content/${encodeURIComponent(contentKey)}` + (loc != null && loc !== "" ? `?locale=${encodeURIComponent(loc)}` : "");
1113
+ const content = await client.get(url);
1114
+ queryClient.setQueryData(cacheKey(contentKey, loc), {
1115
+ value: content?.value ?? "",
1116
+ contentType: content?.contentType ?? "TEXT"
1117
+ });
1118
+ } catch (err) {
1119
+ const status = err?.response?.status;
1120
+ if (status === 404) {
1121
+ queryClient.setQueryData(cacheKey(contentKey, loc), {
1122
+ value: "",
1123
+ contentType: "TEXT"
1124
+ });
1125
+ }
1089
1126
  }
1090
- );
1091
- } catch (err) {
1092
- const status = err?.response?.status;
1093
- if (status === 404) {
1094
- queryClient.setQueryData([SITE_CONTENT_QUERY_KEY, contentKey], {
1095
- value: "",
1096
- contentType: "TEXT"
1097
- });
1098
- }
1099
- }
1100
- })
1101
- );
1127
+ })()
1128
+ );
1129
+ }
1130
+ }
1131
+ await Promise.all(tasks);
1102
1132
  }
1103
1133
 
1104
1134
  // src/blog/hooks.ts