@occluze/tether 0.8.0 → 0.9.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/README.md +5 -5
- package/dist/esm/astro.js +1 -1
- package/dist/esm/chunks/account-FKLGF264.js +1 -0
- package/dist/esm/chunks/{account-pages-XR6QZ3DX.js → account-pages-PNORWX72.js} +1 -1
- package/dist/esm/chunks/analytics-V24XX2J7.js +1 -0
- package/dist/esm/chunks/{chunk-255K6OZ7.js → chunk-2IHA3PVC.js} +1 -1
- package/dist/esm/chunks/chunk-2LYWZ72A.js +1 -0
- package/dist/esm/chunks/{chunk-3OEIEDTK.js → chunk-2NV5PSJ2.js} +1 -1
- package/dist/esm/chunks/chunk-2X5U24IC.js +1 -0
- package/dist/esm/chunks/chunk-5B36ISJF.js +1 -0
- package/dist/esm/chunks/chunk-6WE7XCHH.js +1 -0
- package/dist/esm/chunks/chunk-6ZIOAYKF.js +1 -0
- package/dist/esm/chunks/{chunk-FM7ZLLVP.js → chunk-CR5IGHCO.js} +1 -1
- package/dist/esm/chunks/{chunk-KNJB72OO.js → chunk-E3JL6WS3.js} +1 -1
- package/dist/esm/chunks/{chunk-KVPLRK6Y.js → chunk-F5CLIGSC.js} +1 -1
- package/dist/esm/chunks/{chunk-O4G2PAQC.js → chunk-GOKJQGLG.js} +1 -1
- package/dist/esm/chunks/chunk-RW23CJDZ.js +1 -0
- package/dist/esm/chunks/chunk-TW34GYSL.js +1 -0
- package/dist/esm/chunks/chunk-VKKKH75V.js +1 -0
- package/dist/esm/chunks/{chunk-A3GXCQJ4.js → chunk-YWQWLKFW.js} +1 -1
- package/dist/esm/chunks/chunk-YYNBHXQF.js +1 -0
- package/dist/esm/chunks/{diagnose-XQQTDHLQ.js → diagnose-3RTKEBNW.js} +1 -1
- package/dist/esm/chunks/extras-O54VUXK6.js +1 -0
- package/dist/esm/chunks/lists-MRTI5RXY.js +1 -0
- package/dist/esm/chunks/markets-ui-P7G33T6Y.js +1 -0
- package/dist/esm/chunks/search-YSRDFVD7.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 +83 -206
- 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 -4
- 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 +6 -5
- 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 -0
- package/package.json +5 -5
- package/dist/esm/chunks/account-5X563BON.js +0 -1
- package/dist/esm/chunks/analytics-JSFHDBU3.js +0 -1
- package/dist/esm/chunks/chunk-55OHYO66.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-J7GYROV4.js +0 -4
- package/dist/esm/chunks/chunk-WNFEYPHV.js +0 -1
- package/dist/esm/chunks/chunk-WXF4L42L.js +0 -1
- package/dist/esm/chunks/extras-6WLNUEGD.js +0 -1
- package/dist/esm/chunks/markets-ui-OAJW4PFU.js +0 -1
- package/dist/esm/chunks/search-LUECIYJR.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,11 @@
|
|
|
338
340
|
dropped(name, value);
|
|
339
341
|
}
|
|
340
342
|
}
|
|
343
|
+
var DELAY_OPTIONS = /* @__PURE__ */ new Set(["requestTimeout", "searchDelay"]);
|
|
344
|
+
var MAX_TIMER_MS = 2147483647;
|
|
341
345
|
function countOption(name, value) {
|
|
342
|
-
|
|
346
|
+
const maximum = DELAY_OPTIONS.has(name) ? MAX_TIMER_MS : Number.POSITIVE_INFINITY;
|
|
347
|
+
if (typeof value === "number" && Number.isInteger(value) && value >= 0 && value <= maximum) return value;
|
|
343
348
|
return invalidOption(name, value, DEFAULTS[name]);
|
|
344
349
|
}
|
|
345
350
|
function switchOption(name, value) {
|
|
@@ -545,13 +550,27 @@
|
|
|
545
550
|
const unclear = res.ok && (serverError || operation === "mutation" && data == null);
|
|
546
551
|
throw graphQLFailure(res, errors, conf, unclear ? "SERVER_ERROR" : void 0);
|
|
547
552
|
}
|
|
548
|
-
async function
|
|
553
|
+
async function withTimeout(ms, send2) {
|
|
554
|
+
if (!ms) return send2(null);
|
|
555
|
+
const controller = new AbortController();
|
|
556
|
+
const timer = setTimeout(() => {
|
|
557
|
+
controller.abort(new DOMException("signal timed out", "TimeoutError"));
|
|
558
|
+
}, ms);
|
|
559
|
+
try {
|
|
560
|
+
return await send2(controller.signal);
|
|
561
|
+
} finally {
|
|
562
|
+
clearTimeout(timer);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
async function attempt(conf, query2, variables, isData, retry, operation, signal) {
|
|
549
566
|
let res;
|
|
550
567
|
try {
|
|
551
568
|
res = await (conf.fetch ?? fetch)(endpoint(conf), {
|
|
552
569
|
method: "POST",
|
|
553
570
|
headers: { "Content-Type": "application/json", "X-Shopify-Storefront-Access-Token": conf.token },
|
|
554
|
-
body: JSON.stringify({ query: query2, variables })
|
|
571
|
+
body: JSON.stringify({ query: query2, variables }),
|
|
572
|
+
// A `fetch` given to the server helpers has to honour the signal, as the platform's does.
|
|
573
|
+
signal
|
|
555
574
|
});
|
|
556
575
|
} catch (error) {
|
|
557
576
|
return networkFailure(error, retry);
|
|
@@ -588,7 +607,10 @@
|
|
|
588
607
|
const access = { inventory: !storesWithoutInventory.has(store) };
|
|
589
608
|
const sent = queryText(conf, query2, access, { context, operation });
|
|
590
609
|
const retry = retries < conf.retries ? retryWhileLeft : "none";
|
|
591
|
-
const outcome = await
|
|
610
|
+
const outcome = await withTimeout(
|
|
611
|
+
conf.requestTimeout,
|
|
612
|
+
(signal) => attempt(conf, sent, variables, isData, retry, operation, signal)
|
|
613
|
+
);
|
|
592
614
|
switch (outcome.kind) {
|
|
593
615
|
case "data":
|
|
594
616
|
return outcome.data;
|
|
@@ -598,9 +620,9 @@
|
|
|
598
620
|
storesWithoutInventory.add(store);
|
|
599
621
|
break;
|
|
600
622
|
case "retry":
|
|
623
|
+
await sleep(outcome.backoffMs * 2 ** retries);
|
|
601
624
|
retries += 1;
|
|
602
625
|
log("retry", retries);
|
|
603
|
-
await sleep(outcome.backoffMs * 2 ** retries);
|
|
604
626
|
break;
|
|
605
627
|
}
|
|
606
628
|
}
|
|
@@ -1220,10 +1242,7 @@
|
|
|
1220
1242
|
return ` fragment TetherCart on Cart{id checkoutUrl totalQuantity note createdAt updatedAt attributes{key value}buyerIdentity{countryCode email}discountCodes{code applicable}cost{subtotalAmount{${MONEY}}totalAmount{${MONEY}}checkoutChargeAmount{${MONEY}}}lines(first:100){nodes{id quantity attributes{key value}cost{totalAmount{${MONEY}}subtotalAmount{${MONEY}}amountPerQuantity{${MONEY}}compareAtAmountPerQuantity{${MONEY}}}discountAllocations{discountedAmount{${MONEY}}}sellingPlanAllocation{sellingPlan{id name description recurringDeliveries options{name value}}checkoutChargeAmount{${MONEY}}priceAdjustments{price{${MONEY}}compareAtPrice{${MONEY}}perDeliveryPrice{${MONEY}}}}merchandise{... on ProductVariant{id title sku availableForSale requiresShipping ${inventoryField(access)} image{${IMAGE}}price{${MONEY}}compareAtPrice{${MONEY}}selectedOptions{name value}product{id title handle vendor featuredImage{${IMAGE}}}}}... on ComponentizableCartLine{lineComponents{id quantity merchandise{... on ProductVariant{id title product{title handle}}}}}}}}`;
|
|
1221
1243
|
}
|
|
1222
1244
|
function collectionFields() {
|
|
1223
|
-
return `
|
|
1224
|
-
id handle title description descriptionHtml
|
|
1225
|
-
image { ${IMAGE} }
|
|
1226
|
-
seo { title description }`;
|
|
1245
|
+
return ` id handle title description descriptionHtml image{${IMAGE}}seo{title description}`;
|
|
1227
1246
|
}
|
|
1228
1247
|
|
|
1229
1248
|
// src/selling-plans.ts
|
|
@@ -1372,6 +1391,13 @@
|
|
|
1372
1391
|
};
|
|
1373
1392
|
var isProductShape = (value) => field(value, "id") !== "" && field(value, "handle") !== "" && matches(value, PRODUCT);
|
|
1374
1393
|
var PRODUCT_NODE = (node) => isRecord(node) && (node["id"] === void 0 || matches(node, PRODUCT));
|
|
1394
|
+
var isCollectionAnswer = shaped({
|
|
1395
|
+
collection: orNull({ handle: "string", products: PRODUCT_CONNECTION })
|
|
1396
|
+
});
|
|
1397
|
+
var isSearchAnswer = shaped({ products: PRODUCT_CONNECTION });
|
|
1398
|
+
var isRecommendationsAnswer = shaped({
|
|
1399
|
+
productRecommendations: orNull([PRODUCT])
|
|
1400
|
+
});
|
|
1375
1401
|
|
|
1376
1402
|
// src/cart/cart-shape.ts
|
|
1377
1403
|
var LINE = {
|
|
@@ -1523,12 +1549,12 @@
|
|
|
1523
1549
|
if (ids.length) {
|
|
1524
1550
|
definitions.push("$ids: [ID!]!");
|
|
1525
1551
|
variables["ids"] = ids;
|
|
1526
|
-
selections.push(
|
|
1552
|
+
selections.push(`byId:nodes(ids:$ids){... on Product{...TetherProduct}}`);
|
|
1527
1553
|
}
|
|
1528
1554
|
handles.forEach((handle, index) => {
|
|
1529
1555
|
definitions.push(`$h${index}: String!`);
|
|
1530
1556
|
variables[`h${index}`] = handle;
|
|
1531
|
-
selections.push(`h${index}:
|
|
1557
|
+
selections.push(`h${index}:product(handle:$h${index}){...TetherProduct}`);
|
|
1532
1558
|
});
|
|
1533
1559
|
const query2 = withProductFragment(`query TetherProducts(${definitions.join(",")}){${selections.join(" ")}}`);
|
|
1534
1560
|
return { query: query2, variables, handles };
|
|
@@ -1626,64 +1652,6 @@
|
|
|
1626
1652
|
if (normalized) productCache.delete(normalized);
|
|
1627
1653
|
return getProduct(key);
|
|
1628
1654
|
}
|
|
1629
|
-
var isCollectionAnswer = shaped({
|
|
1630
|
-
collection: orNull({ handle: "string", products: PRODUCT_CONNECTION })
|
|
1631
|
-
});
|
|
1632
|
-
var isSearchAnswer = shaped({ products: PRODUCT_CONNECTION });
|
|
1633
|
-
var isRecommendationsAnswer = shaped({
|
|
1634
|
-
productRecommendations: orNull([PRODUCT])
|
|
1635
|
-
});
|
|
1636
|
-
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}}}}`;
|
|
1637
|
-
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}}}`;
|
|
1638
|
-
async function getProducts({
|
|
1639
|
-
collection,
|
|
1640
|
-
query: query2,
|
|
1641
|
-
first = cfg.collectionFirst,
|
|
1642
|
-
after = null,
|
|
1643
|
-
sortKey,
|
|
1644
|
-
reverse = false,
|
|
1645
|
-
filters
|
|
1646
|
-
} = {}) {
|
|
1647
|
-
if (collection) {
|
|
1648
|
-
const data2 = await gql(
|
|
1649
|
-
withProductFragment(COLLECTION_QUERY),
|
|
1650
|
-
{
|
|
1651
|
-
handle: collection,
|
|
1652
|
-
first,
|
|
1653
|
-
after,
|
|
1654
|
-
sortKey: sortKey || void 0,
|
|
1655
|
-
reverse,
|
|
1656
|
-
filters: filters ?? void 0
|
|
1657
|
-
},
|
|
1658
|
-
isCollectionAnswer
|
|
1659
|
-
);
|
|
1660
|
-
if (!data2.collection) throw new TetherError(`Collection not found: ${collection}`, { code: "NOT_FOUND" });
|
|
1661
|
-
const { products, ...rest } = data2.collection;
|
|
1662
|
-
products.nodes.forEach(primeProduct);
|
|
1663
|
-
return { collection: rest, products: products.nodes, pageInfo: products.pageInfo };
|
|
1664
|
-
}
|
|
1665
|
-
const data = await gql(
|
|
1666
|
-
withProductFragment(SEARCH_QUERY),
|
|
1667
|
-
{ first, after, query: query2 || void 0, sortKey: sortKey || void 0, reverse },
|
|
1668
|
-
isSearchAnswer
|
|
1669
|
-
);
|
|
1670
|
-
data.products.nodes.forEach(primeProduct);
|
|
1671
|
-
return { collection: null, products: data.products.nodes, pageInfo: data.products.pageInfo };
|
|
1672
|
-
}
|
|
1673
|
-
async function getRecommendations(product, intent = "RELATED") {
|
|
1674
|
-
const key = normalizeProductKey(typeof product === "object" ? product?.id : product);
|
|
1675
|
-
const byId = key?.startsWith("gid://") ?? false;
|
|
1676
|
-
const data = await gql(
|
|
1677
|
-
withProductFragment(
|
|
1678
|
-
`query TetherRecs(${byId ? "$id: ID!" : "$handle: String!"},$intent:ProductRecommendationIntent){productRecommendations(${byId ? "productId: $id" : "productHandle: $handle"},intent:$intent){...TetherProduct}}`
|
|
1679
|
-
),
|
|
1680
|
-
byId ? { id: key, intent } : { handle: key, intent },
|
|
1681
|
-
isRecommendationsAnswer
|
|
1682
|
-
);
|
|
1683
|
-
const list = data.productRecommendations ?? [];
|
|
1684
|
-
list.forEach(primeProduct);
|
|
1685
|
-
return list;
|
|
1686
|
-
}
|
|
1687
1655
|
|
|
1688
1656
|
// src/product-render.ts
|
|
1689
1657
|
var NTH_IMAGE_BIND = /^image:(\d+)$/;
|
|
@@ -2234,7 +2202,7 @@
|
|
|
2234
2202
|
}
|
|
2235
2203
|
async function fetchCheckoutUrl(id) {
|
|
2236
2204
|
const data = await gql(
|
|
2237
|
-
|
|
2205
|
+
`query TetherCheckout($id:ID!){cart(id:$id){checkoutUrl}}`,
|
|
2238
2206
|
{ id },
|
|
2239
2207
|
shaped({ cart: orNull({ checkoutUrl: "string" }) })
|
|
2240
2208
|
);
|
|
@@ -3220,128 +3188,6 @@
|
|
|
3220
3188
|
}
|
|
3221
3189
|
};
|
|
3222
3190
|
|
|
3223
|
-
// src/collection.ts
|
|
3224
|
-
var URL_QUERY_SOURCE = "url:";
|
|
3225
|
-
var listSelector = () => `${sel("collection")},${sel("products")},${sel("recommendations")}`;
|
|
3226
|
-
var isElement2 = (target) => target instanceof window.Element;
|
|
3227
|
-
var toLimit = (raw) => parseInt(raw ?? "", 10) || void 0;
|
|
3228
|
-
var toIntent = (raw) => raw === "COMPLEMENTARY" ? "COMPLEMENTARY" : "RELATED";
|
|
3229
|
-
var ListScope = class {
|
|
3230
|
-
constructor(root) {
|
|
3231
|
-
__publicField(this, "root");
|
|
3232
|
-
__publicField(this, "products", []);
|
|
3233
|
-
__publicField(this, "pageInfo", null);
|
|
3234
|
-
__publicField(this, "collection", null);
|
|
3235
|
-
/** Counts loads, so only the latest one renders. */
|
|
3236
|
-
__publicField(this, "loadToken", 0);
|
|
3237
|
-
this.root = root;
|
|
3238
|
-
setScopeStatus(root, "loading");
|
|
3239
|
-
root.addEventListener("click", (event) => {
|
|
3240
|
-
if (!isElement2(event.target)) return;
|
|
3241
|
-
const more = event.target.closest(sel("load-more"));
|
|
3242
|
-
if (more?.closest(listSelector()) !== root) return;
|
|
3243
|
-
event.preventDefault();
|
|
3244
|
-
void busy(more, () => this.load(true));
|
|
3245
|
-
});
|
|
3246
|
-
}
|
|
3247
|
-
$(selector) {
|
|
3248
|
-
return scoped(this.root, selector, listSelector());
|
|
3249
|
-
}
|
|
3250
|
-
/** The collection or search query of the list's attributes. */
|
|
3251
|
-
options() {
|
|
3252
|
-
const { root } = this;
|
|
3253
|
-
const query2 = { reverse: get(root, "reverse") === "true" };
|
|
3254
|
-
const first = toLimit(get(root, "limit"));
|
|
3255
|
-
if (first) query2.first = first;
|
|
3256
|
-
const sortKey = get(root, "sort");
|
|
3257
|
-
if (sortKey) query2.sortKey = sortKey;
|
|
3258
|
-
if (has(root, "collection")) {
|
|
3259
|
-
query2.collection = get(root, "collection") ?? "";
|
|
3260
|
-
return query2;
|
|
3261
|
-
}
|
|
3262
|
-
const raw = get(root, "products") ?? "";
|
|
3263
|
-
query2.query = raw.startsWith(URL_QUERY_SOURCE) ? new URL(window.location.href).searchParams.get(raw.slice(URL_QUERY_SOURCE.length)) || "" : raw;
|
|
3264
|
-
return query2;
|
|
3265
|
-
}
|
|
3266
|
-
/**
|
|
3267
|
-
* The product of a recommendations list: a handle, `url:…` (one dynamic product page), or empty inside a product
|
|
3268
|
-
* scope for that product.
|
|
3269
|
-
*
|
|
3270
|
-
* @throws {TetherError} `NOT_FOUND` when there is no product to recommend for.
|
|
3271
|
-
*/
|
|
3272
|
-
async loadRecommendations() {
|
|
3273
|
-
let { key } = resolveProductKey(this.root, window.location, "recommendations");
|
|
3274
|
-
const scope = this.root.closest(sel("product"));
|
|
3275
|
-
if (!key && scope) ({ key } = resolveProductKey(scope));
|
|
3276
|
-
if (!key) throw new TetherError("No product for recommendations", { code: "NOT_FOUND" });
|
|
3277
|
-
return getRecommendations(key, toIntent(get(this.root, "intent")));
|
|
3278
|
-
}
|
|
3279
|
-
/** @param more Appends the next page instead of replacing the products. */
|
|
3280
|
-
async load(more = false) {
|
|
3281
|
-
this.loadToken += 1;
|
|
3282
|
-
const token = this.loadToken;
|
|
3283
|
-
const stale2 = () => token !== this.loadToken;
|
|
3284
|
-
try {
|
|
3285
|
-
if (has(this.root, "recommendations")) {
|
|
3286
|
-
const recommendations = await this.loadRecommendations();
|
|
3287
|
-
if (stale2()) return;
|
|
3288
|
-
const limit = toLimit(get(this.root, "limit"));
|
|
3289
|
-
this.products = limit ? recommendations.slice(0, limit) : recommendations;
|
|
3290
|
-
} else {
|
|
3291
|
-
const page = await getProducts({ ...this.options(), after: more ? this.pageInfo?.endCursor ?? null : null });
|
|
3292
|
-
if (stale2()) return;
|
|
3293
|
-
this.collection = page.collection;
|
|
3294
|
-
this.pageInfo = page.pageInfo;
|
|
3295
|
-
this.products = more ? [...this.products, ...page.products] : page.products;
|
|
3296
|
-
}
|
|
3297
|
-
this.render();
|
|
3298
|
-
setScopeStatus(this.root, "ready");
|
|
3299
|
-
emit("list-ready", { products: this.products, collection: this.collection }, this.root);
|
|
3300
|
-
} catch (error) {
|
|
3301
|
-
if (stale2()) return;
|
|
3302
|
-
if (!more) setScopeStatus(this.root, isNotFound(error) ? "not-found" : "error", error);
|
|
3303
|
-
if (!(isNotFound(error) && has(this.root, "recommendations"))) reportError(error, "list load failed");
|
|
3304
|
-
emit("error", { error, context: "list" }, this.root);
|
|
3305
|
-
}
|
|
3306
|
-
}
|
|
3307
|
-
render() {
|
|
3308
|
-
const { collection } = this;
|
|
3309
|
-
this.$(sel("collection-bind")).forEach((el) => {
|
|
3310
|
-
switch (get(el, "collection-bind") ?? "") {
|
|
3311
|
-
case "title":
|
|
3312
|
-
setText(el, collection?.title ?? "");
|
|
3313
|
-
break;
|
|
3314
|
-
case "description":
|
|
3315
|
-
setStoreHtml(el, collection?.descriptionHtml);
|
|
3316
|
-
break;
|
|
3317
|
-
case "image":
|
|
3318
|
-
setImage(el, collection?.image?.url, collection?.image?.altText || collection?.title);
|
|
3319
|
-
break;
|
|
3320
|
-
case "count":
|
|
3321
|
-
setText(el, this.products.length);
|
|
3322
|
-
break;
|
|
3323
|
-
}
|
|
3324
|
-
});
|
|
3325
|
-
this.$(sel("list")).forEach((container) => {
|
|
3326
|
-
repeat(container, this.products, (node, product) => {
|
|
3327
|
-
node.setAttribute(attr("product"), product.handle);
|
|
3328
|
-
node.removeAttribute(attr("state"));
|
|
3329
|
-
});
|
|
3330
|
-
emit("list-rendered", { container }, this.root);
|
|
3331
|
-
});
|
|
3332
|
-
const empty = this.products.length === 0;
|
|
3333
|
-
this.$(sel("show")).forEach((el) => {
|
|
3334
|
-
const key = get(el, "show");
|
|
3335
|
-
if (key === "list-empty") show(el, empty);
|
|
3336
|
-
if (key === "list-filled") show(el, !empty);
|
|
3337
|
-
});
|
|
3338
|
-
this.$(sel("load-more")).forEach((el) => {
|
|
3339
|
-
show(el, Boolean(this.pageInfo?.hasNextPage));
|
|
3340
|
-
});
|
|
3341
|
-
notifyLayoutChanged("list");
|
|
3342
|
-
}
|
|
3343
|
-
};
|
|
3344
|
-
|
|
3345
3191
|
// src/mounting.ts
|
|
3346
3192
|
var HYDRATE_SELECTOR = 'script[type="application/json"][data-tether-hydrate]';
|
|
3347
3193
|
var mountedProducts = /* @__PURE__ */ new WeakSet();
|
|
@@ -3581,26 +3427,30 @@
|
|
|
3581
3427
|
}
|
|
3582
3428
|
|
|
3583
3429
|
// src/part-integrity.ts
|
|
3584
|
-
var PART_INTEGRITY = { "tether.diagnose.js": "sha384-
|
|
3430
|
+
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" };
|
|
3585
3431
|
|
|
3586
3432
|
// src/part-registry.ts
|
|
3587
3433
|
function isTetherInternals(value) {
|
|
3588
3434
|
return isRecord(value) && isRecord(value["__core"]) && isRecord(value["__parts"]);
|
|
3589
3435
|
}
|
|
3590
3436
|
|
|
3437
|
+
// src/version.ts
|
|
3438
|
+
var VERSION = "0.9.0";
|
|
3439
|
+
|
|
3591
3440
|
// src/lazy-iife.ts
|
|
3592
3441
|
var coreModules = {
|
|
3593
3442
|
get "config.ts"() {
|
|
3594
3443
|
return [cfg, isConfigured, log, MARKET_SOURCES, parseMarkets, reportError, warn];
|
|
3595
3444
|
},
|
|
3596
3445
|
get "client.ts"() {
|
|
3597
|
-
return [endpoint, gql, orNull, shaped, TetherError];
|
|
3446
|
+
return [endpoint, gql, matches, orNull, shaped, TetherError];
|
|
3598
3447
|
},
|
|
3599
3448
|
get "dom.ts"() {
|
|
3600
3449
|
return [
|
|
3601
3450
|
ANALYTICS_EVENTS,
|
|
3602
3451
|
attr,
|
|
3603
3452
|
attributesFromJson,
|
|
3453
|
+
busy,
|
|
3604
3454
|
emit,
|
|
3605
3455
|
formatDate,
|
|
3606
3456
|
formatMoney2,
|
|
@@ -3608,24 +3458,30 @@
|
|
|
3608
3458
|
has,
|
|
3609
3459
|
hasTemplate,
|
|
3610
3460
|
isOwnEvent,
|
|
3461
|
+
notifyLayoutChanged,
|
|
3611
3462
|
parseJSONAttr,
|
|
3612
3463
|
productUrl2,
|
|
3613
3464
|
qsa,
|
|
3614
3465
|
repeat,
|
|
3466
|
+
scoped,
|
|
3615
3467
|
sel,
|
|
3616
3468
|
setImage,
|
|
3469
|
+
setStoreHtml,
|
|
3617
3470
|
setText,
|
|
3618
3471
|
show
|
|
3619
3472
|
];
|
|
3620
3473
|
},
|
|
3621
3474
|
get "loader.ts"() {
|
|
3622
|
-
return [clearProductCache, getProduct];
|
|
3475
|
+
return [clearProductCache, getProduct, normalizeProductKey, primeProduct, withProductFragment];
|
|
3476
|
+
},
|
|
3477
|
+
get "fragments.ts"() {
|
|
3478
|
+
return [collectionFields];
|
|
3623
3479
|
},
|
|
3624
3480
|
get "selling-plans.ts"() {
|
|
3625
3481
|
return [allPlans];
|
|
3626
3482
|
},
|
|
3627
3483
|
get "status.ts"() {
|
|
3628
|
-
return [boundary, resolveProductKey];
|
|
3484
|
+
return [boundary, isNotFound, resolveProductKey, setScopeStatus];
|
|
3629
3485
|
},
|
|
3630
3486
|
get "cart.ts"() {
|
|
3631
3487
|
return [Cart];
|
|
@@ -3656,11 +3512,18 @@
|
|
|
3656
3512
|
var MINIFIED_SCRIPT = /\.min\.js(\?|$)/;
|
|
3657
3513
|
var coreScript = typeof document === "undefined" ? "" : document.currentScript?.getAttribute("src") ?? "";
|
|
3658
3514
|
var coreScriptUrl = coreScript ? new URL(coreScript, document.baseURI).href : "";
|
|
3515
|
+
var JSDELIVR_ALIAS = /^(https:\/\/cdn\.jsdelivr\.net\/(gh|npm)\/@?[^/@]+\/[^/@]+)(@(latest|\d+(\.\d+)?))?\//;
|
|
3516
|
+
function exactReleaseFolder(folder) {
|
|
3517
|
+
return folder.replace(
|
|
3518
|
+
JSDELIVR_ALIAS,
|
|
3519
|
+
(_alias, path, source) => `${path}@${source === "gh" ? "v" : ""}${VERSION}/`
|
|
3520
|
+
);
|
|
3521
|
+
}
|
|
3659
3522
|
var parts = /* @__PURE__ */ new Map();
|
|
3660
3523
|
function partsFolder() {
|
|
3661
3524
|
if (cfg.partsUrl) return new URL(cfg.partsUrl, document.baseURI).href;
|
|
3662
3525
|
if (!coreScriptUrl) return null;
|
|
3663
|
-
return coreScriptUrl.replace(/[^/]*$/, "");
|
|
3526
|
+
return exactReleaseFolder(coreScriptUrl.replace(/[^/]*$/, ""));
|
|
3664
3527
|
}
|
|
3665
3528
|
function applyIntegrity(script, integrity) {
|
|
3666
3529
|
script.integrity = integrity;
|
|
@@ -3716,6 +3579,19 @@
|
|
|
3716
3579
|
return loading;
|
|
3717
3580
|
}
|
|
3718
3581
|
|
|
3582
|
+
// src/collection.ts
|
|
3583
|
+
var listSelector = () => `${sel("collection")},${sel("products")},${sel("recommendations")}`;
|
|
3584
|
+
function mountedList(root) {
|
|
3585
|
+
setScopeStatus(root, "loading");
|
|
3586
|
+
return {
|
|
3587
|
+
root,
|
|
3588
|
+
load: () => loadPart("lists").then((part) => part.loadList(root)).catch((error) => {
|
|
3589
|
+
setScopeStatus(root, "error", error);
|
|
3590
|
+
reportError(error, "lists");
|
|
3591
|
+
})
|
|
3592
|
+
};
|
|
3593
|
+
}
|
|
3594
|
+
|
|
3719
3595
|
// src/account-marks.ts
|
|
3720
3596
|
var hintKey = () => `${cfg.prefix}:account-hint:${cfg.domain}`;
|
|
3721
3597
|
function removeFromBothAreas(key) {
|
|
@@ -3778,7 +3654,7 @@
|
|
|
3778
3654
|
|
|
3779
3655
|
// src/controls/cart-controls.ts
|
|
3780
3656
|
var lineKeyAttribute = () => `data-${cfg.prefix}-key`;
|
|
3781
|
-
var
|
|
3657
|
+
var isElement2 = (target) => target instanceof window.Element;
|
|
3782
3658
|
function lineOf(target) {
|
|
3783
3659
|
const line = target.closest(`[${lineKeyAttribute()}]`);
|
|
3784
3660
|
const id = line?.getAttribute(lineKeyAttribute());
|
|
@@ -3811,7 +3687,7 @@
|
|
|
3811
3687
|
}
|
|
3812
3688
|
function onClick2(event) {
|
|
3813
3689
|
const { target } = event;
|
|
3814
|
-
if (!
|
|
3690
|
+
if (!isElement2(target)) return;
|
|
3815
3691
|
if (target.closest(sel("cart-open"))) {
|
|
3816
3692
|
event.preventDefault();
|
|
3817
3693
|
Cart.toggle();
|
|
@@ -3848,7 +3724,7 @@
|
|
|
3848
3724
|
}
|
|
3849
3725
|
function onChange2(event) {
|
|
3850
3726
|
const { target } = event;
|
|
3851
|
-
if (!
|
|
3727
|
+
if (!isElement2(target)) return;
|
|
3852
3728
|
const found = lineOf(target);
|
|
3853
3729
|
if (found && target instanceof window.HTMLInputElement && target.matches(sel("line", "quantity"))) {
|
|
3854
3730
|
showLineBusy(found.line, Cart.updateLine(found.id, parseInt(target.value, 10) || 0), "cart line");
|
|
@@ -3874,7 +3750,7 @@
|
|
|
3874
3750
|
}
|
|
3875
3751
|
|
|
3876
3752
|
// src/controls/discount.ts
|
|
3877
|
-
var
|
|
3753
|
+
var isElement3 = (target) => target instanceof window.Element;
|
|
3878
3754
|
function codeInputOf(form) {
|
|
3879
3755
|
const input = form.querySelector(sel("discount-input")) ?? form.querySelector("input");
|
|
3880
3756
|
return input instanceof window.HTMLInputElement ? input : null;
|
|
@@ -3898,7 +3774,7 @@
|
|
|
3898
3774
|
}
|
|
3899
3775
|
function onSubmit(event) {
|
|
3900
3776
|
const { target } = event;
|
|
3901
|
-
const form =
|
|
3777
|
+
const form = isElement3(target) ? target.closest(sel("discount-form")) : null;
|
|
3902
3778
|
if (!form) return;
|
|
3903
3779
|
event.preventDefault();
|
|
3904
3780
|
const input = codeInputOf(form);
|
|
@@ -3908,7 +3784,7 @@
|
|
|
3908
3784
|
}
|
|
3909
3785
|
function onInput(event) {
|
|
3910
3786
|
const { target } = event;
|
|
3911
|
-
if (!
|
|
3787
|
+
if (!isElement3(target)) return;
|
|
3912
3788
|
const form = target.closest(sel("discount-form"));
|
|
3913
3789
|
if (!form) return;
|
|
3914
3790
|
form.classList.remove("is-invalid");
|
|
@@ -3916,7 +3792,7 @@
|
|
|
3916
3792
|
}
|
|
3917
3793
|
function onClick3(event) {
|
|
3918
3794
|
const { target } = event;
|
|
3919
|
-
const remove =
|
|
3795
|
+
const remove = isElement3(target) ? target.closest(sel("discount-remove")) : null;
|
|
3920
3796
|
if (!remove) return;
|
|
3921
3797
|
event.preventDefault();
|
|
3922
3798
|
const code = remove.closest(sel("discount-code"))?.getAttribute(attr("discount-code"));
|
|
@@ -4015,7 +3891,6 @@
|
|
|
4015
3891
|
}
|
|
4016
3892
|
|
|
4017
3893
|
// src/index.ts
|
|
4018
|
-
var VERSION = "0.8.0";
|
|
4019
3894
|
var OBSERVE_DEBOUNCE_MS = 50;
|
|
4020
3895
|
function pageConfig() {
|
|
4021
3896
|
const config = pageGlobal("TETHER_CONFIG");
|
|
@@ -4031,7 +3906,7 @@
|
|
|
4031
3906
|
if (mountedLists.has(el)) return;
|
|
4032
3907
|
mountedLists.add(el);
|
|
4033
3908
|
count++;
|
|
4034
|
-
const list =
|
|
3909
|
+
const list = mountedList(el);
|
|
4035
3910
|
liveLists.add(list);
|
|
4036
3911
|
el.addEventListener(`${cfg.prefix}:list-rendered`, (event) => {
|
|
4037
3912
|
if (isOwnEvent(event, "list-rendered")) mount(event.detail.container);
|
|
@@ -4163,6 +4038,8 @@
|
|
|
4163
4038
|
observer.observe(document.body, { childList: true, subtree: true });
|
|
4164
4039
|
}
|
|
4165
4040
|
var detectMarket = (markets) => loadPart("markets").then((part) => part.detectMarket(markets ?? cfg.markets));
|
|
4041
|
+
var getProducts = (query2) => loadPart("lists").then((part) => part.getProducts(query2));
|
|
4042
|
+
var getRecommendations = (product, intent) => loadPart("lists").then((part) => part.getRecommendations(product, intent));
|
|
4166
4043
|
var getLocalization = () => loadPart("markets").then((part) => part.getLocalization());
|
|
4167
4044
|
var diagnose = (options) => loadPart("diagnose").then((part) => part.diagnose({ ...options, version: VERSION }));
|
|
4168
4045
|
function on(name, listener) {
|