@asteby/storefront-react 0.1.1 → 0.2.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.js CHANGED
@@ -1,6 +1,7 @@
1
- import { createContext, useMemo, useContext, useRef, useState, useCallback, useEffect, createElement, Fragment as Fragment$1 } from 'react';
1
+ import { createContext, useMemo, useContext, useRef, useState, useCallback, useEffect, createElement, Fragment as Fragment$1, useId } from 'react';
2
2
  import { createStorefrontClient, formatMoney, parseMoney, isStorefrontError } from '@asteby/storefront';
3
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
+ import { toSchemaOpeningHours, isValidPoint, rankByDistance, openStatus, directionsUrl } from '@asteby/storefront/geo';
4
5
 
5
6
  // src/context.tsx
6
7
  var StorefrontContext = createContext(null);
@@ -550,8 +551,6 @@ function AddToCartButton({
550
551
  }
551
552
  );
552
553
  }
553
-
554
- // src/seo.ts
555
554
  var clean = (s, max) => {
556
555
  if (!s) return void 0;
557
556
  const text = s.replace(/<[^>]*>/g, " ").replace(/\s+/g, " ").trim();
@@ -685,6 +684,16 @@ function organizationJsonLd(shop, url) {
685
684
  contactPoint
686
685
  });
687
686
  }
687
+ var SCHEMA_HOURS = /^(Mo|Tu|We|Th|Fr|Sa|Su)(-(Mo|Tu|We|Th|Fr|Sa|Su))?( \d{2}:\d{2}-\d{2}:\d{2})?$/;
688
+ function openingHoursJsonLd(hours) {
689
+ if (!hours) return void 0;
690
+ if (typeof hours !== "string") {
691
+ const list = hours.weekly ? toSchemaOpeningHours(hours) : [];
692
+ return list.length ? list : void 0;
693
+ }
694
+ const tokens = hours.split(",").map((t) => t.trim());
695
+ return tokens.length && tokens.every((t) => SCHEMA_HOURS.test(t)) ? tokens : void 0;
696
+ }
688
697
  function localBusinessJsonLd(shop, options = {}) {
689
698
  const site = shopUrl(shop, options.url);
690
699
  return shop.branches.map(
@@ -698,8 +707,8 @@ function localBusinessJsonLd(shop, options = {}) {
698
707
  telephone: b.phone ?? shop.contact.phone ?? void 0,
699
708
  priceRange: options.priceRange,
700
709
  address: compact({ "@type": "PostalAddress", streetAddress: b.address, addressLocality: b.city, addressCountry: shop.country_code }),
701
- geo: b.lat !== null && b.lng !== null ? { "@type": "GeoCoordinates", latitude: b.lat, longitude: b.lng } : void 0,
702
- openingHours: b.hours ? b.hours.split(/\s*,\s*/).filter(Boolean) : void 0,
710
+ geo: isValidPoint(b) ? { "@type": "GeoCoordinates", latitude: b.lat, longitude: b.lng } : void 0,
711
+ openingHours: openingHoursJsonLd(b.opening_hours ?? b.hours),
703
712
  parentOrganization: site ? { "@id": `${site}#organization` } : { "@type": "Organization", name: shop.name }
704
713
  })
705
714
  );
@@ -768,7 +777,7 @@ function resolveSectionProps(schema, raw, path = "") {
768
777
  for (const [name, spec] of Object.entries(schema)) {
769
778
  const key = path ? `${path}.${name}` : name;
770
779
  let value = input[name];
771
- const fail = (message) => {
780
+ const fail2 = (message) => {
772
781
  errors.push({ prop: key, message });
773
782
  if ("default" in spec) props[name] = cloneDefault(spec.default);
774
783
  };
@@ -779,37 +788,37 @@ function resolveSectionProps(schema, raw, path = "") {
779
788
  }
780
789
  if (STRING_KINDS.has(spec.kind)) {
781
790
  if (typeof value !== "string") {
782
- fail("must be a string");
791
+ fail2("must be a string");
783
792
  continue;
784
793
  }
785
794
  } else if (spec.kind === "number") {
786
795
  if (typeof value === "string" && value.trim() !== "" && Number.isFinite(Number(value))) value = Number(value);
787
796
  if (typeof value !== "number" || !Number.isFinite(value)) {
788
- fail("must be a number");
797
+ fail2("must be a number");
789
798
  continue;
790
799
  }
791
800
  if (spec.min !== void 0 && value < spec.min || spec.max !== void 0 && value > spec.max) {
792
- fail(`must be between ${spec.min ?? "-\u221E"} and ${spec.max ?? "\u221E"}`);
801
+ fail2(`must be between ${spec.min ?? "-\u221E"} and ${spec.max ?? "\u221E"}`);
793
802
  continue;
794
803
  }
795
804
  } else if (spec.kind === "boolean") {
796
805
  if (typeof value !== "boolean") {
797
- fail("must be a boolean");
806
+ fail2("must be a boolean");
798
807
  continue;
799
808
  }
800
809
  } else if (spec.kind === "select") {
801
810
  if (typeof value !== "string" || spec.options && !spec.options.some((o) => o.value === value)) {
802
- fail(`must be one of ${(spec.options ?? []).map((o) => o.value).join(", ")}`);
811
+ fail2(`must be one of ${(spec.options ?? []).map((o) => o.value).join(", ")}`);
803
812
  continue;
804
813
  }
805
814
  } else if (spec.kind === "products") {
806
815
  if (!Array.isArray(value) || value.some((v) => typeof v !== "string")) {
807
- fail("must be a list of product handles");
816
+ fail2("must be a list of product handles");
808
817
  continue;
809
818
  }
810
819
  } else if (spec.kind === "list") {
811
820
  if (!Array.isArray(value)) {
812
- fail("must be a list");
821
+ fail2("must be a list");
813
822
  continue;
814
823
  }
815
824
  const items = [];
@@ -980,7 +989,353 @@ function ThemeStyle({ theme, nonce, id = "storefront-theme", ...options }) {
980
989
  if (!css) return null;
981
990
  return /* @__PURE__ */ jsx("style", { id, nonce, "data-storefront-theme": "", dangerouslySetInnerHTML: { __html: css } });
982
991
  }
992
+ var MESSAGES = {
993
+ unsupported: "Tu navegador no permite obtener tu ubicaci\xF3n.",
994
+ insecure: "La ubicaci\xF3n solo est\xE1 disponible en conexiones seguras (HTTPS).",
995
+ denied: "No tenemos permiso para usar tu ubicaci\xF3n. Puedes activarlo en el navegador o escribir tu c\xF3digo postal.",
996
+ unavailable: "No pudimos determinar tu ubicaci\xF3n. Escribe tu c\xF3digo postal.",
997
+ timeout: "Tard\xF3 demasiado en obtener tu ubicaci\xF3n. Intenta de nuevo o escribe tu c\xF3digo postal."
998
+ };
999
+ var fail = (code) => ({ code, message: MESSAGES[code] });
1000
+ var hasGeolocation = () => typeof navigator !== "undefined" && !!navigator.geolocation;
1001
+ function useGeolocation(options = {}) {
1002
+ const { enableHighAccuracy = false, timeoutMs = 1e4, maximumAge = 3e5 } = options;
1003
+ const [supported, setSupported] = useState(false);
1004
+ const [permission, setPermission] = useState("unknown");
1005
+ const [status, setStatus] = useState("idle");
1006
+ const [position, setPosition] = useState(null);
1007
+ const [error, setError] = useState(null);
1008
+ const alive = useRef(true);
1009
+ useEffect(() => {
1010
+ alive.current = true;
1011
+ setSupported(hasGeolocation());
1012
+ let off = () => {
1013
+ };
1014
+ try {
1015
+ const perms = typeof navigator !== "undefined" ? navigator.permissions : void 0;
1016
+ void perms?.query({ name: "geolocation" }).then((p) => {
1017
+ if (!alive.current) return;
1018
+ const sync = () => setPermission(p.state);
1019
+ sync();
1020
+ p.addEventListener?.("change", sync);
1021
+ off = () => p.removeEventListener?.("change", sync);
1022
+ }, () => {
1023
+ });
1024
+ } catch {
1025
+ }
1026
+ return () => {
1027
+ alive.current = false;
1028
+ off();
1029
+ };
1030
+ }, []);
1031
+ const request = useCallback(() => {
1032
+ const failWith = (code) => {
1033
+ if (alive.current) {
1034
+ setStatus("error");
1035
+ setError(fail(code));
1036
+ }
1037
+ return null;
1038
+ };
1039
+ if (!hasGeolocation()) return Promise.resolve(failWith("unsupported"));
1040
+ if (typeof window !== "undefined" && window.isSecureContext === false) return Promise.resolve(failWith("insecure"));
1041
+ setStatus("locating");
1042
+ setError(null);
1043
+ return new Promise((resolve) => {
1044
+ navigator.geolocation.getCurrentPosition(
1045
+ (pos) => {
1046
+ const point = { lat: pos.coords.latitude, lng: pos.coords.longitude };
1047
+ if (alive.current) {
1048
+ setPosition(point);
1049
+ setStatus("success");
1050
+ setPermission("granted");
1051
+ }
1052
+ resolve(point);
1053
+ },
1054
+ (err) => resolve(failWith(err.code === 1 ? "denied" : err.code === 3 ? "timeout" : "unavailable")),
1055
+ { enableHighAccuracy, timeout: timeoutMs, maximumAge }
1056
+ );
1057
+ });
1058
+ }, [enableHighAccuracy, timeoutMs, maximumAge]);
1059
+ const reset = useCallback(() => {
1060
+ setStatus("idle");
1061
+ setPosition(null);
1062
+ setError(null);
1063
+ }, []);
1064
+ return { supported, permission, status, position, error, request, reset };
1065
+ }
1066
+ var EMPTY = [];
1067
+ var IDLE = { locations: [], status: "idle", error: null, source: null };
1068
+ function useNearestLocations(options = {}) {
1069
+ const { origin = null, postalCode = null, limit, radiusKm, remote = false } = options;
1070
+ const sf = useOptionalStorefront();
1071
+ const client = options.client ?? sf?.client ?? null;
1072
+ const branches = options.locations ?? sf?.shop?.branches ?? EMPTY;
1073
+ const lat = origin?.lat;
1074
+ const lng = origin?.lng;
1075
+ const hasOrigin = lat !== void 0 && lng !== void 0;
1076
+ const cp = postalCode?.trim() || null;
1077
+ const mode = useMemo(() => {
1078
+ if (cp) return client ? "remote" : null;
1079
+ if (!hasOrigin) return null;
1080
+ if (remote) return client ? "remote" : null;
1081
+ return branches.length ? "local" : null;
1082
+ }, [cp, hasOrigin, remote, client, branches.length]);
1083
+ const local = useMemo(() => {
1084
+ if (mode !== "local" || !hasOrigin) return [];
1085
+ return rankByDistance(branches, { lat, lng }, { ...radiusKm !== void 0 ? { radiusKm } : {}, ...limit !== void 0 ? { limit } : {} }).map(({ item, distanceKm }) => ({ ...item, distance_km: distanceKm }));
1086
+ }, [mode, branches, lat, lng, radiusKm, limit, hasOrigin]);
1087
+ const [remoteState, setRemoteState] = useState(null);
1088
+ const key = mode === "remote" ? cp ? `cp:${cp}` : `ll:${lat},${lng}` : "";
1089
+ useEffect(() => {
1090
+ if (mode !== "remote" || !client) return;
1091
+ const ctrl = new AbortController();
1092
+ const req = cp ? client.locations.list({ postal_code: cp }, { signal: ctrl.signal }) : client.locations.nearest({ lat, lng }, { signal: ctrl.signal });
1093
+ req.then(
1094
+ (res) => !ctrl.signal.aborted && setRemoteState({ key, nodes: res.nodes }),
1095
+ (err) => !ctrl.signal.aborted && setRemoteState({ key, error: err instanceof Error ? err : new Error(String(err)) })
1096
+ );
1097
+ return () => ctrl.abort();
1098
+ }, [mode, client, key, cp, lat, lng]);
1099
+ return useMemo(() => {
1100
+ if (mode === "local") return { locations: local, status: "success", error: null, source: "local" };
1101
+ if (mode !== "remote") return IDLE;
1102
+ if (!remoteState || remoteState.key !== key) return { locations: [], status: "loading", error: null, source: "remote" };
1103
+ if ("error" in remoteState) return { locations: [], status: "error", error: remoteState.error, source: "remote" };
1104
+ let nodes = remoteState.nodes;
1105
+ if (radiusKm !== void 0) nodes = nodes.filter((n) => n.distance_km == null || n.distance_km <= radiusKm);
1106
+ if (limit !== void 0) nodes = nodes.slice(0, Math.max(0, limit));
1107
+ return { locations: nodes, status: "success", error: null, source: "remote" };
1108
+ }, [mode, local, remoteState, key, radiusKm, limit]);
1109
+ }
1110
+ var SELECTED_LOCATION_PARAM = "sucursal";
1111
+ var SELECTED_LOCATION_STORAGE_KEY = "sf_sucursal";
1112
+ var CHANGE_EVENT = "storefront:selected-location";
1113
+ var storage = () => {
1114
+ try {
1115
+ return typeof localStorage === "undefined" ? null : localStorage;
1116
+ } catch {
1117
+ return null;
1118
+ }
1119
+ };
1120
+ function readSelectedLocationId({ search = typeof location === "undefined" ? "" : location.search, store = storage(), param = SELECTED_LOCATION_PARAM, storageKey = SELECTED_LOCATION_STORAGE_KEY } = {}) {
1121
+ const fromUrl = new URLSearchParams(search).get(param);
1122
+ if (fromUrl) return fromUrl;
1123
+ try {
1124
+ return store?.getItem(storageKey) || null;
1125
+ } catch {
1126
+ return null;
1127
+ }
1128
+ }
1129
+ var EMPTY2 = [];
1130
+ function useSelectedLocation(options = {}) {
1131
+ const { initialId = null, param = SELECTED_LOCATION_PARAM, storageKey = SELECTED_LOCATION_STORAGE_KEY, syncUrl = true } = options;
1132
+ const sf = useOptionalStorefront();
1133
+ const locations = options.locations ?? sf?.shop?.branches ?? EMPTY2;
1134
+ const [raw, setRaw] = useState(initialId);
1135
+ const [ready, setReady] = useState(false);
1136
+ useEffect(() => {
1137
+ const read = () => setRaw(readSelectedLocationId({ param, storageKey }));
1138
+ read();
1139
+ setReady(true);
1140
+ window.addEventListener(CHANGE_EVENT, read);
1141
+ window.addEventListener("storage", read);
1142
+ window.addEventListener("popstate", read);
1143
+ return () => {
1144
+ window.removeEventListener(CHANGE_EVENT, read);
1145
+ window.removeEventListener("storage", read);
1146
+ window.removeEventListener("popstate", read);
1147
+ };
1148
+ }, [param, storageKey]);
1149
+ const location2 = useMemo(() => raw ? locations.find((l) => l.id === raw) ?? null : null, [raw, locations]);
1150
+ const id = location2?.id ?? null;
1151
+ useEffect(() => {
1152
+ if (!ready || !raw || !locations.length) return;
1153
+ try {
1154
+ if (location2) storage()?.setItem(storageKey, raw);
1155
+ else storage()?.removeItem(storageKey);
1156
+ } catch {
1157
+ }
1158
+ }, [ready, raw, locations, location2, storageKey]);
1159
+ const write = useCallback(
1160
+ (next) => {
1161
+ try {
1162
+ if (next) storage()?.setItem(storageKey, next);
1163
+ else storage()?.removeItem(storageKey);
1164
+ } catch {
1165
+ }
1166
+ if (syncUrl && typeof history !== "undefined") {
1167
+ const url = new URL(window.location.href);
1168
+ if (next) url.searchParams.set(param, next);
1169
+ else url.searchParams.delete(param);
1170
+ history.replaceState(history.state, "", url);
1171
+ }
1172
+ setRaw(next);
1173
+ window.dispatchEvent(new Event(CHANGE_EVENT));
1174
+ },
1175
+ [param, storageKey, syncUrl]
1176
+ );
1177
+ const select = useCallback((next) => write(next), [write]);
1178
+ const clear = useCallback(() => write(null), [write]);
1179
+ return { id, location: location2, ready, select, clear };
1180
+ }
1181
+ var EMPTY3 = [];
1182
+ function useLocationsOrShop(locations) {
1183
+ const sf = useOptionalStorefront();
1184
+ return locations ?? (sf?.shop?.branches ?? EMPTY3);
1185
+ }
1186
+ function LocationList({ locations, selectedId, children, ...rest }) {
1187
+ const list = useLocationsOrShop(locations);
1188
+ if (!list.length) return null;
1189
+ return /* @__PURE__ */ jsx("ul", { ...rest, children: list.map((loc, index) => {
1190
+ const selected = loc.id === selectedId;
1191
+ return /* @__PURE__ */ jsx("li", { "data-selected": selected || void 0, "aria-current": selected || void 0, children: children ? children(loc, { index, selected }) : /* @__PURE__ */ jsxs(Fragment, { children: [
1192
+ /* @__PURE__ */ jsx("span", { children: loc.name }),
1193
+ " ",
1194
+ /* @__PURE__ */ jsx("span", { children: loc.address })
1195
+ ] }) }, loc.id);
1196
+ }) });
1197
+ }
1198
+ function LocationPicker({
1199
+ legend,
1200
+ locations,
1201
+ value,
1202
+ defaultValue = null,
1203
+ onChange,
1204
+ name = SELECTED_LOCATION_PARAM,
1205
+ children,
1206
+ ...rest
1207
+ }) {
1208
+ const list = useLocationsOrShop(locations);
1209
+ const [inner, setInner] = useState(defaultValue);
1210
+ if (!list.length) return null;
1211
+ const current = value !== void 0 ? value : inner;
1212
+ return /* @__PURE__ */ jsxs("fieldset", { ...rest, children: [
1213
+ /* @__PURE__ */ jsx("legend", { children: legend }),
1214
+ list.map((loc) => {
1215
+ const checked = loc.id === current;
1216
+ return /* @__PURE__ */ jsxs("label", { "data-checked": checked || void 0, children: [
1217
+ /* @__PURE__ */ jsx(
1218
+ "input",
1219
+ {
1220
+ type: "radio",
1221
+ name,
1222
+ value: loc.id,
1223
+ checked,
1224
+ onChange: () => {
1225
+ if (value === void 0) setInner(loc.id);
1226
+ onChange?.(loc.id, loc);
1227
+ }
1228
+ }
1229
+ ),
1230
+ " ",
1231
+ children ? children(loc, { checked }) : /* @__PURE__ */ jsxs(Fragment, { children: [
1232
+ /* @__PURE__ */ jsx("span", { children: loc.name }),
1233
+ " ",
1234
+ /* @__PURE__ */ jsx("span", { children: loc.address })
1235
+ ] })
1236
+ ] }, loc.id);
1237
+ })
1238
+ ] });
1239
+ }
1240
+ var DEFAULT_TZ = "America/Mexico_City";
1241
+ function OpenStatus({ location: location2, hours, timezone, now, labels, children, ...rest }) {
1242
+ const h = hours ?? location2?.opening_hours;
1243
+ const tz = timezone ?? location2?.timezone ?? DEFAULT_TZ;
1244
+ const [tick, setTick] = useState(null);
1245
+ useEffect(() => {
1246
+ if (now) return;
1247
+ setTick(/* @__PURE__ */ new Date());
1248
+ const t = setInterval(() => setTick(/* @__PURE__ */ new Date()), 6e4);
1249
+ return () => clearInterval(t);
1250
+ }, [now]);
1251
+ const at = now ?? tick;
1252
+ if (!h || !at) return null;
1253
+ let status;
1254
+ try {
1255
+ status = openStatus(h, tz, at);
1256
+ } catch {
1257
+ return null;
1258
+ }
1259
+ const text = { open: "Abierto", closed: "Cerrado", ...labels };
1260
+ return /* @__PURE__ */ jsx("span", { "data-state": status.open ? "open" : "closed", ...rest, children: children ? children(status) : status.open ? text.open : text.closed });
1261
+ }
1262
+ function DirectionsLink({ location: location2, provider, children = "C\xF3mo llegar", ...rest }) {
1263
+ const href = directionsUrl(location2, provider ? { provider } : {});
1264
+ if (!href) return null;
1265
+ return /* @__PURE__ */ jsx("a", { target: "_blank", rel: "noopener noreferrer", ...rest, href, children });
1266
+ }
1267
+ var readyText = (days) => days <= 0 ? "listo hoy" : days === 1 ? "listo en 1 d\xEDa" : `listo en ${days} d\xEDas`;
1268
+ function PickupOption({ location: location2, locale, children, ...rest }) {
1269
+ const sf = useOptionalStorefront();
1270
+ const p = location2.pickup;
1271
+ if (!p?.enabled) return null;
1272
+ const free = !p.fee || Number(p.fee.amount) === 0;
1273
+ const feeText = free ? null : formatMoney(p.fee, locale ?? sf?.locale);
1274
+ const info = { location: location2, fee: free ? null : p.fee, free, feeText, prepDays: p.prep_days };
1275
+ return /* @__PURE__ */ jsx("span", { ...rest, children: children ? children(info) : `Recoge en sucursal \xB7 ${free ? "gratis" : feeText} \xB7 ${readyText(p.prep_days)}` });
1276
+ }
1277
+ function NearestLocationForm({
1278
+ locations,
1279
+ action,
1280
+ name = "cp",
1281
+ defaultValue,
1282
+ onSubmitPostalCode,
1283
+ onLocate,
1284
+ labels,
1285
+ children,
1286
+ ...rest
1287
+ }) {
1288
+ const list = useLocationsOrShop(locations);
1289
+ const id = useId();
1290
+ const geo = useGeolocation();
1291
+ if (!list.length) return null;
1292
+ const text = { postalCode: "C\xF3digo postal", submit: "Buscar sucursales", locate: "Usar mi ubicaci\xF3n", locating: "Buscando\u2026", ...labels };
1293
+ return /* @__PURE__ */ jsxs(
1294
+ "form",
1295
+ {
1296
+ method: "get",
1297
+ ...action !== void 0 ? { action } : {},
1298
+ ...rest,
1299
+ onSubmit: onSubmitPostalCode ? (e) => {
1300
+ e.preventDefault();
1301
+ const value = new FormData(e.currentTarget).get(name);
1302
+ onSubmitPostalCode(typeof value === "string" ? value.trim() : "", e);
1303
+ } : void 0,
1304
+ children: [
1305
+ /* @__PURE__ */ jsx("label", { htmlFor: id, children: text.postalCode }),
1306
+ " ",
1307
+ /* @__PURE__ */ jsx(
1308
+ "input",
1309
+ {
1310
+ id,
1311
+ name,
1312
+ type: "text",
1313
+ inputMode: "numeric",
1314
+ autoComplete: "postal-code",
1315
+ pattern: "[0-9]{5}",
1316
+ maxLength: 5,
1317
+ required: true,
1318
+ ...defaultValue !== void 0 ? { defaultValue } : {}
1319
+ }
1320
+ ),
1321
+ " ",
1322
+ /* @__PURE__ */ jsx("button", { type: "submit", children: text.submit }),
1323
+ onLocate && geo.supported && /* @__PURE__ */ jsx(
1324
+ "button",
1325
+ {
1326
+ type: "button",
1327
+ disabled: geo.status === "locating",
1328
+ onClick: () => void geo.request().then((p) => p && onLocate(p)),
1329
+ children: geo.status === "locating" ? text.locating : text.locate
1330
+ }
1331
+ ),
1332
+ geo.error && /* @__PURE__ */ jsx("span", { role: "alert", children: geo.error.message }),
1333
+ children
1334
+ ]
1335
+ }
1336
+ );
1337
+ }
983
1338
 
984
- export { AddToCartButton, CART_COOKIE_NAME, CartProvider, DEFAULT_IMAGE_WIDTHS, Image, JsonLd, Money, ProductPrice, SectionRegistry, Sections, StorefrontProvider, ThemeStyle, VariantSelector, breadcrumbJsonLd, collectionJsonLd, collectionMeta, createSectionRegistry, defaultImageLoader, defineSection, faqJsonLd, getCartIdFromCookie, isSafeCssValue, localBusinessJsonLd, optimisticCart, organizationJsonLd, productJsonLd, productMeta, readCartCookie, resolveSectionProps, sectionJsonSchema, seoMeta, serializeCartCookie, serializeJsonLd, themeFontsHref, themeToCss, themeToCssVariables, toMerchandise, tokenName, useCart, useOptionalCart, useOptionalStorefront, useProductOptions, useStorefront, useStorefrontClient, writeCartCookie };
1339
+ export { AddToCartButton, CART_COOKIE_NAME, CartProvider, DEFAULT_IMAGE_WIDTHS, DirectionsLink, Image, JsonLd, LocationList, LocationPicker, Money, NearestLocationForm, OpenStatus, PickupOption, ProductPrice, SELECTED_LOCATION_PARAM, SELECTED_LOCATION_STORAGE_KEY, SectionRegistry, Sections, StorefrontProvider, ThemeStyle, VariantSelector, breadcrumbJsonLd, collectionJsonLd, collectionMeta, createSectionRegistry, defaultImageLoader, defineSection, faqJsonLd, getCartIdFromCookie, isSafeCssValue, localBusinessJsonLd, openingHoursJsonLd, optimisticCart, organizationJsonLd, productJsonLd, productMeta, readCartCookie, readSelectedLocationId, resolveSectionProps, sectionJsonSchema, seoMeta, serializeCartCookie, serializeJsonLd, themeFontsHref, themeToCss, themeToCssVariables, toMerchandise, tokenName, useCart, useGeolocation, useNearestLocations, useOptionalCart, useOptionalStorefront, useProductOptions, useSelectedLocation, useStorefront, useStorefrontClient, writeCartCookie };
985
1340
  //# sourceMappingURL=index.js.map
986
1341
  //# sourceMappingURL=index.js.map