shopify 3.93.2 → 3.94.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/dist/assets/dev-console/extensions/dev-console/assets/index-Bm_GpKQW.js +51 -0
- package/dist/assets/dev-console/index.html +1 -1
- package/dist/assets/hydrogen/starter/CHANGELOG.md +0 -64
- package/dist/assets/hydrogen/starter/app/components/Aside.tsx +2 -4
- package/dist/assets/hydrogen/starter/app/components/CartMain.tsx +3 -6
- package/dist/assets/hydrogen/starter/app/components/CartSummary.tsx +23 -117
- package/dist/assets/hydrogen/starter/app/components/Header.tsx +3 -3
- package/dist/assets/hydrogen/starter/app/components/PaginatedResourceSection.tsx +4 -24
- package/dist/assets/hydrogen/starter/app/components/ProductPrice.tsx +1 -1
- package/dist/assets/hydrogen/starter/app/routes/[robots.txt].tsx +53 -14
- package/dist/assets/hydrogen/starter/app/routes/_index.tsx +4 -11
- package/dist/assets/hydrogen/starter/app/routes/account.$.tsx +1 -1
- package/dist/assets/hydrogen/starter/app/routes/account.addresses.tsx +2 -2
- package/dist/assets/hydrogen/starter/app/routes/account.profile.tsx +1 -1
- package/dist/assets/hydrogen/starter/app/routes/api.$version.[graphql.json].tsx +14 -0
- package/dist/assets/hydrogen/starter/package.json +5 -5
- package/dist/assets/hydrogen/starter/storefrontapi.generated.d.ts +11 -0
- package/dist/assets/hydrogen/starter/vite.config.ts +1 -1
- package/dist/assets/hydrogen/vite/vite.config.js +1 -1
- package/dist/chunk-52KHWFYF.js +1 -0
- package/dist/chunk-7F3HZJH4.js +3 -0
- package/dist/{chunk-4VZV4LQX.js → chunk-7JFIBCHH.js} +66 -66
- package/dist/{chunk-MX6WWR5F.js → chunk-AQOYGO3U.js} +16 -16
- package/dist/{chunk-IG47ZDRU.js → chunk-DBDY2YEY.js} +1 -1
- package/dist/chunk-DEW5QFGH.js +415 -0
- package/dist/chunk-FU2Y2M3M.js +5 -0
- package/dist/chunk-JBSYWYIP.js +2 -0
- package/dist/chunk-QYR5VPQA.js +4 -0
- package/dist/{chunk-5FCKEHCK.js → chunk-R6N4NGU6.js} +154 -154
- package/dist/{chunk-XVFYDYZA.js → chunk-SVA22NZQ.js} +209 -211
- package/dist/cli/commands/config/autoupgrade/constants.d.ts +5 -0
- package/dist/cli/commands/config/autoupgrade/constants.js +6 -0
- package/dist/cli/commands/config/autoupgrade/off.d.ts +7 -0
- package/dist/cli/commands/config/autoupgrade/off.js +22 -0
- package/dist/cli/commands/config/autoupgrade/on.d.ts +7 -0
- package/dist/cli/commands/config/autoupgrade/on.js +22 -0
- package/dist/cli/commands/config/autoupgrade/status.d.ts +7 -0
- package/dist/cli/commands/config/autoupgrade/status.js +30 -0
- package/dist/cli/commands/docs/generate.d.ts +1 -1
- package/dist/cli/commands/docs/generate.js +6 -3
- package/dist/cli/commands/upgrade.js +3 -1
- package/dist/cli/services/kitchen-sink/static.js +1 -1
- package/dist/configs/all.yml +3 -0
- package/dist/configs/recommended.yml +3 -0
- package/dist/data/filters.json +30 -0
- package/dist/data/objects.json +17 -1
- package/dist/data/setting.json +25 -0
- package/dist/data/shopify_system_translations.json +29 -6
- package/dist/error-handler-JHFQZGYG.js +1 -0
- package/dist/hooks/postrun.js +1 -1
- package/dist/hooks/prerun.js +1 -1
- package/dist/{http-proxy-node16-DSQMBVDI.js → http-proxy-node16-TTURN6MD.js} +1 -1
- package/dist/index.js +1117 -1121
- package/dist/lib-3WHF5XD3.js +1 -0
- package/dist/{local-WHQ3ZS4K.js → local-4PW2CHVR.js} +1 -1
- package/dist/{morph-Q32V442A.js → morph-DQREIZD2.js} +1 -1
- package/dist/node-package-manager-NTQEYCSE.js +1 -0
- package/dist/path-HUAU3YBW.js +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/{ui-GZ7DOSHP.js → ui-7Z2HOOEO.js} +1 -1
- package/dist/{workerd-LJU6AVMQ.js → workerd-VL54JTEU.js} +1 -1
- package/oclif.manifest.json +65 -4
- package/package.json +8 -7
- package/dist/assets/dev-console/extensions/dev-console/assets/index-BnXVL6nA.js +0 -78
- package/dist/chunk-4QL77VYJ.js +0 -415
- package/dist/chunk-DDTYWTF2.js +0 -1
- package/dist/chunk-FYQIRCLV.js +0 -5
- package/dist/chunk-NOSKVZWJ.js +0 -2
- package/dist/chunk-QJEBL3WX.js +0 -4
- package/dist/cli/commands/store/auth.d.ts +0 -15
- package/dist/cli/commands/store/auth.js +0 -46
- package/dist/cli/commands/store/execute.d.ts +0 -21
- package/dist/cli/commands/store/execute.js +0 -89
- package/dist/cli/services/store/auth/callback.d.ts +0 -8
- package/dist/cli/services/store/auth/callback.js +0 -140
- package/dist/cli/services/store/auth/config.d.ts +0 -6
- package/dist/cli/services/store/auth/config.js +0 -15
- package/dist/cli/services/store/auth/existing-scopes.d.ts +0 -5
- package/dist/cli/services/store/auth/existing-scopes.js +0 -40
- package/dist/cli/services/store/auth/index.d.ts +0 -18
- package/dist/cli/services/store/auth/index.js +0 -88
- package/dist/cli/services/store/auth/pkce.d.ts +0 -36
- package/dist/cli/services/store/auth/pkce.js +0 -49
- package/dist/cli/services/store/auth/recovery.d.ts +0 -4
- package/dist/cli/services/store/auth/recovery.js +0 -17
- package/dist/cli/services/store/auth/result.d.ts +0 -24
- package/dist/cli/services/store/auth/result.js +0 -39
- package/dist/cli/services/store/auth/scopes.d.ts +0 -4
- package/dist/cli/services/store/auth/scopes.js +0 -53
- package/dist/cli/services/store/auth/session-lifecycle.d.ts +0 -3
- package/dist/cli/services/store/auth/session-lifecycle.js +0 -69
- package/dist/cli/services/store/auth/session-store.d.ts +0 -32
- package/dist/cli/services/store/auth/session-store.js +0 -127
- package/dist/cli/services/store/auth/token-client.d.ts +0 -40
- package/dist/cli/services/store/auth/token-client.js +0 -95
- package/dist/cli/services/store/execute/admin-context.d.ts +0 -11
- package/dist/cli/services/store/execute/admin-context.js +0 -41
- package/dist/cli/services/store/execute/admin-transport.d.ts +0 -6
- package/dist/cli/services/store/execute/admin-transport.js +0 -42
- package/dist/cli/services/store/execute/index.d.ts +0 -13
- package/dist/cli/services/store/execute/index.js +0 -22
- package/dist/cli/services/store/execute/request.d.ts +0 -21
- package/dist/cli/services/store/execute/request.js +0 -88
- package/dist/cli/services/store/execute/result.d.ts +0 -3
- package/dist/cli/services/store/execute/result.js +0 -29
- package/dist/cli/services/store/execute/targets.d.ts +0 -18
- package/dist/cli/services/store/execute/targets.js +0 -21
- package/dist/error-handler-GZ2I7BG5.js +0 -1
- package/dist/lib-GGVLMXY5.js +0 -1
- package/dist/node-package-manager-6XMPTNUI.js +0 -1
- package/dist/path-IT7KPARG.js +0 -1
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
<meta name="theme-color" content="#ffffff">
|
|
13
13
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
14
14
|
<title>UI Extensions DevConsole</title>
|
|
15
|
-
<script type="module" crossorigin src="/extensions/dev-console/assets/index-
|
|
15
|
+
<script type="module" crossorigin src="/extensions/dev-console/assets/index-Bm_GpKQW.js"></script>
|
|
16
16
|
<link rel="stylesheet" crossorigin href="/extensions/dev-console/assets/index-DISeE29z.css">
|
|
17
17
|
</head>
|
|
18
18
|
<body>
|
|
@@ -1,69 +1,5 @@
|
|
|
1
1
|
# skeleton
|
|
2
2
|
|
|
3
|
-
## 2026.4.0
|
|
4
|
-
|
|
5
|
-
### Major Changes
|
|
6
|
-
|
|
7
|
-
- Update Storefront API and Customer Account API from 2026-01 to 2026-04. ([#3651](https://github.com/Shopify/hydrogen/pull/3651)) by [@itsjustriley](https://github.com/itsjustriley)
|
|
8
|
-
|
|
9
|
-
## Breaking changes
|
|
10
|
-
|
|
11
|
-
**JSON metafield values limited to 128KB**: When using API version 2026-04 or later, the Storefront API limits JSON type metafield writes to 128KB. This limit applies at the API level - Hydrogen passes through to the Storefront API without additional restriction. Apps that used JSON metafields before April 1, 2026 are grandfathered at the existing 2MB limit. Large metafield values continue to be readable by all API versions.
|
|
12
|
-
|
|
13
|
-
## New features
|
|
14
|
-
|
|
15
|
-
**New `MERCHANDISE_LINE_TRANSFORMERS_RUN_ERROR` cart error code**: Cart operations (`cartCreate`, `cartLinesAdd`, etc.) now return a specific `MERCHANDISE_LINE_TRANSFORMERS_RUN_ERROR` error code when a Cart Transform Function fails at runtime, instead of the previous generic `INVALID` error code. If you handle cart errors in your storefront code, you may want to add handling for this new code.
|
|
16
|
-
|
|
17
|
-
## Changelog links
|
|
18
|
-
- [Storefront API 2026-04 changelog](https://shopify.dev/changelog?filter=api&api_version=2026-04&api_type=storefront-graphql)
|
|
19
|
-
- [Customer Account API 2026-04 changelog](https://shopify.dev/changelog?filter=api&api_version=2026-04&api_type=customer-account-graphql)
|
|
20
|
-
|
|
21
|
-
### Patch Changes
|
|
22
|
-
|
|
23
|
-
- Updated dependencies [[`e7215ed0d7a74cacfa8c935f414c1cf32fc2ccd0`](https://github.com/Shopify/hydrogen/commit/e7215ed0d7a74cacfa8c935f414c1cf32fc2ccd0), [`92ab8e8b59807bbdb5dbecaa18629292d5566135`](https://github.com/Shopify/hydrogen/commit/92ab8e8b59807bbdb5dbecaa18629292d5566135), [`b0caa5c013380c7837f049f48da089a1671e2c6d`](https://github.com/Shopify/hydrogen/commit/b0caa5c013380c7837f049f48da089a1671e2c6d)]:
|
|
24
|
-
- @shopify/hydrogen@2026.4.0
|
|
25
|
-
|
|
26
|
-
## 2026.1.4
|
|
27
|
-
|
|
28
|
-
### Patch Changes
|
|
29
|
-
|
|
30
|
-
- Remove redundant Storefront API proxy route from skeleton template. The server now automatically proxies requests to `/api/:version/graphql.json` via `createRequestHandler` with `proxyStandardRoutes: true` (enabled by default since December 2025). ([#3572](https://github.com/Shopify/hydrogen/pull/3572)) by [@itsjustriley](https://github.com/itsjustriley)
|
|
31
|
-
|
|
32
|
-
Developers no longer need a manual route file for the tokenless Storefront API. Existing apps with this route can safely delete it - the server-level proxy provides the same functionality with better cookie forwarding and analytics integration.
|
|
33
|
-
|
|
34
|
-
- Updated dependencies [[`b0a75c1d759706931876f056662de2497cb3e688`](https://github.com/Shopify/hydrogen/commit/b0a75c1d759706931876f056662de2497cb3e688), [`a44ee3566b9bb9a7f43f05dfaae6f1f2ab1d548f`](https://github.com/Shopify/hydrogen/commit/a44ee3566b9bb9a7f43f05dfaae6f1f2ab1d548f)]:
|
|
35
|
-
- @shopify/hydrogen@2026.1.4
|
|
36
|
-
|
|
37
|
-
## 2026.1.3
|
|
38
|
-
|
|
39
|
-
### Patch Changes
|
|
40
|
-
|
|
41
|
-
- Improve screen reader experience for paginated product grids by hiding decorative arrow characters from assistive technology. ([#3557](https://github.com/Shopify/hydrogen/pull/3557)) by [@itsjustriley](https://github.com/itsjustriley)
|
|
42
|
-
|
|
43
|
-
- Fix broken `aria-label` on territory code input in address form. The label was the raw developer string `"territoryCode"` instead of a human-readable `"Country code"`. ([#3607](https://github.com/Shopify/hydrogen/pull/3607)) by [@itsjustriley](https://github.com/itsjustriley)
|
|
44
|
-
|
|
45
|
-
- Add aria-label to ProductPrice for improved screen reader accessibility ([#3558](https://github.com/Shopify/hydrogen/pull/3558)) by [@itsjustriley](https://github.com/itsjustriley)
|
|
46
|
-
|
|
47
|
-
- Updated dependencies [[`108243003a7f36349a446478f4e8ab0cade3e13a`](https://github.com/Shopify/hydrogen/commit/108243003a7f36349a446478f4e8ab0cade3e13a)]:
|
|
48
|
-
- @shopify/hydrogen@2026.1.3
|
|
49
|
-
|
|
50
|
-
## 2026.1.2
|
|
51
|
-
|
|
52
|
-
### Patch Changes
|
|
53
|
-
|
|
54
|
-
- Improve gift card accessibility in Skeleton template ([#3518](https://github.com/Shopify/hydrogen/pull/3518)) by [@itsjustriley](https://github.com/itsjustriley)
|
|
55
|
-
|
|
56
|
-
- Updated shopify/cli dependencies for cli-hydrogen ([#3553](https://github.com/Shopify/hydrogen/pull/3553)) by [@andguy95](https://github.com/andguy95)
|
|
57
|
-
|
|
58
|
-
- Updated loaders that used `customerAccount.handleAuthStatus()` to now await it. ([#3523](https://github.com/Shopify/hydrogen/pull/3523)) by [@fredericoo](https://github.com/fredericoo)
|
|
59
|
-
|
|
60
|
-
### Migration
|
|
61
|
-
|
|
62
|
-
If you call `handleAuthStatus()` in your own loaders, update those callsites to use `await`.
|
|
63
|
-
|
|
64
|
-
- Updated dependencies [[`16b0e7baca0dfd1fb330d12dac924c7593d169a8`](https://github.com/Shopify/hydrogen/commit/16b0e7baca0dfd1fb330d12dac924c7593d169a8), [`1c19b87782818dbdb4252754d2d44eb9a44fe50f`](https://github.com/Shopify/hydrogen/commit/1c19b87782818dbdb4252754d2d44eb9a44fe50f), [`029fa2d0e2297f67b37c650ba8e875ee5dee81b3`](https://github.com/Shopify/hydrogen/commit/029fa2d0e2297f67b37c650ba8e875ee5dee81b3)]:
|
|
65
|
-
- @shopify/hydrogen@2026.1.2
|
|
66
|
-
|
|
67
3
|
## 2026.1.1
|
|
68
4
|
|
|
69
5
|
### Patch Changes
|
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
useEffect,
|
|
6
6
|
useState,
|
|
7
7
|
} from 'react';
|
|
8
|
-
import {useId} from 'react';
|
|
9
8
|
|
|
10
9
|
type AsideType = 'search' | 'cart' | 'mobile' | 'closed';
|
|
11
10
|
type AsideContextValue = {
|
|
@@ -35,7 +34,7 @@ export function Aside({
|
|
|
35
34
|
}) {
|
|
36
35
|
const {type: activeType, close} = useAside();
|
|
37
36
|
const expanded = type === activeType;
|
|
38
|
-
|
|
37
|
+
|
|
39
38
|
useEffect(() => {
|
|
40
39
|
const abortController = new AbortController();
|
|
41
40
|
|
|
@@ -58,12 +57,11 @@ export function Aside({
|
|
|
58
57
|
aria-modal
|
|
59
58
|
className={`overlay ${expanded ? 'expanded' : ''}`}
|
|
60
59
|
role="dialog"
|
|
61
|
-
aria-labelledby={id}
|
|
62
60
|
>
|
|
63
61
|
<button className="close-outside" onClick={close} />
|
|
64
62
|
<aside>
|
|
65
63
|
<header>
|
|
66
|
-
<h3
|
|
64
|
+
<h3>{heading}</h3>
|
|
67
65
|
<button className="close reset" onClick={close} aria-label="Close">
|
|
68
66
|
×
|
|
69
67
|
</button>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {useOptimisticCart} from '@shopify/hydrogen';
|
|
1
|
+
import {useOptimisticCart, type OptimisticCartLine} from '@shopify/hydrogen';
|
|
2
2
|
import {Link} from 'react-router';
|
|
3
3
|
import type {CartApiQueryFragment} from 'storefrontapi.generated';
|
|
4
4
|
import {useAside} from '~/components/Aside';
|
|
@@ -50,10 +50,7 @@ export function CartMain({layout, cart: originalCart}: CartMainProps) {
|
|
|
50
50
|
const childrenMap = getLineItemChildrenMap(cart?.lines?.nodes ?? []);
|
|
51
51
|
|
|
52
52
|
return (
|
|
53
|
-
<
|
|
54
|
-
className={className}
|
|
55
|
-
aria-label={layout === 'page' ? 'Cart page' : 'Cart drawer'}
|
|
56
|
-
>
|
|
53
|
+
<div className={className}>
|
|
57
54
|
<CartEmpty hidden={linesCount} layout={layout} />
|
|
58
55
|
<div className="cart-details">
|
|
59
56
|
<p id="cart-lines" className="sr-only">
|
|
@@ -82,7 +79,7 @@ export function CartMain({layout, cart: originalCart}: CartMainProps) {
|
|
|
82
79
|
</div>
|
|
83
80
|
{cartHasItems && <CartSummary cart={cart} layout={layout} />}
|
|
84
81
|
</div>
|
|
85
|
-
</
|
|
82
|
+
</div>
|
|
86
83
|
);
|
|
87
84
|
}
|
|
88
85
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type {CartApiQueryFragment} from 'storefrontapi.generated';
|
|
2
2
|
import type {CartLayout} from '~/components/CartMain';
|
|
3
3
|
import {CartForm, Money, type OptimisticCart} from '@shopify/hydrogen';
|
|
4
|
-
import {useEffect,
|
|
4
|
+
import {useEffect, useRef} from 'react';
|
|
5
5
|
import {useFetcher} from 'react-router';
|
|
6
6
|
|
|
7
7
|
type CartSummaryProps = {
|
|
@@ -12,16 +12,11 @@ type CartSummaryProps = {
|
|
|
12
12
|
export function CartSummary({cart, layout}: CartSummaryProps) {
|
|
13
13
|
const className =
|
|
14
14
|
layout === 'page' ? 'cart-summary-page' : 'cart-summary-aside';
|
|
15
|
-
const summaryId = useId();
|
|
16
|
-
const discountsHeadingId = useId();
|
|
17
|
-
const discountCodeInputId = useId();
|
|
18
|
-
const giftCardHeadingId = useId();
|
|
19
|
-
const giftCardInputId = useId();
|
|
20
15
|
|
|
21
16
|
return (
|
|
22
|
-
<div aria-labelledby=
|
|
23
|
-
<h4
|
|
24
|
-
<dl
|
|
17
|
+
<div aria-labelledby="cart-summary" className={className}>
|
|
18
|
+
<h4>Totals</h4>
|
|
19
|
+
<dl className="cart-subtotal">
|
|
25
20
|
<dt>Subtotal</dt>
|
|
26
21
|
<dd>
|
|
27
22
|
{cart?.cost?.subtotalAmount?.amount ? (
|
|
@@ -31,16 +26,8 @@ export function CartSummary({cart, layout}: CartSummaryProps) {
|
|
|
31
26
|
)}
|
|
32
27
|
</dd>
|
|
33
28
|
</dl>
|
|
34
|
-
<CartDiscounts
|
|
35
|
-
|
|
36
|
-
discountsHeadingId={discountsHeadingId}
|
|
37
|
-
discountCodeInputId={discountCodeInputId}
|
|
38
|
-
/>
|
|
39
|
-
<CartGiftCard
|
|
40
|
-
giftCardCodes={cart?.appliedGiftCards}
|
|
41
|
-
giftCardHeadingId={giftCardHeadingId}
|
|
42
|
-
giftCardInputId={giftCardInputId}
|
|
43
|
-
/>
|
|
29
|
+
<CartDiscounts discountCodes={cart?.discountCodes} />
|
|
30
|
+
<CartGiftCard giftCardCodes={cart?.appliedGiftCards} />
|
|
44
31
|
<CartCheckoutActions checkoutUrl={cart?.checkoutUrl} />
|
|
45
32
|
</div>
|
|
46
33
|
);
|
|
@@ -61,12 +48,8 @@ function CartCheckoutActions({checkoutUrl}: {checkoutUrl?: string}) {
|
|
|
61
48
|
|
|
62
49
|
function CartDiscounts({
|
|
63
50
|
discountCodes,
|
|
64
|
-
discountsHeadingId,
|
|
65
|
-
discountCodeInputId,
|
|
66
51
|
}: {
|
|
67
52
|
discountCodes?: CartApiQueryFragment['discountCodes'];
|
|
68
|
-
discountsHeadingId: string;
|
|
69
|
-
discountCodeInputId: string;
|
|
70
53
|
}) {
|
|
71
54
|
const codes: string[] =
|
|
72
55
|
discountCodes
|
|
@@ -74,17 +57,13 @@ function CartDiscounts({
|
|
|
74
57
|
?.map(({code}) => code) || [];
|
|
75
58
|
|
|
76
59
|
return (
|
|
77
|
-
<
|
|
60
|
+
<div>
|
|
78
61
|
{/* Have existing discount, display it with a remove option */}
|
|
79
62
|
<dl hidden={!codes.length}>
|
|
80
63
|
<div>
|
|
81
|
-
<dt
|
|
64
|
+
<dt>Discount(s)</dt>
|
|
82
65
|
<UpdateDiscountForm>
|
|
83
|
-
<div
|
|
84
|
-
className="cart-discount"
|
|
85
|
-
role="group"
|
|
86
|
-
aria-labelledby={discountsHeadingId}
|
|
87
|
-
>
|
|
66
|
+
<div className="cart-discount">
|
|
88
67
|
<code>{codes?.join(', ')}</code>
|
|
89
68
|
|
|
90
69
|
<button type="submit" aria-label="Remove discount">
|
|
@@ -98,11 +77,11 @@ function CartDiscounts({
|
|
|
98
77
|
{/* Show an input to apply a discount */}
|
|
99
78
|
<UpdateDiscountForm discountCodes={codes}>
|
|
100
79
|
<div>
|
|
101
|
-
<label htmlFor=
|
|
80
|
+
<label htmlFor="discount-code-input" className="sr-only">
|
|
102
81
|
Discount code
|
|
103
82
|
</label>
|
|
104
83
|
<input
|
|
105
|
-
id=
|
|
84
|
+
id="discount-code-input"
|
|
106
85
|
type="text"
|
|
107
86
|
name="discountCode"
|
|
108
87
|
placeholder="Discount code"
|
|
@@ -113,7 +92,7 @@ function CartDiscounts({
|
|
|
113
92
|
</button>
|
|
114
93
|
</div>
|
|
115
94
|
</UpdateDiscountForm>
|
|
116
|
-
</
|
|
95
|
+
</div>
|
|
117
96
|
);
|
|
118
97
|
}
|
|
119
98
|
|
|
@@ -139,110 +118,52 @@ function UpdateDiscountForm({
|
|
|
139
118
|
|
|
140
119
|
function CartGiftCard({
|
|
141
120
|
giftCardCodes,
|
|
142
|
-
giftCardHeadingId,
|
|
143
|
-
giftCardInputId,
|
|
144
121
|
}: {
|
|
145
122
|
giftCardCodes: CartApiQueryFragment['appliedGiftCards'] | undefined;
|
|
146
|
-
giftCardHeadingId: string;
|
|
147
|
-
giftCardInputId: string;
|
|
148
123
|
}) {
|
|
149
124
|
const giftCardCodeInput = useRef<HTMLInputElement>(null);
|
|
150
|
-
const removeButtonRefs = useRef<Map<string, HTMLButtonElement>>(new Map());
|
|
151
|
-
const previousCardIdsRef = useRef<string[]>([]);
|
|
152
125
|
const giftCardAddFetcher = useFetcher({key: 'gift-card-add'});
|
|
153
|
-
const [removedCardIndex, setRemovedCardIndex] = useState<number | null>(null);
|
|
154
126
|
|
|
155
127
|
useEffect(() => {
|
|
156
128
|
if (giftCardAddFetcher.data) {
|
|
157
|
-
|
|
158
|
-
giftCardCodeInput.current.value = '';
|
|
159
|
-
}
|
|
129
|
+
giftCardCodeInput.current!.value = '';
|
|
160
130
|
}
|
|
161
131
|
}, [giftCardAddFetcher.data]);
|
|
162
132
|
|
|
163
|
-
useEffect(() => {
|
|
164
|
-
const currentCardIds = giftCardCodes?.map((card) => card.id) || [];
|
|
165
|
-
|
|
166
|
-
if (removedCardIndex !== null && giftCardCodes) {
|
|
167
|
-
const focusTargetIndex = Math.min(
|
|
168
|
-
removedCardIndex,
|
|
169
|
-
giftCardCodes.length - 1,
|
|
170
|
-
);
|
|
171
|
-
const focusTargetCard = giftCardCodes[focusTargetIndex];
|
|
172
|
-
const focusButton = focusTargetCard
|
|
173
|
-
? removeButtonRefs.current.get(focusTargetCard.id)
|
|
174
|
-
: null;
|
|
175
|
-
|
|
176
|
-
if (focusButton) {
|
|
177
|
-
focusButton.focus();
|
|
178
|
-
} else if (giftCardCodeInput.current) {
|
|
179
|
-
giftCardCodeInput.current.focus();
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
setRemovedCardIndex(null);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
previousCardIdsRef.current = currentCardIds;
|
|
186
|
-
}, [giftCardCodes, removedCardIndex]);
|
|
187
|
-
|
|
188
|
-
const handleRemoveClick = (cardId: string) => {
|
|
189
|
-
const index = previousCardIdsRef.current.indexOf(cardId);
|
|
190
|
-
if (index !== -1) {
|
|
191
|
-
setRemovedCardIndex(index);
|
|
192
|
-
}
|
|
193
|
-
};
|
|
194
|
-
|
|
195
133
|
return (
|
|
196
|
-
<
|
|
134
|
+
<div>
|
|
197
135
|
{giftCardCodes && giftCardCodes.length > 0 && (
|
|
198
136
|
<dl>
|
|
199
|
-
<dt
|
|
137
|
+
<dt>Applied Gift Card(s)</dt>
|
|
200
138
|
{giftCardCodes.map((giftCard) => (
|
|
201
|
-
<
|
|
202
|
-
<
|
|
203
|
-
giftCardId={giftCard.id}
|
|
204
|
-
lastCharacters={giftCard.lastCharacters}
|
|
205
|
-
onRemoveClick={() => handleRemoveClick(giftCard.id)}
|
|
206
|
-
buttonRef={(el: HTMLButtonElement | null) => {
|
|
207
|
-
if (el) {
|
|
208
|
-
removeButtonRefs.current.set(giftCard.id, el);
|
|
209
|
-
} else {
|
|
210
|
-
removeButtonRefs.current.delete(giftCard.id);
|
|
211
|
-
}
|
|
212
|
-
}}
|
|
213
|
-
>
|
|
139
|
+
<RemoveGiftCardForm key={giftCard.id} giftCardId={giftCard.id}>
|
|
140
|
+
<div className="cart-discount">
|
|
214
141
|
<code>***{giftCard.lastCharacters}</code>
|
|
215
142
|
|
|
216
143
|
<Money data={giftCard.amountUsed} />
|
|
217
|
-
|
|
218
|
-
|
|
144
|
+
|
|
145
|
+
<button type="submit">Remove</button>
|
|
146
|
+
</div>
|
|
147
|
+
</RemoveGiftCardForm>
|
|
219
148
|
))}
|
|
220
149
|
</dl>
|
|
221
150
|
)}
|
|
222
151
|
|
|
223
152
|
<AddGiftCardForm fetcherKey="gift-card-add">
|
|
224
153
|
<div>
|
|
225
|
-
<label htmlFor={giftCardInputId} className="sr-only">
|
|
226
|
-
Gift card code
|
|
227
|
-
</label>
|
|
228
154
|
<input
|
|
229
|
-
id={giftCardInputId}
|
|
230
155
|
type="text"
|
|
231
156
|
name="giftCardCode"
|
|
232
157
|
placeholder="Gift card code"
|
|
233
158
|
ref={giftCardCodeInput}
|
|
234
159
|
/>
|
|
235
160
|
|
|
236
|
-
<button
|
|
237
|
-
type="submit"
|
|
238
|
-
disabled={giftCardAddFetcher.state !== 'idle'}
|
|
239
|
-
aria-label="Apply gift card code"
|
|
240
|
-
>
|
|
161
|
+
<button type="submit" disabled={giftCardAddFetcher.state !== 'idle'}>
|
|
241
162
|
Apply
|
|
242
163
|
</button>
|
|
243
164
|
</div>
|
|
244
165
|
</AddGiftCardForm>
|
|
245
|
-
</
|
|
166
|
+
</div>
|
|
246
167
|
);
|
|
247
168
|
}
|
|
248
169
|
|
|
@@ -266,16 +187,10 @@ function AddGiftCardForm({
|
|
|
266
187
|
|
|
267
188
|
function RemoveGiftCardForm({
|
|
268
189
|
giftCardId,
|
|
269
|
-
lastCharacters,
|
|
270
190
|
children,
|
|
271
|
-
onRemoveClick,
|
|
272
|
-
buttonRef,
|
|
273
191
|
}: {
|
|
274
192
|
giftCardId: string;
|
|
275
|
-
lastCharacters: string;
|
|
276
193
|
children: React.ReactNode;
|
|
277
|
-
onRemoveClick?: () => void;
|
|
278
|
-
buttonRef?: (el: HTMLButtonElement | null) => void;
|
|
279
194
|
}) {
|
|
280
195
|
return (
|
|
281
196
|
<CartForm
|
|
@@ -286,15 +201,6 @@ function RemoveGiftCardForm({
|
|
|
286
201
|
}}
|
|
287
202
|
>
|
|
288
203
|
{children}
|
|
289
|
-
|
|
290
|
-
<button
|
|
291
|
-
type="submit"
|
|
292
|
-
aria-label={`Remove gift card ending in ${lastCharacters}`}
|
|
293
|
-
onClick={onRemoveClick}
|
|
294
|
-
ref={buttonRef}
|
|
295
|
-
>
|
|
296
|
-
Remove
|
|
297
|
-
</button>
|
|
298
204
|
</CartForm>
|
|
299
205
|
);
|
|
300
206
|
}
|
|
@@ -136,7 +136,7 @@ function SearchToggle() {
|
|
|
136
136
|
);
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
-
function CartBadge({count}: {count: number}) {
|
|
139
|
+
function CartBadge({count}: {count: number | null}) {
|
|
140
140
|
const {open} = useAside();
|
|
141
141
|
const {publish, shop, cart, prevCart} = useAnalytics();
|
|
142
142
|
|
|
@@ -154,14 +154,14 @@ function CartBadge({count}: {count: number}) {
|
|
|
154
154
|
} as CartViewPayload);
|
|
155
155
|
}}
|
|
156
156
|
>
|
|
157
|
-
Cart <span
|
|
157
|
+
Cart {count === null ? <span> </span> : count}
|
|
158
158
|
</a>
|
|
159
159
|
);
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
function CartToggle({cart}: Pick<HeaderProps, 'cart'>) {
|
|
163
163
|
return (
|
|
164
|
-
<Suspense fallback={<CartBadge count={
|
|
164
|
+
<Suspense fallback={<CartBadge count={null} />}>
|
|
165
165
|
<Await resolve={cart}>
|
|
166
166
|
<CartBanner />
|
|
167
167
|
</Await>
|
|
@@ -2,17 +2,15 @@ import * as React from 'react';
|
|
|
2
2
|
import {Pagination} from '@shopify/hydrogen';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* <PaginatedResourceSection>
|
|
5
|
+
* <PaginatedResourceSection > is a component that encapsulate how the previous and next behaviors throughout your application.
|
|
6
6
|
*/
|
|
7
7
|
export function PaginatedResourceSection<NodesType>({
|
|
8
8
|
connection,
|
|
9
9
|
children,
|
|
10
|
-
ariaLabel,
|
|
11
10
|
resourcesClassName,
|
|
12
11
|
}: {
|
|
13
12
|
connection: React.ComponentProps<typeof Pagination<NodesType>>['connection'];
|
|
14
13
|
children: React.FunctionComponent<{node: NodesType; index: number}>;
|
|
15
|
-
ariaLabel?: string;
|
|
16
14
|
resourcesClassName?: string;
|
|
17
15
|
}) {
|
|
18
16
|
return (
|
|
@@ -25,33 +23,15 @@ export function PaginatedResourceSection<NodesType>({
|
|
|
25
23
|
return (
|
|
26
24
|
<div>
|
|
27
25
|
<PreviousLink>
|
|
28
|
-
{isLoading ?
|
|
29
|
-
'Loading...'
|
|
30
|
-
) : (
|
|
31
|
-
<span>
|
|
32
|
-
<span aria-hidden="true">↑</span> Load previous
|
|
33
|
-
</span>
|
|
34
|
-
)}
|
|
26
|
+
{isLoading ? 'Loading...' : <span>↑ Load previous</span>}
|
|
35
27
|
</PreviousLink>
|
|
36
28
|
{resourcesClassName ? (
|
|
37
|
-
<div
|
|
38
|
-
aria-label={ariaLabel}
|
|
39
|
-
className={resourcesClassName}
|
|
40
|
-
role={ariaLabel ? 'region' : undefined}
|
|
41
|
-
>
|
|
42
|
-
{resourcesMarkup}
|
|
43
|
-
</div>
|
|
29
|
+
<div className={resourcesClassName}>{resourcesMarkup}</div>
|
|
44
30
|
) : (
|
|
45
31
|
resourcesMarkup
|
|
46
32
|
)}
|
|
47
33
|
<NextLink>
|
|
48
|
-
{isLoading ?
|
|
49
|
-
'Loading...'
|
|
50
|
-
) : (
|
|
51
|
-
<span>
|
|
52
|
-
Load more <span aria-hidden="true">↓</span>
|
|
53
|
-
</span>
|
|
54
|
-
)}
|
|
34
|
+
{isLoading ? 'Loading...' : <span>Load more ↓</span>}
|
|
55
35
|
</NextLink>
|
|
56
36
|
</div>
|
|
57
37
|
);
|
|
@@ -9,7 +9,7 @@ export function ProductPrice({
|
|
|
9
9
|
compareAtPrice?: MoneyV2 | null;
|
|
10
10
|
}) {
|
|
11
11
|
return (
|
|
12
|
-
<div
|
|
12
|
+
<div className="product-price">
|
|
13
13
|
{compareAtPrice ? (
|
|
14
14
|
<div className="product-price-on-sale">
|
|
15
15
|
{price ? <Money data={price} /> : null}
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import type {Route} from './+types/[robots.txt]';
|
|
2
|
+
import {parseGid} from '@shopify/hydrogen';
|
|
2
3
|
|
|
3
|
-
export function loader({request}: Route.LoaderArgs) {
|
|
4
|
+
export async function loader({request, context}: Route.LoaderArgs) {
|
|
4
5
|
const url = new URL(request.url);
|
|
5
|
-
|
|
6
|
+
|
|
7
|
+
const {shop} = await context.storefront.query(ROBOTS_QUERY);
|
|
8
|
+
|
|
9
|
+
const shopId = parseGid(shop.id).id;
|
|
10
|
+
const body = robotsTxtData({url: url.origin, shopId});
|
|
6
11
|
|
|
7
12
|
return new Response(body, {
|
|
8
13
|
status: 200,
|
|
@@ -14,31 +19,35 @@ export function loader({request}: Route.LoaderArgs) {
|
|
|
14
19
|
});
|
|
15
20
|
}
|
|
16
21
|
|
|
17
|
-
function robotsTxtData({url}: {url?: string}) {
|
|
22
|
+
function robotsTxtData({url, shopId}: {shopId?: string; url?: string}) {
|
|
18
23
|
const sitemapUrl = url ? `${url}/sitemap.xml` : undefined;
|
|
19
24
|
|
|
20
25
|
return `
|
|
21
26
|
User-agent: *
|
|
22
|
-
${generalDisallowRules({sitemapUrl})}
|
|
27
|
+
${generalDisallowRules({sitemapUrl, shopId})}
|
|
23
28
|
|
|
24
29
|
# Google adsbot ignores robots.txt unless specifically named!
|
|
25
30
|
User-agent: adsbot-google
|
|
26
|
-
Disallow: /
|
|
27
|
-
Disallow: /
|
|
28
|
-
Disallow: /
|
|
29
|
-
|
|
30
|
-
Disallow: /
|
|
31
|
+
Disallow: /checkouts/
|
|
32
|
+
Disallow: /checkout
|
|
33
|
+
Disallow: /carts
|
|
34
|
+
Disallow: /orders
|
|
35
|
+
${shopId ? `Disallow: /${shopId}/checkouts` : ''}
|
|
36
|
+
${shopId ? `Disallow: /${shopId}/orders` : ''}
|
|
37
|
+
Disallow: /*?*oseid=*
|
|
38
|
+
Disallow: /*preview_theme_id*
|
|
39
|
+
Disallow: /*preview_script_id*
|
|
31
40
|
|
|
32
41
|
User-agent: Nutch
|
|
33
42
|
Disallow: /
|
|
34
43
|
|
|
35
44
|
User-agent: AhrefsBot
|
|
36
45
|
Crawl-delay: 10
|
|
37
|
-
${generalDisallowRules({sitemapUrl})}
|
|
46
|
+
${generalDisallowRules({sitemapUrl, shopId})}
|
|
38
47
|
|
|
39
48
|
User-agent: AhrefsSiteAudit
|
|
40
49
|
Crawl-delay: 10
|
|
41
|
-
${generalDisallowRules({sitemapUrl})}
|
|
50
|
+
${generalDisallowRules({sitemapUrl, shopId})}
|
|
42
51
|
|
|
43
52
|
User-agent: MJ12bot
|
|
44
53
|
Crawl-Delay: 10
|
|
@@ -52,8 +61,21 @@ Crawl-delay: 1
|
|
|
52
61
|
* This function generates disallow rules that generally follow what Shopify's
|
|
53
62
|
* Online Store has as defaults for their robots.txt
|
|
54
63
|
*/
|
|
55
|
-
function generalDisallowRules({
|
|
56
|
-
|
|
64
|
+
function generalDisallowRules({
|
|
65
|
+
shopId,
|
|
66
|
+
sitemapUrl,
|
|
67
|
+
}: {
|
|
68
|
+
shopId?: string;
|
|
69
|
+
sitemapUrl?: string;
|
|
70
|
+
}) {
|
|
71
|
+
return `Disallow: /admin
|
|
72
|
+
Disallow: /cart
|
|
73
|
+
Disallow: /orders
|
|
74
|
+
Disallow: /checkouts/
|
|
75
|
+
Disallow: /checkout
|
|
76
|
+
${shopId ? `Disallow: /${shopId}/checkouts` : ''}
|
|
77
|
+
${shopId ? `Disallow: /${shopId}/orders` : ''}
|
|
78
|
+
Disallow: /carts
|
|
57
79
|
Disallow: /account
|
|
58
80
|
Disallow: /collections/*sort_by*
|
|
59
81
|
Disallow: /*/collections/*sort_by*
|
|
@@ -63,16 +85,33 @@ Disallow: /collections/*%2b*
|
|
|
63
85
|
Disallow: /*/collections/*+*
|
|
64
86
|
Disallow: /*/collections/*%2B*
|
|
65
87
|
Disallow: /*/collections/*%2b*
|
|
66
|
-
Disallow:
|
|
88
|
+
Disallow: */collections/*filter*&*filter*
|
|
67
89
|
Disallow: /blogs/*+*
|
|
68
90
|
Disallow: /blogs/*%2B*
|
|
69
91
|
Disallow: /blogs/*%2b*
|
|
70
92
|
Disallow: /*/blogs/*+*
|
|
71
93
|
Disallow: /*/blogs/*%2B*
|
|
72
94
|
Disallow: /*/blogs/*%2b*
|
|
95
|
+
Disallow: /*?*oseid=*
|
|
96
|
+
Disallow: /*preview_theme_id*
|
|
97
|
+
Disallow: /*preview_script_id*
|
|
73
98
|
Disallow: /policies/
|
|
99
|
+
Disallow: /*/*?*ls=*&ls=*
|
|
100
|
+
Disallow: /*/*?*ls%3D*%3Fls%3D*
|
|
101
|
+
Disallow: /*/*?*ls%3d*%3fls%3d*
|
|
74
102
|
Disallow: /search
|
|
75
103
|
Allow: /search/
|
|
76
104
|
Disallow: /search/?*
|
|
105
|
+
Disallow: /apple-app-site-association
|
|
106
|
+
Disallow: /.well-known/shopify/monorail
|
|
77
107
|
${sitemapUrl ? `Sitemap: ${sitemapUrl}` : ''}`;
|
|
78
108
|
}
|
|
109
|
+
|
|
110
|
+
const ROBOTS_QUERY = `#graphql
|
|
111
|
+
query StoreRobots($country: CountryCode, $language: LanguageCode)
|
|
112
|
+
@inContext(country: $country, language: $language) {
|
|
113
|
+
shop {
|
|
114
|
+
id
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
` as const;
|
|
@@ -83,11 +83,7 @@ function FeaturedCollection({
|
|
|
83
83
|
>
|
|
84
84
|
{image && (
|
|
85
85
|
<div className="featured-collection-image">
|
|
86
|
-
<Image
|
|
87
|
-
data={image}
|
|
88
|
-
sizes="100vw"
|
|
89
|
-
alt={image.altText || collection.title}
|
|
90
|
-
/>
|
|
86
|
+
<Image data={image} sizes="100vw" />
|
|
91
87
|
</div>
|
|
92
88
|
)}
|
|
93
89
|
<h1>{collection.title}</h1>
|
|
@@ -101,11 +97,8 @@ function RecommendedProducts({
|
|
|
101
97
|
products: Promise<RecommendedProductsQuery | null>;
|
|
102
98
|
}) {
|
|
103
99
|
return (
|
|
104
|
-
<
|
|
105
|
-
|
|
106
|
-
aria-labelledby="recommended-products"
|
|
107
|
-
>
|
|
108
|
-
<h2 id="recommended-products">Recommended Products</h2>
|
|
100
|
+
<div className="recommended-products">
|
|
101
|
+
<h2>Recommended Products</h2>
|
|
109
102
|
<Suspense fallback={<div>Loading...</div>}>
|
|
110
103
|
<Await resolve={products}>
|
|
111
104
|
{(response) => (
|
|
@@ -120,7 +113,7 @@ function RecommendedProducts({
|
|
|
120
113
|
</Await>
|
|
121
114
|
</Suspense>
|
|
122
115
|
<br />
|
|
123
|
-
</
|
|
116
|
+
</div>
|
|
124
117
|
);
|
|
125
118
|
}
|
|
126
119
|
|
|
@@ -3,7 +3,7 @@ import type {Route} from './+types/account.$';
|
|
|
3
3
|
|
|
4
4
|
// fallback wild card for all unauthenticated routes in account section
|
|
5
5
|
export async function loader({context}: Route.LoaderArgs) {
|
|
6
|
-
|
|
6
|
+
context.customerAccount.handleAuthStatus();
|
|
7
7
|
|
|
8
8
|
return redirect('/account');
|
|
9
9
|
}
|
|
@@ -32,7 +32,7 @@ export const meta: Route.MetaFunction = () => {
|
|
|
32
32
|
};
|
|
33
33
|
|
|
34
34
|
export async function loader({context}: Route.LoaderArgs) {
|
|
35
|
-
|
|
35
|
+
context.customerAccount.handleAuthStatus();
|
|
36
36
|
|
|
37
37
|
return {};
|
|
38
38
|
}
|
|
@@ -468,7 +468,7 @@ export function AddressForm({
|
|
|
468
468
|
/>
|
|
469
469
|
<label htmlFor="territoryCode">Country Code*</label>
|
|
470
470
|
<input
|
|
471
|
-
aria-label="
|
|
471
|
+
aria-label="territoryCode"
|
|
472
472
|
autoComplete="country"
|
|
473
473
|
defaultValue={address?.territoryCode ?? ''}
|
|
474
474
|
id="territoryCode"
|