@occluze/tether 0.8.1 → 0.9.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.
Files changed (73) hide show
  1. package/README.md +5 -5
  2. package/dist/esm/astro.js +1 -1
  3. package/dist/esm/chunks/account-LCMJ7QU5.js +1 -0
  4. package/dist/esm/chunks/{account-pages-XR6QZ3DX.js → account-pages-3C5KTPQV.js} +1 -1
  5. package/dist/esm/chunks/analytics-VWSZOX2D.js +1 -0
  6. package/dist/esm/chunks/{chunk-HXZSNZOV.js → chunk-2A2GN3Z7.js} +1 -1
  7. package/dist/esm/chunks/{chunk-A3GXCQJ4.js → chunk-2IGCUTG5.js} +1 -1
  8. package/dist/esm/chunks/{chunk-COQ6ATC6.js → chunk-3UCVDDK6.js} +1 -1
  9. package/dist/esm/chunks/chunk-D3MRWOFI.js +1 -0
  10. package/dist/esm/chunks/chunk-EUCFOBIT.js +1 -0
  11. package/dist/esm/chunks/{chunk-A2PCQK2F.js → chunk-F2BYVA7V.js} +1 -1
  12. package/dist/esm/chunks/chunk-HROQXZYN.js +1 -0
  13. package/dist/esm/chunks/{chunk-X2JZPXLF.js → chunk-MJNPD6LB.js} +1 -1
  14. package/dist/esm/chunks/{chunk-FM7ZLLVP.js → chunk-OURC3H6L.js} +1 -1
  15. package/dist/esm/chunks/chunk-P6DV24RG.js +1 -0
  16. package/dist/esm/chunks/chunk-P73VN3B6.js +1 -0
  17. package/dist/esm/chunks/chunk-S5BUUIB6.js +1 -0
  18. package/dist/esm/chunks/chunk-SOFWDTR7.js +1 -0
  19. package/dist/esm/chunks/{chunk-FPJGQ7Z5.js → chunk-XU27NSXT.js} +1 -1
  20. package/dist/esm/chunks/chunk-YJC3CSEG.js +1 -0
  21. package/dist/esm/chunks/chunk-ZBV2JSHE.js +1 -0
  22. package/dist/esm/chunks/{diagnose-IFRNCEYG.js → diagnose-TE72GNOO.js} +1 -1
  23. package/dist/esm/chunks/extras-7GTMJMOZ.js +1 -0
  24. package/dist/esm/chunks/lists-ZMVRGD6L.js +1 -0
  25. package/dist/esm/chunks/markets-ui-AAQM4PEE.js +1 -0
  26. package/dist/esm/chunks/search-PWF4YZQO.js +1 -0
  27. package/dist/esm/index.js +1 -1
  28. package/dist/esm/server.js +2 -2
  29. package/dist/tether.account-pages.js +2 -2
  30. package/dist/tether.account-pages.min.js +1 -1
  31. package/dist/tether.account.js +2 -2
  32. package/dist/tether.account.min.js +1 -1
  33. package/dist/tether.analytics.js +2 -2
  34. package/dist/tether.analytics.min.js +1 -1
  35. package/dist/tether.diagnose.js +4 -4
  36. package/dist/tether.diagnose.min.js +2 -2
  37. package/dist/tether.extras.js +1 -1
  38. package/dist/tether.extras.min.js +1 -1
  39. package/dist/tether.js +85 -201
  40. package/dist/tether.lists.js +268 -0
  41. package/dist/tether.lists.min.js +1 -0
  42. package/dist/tether.markets.js +3 -3
  43. package/dist/tether.markets.min.js +1 -1
  44. package/dist/tether.min.js +1 -1
  45. package/dist/tether.min.js.map +4 -4
  46. package/dist/tether.search.js +2 -2
  47. package/dist/tether.search.min.js +1 -1
  48. package/dist/types/src/client.d.ts +6 -6
  49. package/dist/types/src/collection.d.ts +7 -23
  50. package/dist/types/src/config-sections.d.ts +7 -0
  51. package/dist/types/src/config.d.ts +6 -0
  52. package/dist/types/src/index.d.ts +4 -3
  53. package/dist/types/src/lazy.d.ts +1 -0
  54. package/dist/types/src/lists.d.ts +20 -0
  55. package/dist/types/src/loader.d.ts +7 -27
  56. package/dist/types/src/mounting.d.ts +1 -6
  57. package/dist/types/src/product-shape.d.ts +13 -36
  58. package/dist/types/src/server.d.ts +5 -4
  59. package/dist/types/src/shopify-values.d.ts +6 -0
  60. package/dist/types/src/storefront/catalog.d.ts +2 -4
  61. package/dist/types/src/version.d.ts +1 -1
  62. package/package.json +7 -6
  63. package/dist/esm/chunks/account-BS5MCC2R.js +0 -1
  64. package/dist/esm/chunks/analytics-BYN3QHBA.js +0 -1
  65. package/dist/esm/chunks/chunk-2IVIZDT5.js +0 -1
  66. package/dist/esm/chunks/chunk-EGIDFV3T.js +0 -1
  67. package/dist/esm/chunks/chunk-EW3GKRT4.js +0 -1
  68. package/dist/esm/chunks/chunk-GXCCTPDF.js +0 -1
  69. package/dist/esm/chunks/chunk-MJFKAMFM.js +0 -1
  70. package/dist/esm/chunks/chunk-TE5PNI76.js +0 -1
  71. package/dist/esm/chunks/extras-3477M6Y7.js +0 -1
  72. package/dist/esm/chunks/markets-ui-3L2UZ7PK.js +0 -1
  73. package/dist/esm/chunks/search-YR73GIWY.js +0 -1
@@ -0,0 +1,268 @@
1
+ (() => {
2
+ var __defProp = Object.defineProperty;
3
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4
+ var __export = (target, all) => {
5
+ for (var name in all)
6
+ __defProp(target, name, { get: all[name], enumerable: true });
7
+ };
8
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
9
+
10
+ // src/lists.ts
11
+ var lists_exports = {};
12
+ __export(lists_exports, {
13
+ getProducts: () => getProducts,
14
+ getRecommendations: () => getRecommendations,
15
+ loadList: () => loadList
16
+ });
17
+
18
+ // tether-core:config.ts
19
+ var m = window.Tether.__core["config.ts"];
20
+ var [cfg, isConfigured, log, MARKET_SOURCES, parseMarkets, reportError, warn] = m;
21
+
22
+ // tether-core:client.ts
23
+ var m2 = window.Tether.__core["client.ts"];
24
+ var [endpoint, gql, matches, orNull, shaped, TetherError] = m2;
25
+
26
+ // tether-core:dom.ts
27
+ var m3 = window.Tether.__core["dom.ts"];
28
+ var [ANALYTICS_EVENTS, attr, attributesFromJson, busy, emit, formatDate, formatMoney, get, has, hasTemplate, isOwnEvent, notifyLayoutChanged, parseJSONAttr, productUrl, qsa, repeat, scoped, sel, setImage, setStoreHtml, setText, show] = m3;
29
+
30
+ // tether-core:fragments.ts
31
+ var m4 = window.Tether.__core["fragments.ts"];
32
+ var [collectionFields] = m4;
33
+
34
+ // tether-core:loader.ts
35
+ var m5 = window.Tether.__core["loader.ts"];
36
+ var [clearProductCache, getProduct, normalizeProductKey, primeProduct, withProductFragment] = m5;
37
+
38
+ // server/src/shared/json.ts
39
+ function isRecord(value) {
40
+ return value !== null && typeof value === "object" && !Array.isArray(value);
41
+ }
42
+
43
+ // src/product-shape.ts
44
+ var MONEY = { amount: "string", currencyCode: "string" };
45
+ var PRODUCT = {
46
+ id: "string",
47
+ handle: "string",
48
+ title: "string",
49
+ options: ["object"],
50
+ images: { nodes: ["object"] },
51
+ priceRange: { minVariantPrice: MONEY, maxVariantPrice: MONEY },
52
+ variants: { nodes: [{ id: "string", price: MONEY, selectedOptions: ["object"] }] }
53
+ };
54
+ var PRODUCT_CONNECTION = {
55
+ nodes: [PRODUCT],
56
+ pageInfo: { hasNextPage: "boolean" }
57
+ };
58
+ var isCollectionAnswer = shaped({
59
+ collection: orNull({ handle: "string", products: PRODUCT_CONNECTION })
60
+ });
61
+ var isSearchAnswer = shaped({ products: PRODUCT_CONNECTION });
62
+ var isRecommendationsAnswer = shaped({
63
+ productRecommendations: orNull([PRODUCT])
64
+ });
65
+
66
+ // tether-core:status.ts
67
+ var m6 = window.Tether.__core["status.ts"];
68
+ var [boundary, isNotFound, resolveProductKey, setScopeStatus] = m6;
69
+
70
+ // tether-core:collection.ts
71
+ var m7 = window.Tether.__core["collection.ts"];
72
+ var [listSelector] = m7;
73
+
74
+ // src/lists.ts
75
+ var URL_QUERY_SOURCE = "url:";
76
+ var COLLECTION_QUERY = `query TetherCollection($handle:String!,$first:Int!,$after:String,$sortKey:ProductCollectionSortKeys,$reverse:Boolean,$filters:[ProductFilter!]){collection(handle:$handle){${collectionFields()} products(first:$first,after:$after,sortKey:$sortKey,reverse:$reverse,filters:$filters){nodes{...TetherProduct}pageInfo{hasNextPage endCursor}}}}`;
77
+ var SEARCH_QUERY = `query TetherSearch($first:Int!,$after:String,$query:String,$sortKey:ProductSortKeys,$reverse:Boolean){products(first:$first,after:$after,query:$query,sortKey:$sortKey,reverse:$reverse){nodes{...TetherProduct}pageInfo{hasNextPage endCursor}}}`;
78
+ async function getProducts({
79
+ collection,
80
+ query,
81
+ first = cfg.collectionFirst,
82
+ after = null,
83
+ sortKey,
84
+ reverse = false,
85
+ filters
86
+ } = {}) {
87
+ if (collection) {
88
+ const data2 = await gql(
89
+ withProductFragment(COLLECTION_QUERY),
90
+ {
91
+ handle: collection,
92
+ first,
93
+ after,
94
+ sortKey: sortKey || void 0,
95
+ reverse,
96
+ filters: filters ?? void 0
97
+ },
98
+ isCollectionAnswer
99
+ );
100
+ if (!data2.collection) throw new TetherError(`Collection not found: ${collection}`, { code: "NOT_FOUND" });
101
+ const { products, ...rest } = data2.collection;
102
+ products.nodes.forEach(primeProduct);
103
+ return { collection: rest, products: products.nodes, pageInfo: products.pageInfo };
104
+ }
105
+ const data = await gql(
106
+ withProductFragment(SEARCH_QUERY),
107
+ { first, after, query: query || void 0, sortKey: sortKey || void 0, reverse },
108
+ isSearchAnswer
109
+ );
110
+ data.products.nodes.forEach(primeProduct);
111
+ return { collection: null, products: data.products.nodes, pageInfo: data.products.pageInfo };
112
+ }
113
+ async function getRecommendations(product, intent = "RELATED") {
114
+ const key = normalizeProductKey(typeof product === "object" ? product?.id : product);
115
+ if (!key) throw new TetherError("No product for recommendations", { code: "NOT_FOUND" });
116
+ const byId = key.startsWith("gid://");
117
+ const data = await gql(
118
+ withProductFragment(
119
+ `query TetherRecs(${byId ? "$id: ID!" : "$handle: String!"},$intent:ProductRecommendationIntent){productRecommendations(${byId ? "productId: $id" : "productHandle: $handle"},intent:$intent){...TetherProduct}}`
120
+ ),
121
+ byId ? { id: key, intent } : { handle: key, intent },
122
+ isRecommendationsAnswer
123
+ );
124
+ const list = data.productRecommendations ?? [];
125
+ list.forEach(primeProduct);
126
+ return list;
127
+ }
128
+ var isElement = (target) => target instanceof window.Element;
129
+ var toLimit = (raw) => parseInt(raw ?? "", 10) || void 0;
130
+ var toIntent = (raw) => raw === "COMPLEMENTARY" ? "COMPLEMENTARY" : "RELATED";
131
+ var ListScope = class {
132
+ constructor(root) {
133
+ __publicField(this, "root");
134
+ __publicField(this, "products", []);
135
+ __publicField(this, "pageInfo", null);
136
+ __publicField(this, "collection", null);
137
+ /** Counts loads, so only the latest one renders. */
138
+ __publicField(this, "loadToken", 0);
139
+ this.root = root;
140
+ root.addEventListener("click", (event) => {
141
+ if (!isElement(event.target)) return;
142
+ const more = event.target.closest(sel("load-more"));
143
+ if (more?.closest(listSelector()) !== root) return;
144
+ event.preventDefault();
145
+ void busy(more, () => this.load(true));
146
+ });
147
+ }
148
+ $(selector) {
149
+ return scoped(this.root, selector, listSelector());
150
+ }
151
+ /** The collection or search query of the list's attributes. */
152
+ options() {
153
+ const { root } = this;
154
+ const query = { reverse: get(root, "reverse") === "true" };
155
+ const first = toLimit(get(root, "limit"));
156
+ if (first) query.first = first;
157
+ const sortKey = get(root, "sort");
158
+ if (sortKey) query.sortKey = sortKey;
159
+ if (has(root, "collection")) {
160
+ query.collection = get(root, "collection") ?? "";
161
+ return query;
162
+ }
163
+ const raw = get(root, "products") ?? "";
164
+ query.query = raw.startsWith(URL_QUERY_SOURCE) ? new URL(window.location.href).searchParams.get(raw.slice(URL_QUERY_SOURCE.length)) || "" : raw;
165
+ return query;
166
+ }
167
+ /**
168
+ * The product of a recommendations list: a handle, `url:…` (one dynamic product page), or empty inside a product
169
+ * scope for that product.
170
+ *
171
+ * @throws {TetherError} `NOT_FOUND` when there is no product to recommend for.
172
+ */
173
+ async loadRecommendations() {
174
+ let { key } = resolveProductKey(this.root, window.location, "recommendations");
175
+ const scope = this.root.closest(sel("product"));
176
+ if (!key && scope) ({ key } = resolveProductKey(scope));
177
+ return getRecommendations(key, toIntent(get(this.root, "intent")));
178
+ }
179
+ /** @param more Appends the next page instead of replacing the products. */
180
+ async load(more = false) {
181
+ this.loadToken += 1;
182
+ const token = this.loadToken;
183
+ const stale = () => token !== this.loadToken;
184
+ try {
185
+ if (has(this.root, "recommendations")) {
186
+ const recommendations = await this.loadRecommendations();
187
+ if (stale()) return;
188
+ const limit = toLimit(get(this.root, "limit"));
189
+ this.products = limit ? recommendations.slice(0, limit) : recommendations;
190
+ } else {
191
+ const page = await getProducts({ ...this.options(), after: more ? this.pageInfo?.endCursor ?? null : null });
192
+ if (stale()) return;
193
+ this.collection = page.collection;
194
+ this.pageInfo = page.pageInfo;
195
+ this.products = more ? [...this.products, ...page.products] : page.products;
196
+ }
197
+ this.render();
198
+ setScopeStatus(this.root, "ready");
199
+ emit("list-ready", { products: this.products, collection: this.collection }, this.root);
200
+ } catch (error) {
201
+ if (stale()) return;
202
+ if (!more) setScopeStatus(this.root, isNotFound(error) ? "not-found" : "error", error);
203
+ if (!(isNotFound(error) && has(this.root, "recommendations"))) reportError(error, "list load failed");
204
+ emit("error", { error, context: "list" }, this.root);
205
+ }
206
+ }
207
+ render() {
208
+ const { collection } = this;
209
+ this.$(sel("collection-bind")).forEach((el) => {
210
+ switch (get(el, "collection-bind") ?? "") {
211
+ case "title":
212
+ setText(el, collection?.title ?? "");
213
+ break;
214
+ case "description":
215
+ setStoreHtml(el, collection?.descriptionHtml);
216
+ break;
217
+ case "image":
218
+ setImage(el, collection?.image?.url, collection?.image?.altText || collection?.title);
219
+ break;
220
+ case "count":
221
+ setText(el, this.products.length);
222
+ break;
223
+ }
224
+ });
225
+ this.$(sel("list")).forEach((container) => {
226
+ repeat(container, this.products, (node, product) => {
227
+ node.setAttribute(attr("product"), product.handle);
228
+ node.removeAttribute(attr("state"));
229
+ });
230
+ emit("list-rendered", { container }, this.root);
231
+ });
232
+ const empty = this.products.length === 0;
233
+ this.$(sel("show")).forEach((el) => {
234
+ const key = get(el, "show");
235
+ if (key === "list-empty") show(el, empty);
236
+ if (key === "list-filled") show(el, !empty);
237
+ });
238
+ this.$(sel("load-more")).forEach((el) => {
239
+ show(el, Boolean(this.pageInfo?.hasNextPage));
240
+ });
241
+ notifyLayoutChanged("list");
242
+ }
243
+ };
244
+ var listScopes = /* @__PURE__ */ new WeakMap();
245
+ function loadList(root) {
246
+ let scope = listScopes.get(root);
247
+ if (!scope) {
248
+ scope = new ListScope(root);
249
+ listScopes.set(root, scope);
250
+ }
251
+ return scope.load();
252
+ }
253
+
254
+ // src/part-registry.ts
255
+ function isTetherInternals(value) {
256
+ return isRecord(value) && isRecord(value["__core"]) && isRecord(value["__parts"]);
257
+ }
258
+ function registerPart(name, part) {
259
+ const tether = Reflect.get(window, "Tether");
260
+ if (!isTetherInternals(tether)) {
261
+ throw new Error(`tether.${name}.js runs after the Tether script, which loads it, and needs its window.Tether`);
262
+ }
263
+ tether.__parts[name] = part;
264
+ }
265
+
266
+ // src/parts/lists.ts
267
+ registerPart("lists", lists_exports);
268
+ })();
@@ -0,0 +1 @@
1
+ (()=>{var O=Object.defineProperty;var et=(e,t,o)=>t in e?O(e,t,{enumerable:!0,configurable:!0,writable:!0,value:o}):e[t]=o;var ot=(e,t)=>{for(var o in t)O(e,o,{get:t[o],enumerable:!0})};var a=(e,t,o)=>et(e,typeof t!="symbol"?t+"":t,o);var S={};ot(S,{getProducts:()=>J,getRecommendations:()=>Z,loadList:()=>ht});var rt=window.Tether.__core["config.ts"],[b,yt,Pt,Tt,Et,A,xt]=rt;var nt=window.Tether.__core["client.ts"],[$t,l,st,P,u,T]=nt;var it=window.Tether.__core["dom.ts"],[Ct,E,kt,L,p,Nt,St,i,m,_t,Ot,K,bt,At,Lt,M,U,c,q,F,x,f]=it;var ct=window.Tether.__core["fragments.ts"],[D]=ct;var at=window.Tether.__core["loader.ts"],[Ut,qt,v,h,g]=at;function d(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}var R={amount:"string",currencyCode:"string"},H={id:"string",handle:"string",title:"string",options:["object"],images:{nodes:["object"]},priceRange:{minVariantPrice:R,maxVariantPrice:R},variants:{nodes:[{id:"string",price:R,selectedOptions:["object"]}]}},Q={nodes:[H],pageInfo:{hasNextPage:"boolean"}};var Y=u({collection:P({handle:"string",products:Q})}),j=u({products:Q}),z=u({productRecommendations:P([H])});var dt=window.Tether.__core["status.ts"],[jt,$,I,C]=dt;var lt=window.Tether.__core["collection.ts"],[k]=lt;var B="url:",ut=`query TetherCollection($handle:String!,$first:Int!,$after:String,$sortKey:ProductCollectionSortKeys,$reverse:Boolean,$filters:[ProductFilter!]){collection(handle:$handle){${D()} products(first:$first,after:$after,sortKey:$sortKey,reverse:$reverse,filters:$filters){nodes{...TetherProduct}pageInfo{hasNextPage endCursor}}}}`,pt="query TetherSearch($first:Int!,$after:String,$query:String,$sortKey:ProductSortKeys,$reverse:Boolean){products(first:$first,after:$after,query:$query,sortKey:$sortKey,reverse:$reverse){nodes{...TetherProduct}pageInfo{hasNextPage endCursor}}}";async function J({collection:e,query:t,first:o=b.collectionFirst,after:r=null,sortKey:n,reverse:s=!1,filters:X}={}){if(e){let _=await l(g(ut),{handle:e,first:o,after:r,sortKey:n||void 0,reverse:s,filters:X??void 0},Y);if(!_.collection)throw new T(`Collection not found: ${e}`,{code:"NOT_FOUND"});let{products:y,...tt}=_.collection;return y.nodes.forEach(h),{collection:tt,products:y.nodes,pageInfo:y.pageInfo}}let w=await l(g(pt),{first:o,after:r,query:t||void 0,sortKey:n||void 0,reverse:s},j);return w.products.nodes.forEach(h),{collection:null,products:w.products.nodes,pageInfo:w.products.pageInfo}}async function Z(e,t="RELATED"){let o=v(typeof e=="object"?e?.id:e);if(!o)throw new T("No product for recommendations",{code:"NOT_FOUND"});let r=o.startsWith("gid://"),s=(await l(g(`query TetherRecs(${r?"$id: ID!":"$handle: String!"},$intent:ProductRecommendationIntent){productRecommendations(${r?"productId: $id":"productHandle: $handle"},intent:$intent){...TetherProduct}}`),r?{id:o,intent:t}:{handle:o,intent:t},z)).productRecommendations??[];return s.forEach(h),s}var mt=e=>e instanceof window.Element,V=e=>parseInt(e??"",10)||void 0,ft=e=>e==="COMPLEMENTARY"?"COMPLEMENTARY":"RELATED",N=class{constructor(t){a(this,"root");a(this,"products",[]);a(this,"pageInfo",null);a(this,"collection",null);a(this,"loadToken",0);this.root=t,t.addEventListener("click",o=>{if(!mt(o.target))return;let r=o.target.closest(c("load-more"));r?.closest(k())===t&&(o.preventDefault(),L(r,()=>this.load(!0)))})}$(t){return U(this.root,t,k())}options(){let{root:t}=this,o={reverse:i(t,"reverse")==="true"},r=V(i(t,"limit"));r&&(o.first=r);let n=i(t,"sort");if(n&&(o.sortKey=n),m(t,"collection"))return o.collection=i(t,"collection")??"",o;let s=i(t,"products")??"";return o.query=s.startsWith(B)?new URL(window.location.href).searchParams.get(s.slice(B.length))||"":s,o}async loadRecommendations(){let{key:t}=I(this.root,window.location,"recommendations"),o=this.root.closest(c("product"));return!t&&o&&({key:t}=I(o)),Z(t,ft(i(this.root,"intent")))}async load(t=!1){this.loadToken+=1;let o=this.loadToken,r=()=>o!==this.loadToken;try{if(m(this.root,"recommendations")){let n=await this.loadRecommendations();if(r())return;let s=V(i(this.root,"limit"));this.products=s?n.slice(0,s):n}else{let n=await J({...this.options(),after:t?this.pageInfo?.endCursor??null:null});if(r())return;this.collection=n.collection,this.pageInfo=n.pageInfo,this.products=t?[...this.products,...n.products]:n.products}this.render(),C(this.root,"ready"),p("list-ready",{products:this.products,collection:this.collection},this.root)}catch(n){if(r())return;t||C(this.root,$(n)?"not-found":"error",n),$(n)&&m(this.root,"recommendations")||A(n,"list load failed"),p("error",{error:n,context:"list"},this.root)}}render(){let{collection:t}=this;this.$(c("collection-bind")).forEach(r=>{switch(i(r,"collection-bind")??""){case"title":x(r,t?.title??"");break;case"description":F(r,t?.descriptionHtml);break;case"image":q(r,t?.image?.url,t?.image?.altText||t?.title);break;case"count":x(r,this.products.length);break}}),this.$(c("list")).forEach(r=>{M(r,this.products,(n,s)=>{n.setAttribute(E("product"),s.handle),n.removeAttribute(E("state"))}),p("list-rendered",{container:r},this.root)});let o=this.products.length===0;this.$(c("show")).forEach(r=>{let n=i(r,"show");n==="list-empty"&&f(r,o),n==="list-filled"&&f(r,!o)}),this.$(c("load-more")).forEach(r=>{f(r,!!this.pageInfo?.hasNextPage)}),K("list")}},W=new WeakMap;function ht(e){let t=W.get(e);return t||(t=new N(e),W.set(e,t)),t.load()}function gt(e){return d(e)&&d(e.__core)&&d(e.__parts)}function G(e,t){let o=Reflect.get(window,"Tether");if(!gt(o))throw new Error(`tether.${e}.js runs after the Tether script, which loads it, and needs its window.Tether`);o.__parts[e]=t}G("lists",S);})();
@@ -20,7 +20,7 @@
20
20
 
21
21
  // tether-core:client.ts
22
22
  var m2 = window.Tether.__core["client.ts"];
23
- var [endpoint, gql, orNull, shaped, TetherError] = m2;
23
+ var [endpoint, gql, matches, orNull, shaped, TetherError] = m2;
24
24
 
25
25
  // tether-core:cart.ts
26
26
  var m3 = window.Tether.__core["cart.ts"];
@@ -32,11 +32,11 @@
32
32
 
33
33
  // tether-core:loader.ts
34
34
  var m5 = window.Tether.__core["loader.ts"];
35
- var [clearProductCache, getProduct] = m5;
35
+ var [clearProductCache, getProduct, normalizeProductKey, primeProduct, withProductFragment] = m5;
36
36
 
37
37
  // tether-core:dom.ts
38
38
  var m6 = window.Tether.__core["dom.ts"];
39
- var [ANALYTICS_EVENTS, attr, attributesFromJson, emit, formatDate, formatMoney, get, has, hasTemplate, isOwnEvent, parseJSONAttr, productUrl, qsa, repeat, sel, setImage, setText, show] = m6;
39
+ var [ANALYTICS_EVENTS, attr, attributesFromJson, busy, emit, formatDate, formatMoney, get, has, hasTemplate, isOwnEvent, notifyLayoutChanged, parseJSONAttr, productUrl, qsa, repeat, scoped, sel, setImage, setStoreHtml, setText, show] = m6;
40
40
 
41
41
  // tether-core:mounting.ts
42
42
  var m7 = window.Tether.__core["mounting.ts"];
@@ -1 +1 @@
1
- (()=>{var G=Object.defineProperty;var V=(e,t)=>{for(var n in t)G(e,n,{get:t[n],enumerable:!0})};var b={};V(b,{detectMarket:()=>$,getLocalization:()=>J,renderCountrySelects:()=>L,setCountry:()=>Ee});var Z=window.Tether.__core["config.ts"],[c,Ae,Ne,M,S,C,ve]=Z;var Q=window.Tether.__core["client.ts"],[Ie,x,Re,T,E]=Q;var X=window.Tether.__core["cart.ts"],[g]=X;var ee=window.Tether.__core["collection.ts"],[_]=ee;var te=window.Tether.__core["loader.ts"],[P,De]=te;var ne=window.Tether.__core["dom.ts"],[je,m,$e,A,qe,Ke,N,Je,Ye,Be,We,Ge,Ve,Ze,w,Qe,Xe,et]=ne;var oe=window.Tether.__core["mounting.ts"],[v,O,I,R,z,k]=oe;var re=window.Tether.__core["market-codes.ts"],[s,d]=re;function U(e,t="localStorage"){try{return window[t].getItem(e)}catch{return null}}function H(e,t,n="localStorage"){try{window[n].setItem(e,t)}catch{}}function D(e){try{return decodeURIComponent(e)}catch(t){if(t instanceof URIError)return e;throw t}}var ae="tether_country",F=()=>`${c.prefix}:market:${c.domain}`,j={getItem:e=>U(e)};function ce(){let e=typeof window<"u";return{document:typeof document<"u"?document:null,location:e?window.location:null,storage:j,global:e?window:{}}}function ie(e){try{return JSON.parse(e)}catch(t){if(t instanceof SyntaxError)return null;throw t}}function ue(e){if(typeof e!="object"||e===null)return null;let t=s(Reflect.get(e,"country"));if(!t)return null;let n=Reflect.get(e,"locale");return{country:t,language:d(Reflect.get(e,"language"))??void 0,locale:typeof n=="string"&&n?n:void 0}}var le=e=>ue(ie(e));function se(e=j){let t=e.getItem(F());return t?le(t):null}function de(e,t){if(!e||!t)return null;let n=e.cookie.split(";").map(a=>a.trim()).find(a=>a.startsWith(`${t}=`));return n?D(n.slice(t.length+1)):null}function h(e,t){if(!e||!t)return null;let n=t.toLowerCase(),a=Object.keys(e).find(o=>o.toLowerCase()===n);return a?e[a]??null:null}function ge(e,t){let n=r=>t.document?.querySelector(`meta[name="${r}"]`)?.getAttribute("content"),a=Reflect.get(t.global,"TETHER_COUNTRY"),o=Reflect.get(t.global,"TETHER_LANGUAGE"),i=n("tether-country")||de(t.document,e.cookie||ae);return{country:a||i,language:o||n("tether-language")}}function fe(e,t){let n=(t.location?.pathname??"/").split("/").find(u=>u!==""),a=h(e.locales,n);if(a)return a;let o=t.document?.documentElement.getAttribute("lang");if(!o)return null;let i=h(e.locales,o)??h(e.locales,o.split("-")[0]);if(i)return{locale:o,...i};if(e.locales&&e.strict)return null;let r=o.split("-")[1];return{language:o,country:r?.length===2?r:null,locale:o}}function me(e,t,n){switch(e){case"saved":return t.remember===!1?null:se(n.storage);case"server":return ge(t,n);case"webflow":return fe(t,n)}}function pe(e){return e?e===!0?M:e:["saved"]}function $(e=c.markets,t=ce()){let n=(e===c.markets?e:S(e))??{};if(n.detect===!1)return{};let a={},o={sources:a};for(let i of pe(n.detect)){let r=me(i,n,t);if(!r)continue;let u=s(r.country),l=d(r.language),f=typeof r.locale=="string"&&r.locale?r.locale:null;u&&!o.country&&(o.country=u,a.country=i),l&&!o.language&&(o.language=l,a.language=i),f&&!o.locale&&(o.locale=f,a.locale=i)}return o}function q(e){if(c.markets?.remember===!1)return;let t={country:e.country,language:e.language||void 0,locale:e.locale||void 0};H(F(),JSON.stringify(t))}var ye="{name} ({currency})",Ce="name",p=null;function we(){p=null}var ke="query TetherLocalization{localization{country{isoCode name currency{isoCode symbol}}language{isoCode name}availableCountries{isoCode name currency{isoCode symbol}availableLanguages{isoCode name}}}}",K={isoCode:"string",name:"string",currency:"object"},he=T({localization:{country:K,availableCountries:[K]}});function J(){return p??(p=x(ke,{},he).then(e=>e.localization,e=>{throw p=null,e})),p}function Y(e,t){switch(t){case"name":return e.name;case"code":return e.isoCode;case"currency":return e.currency.isoCode;case"symbol":return e.currency.symbol;default:return""}}var Le=(e,t)=>e.replace(/\{(name|code|currency|symbol)\}/g,(n,a)=>Y(t,a));function be(e,t,n){let a=e.getAttribute(m("country-label"))||ye,o=(e.getAttribute(m("countries"))||"").toUpperCase().split(/[\s,]+/).filter(Boolean),i=o.length?o.map(r=>t.find(u=>u.isoCode===r)).filter(r=>r!==void 0):t;e.replaceChildren(...i.map(r=>new Option(Le(a,r),r.isoCode))),e.value=n,e.value!==n&&(e.selectedIndex=-1),e.disabled=i.length<2&&!e.hasAttribute(m("always-enabled"))}function Me(e,t,n){let a=(c.country||n.country.isoCode).toUpperCase(),o=[...n.availableCountries].sort((r,u)=>r.name.localeCompare(u.name,c.locale||void 0)),i=o.find(r=>r.isoCode===a)??n.country;e.forEach(r=>{be(r,o,a)}),t.forEach(r=>{r.textContent=Y(i,N(r,"country-bind")||Ce)})}function L(e=document){let t=k(e,`select${w("country-select")}`),n=k(e,w("country-bind"));return!t.length&&!n.length?Promise.resolve():J().then(a=>{Me(t,n,a)}).catch(a=>{C(a,"country select")})}var Se=e=>Object.values(c.markets?.locales??{}).find(t=>s(t.country)===e);function xe(e,t){return e!==void 0?d(e):t?t.language?d(t.language):void 0:c.language}function Te(e){P();let t=[];return g.id()&&t.push(g.setBuyerIdentity({countryCode:e},{create:!1}).catch(n=>{C(n,"cart country")})),z(),v.forEach(n=>t.push(n.load())),O.forEach(n=>{n.closest(_())||(I.delete(n),R(n))}),t}async function Ee(e,{language:t,locale:n,remember:a=!0}={}){let o=s(e);if(!o)throw new E(`Not a country code: ${e}`,{code:"INVALID_COUNTRY"});let i=Se(o),r=n||i?.locale,u=r||c.locale,l=xe(t,i),f=o!==c.country||l!==c.language||u!==c.locale;if(c.country=o,c.language=l||void 0,c.locale=u,a&&q({country:o,language:l,locale:r}),!f)return L(),g.state;t!==void 0&&we();let W=Te(o);return L(),A("country-changed",{country:o,language:c.language}),await Promise.all(W),g.state}function y(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function _e(e){return y(e)&&y(e.__core)&&y(e.__parts)}function B(e,t){let n=Reflect.get(window,"Tether");if(!_e(n))throw new Error(`tether.${e}.js runs after the Tether script, which loads it, and needs its window.Tether`);n.__parts[e]=t}B("markets",b);})();
1
+ (()=>{var G=Object.defineProperty;var V=(e,t)=>{for(var n in t)G(e,n,{get:t[n],enumerable:!0})};var b={};V(b,{detectMarket:()=>K,getLocalization:()=>J,renderCountrySelects:()=>L,setCountry:()=>Ee});var Z=window.Tether.__core["config.ts"],[c,Ae,Ne,M,S,C,ve]=Z;var Q=window.Tether.__core["client.ts"],[Ie,x,ze,Re,T,E]=Q;var X=window.Tether.__core["cart.ts"],[g]=X;var ee=window.Tether.__core["collection.ts"],[P]=ee;var te=window.Tether.__core["loader.ts"],[_,De,je,Ke,$e]=te;var ne=window.Tether.__core["dom.ts"],[Je,m,Ye,Be,A,We,Ge,N,Ve,Ze,Qe,Xe,et,tt,nt,ot,rt,w,at,ct,it,ut]=ne;var oe=window.Tether.__core["mounting.ts"],[v,O,I,z,R,k]=oe;var re=window.Tether.__core["market-codes.ts"],[s,d]=re;function U(e,t="localStorage"){try{return window[t].getItem(e)}catch{return null}}function H(e,t,n="localStorage"){try{window[n].setItem(e,t)}catch{}}function F(e){try{return decodeURIComponent(e)}catch(t){if(t instanceof URIError)return e;throw t}}var ae="tether_country",D=()=>`${c.prefix}:market:${c.domain}`,j={getItem:e=>U(e)};function ce(){let e=typeof window<"u";return{document:typeof document<"u"?document:null,location:e?window.location:null,storage:j,global:e?window:{}}}function ie(e){try{return JSON.parse(e)}catch(t){if(t instanceof SyntaxError)return null;throw t}}function ue(e){if(typeof e!="object"||e===null)return null;let t=s(Reflect.get(e,"country"));if(!t)return null;let n=Reflect.get(e,"locale");return{country:t,language:d(Reflect.get(e,"language"))??void 0,locale:typeof n=="string"&&n?n:void 0}}var le=e=>ue(ie(e));function se(e=j){let t=e.getItem(D());return t?le(t):null}function de(e,t){if(!e||!t)return null;let n=e.cookie.split(";").map(a=>a.trim()).find(a=>a.startsWith(`${t}=`));return n?F(n.slice(t.length+1)):null}function h(e,t){if(!e||!t)return null;let n=t.toLowerCase(),a=Object.keys(e).find(o=>o.toLowerCase()===n);return a?e[a]??null:null}function ge(e,t){let n=r=>t.document?.querySelector(`meta[name="${r}"]`)?.getAttribute("content"),a=Reflect.get(t.global,"TETHER_COUNTRY"),o=Reflect.get(t.global,"TETHER_LANGUAGE"),i=n("tether-country")||de(t.document,e.cookie||ae);return{country:a||i,language:o||n("tether-language")}}function fe(e,t){let n=(t.location?.pathname??"/").split("/").find(u=>u!==""),a=h(e.locales,n);if(a)return a;let o=t.document?.documentElement.getAttribute("lang");if(!o)return null;let i=h(e.locales,o)??h(e.locales,o.split("-")[0]);if(i)return{locale:o,...i};if(e.locales&&e.strict)return null;let r=o.split("-")[1];return{language:o,country:r?.length===2?r:null,locale:o}}function me(e,t,n){switch(e){case"saved":return t.remember===!1?null:se(n.storage);case"server":return ge(t,n);case"webflow":return fe(t,n)}}function pe(e){return e?e===!0?M:e:["saved"]}function K(e=c.markets,t=ce()){let n=(e===c.markets?e:S(e))??{};if(n.detect===!1)return{};let a={},o={sources:a};for(let i of pe(n.detect)){let r=me(i,n,t);if(!r)continue;let u=s(r.country),l=d(r.language),f=typeof r.locale=="string"&&r.locale?r.locale:null;u&&!o.country&&(o.country=u,a.country=i),l&&!o.language&&(o.language=l,a.language=i),f&&!o.locale&&(o.locale=f,a.locale=i)}return o}function $(e){if(c.markets?.remember===!1)return;let t={country:e.country,language:e.language||void 0,locale:e.locale||void 0};H(D(),JSON.stringify(t))}var ye="{name} ({currency})",Ce="name",p=null;function we(){p=null}var ke="query TetherLocalization{localization{country{isoCode name currency{isoCode symbol}}language{isoCode name}availableCountries{isoCode name currency{isoCode symbol}availableLanguages{isoCode name}}}}",q={isoCode:"string",name:"string",currency:"object"},he=T({localization:{country:q,availableCountries:[q]}});function J(){return p??(p=x(ke,{},he).then(e=>e.localization,e=>{throw p=null,e})),p}function Y(e,t){switch(t){case"name":return e.name;case"code":return e.isoCode;case"currency":return e.currency.isoCode;case"symbol":return e.currency.symbol;default:return""}}var Le=(e,t)=>e.replace(/\{(name|code|currency|symbol)\}/g,(n,a)=>Y(t,a));function be(e,t,n){let a=e.getAttribute(m("country-label"))||ye,o=(e.getAttribute(m("countries"))||"").toUpperCase().split(/[\s,]+/).filter(Boolean),i=o.length?o.map(r=>t.find(u=>u.isoCode===r)).filter(r=>r!==void 0):t;e.replaceChildren(...i.map(r=>new Option(Le(a,r),r.isoCode))),e.value=n,e.value!==n&&(e.selectedIndex=-1),e.disabled=i.length<2&&!e.hasAttribute(m("always-enabled"))}function Me(e,t,n){let a=(c.country||n.country.isoCode).toUpperCase(),o=[...n.availableCountries].sort((r,u)=>r.name.localeCompare(u.name,c.locale||void 0)),i=o.find(r=>r.isoCode===a)??n.country;e.forEach(r=>{be(r,o,a)}),t.forEach(r=>{r.textContent=Y(i,N(r,"country-bind")||Ce)})}function L(e=document){let t=k(e,`select${w("country-select")}`),n=k(e,w("country-bind"));return!t.length&&!n.length?Promise.resolve():J().then(a=>{Me(t,n,a)}).catch(a=>{C(a,"country select")})}var Se=e=>Object.values(c.markets?.locales??{}).find(t=>s(t.country)===e);function xe(e,t){return e!==void 0?d(e):t?t.language?d(t.language):void 0:c.language}function Te(e){_();let t=[];return g.id()&&t.push(g.setBuyerIdentity({countryCode:e},{create:!1}).catch(n=>{C(n,"cart country")})),R(),v.forEach(n=>t.push(n.load())),O.forEach(n=>{n.closest(P())||(I.delete(n),z(n))}),t}async function Ee(e,{language:t,locale:n,remember:a=!0}={}){let o=s(e);if(!o)throw new E(`Not a country code: ${e}`,{code:"INVALID_COUNTRY"});let i=Se(o),r=n||i?.locale,u=r||c.locale,l=xe(t,i),f=o!==c.country||l!==c.language||u!==c.locale;if(c.country=o,c.language=l||void 0,c.locale=u,a&&$({country:o,language:l,locale:r}),!f)return L(),g.state;t!==void 0&&we();let W=Te(o);return L(),A("country-changed",{country:o,language:c.language}),await Promise.all(W),g.state}function y(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function Pe(e){return y(e)&&y(e.__core)&&y(e.__parts)}function B(e,t){let n=Reflect.get(window,"Tether");if(!Pe(n))throw new Error(`tether.${e}.js runs after the Tether script, which loads it, and needs its window.Tether`);n.__parts[e]=t}B("markets",b);})();