@occluze/tether 0.9.2 → 0.9.4
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 +1 -1
- package/dist/esm/astro.js +2 -2
- package/dist/esm/chunks/account-2467DHLU.js +1 -0
- package/dist/esm/chunks/{account-pages-FIXSWJH7.js → account-pages-X7U3E7D7.js} +1 -1
- package/dist/esm/chunks/{analytics-MO2ZWBOD.js → analytics-TF7M4KI2.js} +1 -1
- package/dist/esm/chunks/{chunk-7CRTJV25.js → chunk-4QINHHE4.js} +1 -1
- package/dist/esm/chunks/chunk-5TS6IBBB.js +1 -0
- package/dist/esm/chunks/{chunk-BVO7KK2M.js → chunk-646NGAEM.js} +1 -1
- package/dist/esm/chunks/chunk-67MCLHFS.js +1 -0
- package/dist/esm/chunks/{chunk-FWMPL6PR.js → chunk-6FWNC7QH.js} +1 -1
- package/dist/esm/chunks/{chunk-IJAMRI33.js → chunk-AHYDU7Z6.js} +1 -1
- package/dist/esm/chunks/{chunk-SZRDO62E.js → chunk-B2X6ZOKA.js} +1 -1
- package/dist/esm/chunks/chunk-C2GKO34C.js +1 -0
- package/dist/esm/chunks/chunk-EYVBEFKK.js +1 -0
- package/dist/esm/chunks/{chunk-DM5LEAWM.js → chunk-F3OXGENC.js} +1 -1
- package/dist/esm/chunks/{chunk-OENVX4NY.js → chunk-HEK66LYK.js} +1 -1
- package/dist/esm/chunks/chunk-I7XE7GQR.js +1 -0
- package/dist/esm/chunks/chunk-KIZBET7N.js +1 -0
- package/dist/esm/chunks/chunk-UJYL5G7T.js +1 -0
- package/dist/esm/chunks/{chunk-CRKJ2VEX.js → chunk-UM37ZVSP.js} +1 -1
- package/dist/esm/chunks/chunk-YW3ZIFWB.js +1 -0
- package/dist/esm/chunks/{diagnose-XSZPWEG7.js → diagnose-AOSBLXOJ.js} +1 -1
- package/dist/esm/chunks/{extras-DZIOTZ3H.js → extras-THTXX76O.js} +1 -1
- package/dist/esm/chunks/lists-UJMD7BCQ.js +1 -0
- package/dist/esm/chunks/{markets-ui-DEEYV4KT.js → markets-ui-PTAY3FHU.js} +1 -1
- package/dist/esm/chunks/search-G2SRQXDG.js +1 -0
- package/dist/esm/index.js +1 -1
- package/dist/esm/server.js +2 -2
- package/dist/tether.account-pages.js +3 -3
- package/dist/tether.account-pages.min.js +1 -1
- package/dist/tether.account.js +20 -20
- 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 +2 -2
- package/dist/tether.diagnose.min.js +1 -1
- package/dist/tether.extras.js +1 -1
- package/dist/tether.extras.min.js +1 -1
- package/dist/tether.js +248 -129
- package/dist/tether.lists.js +12 -8
- package/dist/tether.lists.min.js +1 -1
- package/dist/tether.markets.js +2 -2
- 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 +60 -23
- package/dist/tether.search.min.js +1 -1
- package/dist/types/server/src/shared/metafield-ref.d.ts +15 -0
- package/dist/types/src/account/server-client.d.ts +2 -1
- package/dist/types/src/analytics-queue.d.ts +9 -0
- package/dist/types/src/cart/checkout.d.ts +2 -2
- package/dist/types/src/cart/drawer.d.ts +9 -4
- package/dist/types/src/cart/store.d.ts +2 -0
- package/dist/types/src/cart.d.ts +1 -1
- package/dist/types/src/client.d.ts +6 -0
- package/dist/types/src/dom.d.ts +25 -1
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/src/search.d.ts +1 -1
- package/dist/types/src/shopify-values.d.ts +2 -0
- package/dist/types/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/dist/esm/chunks/account-XBGNTM7V.js +0 -1
- package/dist/esm/chunks/chunk-2J3MTS3E.js +0 -1
- package/dist/esm/chunks/chunk-4FR3CUO2.js +0 -1
- package/dist/esm/chunks/chunk-7ZXEVDOS.js +0 -1
- package/dist/esm/chunks/chunk-FI4NIWAD.js +0 -1
- package/dist/esm/chunks/chunk-H6IORH7O.js +0 -1
- package/dist/esm/chunks/chunk-OATTAXPO.js +0 -1
- package/dist/esm/chunks/chunk-OJAV2I3C.js +0 -1
- package/dist/esm/chunks/chunk-Y3NKKN2O.js +0 -1
- package/dist/esm/chunks/lists-OJGSVQMM.js +0 -1
- package/dist/esm/chunks/search-A6HF5PMJ.js +0 -1
package/dist/tether.js
CHANGED
|
@@ -28,9 +28,19 @@
|
|
|
28
28
|
return isRecord(value) ? value[key] : void 0;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
// src/
|
|
32
|
-
var
|
|
31
|
+
// server/src/shared/metafield-ref.ts
|
|
32
|
+
var METAFIELD_KEY = /^[A-Za-z0-9_.-]+$/;
|
|
33
33
|
var METAFIELD_NAMESPACE = /^(\$app(:[A-Za-z0-9_-]+)?|[A-Za-z0-9_.-]+)$/;
|
|
34
|
+
var isMetafieldIdentifier = (namespace, key) => METAFIELD_NAMESPACE.test(namespace) && METAFIELD_KEY.test(key);
|
|
35
|
+
function metafieldIdentifierOf(ref) {
|
|
36
|
+
const dot = ref.indexOf(".");
|
|
37
|
+
if (dot <= 0) return null;
|
|
38
|
+
const namespace = ref.slice(0, dot);
|
|
39
|
+
const key = ref.slice(dot + 1);
|
|
40
|
+
return isMetafieldIdentifier(namespace, key) ? { namespace, key } : null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// src/config-sections.ts
|
|
34
44
|
var HOSTNAME = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
|
|
35
45
|
var COOKIE_NAME = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
|
|
36
46
|
var GLOBAL_NAME = /^[A-Za-z_$][\w$]*$/;
|
|
@@ -99,18 +109,12 @@
|
|
|
99
109
|
return origins;
|
|
100
110
|
}
|
|
101
111
|
function toMetafieldIdentifier(ref) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
namespace = dot > 0 ? ref.slice(0, dot) : "";
|
|
107
|
-
key = ref.slice(dot + 1);
|
|
108
|
-
} else if (typeof ref === "object" && ref !== null) {
|
|
109
|
-
namespace = Reflect.get(ref, "namespace");
|
|
110
|
-
key = Reflect.get(ref, "key");
|
|
111
|
-
}
|
|
112
|
+
if (typeof ref === "string") return metafieldIdentifierOf(ref);
|
|
113
|
+
if (typeof ref !== "object" || ref === null) return null;
|
|
114
|
+
const namespace = Reflect.get(ref, "namespace");
|
|
115
|
+
const key = Reflect.get(ref, "key");
|
|
112
116
|
if (typeof namespace !== "string" || typeof key !== "string") return null;
|
|
113
|
-
return
|
|
117
|
+
return isMetafieldIdentifier(namespace, key) ? { namespace, key } : null;
|
|
114
118
|
}
|
|
115
119
|
function metafieldsOption(value, invalid) {
|
|
116
120
|
if (!Array.isArray(value)) {
|
|
@@ -220,6 +224,45 @@
|
|
|
220
224
|
return LANGUAGE.test(primary) ? primary : null;
|
|
221
225
|
}
|
|
222
226
|
|
|
227
|
+
// src/shopify-values.ts
|
|
228
|
+
var MAX_CONNECTION_SIZE = 250;
|
|
229
|
+
function isHttpsUrl(url2) {
|
|
230
|
+
if (typeof url2 !== "string") return false;
|
|
231
|
+
try {
|
|
232
|
+
return new URL(url2).protocol === "https:";
|
|
233
|
+
} catch {
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
function formatMoney(money, locale) {
|
|
238
|
+
if (!money) return "";
|
|
239
|
+
const amount = parseFloat(money.amount);
|
|
240
|
+
if (Number.isNaN(amount)) return "";
|
|
241
|
+
try {
|
|
242
|
+
return new Intl.NumberFormat(locale || void 0, { style: "currency", currency: money.currencyCode }).format(
|
|
243
|
+
amount
|
|
244
|
+
);
|
|
245
|
+
} catch {
|
|
246
|
+
return `${money.currencyCode} ${amount.toFixed(2)}`;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
function productUrl(productPath, handle, id) {
|
|
250
|
+
if (!/\{(handle|id)\}/.test(productPath)) {
|
|
251
|
+
return handle ? `${productPath.replace(/\/$/, "")}/${encodeURIComponent(handle)}` : null;
|
|
252
|
+
}
|
|
253
|
+
const numericId2 = id ? id.split("/").at(-1) ?? "" : "";
|
|
254
|
+
if (productPath.includes("{handle}") && !handle) return null;
|
|
255
|
+
if (productPath.includes("{id}") && !numericId2) return null;
|
|
256
|
+
return productPath.replace(/\{handle\}/g, encodeURIComponent(handle ?? "")).replace(/\{id\}/g, encodeURIComponent(numericId2));
|
|
257
|
+
}
|
|
258
|
+
function productKey(raw) {
|
|
259
|
+
const value = String(raw ?? "").trim();
|
|
260
|
+
if (!value) return null;
|
|
261
|
+
if (value.startsWith("gid://")) return value;
|
|
262
|
+
if (/^\d+$/.test(value)) return `gid://shopify/Product/${value}`;
|
|
263
|
+
return /\/products\/([^/?#]+)/.exec(value)?.[1] ?? value;
|
|
264
|
+
}
|
|
265
|
+
|
|
223
266
|
// src/config.ts
|
|
224
267
|
var DEFAULTS = {
|
|
225
268
|
domain: "",
|
|
@@ -270,22 +313,29 @@
|
|
|
270
313
|
debug: false
|
|
271
314
|
};
|
|
272
315
|
var cfg = { ...DEFAULTS };
|
|
316
|
+
function refuseChange(key) {
|
|
317
|
+
warn(`Tether.config is read-only (${String(key)}): pass options to Tether.init() instead`);
|
|
318
|
+
return false;
|
|
319
|
+
}
|
|
320
|
+
var readOnlyViews = /* @__PURE__ */ new WeakMap();
|
|
321
|
+
var READ_ONLY = {
|
|
322
|
+
get(object, key) {
|
|
323
|
+
const value = Reflect.get(object, key);
|
|
324
|
+
return typeof value === "object" && value !== null ? readOnlyView(value) : value;
|
|
325
|
+
},
|
|
326
|
+
set: (_object, key) => refuseChange(key),
|
|
327
|
+
deleteProperty: (_object, key) => refuseChange(key),
|
|
328
|
+
defineProperty: (_object, key) => refuseChange(key)
|
|
329
|
+
};
|
|
273
330
|
function readOnlyView(target) {
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
const value = Reflect.get(object, key);
|
|
281
|
-
return typeof value === "object" && value !== null ? readOnlyView(value) : value;
|
|
282
|
-
},
|
|
283
|
-
set: (_object, key) => refuse(key),
|
|
284
|
-
deleteProperty: (_object, key) => refuse(key),
|
|
285
|
-
defineProperty: (_object, key) => refuse(key)
|
|
286
|
-
});
|
|
331
|
+
let view = readOnlyViews.get(target);
|
|
332
|
+
if (!view) {
|
|
333
|
+
view = new Proxy(target, READ_ONLY);
|
|
334
|
+
readOnlyViews.set(target, view);
|
|
335
|
+
}
|
|
336
|
+
return view;
|
|
287
337
|
}
|
|
288
|
-
var configView =
|
|
338
|
+
var configView = new Proxy(cfg, READ_ONLY);
|
|
289
339
|
var PREFIX = /^[a-z][a-z0-9-]*$/;
|
|
290
340
|
var SWITCH_OPTIONS = [
|
|
291
341
|
"revalidate",
|
|
@@ -297,7 +347,7 @@
|
|
|
297
347
|
"astro",
|
|
298
348
|
"debug"
|
|
299
349
|
];
|
|
300
|
-
var TEXT_OPTIONS = ["token", "productPath", "collectionPath"
|
|
350
|
+
var TEXT_OPTIONS = ["token", "productPath", "collectionPath"];
|
|
301
351
|
var COUNT_OPTIONS = [
|
|
302
352
|
"imagesFirst",
|
|
303
353
|
"variantsFirst",
|
|
@@ -330,7 +380,7 @@
|
|
|
330
380
|
}
|
|
331
381
|
function warnUnknownKeys(options) {
|
|
332
382
|
for (const key of Object.keys(options)) {
|
|
333
|
-
if (!(key
|
|
383
|
+
if (!Object.hasOwn(DEFAULTS, key)) warn(`unknown option ${JSON.stringify(key)}: ignored`);
|
|
334
384
|
}
|
|
335
385
|
}
|
|
336
386
|
function setHook(config, name, value) {
|
|
@@ -342,16 +392,22 @@
|
|
|
342
392
|
}
|
|
343
393
|
var MAX_TIMER_MS = 2147483647;
|
|
344
394
|
var MAX_RETRIES = 10;
|
|
345
|
-
var
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
395
|
+
var CONNECTION_RANGE = { min: 1, max: MAX_CONNECTION_SIZE };
|
|
396
|
+
var COUNT_RANGES = {
|
|
397
|
+
imagesFirst: CONNECTION_RANGE,
|
|
398
|
+
variantsFirst: CONNECTION_RANGE,
|
|
399
|
+
sellingPlanGroupsFirst: CONNECTION_RANGE,
|
|
400
|
+
sellingPlansFirst: CONNECTION_RANGE,
|
|
401
|
+
collectionFirst: CONNECTION_RANGE,
|
|
402
|
+
requestTimeout: { max: MAX_TIMER_MS },
|
|
403
|
+
searchDelay: { max: MAX_TIMER_MS },
|
|
404
|
+
retries: { max: MAX_RETRIES }
|
|
349
405
|
};
|
|
350
406
|
function countOption(name, value) {
|
|
351
|
-
|
|
407
|
+
const { min = 0, max: maximum } = COUNT_RANGES[name] ?? {};
|
|
408
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value < min) {
|
|
352
409
|
return invalidOption(name, value, DEFAULTS[name]);
|
|
353
410
|
}
|
|
354
|
-
const maximum = COUNT_MAXIMUMS[name];
|
|
355
411
|
if (maximum === void 0 || value <= maximum) return value;
|
|
356
412
|
warn(`${name} ${String(value)} is more than its maximum: using ${String(maximum)}`);
|
|
357
413
|
return maximum;
|
|
@@ -362,6 +418,10 @@
|
|
|
362
418
|
function textOption(name, value) {
|
|
363
419
|
return typeof value === "string" ? value : invalidOption(name, value, DEFAULTS[name]);
|
|
364
420
|
}
|
|
421
|
+
var CLASS_TOKEN = /^\S+$/;
|
|
422
|
+
function classOption(name, value) {
|
|
423
|
+
return typeof value === "string" && CLASS_TOKEN.test(value) ? value : invalidOption(name, value, DEFAULTS[name]);
|
|
424
|
+
}
|
|
365
425
|
function localeOption(value) {
|
|
366
426
|
if (value === void 0 || value === null || value === "") return void 0;
|
|
367
427
|
try {
|
|
@@ -408,7 +468,8 @@
|
|
|
408
468
|
metafields: metafieldsOption(options.metafields ?? [], dropped),
|
|
409
469
|
embedOrigins: embedOriginsOption(options.embedOrigins ?? [], dropped),
|
|
410
470
|
checkoutTarget: choiceOption("checkoutTarget", options.checkoutTarget, ["_self", "_blank"]),
|
|
411
|
-
defaultPurchase: choiceOption("defaultPurchase", options.defaultPurchase, ["one-time", "subscription"])
|
|
471
|
+
defaultPurchase: choiceOption("defaultPurchase", options.defaultPurchase, ["one-time", "subscription"]),
|
|
472
|
+
cartDrawerOpenClass: classOption("cartDrawerOpenClass", options.cartDrawerOpenClass)
|
|
412
473
|
};
|
|
413
474
|
for (const name of COUNT_OPTIONS) resolved[name] = countOption(name, options[name]);
|
|
414
475
|
for (const name of SWITCH_OPTIONS) resolved[name] = switchOption(name, options[name]);
|
|
@@ -881,44 +942,6 @@
|
|
|
881
942
|
return template.content;
|
|
882
943
|
}
|
|
883
944
|
|
|
884
|
-
// src/shopify-values.ts
|
|
885
|
-
function isHttpsUrl(url2) {
|
|
886
|
-
if (typeof url2 !== "string") return false;
|
|
887
|
-
try {
|
|
888
|
-
return new URL(url2).protocol === "https:";
|
|
889
|
-
} catch {
|
|
890
|
-
return false;
|
|
891
|
-
}
|
|
892
|
-
}
|
|
893
|
-
function formatMoney(money, locale) {
|
|
894
|
-
if (!money) return "";
|
|
895
|
-
const amount = parseFloat(money.amount);
|
|
896
|
-
if (Number.isNaN(amount)) return "";
|
|
897
|
-
try {
|
|
898
|
-
return new Intl.NumberFormat(locale || void 0, { style: "currency", currency: money.currencyCode }).format(
|
|
899
|
-
amount
|
|
900
|
-
);
|
|
901
|
-
} catch {
|
|
902
|
-
return `${money.currencyCode} ${amount.toFixed(2)}`;
|
|
903
|
-
}
|
|
904
|
-
}
|
|
905
|
-
function productUrl(productPath, handle, id) {
|
|
906
|
-
if (!/\{(handle|id)\}/.test(productPath)) {
|
|
907
|
-
return handle ? `${productPath.replace(/\/$/, "")}/${encodeURIComponent(handle)}` : null;
|
|
908
|
-
}
|
|
909
|
-
const numericId2 = id ? id.split("/").at(-1) ?? "" : "";
|
|
910
|
-
if (productPath.includes("{handle}") && !handle) return null;
|
|
911
|
-
if (productPath.includes("{id}") && !numericId2) return null;
|
|
912
|
-
return productPath.replace(/\{handle\}/g, encodeURIComponent(handle ?? "")).replace(/\{id\}/g, encodeURIComponent(numericId2));
|
|
913
|
-
}
|
|
914
|
-
function productKey(raw) {
|
|
915
|
-
const value = String(raw ?? "").trim();
|
|
916
|
-
if (!value) return null;
|
|
917
|
-
if (value.startsWith("gid://")) return value;
|
|
918
|
-
if (/^\d+$/.test(value)) return `gid://shopify/Product/${value}`;
|
|
919
|
-
return /\/products\/([^/?#]+)/.exec(value)?.[1] ?? value;
|
|
920
|
-
}
|
|
921
|
-
|
|
922
945
|
// src/images.ts
|
|
923
946
|
function imageUrl(url2, { width, height, crop } = {}) {
|
|
924
947
|
if (!url2) return url2;
|
|
@@ -1152,13 +1175,33 @@
|
|
|
1152
1175
|
}
|
|
1153
1176
|
el.style.display = "none";
|
|
1154
1177
|
}
|
|
1178
|
+
var CHECKABLE = 'input[type="radio"],input[type="checkbox"]';
|
|
1179
|
+
var CHECKED_ROLES = ["radio", "checkbox", "switch", "menuitemradio", "menuitemcheckbox"];
|
|
1180
|
+
var BUTTON_INPUTS = ["button", "submit", "reset"];
|
|
1181
|
+
function chosenState(el) {
|
|
1182
|
+
const role = el.getAttribute("role");
|
|
1183
|
+
if (role === "button") return "aria-pressed";
|
|
1184
|
+
if (role && CHECKED_ROLES.includes(role)) return "aria-checked";
|
|
1185
|
+
if (role === "option" || role === "tab") return "aria-selected";
|
|
1186
|
+
if (role) return null;
|
|
1187
|
+
if (isInput(el)) return BUTTON_INPUTS.includes(el.type) ? "aria-pressed" : null;
|
|
1188
|
+
return el.querySelector(CHECKABLE) ? null : "aria-pressed";
|
|
1189
|
+
}
|
|
1155
1190
|
function setSelected(el, selected) {
|
|
1156
1191
|
el.classList.toggle("is-selected", selected);
|
|
1157
|
-
|
|
1158
|
-
if (
|
|
1159
|
-
|
|
1192
|
+
const state = chosenState(el);
|
|
1193
|
+
if (state === "aria-pressed" && el.tagName !== "BUTTON" && !isInput(el)) el.setAttribute("role", "button");
|
|
1194
|
+
if (state) el.setAttribute(state, String(selected));
|
|
1195
|
+
if (isInput(el) && el.matches(CHECKABLE)) el.checked = selected;
|
|
1196
|
+
const input = el.querySelector(CHECKABLE);
|
|
1160
1197
|
if (input && isInput(input)) input.checked = selected;
|
|
1161
1198
|
}
|
|
1199
|
+
function setUnavailable(el, unavailable) {
|
|
1200
|
+
el.classList.toggle("is-unavailable", unavailable);
|
|
1201
|
+
const isControl = chosenState(el) !== null || isInput(el);
|
|
1202
|
+
const control = isControl ? el : el.querySelector(CHECKABLE);
|
|
1203
|
+
control?.setAttribute("aria-disabled", String(unavailable));
|
|
1204
|
+
}
|
|
1162
1205
|
var layoutTimer;
|
|
1163
1206
|
var pageGlobal = (name) => Reflect.get(window, name);
|
|
1164
1207
|
function refreshScrollTrigger() {
|
|
@@ -1209,6 +1252,31 @@
|
|
|
1209
1252
|
return null;
|
|
1210
1253
|
}
|
|
1211
1254
|
}
|
|
1255
|
+
var INTEGER_TEXT = /^-?\d+$/;
|
|
1256
|
+
var invalidIntegerAttributes = /* @__PURE__ */ new WeakMap();
|
|
1257
|
+
function warnInvalidAttribute(el, name, message) {
|
|
1258
|
+
const warned = invalidIntegerAttributes.get(el) ?? /* @__PURE__ */ new Set();
|
|
1259
|
+
invalidIntegerAttributes.set(el, warned);
|
|
1260
|
+
if (warned.has(name)) return;
|
|
1261
|
+
warned.add(name);
|
|
1262
|
+
warn(`${attr(name)} ${message}`, el);
|
|
1263
|
+
}
|
|
1264
|
+
function integerAttribute(el, name, { min, max, fallback }) {
|
|
1265
|
+
const raw = get(el, name)?.trim();
|
|
1266
|
+
if (!raw) return fallback;
|
|
1267
|
+
const value = INTEGER_TEXT.test(raw) ? Number(raw) : Number.NaN;
|
|
1268
|
+
if (Number.isNaN(value) || value < min) {
|
|
1269
|
+
warnInvalidAttribute(
|
|
1270
|
+
el,
|
|
1271
|
+
name,
|
|
1272
|
+
`${JSON.stringify(raw)} is not a whole number from ${String(min)}: using ${String(fallback)}`
|
|
1273
|
+
);
|
|
1274
|
+
return fallback;
|
|
1275
|
+
}
|
|
1276
|
+
if (max === void 0 || value <= max) return value;
|
|
1277
|
+
warnInvalidAttribute(el, name, `${raw} is more than its maximum: using ${String(max)}`);
|
|
1278
|
+
return max;
|
|
1279
|
+
}
|
|
1212
1280
|
function attributeText(value) {
|
|
1213
1281
|
if (value === null || value === void 0) return "";
|
|
1214
1282
|
if (typeof value === "string") return value;
|
|
@@ -1434,28 +1502,43 @@
|
|
|
1434
1502
|
var FOCUSABLE = 'a[href],button:not([disabled]),input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"])';
|
|
1435
1503
|
var FOCUS_AFTER_OPEN_MS = 60;
|
|
1436
1504
|
var openWithoutDrawer = false;
|
|
1505
|
+
var announcedOpen = false;
|
|
1437
1506
|
var returnFocus = null;
|
|
1507
|
+
var classWatcher = null;
|
|
1438
1508
|
var isFocusable = (el) => el !== null && "focus" in el;
|
|
1439
1509
|
var focusables = (drawer) => qsa(drawer, FOCUSABLE).filter((el) => el.offsetParent !== null || el === document.activeElement);
|
|
1440
1510
|
var drawers = () => qsa(document, sel("cart-drawer"));
|
|
1441
1511
|
var isOpenDrawer = (drawer) => drawer.classList.contains(cfg.cartDrawerOpenClass);
|
|
1512
|
+
var hasFocusInside = (all) => all.some((drawer) => drawer.contains(document.activeElement));
|
|
1513
|
+
var isManual = (drawer) => get(drawer, "cart-drawer") === "manual";
|
|
1442
1514
|
function isOpen() {
|
|
1443
1515
|
const all = drawers();
|
|
1444
1516
|
return all.length ? all.some(isOpenDrawer) : openWithoutDrawer;
|
|
1445
1517
|
}
|
|
1446
|
-
function
|
|
1518
|
+
function watchOpenClass(drawer) {
|
|
1519
|
+
classWatcher ?? (classWatcher = new MutationObserver(() => {
|
|
1520
|
+
const open = isOpen();
|
|
1521
|
+
if (open === announcedOpen) return;
|
|
1522
|
+
const all = drawers();
|
|
1523
|
+
if (open) announceOpen(all.filter(isOpenDrawer));
|
|
1524
|
+
else announceClosed(all, hasFocusInside(all));
|
|
1525
|
+
}));
|
|
1526
|
+
classWatcher.observe(drawer, { attributes: true, attributeFilter: ["class"] });
|
|
1527
|
+
}
|
|
1528
|
+
function syncDrawerAria() {
|
|
1447
1529
|
qsa(document, sel("cart-open")).forEach((button) => {
|
|
1448
|
-
button.setAttribute("aria-expanded", String(
|
|
1530
|
+
button.setAttribute("aria-expanded", String(isOpen()));
|
|
1449
1531
|
});
|
|
1450
1532
|
drawers().forEach((drawer) => {
|
|
1451
1533
|
if (!drawer.hasAttribute("role")) drawer.setAttribute("role", "dialog");
|
|
1452
1534
|
if (!drawer.hasAttribute("aria-label") && !drawer.hasAttribute("aria-labelledby")) {
|
|
1453
1535
|
drawer.setAttribute("aria-label", get(drawer, "cart-label") || "Cart");
|
|
1454
1536
|
}
|
|
1537
|
+
const open = isOpenDrawer(drawer);
|
|
1455
1538
|
drawer.setAttribute("aria-modal", String(open));
|
|
1456
|
-
|
|
1457
|
-
drawer.
|
|
1458
|
-
|
|
1539
|
+
drawer.setAttribute("aria-hidden", String(!open));
|
|
1540
|
+
drawer.inert = !open;
|
|
1541
|
+
watchOpenClass(drawer);
|
|
1459
1542
|
});
|
|
1460
1543
|
}
|
|
1461
1544
|
function focusInto(drawer) {
|
|
@@ -1463,16 +1546,9 @@
|
|
|
1463
1546
|
if (target === drawer && !drawer.hasAttribute("tabindex")) drawer.tabIndex = -1;
|
|
1464
1547
|
target.focus({ preventScroll: true });
|
|
1465
1548
|
}
|
|
1466
|
-
function
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
const opened = drawers().filter((drawer) => get(drawer, "cart-drawer") !== "manual");
|
|
1470
|
-
opened.forEach((drawer) => {
|
|
1471
|
-
drawer.inert = false;
|
|
1472
|
-
drawer.classList.add(cfg.cartDrawerOpenClass);
|
|
1473
|
-
drawer.setAttribute("aria-hidden", "false");
|
|
1474
|
-
});
|
|
1475
|
-
syncDrawerAria(true);
|
|
1549
|
+
function announceOpen(opened) {
|
|
1550
|
+
announcedOpen = true;
|
|
1551
|
+
syncDrawerAria();
|
|
1476
1552
|
const [first] = opened;
|
|
1477
1553
|
if (cfg.cartFocus && first) {
|
|
1478
1554
|
returnFocus = isFocusable(document.activeElement) ? document.activeElement : null;
|
|
@@ -1483,21 +1559,34 @@
|
|
|
1483
1559
|
cfg.onCartOpen?.(opened);
|
|
1484
1560
|
emit("cart-toggled", { open: true });
|
|
1485
1561
|
}
|
|
1562
|
+
function announceClosed(all, hadFocus) {
|
|
1563
|
+
announcedOpen = false;
|
|
1564
|
+
syncDrawerAria();
|
|
1565
|
+
if (hadFocus && returnFocus?.isConnected) returnFocus.focus({ preventScroll: true });
|
|
1566
|
+
returnFocus = null;
|
|
1567
|
+
cfg.onCartClose?.(all);
|
|
1568
|
+
emit("cart-toggled", { open: false });
|
|
1569
|
+
}
|
|
1570
|
+
function openCart() {
|
|
1571
|
+
if (isOpen()) return;
|
|
1572
|
+
const all = drawers();
|
|
1573
|
+
const opened = all.filter((drawer) => !isManual(drawer));
|
|
1574
|
+
if (all.length && !opened.length) return;
|
|
1575
|
+
openWithoutDrawer = true;
|
|
1576
|
+
opened.forEach((drawer) => {
|
|
1577
|
+
drawer.classList.add(cfg.cartDrawerOpenClass);
|
|
1578
|
+
});
|
|
1579
|
+
announceOpen(opened);
|
|
1580
|
+
}
|
|
1486
1581
|
function closeCart() {
|
|
1487
1582
|
if (!isOpen()) return;
|
|
1488
1583
|
openWithoutDrawer = false;
|
|
1489
1584
|
const all = drawers();
|
|
1490
|
-
const hadFocus = all
|
|
1585
|
+
const hadFocus = hasFocusInside(all);
|
|
1491
1586
|
all.forEach((drawer) => {
|
|
1492
1587
|
drawer.classList.remove(cfg.cartDrawerOpenClass);
|
|
1493
|
-
drawer.setAttribute("aria-hidden", "true");
|
|
1494
|
-
if (cfg.cartFocus) drawer.inert = true;
|
|
1495
1588
|
});
|
|
1496
|
-
|
|
1497
|
-
if (hadFocus && returnFocus?.isConnected) returnFocus.focus({ preventScroll: true });
|
|
1498
|
-
returnFocus = null;
|
|
1499
|
-
cfg.onCartClose?.(all);
|
|
1500
|
-
emit("cart-toggled", { open: false });
|
|
1589
|
+
announceClosed(all, hadFocus);
|
|
1501
1590
|
}
|
|
1502
1591
|
function toggleCart() {
|
|
1503
1592
|
if (isOpen()) closeCart();
|
|
@@ -1969,7 +2058,7 @@
|
|
|
1969
2058
|
function renderCart(view) {
|
|
1970
2059
|
const { cart } = view;
|
|
1971
2060
|
const money = (key) => cart ? formatMoney2(cart.cost[key]) : "";
|
|
1972
|
-
syncDrawerAria(
|
|
2061
|
+
syncDrawerAria();
|
|
1973
2062
|
qsa(document, sel("cart-count")).forEach((el) => {
|
|
1974
2063
|
setTextTracked(el, cart?.totalQuantity ?? 0);
|
|
1975
2064
|
});
|
|
@@ -2282,14 +2371,23 @@
|
|
|
2282
2371
|
} catch {
|
|
2283
2372
|
}
|
|
2284
2373
|
}
|
|
2285
|
-
|
|
2286
|
-
const cartId = savedCartId();
|
|
2374
|
+
function cartToCheckOut() {
|
|
2287
2375
|
const cart = currentCart();
|
|
2288
|
-
|
|
2376
|
+
return cart && !cart.totalQuantity ? null : savedCartId();
|
|
2377
|
+
}
|
|
2378
|
+
async function checkout(target = cfg.checkoutTarget) {
|
|
2379
|
+
if (!cartToCheckOut()) return null;
|
|
2289
2380
|
const tab = target === "_blank" ? window.open("", "_blank") : null;
|
|
2290
2381
|
if (tab) detachOpenerIfAllowed(tab);
|
|
2291
2382
|
try {
|
|
2292
|
-
const url2 = await
|
|
2383
|
+
const url2 = await runInOrder(async () => {
|
|
2384
|
+
const cartId = cartToCheckOut();
|
|
2385
|
+
return cartId && checkoutUrl(cartId);
|
|
2386
|
+
});
|
|
2387
|
+
if (!url2) {
|
|
2388
|
+
tab?.close();
|
|
2389
|
+
return null;
|
|
2390
|
+
}
|
|
2293
2391
|
if (!isHttpsUrl(url2)) throw new TetherError("The checkout URL is not https: not opened");
|
|
2294
2392
|
emit("checkout", { url: url2, cart: currentCart() });
|
|
2295
2393
|
if (tab && !tab.closed) tab.location.href = url2;
|
|
@@ -2532,7 +2630,8 @@
|
|
|
2532
2630
|
*
|
|
2533
2631
|
* @throws {TetherError} `INVALID_DISCOUNT` (rejected) when Shopify doesn't accept the code.
|
|
2534
2632
|
*/
|
|
2535
|
-
async applyDiscount(
|
|
2633
|
+
async applyDiscount(typed) {
|
|
2634
|
+
const code = typed.trim();
|
|
2536
2635
|
const cart = await Cart.setDiscountCodes((current) => [.../* @__PURE__ */ new Set([...current, code])]);
|
|
2537
2636
|
const wanted = code.toLowerCase();
|
|
2538
2637
|
const applied = (cart?.discountCodes ?? []).find((discount) => discount.code.toLowerCase() === wanted);
|
|
@@ -2545,7 +2644,7 @@
|
|
|
2545
2644
|
throw new TetherError(`Discount code not valid: ${code}`, { code: "INVALID_DISCOUNT" });
|
|
2546
2645
|
},
|
|
2547
2646
|
removeDiscount(code) {
|
|
2548
|
-
const unwanted = code.toLowerCase();
|
|
2647
|
+
const unwanted = code.trim().toLowerCase();
|
|
2549
2648
|
return Cart.setDiscountCodes((current) => current.filter((existing) => existing.toLowerCase() !== unwanted));
|
|
2550
2649
|
},
|
|
2551
2650
|
/**
|
|
@@ -2803,7 +2902,7 @@
|
|
|
2803
2902
|
const value = get(node, "option-value") ?? "";
|
|
2804
2903
|
setSelected(node, view.selected[name] === value);
|
|
2805
2904
|
const unavailable = !isValueAvailable(product, view.selected, name, value);
|
|
2806
|
-
node
|
|
2905
|
+
setUnavailable(node, unavailable);
|
|
2807
2906
|
node.setAttribute("data-unavailable", unavailable ? "true" : "false");
|
|
2808
2907
|
});
|
|
2809
2908
|
});
|
|
@@ -2823,13 +2922,12 @@
|
|
|
2823
2922
|
}
|
|
2824
2923
|
const mode = get(el, "purchase");
|
|
2825
2924
|
setSelected(el, mode === purchase.kind);
|
|
2826
|
-
|
|
2827
|
-
el.classList.toggle("is-unavailable", unavailable);
|
|
2925
|
+
setUnavailable(el, mode === "subscription" ? !view.subscriptionAvailable : scope.product.requiresSellingPlan);
|
|
2828
2926
|
});
|
|
2829
2927
|
scope.$(sel("plan-value")).forEach((node) => {
|
|
2830
2928
|
const planId = get(node, "plan-value") ?? "";
|
|
2831
2929
|
setSelected(node, line.kind === "subscription" && planId === line.planId);
|
|
2832
|
-
node
|
|
2930
|
+
setUnavailable(node, !allocationFor(variant, planId));
|
|
2833
2931
|
const plan = scope.plans.find((candidate) => candidate.id === planId);
|
|
2834
2932
|
const texts = planBindTexts(variant, planId, plan, FORMAT);
|
|
2835
2933
|
qsa(node, sel("plan-bind")).forEach((el) => {
|
|
@@ -3223,7 +3321,12 @@
|
|
|
3223
3321
|
function applyPageTitle(el, product) {
|
|
3224
3322
|
const template = get(el, "page-title");
|
|
3225
3323
|
if (!template || typeof document === "undefined") return;
|
|
3226
|
-
|
|
3324
|
+
const fields = /* @__PURE__ */ new Map([
|
|
3325
|
+
["title", product.title],
|
|
3326
|
+
["vendor", product.vendor || ""],
|
|
3327
|
+
["type", product.productType || ""]
|
|
3328
|
+
]);
|
|
3329
|
+
document.title = template.replace(/\{(\w+)\}/g, (placeholder, name) => fields.get(name) ?? placeholder);
|
|
3227
3330
|
}
|
|
3228
3331
|
function mountWithoutKey(el, { fromUrl, raw }) {
|
|
3229
3332
|
if (fromUrl) {
|
|
@@ -3440,7 +3543,7 @@
|
|
|
3440
3543
|
}
|
|
3441
3544
|
|
|
3442
3545
|
// src/part-integrity.ts
|
|
3443
|
-
var PART_INTEGRITY = { "tether.diagnose.js": "sha384-
|
|
3546
|
+
var PART_INTEGRITY = { "tether.diagnose.js": "sha384-CqtXzvWbLD8aIgyTM43+KMXEFA7r7lhG+0XyQAw3Sp7B5qrzPsxlA9QfzBjoPqZz", "tether.markets.js": "sha384-WjowbRhM7OzzZOrCPZWSZqN7EjIiiR7u9cGmdI+9kgFVgmEQS8lVGWjgx+8jILOf", "tether.search.js": "sha384-fLQ7eKc5XOv0Cg2FfrZyeFAkRR4wDMjUWFpwvKrfPRnT2NvTuhKg80+KVu8Qce/G", "tether.lists.js": "sha384-l2uyr96zTetjo2WWhGsBamd1ZYkC3OB3G3+OScLEvxdok0c8k9GXLAh1WRALUr4S", "tether.extras.js": "sha384-/SMjz6qCFAOV0wwvEVNhQxtT/1pyx4hRxDJHOxHB6M3uclAvItSULKZqJvaehH+i", "tether.account.js": "sha384-XUPSX/7R9chq2KlQ1RzLiV7jYcWGe7o5tj4rLZMnf8MEa2aDOOCW2269Bj/ZkbmX", "tether.account-pages.js": "sha384-ND3kIaRypgnHG3QMDb8CqDxt7fuukDCdHsIAHoOUUsz3+FjvBqXgRDV4Mjp6x8jr", "tether.analytics.js": "sha384-jnLesn/+edWBSPuXLj7VX1kSAGwEqtb0VbHjuU//ofqgxkndHlDFsS8Bc8htlGt8" };
|
|
3444
3547
|
|
|
3445
3548
|
// src/part-registry.ts
|
|
3446
3549
|
function isTetherInternals(value) {
|
|
@@ -3448,7 +3551,7 @@
|
|
|
3448
3551
|
}
|
|
3449
3552
|
|
|
3450
3553
|
// src/version.ts
|
|
3451
|
-
var VERSION = "0.9.
|
|
3554
|
+
var VERSION = "0.9.4";
|
|
3452
3555
|
|
|
3453
3556
|
// src/lazy-iife.ts
|
|
3454
3557
|
var coreModules = {
|
|
@@ -3456,7 +3559,7 @@
|
|
|
3456
3559
|
return [cfg, isConfigured, log, MARKET_SOURCES, parseMarkets, reportError, warn];
|
|
3457
3560
|
},
|
|
3458
3561
|
get "client.ts"() {
|
|
3459
|
-
return [endpoint, gql, matches, orNull, shaped, TetherError];
|
|
3562
|
+
return [endpoint, gql, matches, orNull, shaped, TetherError, withTimeout];
|
|
3460
3563
|
},
|
|
3461
3564
|
get "dom.ts"() {
|
|
3462
3565
|
return [
|
|
@@ -3470,6 +3573,7 @@
|
|
|
3470
3573
|
get,
|
|
3471
3574
|
has,
|
|
3472
3575
|
hasTemplate,
|
|
3576
|
+
integerAttribute,
|
|
3473
3577
|
isOwnEvent,
|
|
3474
3578
|
notifyLayoutChanged,
|
|
3475
3579
|
parseJSONAttr,
|
|
@@ -3515,7 +3619,7 @@
|
|
|
3515
3619
|
return [setCountry];
|
|
3516
3620
|
},
|
|
3517
3621
|
get "shopify-values.ts"() {
|
|
3518
|
-
return [isHttpsUrl];
|
|
3622
|
+
return [isHttpsUrl, MAX_CONNECTION_SIZE];
|
|
3519
3623
|
},
|
|
3520
3624
|
// Parts that load other parts (account → account-pages) use this same loader.
|
|
3521
3625
|
get "lazy.ts"() {
|
|
@@ -3605,6 +3709,23 @@
|
|
|
3605
3709
|
};
|
|
3606
3710
|
}
|
|
3607
3711
|
|
|
3712
|
+
// src/analytics-queue.ts
|
|
3713
|
+
function queueAnalyticsEvents(load) {
|
|
3714
|
+
const queue = [];
|
|
3715
|
+
const listening = new window.AbortController();
|
|
3716
|
+
const options = { signal: listening.signal };
|
|
3717
|
+
ANALYTICS_EVENTS.forEach((name) => {
|
|
3718
|
+
document.addEventListener(`${cfg.prefix}:${name}`, (event) => queue.push(event), options);
|
|
3719
|
+
});
|
|
3720
|
+
document.addEventListener("astro:page-load", (event) => queue.push(event), options);
|
|
3721
|
+
load().then((part) => part.startAnalytics(queue)).catch((error) => {
|
|
3722
|
+
listening.abort();
|
|
3723
|
+
queue.length = 0;
|
|
3724
|
+
reportError(error, "analytics");
|
|
3725
|
+
});
|
|
3726
|
+
return queue;
|
|
3727
|
+
}
|
|
3728
|
+
|
|
3608
3729
|
// src/account-marks.ts
|
|
3609
3730
|
var hintKey = () => `${cfg.prefix}:account-hint:${cfg.domain}`;
|
|
3610
3731
|
function removeFromBothAreas(key) {
|
|
@@ -3735,12 +3856,21 @@
|
|
|
3735
3856
|
line.setAttribute("aria-busy", "true");
|
|
3736
3857
|
reportFailure(change, context);
|
|
3737
3858
|
}
|
|
3859
|
+
function onQuantityInput(input, { line, id }) {
|
|
3860
|
+
const typed = input.value.trim();
|
|
3861
|
+
if (INTEGER_TEXT.test(typed)) {
|
|
3862
|
+
showLineBusy(line, Cart.updateLine(id, Number(typed)), "cart line");
|
|
3863
|
+
return;
|
|
3864
|
+
}
|
|
3865
|
+
const current = Cart.lines.find((candidate) => candidate.id === id);
|
|
3866
|
+
if (current) input.value = String(Cart.quantityOf(current));
|
|
3867
|
+
}
|
|
3738
3868
|
function onChange2(event) {
|
|
3739
3869
|
const { target } = event;
|
|
3740
3870
|
if (!isElement2(target)) return;
|
|
3741
3871
|
const found = lineOf(target);
|
|
3742
3872
|
if (found && target instanceof window.HTMLInputElement && target.matches(sel("line", "quantity"))) {
|
|
3743
|
-
|
|
3873
|
+
onQuantityInput(target, found);
|
|
3744
3874
|
} else if (found && target instanceof window.HTMLSelectElement && target.matches(sel("line-plan"))) {
|
|
3745
3875
|
showLineBusy(found.line, Cart.updateLine(found.id, { sellingPlanId: target.value || null }), "cart line plan");
|
|
3746
3876
|
} else if (hasValue(target) && target.matches(sel("cart-note"))) {
|
|
@@ -3991,17 +4121,6 @@
|
|
|
3991
4121
|
bindExtrasControls();
|
|
3992
4122
|
bindNavigation({ ready: () => initPromise ?? Promise.resolve(null), mount, unmount });
|
|
3993
4123
|
}
|
|
3994
|
-
function startAnalyticsQueue() {
|
|
3995
|
-
const queue = [];
|
|
3996
|
-
analyticsQueue = queue;
|
|
3997
|
-
ANALYTICS_EVENTS.forEach((name) => {
|
|
3998
|
-
document.addEventListener(`${cfg.prefix}:${name}`, (event) => queue.push(event));
|
|
3999
|
-
});
|
|
4000
|
-
document.addEventListener("astro:page-load", (event) => queue.push(event));
|
|
4001
|
-
loadPart("analytics").then((part) => part.startAnalytics(queue)).catch((error) => {
|
|
4002
|
-
reportError(error, "analytics");
|
|
4003
|
-
});
|
|
4004
|
-
}
|
|
4005
4124
|
async function cartInPageMarket(cart) {
|
|
4006
4125
|
const country = cfg.country;
|
|
4007
4126
|
const cartCountry = cart?.buyerIdentity.countryCode;
|
|
@@ -4024,7 +4143,7 @@
|
|
|
4024
4143
|
forgetBrowserModeTokens();
|
|
4025
4144
|
bindControls();
|
|
4026
4145
|
if (cfg.observe) startObserver();
|
|
4027
|
-
if (cfg.analytics
|
|
4146
|
+
if (cfg.analytics) analyticsQueue ?? (analyticsQueue = queueAnalyticsEvents(() => loadPart("analytics")));
|
|
4028
4147
|
initPromise = applyStartMarket(overrides).then(() => Cart.init()).then(cartInPageMarket).then((cart) => {
|
|
4029
4148
|
emit("ready", { cart });
|
|
4030
4149
|
return api;
|