@occluze/tether 0.6.8 → 0.7.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 +11 -11
- package/dist/esm/astro.js +2 -2
- package/dist/esm/chunks/account-UIPWJQ3Y.js +1 -0
- package/dist/esm/chunks/account-pages-6ROA6Y4V.js +1 -0
- package/dist/esm/chunks/analytics-2V632IRV.js +1 -0
- package/dist/esm/chunks/chunk-4GCXM764.js +1 -0
- package/dist/esm/chunks/chunk-56FCLJJD.js +1 -0
- package/dist/esm/chunks/chunk-5Z5O3767.js +1 -0
- package/dist/esm/chunks/chunk-6OZJCAGZ.js +1 -0
- package/dist/esm/chunks/chunk-A5SYCVQM.js +1 -0
- package/dist/esm/chunks/chunk-BA4LQJJQ.js +1 -0
- package/dist/esm/chunks/chunk-BFTZR4OB.js +4 -0
- package/dist/esm/chunks/chunk-C5JYQCWH.js +1 -0
- package/dist/esm/chunks/chunk-E5YO6274.js +1 -0
- package/dist/esm/chunks/chunk-MPDWM2NN.js +1 -0
- package/dist/esm/chunks/chunk-T44MUL4Y.js +1 -0
- package/dist/esm/chunks/chunk-YLUULATY.js +1 -0
- package/dist/esm/chunks/diagnose-3FEKRIEK.js +14 -0
- package/dist/esm/chunks/extras-6POFBNOP.js +1 -0
- package/dist/esm/chunks/markets-ui-FD6NI2OG.js +1 -0
- package/dist/esm/chunks/search-UJ73YBQ5.js +1 -0
- package/dist/esm/index.js +1 -1
- package/dist/esm/server.js +2 -2
- package/dist/presets/barba.esm.js +19 -23
- package/dist/tether.account-pages.js +320 -365
- package/dist/tether.account-pages.min.js +1 -1
- package/dist/tether.account.js +242 -491
- package/dist/tether.account.min.js +1 -1
- package/dist/tether.analytics.js +66 -88
- package/dist/tether.analytics.min.js +1 -1
- package/dist/tether.diagnose.js +36 -33
- package/dist/tether.diagnose.min.js +2 -2
- package/dist/tether.extras.js +28 -36
- package/dist/tether.extras.min.js +1 -1
- package/dist/tether.js +1270 -894
- package/dist/tether.markets.js +73 -90
- package/dist/tether.markets.min.js +1 -1
- package/dist/tether.min.js +0 -0
- package/dist/tether.min.js.map +4 -4
- package/dist/tether.search.js +44 -68
- package/dist/tether.search.min.js +1 -1
- package/dist/types/server/src/shared/account-orders.d.ts +44 -0
- package/dist/types/server/src/shared/account-routes.d.ts +153 -0
- package/dist/types/server/src/shared/api-versions.d.ts +13 -0
- package/dist/types/server/src/shared/error-message.d.ts +2 -0
- package/dist/types/server/src/shared/json.d.ts +25 -0
- package/dist/types/server/src/shared/market-codes.d.ts +16 -0
- package/dist/types/src/account/addresses-view.d.ts +5 -0
- package/dist/types/src/account/answers.d.ts +40 -0
- package/dist/types/src/account/markup.d.ts +19 -0
- package/dist/types/src/account/operations.d.ts +41 -0
- package/dist/types/src/account/order-lines.d.ts +13 -0
- package/dist/types/src/account/order-list.d.ts +12 -0
- package/dist/types/src/account/order-page.d.ts +6 -0
- package/dist/types/src/account/page-answers.d.ts +182 -0
- package/dist/types/src/account/page-events.d.ts +2 -0
- package/dist/types/src/account/server-client.d.ts +60 -0
- package/dist/types/src/account/subscriptions-view.d.ts +2 -0
- package/dist/types/src/account-api.d.ts +18 -0
- package/dist/types/src/account-marks.d.ts +15 -0
- package/dist/types/src/account-pages.d.ts +8 -0
- package/dist/types/src/account.d.ts +64 -0
- package/dist/types/src/amounts.d.ts +12 -0
- package/dist/types/src/analytics-shopify.d.ts +41 -0
- package/dist/types/src/analytics.d.ts +2 -0
- package/dist/types/src/api-version.d.ts +28 -0
- package/dist/types/src/astro.d.ts +42 -0
- package/dist/types/src/cart/cart-shape.d.ts +43 -0
- package/dist/types/src/cart/checkout.d.ts +16 -0
- package/dist/types/src/cart/drawer.d.ts +18 -0
- package/dist/types/src/cart/mutations.d.ts +79 -0
- package/dist/types/src/cart/render.d.ts +17 -0
- package/dist/types/src/cart/store.d.ts +182 -0
- package/dist/types/src/cart.d.ts +106 -0
- package/dist/types/src/client.d.ts +100 -0
- package/dist/types/src/collection.d.ts +25 -0
- package/dist/types/src/config-sections.d.ts +40 -0
- package/dist/types/src/config.d.ts +185 -0
- package/dist/types/src/controls/cart-controls.d.ts +2 -0
- package/dist/types/src/controls/discount.d.ts +2 -0
- package/dist/types/src/controls/extras.d.ts +5 -0
- package/dist/types/src/controls/navigation.d.ts +12 -0
- package/dist/types/src/diagnose-markup.d.ts +19 -0
- package/dist/types/src/diagnose.d.ts +60 -0
- package/dist/types/src/dom.d.ts +75 -0
- package/dist/types/src/extras.d.ts +21 -0
- package/dist/types/src/fragments.d.ts +158 -0
- package/dist/types/src/globals.d.ts +15 -0
- package/dist/types/src/images.d.ts +20 -0
- package/dist/types/src/index.d.ts +167 -0
- package/dist/types/src/initial.d.ts +56 -0
- package/dist/types/src/lazy.d.ts +28 -0
- package/dist/types/src/loader.d.ts +84 -0
- package/dist/types/src/market-codes.d.ts +6 -0
- package/dist/types/src/markets-ui.d.ts +32 -0
- package/dist/types/src/markets.d.ts +72 -0
- package/dist/types/src/markup.d.ts +131 -0
- package/dist/types/src/mounting.d.ts +46 -0
- package/dist/types/src/page-market.d.ts +27 -0
- package/dist/types/src/presets/barba.d.ts +56 -0
- package/dist/types/src/product-events.d.ts +2 -0
- package/dist/types/src/product-render.d.ts +17 -0
- package/dist/types/src/product-shape.d.ts +88 -0
- package/dist/types/src/product-state.d.ts +110 -0
- package/dist/types/src/product.d.ts +66 -0
- package/dist/types/src/repeaters.d.ts +16 -0
- package/dist/types/src/search.d.ts +33 -0
- package/dist/types/src/selling-plans.d.ts +64 -0
- package/dist/types/src/server.d.ts +88 -0
- package/dist/types/src/shopify-values.d.ts +46 -0
- package/dist/types/src/status.d.ts +33 -0
- package/dist/types/src/storage.d.ts +12 -0
- package/dist/types/src/store-html.d.ts +39 -0
- package/dist/types/src/storefront/catalog.d.ts +38 -0
- package/dist/types/src/storefront/json-ld.d.ts +20 -0
- package/dist/types/src/variant-render.d.ts +14 -0
- package/package.json +24 -23
- package/src/account/addresses-view.ts +58 -0
- package/src/account/answers.ts +79 -0
- package/src/account/markup.ts +36 -0
- package/src/account/operations.ts +145 -0
- package/src/account/{order-lines.js → order-lines.ts} +20 -41
- package/src/account/order-list.ts +107 -0
- package/src/account/order-page.ts +137 -0
- package/src/account/page-answers.ts +317 -0
- package/src/account/{page-events.js → page-events.ts} +55 -90
- package/src/account/server-client.ts +183 -0
- package/src/account/{subscriptions-view.js → subscriptions-view.ts} +25 -68
- package/src/account-api.ts +98 -0
- package/src/account-marks.ts +35 -0
- package/src/{account-pages.js → account-pages.ts} +29 -37
- package/src/account.ts +284 -0
- package/src/amounts.ts +64 -0
- package/src/{analytics-shopify.js → analytics-shopify.ts} +112 -107
- package/src/analytics.ts +315 -0
- package/src/{api-version.js → api-version.ts} +25 -31
- package/src/{astro.js → astro.ts} +110 -104
- package/src/cart/cart-shape.ts +25 -0
- package/src/cart/checkout.ts +101 -0
- package/src/cart/{drawer.js → drawer.ts} +18 -31
- package/src/cart/mutations.ts +237 -0
- package/src/cart/{render.js → render.ts} +68 -96
- package/src/cart/store.ts +279 -0
- package/src/{cart.js → cart.ts} +82 -128
- package/src/client.ts +391 -0
- package/src/{collection.js → collection.ts} +30 -38
- package/src/config-sections.ts +284 -0
- package/src/config.ts +480 -0
- package/src/controls/{cart-controls.js → cart-controls.ts} +22 -54
- package/src/controls/{discount.js → discount.ts} +13 -34
- package/src/controls/{extras.js → extras.ts} +15 -24
- package/src/controls/{navigation.js → navigation.ts} +24 -30
- package/src/{diagnose-markup.js → diagnose-markup.ts} +37 -72
- package/src/{diagnose.js → diagnose.ts} +95 -96
- package/src/dom.ts +268 -0
- package/src/{extras.js → extras.ts} +43 -52
- package/src/fragments.ts +261 -0
- package/src/globals.d.ts +15 -0
- package/src/{images.js → images.ts} +30 -43
- package/src/index.ts +415 -0
- package/src/initial.ts +101 -0
- package/src/lazy-iife.ts +197 -0
- package/src/lazy.ts +42 -0
- package/src/{loader.js → loader.ts} +149 -123
- package/src/market-codes.ts +6 -0
- package/src/{markets-ui.js → markets-ui.ts} +91 -68
- package/src/markets.ts +246 -0
- package/src/markup.ts +127 -0
- package/src/{mounting.js → mounting.ts} +88 -101
- package/src/{page-market.js → page-market.ts} +32 -38
- package/src/part-integrity.ts +7 -0
- package/src/parts/account-pages.ts +7 -0
- package/src/parts/account.ts +7 -0
- package/src/parts/analytics.ts +7 -0
- package/src/parts/diagnose.ts +7 -0
- package/src/parts/extras.ts +7 -0
- package/src/parts/markets.ts +7 -0
- package/src/parts/search.ts +7 -0
- package/src/presets/barba.ts +194 -0
- package/src/{product-events.js → product-events.ts} +33 -48
- package/src/{product-render.js → product-render.ts} +38 -77
- package/src/product-shape.ts +49 -0
- package/src/product-state.ts +318 -0
- package/src/{product.js → product.ts} +90 -126
- package/src/{repeaters.js → repeaters.ts} +40 -52
- package/src/{search.js → search.ts} +85 -103
- package/src/selling-plans.ts +145 -0
- package/src/server.ts +211 -0
- package/src/{shopify-values.js → shopify-values.ts} +24 -22
- package/src/{status.js → status.ts} +34 -54
- package/src/storage.ts +34 -0
- package/src/store-html.ts +359 -0
- package/src/storefront/catalog.ts +196 -0
- package/src/storefront/{json-ld.js → json-ld.ts} +45 -68
- package/src/{variant-render.js → variant-render.ts} +24 -50
- package/dist/esm/chunks/account-C3NP6HFB.js +0 -1
- package/dist/esm/chunks/account-pages-WLK374FO.js +0 -1
- package/dist/esm/chunks/analytics-G3SAWMNL.js +0 -1
- package/dist/esm/chunks/chunk-27PJJZGC.js +0 -1
- package/dist/esm/chunks/chunk-2FSXS55U.js +0 -1
- package/dist/esm/chunks/chunk-FCSWQDVV.js +0 -1
- package/dist/esm/chunks/chunk-FOMSMIAM.js +0 -1
- package/dist/esm/chunks/chunk-GZJTCLLW.js +0 -1
- package/dist/esm/chunks/chunk-HEQILZVR.js +0 -1
- package/dist/esm/chunks/chunk-JOOEXYF3.js +0 -4
- package/dist/esm/chunks/chunk-MPTQYLSM.js +0 -1
- package/dist/esm/chunks/chunk-NEHZ37TU.js +0 -3
- package/dist/esm/chunks/chunk-V74KGEJF.js +0 -1
- package/dist/esm/chunks/chunk-VT4CDUJJ.js +0 -1
- package/dist/esm/chunks/chunk-YJLWX2HK.js +0 -1
- package/dist/esm/chunks/diagnose-6VVGZNTY.js +0 -14
- package/dist/esm/chunks/extras-GJVRDFM3.js +0 -1
- package/dist/esm/chunks/markets-ui-UNB4PTA7.js +0 -1
- package/dist/esm/chunks/search-OU75RNQL.js +0 -1
- package/src/account/addresses-view.js +0 -92
- package/src/account/browser-session.js +0 -359
- package/src/account/markup.js +0 -48
- package/src/account/operations.js +0 -180
- package/src/account/order-list.js +0 -91
- package/src/account/order-page.js +0 -192
- package/src/account/server-client.js +0 -172
- package/src/account/shared.js +0 -111
- package/src/account/shopify-auth.js +0 -150
- package/src/account-api.js +0 -118
- package/src/account-links.js +0 -35
- package/src/account.js +0 -342
- package/src/amounts.js +0 -36
- package/src/analytics.js +0 -352
- package/src/cart/checkout.js +0 -97
- package/src/cart/mutations.js +0 -234
- package/src/cart/store.js +0 -326
- package/src/client.js +0 -267
- package/src/config.js +0 -349
- package/src/dom.js +0 -287
- package/src/fragments.js +0 -237
- package/src/index.js +0 -353
- package/src/initial.js +0 -87
- package/src/lazy-iife.js +0 -116
- package/src/lazy.js +0 -39
- package/src/market-codes.js +0 -35
- package/src/markets.js +0 -334
- package/src/markup.js +0 -64
- package/src/parts/account-pages.js +0 -6
- package/src/parts/account.js +0 -6
- package/src/parts/analytics.js +0 -6
- package/src/parts/diagnose.js +0 -6
- package/src/parts/extras.js +0 -6
- package/src/parts/markets.js +0 -6
- package/src/parts/search.js +0 -6
- package/src/presets/barba.js +0 -190
- package/src/product-state.js +0 -318
- package/src/selling-plans.js +0 -154
- package/src/server.js +0 -215
- package/src/store-html.js +0 -0
- package/src/storefront/catalog.js +0 -199
- package/types/astro.d.ts +0 -28
- package/types/barba.d.ts +0 -16
- package/types/index.d.ts +0 -577
- package/types/server.d.ts +0 -182
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { productKey } from './shopify-values.js';
|
|
2
|
+
import type { Product, Image } from './fragments.js';
|
|
3
|
+
import type { ProductConnection } from './product-shape.js';
|
|
4
|
+
/** Accepts a handle, numeric id, gid or a full product URL. */
|
|
5
|
+
export declare const normalizeProductKey: typeof productKey;
|
|
6
|
+
/** Puts a product the page already has (from a collection query) in the cache, under its handle and its id. */
|
|
7
|
+
export declare function primeProduct(product: Product | null | undefined): void;
|
|
8
|
+
/**
|
|
9
|
+
* @param rawKey A handle, numeric id, gid or product URL.
|
|
10
|
+
* @throws {TetherError} `NOT_FOUND` (rejected) for an empty key or a product the store doesn't have.
|
|
11
|
+
*/
|
|
12
|
+
export declare function getProduct(rawKey: string | number | null | undefined): Promise<Product>;
|
|
13
|
+
/** Forgets every product, for a new market: requests already sent no longer fill the cache. */
|
|
14
|
+
export declare function clearProductCache(): void;
|
|
15
|
+
/**
|
|
16
|
+
* Uses products the server rendered, unless the page loaded the same product live in the last `FRESH_MS` (an earlier
|
|
17
|
+
* page of a View Transition visit), whose copy is newer.
|
|
18
|
+
*/
|
|
19
|
+
export declare function hydrateProducts(products: readonly Product[] | null | undefined): void;
|
|
20
|
+
/** @returns True once per server-rendered product: the caller then refreshes it. */
|
|
21
|
+
export declare function takeStale(rawKey: string | number | null | undefined): boolean;
|
|
22
|
+
/** Loads this product again, past the cache. Products refreshed in the same tick go out as one request. */
|
|
23
|
+
export declare function refreshProduct(key: string | number): Promise<Product>;
|
|
24
|
+
export interface PageInfo {
|
|
25
|
+
hasNextPage: boolean;
|
|
26
|
+
endCursor: string | null;
|
|
27
|
+
}
|
|
28
|
+
export interface Collection {
|
|
29
|
+
id: string;
|
|
30
|
+
handle: string;
|
|
31
|
+
title: string;
|
|
32
|
+
description: string;
|
|
33
|
+
descriptionHtml: string;
|
|
34
|
+
image: Image | null;
|
|
35
|
+
seo: {
|
|
36
|
+
title: string | null;
|
|
37
|
+
description: string | null;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export interface ProductPage {
|
|
41
|
+
collection: Collection | null;
|
|
42
|
+
products: Product[];
|
|
43
|
+
pageInfo: PageInfo;
|
|
44
|
+
}
|
|
45
|
+
export interface ProductQuery {
|
|
46
|
+
/** A collection handle; without one, a search. */
|
|
47
|
+
collection?: string;
|
|
48
|
+
/** Storefront search syntax, for a search. */
|
|
49
|
+
query?: string;
|
|
50
|
+
first?: number;
|
|
51
|
+
/** The cursor of the page before. */
|
|
52
|
+
after?: string | null;
|
|
53
|
+
/** `ProductCollectionSortKeys` for a collection, `ProductSortKeys` for a search. */
|
|
54
|
+
sortKey?: string;
|
|
55
|
+
reverse?: boolean;
|
|
56
|
+
/** `ProductFilter` values, for a collection. */
|
|
57
|
+
filters?: unknown[];
|
|
58
|
+
}
|
|
59
|
+
/** A collection's answer: `null` for a handle the store doesn't have. Its other fields are written as text. */
|
|
60
|
+
export declare const isCollectionAnswer: import("./client.js").DataCheck<{
|
|
61
|
+
collection: (Collection & {
|
|
62
|
+
products: ProductConnection;
|
|
63
|
+
}) | null;
|
|
64
|
+
}>;
|
|
65
|
+
export declare const isSearchAnswer: import("./client.js").DataCheck<{
|
|
66
|
+
products: ProductConnection;
|
|
67
|
+
}>;
|
|
68
|
+
export declare const isRecommendationsAnswer: import("./client.js").DataCheck<{
|
|
69
|
+
productRecommendations: Product[] | null;
|
|
70
|
+
}>;
|
|
71
|
+
/**
|
|
72
|
+
* A page of products from a collection (by handle) or from a search. Every product on it is cached.
|
|
73
|
+
*
|
|
74
|
+
* @throws {TetherError} `NOT_FOUND` for a collection the store doesn't have.
|
|
75
|
+
*/
|
|
76
|
+
export declare function getProducts({ collection, query, first, after, sortKey, reverse, filters, }?: ProductQuery): Promise<ProductPage>;
|
|
77
|
+
/**
|
|
78
|
+
* Shopify's recommendations for a product. Every product in them is cached.
|
|
79
|
+
*
|
|
80
|
+
* @param product A product, or its handle, id or gid.
|
|
81
|
+
*/
|
|
82
|
+
export declare function getRecommendations(product: string | number | {
|
|
83
|
+
id: string;
|
|
84
|
+
} | null | undefined, intent?: 'RELATED' | 'COMPLEMENTARY'): Promise<Product[]>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Country and language codes as Shopify's `@inContext` takes them, parsed by the module the Worker uses for the
|
|
3
|
+
* login's market, so the browser and the Worker accept and refuse the same values.
|
|
4
|
+
*/
|
|
5
|
+
export { toCountry, toLanguage } from '../server/src/shared/market-codes.js';
|
|
6
|
+
export type { CountryCode, LanguageCode } from '../server/src/shared/market-codes.js';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Cart } from './cart.js';
|
|
2
|
+
import type { Localization } from './markets.js';
|
|
3
|
+
export { detectMarket } from './markets.js';
|
|
4
|
+
/**
|
|
5
|
+
* The countries the store sells to (Shopify Markets), with their currency. Cached per page; a failed request is not
|
|
6
|
+
* cached, so the next call tries again.
|
|
7
|
+
*/
|
|
8
|
+
export declare function getLocalization(): Promise<Localization>;
|
|
9
|
+
interface SetCountryOptions {
|
|
10
|
+
/** A Shopify language; `null` clears it. Default: the `markets.locales` entry for the country, else unchanged. */
|
|
11
|
+
language?: string | null | undefined;
|
|
12
|
+
/** The money format. Default: the `markets.locales` entry, else unchanged. */
|
|
13
|
+
locale?: string | undefined;
|
|
14
|
+
/** Save the choice for the next pages (default true). */
|
|
15
|
+
remember?: boolean | undefined;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Fills `select[tether-country-select]` with the countries the store sells to (Shopify Markets), and
|
|
19
|
+
* `tether-country-bind="name|code|currency|symbol"` with the current country. `tether-country-label` sets the option
|
|
20
|
+
* text from `{name}`, `{code}`, `{currency}` and `{symbol}`. A failure is reported, never thrown.
|
|
21
|
+
*/
|
|
22
|
+
export declare function renderCountrySelects(root?: ParentNode): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Switches the market: prices, currency and translations follow (`@inContext`), the cart's
|
|
25
|
+
* `buyerIdentity.countryCode` is updated, and every product and list on the page re-renders.
|
|
26
|
+
*
|
|
27
|
+
* Tether.setCountry('DE') Tether.setCountry('BE', { language: 'FR' })
|
|
28
|
+
*
|
|
29
|
+
* @returns The cart once everything is in the new market.
|
|
30
|
+
* @throws {TetherError} `INVALID_COUNTRY` for anything that isn't a country code.
|
|
31
|
+
*/
|
|
32
|
+
export declare function setCountry(code: string, { language, locale, remember }?: SetCountryOptions): Promise<typeof Cart.state>;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { MarketsConfig } from './config.js';
|
|
2
|
+
import type { CountryCode, LanguageCode } from './market-codes.js';
|
|
3
|
+
/** A market a visitor chose, as `setCountry()` stores it. */
|
|
4
|
+
export interface Market {
|
|
5
|
+
country: CountryCode;
|
|
6
|
+
language: LanguageCode | undefined;
|
|
7
|
+
/** An `Intl` locale for money and dates. */
|
|
8
|
+
locale: string | undefined;
|
|
9
|
+
}
|
|
10
|
+
export type MarketSource = 'saved' | 'server' | 'webflow';
|
|
11
|
+
type MarketField = 'country' | 'language' | 'locale';
|
|
12
|
+
type MarketSources = Partial<Record<MarketField, MarketSource>>;
|
|
13
|
+
/** The fields detection found, and the source each came from. */
|
|
14
|
+
export interface DetectedMarket {
|
|
15
|
+
country?: CountryCode;
|
|
16
|
+
language?: LanguageCode;
|
|
17
|
+
locale?: string;
|
|
18
|
+
/** Absent when `detect: false` turns detection off. */
|
|
19
|
+
sources?: MarketSources;
|
|
20
|
+
}
|
|
21
|
+
/** What detection reads, passed in so it runs on any document. */
|
|
22
|
+
interface MarketEnv {
|
|
23
|
+
document: Pick<Document, 'cookie' | 'querySelector' | 'documentElement'> | null;
|
|
24
|
+
location: Pick<Location, 'pathname'> | null;
|
|
25
|
+
/** `localStorage`, read through `getStored`, which finds nothing where the browser blocks it. */
|
|
26
|
+
storage: Pick<Storage, 'getItem'>;
|
|
27
|
+
/** Where `TETHER_COUNTRY` and `TETHER_LANGUAGE` are read from (`window`). */
|
|
28
|
+
global: object;
|
|
29
|
+
}
|
|
30
|
+
interface NamedCode {
|
|
31
|
+
isoCode: string;
|
|
32
|
+
name: string;
|
|
33
|
+
}
|
|
34
|
+
interface Currency {
|
|
35
|
+
isoCode: string;
|
|
36
|
+
symbol: string;
|
|
37
|
+
}
|
|
38
|
+
export type LocalizedCountry = NamedCode & {
|
|
39
|
+
currency: Currency;
|
|
40
|
+
};
|
|
41
|
+
/** The store's markets, from the Storefront API's `localization`. */
|
|
42
|
+
export interface Localization {
|
|
43
|
+
/** The country of the current `@inContext`. */
|
|
44
|
+
country: LocalizedCountry;
|
|
45
|
+
language: NamedCode;
|
|
46
|
+
availableCountries: (LocalizedCountry & {
|
|
47
|
+
availableLanguages: NamedCode[];
|
|
48
|
+
})[];
|
|
49
|
+
}
|
|
50
|
+
/** The localStorage key of the visitor's market: `<prefix>:market:<domain>`. */
|
|
51
|
+
export declare const storageKey: () => string;
|
|
52
|
+
/**
|
|
53
|
+
* The visitor's saved market (`setCountry()`, `tether-country-select`), validated: storage is written by other tabs,
|
|
54
|
+
* older versions and other scripts too.
|
|
55
|
+
*
|
|
56
|
+
* @param storage Default `localStorage`.
|
|
57
|
+
* @returns `null` when nothing valid is saved.
|
|
58
|
+
*/
|
|
59
|
+
export declare function readSavedMarket(storage?: Pick<Storage, 'getItem'>): Market | null;
|
|
60
|
+
/**
|
|
61
|
+
* The market the page's sources point to. Reads the DOM and storage only, so it can run on any `env`.
|
|
62
|
+
*
|
|
63
|
+
* @returns Only the fields found; `{}` with `detect: false`.
|
|
64
|
+
*/
|
|
65
|
+
export declare function detectMarket(markets?: MarketsConfig | null | undefined, env?: MarketEnv): DetectedMarket;
|
|
66
|
+
/** Saves the visitor's choice for the next pages, unless `markets.remember` is false. */
|
|
67
|
+
export declare function rememberMarket(market: {
|
|
68
|
+
country: CountryCode;
|
|
69
|
+
language?: string | null | undefined;
|
|
70
|
+
locale?: string | null | undefined;
|
|
71
|
+
}): void;
|
|
72
|
+
export {};
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import type { ShopifyCart } from './cart/store.js';
|
|
2
|
+
import type { CartLineInput } from './cart/mutations.js';
|
|
3
|
+
import type { CartWarning } from './config.js';
|
|
4
|
+
import type { Product, ProductVariant } from './fragments.js';
|
|
5
|
+
import type { Collection } from './loader.js';
|
|
6
|
+
import type { ProductScope } from './product.js';
|
|
7
|
+
import type { Purchase } from './product-state.js';
|
|
8
|
+
import type { SearchResults } from './search.js';
|
|
9
|
+
/** @returns The prefixed attribute name: `product` → `tether-product`. */
|
|
10
|
+
export declare const attr: (name: string) => string;
|
|
11
|
+
/** @returns A selector for the attribute, with that exact value when given. */
|
|
12
|
+
export declare const sel: (name: string, value?: string) => string;
|
|
13
|
+
export declare const get: (el: Element, name: string) => string | null;
|
|
14
|
+
export declare const has: (el: Element, name: string) => boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Tether's attributes go on HTML elements, so matches are typed as such. An SVG element that carries one still has
|
|
17
|
+
* the `style`, `dataset` and attribute methods Tether uses.
|
|
18
|
+
*
|
|
19
|
+
* @returns The matches in `root`, none without a root.
|
|
20
|
+
*/
|
|
21
|
+
export declare function qsa(root: ParentNode | null | undefined, selector: string): HTMLElement[];
|
|
22
|
+
/** @returns Matches in `root` whose nearest `scopeSelector` ancestor is `root` itself, not a nested scope. */
|
|
23
|
+
export declare const scoped: (root: Element | null | undefined, selector: string, scopeSelector: string) => HTMLElement[];
|
|
24
|
+
/**
|
|
25
|
+
* The events Tether dispatches, as `<prefix>:<name>` (`tether:cart-updated`), bubbling up to `document`, with the
|
|
26
|
+
* detail each carries. `emit` takes only these, and `Tether.on()` passes on only the events `emit` dispatched, so a listener gets the
|
|
27
|
+
* detail its event really has.
|
|
28
|
+
*/
|
|
29
|
+
export interface TetherEvents {
|
|
30
|
+
ready: {
|
|
31
|
+
cart: ShopifyCart | null;
|
|
32
|
+
};
|
|
33
|
+
'product-ready': {
|
|
34
|
+
product: Product;
|
|
35
|
+
scope: ProductScope;
|
|
36
|
+
};
|
|
37
|
+
'product-updated': {
|
|
38
|
+
product: Product;
|
|
39
|
+
scope: ProductScope;
|
|
40
|
+
};
|
|
41
|
+
/** `key` is null when the scope names no product; `source` is what it named. */
|
|
42
|
+
'product-not-found': {
|
|
43
|
+
key: string | null;
|
|
44
|
+
source: string;
|
|
45
|
+
};
|
|
46
|
+
'variant-changed': {
|
|
47
|
+
product: Product;
|
|
48
|
+
variant: ProductVariant;
|
|
49
|
+
selected: Record<string, string>;
|
|
50
|
+
purchase: Purchase['kind'];
|
|
51
|
+
sellingPlanId: string | null;
|
|
52
|
+
};
|
|
53
|
+
'product-added': {
|
|
54
|
+
product: Product;
|
|
55
|
+
variant: ProductVariant;
|
|
56
|
+
line: CartLineInput;
|
|
57
|
+
};
|
|
58
|
+
added: {
|
|
59
|
+
cart: ShopifyCart;
|
|
60
|
+
lines: CartLineInput[];
|
|
61
|
+
};
|
|
62
|
+
'group-added': {
|
|
63
|
+
group: string | null;
|
|
64
|
+
lines: CartLineInput[];
|
|
65
|
+
};
|
|
66
|
+
'cart-warning': {
|
|
67
|
+
warnings: readonly CartWarning[];
|
|
68
|
+
};
|
|
69
|
+
'cart-updated': {
|
|
70
|
+
cart: ShopifyCart | null;
|
|
71
|
+
reason: string;
|
|
72
|
+
};
|
|
73
|
+
'cart-toggled': {
|
|
74
|
+
open: boolean;
|
|
75
|
+
};
|
|
76
|
+
'cart-error': {
|
|
77
|
+
error: unknown;
|
|
78
|
+
};
|
|
79
|
+
checkout: {
|
|
80
|
+
url: string;
|
|
81
|
+
cart: ShopifyCart | null;
|
|
82
|
+
};
|
|
83
|
+
'list-ready': {
|
|
84
|
+
products: Product[];
|
|
85
|
+
collection: Collection | null;
|
|
86
|
+
};
|
|
87
|
+
/** A list's cards were drawn (again): `container` holds them. */
|
|
88
|
+
'list-rendered': {
|
|
89
|
+
container: Element;
|
|
90
|
+
};
|
|
91
|
+
/** The search part's suggestions for `term`. */
|
|
92
|
+
search: SearchResults & {
|
|
93
|
+
term: string;
|
|
94
|
+
};
|
|
95
|
+
'country-changed': {
|
|
96
|
+
country: string;
|
|
97
|
+
language: string | undefined;
|
|
98
|
+
};
|
|
99
|
+
'discount-applied': {
|
|
100
|
+
code: string;
|
|
101
|
+
};
|
|
102
|
+
'discount-invalid': {
|
|
103
|
+
code: string;
|
|
104
|
+
};
|
|
105
|
+
'layout-changed': {
|
|
106
|
+
reason: string;
|
|
107
|
+
};
|
|
108
|
+
error: {
|
|
109
|
+
error: unknown;
|
|
110
|
+
context: string;
|
|
111
|
+
key?: string | null;
|
|
112
|
+
};
|
|
113
|
+
'account-login': Record<string, never>;
|
|
114
|
+
'account-logout': Record<string, never>;
|
|
115
|
+
/** A login that failed: `expired` (it took too long, or came back to another browser) or `error`. */
|
|
116
|
+
'account-error': {
|
|
117
|
+
error: 'expired' | 'error';
|
|
118
|
+
};
|
|
119
|
+
'account-updated': {
|
|
120
|
+
what: 'profile' | 'addresses' | 'subscriptions' | 'orders';
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
/** The events the analytics part reports, which the core buffers from `init()` until the part has loaded. */
|
|
124
|
+
export declare const ANALYTICS_EVENTS: readonly ["product-ready", "list-ready", "cart-updated", "cart-toggled", "checkout", "search"];
|
|
125
|
+
export type AnalyticsEventName = (typeof ANALYTICS_EVENTS)[number];
|
|
126
|
+
/** @returns The bubbling event `<prefix>:<name>`, known to `isOwnEvent`. */
|
|
127
|
+
export declare function ownEvent<Name extends keyof TetherEvents>(name: Name, detail: TetherEvents[Name]): CustomEvent<TetherEvents[Name]>;
|
|
128
|
+
/** @returns True for an event `ownEvent` created as `name`, false for any other, such as one another script dispatched. */
|
|
129
|
+
export declare function isOwnEvent<Name extends keyof TetherEvents>(event: Event, name: Name): event is CustomEvent<TetherEvents[Name]>;
|
|
130
|
+
/** Dispatches the bubbling event `<prefix>:<name>`. */
|
|
131
|
+
export declare function emit<Name extends keyof TetherEvents>(name: Name, detail: TetherEvents[Name], target?: EventTarget): void;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** A mounted `ListScope`. */
|
|
2
|
+
interface MountedList {
|
|
3
|
+
root: Element;
|
|
4
|
+
load: (more?: boolean) => Promise<unknown>;
|
|
5
|
+
}
|
|
6
|
+
export declare const mountedProducts: WeakSet<Element>;
|
|
7
|
+
export declare const mountedLists: WeakSet<Element>;
|
|
8
|
+
/** Product roots to re-render after a country switch; pruned once disconnected. */
|
|
9
|
+
export declare const liveProducts: Set<HTMLElement>;
|
|
10
|
+
/** Lists to reload after a country switch; pruned once disconnected. */
|
|
11
|
+
export declare const liveLists: Set<MountedList>;
|
|
12
|
+
/** Forgets roots a page transition removed, so they aren't kept alive. */
|
|
13
|
+
export declare function pruneLive(): void;
|
|
14
|
+
/** @returns `root` itself when it matches, then the matches inside it. */
|
|
15
|
+
export declare function within(root: ParentNode & Partial<Pick<Element, 'matches'>>, selector: string): HTMLElement[];
|
|
16
|
+
/**
|
|
17
|
+
* Mounts one product root.
|
|
18
|
+
*
|
|
19
|
+
* @returns True when a product request was started.
|
|
20
|
+
*/
|
|
21
|
+
export declare function mountProduct(el: HTMLElement): boolean;
|
|
22
|
+
/** Loads again the product scopes that failed on a network or API error, for when the browser is back online. */
|
|
23
|
+
export declare function retryFailed(): void;
|
|
24
|
+
/**
|
|
25
|
+
* Lists, and anything else that loads prices, hold `html.tether-market-pending` until they are in.
|
|
26
|
+
*
|
|
27
|
+
* @returns `loading` itself.
|
|
28
|
+
*/
|
|
29
|
+
export declare const trackMarket: <T>(loading: Promise<T>) => Promise<T>;
|
|
30
|
+
/** After a mount: drops `html.tether-market-pending` once this page's products are live. */
|
|
31
|
+
export declare function settleMarket(): void;
|
|
32
|
+
/**
|
|
33
|
+
* Uses the products in the page's hydrate tags (`tether/server` `hydrate()`) without a request. A tag made for another
|
|
34
|
+
* market is skipped, and marks the page (`html.tether-market-pending`) until the live prices are in, so CSS can hide
|
|
35
|
+
* prices meanwhile.
|
|
36
|
+
*
|
|
37
|
+
* Trust: a hydrate tag is part of the page, written by the site's own build like the rest of its HTML and scripts, so
|
|
38
|
+
* its prices and products are shown until the background refresh replaces them. Whoever can write a tag into the page
|
|
39
|
+
* can already write a script there; the shape check (`isProductShape`) is for a truncated or hand-written tag, which
|
|
40
|
+
* is skipped instead of failing a render.
|
|
41
|
+
*
|
|
42
|
+
* @param root Where to look: the document for a mount (a tag may sit in `<head>` or anywhere else on the page), the
|
|
43
|
+
* added elements for `observe`.
|
|
44
|
+
*/
|
|
45
|
+
export declare function hydrateFromPage(root?: Document | Element): void;
|
|
46
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { TetherOptions } from './config.js';
|
|
2
|
+
import type { Parts } from './lazy.js';
|
|
3
|
+
import type { ShopifyCart } from './cart/store.js';
|
|
4
|
+
export type SetCountryOptions = Parameters<Parts['markets']['setCountry']>[1];
|
|
5
|
+
/**
|
|
6
|
+
* Sets `cfg`'s market for the first page, over the configured one.
|
|
7
|
+
*
|
|
8
|
+
* @param overrides What `init()` was called with: a `locale` there wins over the visitor's.
|
|
9
|
+
*/
|
|
10
|
+
export declare function applyStartMarket(overrides: TetherOptions): Promise<void>;
|
|
11
|
+
/**
|
|
12
|
+
* The market to switch to on arriving at the current page. A page built for a market switches to it; the first page
|
|
13
|
+
* without one after such a page switches back to the visitor's own choice, else to the configured market.
|
|
14
|
+
*
|
|
15
|
+
* @returns `null` when the page stays in the market in use.
|
|
16
|
+
*/
|
|
17
|
+
export declare function marketForArrival(): {
|
|
18
|
+
country: string;
|
|
19
|
+
language: string | undefined;
|
|
20
|
+
locale: string | undefined;
|
|
21
|
+
} | null;
|
|
22
|
+
/**
|
|
23
|
+
* `Tether.setCountry('DE')`: loads the markets part on first use.
|
|
24
|
+
*
|
|
25
|
+
* @returns The cart once everything is in the new market.
|
|
26
|
+
*/
|
|
27
|
+
export declare function setCountry(code: string, options?: SetCountryOptions): Promise<ShopifyCart | null>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Preset for sites with page transitions (Barba, Swup), smooth scroll (Lenis) and GSAP. Nothing is read from globals
|
|
3
|
+
* except GSAP and ScrollTrigger by default: pass in what your site has.
|
|
4
|
+
*
|
|
5
|
+
* import Tether from "@occluze/tether";
|
|
6
|
+
* import { barbaPreset } from "@occluze/tether/presets/barba";
|
|
7
|
+
*
|
|
8
|
+
* Tether.init({
|
|
9
|
+
* ...window.TETHER_CONFIG,
|
|
10
|
+
* ...barbaPreset({
|
|
11
|
+
* lenis: () => myLenis, // resized after async renders
|
|
12
|
+
* lockScroll: (drawer) => myLock.lock(drawer), // when the cart opens
|
|
13
|
+
* unlockScroll: () => myLock.unlock(), // when the cart closes
|
|
14
|
+
* onValueChange: (el, previous) => {}, // e.g. a text scramble
|
|
15
|
+
* }),
|
|
16
|
+
* });
|
|
17
|
+
*
|
|
18
|
+
* // once per page container, e.g. in Barba's beforeEnter AND once():
|
|
19
|
+
* Tether.mount(container);
|
|
20
|
+
* // when leaving a page:
|
|
21
|
+
* Tether.unmount();
|
|
22
|
+
*/
|
|
23
|
+
import type { TetherConfig } from '../config.js';
|
|
24
|
+
/** `gsap`, `lenis` and `scrollTrigger` are getters, read each time they are used, so an instance made later is found. */
|
|
25
|
+
interface BarbaPresetOptions {
|
|
26
|
+
/** Default `window.gsap`. */
|
|
27
|
+
gsap?: () => unknown;
|
|
28
|
+
/** Resized after async renders. */
|
|
29
|
+
lenis?: (() => unknown) | null;
|
|
30
|
+
/** Default `window.ScrollTrigger`, refreshed after async renders. */
|
|
31
|
+
scrollTrigger?: () => unknown;
|
|
32
|
+
/** When the cart opens. */
|
|
33
|
+
lockScroll?: ((drawer: HTMLElement) => void) | null;
|
|
34
|
+
/** When the cart closes. */
|
|
35
|
+
unlockScroll?: (() => void) | null;
|
|
36
|
+
/** After a cart line animated in or out. */
|
|
37
|
+
onResize?: (() => void) | null;
|
|
38
|
+
onValueChange?: TetherConfig['onValueChange'];
|
|
39
|
+
/** Animate cart lines in and out (default true). */
|
|
40
|
+
animateLines?: boolean;
|
|
41
|
+
/** Seconds. */
|
|
42
|
+
lineDuration?: number;
|
|
43
|
+
}
|
|
44
|
+
/** The hooks the preset always sets, and `onValueChange` as passed (`null` when it isn't). */
|
|
45
|
+
type BarbaPresetConfig = {
|
|
46
|
+
autoMount: false;
|
|
47
|
+
} & {
|
|
48
|
+
[Hook in 'onLayoutChange' | 'onCartOpen' | 'onCartClose' | 'onLineEnter' | 'onLineLeave']: NonNullable<TetherConfig[Hook]>;
|
|
49
|
+
} & Pick<TetherConfig, 'onValueChange'>;
|
|
50
|
+
export type { BarbaPresetOptions, BarbaPresetConfig };
|
|
51
|
+
/**
|
|
52
|
+
* Hooks for sites with page transitions, smooth scroll and GSAP: spread into `Tether.init()`.
|
|
53
|
+
*/
|
|
54
|
+
export declare function barbaPreset(options?: BarbaPresetOptions): BarbaPresetConfig;
|
|
55
|
+
/** @alias `barbaPreset`, for `import barbaPreset from '@occluze/tether/presets/barba'`. */
|
|
56
|
+
export default barbaPreset;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Product } from './fragments.js';
|
|
2
|
+
import type { PlanInGroup } from './selling-plans.js';
|
|
3
|
+
/** The product scope as its renders see it. */
|
|
4
|
+
export interface RenderScope {
|
|
5
|
+
readonly root: HTMLElement;
|
|
6
|
+
readonly product: Product;
|
|
7
|
+
readonly plans: PlanInGroup[];
|
|
8
|
+
/** Matches in this scope, the root included. */
|
|
9
|
+
$: (selector: string) => HTMLElement[];
|
|
10
|
+
/** The product's option name for one written in the markup. */
|
|
11
|
+
optName: (authored: string | null) => string;
|
|
12
|
+
}
|
|
13
|
+
export declare const isSelect: (el: Element) => el is HTMLSelectElement;
|
|
14
|
+
/** @returns The `<select>` elements in the scope that match `selector`. */
|
|
15
|
+
export declare const selectsIn: (scope: RenderScope, selector: string) => HTMLSelectElement[];
|
|
16
|
+
/** Writes what depends on the product alone: its binds, option and plan lists and the selects' options. */
|
|
17
|
+
export declare function writeProduct(scope: RenderScope): void;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { Product } from './fragments.js';
|
|
2
|
+
import type { PageInfo } from './loader.js';
|
|
3
|
+
/** A page of a GraphQL connection of products. */
|
|
4
|
+
export interface ProductConnection {
|
|
5
|
+
nodes: Product[];
|
|
6
|
+
pageInfo: PageInfo;
|
|
7
|
+
}
|
|
8
|
+
/** A Storefront API `MoneyV2`. */
|
|
9
|
+
export declare const MONEY: {
|
|
10
|
+
readonly amount: "string";
|
|
11
|
+
readonly currencyCode: "string";
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* A product's id, handle and title, and every list and price a render walks without a fallback: images, options,
|
|
15
|
+
* variants (each with an id, a price and its options) and the price range. Text fields are written as text, and the
|
|
16
|
+
* selling plan lists are read with a fallback, so they need no check.
|
|
17
|
+
*/
|
|
18
|
+
export declare const PRODUCT: {
|
|
19
|
+
readonly id: "string";
|
|
20
|
+
readonly handle: "string";
|
|
21
|
+
readonly title: "string";
|
|
22
|
+
readonly options: readonly ["object"];
|
|
23
|
+
readonly images: {
|
|
24
|
+
readonly nodes: readonly ["object"];
|
|
25
|
+
};
|
|
26
|
+
readonly priceRange: {
|
|
27
|
+
readonly minVariantPrice: {
|
|
28
|
+
readonly amount: "string";
|
|
29
|
+
readonly currencyCode: "string";
|
|
30
|
+
};
|
|
31
|
+
readonly maxVariantPrice: {
|
|
32
|
+
readonly amount: "string";
|
|
33
|
+
readonly currencyCode: "string";
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
readonly variants: {
|
|
37
|
+
readonly nodes: readonly [{
|
|
38
|
+
readonly id: "string";
|
|
39
|
+
readonly price: {
|
|
40
|
+
readonly amount: "string";
|
|
41
|
+
readonly currencyCode: "string";
|
|
42
|
+
};
|
|
43
|
+
readonly selectedOptions: readonly ["object"];
|
|
44
|
+
}];
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
/** A page of products, with the `pageInfo` paging reads. */
|
|
48
|
+
export declare const PRODUCT_CONNECTION: {
|
|
49
|
+
readonly nodes: readonly [{
|
|
50
|
+
readonly id: "string";
|
|
51
|
+
readonly handle: "string";
|
|
52
|
+
readonly title: "string";
|
|
53
|
+
readonly options: readonly ["object"];
|
|
54
|
+
readonly images: {
|
|
55
|
+
readonly nodes: readonly ["object"];
|
|
56
|
+
};
|
|
57
|
+
readonly priceRange: {
|
|
58
|
+
readonly minVariantPrice: {
|
|
59
|
+
readonly amount: "string";
|
|
60
|
+
readonly currencyCode: "string";
|
|
61
|
+
};
|
|
62
|
+
readonly maxVariantPrice: {
|
|
63
|
+
readonly amount: "string";
|
|
64
|
+
readonly currencyCode: "string";
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
readonly variants: {
|
|
68
|
+
readonly nodes: readonly [{
|
|
69
|
+
readonly id: "string";
|
|
70
|
+
readonly price: {
|
|
71
|
+
readonly amount: "string";
|
|
72
|
+
readonly currencyCode: "string";
|
|
73
|
+
};
|
|
74
|
+
readonly selectedOptions: readonly ["object"];
|
|
75
|
+
}];
|
|
76
|
+
};
|
|
77
|
+
}];
|
|
78
|
+
readonly pageInfo: {
|
|
79
|
+
readonly hasNextPage: "boolean";
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
/** True for a value with the structure of `PRODUCT` and a non-empty id and handle. */
|
|
83
|
+
export declare const isProductShape: (value: unknown) => value is Product;
|
|
84
|
+
/**
|
|
85
|
+
* A node a lookup by gid answers: a product, or a node of another type, for which `... on Product` selects no field
|
|
86
|
+
* (no `id`).
|
|
87
|
+
*/
|
|
88
|
+
export declare const PRODUCT_NODE: (node: unknown) => boolean;
|