@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.
- package/README.md +5 -5
- package/dist/esm/astro.js +1 -1
- package/dist/esm/chunks/account-LCMJ7QU5.js +1 -0
- package/dist/esm/chunks/{account-pages-XR6QZ3DX.js → account-pages-3C5KTPQV.js} +1 -1
- package/dist/esm/chunks/analytics-VWSZOX2D.js +1 -0
- package/dist/esm/chunks/{chunk-HXZSNZOV.js → chunk-2A2GN3Z7.js} +1 -1
- package/dist/esm/chunks/{chunk-A3GXCQJ4.js → chunk-2IGCUTG5.js} +1 -1
- package/dist/esm/chunks/{chunk-COQ6ATC6.js → chunk-3UCVDDK6.js} +1 -1
- package/dist/esm/chunks/chunk-D3MRWOFI.js +1 -0
- package/dist/esm/chunks/chunk-EUCFOBIT.js +1 -0
- package/dist/esm/chunks/{chunk-A2PCQK2F.js → chunk-F2BYVA7V.js} +1 -1
- package/dist/esm/chunks/chunk-HROQXZYN.js +1 -0
- package/dist/esm/chunks/{chunk-X2JZPXLF.js → chunk-MJNPD6LB.js} +1 -1
- package/dist/esm/chunks/{chunk-FM7ZLLVP.js → chunk-OURC3H6L.js} +1 -1
- package/dist/esm/chunks/chunk-P6DV24RG.js +1 -0
- package/dist/esm/chunks/chunk-P73VN3B6.js +1 -0
- package/dist/esm/chunks/chunk-S5BUUIB6.js +1 -0
- package/dist/esm/chunks/chunk-SOFWDTR7.js +1 -0
- package/dist/esm/chunks/{chunk-FPJGQ7Z5.js → chunk-XU27NSXT.js} +1 -1
- package/dist/esm/chunks/chunk-YJC3CSEG.js +1 -0
- package/dist/esm/chunks/chunk-ZBV2JSHE.js +1 -0
- package/dist/esm/chunks/{diagnose-IFRNCEYG.js → diagnose-TE72GNOO.js} +1 -1
- package/dist/esm/chunks/extras-7GTMJMOZ.js +1 -0
- package/dist/esm/chunks/lists-ZMVRGD6L.js +1 -0
- package/dist/esm/chunks/markets-ui-AAQM4PEE.js +1 -0
- package/dist/esm/chunks/search-PWF4YZQO.js +1 -0
- package/dist/esm/index.js +1 -1
- package/dist/esm/server.js +2 -2
- package/dist/tether.account-pages.js +2 -2
- package/dist/tether.account-pages.min.js +1 -1
- package/dist/tether.account.js +2 -2
- package/dist/tether.account.min.js +1 -1
- package/dist/tether.analytics.js +2 -2
- package/dist/tether.analytics.min.js +1 -1
- package/dist/tether.diagnose.js +4 -4
- package/dist/tether.diagnose.min.js +2 -2
- package/dist/tether.extras.js +1 -1
- package/dist/tether.extras.min.js +1 -1
- package/dist/tether.js +85 -201
- package/dist/tether.lists.js +268 -0
- package/dist/tether.lists.min.js +1 -0
- package/dist/tether.markets.js +3 -3
- package/dist/tether.markets.min.js +1 -1
- package/dist/tether.min.js +1 -1
- package/dist/tether.min.js.map +4 -4
- package/dist/tether.search.js +2 -2
- package/dist/tether.search.min.js +1 -1
- package/dist/types/src/client.d.ts +6 -6
- package/dist/types/src/collection.d.ts +7 -23
- package/dist/types/src/config-sections.d.ts +7 -0
- package/dist/types/src/config.d.ts +6 -0
- package/dist/types/src/index.d.ts +4 -3
- package/dist/types/src/lazy.d.ts +1 -0
- package/dist/types/src/lists.d.ts +20 -0
- package/dist/types/src/loader.d.ts +7 -27
- package/dist/types/src/mounting.d.ts +1 -6
- package/dist/types/src/product-shape.d.ts +13 -36
- package/dist/types/src/server.d.ts +5 -4
- package/dist/types/src/shopify-values.d.ts +6 -0
- package/dist/types/src/storefront/catalog.d.ts +2 -4
- package/dist/types/src/version.d.ts +1 -1
- package/package.json +7 -6
- package/dist/esm/chunks/account-BS5MCC2R.js +0 -1
- package/dist/esm/chunks/analytics-BYN3QHBA.js +0 -1
- package/dist/esm/chunks/chunk-2IVIZDT5.js +0 -1
- package/dist/esm/chunks/chunk-EGIDFV3T.js +0 -1
- package/dist/esm/chunks/chunk-EW3GKRT4.js +0 -1
- package/dist/esm/chunks/chunk-GXCCTPDF.js +0 -1
- package/dist/esm/chunks/chunk-MJFKAMFM.js +0 -1
- package/dist/esm/chunks/chunk-TE5PNI76.js +0 -1
- package/dist/esm/chunks/extras-3477M6Y7.js +0 -1
- package/dist/esm/chunks/markets-ui-3L2UZ7PK.js +0 -1
- package/dist/esm/chunks/search-YR73GIWY.js +0 -1
package/dist/tether.js
CHANGED
|
@@ -240,6 +240,7 @@
|
|
|
240
240
|
sellingPlansFirst: 25,
|
|
241
241
|
collectionFirst: 24,
|
|
242
242
|
retries: 2,
|
|
243
|
+
requestTimeout: 15e3,
|
|
243
244
|
revalidate: true,
|
|
244
245
|
storageKey: "",
|
|
245
246
|
cartDrawerOpenClass: "is-open",
|
|
@@ -304,6 +305,7 @@
|
|
|
304
305
|
"sellingPlansFirst",
|
|
305
306
|
"collectionFirst",
|
|
306
307
|
"retries",
|
|
308
|
+
"requestTimeout",
|
|
307
309
|
"maxAge",
|
|
308
310
|
"lowStock",
|
|
309
311
|
"searchDelay"
|
|
@@ -338,8 +340,16 @@
|
|
|
338
340
|
dropped(name, value);
|
|
339
341
|
}
|
|
340
342
|
}
|
|
343
|
+
var MAX_TIMER_MS = 2147483647;
|
|
344
|
+
var MAX_RETRIES = 10;
|
|
345
|
+
var COUNT_MAXIMUMS = {
|
|
346
|
+
requestTimeout: MAX_TIMER_MS,
|
|
347
|
+
searchDelay: MAX_TIMER_MS,
|
|
348
|
+
retries: MAX_RETRIES
|
|
349
|
+
};
|
|
341
350
|
function countOption(name, value) {
|
|
342
|
-
|
|
351
|
+
const maximum = COUNT_MAXIMUMS[name] ?? Number.POSITIVE_INFINITY;
|
|
352
|
+
if (typeof value === "number" && Number.isInteger(value) && value >= 0 && value <= maximum) return value;
|
|
343
353
|
return invalidOption(name, value, DEFAULTS[name]);
|
|
344
354
|
}
|
|
345
355
|
function switchOption(name, value) {
|
|
@@ -486,6 +496,7 @@
|
|
|
486
496
|
}
|
|
487
497
|
var RETRY_BACKOFF_MS = 300;
|
|
488
498
|
var THROTTLE_BACKOFF_MS = 500;
|
|
499
|
+
var MAX_BACKOFF_MS = 3e4;
|
|
489
500
|
var SECURITY_REJECTION = 430;
|
|
490
501
|
var MS_PER_SECOND = 1e3;
|
|
491
502
|
var INVENTORY_FIELD = "quantityAvailable";
|
|
@@ -545,13 +556,27 @@
|
|
|
545
556
|
const unclear = res.ok && (serverError || operation === "mutation" && data == null);
|
|
546
557
|
throw graphQLFailure(res, errors, conf, unclear ? "SERVER_ERROR" : void 0);
|
|
547
558
|
}
|
|
548
|
-
async function
|
|
559
|
+
async function withTimeout(ms, send2) {
|
|
560
|
+
if (!ms) return send2(null);
|
|
561
|
+
const controller = new AbortController();
|
|
562
|
+
const timer = setTimeout(() => {
|
|
563
|
+
controller.abort(new DOMException("signal timed out", "TimeoutError"));
|
|
564
|
+
}, ms);
|
|
565
|
+
try {
|
|
566
|
+
return await send2(controller.signal);
|
|
567
|
+
} finally {
|
|
568
|
+
clearTimeout(timer);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
async function attempt(conf, query2, variables, isData, retry, operation, signal) {
|
|
549
572
|
let res;
|
|
550
573
|
try {
|
|
551
574
|
res = await (conf.fetch ?? fetch)(endpoint(conf), {
|
|
552
575
|
method: "POST",
|
|
553
576
|
headers: { "Content-Type": "application/json", "X-Shopify-Storefront-Access-Token": conf.token },
|
|
554
|
-
body: JSON.stringify({ query: query2, variables })
|
|
577
|
+
body: JSON.stringify({ query: query2, variables }),
|
|
578
|
+
// A `fetch` given to the server helpers has to honour the signal, as the platform's does.
|
|
579
|
+
signal
|
|
555
580
|
});
|
|
556
581
|
} catch (error) {
|
|
557
582
|
return networkFailure(error, retry);
|
|
@@ -588,7 +613,10 @@
|
|
|
588
613
|
const access = { inventory: !storesWithoutInventory.has(store) };
|
|
589
614
|
const sent = queryText(conf, query2, access, { context, operation });
|
|
590
615
|
const retry = retries < conf.retries ? retryWhileLeft : "none";
|
|
591
|
-
const outcome = await
|
|
616
|
+
const outcome = await withTimeout(
|
|
617
|
+
conf.requestTimeout,
|
|
618
|
+
(signal) => attempt(conf, sent, variables, isData, retry, operation, signal)
|
|
619
|
+
);
|
|
592
620
|
switch (outcome.kind) {
|
|
593
621
|
case "data":
|
|
594
622
|
return outcome.data;
|
|
@@ -598,9 +626,9 @@
|
|
|
598
626
|
storesWithoutInventory.add(store);
|
|
599
627
|
break;
|
|
600
628
|
case "retry":
|
|
629
|
+
await sleep(Math.min(outcome.backoffMs * 2 ** retries, MAX_BACKOFF_MS));
|
|
601
630
|
retries += 1;
|
|
602
631
|
log("retry", retries);
|
|
603
|
-
await sleep(outcome.backoffMs * 2 ** retries);
|
|
604
632
|
break;
|
|
605
633
|
}
|
|
606
634
|
}
|
|
@@ -805,6 +833,7 @@
|
|
|
805
833
|
if (cleaned === "") element.removeAttribute("style");
|
|
806
834
|
else element.setAttribute("style", cleaned);
|
|
807
835
|
}
|
|
836
|
+
var SAME_TAB_TARGETS = /* @__PURE__ */ new Set(["", "_self", "_parent", "_top"]);
|
|
808
837
|
function hardenEmbedsAndLinks(element) {
|
|
809
838
|
if (element.localName === "iframe") {
|
|
810
839
|
const allow = allowedFeatures(element.getAttribute("allow") ?? "");
|
|
@@ -814,7 +843,9 @@
|
|
|
814
843
|
element.setAttribute("referrerpolicy", IFRAME_REFERRER_POLICY);
|
|
815
844
|
return;
|
|
816
845
|
}
|
|
817
|
-
if (element.localName !== "a"
|
|
846
|
+
if (element.localName !== "a") return;
|
|
847
|
+
const target = element.getAttribute("target");
|
|
848
|
+
if (target === null || SAME_TAB_TARGETS.has(target.toLowerCase())) return;
|
|
818
849
|
const rel = new Set((element.getAttribute("rel") ?? "").split(/\s+/).filter(Boolean));
|
|
819
850
|
rel.add("noopener");
|
|
820
851
|
rel.add("noreferrer");
|
|
@@ -1369,6 +1400,13 @@
|
|
|
1369
1400
|
};
|
|
1370
1401
|
var isProductShape = (value) => field(value, "id") !== "" && field(value, "handle") !== "" && matches(value, PRODUCT);
|
|
1371
1402
|
var PRODUCT_NODE = (node) => isRecord(node) && (node["id"] === void 0 || matches(node, PRODUCT));
|
|
1403
|
+
var isCollectionAnswer = shaped({
|
|
1404
|
+
collection: orNull({ handle: "string", products: PRODUCT_CONNECTION })
|
|
1405
|
+
});
|
|
1406
|
+
var isSearchAnswer = shaped({ products: PRODUCT_CONNECTION });
|
|
1407
|
+
var isRecommendationsAnswer = shaped({
|
|
1408
|
+
productRecommendations: orNull([PRODUCT])
|
|
1409
|
+
});
|
|
1372
1410
|
|
|
1373
1411
|
// src/cart/cart-shape.ts
|
|
1374
1412
|
var LINE = {
|
|
@@ -1623,64 +1661,6 @@
|
|
|
1623
1661
|
if (normalized) productCache.delete(normalized);
|
|
1624
1662
|
return getProduct(key);
|
|
1625
1663
|
}
|
|
1626
|
-
var isCollectionAnswer = shaped({
|
|
1627
|
-
collection: orNull({ handle: "string", products: PRODUCT_CONNECTION })
|
|
1628
|
-
});
|
|
1629
|
-
var isSearchAnswer = shaped({ products: PRODUCT_CONNECTION });
|
|
1630
|
-
var isRecommendationsAnswer = shaped({
|
|
1631
|
-
productRecommendations: orNull([PRODUCT])
|
|
1632
|
-
});
|
|
1633
|
-
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}}}}`;
|
|
1634
|
-
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}}}`;
|
|
1635
|
-
async function getProducts({
|
|
1636
|
-
collection,
|
|
1637
|
-
query: query2,
|
|
1638
|
-
first = cfg.collectionFirst,
|
|
1639
|
-
after = null,
|
|
1640
|
-
sortKey,
|
|
1641
|
-
reverse = false,
|
|
1642
|
-
filters
|
|
1643
|
-
} = {}) {
|
|
1644
|
-
if (collection) {
|
|
1645
|
-
const data2 = await gql(
|
|
1646
|
-
withProductFragment(COLLECTION_QUERY),
|
|
1647
|
-
{
|
|
1648
|
-
handle: collection,
|
|
1649
|
-
first,
|
|
1650
|
-
after,
|
|
1651
|
-
sortKey: sortKey || void 0,
|
|
1652
|
-
reverse,
|
|
1653
|
-
filters: filters ?? void 0
|
|
1654
|
-
},
|
|
1655
|
-
isCollectionAnswer
|
|
1656
|
-
);
|
|
1657
|
-
if (!data2.collection) throw new TetherError(`Collection not found: ${collection}`, { code: "NOT_FOUND" });
|
|
1658
|
-
const { products, ...rest } = data2.collection;
|
|
1659
|
-
products.nodes.forEach(primeProduct);
|
|
1660
|
-
return { collection: rest, products: products.nodes, pageInfo: products.pageInfo };
|
|
1661
|
-
}
|
|
1662
|
-
const data = await gql(
|
|
1663
|
-
withProductFragment(SEARCH_QUERY),
|
|
1664
|
-
{ first, after, query: query2 || void 0, sortKey: sortKey || void 0, reverse },
|
|
1665
|
-
isSearchAnswer
|
|
1666
|
-
);
|
|
1667
|
-
data.products.nodes.forEach(primeProduct);
|
|
1668
|
-
return { collection: null, products: data.products.nodes, pageInfo: data.products.pageInfo };
|
|
1669
|
-
}
|
|
1670
|
-
async function getRecommendations(product, intent = "RELATED") {
|
|
1671
|
-
const key = normalizeProductKey(typeof product === "object" ? product?.id : product);
|
|
1672
|
-
const byId = key?.startsWith("gid://") ?? false;
|
|
1673
|
-
const data = await gql(
|
|
1674
|
-
withProductFragment(
|
|
1675
|
-
`query TetherRecs(${byId ? "$id: ID!" : "$handle: String!"},$intent:ProductRecommendationIntent){productRecommendations(${byId ? "productId: $id" : "productHandle: $handle"},intent:$intent){...TetherProduct}}`
|
|
1676
|
-
),
|
|
1677
|
-
byId ? { id: key, intent } : { handle: key, intent },
|
|
1678
|
-
isRecommendationsAnswer
|
|
1679
|
-
);
|
|
1680
|
-
const list = data.productRecommendations ?? [];
|
|
1681
|
-
list.forEach(primeProduct);
|
|
1682
|
-
return list;
|
|
1683
|
-
}
|
|
1684
1664
|
|
|
1685
1665
|
// src/product-render.ts
|
|
1686
1666
|
var NTH_IMAGE_BIND = /^image:(\d+)$/;
|
|
@@ -3217,128 +3197,6 @@
|
|
|
3217
3197
|
}
|
|
3218
3198
|
};
|
|
3219
3199
|
|
|
3220
|
-
// src/collection.ts
|
|
3221
|
-
var URL_QUERY_SOURCE = "url:";
|
|
3222
|
-
var listSelector = () => `${sel("collection")},${sel("products")},${sel("recommendations")}`;
|
|
3223
|
-
var isElement2 = (target) => target instanceof window.Element;
|
|
3224
|
-
var toLimit = (raw) => parseInt(raw ?? "", 10) || void 0;
|
|
3225
|
-
var toIntent = (raw) => raw === "COMPLEMENTARY" ? "COMPLEMENTARY" : "RELATED";
|
|
3226
|
-
var ListScope = class {
|
|
3227
|
-
constructor(root) {
|
|
3228
|
-
__publicField(this, "root");
|
|
3229
|
-
__publicField(this, "products", []);
|
|
3230
|
-
__publicField(this, "pageInfo", null);
|
|
3231
|
-
__publicField(this, "collection", null);
|
|
3232
|
-
/** Counts loads, so only the latest one renders. */
|
|
3233
|
-
__publicField(this, "loadToken", 0);
|
|
3234
|
-
this.root = root;
|
|
3235
|
-
setScopeStatus(root, "loading");
|
|
3236
|
-
root.addEventListener("click", (event) => {
|
|
3237
|
-
if (!isElement2(event.target)) return;
|
|
3238
|
-
const more = event.target.closest(sel("load-more"));
|
|
3239
|
-
if (more?.closest(listSelector()) !== root) return;
|
|
3240
|
-
event.preventDefault();
|
|
3241
|
-
void busy(more, () => this.load(true));
|
|
3242
|
-
});
|
|
3243
|
-
}
|
|
3244
|
-
$(selector) {
|
|
3245
|
-
return scoped(this.root, selector, listSelector());
|
|
3246
|
-
}
|
|
3247
|
-
/** The collection or search query of the list's attributes. */
|
|
3248
|
-
options() {
|
|
3249
|
-
const { root } = this;
|
|
3250
|
-
const query2 = { reverse: get(root, "reverse") === "true" };
|
|
3251
|
-
const first = toLimit(get(root, "limit"));
|
|
3252
|
-
if (first) query2.first = first;
|
|
3253
|
-
const sortKey = get(root, "sort");
|
|
3254
|
-
if (sortKey) query2.sortKey = sortKey;
|
|
3255
|
-
if (has(root, "collection")) {
|
|
3256
|
-
query2.collection = get(root, "collection") ?? "";
|
|
3257
|
-
return query2;
|
|
3258
|
-
}
|
|
3259
|
-
const raw = get(root, "products") ?? "";
|
|
3260
|
-
query2.query = raw.startsWith(URL_QUERY_SOURCE) ? new URL(window.location.href).searchParams.get(raw.slice(URL_QUERY_SOURCE.length)) || "" : raw;
|
|
3261
|
-
return query2;
|
|
3262
|
-
}
|
|
3263
|
-
/**
|
|
3264
|
-
* The product of a recommendations list: a handle, `url:…` (one dynamic product page), or empty inside a product
|
|
3265
|
-
* scope for that product.
|
|
3266
|
-
*
|
|
3267
|
-
* @throws {TetherError} `NOT_FOUND` when there is no product to recommend for.
|
|
3268
|
-
*/
|
|
3269
|
-
async loadRecommendations() {
|
|
3270
|
-
let { key } = resolveProductKey(this.root, window.location, "recommendations");
|
|
3271
|
-
const scope = this.root.closest(sel("product"));
|
|
3272
|
-
if (!key && scope) ({ key } = resolveProductKey(scope));
|
|
3273
|
-
if (!key) throw new TetherError("No product for recommendations", { code: "NOT_FOUND" });
|
|
3274
|
-
return getRecommendations(key, toIntent(get(this.root, "intent")));
|
|
3275
|
-
}
|
|
3276
|
-
/** @param more Appends the next page instead of replacing the products. */
|
|
3277
|
-
async load(more = false) {
|
|
3278
|
-
this.loadToken += 1;
|
|
3279
|
-
const token = this.loadToken;
|
|
3280
|
-
const stale2 = () => token !== this.loadToken;
|
|
3281
|
-
try {
|
|
3282
|
-
if (has(this.root, "recommendations")) {
|
|
3283
|
-
const recommendations = await this.loadRecommendations();
|
|
3284
|
-
if (stale2()) return;
|
|
3285
|
-
const limit = toLimit(get(this.root, "limit"));
|
|
3286
|
-
this.products = limit ? recommendations.slice(0, limit) : recommendations;
|
|
3287
|
-
} else {
|
|
3288
|
-
const page = await getProducts({ ...this.options(), after: more ? this.pageInfo?.endCursor ?? null : null });
|
|
3289
|
-
if (stale2()) return;
|
|
3290
|
-
this.collection = page.collection;
|
|
3291
|
-
this.pageInfo = page.pageInfo;
|
|
3292
|
-
this.products = more ? [...this.products, ...page.products] : page.products;
|
|
3293
|
-
}
|
|
3294
|
-
this.render();
|
|
3295
|
-
setScopeStatus(this.root, "ready");
|
|
3296
|
-
emit("list-ready", { products: this.products, collection: this.collection }, this.root);
|
|
3297
|
-
} catch (error) {
|
|
3298
|
-
if (stale2()) return;
|
|
3299
|
-
if (!more) setScopeStatus(this.root, isNotFound(error) ? "not-found" : "error", error);
|
|
3300
|
-
if (!(isNotFound(error) && has(this.root, "recommendations"))) reportError(error, "list load failed");
|
|
3301
|
-
emit("error", { error, context: "list" }, this.root);
|
|
3302
|
-
}
|
|
3303
|
-
}
|
|
3304
|
-
render() {
|
|
3305
|
-
const { collection } = this;
|
|
3306
|
-
this.$(sel("collection-bind")).forEach((el) => {
|
|
3307
|
-
switch (get(el, "collection-bind") ?? "") {
|
|
3308
|
-
case "title":
|
|
3309
|
-
setText(el, collection?.title ?? "");
|
|
3310
|
-
break;
|
|
3311
|
-
case "description":
|
|
3312
|
-
setStoreHtml(el, collection?.descriptionHtml);
|
|
3313
|
-
break;
|
|
3314
|
-
case "image":
|
|
3315
|
-
setImage(el, collection?.image?.url, collection?.image?.altText || collection?.title);
|
|
3316
|
-
break;
|
|
3317
|
-
case "count":
|
|
3318
|
-
setText(el, this.products.length);
|
|
3319
|
-
break;
|
|
3320
|
-
}
|
|
3321
|
-
});
|
|
3322
|
-
this.$(sel("list")).forEach((container) => {
|
|
3323
|
-
repeat(container, this.products, (node, product) => {
|
|
3324
|
-
node.setAttribute(attr("product"), product.handle);
|
|
3325
|
-
node.removeAttribute(attr("state"));
|
|
3326
|
-
});
|
|
3327
|
-
emit("list-rendered", { container }, this.root);
|
|
3328
|
-
});
|
|
3329
|
-
const empty = this.products.length === 0;
|
|
3330
|
-
this.$(sel("show")).forEach((el) => {
|
|
3331
|
-
const key = get(el, "show");
|
|
3332
|
-
if (key === "list-empty") show(el, empty);
|
|
3333
|
-
if (key === "list-filled") show(el, !empty);
|
|
3334
|
-
});
|
|
3335
|
-
this.$(sel("load-more")).forEach((el) => {
|
|
3336
|
-
show(el, Boolean(this.pageInfo?.hasNextPage));
|
|
3337
|
-
});
|
|
3338
|
-
notifyLayoutChanged("list");
|
|
3339
|
-
}
|
|
3340
|
-
};
|
|
3341
|
-
|
|
3342
3200
|
// src/mounting.ts
|
|
3343
3201
|
var HYDRATE_SELECTOR = 'script[type="application/json"][data-tether-hydrate]';
|
|
3344
3202
|
var mountedProducts = /* @__PURE__ */ new WeakSet();
|
|
@@ -3578,7 +3436,7 @@
|
|
|
3578
3436
|
}
|
|
3579
3437
|
|
|
3580
3438
|
// src/part-integrity.ts
|
|
3581
|
-
var PART_INTEGRITY = { "tether.diagnose.js": "sha384-
|
|
3439
|
+
var PART_INTEGRITY = { "tether.diagnose.js": "sha384-6b98ZqhqrOFydwTyklda6rjvyWrgz1OnmffApLQ3+gg6VPSU1Yy3LhR1OT4lprfa", "tether.markets.js": "sha384-f9ZeUfc/tMICwVFPrC44Sa1oxm9c6jTQASJdNhHWDk55thsEVScodDBKSYUiuDgr", "tether.search.js": "sha384-kNQI7aVmvUyNgV2e6+PRy53xmbKiZi2n1hhYmHUDFCGU3BR6SoGpGKVKVbPE0ZtG", "tether.lists.js": "sha384-MfQgl9RjiTn6vr80fQymnFikrsDXh3wcmT8cu858s7z9p/oByQaJUKZo92qhjX1P", "tether.extras.js": "sha384-H4CWsEibHw/99UiBAi366ctyaNZrVMkK6Y1YJYYcGDbNthy5eQdS+RRcrlm1clmQ", "tether.account.js": "sha384-UeOp/wddJlVjmlYcVqqO9hU7ANLYEtY/TtK/y5cFkQ6J+SPBmqI/VReaAh+reCMC", "tether.account-pages.js": "sha384-jBeU+vF/U13v+9LZxg5R8lQb/PDHTXPVvu1EmsdDUrlh7BmIntbZJh2+iT6YykTy", "tether.analytics.js": "sha384-4gJ/lcu+S+sfpEHu64+0m2zbXpvNsyOxKDQchPEIb1SFg3ky1JlXODNSdRoodST9" };
|
|
3582
3440
|
|
|
3583
3441
|
// src/part-registry.ts
|
|
3584
3442
|
function isTetherInternals(value) {
|
|
@@ -3586,7 +3444,7 @@
|
|
|
3586
3444
|
}
|
|
3587
3445
|
|
|
3588
3446
|
// src/version.ts
|
|
3589
|
-
var VERSION = "0.
|
|
3447
|
+
var VERSION = "0.9.1";
|
|
3590
3448
|
|
|
3591
3449
|
// src/lazy-iife.ts
|
|
3592
3450
|
var coreModules = {
|
|
@@ -3594,13 +3452,14 @@
|
|
|
3594
3452
|
return [cfg, isConfigured, log, MARKET_SOURCES, parseMarkets, reportError, warn];
|
|
3595
3453
|
},
|
|
3596
3454
|
get "client.ts"() {
|
|
3597
|
-
return [endpoint, gql, orNull, shaped, TetherError];
|
|
3455
|
+
return [endpoint, gql, matches, orNull, shaped, TetherError];
|
|
3598
3456
|
},
|
|
3599
3457
|
get "dom.ts"() {
|
|
3600
3458
|
return [
|
|
3601
3459
|
ANALYTICS_EVENTS,
|
|
3602
3460
|
attr,
|
|
3603
3461
|
attributesFromJson,
|
|
3462
|
+
busy,
|
|
3604
3463
|
emit,
|
|
3605
3464
|
formatDate,
|
|
3606
3465
|
formatMoney2,
|
|
@@ -3608,24 +3467,30 @@
|
|
|
3608
3467
|
has,
|
|
3609
3468
|
hasTemplate,
|
|
3610
3469
|
isOwnEvent,
|
|
3470
|
+
notifyLayoutChanged,
|
|
3611
3471
|
parseJSONAttr,
|
|
3612
3472
|
productUrl2,
|
|
3613
3473
|
qsa,
|
|
3614
3474
|
repeat,
|
|
3475
|
+
scoped,
|
|
3615
3476
|
sel,
|
|
3616
3477
|
setImage,
|
|
3478
|
+
setStoreHtml,
|
|
3617
3479
|
setText,
|
|
3618
3480
|
show
|
|
3619
3481
|
];
|
|
3620
3482
|
},
|
|
3621
3483
|
get "loader.ts"() {
|
|
3622
|
-
return [clearProductCache, getProduct];
|
|
3484
|
+
return [clearProductCache, getProduct, normalizeProductKey, primeProduct, withProductFragment];
|
|
3485
|
+
},
|
|
3486
|
+
get "fragments.ts"() {
|
|
3487
|
+
return [collectionFields];
|
|
3623
3488
|
},
|
|
3624
3489
|
get "selling-plans.ts"() {
|
|
3625
3490
|
return [allPlans];
|
|
3626
3491
|
},
|
|
3627
3492
|
get "status.ts"() {
|
|
3628
|
-
return [boundary, resolveProductKey];
|
|
3493
|
+
return [boundary, isNotFound, resolveProductKey, setScopeStatus];
|
|
3629
3494
|
},
|
|
3630
3495
|
get "cart.ts"() {
|
|
3631
3496
|
return [Cart];
|
|
@@ -3688,12 +3553,16 @@
|
|
|
3688
3553
|
return;
|
|
3689
3554
|
}
|
|
3690
3555
|
parts.delete(name);
|
|
3691
|
-
const problem = isTetherInternals(tether) ? "did not register" : "can't register: window.Tether is no longer this Tether script's";
|
|
3556
|
+
const problem = isTetherInternals(tether) ? "did not register" : "can't register: window.Tether is no longer this Tether script's, another script replaced it";
|
|
3692
3557
|
reject(new Error(`${url2} ${problem}`));
|
|
3693
3558
|
};
|
|
3694
3559
|
script.onerror = () => {
|
|
3695
3560
|
parts.delete(name);
|
|
3696
|
-
reject(
|
|
3561
|
+
reject(
|
|
3562
|
+
new Error(
|
|
3563
|
+
`Could not load ${url2}, or it is not the file built with this Tether script. Host the same release's files next to the Tether script or at partsUrl.`
|
|
3564
|
+
)
|
|
3565
|
+
);
|
|
3697
3566
|
};
|
|
3698
3567
|
document.head.appendChild(script);
|
|
3699
3568
|
});
|
|
@@ -3719,6 +3588,19 @@
|
|
|
3719
3588
|
return loading;
|
|
3720
3589
|
}
|
|
3721
3590
|
|
|
3591
|
+
// src/collection.ts
|
|
3592
|
+
var listSelector = () => `${sel("collection")},${sel("products")},${sel("recommendations")}`;
|
|
3593
|
+
function mountedList(root) {
|
|
3594
|
+
setScopeStatus(root, "loading");
|
|
3595
|
+
return {
|
|
3596
|
+
root,
|
|
3597
|
+
load: () => loadPart("lists").then((part) => part.loadList(root)).catch((error) => {
|
|
3598
|
+
setScopeStatus(root, "error", error);
|
|
3599
|
+
reportError(error, "lists");
|
|
3600
|
+
})
|
|
3601
|
+
};
|
|
3602
|
+
}
|
|
3603
|
+
|
|
3722
3604
|
// src/account-marks.ts
|
|
3723
3605
|
var hintKey = () => `${cfg.prefix}:account-hint:${cfg.domain}`;
|
|
3724
3606
|
function removeFromBothAreas(key) {
|
|
@@ -3781,7 +3663,7 @@
|
|
|
3781
3663
|
|
|
3782
3664
|
// src/controls/cart-controls.ts
|
|
3783
3665
|
var lineKeyAttribute = () => `data-${cfg.prefix}-key`;
|
|
3784
|
-
var
|
|
3666
|
+
var isElement2 = (target) => target instanceof window.Element;
|
|
3785
3667
|
function lineOf(target) {
|
|
3786
3668
|
const line = target.closest(`[${lineKeyAttribute()}]`);
|
|
3787
3669
|
const id = line?.getAttribute(lineKeyAttribute());
|
|
@@ -3814,7 +3696,7 @@
|
|
|
3814
3696
|
}
|
|
3815
3697
|
function onClick2(event) {
|
|
3816
3698
|
const { target } = event;
|
|
3817
|
-
if (!
|
|
3699
|
+
if (!isElement2(target)) return;
|
|
3818
3700
|
if (target.closest(sel("cart-open"))) {
|
|
3819
3701
|
event.preventDefault();
|
|
3820
3702
|
Cart.toggle();
|
|
@@ -3851,7 +3733,7 @@
|
|
|
3851
3733
|
}
|
|
3852
3734
|
function onChange2(event) {
|
|
3853
3735
|
const { target } = event;
|
|
3854
|
-
if (!
|
|
3736
|
+
if (!isElement2(target)) return;
|
|
3855
3737
|
const found = lineOf(target);
|
|
3856
3738
|
if (found && target instanceof window.HTMLInputElement && target.matches(sel("line", "quantity"))) {
|
|
3857
3739
|
showLineBusy(found.line, Cart.updateLine(found.id, parseInt(target.value, 10) || 0), "cart line");
|
|
@@ -3877,7 +3759,7 @@
|
|
|
3877
3759
|
}
|
|
3878
3760
|
|
|
3879
3761
|
// src/controls/discount.ts
|
|
3880
|
-
var
|
|
3762
|
+
var isElement3 = (target) => target instanceof window.Element;
|
|
3881
3763
|
function codeInputOf(form) {
|
|
3882
3764
|
const input = form.querySelector(sel("discount-input")) ?? form.querySelector("input");
|
|
3883
3765
|
return input instanceof window.HTMLInputElement ? input : null;
|
|
@@ -3901,7 +3783,7 @@
|
|
|
3901
3783
|
}
|
|
3902
3784
|
function onSubmit(event) {
|
|
3903
3785
|
const { target } = event;
|
|
3904
|
-
const form =
|
|
3786
|
+
const form = isElement3(target) ? target.closest(sel("discount-form")) : null;
|
|
3905
3787
|
if (!form) return;
|
|
3906
3788
|
event.preventDefault();
|
|
3907
3789
|
const input = codeInputOf(form);
|
|
@@ -3911,7 +3793,7 @@
|
|
|
3911
3793
|
}
|
|
3912
3794
|
function onInput(event) {
|
|
3913
3795
|
const { target } = event;
|
|
3914
|
-
if (!
|
|
3796
|
+
if (!isElement3(target)) return;
|
|
3915
3797
|
const form = target.closest(sel("discount-form"));
|
|
3916
3798
|
if (!form) return;
|
|
3917
3799
|
form.classList.remove("is-invalid");
|
|
@@ -3919,7 +3801,7 @@
|
|
|
3919
3801
|
}
|
|
3920
3802
|
function onClick3(event) {
|
|
3921
3803
|
const { target } = event;
|
|
3922
|
-
const remove =
|
|
3804
|
+
const remove = isElement3(target) ? target.closest(sel("discount-remove")) : null;
|
|
3923
3805
|
if (!remove) return;
|
|
3924
3806
|
event.preventDefault();
|
|
3925
3807
|
const code = remove.closest(sel("discount-code"))?.getAttribute(attr("discount-code"));
|
|
@@ -4033,7 +3915,7 @@
|
|
|
4033
3915
|
if (mountedLists.has(el)) return;
|
|
4034
3916
|
mountedLists.add(el);
|
|
4035
3917
|
count++;
|
|
4036
|
-
const list =
|
|
3918
|
+
const list = mountedList(el);
|
|
4037
3919
|
liveLists.add(list);
|
|
4038
3920
|
el.addEventListener(`${cfg.prefix}:list-rendered`, (event) => {
|
|
4039
3921
|
if (isOwnEvent(event, "list-rendered")) mount(event.detail.container);
|
|
@@ -4165,6 +4047,8 @@
|
|
|
4165
4047
|
observer.observe(document.body, { childList: true, subtree: true });
|
|
4166
4048
|
}
|
|
4167
4049
|
var detectMarket = (markets) => loadPart("markets").then((part) => part.detectMarket(markets ?? cfg.markets));
|
|
4050
|
+
var getProducts = (query2) => loadPart("lists").then((part) => part.getProducts(query2));
|
|
4051
|
+
var getRecommendations = (product, intent) => loadPart("lists").then((part) => part.getRecommendations(product, intent));
|
|
4168
4052
|
var getLocalization = () => loadPart("markets").then((part) => part.getLocalization());
|
|
4169
4053
|
var diagnose = (options) => loadPart("diagnose").then((part) => part.diagnose({ ...options, version: VERSION }));
|
|
4170
4054
|
function on(name, listener) {
|