@shopbb/helium 0.2.0 → 0.3.0-alpha.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 (56) hide show
  1. package/dist/components/AddToCartButton.d.ts +41 -0
  2. package/dist/components/AddToCartButton.d.ts.map +1 -0
  3. package/dist/components/AddToCartButton.js +63 -0
  4. package/dist/components/AddToCartButton.js.map +1 -0
  5. package/dist/components/AnalyticsProvider.d.ts +106 -0
  6. package/dist/components/AnalyticsProvider.d.ts.map +1 -0
  7. package/dist/components/AnalyticsProvider.js +135 -0
  8. package/dist/components/AnalyticsProvider.js.map +1 -0
  9. package/dist/components/CartLineQuantityAdjustButton.d.ts +40 -0
  10. package/dist/components/CartLineQuantityAdjustButton.d.ts.map +1 -0
  11. package/dist/components/CartLineQuantityAdjustButton.js +58 -0
  12. package/dist/components/CartLineQuantityAdjustButton.js.map +1 -0
  13. package/dist/components/CartProvider.d.ts +111 -0
  14. package/dist/components/CartProvider.d.ts.map +1 -0
  15. package/dist/components/CartProvider.js +263 -0
  16. package/dist/components/CartProvider.js.map +1 -0
  17. package/dist/components/Image.d.ts +39 -0
  18. package/dist/components/Image.d.ts.map +1 -0
  19. package/dist/components/Image.js +28 -0
  20. package/dist/components/Image.js.map +1 -0
  21. package/dist/components/Money.d.ts +41 -0
  22. package/dist/components/Money.d.ts.map +1 -0
  23. package/dist/components/Money.js +53 -0
  24. package/dist/components/Money.js.map +1 -0
  25. package/dist/components/ProductOptionsProvider.d.ts +70 -0
  26. package/dist/components/ProductOptionsProvider.d.ts.map +1 -0
  27. package/dist/components/ProductOptionsProvider.js +93 -0
  28. package/dist/components/ProductOptionsProvider.js.map +1 -0
  29. package/dist/components/ProductPrice.d.ts +28 -0
  30. package/dist/components/ProductPrice.d.ts.map +1 -0
  31. package/dist/components/ProductPrice.js +10 -0
  32. package/dist/components/ProductPrice.js.map +1 -0
  33. package/dist/components/ShopProvider.d.ts +49 -0
  34. package/dist/components/ShopProvider.d.ts.map +1 -0
  35. package/dist/components/ShopProvider.js +62 -0
  36. package/dist/components/ShopProvider.js.map +1 -0
  37. package/dist/components/VariantSelector.d.ts +80 -0
  38. package/dist/components/VariantSelector.d.ts.map +1 -0
  39. package/dist/components/VariantSelector.js +87 -0
  40. package/dist/components/VariantSelector.js.map +1 -0
  41. package/dist/components/index.d.ts +41 -0
  42. package/dist/components/index.d.ts.map +1 -0
  43. package/dist/components/index.js +33 -0
  44. package/dist/components/index.js.map +1 -0
  45. package/package.json +12 -4
  46. package/src/components/AddToCartButton.tsx +101 -0
  47. package/src/components/AnalyticsProvider.tsx +175 -0
  48. package/src/components/CartLineQuantityAdjustButton.tsx +119 -0
  49. package/src/components/CartProvider.tsx +378 -0
  50. package/src/components/Image.tsx +93 -0
  51. package/src/components/Money.tsx +112 -0
  52. package/src/components/ProductOptionsProvider.tsx +149 -0
  53. package/src/components/ProductPrice.tsx +61 -0
  54. package/src/components/ShopProvider.tsx +86 -0
  55. package/src/components/VariantSelector.tsx +148 -0
  56. package/src/components/index.ts +71 -0
@@ -0,0 +1,41 @@
1
+ /**
2
+ * <AddToCartButton> — 加入购物车按钮
3
+ *
4
+ * 对齐 @shopify/hydrogen <AddToCartButton>:
5
+ * - 内置 loading 态、disabled、error 处理
6
+ * - 支持 onAdd 回调(实际加购逻辑由外部 cart hook 提供)
7
+ * - 触发 analytics 事件钩子
8
+ * - 不带样式,商家自己控制
9
+ *
10
+ * 用法(Phase 1,需要传 onAdd):
11
+ * const { addLine } = useCart();
12
+ * <AddToCartButton
13
+ * variantId={selectedVariant.id}
14
+ * quantity={1}
15
+ * disabled={!selectedVariant.availableForSale}
16
+ * onAdd={(vid, qty) => addLine(vid, qty)}
17
+ * >
18
+ * 加入购物车
19
+ * </AddToCartButton>
20
+ *
21
+ * Phase 2 后:组件会自动从 <CartProvider> 拿,无需 onAdd 也能用。
22
+ */
23
+ import * as React from 'react';
24
+ export interface AddToCartButtonProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'onClick' | 'onError'> {
25
+ /** 必传:variant 的 GID(gid://shopbb/ProductVariant/...) */
26
+ variantId: string;
27
+ /** 数量,默认 1 */
28
+ quantity?: number;
29
+ /** 实际加购回调。Phase 1 必传;Phase 2 后可从 Provider 自动获取 */
30
+ onAdd?: (variantId: string, quantity: number) => Promise<void>;
31
+ /** 加购成功回调(如导航到 /cart) */
32
+ onAdded?: () => void;
33
+ /** 加购失败回调 */
34
+ onError?: (err: Error) => void;
35
+ /** 加购中显示的文本,默认 "加入中..." */
36
+ loadingText?: React.ReactNode;
37
+ /** 不可用时显示的文本,默认 "缺货" */
38
+ unavailableText?: React.ReactNode;
39
+ }
40
+ export declare function AddToCartButton(props: AddToCartButtonProps): import("react/jsx-runtime").JSX.Element;
41
+ //# sourceMappingURL=AddToCartButton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AddToCartButton.d.ts","sourceRoot":"","sources":["../../src/components/AddToCartButton.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,MAAM,WAAW,oBAAqB,SAAQ,IAAI,CAAC,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IACtH,wDAAwD;IACxD,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kDAAkD;IAClD,KAAK,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/D,yBAAyB;IACzB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,aAAa;IACb,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,CAAC;IAC/B,2BAA2B;IAC3B,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC9B,wBAAwB;IACxB,eAAe,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CACnC;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,2CAwD1D"}
@@ -0,0 +1,63 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * <AddToCartButton> — 加入购物车按钮
4
+ *
5
+ * 对齐 @shopify/hydrogen <AddToCartButton>:
6
+ * - 内置 loading 态、disabled、error 处理
7
+ * - 支持 onAdd 回调(实际加购逻辑由外部 cart hook 提供)
8
+ * - 触发 analytics 事件钩子
9
+ * - 不带样式,商家自己控制
10
+ *
11
+ * 用法(Phase 1,需要传 onAdd):
12
+ * const { addLine } = useCart();
13
+ * <AddToCartButton
14
+ * variantId={selectedVariant.id}
15
+ * quantity={1}
16
+ * disabled={!selectedVariant.availableForSale}
17
+ * onAdd={(vid, qty) => addLine(vid, qty)}
18
+ * >
19
+ * 加入购物车
20
+ * </AddToCartButton>
21
+ *
22
+ * Phase 2 后:组件会自动从 <CartProvider> 拿,无需 onAdd 也能用。
23
+ */
24
+ import * as React from 'react';
25
+ import { useCartOptional } from './CartProvider';
26
+ import { useAnalytics } from './AnalyticsProvider';
27
+ export function AddToCartButton(props) {
28
+ const { variantId, quantity = 1, onAdd, onAdded, onError, loadingText = '加入中...', unavailableText = '缺货', children = '加入购物车', disabled: disabledProp, ...rest } = props;
29
+ const [adding, setAdding] = React.useState(false);
30
+ const cart = useCartOptional();
31
+ const analytics = useAnalytics();
32
+ const handleClick = async (e) => {
33
+ e.preventDefault();
34
+ if (adding || disabledProp)
35
+ return;
36
+ setAdding(true);
37
+ try {
38
+ if (onAdd) {
39
+ // 商家显式传了 onAdd 优先用(Phase 1 兼容路径)
40
+ await onAdd(variantId, quantity);
41
+ }
42
+ else if (cart) {
43
+ // 自动从 <CartProvider> 取
44
+ await cart.linesAdd([{ merchandiseId: variantId, quantity }]);
45
+ }
46
+ else {
47
+ console.warn('[AddToCartButton] no onAdd and no <CartProvider> — button does nothing');
48
+ return;
49
+ }
50
+ analytics.emit('add_to_cart', { variantId, quantity });
51
+ onAdded?.();
52
+ }
53
+ catch (err) {
54
+ console.error('[AddToCartButton] add failed:', err);
55
+ onError?.(err instanceof Error ? err : new Error(String(err)));
56
+ }
57
+ finally {
58
+ setAdding(false);
59
+ }
60
+ };
61
+ return (_jsx("button", { type: "button", ...rest, "data-add-to-cart": true, "data-loading": adding ? '' : undefined, disabled: disabledProp || adding, onClick: handleClick, children: adding ? loadingText : disabledProp ? unavailableText : children }));
62
+ }
63
+ //# sourceMappingURL=AddToCartButton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AddToCartButton.js","sourceRoot":"","sources":["../../src/components/AddToCartButton.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAmBnD,MAAM,UAAU,eAAe,CAAC,KAA2B;IACzD,MAAM,EACJ,SAAS,EACT,QAAQ,GAAG,CAAC,EACZ,KAAK,EACL,OAAO,EACP,OAAO,EACP,WAAW,GAAG,QAAQ,EACtB,eAAe,GAAG,IAAI,EACtB,QAAQ,GAAG,OAAO,EAClB,QAAQ,EAAE,YAAY,EACtB,GAAG,IAAI,EACR,GAAG,KAAK,CAAC;IAEV,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClD,MAAM,IAAI,GAAG,eAAe,EAAE,CAAC;IAC/B,MAAM,SAAS,GAAG,YAAY,EAAE,CAAC;IAEjC,MAAM,WAAW,GAAG,KAAK,EAAE,CAAsC,EAAE,EAAE;QACnE,CAAC,CAAC,cAAc,EAAE,CAAC;QACnB,IAAI,MAAM,IAAI,YAAY;YAAE,OAAO;QAEnC,SAAS,CAAC,IAAI,CAAC,CAAC;QAChB,IAAI,CAAC;YACH,IAAI,KAAK,EAAE,CAAC;gBACV,iCAAiC;gBACjC,MAAM,KAAK,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;YACnC,CAAC;iBAAM,IAAI,IAAI,EAAE,CAAC;gBAChB,uBAAuB;gBACvB,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,aAAa,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;YAChE,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,IAAI,CAAC,wEAAwE,CAAC,CAAC;gBACvF,OAAO;YACT,CAAC;YACD,SAAS,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC;YACvD,OAAO,EAAE,EAAE,CAAC;QACd,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,GAAG,CAAC,CAAC;YACpD,OAAO,EAAE,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACjE,CAAC;gBAAS,CAAC;YACT,SAAS,CAAC,KAAK,CAAC,CAAC;QACnB,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,CACL,iBACE,IAAI,EAAC,QAAQ,KACT,IAAI,4CAEM,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,EACrC,QAAQ,EAAE,YAAY,IAAI,MAAM,EAChC,OAAO,EAAE,WAAW,YAEnB,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,GAC1D,CACV,CAAC;AACJ,CAAC"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * <AnalyticsProvider> + useAnalytics() + <Analytics.*> 事件组件
3
+ *
4
+ * 简单事件总线:
5
+ * - 商家注册 reporters(GA / Plausible / 自家 API)
6
+ * - 通过 <Analytics.PageView /> / <Analytics.ProductView /> 等组件声明式触发
7
+ * - 也可以 useAnalytics().emit(name, data)
8
+ *
9
+ * 用法:
10
+ * <AnalyticsProvider
11
+ * onEvent={(e) => {
12
+ * fetch('/api/analytics', { method: 'POST', body: JSON.stringify(e) });
13
+ * window.dataLayer?.push(e);
14
+ * }}
15
+ * >
16
+ * <App />
17
+ * </AnalyticsProvider>
18
+ *
19
+ * // 在某页:
20
+ * <Analytics.PageView path="/products" title="Products" />
21
+ * <Analytics.ProductView product={product} />
22
+ * <Analytics.AddToCart cart={cart} addedLineId={lineId} />
23
+ *
24
+ * // 命令式:
25
+ * const { emit } = useAnalytics();
26
+ * emit('search', { query: 'wireless' });
27
+ */
28
+ import * as React from 'react';
29
+ export interface AnalyticsEvent {
30
+ /** 事件名,例如 'page_view' / 'product_view' / 'add_to_cart' */
31
+ name: string;
32
+ /** 时间戳 (ms) */
33
+ timestamp: number;
34
+ /** 当前 shop(如果在 ShopProvider 内) */
35
+ shop?: {
36
+ storeId: string;
37
+ shopName: string;
38
+ } | null;
39
+ /** 自定义 payload */
40
+ payload: Record<string, any>;
41
+ }
42
+ export interface AnalyticsContextValue {
43
+ emit: (name: string, payload?: Record<string, any>) => void;
44
+ }
45
+ export interface AnalyticsProviderProps {
46
+ children: React.ReactNode;
47
+ /** 接收所有事件的回调 */
48
+ onEvent?: (event: AnalyticsEvent) => void;
49
+ /** 是否自动监听 cart 变化触发 cart_updated 事件 */
50
+ trackCart?: boolean;
51
+ }
52
+ export declare function AnalyticsProvider(props: AnalyticsProviderProps): import("react/jsx-runtime").JSX.Element;
53
+ export declare function useAnalytics(): AnalyticsContextValue;
54
+ declare function PageView(props: {
55
+ path?: string;
56
+ title?: string;
57
+ [key: string]: any;
58
+ }): null;
59
+ declare function ProductView(props: {
60
+ product: {
61
+ id: string;
62
+ handle?: string;
63
+ title?: string;
64
+ };
65
+ [key: string]: any;
66
+ }): null;
67
+ declare function CollectionView(props: {
68
+ collection: {
69
+ id: string;
70
+ handle?: string;
71
+ };
72
+ [key: string]: any;
73
+ }): null;
74
+ declare function SearchView(props: {
75
+ query: string;
76
+ results?: number;
77
+ }): null;
78
+ declare function AddToCart(props: {
79
+ variantId: string;
80
+ quantity?: number;
81
+ [key: string]: any;
82
+ }): null;
83
+ declare function CheckoutStart(props: {
84
+ cart?: {
85
+ id: string;
86
+ totalQuantity?: number;
87
+ };
88
+ }): null;
89
+ declare function Purchase(props: {
90
+ orderId: string;
91
+ total: number;
92
+ currencyCode: string;
93
+ [key: string]: any;
94
+ }): null;
95
+ /** 命名空间导出,让用户写 <Analytics.PageView /> */
96
+ export declare const Analytics: {
97
+ PageView: typeof PageView;
98
+ ProductView: typeof ProductView;
99
+ CollectionView: typeof CollectionView;
100
+ SearchView: typeof SearchView;
101
+ AddToCart: typeof AddToCart;
102
+ CheckoutStart: typeof CheckoutStart;
103
+ Purchase: typeof Purchase;
104
+ };
105
+ export {};
106
+ //# sourceMappingURL=AnalyticsProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AnalyticsProvider.d.ts","sourceRoot":"","sources":["../../src/components/AnalyticsProvider.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,MAAM,WAAW,cAAc;IAC7B,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,eAAe;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,kCAAkC;IAClC,IAAI,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACpD,kBAAkB;IAClB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,CAAC;CAC7D;AAID,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,gBAAgB;IAChB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC1C,uCAAuC;IACvC,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,2CAkC9D;AAED,wBAAgB,YAAY,IAAI,qBAAqB,CAOpD;AAkBD,iBAAS,QAAQ,CAAC,KAAK,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,QAE7E;AAED,iBAAS,WAAW,CAAC,KAAK,EAAE;IAAE,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,QAQ3G;AAED,iBAAS,cAAc,CAAC,KAAK,EAAE;IAAE,UAAU,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,QAOjG;AAED,iBAAS,UAAU,CAAC,KAAK,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,QAE7D;AAED,iBAAS,SAAS,CAAC,KAAK,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,QAOrF;AAED,iBAAS,aAAa,CAAC,KAAK,EAAE;IAAE,IAAI,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,QAK9E;AAED,iBAAS,QAAQ,CAAC,KAAK,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,QAEpG;AAED,yCAAyC;AACzC,eAAO,MAAM,SAAS;;;;;;;;CAQrB,CAAC"}
@@ -0,0 +1,135 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * <AnalyticsProvider> + useAnalytics() + <Analytics.*> 事件组件
4
+ *
5
+ * 简单事件总线:
6
+ * - 商家注册 reporters(GA / Plausible / 自家 API)
7
+ * - 通过 <Analytics.PageView /> / <Analytics.ProductView /> 等组件声明式触发
8
+ * - 也可以 useAnalytics().emit(name, data)
9
+ *
10
+ * 用法:
11
+ * <AnalyticsProvider
12
+ * onEvent={(e) => {
13
+ * fetch('/api/analytics', { method: 'POST', body: JSON.stringify(e) });
14
+ * window.dataLayer?.push(e);
15
+ * }}
16
+ * >
17
+ * <App />
18
+ * </AnalyticsProvider>
19
+ *
20
+ * // 在某页:
21
+ * <Analytics.PageView path="/products" title="Products" />
22
+ * <Analytics.ProductView product={product} />
23
+ * <Analytics.AddToCart cart={cart} addedLineId={lineId} />
24
+ *
25
+ * // 命令式:
26
+ * const { emit } = useAnalytics();
27
+ * emit('search', { query: 'wireless' });
28
+ */
29
+ import * as React from 'react';
30
+ import { useCartOptional } from './CartProvider';
31
+ import { useShopOptional } from './ShopProvider';
32
+ const Ctx = React.createContext(null);
33
+ export function AnalyticsProvider(props) {
34
+ const { children, onEvent, trackCart = true } = props;
35
+ const shop = useShopOptional();
36
+ const cartCtx = useCartOptional();
37
+ const onEventRef = React.useRef(onEvent);
38
+ React.useEffect(() => {
39
+ onEventRef.current = onEvent;
40
+ }, [onEvent]);
41
+ const emit = React.useCallback((name, payload = {}) => {
42
+ onEventRef.current?.({
43
+ name,
44
+ timestamp: Date.now(),
45
+ shop: shop ? { storeId: shop.storeId, shopName: shop.shopName } : null,
46
+ payload,
47
+ });
48
+ }, [shop]);
49
+ // cart 自动追踪
50
+ React.useEffect(() => {
51
+ if (!trackCart || !cartCtx)
52
+ return;
53
+ return cartCtx.subscribe((c) => {
54
+ emit('cart_updated', {
55
+ cartId: c?.id,
56
+ totalQuantity: c?.totalQuantity,
57
+ totalAmount: c?.cost.totalAmount,
58
+ });
59
+ });
60
+ }, [trackCart, cartCtx, emit]);
61
+ return _jsx(Ctx.Provider, { value: { emit }, children: children });
62
+ }
63
+ export function useAnalytics() {
64
+ const v = React.useContext(Ctx);
65
+ if (!v) {
66
+ // 没 Provider 时返回 noop(不 throw,便于组件可选嵌入)
67
+ return { emit: () => { } };
68
+ }
69
+ return v;
70
+ }
71
+ // ============================================================
72
+ // 声明式事件组件
73
+ // ============================================================
74
+ function useEmitOnMount(name, payload) {
75
+ const { emit } = useAnalytics();
76
+ const payloadRef = React.useRef(payload);
77
+ payloadRef.current = payload;
78
+ React.useEffect(() => {
79
+ emit(name, payloadRef.current);
80
+ // 只 mount 时触发一次(路由切换会重新 mount)
81
+ // eslint-disable-next-line react-hooks/exhaustive-deps
82
+ }, []);
83
+ return null;
84
+ }
85
+ function PageView(props) {
86
+ return useEmitOnMount('page_view', props);
87
+ }
88
+ function ProductView(props) {
89
+ const { product, ...rest } = props;
90
+ return useEmitOnMount('product_view', {
91
+ ...rest,
92
+ productId: product.id,
93
+ productHandle: product.handle,
94
+ productTitle: product.title,
95
+ });
96
+ }
97
+ function CollectionView(props) {
98
+ const { collection, ...rest } = props;
99
+ return useEmitOnMount('collection_view', {
100
+ ...rest,
101
+ collectionId: collection.id,
102
+ collectionHandle: collection.handle,
103
+ });
104
+ }
105
+ function SearchView(props) {
106
+ return useEmitOnMount('search', { query: props.query, results: props.results });
107
+ }
108
+ function AddToCart(props) {
109
+ const { variantId, quantity, ...rest } = props;
110
+ return useEmitOnMount('add_to_cart', {
111
+ ...rest,
112
+ variantId,
113
+ quantity: quantity ?? 1,
114
+ });
115
+ }
116
+ function CheckoutStart(props) {
117
+ return useEmitOnMount('checkout_start', {
118
+ cartId: props.cart?.id,
119
+ totalQuantity: props.cart?.totalQuantity,
120
+ });
121
+ }
122
+ function Purchase(props) {
123
+ return useEmitOnMount('purchase', props);
124
+ }
125
+ /** 命名空间导出,让用户写 <Analytics.PageView /> */
126
+ export const Analytics = {
127
+ PageView,
128
+ ProductView,
129
+ CollectionView,
130
+ SearchView,
131
+ AddToCart,
132
+ CheckoutStart,
133
+ Purchase,
134
+ };
135
+ //# sourceMappingURL=AnalyticsProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AnalyticsProvider.js","sourceRoot":"","sources":["../../src/components/AnalyticsProvider.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * <CartLineQuantityAdjustButton> — cart 行数量加减按钮
3
+ *
4
+ * 对齐 @shopify/hydrogen <CartLineQuantityAdjustButton>:
5
+ * - +/- 按钮调用 onChange
6
+ * - 防抖(300ms)避免点快导致多次请求
7
+ * - min/max 校验
8
+ * - 移除时弹确认(可选)
9
+ *
10
+ * 用法:
11
+ * const { updateLine, removeLine } = useCart();
12
+ * <CartLineQuantityAdjustButton
13
+ * line={line}
14
+ * onUpdate={(newQty) => updateLine(line.id, newQty)}
15
+ * onRemove={() => removeLine(line.id)}
16
+ * />
17
+ */
18
+ import * as React from 'react';
19
+ export interface CartLineQuantityAdjustButtonProps {
20
+ /** line 的当前数量 */
21
+ quantity: number;
22
+ /** 最小值,默认 1(小于此值改成 remove) */
23
+ min?: number;
24
+ /** 最大值,默认 99 */
25
+ max?: number;
26
+ /** 数量变化回调 */
27
+ onUpdate?: (newQuantity: number) => Promise<void> | void;
28
+ /** 数量降到 0 时触发 remove */
29
+ onRemove?: () => Promise<void> | void;
30
+ /** 防抖延迟(ms),默认 300 */
31
+ debounceMs?: number;
32
+ /** 自定义包装容器 className */
33
+ className?: string;
34
+ /** 减号按钮 props 透传 */
35
+ decreaseProps?: React.ButtonHTMLAttributes<HTMLButtonElement>;
36
+ /** 加号按钮 props 透传 */
37
+ increaseProps?: React.ButtonHTMLAttributes<HTMLButtonElement>;
38
+ }
39
+ export declare function CartLineQuantityAdjustButton(props: CartLineQuantityAdjustButtonProps): import("react/jsx-runtime").JSX.Element;
40
+ //# sourceMappingURL=CartLineQuantityAdjustButton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CartLineQuantityAdjustButton.d.ts","sourceRoot":"","sources":["../../src/components/CartLineQuantityAdjustButton.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,MAAM,WAAW,iCAAiC;IAChD,iBAAiB;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,8BAA8B;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,gBAAgB;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,aAAa;IACb,QAAQ,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACzD,wBAAwB;IACxB,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACtC,sBAAsB;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wBAAwB;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oBAAoB;IACpB,aAAa,CAAC,EAAE,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,CAAC;IAC9D,oBAAoB;IACpB,aAAa,CAAC,EAAE,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,CAAC;CAC/D;AAED,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,iCAAiC,2CA6EpF"}
@@ -0,0 +1,58 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * <CartLineQuantityAdjustButton> — cart 行数量加减按钮
4
+ *
5
+ * 对齐 @shopify/hydrogen <CartLineQuantityAdjustButton>:
6
+ * - +/- 按钮调用 onChange
7
+ * - 防抖(300ms)避免点快导致多次请求
8
+ * - min/max 校验
9
+ * - 移除时弹确认(可选)
10
+ *
11
+ * 用法:
12
+ * const { updateLine, removeLine } = useCart();
13
+ * <CartLineQuantityAdjustButton
14
+ * line={line}
15
+ * onUpdate={(newQty) => updateLine(line.id, newQty)}
16
+ * onRemove={() => removeLine(line.id)}
17
+ * />
18
+ */
19
+ import * as React from 'react';
20
+ export function CartLineQuantityAdjustButton(props) {
21
+ const { quantity, min = 1, max = 99, onUpdate, onRemove, debounceMs = 300, className, decreaseProps, increaseProps, } = props;
22
+ // optimistic 显示的 quantity
23
+ const [optimistic, setOptimistic] = React.useState(quantity);
24
+ React.useEffect(() => setOptimistic(quantity), [quantity]);
25
+ const [pending, setPending] = React.useState(false);
26
+ const timerRef = React.useRef(null);
27
+ const flushUpdate = React.useCallback((target) => {
28
+ if (timerRef.current)
29
+ clearTimeout(timerRef.current);
30
+ timerRef.current = setTimeout(async () => {
31
+ setPending(true);
32
+ try {
33
+ if (target < min) {
34
+ await onRemove?.();
35
+ }
36
+ else {
37
+ await onUpdate?.(target);
38
+ }
39
+ }
40
+ finally {
41
+ setPending(false);
42
+ }
43
+ }, debounceMs);
44
+ }, [min, onRemove, onUpdate, debounceMs]);
45
+ const handleAdjust = (delta) => {
46
+ const next = optimistic + delta;
47
+ if (next > max)
48
+ return;
49
+ setOptimistic(next);
50
+ flushUpdate(next);
51
+ };
52
+ React.useEffect(() => () => {
53
+ if (timerRef.current)
54
+ clearTimeout(timerRef.current);
55
+ }, []);
56
+ return (_jsxs("div", { className: className, "data-quantity-adjust": true, style: { display: 'inline-flex', alignItems: 'center' }, children: [_jsx("button", { type: "button", ...decreaseProps, "aria-label": "\u51CF\u5C11", "data-quantity-decrease": true, onClick: () => handleAdjust(-1), disabled: pending && optimistic <= min, children: decreaseProps?.children ?? '−' }), _jsx("span", { "data-quantity-value": true, "aria-live": "polite", style: { margin: '0 0.5em', minWidth: '1.5em', textAlign: 'center' }, children: optimistic }), _jsx("button", { type: "button", ...increaseProps, "aria-label": "\u589E\u52A0", "data-quantity-increase": true, onClick: () => handleAdjust(1), disabled: pending && optimistic >= max, children: increaseProps?.children ?? '+' })] }));
57
+ }
58
+ //# sourceMappingURL=CartLineQuantityAdjustButton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CartLineQuantityAdjustButton.js","sourceRoot":"","sources":["../../src/components/CartLineQuantityAdjustButton.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * <CartProvider> + useCart()
3
+ *
4
+ * 接管 cart 全生命周期:
5
+ * - 自动从 cookie 读取 cart_id 并 fetch
6
+ * - 不存在则懒创建
7
+ * - linesAdd / linesUpdate / linesRemove 全部带 optimistic update + 失败回滚
8
+ * - subscribe(callback) 给外部(如 Analytics)订阅 cart 变化
9
+ *
10
+ * 用法:
11
+ * <ShopProvider {...}>
12
+ * <CartProvider>
13
+ * <App />
14
+ * </CartProvider>
15
+ * </ShopProvider>
16
+ *
17
+ * const { cart, status, linesAdd, linesUpdate, linesRemove } = useCart();
18
+ *
19
+ * 注意:必须套在 <ShopProvider> 内(依赖它的 storefrontAccessToken + apiUrl)。
20
+ */
21
+ import * as React from 'react';
22
+ export interface CartLineMerchandise {
23
+ id: string;
24
+ title?: string;
25
+ image?: {
26
+ url: string;
27
+ altText?: string | null;
28
+ width?: number | null;
29
+ height?: number | null;
30
+ };
31
+ price?: {
32
+ amount: string;
33
+ currencyCode: string;
34
+ };
35
+ product?: {
36
+ title: string;
37
+ handle: string;
38
+ };
39
+ }
40
+ export interface CartLine {
41
+ id: string;
42
+ quantity: number;
43
+ merchandise: CartLineMerchandise;
44
+ cost: {
45
+ totalAmount: {
46
+ amount: string;
47
+ currencyCode: string;
48
+ };
49
+ };
50
+ }
51
+ export interface Cart {
52
+ id: string;
53
+ totalQuantity: number;
54
+ checkoutUrl: string;
55
+ lines: {
56
+ nodes: CartLine[];
57
+ };
58
+ cost: {
59
+ subtotalAmount: {
60
+ amount: string;
61
+ currencyCode: string;
62
+ };
63
+ totalAmount: {
64
+ amount: string;
65
+ currencyCode: string;
66
+ };
67
+ };
68
+ }
69
+ export type CartStatus = 'uninitialized' | 'loading' | 'idle' | 'updating' | 'error';
70
+ export interface CartUserError {
71
+ field?: string[] | null;
72
+ message: string;
73
+ code?: string;
74
+ }
75
+ export interface CartContextValue {
76
+ cart: Cart | null;
77
+ status: CartStatus;
78
+ error: string | null;
79
+ /** 加 line */
80
+ linesAdd: (lines: Array<{
81
+ merchandiseId: string;
82
+ quantity?: number;
83
+ }>) => Promise<void>;
84
+ /** 更新数量(lineId, quantity);quantity<=0 等价 remove */
85
+ linesUpdate: (lines: Array<{
86
+ id: string;
87
+ quantity: number;
88
+ }>) => Promise<void>;
89
+ /** 删 line */
90
+ linesRemove: (lineIds: string[]) => Promise<void>;
91
+ /** 重新从服务端拉 cart */
92
+ refetch: () => Promise<void>;
93
+ /** 订阅 cart 变化(Analytics 用) */
94
+ subscribe: (listener: (cart: Cart | null) => void) => () => void;
95
+ }
96
+ export interface CartProviderProps {
97
+ children: React.ReactNode;
98
+ /** 加载完成后是否自动拉 cart。默认 true */
99
+ fetchOnMount?: boolean;
100
+ }
101
+ export declare function CartProvider({ children, fetchOnMount }: CartProviderProps): import("react/jsx-runtime").JSX.Element;
102
+ /**
103
+ * 拿 cart context。Provider 外 throw。
104
+ */
105
+ export declare function useCart(): CartContextValue;
106
+ /**
107
+ * 非 throw 版本:Provider 外返回 null。
108
+ * 给可选 fallback 用,比如 <AddToCartButton> 在没 Provider 时退化到 props.onAdd。
109
+ */
110
+ export declare function useCartOptional(): CartContextValue | null;
111
+ //# sourceMappingURL=CartProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CartProvider.d.ts","sourceRoot":"","sources":["../../src/components/CartProvider.tsx"],"names":[],"mappings":"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"}