@occluze/tether 0.7.0 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/README.md +51 -109
  2. package/dist/esm/astro.js +1 -1
  3. package/dist/esm/chunks/{account-UIPWJQ3Y.js → account-W4FBRKXA.js} +1 -1
  4. package/dist/esm/chunks/{account-pages-6ROA6Y4V.js → account-pages-IM3OQTOP.js} +1 -1
  5. package/dist/esm/chunks/analytics-QDVOLZY3.js +1 -0
  6. package/dist/esm/chunks/{chunk-T44MUL4Y.js → chunk-AUVAN3KZ.js} +1 -1
  7. package/dist/esm/chunks/chunk-BMDYNMRC.js +1 -0
  8. package/dist/esm/chunks/chunk-CUL66KRA.js +1 -0
  9. package/dist/esm/chunks/{chunk-6OZJCAGZ.js → chunk-CVNRODH3.js} +1 -1
  10. package/dist/esm/chunks/{chunk-5Z5O3767.js → chunk-CXHPBT7N.js} +1 -1
  11. package/dist/esm/chunks/chunk-GF6JTI65.js +1 -0
  12. package/dist/esm/chunks/chunk-MRSDJPBC.js +1 -0
  13. package/dist/esm/chunks/chunk-NYDZPTLP.js +1 -0
  14. package/dist/esm/chunks/chunk-QDHLXXAZ.js +1 -0
  15. package/dist/esm/chunks/{chunk-4GCXM764.js → chunk-QUECUXHD.js} +1 -1
  16. package/dist/esm/chunks/chunk-RJY76ESL.js +1 -0
  17. package/dist/esm/chunks/chunk-RPI5C3EJ.js +1 -0
  18. package/dist/esm/chunks/{chunk-BFTZR4OB.js → chunk-YC4JXWRG.js} +2 -2
  19. package/dist/esm/chunks/{diagnose-3FEKRIEK.js → diagnose-3XHPZZNP.js} +1 -1
  20. package/dist/esm/chunks/extras-C724KKG6.js +1 -0
  21. package/dist/esm/chunks/{markets-ui-FD6NI2OG.js → markets-ui-WBWWQAGU.js} +1 -1
  22. package/dist/esm/chunks/{search-UJ73YBQ5.js → search-5NFIZBPJ.js} +1 -1
  23. package/dist/esm/index.js +1 -1
  24. package/dist/esm/server.js +2 -2
  25. package/dist/tether.account-pages.js +13 -3
  26. package/dist/tether.account-pages.min.js +1 -1
  27. package/dist/tether.account.js +13 -3
  28. package/dist/tether.account.min.js +1 -1
  29. package/dist/tether.analytics.js +18 -3
  30. package/dist/tether.analytics.min.js +1 -1
  31. package/dist/tether.diagnose.js +20 -5
  32. package/dist/tether.diagnose.min.js +2 -2
  33. package/dist/tether.extras.js +52 -28
  34. package/dist/tether.extras.min.js +1 -1
  35. package/dist/tether.js +353 -288
  36. package/dist/tether.markets.js +31 -5
  37. package/dist/tether.markets.min.js +1 -1
  38. package/dist/tether.min.js +2 -2
  39. package/dist/tether.min.js.map +4 -4
  40. package/dist/tether.search.js +18 -3
  41. package/dist/tether.search.min.js +1 -1
  42. package/dist/types/server/src/shared/cart-id.d.ts +2 -0
  43. package/dist/types/src/cart/mutations.d.ts +6 -0
  44. package/dist/types/src/cart/store.d.ts +5 -2
  45. package/dist/types/src/cart.d.ts +3 -2
  46. package/dist/types/src/client.d.ts +61 -22
  47. package/dist/types/src/config.d.ts +6 -1
  48. package/dist/types/src/index.d.ts +2 -2
  49. package/dist/types/src/markets.d.ts +9 -2
  50. package/dist/types/src/product-shape.d.ts +3 -1
  51. package/dist/types/src/uri.d.ts +6 -0
  52. package/package.json +54 -6
  53. package/dist/esm/chunks/analytics-2V632IRV.js +0 -1
  54. package/dist/esm/chunks/chunk-56FCLJJD.js +0 -1
  55. package/dist/esm/chunks/chunk-A5SYCVQM.js +0 -1
  56. package/dist/esm/chunks/chunk-BA4LQJJQ.js +0 -1
  57. package/dist/esm/chunks/chunk-C5JYQCWH.js +0 -1
  58. package/dist/esm/chunks/chunk-E5YO6274.js +0 -1
  59. package/dist/esm/chunks/chunk-MPDWM2NN.js +0 -1
  60. package/dist/esm/chunks/chunk-YLUULATY.js +0 -1
  61. package/dist/esm/chunks/extras-6POFBNOP.js +0 -1
  62. package/src/account/addresses-view.ts +0 -58
  63. package/src/account/answers.ts +0 -79
  64. package/src/account/markup.ts +0 -36
  65. package/src/account/operations.ts +0 -145
  66. package/src/account/order-lines.ts +0 -75
  67. package/src/account/order-list.ts +0 -107
  68. package/src/account/order-page.ts +0 -137
  69. package/src/account/page-answers.ts +0 -317
  70. package/src/account/page-events.ts +0 -253
  71. package/src/account/server-client.ts +0 -183
  72. package/src/account/subscriptions-view.ts +0 -115
  73. package/src/account-api.ts +0 -98
  74. package/src/account-marks.ts +0 -35
  75. package/src/account-pages.ts +0 -81
  76. package/src/account.ts +0 -284
  77. package/src/amounts.ts +0 -64
  78. package/src/analytics-shopify.ts +0 -246
  79. package/src/analytics.ts +0 -315
  80. package/src/api-version.ts +0 -79
  81. package/src/astro.ts +0 -272
  82. package/src/cart/cart-shape.ts +0 -25
  83. package/src/cart/checkout.ts +0 -101
  84. package/src/cart/drawer.ts +0 -125
  85. package/src/cart/mutations.ts +0 -237
  86. package/src/cart/render.ts +0 -266
  87. package/src/cart/store.ts +0 -279
  88. package/src/cart.ts +0 -345
  89. package/src/client.ts +0 -391
  90. package/src/collection.ts +0 -175
  91. package/src/config-sections.ts +0 -284
  92. package/src/config.ts +0 -480
  93. package/src/controls/cart-controls.ts +0 -123
  94. package/src/controls/discount.ts +0 -75
  95. package/src/controls/extras.ts +0 -54
  96. package/src/controls/navigation.ts +0 -77
  97. package/src/diagnose-markup.ts +0 -298
  98. package/src/diagnose.ts +0 -294
  99. package/src/dom.ts +0 -268
  100. package/src/extras.ts +0 -136
  101. package/src/fragments.ts +0 -261
  102. package/src/globals.d.ts +0 -15
  103. package/src/images.ts +0 -91
  104. package/src/index.ts +0 -415
  105. package/src/initial.ts +0 -101
  106. package/src/lazy-iife.ts +0 -197
  107. package/src/lazy.ts +0 -42
  108. package/src/loader.ts +0 -363
  109. package/src/market-codes.ts +0 -6
  110. package/src/markets-ui.ts +0 -227
  111. package/src/markets.ts +0 -246
  112. package/src/markup.ts +0 -127
  113. package/src/mounting.ts +0 -264
  114. package/src/page-market.ts +0 -110
  115. package/src/part-integrity.ts +0 -7
  116. package/src/parts/account-pages.ts +0 -7
  117. package/src/parts/account.ts +0 -7
  118. package/src/parts/analytics.ts +0 -7
  119. package/src/parts/diagnose.ts +0 -7
  120. package/src/parts/extras.ts +0 -7
  121. package/src/parts/markets.ts +0 -7
  122. package/src/parts/search.ts +0 -7
  123. package/src/presets/barba.ts +0 -194
  124. package/src/product-events.ts +0 -115
  125. package/src/product-render.ts +0 -218
  126. package/src/product-shape.ts +0 -49
  127. package/src/product-state.ts +0 -318
  128. package/src/product.ts +0 -308
  129. package/src/repeaters.ts +0 -161
  130. package/src/search.ts +0 -305
  131. package/src/selling-plans.ts +0 -145
  132. package/src/server.ts +0 -211
  133. package/src/shopify-values.ts +0 -91
  134. package/src/status.ts +0 -106
  135. package/src/storage.ts +0 -34
  136. package/src/store-html.ts +0 -359
  137. package/src/storefront/catalog.ts +0 -196
  138. package/src/storefront/json-ld.ts +0 -144
  139. package/src/variant-render.ts +0 -139
package/src/fragments.ts DELETED
@@ -1,261 +0,0 @@
1
- /**
2
- * The GraphQL fragments of what Tether renders. They are built at call time because the list sizes and metafields come
3
- * from the config; the browser passes its validated `cfg`, the server helpers their own. Operations put these after
4
- * the operation, where `withContext` expects them.
5
- */
6
- import { cfg } from './config.ts';
7
- import { toMetafieldIdentifier } from './config-sections.ts';
8
- import type { TetherConfig, MetafieldIdentifier } from './config.ts';
9
- import type { Money } from './shopify-values.ts';
10
- import type { StoreAccess } from './client.ts';
11
-
12
- export interface Image {
13
- url: string;
14
- altText: string | null;
15
- width: number | null;
16
- height: number | null;
17
- }
18
-
19
- /** An option value's swatch: a colour, an image, or both, as the merchant set them in the admin. */
20
- interface Swatch {
21
- color: string | null;
22
- image: { previewImage: Image | null } | null;
23
- }
24
-
25
- export type SellingPlanAdjustmentValue =
26
- | { __typename: 'SellingPlanPercentagePriceAdjustment'; adjustmentPercentage: number }
27
- | { __typename: 'SellingPlanFixedAmountPriceAdjustment'; adjustmentAmount: Money }
28
- | { __typename: 'SellingPlanFixedPriceAdjustment'; price: Money };
29
-
30
- export interface SellingPlan {
31
- id: string;
32
- name: string;
33
- description: string | null;
34
- recurringDeliveries: boolean;
35
- options: { name: string; value: string }[];
36
- priceAdjustments: { orderCount: number | null; adjustmentValue: SellingPlanAdjustmentValue }[];
37
- }
38
-
39
- export interface SellingPlanGroup {
40
- name: string;
41
- appName: string | null;
42
- options: { name: string; values: string[] }[];
43
- sellingPlans: { nodes: SellingPlan[] };
44
- }
45
-
46
- /** A variant's price on one plan. */
47
- export interface SellingPlanAllocation {
48
- sellingPlan: { id: string };
49
- /** What the customer pays at checkout (more for a prepaid plan). */
50
- checkoutChargeAmount: Money;
51
- remainingBalanceChargeAmount: Money;
52
- priceAdjustments: { price: Money; compareAtPrice: Money; perDeliveryPrice: Money; unitPrice: Money | null }[];
53
- }
54
-
55
- export interface ProductVariant {
56
- id: string;
57
- title: string;
58
- availableForSale: boolean;
59
- currentlyNotInStock: boolean;
60
- /** Absent when the store's token can't read inventory. */
61
- quantityAvailable?: number | null;
62
- sku: string | null;
63
- barcode: string | null;
64
- selectedOptions: { name: string; value: string }[];
65
- image: Image | null;
66
- price: Money;
67
- compareAtPrice: Money | null;
68
- unitPrice: Money | null;
69
- sellingPlanAllocations: { nodes: SellingPlanAllocation[] };
70
- }
71
-
72
- export interface Metafield {
73
- namespace: string;
74
- key: string;
75
- type: string;
76
- value: string;
77
- /** A file reference's image. */
78
- reference: { image?: Image } | null;
79
- }
80
-
81
- /** The fields of `fragment TetherProduct`. */
82
- export interface Product {
83
- id: string;
84
- handle: string;
85
- title: string;
86
- description: string;
87
- descriptionHtml: string;
88
- productType: string;
89
- vendor: string;
90
- tags: string[];
91
- availableForSale: boolean;
92
- publishedAt: string | null;
93
- onlineStoreUrl: string | null;
94
- requiresSellingPlan: boolean;
95
- seo: { title: string | null; description: string | null };
96
- featuredImage: Image | null;
97
- images: { nodes: Image[] };
98
- options: { name: string; optionValues: { name: string; swatch: Swatch | null }[] }[];
99
- priceRange: { minVariantPrice: Money; maxVariantPrice: Money };
100
- compareAtPriceRange: { minVariantPrice: Money; maxVariantPrice: Money };
101
- /** Present when metafields are configured; `null` for one that isn't set. */
102
- metafields?: (Metafield | null)[];
103
- sellingPlanGroups: { nodes: SellingPlanGroup[] };
104
- variants: { nodes: ProductVariant[] };
105
- }
106
-
107
- export type ProductFragmentConfig = Pick<
108
- TetherConfig,
109
- 'imagesFirst' | 'variantsFirst' | 'sellingPlanGroupsFirst' | 'sellingPlansFirst' | 'metafields'
110
- >;
111
-
112
- const MONEY = 'amount currencyCode';
113
- /** What a token reads unless the store turned out to refuse more (client.ts). */
114
- const FULL_ACCESS: StoreAccess = { inventory: true };
115
-
116
- /** The stock field, for a token that may read inventory. */
117
- const inventoryField = (access: StoreAccess): string => (access.inventory ? 'quantityAvailable' : '');
118
- const IMAGE = 'url altText width height';
119
-
120
- /**
121
- * The `metafields(identifiers:)` field. A fragment can't declare variables, so the identifiers are written into the
122
- * text: only valid ones (`toMetafieldIdentifier`), each quoted as a string literal.
123
- */
124
- function metafieldsField(metafields: ProductFragmentConfig['metafields']) {
125
- const identifiers: MetafieldIdentifier[] = [];
126
- for (const ref of metafields) {
127
- const identifier = toMetafieldIdentifier(ref);
128
- if (identifier) identifiers.push(identifier);
129
- }
130
- if (!identifiers.length) return '';
131
- const list = identifiers
132
- .map(({ namespace, key }) => `{namespace: ${JSON.stringify(namespace)}, key: ${JSON.stringify(key)}}`)
133
- .join(', ');
134
- return `metafields(identifiers: [${list}]) {
135
- namespace key type value
136
- reference { ... on MediaImage { image { ${IMAGE} } } }
137
- }`;
138
- }
139
-
140
- const SELLING_PLAN_FIELDS = `
141
- id name description recurringDeliveries
142
- options { name value }
143
- priceAdjustments {
144
- orderCount
145
- adjustmentValue {
146
- __typename
147
- ... on SellingPlanPercentagePriceAdjustment { adjustmentPercentage }
148
- ... on SellingPlanFixedAmountPriceAdjustment { adjustmentAmount { ${MONEY} } }
149
- ... on SellingPlanFixedPriceAdjustment { price { ${MONEY} } }
150
- }
151
- }`;
152
-
153
- const ALLOCATION_FIELDS = `
154
- sellingPlan { id }
155
- checkoutChargeAmount { ${MONEY} }
156
- remainingBalanceChargeAmount { ${MONEY} }
157
- priceAdjustments {
158
- price { ${MONEY} }
159
- compareAtPrice { ${MONEY} }
160
- perDeliveryPrice { ${MONEY} }
161
- unitPrice { ${MONEY} }
162
- }`;
163
-
164
- /**
165
- * @param o The list sizes and metafields.
166
- * @param access What the token may read.
167
- * @returns `fragment TetherProduct on Product`.
168
- */
169
- export function productFragment(o: ProductFragmentConfig = cfg, access: StoreAccess = FULL_ACCESS): string {
170
- return `
171
- fragment TetherProduct on Product {
172
- id handle title description descriptionHtml productType vendor tags
173
- availableForSale publishedAt onlineStoreUrl requiresSellingPlan
174
- seo { title description }
175
- featuredImage { ${IMAGE} }
176
- images(first: ${o.imagesFirst}) { nodes { ${IMAGE} } }
177
- options { name optionValues { name swatch { color image { previewImage { ${IMAGE} } } } } }
178
- priceRange { minVariantPrice { ${MONEY} } maxVariantPrice { ${MONEY} } }
179
- compareAtPriceRange { minVariantPrice { ${MONEY} } maxVariantPrice { ${MONEY} } }
180
- ${metafieldsField(o.metafields)}
181
- sellingPlanGroups(first: ${o.sellingPlanGroupsFirst}) {
182
- nodes {
183
- name appName
184
- options { name values }
185
- sellingPlans(first: ${o.sellingPlansFirst}) { nodes { ${SELLING_PLAN_FIELDS} } }
186
- }
187
- }
188
- variants(first: ${o.variantsFirst}) {
189
- nodes {
190
- id title availableForSale currentlyNotInStock ${inventoryField(access)} sku barcode
191
- selectedOptions { name value }
192
- image { ${IMAGE} }
193
- price { ${MONEY} }
194
- compareAtPrice { ${MONEY} }
195
- unitPrice { ${MONEY} }
196
- sellingPlanAllocations(first: ${o.sellingPlansFirst}) { nodes { ${ALLOCATION_FIELDS} } }
197
- }
198
- }
199
- }`;
200
- }
201
-
202
- /**
203
- * @param access What the token may read.
204
- * @returns `fragment TetherCart on Cart`.
205
- */
206
- export function cartFragment(access: StoreAccess = FULL_ACCESS): string {
207
- return `
208
- fragment TetherCart on Cart {
209
- id checkoutUrl totalQuantity note createdAt updatedAt
210
- attributes { key value }
211
- buyerIdentity { countryCode email }
212
- discountCodes { code applicable }
213
- cost {
214
- subtotalAmount { ${MONEY} }
215
- totalAmount { ${MONEY} }
216
- checkoutChargeAmount { ${MONEY} }
217
- }
218
- lines(first: 100) {
219
- nodes {
220
- id quantity
221
- attributes { key value }
222
- cost {
223
- totalAmount { ${MONEY} }
224
- subtotalAmount { ${MONEY} }
225
- amountPerQuantity { ${MONEY} }
226
- compareAtAmountPerQuantity { ${MONEY} }
227
- }
228
- discountAllocations { discountedAmount { ${MONEY} } }
229
- sellingPlanAllocation {
230
- sellingPlan { id name description recurringDeliveries options { name value } }
231
- checkoutChargeAmount { ${MONEY} }
232
- priceAdjustments { price { ${MONEY} } compareAtPrice { ${MONEY} } perDeliveryPrice { ${MONEY} } }
233
- }
234
- merchandise {
235
- ... on ProductVariant {
236
- id title sku availableForSale requiresShipping ${inventoryField(access)}
237
- image { ${IMAGE} }
238
- price { ${MONEY} }
239
- compareAtPrice { ${MONEY} }
240
- selectedOptions { name value }
241
- product { id title handle vendor featuredImage { ${IMAGE} } }
242
- }
243
- }
244
- ... on ComponentizableCartLine {
245
- lineComponents {
246
- id quantity
247
- merchandise { ... on ProductVariant { id title product { title handle } } }
248
- }
249
- }
250
- }
251
- }
252
- }`;
253
- }
254
-
255
- /** The collection fields Tether renders, for inside a `collection { }` selection. */
256
- export function collectionFields(): string {
257
- return `
258
- id handle title description descriptionHtml
259
- image { ${IMAGE} }
260
- seo { title description }`;
261
- }
package/src/globals.d.ts DELETED
@@ -1,15 +0,0 @@
1
- /**
2
- * What Tether reads from and sets on `window`, for sites that use the `<script>` build or `window.Tether`. Only the
3
- * published declarations carry it (scripts/build.ts adds it to the generated `index.d.ts`): the source reads these
4
- * names as unknown and validates them, so they stay out of its own program.
5
- */
6
- import type { Tether, TetherConfig } from './index.ts';
7
-
8
- declare global {
9
- interface Window {
10
- Tether: Tether;
11
- TETHER_CONFIG?: TetherConfig;
12
- TETHER_COUNTRY?: string;
13
- TETHER_LANGUAGE?: string;
14
- }
15
- }
package/src/images.ts DELETED
@@ -1,91 +0,0 @@
1
- /**
2
- * Shopify images on the page: sized through the CDN's URL parameters, written to an `<img>` or as a CSS background,
3
- * and never downloaded twice when the server already rendered the same image.
4
- */
5
- import { attr } from './markup.ts';
6
-
7
- /** Shopify CDN parameters. */
8
- export interface ImageSize {
9
- width?: string | number | null;
10
- height?: string | number | null;
11
- /** `center`, `top`, `bottom`, `left` or `right`; only applies with a width or height. */
12
- crop?: string | null;
13
- }
14
-
15
- /**
16
- * Shopify CDN image at a size: `imageUrl(url, { width: 800 })`. Use the same width as the element's max-width
17
- * attribute, so the browser script keeps the image instead of loading it again.
18
- *
19
- * @returns The sized URL; `url` itself when it is empty or not absolute.
20
- */
21
- export function imageUrl<Url extends string | null | undefined>(
22
- url: Url,
23
- { width, height, crop }: ImageSize = {},
24
- ): Url {
25
- if (!url) return url;
26
- let parsed;
27
- try {
28
- parsed = new URL(url);
29
- } catch (error) {
30
- // A relative or malformed URL has no CDN parameters to set: it is used as written.
31
- if (error instanceof TypeError) return url;
32
- throw error;
33
- }
34
- if (width) parsed.searchParams.set('width', String(width));
35
- if (height) parsed.searchParams.set('height', String(height));
36
- if (crop) parsed.searchParams.set('crop', crop);
37
- // `url` is a non-empty string here, so `Url` is a string type.
38
- return parsed.toString() as Url;
39
- }
40
-
41
- /** @returns `name` as Webflow's custom attribute, or in valid HTML as `<prefix>-name` / `data-name`. */
42
- function sizeAttribute(el: Element, name: string): string | null {
43
- return el.getAttribute(name) ?? el.getAttribute(attr(name)) ?? el.getAttribute(`data-${name}`);
44
- }
45
-
46
- /** @param el The element whose max-width / max-height / crop attributes size the image. */
47
- export function cdnUrl<Url extends string | null | undefined>(url: Url, el: Element | null | undefined): Url {
48
- if (!url || !el) return url;
49
- const width = sizeAttribute(el, 'max-width');
50
- const height = sizeAttribute(el, 'max-height');
51
- return imageUrl(url, { width, height, crop: width || height ? sizeAttribute(el, 'crop') : null });
52
- }
53
-
54
- /** @returns The URL without its query (the size parameters). */
55
- const withoutQuery = (url: string) => url.replace(/\?.*$/, '');
56
-
57
- /** @returns True for the same image at any size parameters: the server-rendered one is kept. */
58
- export function sameImage(a: string | null | undefined, b: string | null | undefined): boolean {
59
- if (!a || !b) return false;
60
- return withoutQuery(a) === withoutQuery(b);
61
- }
62
-
63
- /**
64
- * A CSS `url()` for an image URL from Shopify. Characters that would end the string are escaped, so the URL can't
65
- * add declarations; only http(s), relative and data:image URLs are used.
66
- */
67
- function cssUrl(url: string): string {
68
- const hasScheme = /^\s*[a-z][a-z0-9+.-]*:/i.test(url);
69
- if (hasScheme && !/^\s*(https?:|data:image\/)/i.test(url)) return 'none';
70
- const escaped = url.replace(/["\\\n\r\f]/g, (char) => `\\${char.charCodeAt(0).toString(16)} `);
71
- return `url("${escaped}")`;
72
- }
73
-
74
- /** Shows `url` in `el`: as the `src` of an `<img>` (lazy unless it says otherwise), else as its background image. */
75
- export function setImage(el: HTMLElement, url: string | null | undefined, alt?: string | null): void {
76
- if (!url) return;
77
- const src = cdnUrl(url, el);
78
- if (el.tagName !== 'IMG') {
79
- el.style.backgroundImage = cssUrl(src);
80
- return;
81
- }
82
- if (sameImage(el.getAttribute('src'), src)) {
83
- if (alt != null && !el.getAttribute('alt')) el.setAttribute('alt', alt);
84
- return;
85
- }
86
- el.removeAttribute('srcset');
87
- el.removeAttribute('sizes');
88
- el.setAttribute('src', src);
89
- if (alt != null) el.setAttribute('alt', alt);
90
- if (!el.getAttribute('loading')) el.setAttribute('loading', 'lazy');
91
- }