@occluze/tether 0.3.6 → 0.5.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.
Files changed (45) hide show
  1. package/README.md +12 -7
  2. package/dist/esm/astro.js +2 -0
  3. package/dist/esm/chunks/chunk-HHMOPDZG.js +1 -0
  4. package/dist/esm/chunks/chunk-HXKV6QGB.js +4 -0
  5. package/dist/esm/chunks/chunk-RBVRRQIU.js +1 -0
  6. package/dist/esm/chunks/chunk-RNZMTQTX.js +1 -0
  7. package/dist/esm/chunks/chunk-VC46IEJQ.js +1 -0
  8. package/dist/esm/chunks/diagnose-J667GHGS.js +1 -0
  9. package/dist/esm/chunks/markets-ui-EGWIEUOZ.js +1 -0
  10. package/dist/esm/index.js +1 -0
  11. package/dist/esm/server.js +1 -0
  12. package/dist/presets/barba.esm.js +4 -5
  13. package/dist/tether.diagnose.js +320 -0
  14. package/dist/tether.diagnose.min.js +1 -0
  15. package/dist/tether.esm.js +2 -2608
  16. package/dist/tether.js +637 -833
  17. package/dist/tether.markets.js +213 -0
  18. package/dist/tether.markets.min.js +1 -0
  19. package/dist/tether.min.js +3 -132
  20. package/dist/tether.min.js.map +4 -4
  21. package/package.json +52 -11
  22. package/src/astro.js +73 -0
  23. package/src/cart.js +79 -7
  24. package/src/client.js +25 -15
  25. package/src/config.js +4 -0
  26. package/src/diagnose.js +1 -1
  27. package/src/dom.js +32 -9
  28. package/src/fragments.js +12 -11
  29. package/src/index.js +80 -160
  30. package/src/initial.js +66 -0
  31. package/src/lazy-iife.js +43 -0
  32. package/src/lazy.js +9 -0
  33. package/src/loader.js +50 -7
  34. package/src/markets-ui.js +89 -0
  35. package/src/markets.js +1 -1
  36. package/src/mounting.js +129 -0
  37. package/src/parts/diagnose.js +3 -0
  38. package/src/parts/markets.js +3 -0
  39. package/src/product.js +86 -61
  40. package/src/server.js +179 -0
  41. package/src/status.js +2 -6
  42. package/types/astro.d.ts +15 -0
  43. package/types/barba.d.ts +16 -0
  44. package/types/index.d.ts +347 -0
  45. package/types/server.d.ts +94 -0
@@ -0,0 +1,213 @@
1
+ (() => {
2
+ var __defProp = Object.defineProperty;
3
+ var __export = (target, all) => {
4
+ for (var name in all)
5
+ __defProp(target, name, { get: all[name], enumerable: true });
6
+ };
7
+
8
+ // src/markets-ui.js
9
+ var markets_ui_exports = {};
10
+ __export(markets_ui_exports, {
11
+ detectMarket: () => detectMarket,
12
+ getLocalization: () => getLocalization,
13
+ renderCountrySelects: () => renderCountrySelects,
14
+ setCountry: () => setCountry
15
+ });
16
+
17
+ // tether-core:config.js
18
+ var m = window.Tether.__core["config.js"];
19
+ var { DEFAULTS, cfg, configure, isConfigured, log, reportError, warn } = m;
20
+
21
+ // tether-core:client.js
22
+ var m2 = window.Tether.__core["client.js"];
23
+ var { TetherError, endpoint, gql, request, unwrap, withContext } = m2;
24
+
25
+ // tether-core:cart.js
26
+ var m3 = window.Tether.__core["cart.js"];
27
+ var { Cart, focusables, toLineInput } = m3;
28
+
29
+ // tether-core:collection.js
30
+ var m4 = window.Tether.__core["collection.js"];
31
+ var { ListScope, listSelector } = m4;
32
+
33
+ // tether-core:loader.js
34
+ var m5 = window.Tether.__core["loader.js"];
35
+ var { clearProductCache, getProduct, getProducts, getRecommendations, hydrateProducts, normalizeProductKey, primeProduct, refreshProducts, takeStale } = m5;
36
+
37
+ // tether-core:dom.js
38
+ var m6 = window.Tether.__core["dom.js"];
39
+ var { attr, busy, cdnUrl, dataKey, emit, formatDate, formatMoney, get, has, hasTemplate, imageUrl, notifyLayoutChanged, parseJSONAttr, productUrl, qsa, readText, repeat, repeatKeyed, sameImage, scoped, sel, setImage, setSelected, setText, setTextTracked, show, toAttributes, watchImages } = m6;
40
+
41
+ // tether-core:mounting.js
42
+ var m7 = window.Tether.__core["mounting.js"];
43
+ var { hydrateFromPage, liveLists, liveProducts, mountProduct, mountedLists, mountedProducts, pruneLive, retryFailed, within } = m7;
44
+
45
+ // src/markets.js
46
+ var COUNTRY = /^[A-Z]{2}$/;
47
+ var REGIONAL_LANGUAGES = /* @__PURE__ */ new Set(["PT_BR", "PT_PT", "ZH_CN", "ZH_TW"]);
48
+ var storageKey = () => `${cfg.prefix}:market:${cfg.domain}`;
49
+ var defaultEnv = () => ({
50
+ document: typeof document !== "undefined" ? document : null,
51
+ location: typeof window !== "undefined" ? window.location : null,
52
+ storage: (() => {
53
+ try {
54
+ return window.localStorage;
55
+ } catch {
56
+ return null;
57
+ }
58
+ })(),
59
+ global: typeof window !== "undefined" ? window : {}
60
+ });
61
+ function toCountry(v) {
62
+ const c = String(v || "").trim().toUpperCase();
63
+ return COUNTRY.test(c) && c !== "XX" && c !== "T1" ? c : null;
64
+ }
65
+ function toLanguage(v) {
66
+ const raw = String(v || "").trim().replace("-", "_").toUpperCase();
67
+ if (!raw) return null;
68
+ if (REGIONAL_LANGUAGES.has(raw)) return raw;
69
+ const primary = raw.split("_")[0];
70
+ return /^[A-Z]{2,3}$/.test(primary) ? primary : null;
71
+ }
72
+ function readCookie(doc, name) {
73
+ if (!doc || !name) return null;
74
+ const hit = String(doc.cookie || "").split(";").map((c) => c.trim()).find((c) => c.startsWith(`${name}=`));
75
+ return hit ? decodeURIComponent(hit.slice(name.length + 1)) : null;
76
+ }
77
+ var lookup = (locales, key) => {
78
+ if (!locales || !key) return null;
79
+ const k = String(key).toLowerCase();
80
+ const found = Object.keys(locales).find((x) => x.toLowerCase() === k);
81
+ return found ? locales[found] : null;
82
+ };
83
+ var readers = {
84
+ saved(m8, env) {
85
+ if (m8.remember === false || !env.storage) return null;
86
+ try {
87
+ return JSON.parse(env.storage.getItem(storageKey()) || "null");
88
+ } catch {
89
+ return null;
90
+ }
91
+ },
92
+ server(m8, env) {
93
+ const meta = (name) => env.document?.querySelector?.(`meta[name="${name}"]`)?.getAttribute("content");
94
+ const country = env.global.TETHER_COUNTRY || meta("tether-country") || readCookie(env.document, m8.cookie || "tether_country");
95
+ const language = env.global.TETHER_LANGUAGE || meta("tether-language");
96
+ return { country, language };
97
+ },
98
+ webflow(m8, env) {
99
+ const segment = (env.location?.pathname || "/").split("/").filter(Boolean)[0];
100
+ const fromPath = lookup(m8.locales, segment);
101
+ if (fromPath) return fromPath;
102
+ const lang = env.document?.documentElement?.getAttribute("lang");
103
+ if (!lang) return null;
104
+ const mapped = lookup(m8.locales, lang) || lookup(m8.locales, lang.split("-")[0]);
105
+ if (mapped) return { locale: lang, ...mapped };
106
+ if (m8.locales && m8.strict) return null;
107
+ const region = lang.split("-")[1];
108
+ return { language: lang, country: region && region.length === 2 ? region : null, locale: lang };
109
+ }
110
+ };
111
+ function detectMarket(markets = cfg.markets, env = defaultEnv()) {
112
+ const m8 = markets || {};
113
+ if (m8.detect === false) return {};
114
+ const list = !m8.detect ? ["saved"] : m8.detect === true ? ["saved", "server", "webflow"] : [].concat(m8.detect);
115
+ markets = m8;
116
+ const out = { sources: {} };
117
+ list.forEach((name) => {
118
+ const r = readers[name]?.(markets, env);
119
+ if (!r) return;
120
+ const vals = { country: toCountry(r.country), language: toLanguage(r.language), locale: r.locale || null };
121
+ Object.entries(vals).forEach(([k, v]) => {
122
+ if (v && !out[k]) {
123
+ out[k] = v;
124
+ out.sources[k] = name;
125
+ }
126
+ });
127
+ });
128
+ return out;
129
+ }
130
+ function rememberMarket(market) {
131
+ if (cfg.markets?.remember === false) return;
132
+ try {
133
+ localStorage.setItem(storageKey(), JSON.stringify({ country: market.country, language: market.language || void 0, locale: market.locale || void 0 }));
134
+ } catch {
135
+ }
136
+ }
137
+ var localizationPromise = null;
138
+ function clearLocalization() {
139
+ localizationPromise = null;
140
+ }
141
+ function getLocalization() {
142
+ if (!localizationPromise) {
143
+ localizationPromise = gql(`query TetherLocalization{localization{country{isoCode name currency{isoCode symbol}}language{isoCode name}availableCountries{isoCode name currency{isoCode symbol}availableLanguages{isoCode name}}}}`).then((d) => d.localization).catch((err) => {
144
+ localizationPromise = null;
145
+ throw err;
146
+ });
147
+ }
148
+ return localizationPromise;
149
+ }
150
+
151
+ // src/markets-ui.js
152
+ function renderCountrySelects(root = document) {
153
+ const selects = within(root, `select${sel("country-select")}`);
154
+ const binds = within(root, sel("country-bind"));
155
+ if (!selects.length && !binds.length) return Promise.resolve();
156
+ return getLocalization().then((loc) => {
157
+ const current = (cfg.country || loc.country?.isoCode || "").toUpperCase();
158
+ const countries = [...loc.availableCountries || []].sort((a, b) => a.name.localeCompare(b.name, cfg.locale || void 0));
159
+ const info = countries.find((c) => c.isoCode === current) || loc.country;
160
+ const fill = (tpl, c) => tpl.replace(/\{name\}/g, c.name).replace(/\{code\}/g, c.isoCode).replace(/\{currency\}/g, c.currency?.isoCode || "").replace(/\{symbol\}/g, c.currency?.symbol || "");
161
+ selects.forEach((s) => {
162
+ const tpl = s.getAttribute(attr("country-label")) || "{name} ({currency})";
163
+ const only = (s.getAttribute(attr("countries")) || "").toUpperCase().split(/[\s,]+/).filter(Boolean);
164
+ const list = only.length ? only.map((c) => countries.find((x) => x.isoCode === c)).filter(Boolean) : countries;
165
+ s.innerHTML = "";
166
+ list.forEach((c) => s.appendChild(new Option(fill(tpl, c), c.isoCode)));
167
+ s.value = current;
168
+ if (s.value !== current) s.selectedIndex = -1;
169
+ s.disabled = list.length < 2 && !s.hasAttribute(attr("always-enabled"));
170
+ });
171
+ binds.forEach((el) => {
172
+ const k = get(el, "country-bind") || "name";
173
+ const v = { name: info?.name, code: info?.isoCode, currency: info?.currency?.isoCode, symbol: info?.currency?.symbol }[k];
174
+ el.textContent = v || "";
175
+ });
176
+ }).catch((err) => reportError(err, "country select"));
177
+ }
178
+ async function setCountry(code, { language, locale, remember = true } = {}) {
179
+ const country = toCountry(code);
180
+ if (!country) throw new TetherError(`Not a country code: ${code}`, { code: "INVALID_COUNTRY" });
181
+ const entry = Object.values(cfg.markets?.locales || {}).find((m8) => toCountry(m8?.country) === country);
182
+ const own = locale || entry?.locale;
183
+ const loc = own || cfg.locale;
184
+ const lang = language === void 0 ? cfg.language : toLanguage(language);
185
+ const changed = country !== String(cfg.country || "").toUpperCase() || lang !== cfg.language || loc !== cfg.locale;
186
+ cfg.country = country;
187
+ cfg.language = lang || void 0;
188
+ cfg.locale = loc;
189
+ if (remember) rememberMarket({ country, language: lang, locale: own });
190
+ if (!changed) {
191
+ renderCountrySelects();
192
+ return Cart.state;
193
+ }
194
+ clearProductCache();
195
+ const jobs = [];
196
+ if (language !== void 0) clearLocalization();
197
+ if (Cart.id()) jobs.push(Cart.setBuyerIdentity({ countryCode: country }, { create: false }).catch((err) => reportError(err, "cart country")));
198
+ pruneLive();
199
+ liveLists.forEach((list) => jobs.push(list.load()));
200
+ liveProducts.forEach((el) => {
201
+ if (el.closest(listSelector())) return;
202
+ mountedProducts.delete(el);
203
+ mountProduct(el);
204
+ });
205
+ renderCountrySelects();
206
+ emit("country-changed", { country, language: cfg.language });
207
+ await Promise.all(jobs);
208
+ return Cart.state;
209
+ }
210
+
211
+ // src/parts/markets.js
212
+ window.Tether.__parts.markets = markets_ui_exports;
213
+ })();
@@ -0,0 +1 @@
1
+ (()=>{var G=Object.defineProperty;var H=(e,t)=>{for(var r in t)G(e,r,{get:t[r],enumerable:!0})};var P={};H(P,{detectMarket:()=>$,getLocalization:()=>w,renderCountrySelects:()=>x,setCountry:()=>oe});var K=window.Tether.__core["config.js"],{DEFAULTS:ne,cfg:a,configure:ce,isConfigured:ae,log:le,reportError:C,warn:se}=K;var Z=window.Tether.__core["client.js"],{TetherError:E,endpoint:ue,gql:S,request:de,unwrap:me,withContext:fe}=Z;var D=window.Tether.__core["cart.js"],{Cart:f,focusables:pe,toLineInput:ye}=D;var F=window.Tether.__core["collection.js"],{ListScope:we,listSelector:A}=F;var J=window.Tether.__core["loader.js"],{clearProductCache:v,getProduct:be,getProducts:Te,getRecommendations:_e,hydrateProducts:Le,normalizeProductKey:xe,primeProduct:Pe,refreshProducts:Ee,takeStale:Se}=J;var Y=window.Tether.__core["dom.js"],{attr:y,busy:ve,cdnUrl:Ue,dataKey:Ie,emit:U,formatDate:Ne,formatMoney:je,get:I,has:ke,hasTemplate:Oe,imageUrl:ze,notifyLayoutChanged:Re,parseJSONAttr:$e,productUrl:qe,qsa:Me,readText:Be,repeat:Ge,repeatKeyed:He,sameImage:Ke,scoped:Ze,sel:b,setImage:De,setSelected:Fe,setText:Je,setTextTracked:Ye,show:We,toAttributes:Xe,watchImages:Ve}=Y;var W=window.Tether.__core["mounting.js"],{hydrateFromPage:et,liveLists:N,liveProducts:j,mountProduct:k,mountedLists:tt,mountedProducts:O,pruneLive:z,retryFailed:ot,within:T}=W;var X=/^[A-Z]{2}$/,V=new Set(["PT_BR","PT_PT","ZH_CN","ZH_TW"]),R=()=>`${a.prefix}:market:${a.domain}`,Q=()=>({document:typeof document<"u"?document:null,location:typeof window<"u"?window.location:null,storage:(()=>{try{return window.localStorage}catch{return null}})(),global:typeof window<"u"?window:{}});function h(e){let t=String(e||"").trim().toUpperCase();return X.test(t)&&t!=="XX"&&t!=="T1"?t:null}function L(e){let t=String(e||"").trim().replace("-","_").toUpperCase();if(!t)return null;if(V.has(t))return t;let r=t.split("_")[0];return/^[A-Z]{2,3}$/.test(r)?r:null}function ee(e,t){if(!e||!t)return null;let r=String(e.cookie||"").split(";").map(c=>c.trim()).find(c=>c.startsWith(`${t}=`));return r?decodeURIComponent(r.slice(t.length+1)):null}var _=(e,t)=>{if(!e||!t)return null;let r=String(t).toLowerCase(),c=Object.keys(e).find(o=>o.toLowerCase()===r);return c?e[c]:null},te={saved(e,t){if(e.remember===!1||!t.storage)return null;try{return JSON.parse(t.storage.getItem(R())||"null")}catch{return null}},server(e,t){let r=i=>t.document?.querySelector?.(`meta[name="${i}"]`)?.getAttribute("content"),c=t.global.TETHER_COUNTRY||r("tether-country")||ee(t.document,e.cookie||"tether_country"),o=t.global.TETHER_LANGUAGE||r("tether-language");return{country:c,language:o}},webflow(e,t){let r=(t.location?.pathname||"/").split("/").filter(Boolean)[0],c=_(e.locales,r);if(c)return c;let o=t.document?.documentElement?.getAttribute("lang");if(!o)return null;let i=_(e.locales,o)||_(e.locales,o.split("-")[0]);if(i)return{locale:o,...i};if(e.locales&&e.strict)return null;let l=o.split("-")[1];return{language:o,country:l&&l.length===2?l:null,locale:o}}};function $(e=a.markets,t=Q()){let r=e||{};if(r.detect===!1)return{};let c=r.detect?r.detect===!0?["saved","server","webflow"]:[].concat(r.detect):["saved"];e=r;let o={sources:{}};return c.forEach(i=>{let l=te[i]?.(e,t);if(!l)return;let m={country:h(l.country),language:L(l.language),locale:l.locale||null};Object.entries(m).forEach(([n,s])=>{s&&!o[n]&&(o[n]=s,o.sources[n]=i)})}),o}function q(e){if(a.markets?.remember!==!1)try{localStorage.setItem(R(),JSON.stringify({country:e.country,language:e.language||void 0,locale:e.locale||void 0}))}catch{}}var g=null;function M(){g=null}function w(){return g||(g=S("query TetherLocalization{localization{country{isoCode name currency{isoCode symbol}}language{isoCode name}availableCountries{isoCode name currency{isoCode symbol}availableLanguages{isoCode name}}}}").then(e=>e.localization).catch(e=>{throw g=null,e})),g}function x(e=document){let t=T(e,`select${b("country-select")}`),r=T(e,b("country-bind"));return!t.length&&!r.length?Promise.resolve():w().then(c=>{let o=(a.country||c.country?.isoCode||"").toUpperCase(),i=[...c.availableCountries||[]].sort((n,s)=>n.name.localeCompare(s.name,a.locale||void 0)),l=i.find(n=>n.isoCode===o)||c.country,m=(n,s)=>n.replace(/\{name\}/g,s.name).replace(/\{code\}/g,s.isoCode).replace(/\{currency\}/g,s.currency?.isoCode||"").replace(/\{symbol\}/g,s.currency?.symbol||"");t.forEach(n=>{let s=n.getAttribute(y("country-label"))||"{name} ({currency})",d=(n.getAttribute(y("countries"))||"").toUpperCase().split(/[\s,]+/).filter(Boolean),u=d.length?d.map(p=>i.find(B=>B.isoCode===p)).filter(Boolean):i;n.innerHTML="",u.forEach(p=>n.appendChild(new Option(m(s,p),p.isoCode))),n.value=o,n.value!==o&&(n.selectedIndex=-1),n.disabled=u.length<2&&!n.hasAttribute(y("always-enabled"))}),r.forEach(n=>{let s=I(n,"country-bind")||"name",d={name:l?.name,code:l?.isoCode,currency:l?.currency?.isoCode,symbol:l?.currency?.symbol}[s];n.textContent=d||""})}).catch(c=>C(c,"country select"))}async function oe(e,{language:t,locale:r,remember:c=!0}={}){let o=h(e);if(!o)throw new E(`Not a country code: ${e}`,{code:"INVALID_COUNTRY"});let i=Object.values(a.markets?.locales||{}).find(u=>h(u?.country)===o),l=r||i?.locale,m=l||a.locale,n=t===void 0?a.language:L(t),s=o!==String(a.country||"").toUpperCase()||n!==a.language||m!==a.locale;if(a.country=o,a.language=n||void 0,a.locale=m,c&&q({country:o,language:n,locale:l}),!s)return x(),f.state;v();let d=[];return t!==void 0&&M(),f.id()&&d.push(f.setBuyerIdentity({countryCode:o},{create:!1}).catch(u=>C(u,"cart country"))),z(),N.forEach(u=>d.push(u.load())),j.forEach(u=>{u.closest(A())||(O.delete(u),k(u))}),x(),U("country-changed",{country:o,language:a.language}),await Promise.all(d),f.state}window.Tether.__parts.markets=P;})();