@shopbb/helium 0.6.4 → 0.7.1

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 (77) 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 +30 -15
  42. package/dist/components/DiscountSelector.d.ts.map +1 -1
  43. package/dist/components/DiscountSelector.js +21 -48
  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/index.d.ts +0 -2
  54. package/dist/index.d.ts.map +1 -1
  55. package/dist/index.js +0 -1
  56. package/dist/index.js.map +1 -1
  57. package/package.json +4 -10
  58. package/src/components/AddToCartButton.tsx +34 -92
  59. package/src/components/AddressForm.tsx +56 -26
  60. package/src/components/AddressList.tsx +42 -33
  61. package/src/components/AddressPicker.tsx +19 -29
  62. package/src/components/AnalyticsProvider.tsx +18 -13
  63. package/src/components/BuyNowButton.tsx +28 -93
  64. package/src/components/CartCheckoutButton.tsx +16 -33
  65. package/src/components/CartCost.tsx +16 -28
  66. package/src/components/CartForm.tsx +87 -231
  67. package/src/components/DiscountComponents.tsx +94 -100
  68. package/src/components/DiscountSelector.tsx +58 -53
  69. package/src/components/hooks/useOptimisticCart.ts +122 -156
  70. package/src/components/index.ts +51 -99
  71. package/src/index.ts +0 -2
  72. /package/src/components/{AddressBookProvider.tsx → AddressBookProvider.tsx.deleted-0.7} +0 -0
  73. /package/src/components/{CartLineQuantityAdjustButton.tsx → CartLineQuantityAdjustButton.tsx.deleted-0.7} +0 -0
  74. /package/src/components/{CartProvider.tsx → CartProvider.tsx.deleted-0.7} +0 -0
  75. /package/src/components/{DiscountProvider.tsx → DiscountProvider.tsx.deleted-0.7} +0 -0
  76. /package/src/components/hooks/{useMounted.ts → useMounted.ts.deleted-0.7} +0 -0
  77. /package/src/{handleCartFormAction.ts → handleCartFormAction.ts.deleted-0.7} +0 -0
@@ -1,183 +1,149 @@
1
1
  /**
2
- * useOptimisticCart — 对齐 Hydrogen React 同名 hook
2
+ * useOptimisticCart — 严格对齐 Shopify Hydrogen
3
3
  *
4
- * 接受 actualCart(来自 CartProvider),返回一个"叠加了所有 pending mutation"
5
- * 的 cart 视图。让 UI 在网络回来之前立刻反应用户操作(数量+1 / 删除等)。
4
+ * 源文件参考:packages/hydrogen/src/cart/optimistic/useOptimisticCart.tsx
6
5
  *
7
- * const { cart: actualCart } = useCart();
8
- * const cart = useOptimisticCart(actualCart);
9
- * // cart 看起来已经"立刻应用了",但 fetcher 还在跑后端
6
+ * 核心:用 RR7 `useFetchers()` 拿当前所有 in-flight fetcher,遍历它们的 formData
7
+ * CartForm.getFormInput 解析出 action/inputs,合并到 actualCart 上。
10
8
  *
11
- * 实现:
12
- * - <CartForm> submit 时把 pending action 注册到模块内 store
13
- * - 完成后从 store 摘掉
14
- * - useOptimisticCart 订阅 store,把 actualCart 复制一份 + 应用所有 pending
9
+ * 用法:
10
+ * const data = useLoaderData<typeof loader>();
11
+ * const cart = useOptimisticCart(data.cart);
12
+ * // cart 包含 isOptimistic 字段、cart.lines 包含 in-flight 添加的 line(也带 isOptimistic)
15
13
  *
16
- * 简化点(vs Hydrogen 完整实现):
17
- * - 只支持 LinesAdd / LinesUpdate / LinesRemove(足够 cart 主流操作)
18
- * - DiscountCodesUpdate / NoteUpdate 等不做 optimistic(这些在网络层用 applyCart 兜底)
19
- * - 不持久化(页面刷新清空)
14
+ * 与之前 helium 0.6.x 区别:
15
+ * - 删除自造 pendingStore 全局变量
16
+ * - 直接用 RR7 useFetchers()
20
17
  */
21
18
 
22
- import * as React from 'react';
23
- import { useCartOptional } from '../CartProvider';
19
+ import { useFetchers } from 'react-router';
20
+ import { CartForm, type CartLineInput } from '../CartForm';
24
21
 
25
- // ============================================================
26
- // Pending mutation store(模块级单例)
27
- // ============================================================
28
-
29
- export interface PendingMutation {
30
- id: string; // unique
31
- action: 'LinesAdd' | 'LinesUpdate' | 'LinesRemove';
32
- inputs: any;
22
+ interface LikeACart {
23
+ lines: { nodes: Array<any> };
33
24
  }
34
25
 
35
- // 关键:snapshot 必须是稳定引用,否则 useSyncExternalStore 每次比对都觉得变了
36
- // 无限 re-render(React #185)+ hydration mismatch(#418/#423)
37
- const EMPTY_SNAPSHOT: PendingMutation[] = [];
38
-
39
- const pendingStore = {
40
- items: new Map<string, PendingMutation>(),
41
- listeners: new Set<() => void>(),
42
- cachedSnapshot: EMPTY_SNAPSHOT as PendingMutation[],
43
-
44
- add(m: PendingMutation) {
45
- this.items.set(m.id, m);
46
- this.cachedSnapshot = Array.from(this.items.values());
47
- this.notify();
48
- },
49
- remove(id: string) {
50
- if (this.items.delete(id)) {
51
- this.cachedSnapshot = this.items.size === 0 ? EMPTY_SNAPSHOT : Array.from(this.items.values());
52
- this.notify();
26
+ export type OptimisticCartLine<T = any> = T extends LikeACart
27
+ ? T['lines']['nodes'][number] & { isOptimistic?: boolean }
28
+ : T & { isOptimistic?: boolean };
29
+
30
+ export type OptimisticCart<T = any> = T extends undefined | null
31
+ ? {
32
+ isOptimistic?: boolean;
33
+ lines: { nodes: Array<OptimisticCartLine> };
34
+ totalQuantity?: number;
53
35
  }
54
- },
55
- list(): PendingMutation[] {
56
- // 返回稳定引用(只在 add/remove 时改变)— 满足 useSyncExternalStore 契约
57
- return this.cachedSnapshot;
58
- },
59
- subscribe(fn: () => void): () => void {
60
- this.listeners.add(fn);
61
- return () => { this.listeners.delete(fn); };
62
- },
63
- notify() {
64
- for (const fn of this.listeners) fn();
65
- },
66
- };
36
+ : Omit<T, 'lines'> & {
37
+ isOptimistic?: boolean;
38
+ lines: { nodes: Array<OptimisticCartLine<T>> };
39
+ totalQuantity?: number;
40
+ };
67
41
 
68
42
  /**
69
- * Internal: CartForm 提交时调用,注册一个 pending mutation。返回 unregister。
43
+ * optimistic line 一个临时 id。Hydrogen 用 `gid://shopify/CartLine/optimistic-<variantId>`。
44
+ * 我们 shopbb 也用类似前缀。
70
45
  */
71
- export function __registerPendingMutation(m: PendingMutation): () => void {
72
- pendingStore.add(m);
73
- return () => pendingStore.remove(m.id);
46
+ function getOptimisticLineId(variantId: string): string {
47
+ return `optimistic-${variantId}`;
74
48
  }
75
49
 
76
- // ============================================================
77
- // useOptimisticCart hook
78
- // ============================================================
79
-
80
- export interface OptimisticCartLine {
81
- id: string;
82
- quantity: number;
83
- isOptimistic?: boolean;
84
- merchandise?: any;
85
- cost?: any;
86
- attributes?: any;
87
- [key: string]: any;
50
+ function isOptimisticLineId(id: string): boolean {
51
+ return id.startsWith('optimistic-');
88
52
  }
89
53
 
90
- export interface OptimisticCart<TCart = any> {
91
- isOptimistic?: boolean;
92
- totalQuantity?: number;
93
- lines?: { nodes: OptimisticCartLine[]; edges?: any };
94
- cost?: any;
95
- [key: string]: any;
96
- }
54
+ export function useOptimisticCart<DefaultCart = any>(
55
+ cart?: DefaultCart,
56
+ ): OptimisticCart<DefaultCart> {
57
+ const fetchers = useFetchers();
97
58
 
98
- export function useOptimisticCart<TCart extends OptimisticCart = OptimisticCart>(
99
- actualCart: TCart | null,
100
- ): TCart | null {
101
- // 订阅 pending store 重渲染
102
- const subscribe = React.useCallback((cb: () => void) => pendingStore.subscribe(cb), []);
103
- const getSnapshot = React.useCallback(() => pendingStore.list(), []);
104
- const pendings = React.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
105
-
106
- // 如果没有 pending,CartProvider 内部的 cart 已经是最新(因为 applyCart 同步过)
107
- const fallback = useCartOptional();
108
- const baseCart = (actualCart ?? (fallback?.cart as any)) as TCart | null;
109
-
110
- return React.useMemo(() => {
111
- if (!baseCart) {
112
- // 如果没有 actual cart 但有 pending LinesAdd → 模拟一个空 cart + 即将添加的行
113
- if (pendings.length === 0) return null;
114
- const optimisticLines: OptimisticCartLine[] = [];
115
- for (const p of pendings) {
116
- if (p.action === 'LinesAdd' && Array.isArray(p.inputs?.lines)) {
117
- for (const ln of p.inputs.lines) {
118
- optimisticLines.push({
119
- id: `__optimistic_${p.id}_${ln.merchandiseId}`,
120
- quantity: ln.quantity ?? 1,
121
- merchandise: { id: ln.merchandiseId },
122
- isOptimistic: true,
123
- });
124
- }
125
- }
126
- }
127
- if (optimisticLines.length === 0) return null;
128
- return {
129
- isOptimistic: true,
130
- totalQuantity: optimisticLines.reduce((s, l) => s + l.quantity, 0),
131
- lines: { nodes: optimisticLines },
132
- } as TCart;
133
- }
59
+ if (!fetchers || !fetchers.length) {
60
+ return cart as OptimisticCart<DefaultCart>;
61
+ }
62
+
63
+ // structuredClone 拷贝 cart(不污染 useLoaderData 的引用)
64
+ const optimisticCart: any = (cart as any)?.lines
65
+ ? (typeof structuredClone === 'function' ? structuredClone(cart) : JSON.parse(JSON.stringify(cart)))
66
+ : { lines: { nodes: [] } };
67
+
68
+ const cartLines: any[] = optimisticCart.lines?.nodes ?? [];
69
+ let isOptimistic = false;
70
+
71
+ for (const { formData } of fetchers) {
72
+ if (!formData) continue;
134
73
 
135
- if (pendings.length === 0) return baseCart;
136
-
137
- // 复制 lines(不深拷贝整个 cart — 只动 lines 节点列表)
138
- const linesNodes = ((baseCart as any).lines?.nodes ?? []).slice() as OptimisticCartLine[];
139
-
140
- for (const p of pendings) {
141
- if (p.action === 'LinesAdd' && Array.isArray(p.inputs?.lines)) {
142
- for (const ln of p.inputs.lines) {
143
- // 简化:若已有相同 merchandiseId 累加,否则追加
144
- const idx = linesNodes.findIndex((l) => l.merchandise?.id === ln.merchandiseId);
145
- if (idx >= 0) {
146
- linesNodes[idx] = {
147
- ...linesNodes[idx],
148
- quantity: linesNodes[idx].quantity + (ln.quantity ?? 1),
149
- isOptimistic: true,
150
- };
151
- } else {
152
- linesNodes.push({
153
- id: `__optimistic_${p.id}_${ln.merchandiseId}`,
154
- quantity: ln.quantity ?? 1,
155
- merchandise: { id: ln.merchandiseId },
156
- isOptimistic: true,
157
- });
158
- }
74
+ let cartFormData: any;
75
+ try {
76
+ cartFormData = CartForm.getFormInput(formData);
77
+ } catch {
78
+ continue;
79
+ }
80
+ if (!cartFormData?.action) continue;
81
+
82
+ if (cartFormData.action === CartForm.ACTIONS.LinesAdd) {
83
+ const lines: CartLineInput[] = cartFormData.inputs?.lines ?? [];
84
+ for (const input of lines) {
85
+ if (!input.selectedVariant) {
86
+ // 没传 selectedVariant,无法 optimistic 显示具体信息 — Hydrogen 的约束相同
87
+ continue;
88
+ }
89
+ const variantId = (input.selectedVariant as any)?.id;
90
+ const existingLine = cartLines.find(
91
+ (line) => line.merchandise?.id === variantId,
92
+ );
93
+ isOptimistic = true;
94
+ if (existingLine) {
95
+ existingLine.quantity = (existingLine.quantity || 1) + (input.quantity || 1);
96
+ existingLine.isOptimistic = true;
97
+ } else {
98
+ cartLines.unshift({
99
+ id: getOptimisticLineId(variantId),
100
+ merchandise: input.selectedVariant,
101
+ quantity: input.quantity || 1,
102
+ isOptimistic: true,
103
+ });
159
104
  }
160
- } else if (p.action === 'LinesUpdate' && Array.isArray(p.inputs?.lines)) {
161
- for (const ln of p.inputs.lines) {
162
- const idx = linesNodes.findIndex((l) => l.id === ln.id);
163
- if (idx >= 0) {
164
- linesNodes[idx] = { ...linesNodes[idx], quantity: ln.quantity ?? linesNodes[idx].quantity, isOptimistic: true };
165
- }
105
+ }
106
+ } else if (cartFormData.action === CartForm.ACTIONS.LinesRemove) {
107
+ const lineIds: string[] = cartFormData.inputs?.lineIds ?? [];
108
+ for (const lineId of lineIds) {
109
+ const idx = cartLines.findIndex((line) => line.id === lineId);
110
+ if (idx !== -1) {
111
+ if (isOptimisticLineId(cartLines[idx].id)) continue;
112
+ cartLines.splice(idx, 1);
113
+ isOptimistic = true;
166
114
  }
167
- } else if (p.action === 'LinesRemove' && Array.isArray(p.inputs?.lineIds)) {
168
- for (const id of p.inputs.lineIds) {
169
- const idx = linesNodes.findIndex((l) => l.id === id);
170
- if (idx >= 0) linesNodes.splice(idx, 1);
115
+ }
116
+ } else if (cartFormData.action === CartForm.ACTIONS.LinesUpdate) {
117
+ const lines: any[] = cartFormData.inputs?.lines ?? [];
118
+ for (const line of lines) {
119
+ const idx = cartLines.findIndex((optimisticLine) => line.id === optimisticLine.id);
120
+ if (idx > -1) {
121
+ if (isOptimisticLineId(cartLines[idx].id)) continue;
122
+ cartLines[idx].quantity = line.quantity as number;
123
+ if (cartLines[idx].quantity === 0) cartLines.splice(idx, 1);
124
+ isOptimistic = true;
171
125
  }
172
126
  }
173
127
  }
128
+ }
129
+
130
+ if (isOptimistic) optimisticCart.isOptimistic = isOptimistic;
131
+ optimisticCart.totalQuantity = cartLines.reduce(
132
+ (sum, line) => sum + (line.quantity || 0),
133
+ 0,
134
+ );
135
+ optimisticCart.lines = { ...optimisticCart.lines, nodes: cartLines };
136
+
137
+ return optimisticCart as OptimisticCart<DefaultCart>;
138
+ }
174
139
 
175
- const totalQuantity = linesNodes.reduce((s, l) => s + l.quantity, 0);
176
- return {
177
- ...(baseCart as any),
178
- isOptimistic: true,
179
- totalQuantity,
180
- lines: { ...(baseCart as any).lines, nodes: linesNodes },
181
- } as TCart;
182
- }, [baseCart, pendings]);
140
+ // API 兼容(pendingStore 已废弃)
141
+ export function __registerPendingMutation(): () => void {
142
+ return () => {};
143
+ }
144
+
145
+ export interface PendingMutation {
146
+ id: string;
147
+ action: 'LinesAdd' | 'LinesUpdate' | 'LinesRemove';
148
+ inputs: any;
183
149
  }
@@ -1,42 +1,18 @@
1
1
  /**
2
2
  * @shopbb/helium/components — 商家用 React 组件
3
3
  *
4
- * 用法:
5
- * import {
6
- * ShopProvider, CartProvider, AnalyticsProvider,
7
- * useShop, useCart, useAnalytics,
8
- * Money, Image, ProductPrice,
9
- * AddToCartButton, CartLineQuantityAdjustButton,
10
- * VariantSelector, ProductOptionsProvider, useProductOptions,
11
- * Analytics,
12
- * } from '@shopbb/helium/components';
13
- *
14
- * 设计原则:
15
- * - 无样式:组件只管行为 + 语义化 DOM,样式商家自己写
16
- * - data-* 钩子:方便选择器
17
- * - 对齐 Shopify Hydrogen 同名组件的 API,迁移成本低
18
- * - Provider 链:<ShopProvider> > <CartProvider> > <AnalyticsProvider> > App
19
- * 组件优先从 Provider 拿;Provider 缺省时回退到 props 或 noop
4
+ * 0.7 起严格对齐 Shopify Hydrogen 设计原则:
5
+ * - 数据流:服务端 loader → useLoaderData → 组件 props(不通过 Provider)
6
+ * - mutation:<CartForm> + RR7 useFetcher(自动 revalidate loader)
7
+ * - 删除 CartProvider / DiscountProvider / AddressBookProvider
20
8
  */
21
9
 
22
- // Providers + hooks
10
+ // Providers + hooks(保留:仅 Shop / ProductOptions / CartLine / Analytics,对齐 Hydrogen)
23
11
  export { ShopProvider, useShop, useShopOptional } from './ShopProvider';
24
12
  export type { ShopContextValue, ShopProviderProps } from './ShopProvider';
25
- // Hydrogen-compatible alias: <ShopifyProvider> 在我们叫 <ShopProvider>,提供别名让 Hydrogen 代码无痛迁移
26
13
  export { ShopProvider as ShopifyProvider } from './ShopProvider';
27
14
  export type { ShopProviderProps as ShopifyProviderProps } from './ShopProvider';
28
15
 
29
- export { CartProvider, useCart, useCartOptional } from './CartProvider';
30
- export type {
31
- Cart,
32
- CartLine,
33
- CartLineMerchandise,
34
- CartStatus,
35
- CartUserError,
36
- CartContextValue,
37
- CartProviderProps,
38
- } from './CartProvider';
39
-
40
16
  export {
41
17
  ProductOptionsProvider,
42
18
  useProductOptions,
@@ -50,6 +26,10 @@ export type {
50
26
  export { AnalyticsProvider, useAnalytics, Analytics } from './AnalyticsProvider';
51
27
  export type { AnalyticsEvent, AnalyticsContextValue, AnalyticsProviderProps } from './AnalyticsProvider';
52
28
 
29
+ // CartLine context(Hydrogen 标准:cart line 子组件用 useCartLine 拿当前 line)
30
+ export { CartLineProvider, useCartLine, useCartLineOptional } from './CartLineProvider';
31
+ export type { CartLineProviderProps, CartLineLike } from './CartLineProvider';
32
+
53
33
  // 展示型组件
54
34
  export { Money } from './Money';
55
35
  export type { MoneyProps, MoneyData, MoneyMeasurement } from './Money';
@@ -60,12 +40,6 @@ export type { ImageProps, ImageData } from './Image';
60
40
  export { ProductPrice } from './ProductPrice';
61
41
  export type { ProductPriceProps } from './ProductPrice';
62
42
 
63
- export { AddToCartButton } from './AddToCartButton';
64
- export type { AddToCartButtonProps } from './AddToCartButton';
65
-
66
- export { CartLineQuantityAdjustButton } from './CartLineQuantityAdjustButton';
67
- export type { CartLineQuantityAdjustButtonProps } from './CartLineQuantityAdjustButton';
68
-
69
43
  export { VariantSelector } from './VariantSelector';
70
44
  export type {
71
45
  VariantSelectorProps,
@@ -73,51 +47,45 @@ export type {
73
47
  VariantOption,
74
48
  } from './VariantSelector';
75
49
 
76
- // 地址簿(W4a)
77
- export {
78
- AddressBookProvider,
79
- useAddressBook,
80
- useAddressBookOptional,
81
- } from './AddressBookProvider';
50
+ export { CartLineQuantity } from './CartLineQuantity';
51
+ export type { CartLineQuantityProps } from './CartLineQuantity';
52
+
53
+ export { CartCost } from './CartCost';
54
+ export type { CartCostProps, MoneyValue } from './CartCost';
55
+
56
+ export { CartCheckoutButton } from './CartCheckoutButton';
57
+ export type { CartCheckoutButtonProps } from './CartCheckoutButton';
58
+
59
+ // CartForm + useFetcher 透传(Hydrogen 标准)
60
+ export { CartForm, CART_FORM_ACTIONS, useFetcher } from './CartForm';
82
61
  export type {
83
- Address,
84
- AddressInput,
85
- AddressBookStatus,
86
- AddressBookUserError,
87
- AddressBookContextValue,
88
- AddressBookProviderProps,
89
- } from './AddressBookProvider';
62
+ CartFormProps, CartFormInput, CartFormFetcher, CartFormAction,
63
+ CartLineInput, CartLineUpdateInput, FetcherWithComponents,
64
+ } from './CartForm';
90
65
 
91
- export { AddressList } from './AddressList';
92
- export type { AddressListProps, AddressListItemActions } from './AddressList';
66
+ // 按钮组件(内部用 CartForm)
67
+ export { AddToCartButton } from './AddToCartButton';
68
+ export type { AddToCartButtonProps } from './AddToCartButton';
69
+ export { BuyNowButton } from './BuyNowButton';
70
+ export type { BuyNowButtonProps } from './BuyNowButton';
93
71
 
94
- export { AddressForm } from './AddressForm';
95
- export type { AddressFormProps, AddressFormI18n } from './AddressForm';
72
+ // useOptimisticCart RR7 useFetchers() 实现(对齐 Hydrogen)
73
+ export { useOptimisticCart } from './hooks/useOptimisticCart';
74
+ export type { OptimisticCart, OptimisticCartLine, PendingMutation } from './hooks/useOptimisticCart';
96
75
 
76
+ // useMoney hook
77
+ export { useMoney } from './hooks/useMoney';
78
+ export type { MoneyV2, MoneyParts } from './hooks/useMoney';
79
+
80
+ // 地址簿(接 props,不再用 Provider)
81
+ export { AddressList } from './AddressList';
82
+ export type { AddressListProps, AddressListItemActions, Address } from './AddressList';
83
+ export { AddressForm } from './AddressForm';
84
+ export type { AddressFormProps, AddressFormI18n, AddressInput, AddressBookUserError, AddressFormSubmitResult } from './AddressForm';
97
85
  export { AddressPicker } from './AddressPicker';
98
86
  export type { AddressPickerProps } from './AddressPicker';
99
87
 
100
- // 优惠券(W4b
101
- export {
102
- DiscountProvider,
103
- useDiscounts,
104
- useDiscountsOptional,
105
- useProductDiscounts,
106
- } from './DiscountProvider';
107
- export type {
108
- Discount,
109
- DiscountClaim,
110
- DiscountValueType,
111
- DiscountValuePercentage,
112
- DiscountValueAmount,
113
- DiscountValueFreeShipping,
114
- CartDiscountCode,
115
- CartDiscountAllocation,
116
- DiscountUserError,
117
- DiscountContextValue,
118
- DiscountProviderProps,
119
- } from './DiscountProvider';
120
-
88
+ // 优惠券(接 props,不再用 Provider
121
89
  export {
122
90
  AppliedDiscountList,
123
91
  ClaimableDiscountList,
@@ -129,36 +97,20 @@ export type {
129
97
  ClaimableDiscountListProps,
130
98
  DiscountClaimButtonProps,
131
99
  MyDiscountListProps,
100
+ Discount,
101
+ DiscountClaim,
102
+ DiscountValueType,
103
+ DiscountValuePercentage,
104
+ DiscountValueAmount,
105
+ DiscountValueFreeShipping,
106
+ DiscountAllocation,
132
107
  } from './DiscountComponents';
133
108
 
134
109
  export { DiscountSelector } from './DiscountSelector';
135
- export type { DiscountSelectorProps } from './DiscountSelector';
136
-
137
- // SSR / hydrate 辅助 hook
138
- export { useMounted } from './hooks/useMounted';
139
- export { useOptimisticCart } from './hooks/useOptimisticCart';
140
- export type { OptimisticCart, OptimisticCartLine, PendingMutation } from './hooks/useOptimisticCart';
141
- export { useMoney } from './hooks/useMoney';
142
- export type { MoneyV2, MoneyParts } from './hooks/useMoney';
143
-
144
- // CartForm — Hydrogen-compatible form-based cart mutation API
145
- export { CartForm, CART_FORM_ACTIONS, useFetcher } from './CartForm';
146
110
  export type {
147
- CartFormProps, CartFormInput, CartFormFetcher, CartFormAction,
148
- CartLineInput, CartLineUpdateInput,
149
- } from './CartForm';
150
-
151
- // Cart line context + 子组件
152
- export { CartLineProvider, useCartLine, useCartLineOptional } from './CartLineProvider';
153
- export type { CartLineProviderProps, CartLineLike } from './CartLineProvider';
154
- export { CartLineQuantity } from './CartLineQuantity';
155
- export type { CartLineQuantityProps } from './CartLineQuantity';
156
- export { CartCost } from './CartCost';
157
- export type { CartCostProps, MoneyValue } from './CartCost';
158
- export { CartCheckoutButton } from './CartCheckoutButton';
159
- export type { CartCheckoutButtonProps } from './CartCheckoutButton';
160
- export { BuyNowButton } from './BuyNowButton';
161
- export type { BuyNowButtonProps } from './BuyNowButton';
111
+ DiscountSelectorProps,
112
+ AppliedDiscountClaim,
113
+ } from './DiscountSelector';
162
114
 
163
115
  // Rich text
164
116
  export { RichText } from './RichText';
package/src/index.ts CHANGED
@@ -18,8 +18,6 @@ export { createStorefrontClient } from './createStorefrontClient';
18
18
  export { createCartHandler, DEFAULT_CART_FRAGMENT } from './createCartHandler';
19
19
  export { cartGetIdDefault, cartSetIdDefault } from './cart-id';
20
20
  export type { CartSetIdOptions } from './cart-id';
21
- export { handleCartFormAction } from './handleCartFormAction';
22
- export type { HandleCartFormActionOptions } from './handleCartFormAction';
23
21
  export { CacheNone, CacheShort, CacheLong, CacheCustom } from './cache';
24
22
 
25
23
  // 服务端工具