@shopbb/helium 0.6.3 → 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.
Files changed (81) hide show
  1. package/dist/components/AddToCartButton.d.ts +17 -22
  2. package/dist/components/AddToCartButton.d.ts.map +1 -1
  3. package/dist/components/AddToCartButton.js +8 -45
  4. package/dist/components/AddToCartButton.js.map +1 -1
  5. package/dist/components/AddressForm.d.ts +42 -18
  6. package/dist/components/AddressForm.d.ts.map +1 -1
  7. package/dist/components/AddressForm.js +23 -20
  8. package/dist/components/AddressForm.js.map +1 -1
  9. package/dist/components/AddressList.d.ts +34 -17
  10. package/dist/components/AddressList.d.ts.map +1 -1
  11. package/dist/components/AddressList.js +7 -21
  12. package/dist/components/AddressList.js.map +1 -1
  13. package/dist/components/AddressPicker.d.ts +14 -16
  14. package/dist/components/AddressPicker.d.ts.map +1 -1
  15. package/dist/components/AddressPicker.js +10 -26
  16. package/dist/components/AddressPicker.js.map +1 -1
  17. package/dist/components/AnalyticsProvider.d.ts +5 -2
  18. package/dist/components/AnalyticsProvider.d.ts.map +1 -1
  19. package/dist/components/AnalyticsProvider.js +13 -11
  20. package/dist/components/AnalyticsProvider.js.map +1 -1
  21. package/dist/components/BuyNowButton.d.ts +7 -24
  22. package/dist/components/BuyNowButton.d.ts.map +1 -1
  23. package/dist/components/BuyNowButton.js +9 -43
  24. package/dist/components/BuyNowButton.js.map +1 -1
  25. package/dist/components/CartCheckoutButton.d.ts +10 -21
  26. package/dist/components/CartCheckoutButton.d.ts.map +1 -1
  27. package/dist/components/CartCheckoutButton.js +6 -11
  28. package/dist/components/CartCheckoutButton.js.map +1 -1
  29. package/dist/components/CartCost.d.ts +15 -23
  30. package/dist/components/CartCost.d.ts.map +1 -1
  31. package/dist/components/CartCost.js +1 -3
  32. package/dist/components/CartCost.js.map +1 -1
  33. package/dist/components/CartForm.d.ts +30 -102
  34. package/dist/components/CartForm.d.ts.map +1 -1
  35. package/dist/components/CartForm.js +32 -172
  36. package/dist/components/CartForm.js.map +1 -1
  37. package/dist/components/DiscountComponents.d.ts +67 -17
  38. package/dist/components/DiscountComponents.d.ts.map +1 -1
  39. package/dist/components/DiscountComponents.js +28 -74
  40. package/dist/components/DiscountComponents.js.map +1 -1
  41. package/dist/components/DiscountSelector.d.ts +50 -15
  42. package/dist/components/DiscountSelector.d.ts.map +1 -1
  43. package/dist/components/DiscountSelector.js +16 -44
  44. package/dist/components/DiscountSelector.js.map +1 -1
  45. package/dist/components/hooks/useOptimisticCart.d.ts +36 -37
  46. package/dist/components/hooks/useOptimisticCart.d.ts.map +1 -1
  47. package/dist/components/hooks/useOptimisticCart.js +95 -127
  48. package/dist/components/hooks/useOptimisticCart.js.map +1 -1
  49. package/dist/components/index.d.ts +24 -45
  50. package/dist/components/index.d.ts.map +1 -1
  51. package/dist/components/index.js +21 -37
  52. package/dist/components/index.js.map +1 -1
  53. package/dist/createCartHandler.d.ts.map +1 -1
  54. package/dist/createCartHandler.js +8 -1
  55. package/dist/createCartHandler.js.map +1 -1
  56. package/dist/index.d.ts +0 -2
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +0 -1
  59. package/dist/index.js.map +1 -1
  60. package/package.json +4 -10
  61. package/src/components/AddToCartButton.tsx +34 -92
  62. package/src/components/AddressForm.tsx +56 -26
  63. package/src/components/AddressList.tsx +42 -33
  64. package/src/components/AddressPicker.tsx +19 -29
  65. package/src/components/AnalyticsProvider.tsx +18 -13
  66. package/src/components/BuyNowButton.tsx +28 -93
  67. package/src/components/CartCheckoutButton.tsx +16 -33
  68. package/src/components/CartCost.tsx +16 -28
  69. package/src/components/CartForm.tsx +87 -231
  70. package/src/components/DiscountComponents.tsx +94 -100
  71. package/src/components/DiscountSelector.tsx +68 -49
  72. package/src/components/hooks/useOptimisticCart.ts +122 -156
  73. package/src/components/index.ts +51 -99
  74. package/src/createCartHandler.ts +10 -1
  75. package/src/index.ts +0 -2
  76. /package/src/components/{AddressBookProvider.tsx → AddressBookProvider.tsx.deleted-0.7} +0 -0
  77. /package/src/components/{CartLineQuantityAdjustButton.tsx → CartLineQuantityAdjustButton.tsx.deleted-0.7} +0 -0
  78. /package/src/components/{CartProvider.tsx → CartProvider.tsx.deleted-0.7} +0 -0
  79. /package/src/components/{DiscountProvider.tsx → DiscountProvider.tsx.deleted-0.7} +0 -0
  80. /package/src/components/hooks/{useMounted.ts → useMounted.ts.deleted-0.7} +0 -0
  81. /package/src/{handleCartFormAction.ts → handleCartFormAction.ts.deleted-0.7} +0 -0
@@ -1,90 +1,52 @@
1
1
  /**
2
- * <CartForm> — 对齐 Shopify Hydrogen 的 CartForm 组件
2
+ * <CartForm> — 严格对齐 Shopify Hydrogen 的 CartForm 实现
3
3
  *
4
- * Hydrogen 文档:https://shopify.dev/docs/api/hydrogen/latest/components/cartform
4
+ * 源文件参考:packages/hydrogen/src/cart/CartForm.tsx
5
5
  *
6
- * 用法:
6
+ * 核心机制:
7
+ * - 用 react-router 的 useFetcher() + <fetcher.Form>
8
+ * - submit 后 RR7 自动调对应 route 的 action(),完成后自动 revalidate 所有 loader
9
+ * - children 是 render prop 可以接 fetcher 对象(state / data / formData)
10
+ * - fetcherKey 让相同的 mutation 互相 cancel(例如多次点 +/- 只跑最后一次)
7
11
  *
8
- * import { CartForm } from '@shopby/helium';
9
- *
10
- * // 加入购物车
11
- * <CartForm
12
- * action={CartForm.ACTIONS.LinesAdd}
13
- * inputs={{ lines: [{ merchandiseId, quantity: 1 }] }}
14
- * route="/cart"
15
- * >
16
- * <button type="submit">加入购物车</button>
17
- * </CartForm>
18
- *
19
- * // 自定义按钮渲染
20
- * <CartForm action={CartForm.ACTIONS.LinesAdd} inputs={{ lines }}>
21
- * {(fetcher) => (
22
- * <button disabled={fetcher.state !== 'idle'}>
23
- * {fetcher.state === 'submitting' ? '添加中…' : '加入购物车'}
24
- * </button>
25
- * )}
26
- * </CartForm>
27
- *
28
- * 服务端(route action):
29
- *
30
- * import { CartForm } from '@shopbb/helium';
31
- *
32
- * export async function action(request, context) {
33
- * const formData = await request.formData();
34
- * const { action, inputs } = CartForm.getFormInput(formData);
35
- * // ... switch(action) { ... }
36
- * }
37
- *
38
- * ─────────────────────────────────────────────────────────────────
39
- *
40
- * 实现说明:
41
- *
42
- * - 渲染原生 <form method="POST">,无 JS 也能工作(form 默认提交 = 整页 POST)
43
- * - INPUT_NAME = "cartFormInput"(hidden input,value = JSON.stringify({action, inputs}))
44
- * - JS 加载后,由 helium 提供的 useCartFormFetcher hook(或 useFetcher 实现) 拦截 submit 实现"不跳页"
45
- * - 当前简化实现:hydrate 后 onSubmit preventDefault,自己用 fetch 调,调完后通过 CartProvider.applyCart 更新
12
+ * helium 0.6.x 之前的差异:
13
+ * - 删除自己造的 FetcherContext + raw fetch 实现
14
+ * - peerDep 加 react-router(这就是 Hydrogen 自己的依赖)
46
15
  */
47
16
  import * as React from 'react';
17
+ import { type FetcherWithComponents } from 'react-router';
48
18
  export declare const CART_FORM_ACTIONS: {
49
- /** Update cart attributes */
50
19
  readonly AttributesUpdateInput: "AttributesUpdateInput";
51
- /** Update buyer identity (email, customerAccessToken, country, etc.) */
52
20
  readonly BuyerIdentityUpdate: "BuyerIdentityUpdate";
53
- /** Create a new cart */
54
21
  readonly Create: "Create";
55
- /** Replace discount codes */
56
22
  readonly DiscountCodesUpdate: "DiscountCodesUpdate";
57
- /** Replace gift card codes */
58
23
  readonly GiftCardCodesUpdate: "GiftCardCodesUpdate";
59
- /** Append gift card codes */
60
24
  readonly GiftCardCodesAdd: "GiftCardCodesAdd";
61
- /** Remove specific gift card codes */
62
25
  readonly GiftCardCodesRemove: "GiftCardCodesRemove";
63
- /** Add cart lines */
64
26
  readonly LinesAdd: "LinesAdd";
65
- /** Update cart lines (quantity / attributes) */
66
- readonly LinesUpdate: "LinesUpdate";
67
- /** Remove cart lines */
68
27
  readonly LinesRemove: "LinesRemove";
69
- /** Update cart note */
28
+ readonly LinesUpdate: "LinesUpdate";
70
29
  readonly NoteUpdate: "NoteUpdate";
71
- /** Update selected delivery options */
72
30
  readonly SelectedDeliveryOptionsUpdate: "SelectedDeliveryOptionsUpdate";
73
- /** Set metafields */
74
31
  readonly MetafieldsSet: "MetafieldsSet";
75
- /** Delete metafields */
76
- readonly MetafieldsDelete: "MetafieldsDelete";
32
+ readonly MetafieldDelete: "MetafieldDelete";
33
+ readonly DeliveryAddressesAdd: "DeliveryAddressesAdd";
34
+ readonly DeliveryAddressesUpdate: "DeliveryAddressesUpdate";
35
+ readonly DeliveryAddressesRemove: "DeliveryAddressesRemove";
36
+ readonly DeliveryAddressesReplace: "DeliveryAddressesReplace";
77
37
  };
78
38
  export type CartFormAction = (typeof CART_FORM_ACTIONS)[keyof typeof CART_FORM_ACTIONS] | `Custom${string}`;
79
- export type CartLineInput = {
39
+ export interface CartLineInput {
80
40
  merchandiseId: string;
81
41
  quantity?: number;
82
42
  attributes?: Array<{
83
43
  key: string;
84
44
  value: string;
85
45
  }>;
86
- };
87
- export type CartLineUpdateInput = {
46
+ /** 用于 optimistic UI 展示(不会发到服务端) */
47
+ selectedVariant?: unknown;
48
+ }
49
+ export interface CartLineUpdateInput {
88
50
  id: string;
89
51
  quantity?: number;
90
52
  merchandiseId?: string;
@@ -92,7 +54,7 @@ export type CartLineUpdateInput = {
92
54
  key: string;
93
55
  value: string;
94
56
  }>;
95
- };
57
+ }
96
58
  interface OtherFormData {
97
59
  [key: string]: unknown;
98
60
  }
@@ -143,59 +105,25 @@ export type CartFormInput = {
143
105
  action: `Custom${string}`;
144
106
  inputs: Record<string, unknown>;
145
107
  };
146
- /** 服务端 / 客户端共享的 hidden field name — 对齐 Hydrogen */
147
108
  declare const INPUT_NAME = "cartFormInput";
148
- /**
149
- * Fetcher 状态对象 — 模仿 Remix useFetcher
150
- *
151
- * 关键属性:
152
- * - state: 'idle' | 'submitting' | 'loading'
153
- * - data: 服务端 action 返回的 JSON(成功时)
154
- * - error: 错误信息
155
- */
156
- export interface CartFormFetcher {
157
- state: 'idle' | 'submitting' | 'loading';
158
- data: any;
159
- error: string | null;
160
- /** 取最近一次提交的 form data(optimistic UI 用) */
161
- formData: FormData | null;
162
- }
163
- /**
164
- * 在 <CartForm> 内部任何深度的组件里拿 fetcher 状态。
165
- *
166
- * <CartForm action="LinesAdd" inputs={{lines}}>
167
- * <MyButton />
168
- * </CartForm>
169
- *
170
- * function MyButton() {
171
- * const fetcher = useFetcher();
172
- * return <button disabled={fetcher.state !== 'idle'}>添加</button>;
173
- * }
174
- */
175
- export declare function useFetcher(): CartFormFetcher;
176
109
  export interface CartFormCommonProps {
177
- /** children 可以是普通节点,也可以是 (fetcher) => ReactNode */
178
- children: React.ReactNode | ((fetcher: CartFormFetcher) => React.ReactNode);
179
- /** 提交的 route。默认 "/cart" */
110
+ /** children 可以是普通 React 节点,也可以是 render prop 接收 fetcher 对象 */
111
+ children: React.ReactNode | ((fetcher: FetcherWithComponents<any>) => React.ReactNode);
112
+ /** 提交的 route。默认空字符串表示当前 route */
180
113
  route?: string;
181
- /** Optional key — 同一 key 的 fetcher state 共享。当前简化版未使用 */
114
+ /** Fetcher key — 相同 key 的 fetcher 会互相 cancel(用于幂等操作)*/
182
115
  fetcherKey?: string;
183
- /** 表单 className(不影响行为) */
184
- className?: string;
185
116
  }
186
117
  export type CartFormProps = CartFormInput & CartFormCommonProps;
187
118
  interface CartFormImpl {
188
119
  (props: CartFormProps): React.ReactElement;
189
120
  ACTIONS: typeof CART_FORM_ACTIONS;
190
121
  INPUT_NAME: typeof INPUT_NAME;
191
- /**
192
- * 服务端 helper:从 request.formData() 解析出 { action, inputs }
193
- *
194
- * const formData = await request.formData();
195
- * const { action, inputs } = CartForm.getFormInput(formData);
196
- */
197
122
  getFormInput: (formData: FormData) => CartFormInput;
198
123
  }
199
124
  declare const CartForm: CartFormImpl;
200
125
  export { CartForm };
126
+ export { useFetcher } from 'react-router';
127
+ export type { FetcherWithComponents } from 'react-router';
128
+ export type CartFormFetcher = FetcherWithComponents<any>;
201
129
  //# sourceMappingURL=CartForm.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"CartForm.d.ts","sourceRoot":"","sources":["../../src/components/CartForm.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"CartForm.d.ts","sourceRoot":"","sources":["../../src/components/CartForm.tsx"],"names":[],"mappings":"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"}
@@ -1,213 +1,73 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- /**
3
- * <CartForm> — 对齐 Shopify Hydrogen 的 CartForm 组件
4
- *
5
- * Hydrogen 文档:https://shopify.dev/docs/api/hydrogen/latest/components/cartform
6
- *
7
- * 用法:
8
- *
9
- * import { CartForm } from '@shopby/helium';
10
- *
11
- * // 加入购物车
12
- * <CartForm
13
- * action={CartForm.ACTIONS.LinesAdd}
14
- * inputs={{ lines: [{ merchandiseId, quantity: 1 }] }}
15
- * route="/cart"
16
- * >
17
- * <button type="submit">加入购物车</button>
18
- * </CartForm>
19
- *
20
- * // 自定义按钮渲染
21
- * <CartForm action={CartForm.ACTIONS.LinesAdd} inputs={{ lines }}>
22
- * {(fetcher) => (
23
- * <button disabled={fetcher.state !== 'idle'}>
24
- * {fetcher.state === 'submitting' ? '添加中…' : '加入购物车'}
25
- * </button>
26
- * )}
27
- * </CartForm>
28
- *
29
- * 服务端(route action):
30
- *
31
- * import { CartForm } from '@shopbb/helium';
32
- *
33
- * export async function action(request, context) {
34
- * const formData = await request.formData();
35
- * const { action, inputs } = CartForm.getFormInput(formData);
36
- * // ... switch(action) { ... }
37
- * }
38
- *
39
- * ─────────────────────────────────────────────────────────────────
40
- *
41
- * 实现说明:
42
- *
43
- * - 渲染原生 <form method="POST">,无 JS 也能工作(form 默认提交 = 整页 POST)
44
- * - INPUT_NAME = "cartFormInput"(hidden input,value = JSON.stringify({action, inputs}))
45
- * - JS 加载后,由 helium 提供的 useCartFormFetcher hook(或 useFetcher 实现) 拦截 submit 实现"不跳页"
46
- * - 当前简化实现:hydrate 后 onSubmit preventDefault,自己用 fetch 调,调完后通过 CartProvider.applyCart 更新
47
- */
48
- import * as React from 'react';
49
- import { useCartOptional } from './CartProvider';
50
- import { __registerPendingMutation } from './hooks/useOptimisticCart';
2
+ import { useFetcher } from 'react-router';
51
3
  // ============================================================
52
4
  // Action 枚举 — 对齐 Hydrogen CartForm.ACTIONS
53
5
  // ============================================================
54
6
  export const CART_FORM_ACTIONS = {
55
- /** Update cart attributes */
56
7
  AttributesUpdateInput: 'AttributesUpdateInput',
57
- /** Update buyer identity (email, customerAccessToken, country, etc.) */
58
8
  BuyerIdentityUpdate: 'BuyerIdentityUpdate',
59
- /** Create a new cart */
60
9
  Create: 'Create',
61
- /** Replace discount codes */
62
10
  DiscountCodesUpdate: 'DiscountCodesUpdate',
63
- /** Replace gift card codes */
64
11
  GiftCardCodesUpdate: 'GiftCardCodesUpdate',
65
- /** Append gift card codes */
66
12
  GiftCardCodesAdd: 'GiftCardCodesAdd',
67
- /** Remove specific gift card codes */
68
13
  GiftCardCodesRemove: 'GiftCardCodesRemove',
69
- /** Add cart lines */
70
14
  LinesAdd: 'LinesAdd',
71
- /** Update cart lines (quantity / attributes) */
72
- LinesUpdate: 'LinesUpdate',
73
- /** Remove cart lines */
74
15
  LinesRemove: 'LinesRemove',
75
- /** Update cart note */
16
+ LinesUpdate: 'LinesUpdate',
76
17
  NoteUpdate: 'NoteUpdate',
77
- /** Update selected delivery options */
78
18
  SelectedDeliveryOptionsUpdate: 'SelectedDeliveryOptionsUpdate',
79
- /** Set metafields */
80
19
  MetafieldsSet: 'MetafieldsSet',
81
- /** Delete metafields */
82
- MetafieldsDelete: 'MetafieldsDelete',
20
+ MetafieldDelete: 'MetafieldDelete',
21
+ DeliveryAddressesAdd: 'DeliveryAddressesAdd',
22
+ DeliveryAddressesUpdate: 'DeliveryAddressesUpdate',
23
+ DeliveryAddressesRemove: 'DeliveryAddressesRemove',
24
+ DeliveryAddressesReplace: 'DeliveryAddressesReplace',
83
25
  };
84
26
  // ============================================================
85
- // <CartForm> 组件
27
+ // CartForm
86
28
  // ============================================================
87
- /** 服务端 / 客户端共享的 hidden field name — 对齐 Hydrogen */
88
29
  const INPUT_NAME = 'cartFormInput';
89
30
  /**
90
- * CartFormFetcher Context — 让 CartForm 内部任何位置都能用 useFetcher() 拿状态
91
- *
92
- * Hydrogen 是用 Remix global fetcher,我们用一个本地 Context。children 既可以是
93
- * render prop(推荐),也可以是普通节点 + useFetcher() 调用。
31
+ * 严格照抄 Hydrogen 实现(packages/hydrogen/src/cart/CartForm.tsx)
94
32
  */
95
- const FetcherContext = React.createContext(null);
96
- /**
97
- * 在 <CartForm> 内部任何深度的组件里拿 fetcher 状态。
98
- *
99
- * <CartForm action="LinesAdd" inputs={{lines}}>
100
- * <MyButton />
101
- * </CartForm>
102
- *
103
- * function MyButton() {
104
- * const fetcher = useFetcher();
105
- * return <button disabled={fetcher.state !== 'idle'}>添加</button>;
106
- * }
107
- */
108
- export function useFetcher() {
109
- const ctx = React.useContext(FetcherContext);
110
- if (!ctx) {
111
- throw new Error('useFetcher must be used inside a <CartForm>');
112
- }
113
- return ctx;
114
- }
115
33
  const CartFormBase = (props) => {
116
- const { children, route = '/cart', className, action, inputs, ...rest } = props;
117
- const cartCtx = useCartOptional();
118
- // 序列化 { action, inputs } 一并放进 hidden input
119
- // 服务端用 CartForm.getFormInput(formData) 反序列化
120
- const payload = React.useMemo(() => JSON.stringify({ action, inputs }), [action, inputs]);
121
- const [fetcher, setFetcher] = React.useState({
122
- state: 'idle',
123
- data: null,
124
- error: null,
125
- formData: null,
126
- });
127
- // hydrate 后拦截 submit;SSR 时 onSubmit 不存在 → form 原生 POST
128
- const handleSubmit = React.useCallback(async (e) => {
129
- e.preventDefault();
130
- const form = e.currentTarget;
131
- const formData = new FormData(form);
132
- setFetcher({ state: 'submitting', data: null, error: null, formData });
133
- // 注册到 pending store — useOptimisticCart 会看到这个 mutation 立刻应用
134
- // 只对 cart line 类型的 action 做(DiscountCodesUpdate / Custom* 等不做 optimistic)
135
- let unregisterPending = null;
136
- if (action === 'LinesAdd' || action === 'LinesUpdate' || action === 'LinesRemove') {
137
- const pendingId = `${action}_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
138
- unregisterPending = __registerPendingMutation({ id: pendingId, action: action, inputs });
139
- }
140
- try {
141
- // 显式标记 X-Helium-Fetch — 让服务端知道这是 JS fetch 不是原生 form POST
142
- // 服务端 handleCartFormAction 看到此 header 会返回 JSON 而不是 303 redirect
143
- const res = await fetch(route, {
144
- method: 'POST',
145
- body: formData,
146
- credentials: 'include',
147
- headers: { 'Accept': 'application/json', 'X-Helium-Fetch': '1' },
148
- });
149
- const data = await res.json().catch(() => null);
150
- if (!res.ok || data?.error || data?.userErrors?.length) {
151
- throw new Error(data?.error || data?.userErrors?.[0]?.message || `HTTP ${res.status}`);
152
- }
153
- // 服务端约定:成功时返回 { cart: Cart }
154
- // 这里直接 applyCart 到 CartProvider,避免 refetch
155
- if (data?.cart && cartCtx?.applyCart) {
156
- cartCtx.applyCart(data.cart);
157
- }
158
- setFetcher({ state: 'idle', data, error: null, formData: null });
159
- }
160
- catch (err) {
161
- setFetcher({ state: 'idle', data: null, error: err.message || String(err), formData: null });
162
- }
163
- finally {
164
- unregisterPending?.();
165
- }
166
- }, [route, cartCtx, action, inputs]);
167
- const renderedChildren = typeof children === 'function' ? children(fetcher) : children;
168
- return (_jsx(FetcherContext.Provider, { value: fetcher, children: _jsxs("form", { method: "POST", action: route, onSubmit: handleSubmit, className: className, "data-cart-form": true, "data-cart-action": action, children: [_jsx("input", { type: "hidden", name: INPUT_NAME, value: payload }), renderedChildren] }) }));
34
+ const { children, action, inputs, route, fetcherKey } = props;
35
+ const fetcher = useFetcher({ key: fetcherKey });
36
+ return (_jsxs(fetcher.Form, { action: route || '', method: "post", children: [(action || inputs) && (_jsx("input", { type: "hidden", name: INPUT_NAME, value: JSON.stringify({ action, inputs }) })), typeof children === 'function' ? children(fetcher) : children] }));
169
37
  };
170
38
  /**
171
39
  * 服务端 helper:从 request.formData() 还原出 { action, inputs }
172
40
  *
173
- * Hydrogen 完全一致的 API:
174
- *
175
- * const formData = await request.formData();
176
- * const { action, inputs } = CartForm.getFormInput(formData);
41
+ * 严格照抄 Hydrogen 实现:把 form 内其它 input(如 <input name="note">)合并进 inputs。
177
42
  */
178
43
  function getFormInput(formData) {
179
- const raw = formData.get(INPUT_NAME);
180
- if (typeof raw !== 'string') {
181
- throw new Error(`CartForm.getFormInput: missing field "${INPUT_NAME}" in form data`);
182
- }
183
- let parsed;
184
- try {
185
- parsed = JSON.parse(raw);
186
- }
187
- catch {
188
- throw new Error(`CartForm.getFormInput: field "${INPUT_NAME}" is not valid JSON`);
189
- }
190
- if (!parsed || typeof parsed.action !== 'string') {
191
- throw new Error('CartForm.getFormInput: missing "action" in parsed payload');
192
- }
193
- // 合并 form 里的其它字段进 inputs(对齐 Hydrogen 的 OtherFormData 设计)
194
- // <CartForm action=NoteUpdate><input name="note" /></CartForm> 这种场景
195
- // FormData 里同时有 cartFormInput 和 note 两个字段,inputs.note 来自 FormData 而不是 JSON。
196
- const otherInputs = {};
197
- for (const [key, value] of formData.entries()) {
198
- if (key === INPUT_NAME)
199
- continue;
200
- otherInputs[key] = value;
44
+ // 拿全部 form data
45
+ const data = {};
46
+ for (const pair of formData.entries()) {
47
+ const key = pair[0];
48
+ const values = formData.getAll(key);
49
+ data[key] = values.length > 1 ? values : pair[1];
50
+ // checkbox → boolean
51
+ if (data[key] === 'on')
52
+ data[key] = true;
53
+ else if (data[key] === 'off')
54
+ data[key] = false;
201
55
  }
56
+ const { cartFormInput, ...otherData } = data;
57
+ const parsed = cartFormInput ? JSON.parse(String(cartFormInput)) : {};
202
58
  return {
203
59
  action: parsed.action,
204
- inputs: { ...otherInputs, ...(parsed.inputs || {}) },
60
+ inputs: {
61
+ ...(parsed.inputs || {}),
62
+ ...otherData,
63
+ },
205
64
  };
206
65
  }
207
- // 把 ACTIONS / INPUT_NAME / getFormInput 挂到 CartForm 对象上 — 对齐 Hydrogen
208
66
  const CartForm = CartFormBase;
209
67
  CartForm.ACTIONS = CART_FORM_ACTIONS;
210
68
  CartForm.INPUT_NAME = INPUT_NAME;
211
69
  CartForm.getFormInput = getFormInput;
212
70
  export { CartForm };
71
+ // useFetcher 透传 — 让商家也能用同款 API(其实就是 RR7 原生)
72
+ export { useFetcher } from 'react-router';
213
73
  //# sourceMappingURL=CartForm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CartForm.js","sourceRoot":"","sources":["../../src/components/CartForm.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"CartForm.js","sourceRoot":"","sources":["../../src/components/CartForm.tsx"],"names":[],"mappings":"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"}
@@ -6,44 +6,94 @@
6
6
  * <DiscountClaimButton> 单个领取按钮
7
7
  * <MyDiscountList> 我的卡包
8
8
  *
9
- * 注:W5 已删除以下组件(旧设计):
10
- * - <DiscountCodeInput>: 输入框范式已过时。请用 <DiscountSelector> + <ClaimableDiscountList>。
11
- * - <BestDiscountHint>: 服务端自动选择最佳券,不需要前端提示。用户在 <DiscountSelector> 看到 / 切换。
12
- *
13
- * 全部无样式 + data-* 钩子。
9
+ * helium 0.7:所有组件**接 props 不靠 Provider**。
10
+ * 商家从 loader publicDiscounts / myClaims / cart.discountAllocations 传入。
14
11
  */
15
12
  import * as React from 'react';
16
- import { type Discount } from './DiscountProvider';
13
+ export type DiscountValueType = 'PERCENTAGE' | 'FIXED_AMOUNT' | 'FREE_SHIPPING';
14
+ export interface DiscountValuePercentage {
15
+ __typename: 'DiscountPercentage';
16
+ percentage: number;
17
+ }
18
+ export interface DiscountValueAmount {
19
+ __typename: 'DiscountAmount';
20
+ amount: {
21
+ amount: string;
22
+ currencyCode: string;
23
+ };
24
+ }
25
+ export interface DiscountValueFreeShipping {
26
+ __typename: 'DiscountFreeShipping';
27
+ freeShipping: boolean;
28
+ }
29
+ export interface Discount {
30
+ id: string;
31
+ code: string | null;
32
+ title: string;
33
+ description: string | null;
34
+ valueType: DiscountValueType;
35
+ value: DiscountValuePercentage | DiscountValueAmount | DiscountValueFreeShipping;
36
+ minSubtotal: {
37
+ amount: string;
38
+ currencyCode: string;
39
+ } | null;
40
+ startsAt: string | null;
41
+ endsAt: string | null;
42
+ }
43
+ export interface DiscountClaim {
44
+ id: string;
45
+ claimedAt: string;
46
+ expiresAt: string | null;
47
+ isExpired: boolean;
48
+ remainingUses: number;
49
+ usedCount: number;
50
+ discount: Discount;
51
+ }
52
+ export interface DiscountAllocation {
53
+ discountedAmount: {
54
+ amount: string;
55
+ currencyCode: string;
56
+ };
57
+ title?: string | null;
58
+ code?: string | null;
59
+ }
17
60
  export interface AppliedDiscountListProps {
61
+ /** 从 cart.discountAllocations 传入 */
62
+ allocations?: DiscountAllocation[];
18
63
  className?: string;
19
64
  emptyText?: React.ReactNode;
20
65
  }
21
66
  export declare function AppliedDiscountList(props: AppliedDiscountListProps): import("react/jsx-runtime").JSX.Element;
22
67
  export interface ClaimableDiscountListProps {
23
- scope?: 'store' | 'product';
24
- productHandle?: string;
68
+ /** 可领取的折扣(从 loader 拉,例如 publicDiscounts 或 productDiscounts) */
69
+ discounts?: Discount[];
70
+ /** 一次最多渲染几张,默认 10 */
25
71
  first?: number;
26
72
  className?: string;
27
73
  emptyText?: React.ReactNode;
28
74
  renderItem?: (discount: Discount) => React.ReactNode;
29
75
  }
30
- export declare function ClaimableDiscountList(props: ClaimableDiscountListProps): import("react/jsx-runtime").JSX.Element | null;
76
+ export declare function ClaimableDiscountList(props: ClaimableDiscountListProps): import("react/jsx-runtime").JSX.Element;
31
77
  export interface DiscountClaimButtonProps {
32
78
  discount: Discount;
33
- children?: React.ReactNode;
79
+ /** 点击触发的回调(商家实现 claim 逻辑) */
80
+ onClaim?: (discount: Discount) => Promise<void> | void;
81
+ /** 是否已领(外部判断后传入,按钮 disabled) */
82
+ claimed?: boolean;
83
+ /** 加载中文本 */
34
84
  loadingText?: React.ReactNode;
85
+ /** 已领文本 */
35
86
  claimedText?: React.ReactNode;
36
- /** 未登录时跳转的路径。默认 `/login?next=` + 当前路径 */
37
- loginPath?: string;
38
- onClaimed?: () => void;
39
- onError?: (msg: string) => void;
87
+ children?: React.ReactNode;
40
88
  className?: string;
41
89
  }
42
90
  export declare function DiscountClaimButton(props: DiscountClaimButtonProps): import("react/jsx-runtime").JSX.Element;
43
91
  export interface MyDiscountListProps {
44
- className?: string;
45
- emptyText?: React.ReactNode;
92
+ /** 从 customer GraphQL 拉的 claims */
93
+ claims?: DiscountClaim[];
46
94
  filter?: 'available' | 'used' | 'expired' | 'all';
95
+ emptyText?: React.ReactNode;
96
+ className?: string;
47
97
  }
48
- export declare function MyDiscountList(props: MyDiscountListProps): import("react/jsx-runtime").JSX.Element | null;
98
+ export declare function MyDiscountList(props: MyDiscountListProps): import("react/jsx-runtime").JSX.Element;
49
99
  //# sourceMappingURL=DiscountComponents.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DiscountComponents.d.ts","sourceRoot":"","sources":["../../src/components/DiscountComponents.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAqC,KAAK,QAAQ,EAAsB,MAAM,oBAAoB,CAAC;AAU1G,MAAM,WAAW,wBAAwB;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC7B;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,wBAAwB,2CAqBlE;AAMD,MAAM,WAAW,0BAA0B;IACzC,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC5B,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,KAAK,CAAC,SAAS,CAAC;CACtD;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,0BAA0B,kDA0BtE;AAsCD,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,QAAQ,CAAC;IACnB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC9B,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC9B,yCAAyC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,wBAAwB,2CA2DlE;AAMD,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC5B,MAAM,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,GAAG,KAAK,CAAC;CACnD;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,kDA8CxD"}
1
+ {"version":3,"file":"DiscountComponents.d.ts","sourceRoot":"","sources":["../../src/components/DiscountComponents.tsx"],"names":[],"mappings":"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"}