@anker-in/headless-ui 1.1.74 → 1.1.76
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/cjs/biz-components/ActiveShelf/ProductCard.js +1 -1
- package/dist/cjs/biz-components/ActiveShelf/ProductCard.js.map +2 -2
- package/dist/cjs/biz-components/ActivityMechanism/index.d.ts +9 -0
- package/dist/cjs/biz-components/ActivityMechanism/index.js +2 -0
- package/dist/cjs/biz-components/ActivityMechanism/index.js.map +7 -0
- package/dist/cjs/biz-components/ActivityMechanism/types.d.ts +43 -0
- package/dist/cjs/biz-components/ActivityMechanism/types.js +2 -0
- package/dist/cjs/biz-components/ActivityMechanism/types.js.map +7 -0
- package/dist/cjs/biz-components/ActivitySchedule/index.d.ts +3 -0
- package/dist/cjs/biz-components/ActivitySchedule/index.js +2 -0
- package/dist/cjs/biz-components/ActivitySchedule/index.js.map +7 -0
- package/dist/cjs/biz-components/ActivitySchedule/types.d.ts +44 -0
- package/dist/cjs/biz-components/ActivitySchedule/types.js +2 -0
- package/dist/cjs/biz-components/ActivitySchedule/types.js.map +7 -0
- package/dist/cjs/biz-components/AnchorNavigation/index.d.ts +20 -0
- package/dist/cjs/biz-components/AnchorNavigation/index.js +1 -1
- package/dist/cjs/biz-components/AnchorNavigation/index.js.map +3 -3
- package/dist/cjs/biz-components/EventSchedule/index.js +1 -1
- package/dist/cjs/biz-components/EventSchedule/index.js.map +2 -2
- package/dist/cjs/biz-components/FooterNavigation/index.js +1 -1
- package/dist/cjs/biz-components/FooterNavigation/index.js.map +3 -3
- package/dist/cjs/biz-components/FooterNavigation/types.d.ts +7 -0
- package/dist/cjs/biz-components/FooterNavigation/types.js +1 -1
- package/dist/cjs/biz-components/FooterNavigation/types.js.map +2 -2
- package/dist/cjs/biz-components/GiftShelf/index.d.ts +3 -0
- package/dist/cjs/biz-components/GiftShelf/index.js +2 -0
- package/dist/cjs/biz-components/GiftShelf/index.js.map +7 -0
- package/dist/cjs/biz-components/GiftShelf/types.d.ts +120 -0
- package/dist/cjs/biz-components/GiftShelf/types.js +2 -0
- package/dist/cjs/biz-components/GiftShelf/types.js.map +7 -0
- package/dist/cjs/biz-components/GiftTierShelf/index.d.ts +3 -0
- package/dist/cjs/biz-components/GiftTierShelf/index.js +2 -0
- package/dist/cjs/biz-components/GiftTierShelf/index.js.map +7 -0
- package/dist/cjs/biz-components/GiftTierShelf/types.d.ts +75 -0
- package/dist/cjs/biz-components/GiftTierShelf/types.js +2 -0
- package/dist/cjs/biz-components/GiftTierShelf/types.js.map +7 -0
- package/dist/cjs/biz-components/HeroBanner/HeroBanner.js +1 -1
- package/dist/cjs/biz-components/HeroBanner/HeroBanner.js.map +2 -2
- package/dist/cjs/biz-components/HeroBanner/types.d.ts +2 -0
- package/dist/cjs/biz-components/HeroBanner/types.js +1 -1
- package/dist/cjs/biz-components/HeroBanner/types.js.map +1 -1
- package/dist/cjs/biz-components/ImageWithText/ImageWithText.js +1 -1
- package/dist/cjs/biz-components/ImageWithText/ImageWithText.js.map +2 -2
- package/dist/cjs/biz-components/Ksp/index.d.ts +45 -6
- package/dist/cjs/biz-components/Ksp/index.js +1 -1
- package/dist/cjs/biz-components/Ksp/index.js.map +3 -3
- package/dist/cjs/biz-components/MediaPlayerBase/index.js +1 -1
- package/dist/cjs/biz-components/MediaPlayerBase/index.js.map +3 -3
- package/dist/cjs/biz-components/PromotionalBar/index.js +1 -1
- package/dist/cjs/biz-components/PromotionalBar/index.js.map +3 -3
- package/dist/cjs/biz-components/ThreeDCarousel/ThreeDCarousel.js +1 -1
- package/dist/cjs/biz-components/ThreeDCarousel/ThreeDCarousel.js.map +2 -2
- package/dist/cjs/biz-components/Title/index.js +1 -1
- package/dist/cjs/biz-components/Title/index.js.map +3 -3
- package/dist/cjs/biz-components/Title/types.d.ts +10 -1
- package/dist/cjs/biz-components/Title/types.js +1 -1
- package/dist/cjs/biz-components/Title/types.js.map +1 -1
- package/dist/cjs/biz-components/VideoModal/index.js +1 -1
- package/dist/cjs/biz-components/VideoModal/index.js.map +2 -2
- package/dist/cjs/biz-components/WheelLottery/BaseModal.d.ts +61 -0
- package/dist/cjs/biz-components/WheelLottery/BaseModal.js +2 -0
- package/dist/cjs/biz-components/WheelLottery/BaseModal.js.map +7 -0
- package/dist/cjs/biz-components/WheelLottery/ChanceMethods.d.ts +25 -0
- package/dist/cjs/biz-components/WheelLottery/ChanceMethods.js +2 -0
- package/dist/cjs/biz-components/WheelLottery/ChanceMethods.js.map +7 -0
- package/dist/cjs/biz-components/WheelLottery/ErrorModal.d.ts +47 -0
- package/dist/cjs/biz-components/WheelLottery/ErrorModal.js +2 -0
- package/dist/cjs/biz-components/WheelLottery/ErrorModal.js.map +7 -0
- package/dist/cjs/biz-components/WheelLottery/MyRewardsModal.d.ts +101 -0
- package/dist/cjs/biz-components/WheelLottery/MyRewardsModal.js +2 -0
- package/dist/cjs/biz-components/WheelLottery/MyRewardsModal.js.map +7 -0
- package/dist/cjs/biz-components/WheelLottery/PrizePool.d.ts +29 -0
- package/dist/cjs/biz-components/WheelLottery/PrizePool.js +2 -0
- package/dist/cjs/biz-components/WheelLottery/PrizePool.js.map +7 -0
- package/dist/cjs/biz-components/WheelLottery/RulesModal.d.ts +56 -0
- package/dist/cjs/biz-components/WheelLottery/RulesModal.js +2 -0
- package/dist/cjs/biz-components/WheelLottery/RulesModal.js.map +7 -0
- package/dist/cjs/biz-components/WheelLottery/ShareModal.d.ts +79 -0
- package/dist/cjs/biz-components/WheelLottery/ShareModal.js +2 -0
- package/dist/cjs/biz-components/WheelLottery/ShareModal.js.map +7 -0
- package/dist/cjs/biz-components/WheelLottery/Wheel.d.ts +27 -0
- package/dist/cjs/biz-components/WheelLottery/Wheel.js +2 -0
- package/dist/cjs/biz-components/WheelLottery/Wheel.js.map +7 -0
- package/dist/cjs/biz-components/WheelLottery/WinnerModal.d.ts +27 -0
- package/dist/cjs/biz-components/WheelLottery/WinnerModal.js +2 -0
- package/dist/cjs/biz-components/WheelLottery/WinnerModal.js.map +7 -0
- package/dist/cjs/biz-components/WheelLottery/index.d.ts +48 -0
- package/dist/cjs/biz-components/WheelLottery/index.js +2 -0
- package/dist/cjs/biz-components/WheelLottery/index.js.map +7 -0
- package/dist/cjs/biz-components/WheelLottery/types.d.ts +1229 -0
- package/dist/cjs/biz-components/WheelLottery/types.js +2 -0
- package/dist/cjs/biz-components/WheelLottery/types.js.map +7 -0
- package/dist/cjs/biz-components/index.d.ts +11 -0
- package/dist/cjs/biz-components/index.js +1 -1
- package/dist/cjs/biz-components/index.js.map +3 -3
- package/dist/cjs/components/Countdown.d.ts +27 -4
- package/dist/cjs/components/Countdown.js +1 -1
- package/dist/cjs/components/Countdown.js.map +3 -3
- package/dist/cjs/hooks/useCountDown.js +1 -1
- package/dist/cjs/hooks/useCountDown.js.map +3 -3
- package/dist/cjs/hooks/useDraggableScroll.d.ts +77 -0
- package/dist/cjs/hooks/useDraggableScroll.js +2 -0
- package/dist/cjs/hooks/useDraggableScroll.js.map +7 -0
- package/dist/esm/biz-components/ActiveShelf/ProductCard.js +1 -1
- package/dist/esm/biz-components/ActiveShelf/ProductCard.js.map +2 -2
- package/dist/esm/biz-components/ActivityMechanism/index.d.ts +9 -0
- package/dist/esm/biz-components/ActivityMechanism/index.js +2 -0
- package/dist/esm/biz-components/ActivityMechanism/index.js.map +7 -0
- package/dist/esm/biz-components/ActivityMechanism/types.d.ts +43 -0
- package/dist/esm/biz-components/ActivityMechanism/types.js +1 -0
- package/dist/esm/biz-components/ActivityMechanism/types.js.map +7 -0
- package/dist/esm/biz-components/ActivitySchedule/index.d.ts +3 -0
- package/dist/esm/biz-components/ActivitySchedule/index.js +2 -0
- package/dist/esm/biz-components/ActivitySchedule/index.js.map +7 -0
- package/dist/esm/biz-components/ActivitySchedule/types.d.ts +44 -0
- package/dist/esm/biz-components/ActivitySchedule/types.js +1 -0
- package/dist/esm/biz-components/ActivitySchedule/types.js.map +7 -0
- package/dist/esm/biz-components/AnchorNavigation/index.d.ts +20 -0
- package/dist/esm/biz-components/AnchorNavigation/index.js +1 -1
- package/dist/esm/biz-components/AnchorNavigation/index.js.map +3 -3
- package/dist/esm/biz-components/EventSchedule/index.js +1 -1
- package/dist/esm/biz-components/EventSchedule/index.js.map +3 -3
- package/dist/esm/biz-components/FooterNavigation/index.js +1 -1
- package/dist/esm/biz-components/FooterNavigation/index.js.map +3 -3
- package/dist/esm/biz-components/FooterNavigation/types.d.ts +7 -0
- package/dist/esm/biz-components/FooterNavigation/types.js.map +2 -2
- package/dist/esm/biz-components/GiftShelf/index.d.ts +3 -0
- package/dist/esm/biz-components/GiftShelf/index.js +2 -0
- package/dist/esm/biz-components/GiftShelf/index.js.map +7 -0
- package/dist/esm/biz-components/GiftShelf/types.d.ts +120 -0
- package/dist/esm/biz-components/GiftShelf/types.js +1 -0
- package/dist/esm/biz-components/GiftShelf/types.js.map +7 -0
- package/dist/esm/biz-components/GiftTierShelf/index.d.ts +3 -0
- package/dist/esm/biz-components/GiftTierShelf/index.js +2 -0
- package/dist/esm/biz-components/GiftTierShelf/index.js.map +7 -0
- package/dist/esm/biz-components/GiftTierShelf/types.d.ts +75 -0
- package/dist/esm/biz-components/GiftTierShelf/types.js +1 -0
- package/dist/esm/biz-components/GiftTierShelf/types.js.map +7 -0
- package/dist/esm/biz-components/HeroBanner/HeroBanner.js +1 -1
- package/dist/esm/biz-components/HeroBanner/HeroBanner.js.map +2 -2
- package/dist/esm/biz-components/HeroBanner/types.d.ts +2 -0
- package/dist/esm/biz-components/ImageWithText/ImageWithText.js +1 -1
- package/dist/esm/biz-components/ImageWithText/ImageWithText.js.map +2 -2
- package/dist/esm/biz-components/Ksp/index.d.ts +45 -6
- package/dist/esm/biz-components/Ksp/index.js +1 -1
- package/dist/esm/biz-components/Ksp/index.js.map +3 -3
- package/dist/esm/biz-components/MediaPlayerBase/index.js +1 -1
- package/dist/esm/biz-components/MediaPlayerBase/index.js.map +3 -3
- package/dist/esm/biz-components/PromotionalBar/index.js +1 -1
- package/dist/esm/biz-components/PromotionalBar/index.js.map +3 -3
- package/dist/esm/biz-components/ThreeDCarousel/ThreeDCarousel.js +1 -1
- package/dist/esm/biz-components/ThreeDCarousel/ThreeDCarousel.js.map +2 -2
- package/dist/esm/biz-components/Title/index.js +1 -1
- package/dist/esm/biz-components/Title/index.js.map +3 -3
- package/dist/esm/biz-components/Title/types.d.ts +10 -1
- package/dist/esm/biz-components/VideoModal/index.js +1 -1
- package/dist/esm/biz-components/VideoModal/index.js.map +2 -2
- package/dist/esm/biz-components/WheelLottery/BaseModal.d.ts +61 -0
- package/dist/esm/biz-components/WheelLottery/BaseModal.js +2 -0
- package/dist/esm/biz-components/WheelLottery/BaseModal.js.map +7 -0
- package/dist/esm/biz-components/WheelLottery/ChanceMethods.d.ts +25 -0
- package/dist/esm/biz-components/WheelLottery/ChanceMethods.js +2 -0
- package/dist/esm/biz-components/WheelLottery/ChanceMethods.js.map +7 -0
- package/dist/esm/biz-components/WheelLottery/ErrorModal.d.ts +47 -0
- package/dist/esm/biz-components/WheelLottery/ErrorModal.js +2 -0
- package/dist/esm/biz-components/WheelLottery/ErrorModal.js.map +7 -0
- package/dist/esm/biz-components/WheelLottery/MyRewardsModal.d.ts +101 -0
- package/dist/esm/biz-components/WheelLottery/MyRewardsModal.js +2 -0
- package/dist/esm/biz-components/WheelLottery/MyRewardsModal.js.map +7 -0
- package/dist/esm/biz-components/WheelLottery/PrizePool.d.ts +29 -0
- package/dist/esm/biz-components/WheelLottery/PrizePool.js +2 -0
- package/dist/esm/biz-components/WheelLottery/PrizePool.js.map +7 -0
- package/dist/esm/biz-components/WheelLottery/RulesModal.d.ts +56 -0
- package/dist/esm/biz-components/WheelLottery/RulesModal.js +2 -0
- package/dist/esm/biz-components/WheelLottery/RulesModal.js.map +7 -0
- package/dist/esm/biz-components/WheelLottery/ShareModal.d.ts +79 -0
- package/dist/esm/biz-components/WheelLottery/ShareModal.js +2 -0
- package/dist/esm/biz-components/WheelLottery/ShareModal.js.map +7 -0
- package/dist/esm/biz-components/WheelLottery/Wheel.d.ts +27 -0
- package/dist/esm/biz-components/WheelLottery/Wheel.js +2 -0
- package/dist/esm/biz-components/WheelLottery/Wheel.js.map +7 -0
- package/dist/esm/biz-components/WheelLottery/WinnerModal.d.ts +27 -0
- package/dist/esm/biz-components/WheelLottery/WinnerModal.js +2 -0
- package/dist/esm/biz-components/WheelLottery/WinnerModal.js.map +7 -0
- package/dist/esm/biz-components/WheelLottery/index.d.ts +48 -0
- package/dist/esm/biz-components/WheelLottery/index.js +2 -0
- package/dist/esm/biz-components/WheelLottery/index.js.map +7 -0
- package/dist/esm/biz-components/WheelLottery/types.d.ts +1229 -0
- package/dist/esm/biz-components/WheelLottery/types.js +2 -0
- package/dist/esm/biz-components/WheelLottery/types.js.map +7 -0
- package/dist/esm/biz-components/index.d.ts +11 -0
- package/dist/esm/biz-components/index.js +1 -1
- package/dist/esm/biz-components/index.js.map +2 -2
- package/dist/esm/components/Countdown.d.ts +27 -4
- package/dist/esm/components/Countdown.js +1 -1
- package/dist/esm/components/Countdown.js.map +3 -3
- package/dist/esm/hooks/useCountDown.js +1 -1
- package/dist/esm/hooks/useCountDown.js.map +3 -3
- package/dist/esm/hooks/useDraggableScroll.d.ts +77 -0
- package/dist/esm/hooks/useDraggableScroll.js +2 -0
- package/dist/esm/hooks/useDraggableScroll.js.map +7 -0
- package/package.json +1 -1
- package/style.css +6252 -862
- package/tailwind.config.js +18 -2
- package/dist/cjs/biz-components/HeroBanner/Countdown.d.ts +0 -10
- package/dist/cjs/biz-components/HeroBanner/Countdown.js +0 -2
- package/dist/cjs/biz-components/HeroBanner/Countdown.js.map +0 -7
- package/dist/cjs/biz-components/Title/Countdown.d.ts +0 -14
- package/dist/cjs/biz-components/Title/Countdown.js +0 -2
- package/dist/cjs/biz-components/Title/Countdown.js.map +0 -7
- package/dist/esm/biz-components/HeroBanner/Countdown.d.ts +0 -10
- package/dist/esm/biz-components/HeroBanner/Countdown.js +0 -2
- package/dist/esm/biz-components/HeroBanner/Countdown.js.map +0 -7
- package/dist/esm/biz-components/Title/Countdown.d.ts +0 -14
- package/dist/esm/biz-components/Title/Countdown.js +0 -2
- package/dist/esm/biz-components/Title/Countdown.js.map +0 -7
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useDraggableScroll - 拖拽滚动 Hook
|
|
3
|
+
*
|
|
4
|
+
* 基于 Framer Motion 实现的水平拖拽滚动功能
|
|
5
|
+
*
|
|
6
|
+
* @module useDraggableScroll
|
|
7
|
+
* @date 2026-01-29
|
|
8
|
+
*/
|
|
9
|
+
export interface UseDraggableScrollOptions {
|
|
10
|
+
/**
|
|
11
|
+
* 拖拽速度倍数
|
|
12
|
+
* @default 1
|
|
13
|
+
*/
|
|
14
|
+
dragSpeed?: number;
|
|
15
|
+
/**
|
|
16
|
+
* 是否启用惯性滚动
|
|
17
|
+
* @default true
|
|
18
|
+
*/
|
|
19
|
+
enableMomentum?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* 边界弹性系数(0-1,0表示无弹性)
|
|
22
|
+
* @default 0.1
|
|
23
|
+
*/
|
|
24
|
+
dragElastic?: number;
|
|
25
|
+
}
|
|
26
|
+
export interface UseDraggableScrollReturn {
|
|
27
|
+
/**
|
|
28
|
+
* 容器 ref
|
|
29
|
+
*/
|
|
30
|
+
containerRef: React.RefObject<HTMLDivElement>;
|
|
31
|
+
/**
|
|
32
|
+
* 是否正在拖拽
|
|
33
|
+
*/
|
|
34
|
+
isDragging: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* 滚动进度(0-100)
|
|
37
|
+
*/
|
|
38
|
+
scrollProgress: number;
|
|
39
|
+
/**
|
|
40
|
+
* 是否可以向左滚动
|
|
41
|
+
*/
|
|
42
|
+
canScrollLeft: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* 是否可以向右滚动
|
|
45
|
+
*/
|
|
46
|
+
canScrollRight: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* 滚动到指定位置
|
|
49
|
+
*/
|
|
50
|
+
scrollTo: (position: number, smooth?: boolean) => void;
|
|
51
|
+
/**
|
|
52
|
+
* 向左滚动
|
|
53
|
+
*/
|
|
54
|
+
scrollLeft: (amount?: number) => void;
|
|
55
|
+
/**
|
|
56
|
+
* 向右滚动
|
|
57
|
+
*/
|
|
58
|
+
scrollRight: (amount?: number) => void;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* 拖拽滚动 Hook
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```tsx
|
|
65
|
+
* const { containerRef, isDragging, scrollProgress } = useDraggableScroll({
|
|
66
|
+
* dragSpeed: 1.5,
|
|
67
|
+
* enableMomentum: true
|
|
68
|
+
* })
|
|
69
|
+
*
|
|
70
|
+
* return (
|
|
71
|
+
* <div ref={containerRef} className="overflow-x-auto">
|
|
72
|
+
* {items.map(item => <Item key={item.id} />)}
|
|
73
|
+
* </div>
|
|
74
|
+
* )
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export declare function useDraggableScroll(options?: UseDraggableScrollOptions): UseDraggableScrollReturn;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var m=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var M=Object.getOwnPropertyNames;var x=Object.prototype.hasOwnProperty;var E=(n,o)=>{for(var s in o)m(n,s,{get:o[s],enumerable:!0})},O=(n,o,s,i)=>{if(o&&typeof o=="object"||typeof o=="function")for(let t of M(o))!x.call(n,t)&&t!==s&&m(n,t,{get:()=>o[t],enumerable:!(i=D(o,t))||i.enumerable});return n};var T=n=>O(m({},"__esModule",{value:!0}),n);var U={};E(U,{useDraggableScroll:()=>F});module.exports=T(U);var l=require("react");function F(n={}){const{dragSpeed:o=1,enableMomentum:s=!0,dragElastic:i=.1}=n,t=(0,l.useRef)(null),[b,W]=(0,l.useState)(!1),[S,h]=(0,l.useState)(0),[d,R]=(0,l.useState)(!1),[L,v]=(0,l.useState)(!1),a=()=>{const r=t.current;if(!r)return;const{scrollLeft:e,scrollWidth:c,clientWidth:u}=r,f=c-u,p=f>0?e/f*100:0;h(Math.min(100,Math.max(0,p))),R(e>0),v(e<f-1)};(0,l.useEffect)(()=>{const r=t.current;if(!r)return;a(),r.addEventListener("scroll",a);const e=new ResizeObserver(a);return e.observe(r),()=>{r.removeEventListener("scroll",a),e.disconnect()}},[]);const g=(r,e=!0)=>{const c=t.current;c&&c.scrollTo({left:r,behavior:e?"smooth":"auto"})};return{containerRef:t,isDragging:b,scrollProgress:S,canScrollLeft:d,canScrollRight:L,scrollTo:g,scrollLeft:(r=300)=>{const e=t.current;if(!e)return;const c=Math.max(0,e.scrollLeft-r);g(c)},scrollRight:(r=300)=>{const e=t.current;if(!e)return;const c=e.scrollWidth-e.clientWidth,u=Math.min(c,e.scrollLeft+r);g(u)}}}
|
|
2
|
+
//# sourceMappingURL=useDraggableScroll.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/hooks/useDraggableScroll.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * useDraggableScroll - \u62D6\u62FD\u6EDA\u52A8 Hook\n *\n * \u57FA\u4E8E Framer Motion \u5B9E\u73B0\u7684\u6C34\u5E73\u62D6\u62FD\u6EDA\u52A8\u529F\u80FD\n *\n * @module useDraggableScroll\n * @date 2026-01-29\n */\n\nimport { useRef, useState, useEffect } from 'react'\n\nexport interface UseDraggableScrollOptions {\n /**\n * \u62D6\u62FD\u901F\u5EA6\u500D\u6570\n * @default 1\n */\n dragSpeed?: number\n\n /**\n * \u662F\u5426\u542F\u7528\u60EF\u6027\u6EDA\u52A8\n * @default true\n */\n enableMomentum?: boolean\n\n /**\n * \u8FB9\u754C\u5F39\u6027\u7CFB\u6570\uFF080-1\uFF0C0\u8868\u793A\u65E0\u5F39\u6027\uFF09\n * @default 0.1\n */\n dragElastic?: number\n}\n\nexport interface UseDraggableScrollReturn {\n /**\n * \u5BB9\u5668 ref\n */\n containerRef: React.RefObject<HTMLDivElement>\n\n /**\n * \u662F\u5426\u6B63\u5728\u62D6\u62FD\n */\n isDragging: boolean\n\n /**\n * \u6EDA\u52A8\u8FDB\u5EA6\uFF080-100\uFF09\n */\n scrollProgress: number\n\n /**\n * \u662F\u5426\u53EF\u4EE5\u5411\u5DE6\u6EDA\u52A8\n */\n canScrollLeft: boolean\n\n /**\n * \u662F\u5426\u53EF\u4EE5\u5411\u53F3\u6EDA\u52A8\n */\n canScrollRight: boolean\n\n /**\n * \u6EDA\u52A8\u5230\u6307\u5B9A\u4F4D\u7F6E\n */\n scrollTo: (position: number, smooth?: boolean) => void\n\n /**\n * \u5411\u5DE6\u6EDA\u52A8\n */\n scrollLeft: (amount?: number) => void\n\n /**\n * \u5411\u53F3\u6EDA\u52A8\n */\n scrollRight: (amount?: number) => void\n}\n\n/**\n * \u62D6\u62FD\u6EDA\u52A8 Hook\n *\n * @example\n * ```tsx\n * const { containerRef, isDragging, scrollProgress } = useDraggableScroll({\n * dragSpeed: 1.5,\n * enableMomentum: true\n * })\n *\n * return (\n * <div ref={containerRef} className=\"overflow-x-auto\">\n * {items.map(item => <Item key={item.id} />)}\n * </div>\n * )\n * ```\n */\nexport function useDraggableScroll(options: UseDraggableScrollOptions = {}): UseDraggableScrollReturn {\n const { dragSpeed = 1, enableMomentum = true, dragElastic = 0.1 } = options\n\n const containerRef = useRef<HTMLDivElement>(null)\n const [isDragging, setIsDragging] = useState(false)\n const [scrollProgress, setScrollProgress] = useState(0)\n const [canScrollLeft, setCanScrollLeft] = useState(false)\n const [canScrollRight, setCanScrollRight] = useState(false)\n\n // \u66F4\u65B0\u6EDA\u52A8\u72B6\u6001\n const updateScrollState = () => {\n const container = containerRef.current\n if (!container) return\n\n const { scrollLeft, scrollWidth, clientWidth } = container\n\n // \u8BA1\u7B97\u6EDA\u52A8\u8FDB\u5EA6\n const maxScroll = scrollWidth - clientWidth\n const progress = maxScroll > 0 ? (scrollLeft / maxScroll) * 100 : 0\n setScrollProgress(Math.min(100, Math.max(0, progress)))\n\n // \u66F4\u65B0\u6EDA\u52A8\u65B9\u5411\u53EF\u7528\u6027\n setCanScrollLeft(scrollLeft > 0)\n setCanScrollRight(scrollLeft < maxScroll - 1) // -1 \u5BB9\u9519\n }\n\n // \u76D1\u542C\u5BB9\u5668\u6EDA\u52A8\u4E8B\u4EF6\n useEffect(() => {\n const container = containerRef.current\n if (!container) return\n\n // \u521D\u59CB\u5316\u72B6\u6001\n updateScrollState()\n\n // \u76D1\u542C\u6EDA\u52A8\n container.addEventListener('scroll', updateScrollState)\n\n // \u76D1\u542C\u7A97\u53E3\u5927\u5C0F\u53D8\u5316\n const resizeObserver = new ResizeObserver(updateScrollState)\n resizeObserver.observe(container)\n\n return () => {\n container.removeEventListener('scroll', updateScrollState)\n resizeObserver.disconnect()\n }\n }, [])\n\n // \u6EDA\u52A8\u5230\u6307\u5B9A\u4F4D\u7F6E\n const scrollTo = (position: number, smooth = true) => {\n const container = containerRef.current\n if (!container) return\n\n container.scrollTo({\n left: position,\n behavior: smooth ? 'smooth' : 'auto',\n })\n }\n\n // \u5411\u5DE6\u6EDA\u52A8\n const scrollLeftFn = (amount = 300) => {\n const container = containerRef.current\n if (!container) return\n\n const targetScroll = Math.max(0, container.scrollLeft - amount)\n scrollTo(targetScroll)\n }\n\n // \u5411\u53F3\u6EDA\u52A8\n const scrollRightFn = (amount = 300) => {\n const container = containerRef.current\n if (!container) return\n\n const maxScroll = container.scrollWidth - container.clientWidth\n const targetScroll = Math.min(maxScroll, container.scrollLeft + amount)\n scrollTo(targetScroll)\n }\n\n return {\n containerRef,\n isDragging,\n scrollProgress,\n canScrollLeft,\n canScrollRight,\n scrollTo,\n scrollLeft: scrollLeftFn,\n scrollRight: scrollRightFn,\n }\n}\n"],
|
|
5
|
+
"mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,wBAAAE,IAAA,eAAAC,EAAAH,GASA,IAAAI,EAA4C,iBAiFrC,SAASF,EAAmBG,EAAqC,CAAC,EAA6B,CACpG,KAAM,CAAE,UAAAC,EAAY,EAAG,eAAAC,EAAiB,GAAM,YAAAC,EAAc,EAAI,EAAIH,EAE9DI,KAAe,UAAuB,IAAI,EAC1C,CAACC,EAAYC,CAAa,KAAI,YAAS,EAAK,EAC5C,CAACC,EAAgBC,CAAiB,KAAI,YAAS,CAAC,EAChD,CAACC,EAAeC,CAAgB,KAAI,YAAS,EAAK,EAClD,CAACC,EAAgBC,CAAiB,KAAI,YAAS,EAAK,EAGpDC,EAAoB,IAAM,CAC9B,MAAMC,EAAYV,EAAa,QAC/B,GAAI,CAACU,EAAW,OAEhB,KAAM,CAAE,WAAAC,EAAY,YAAAC,EAAa,YAAAC,CAAY,EAAIH,EAG3CI,EAAYF,EAAcC,EAC1BE,EAAWD,EAAY,EAAKH,EAAaG,EAAa,IAAM,EAClEV,EAAkB,KAAK,IAAI,IAAK,KAAK,IAAI,EAAGW,CAAQ,CAAC,CAAC,EAGtDT,EAAiBK,EAAa,CAAC,EAC/BH,EAAkBG,EAAaG,EAAY,CAAC,CAC9C,KAGA,aAAU,IAAM,CACd,MAAMJ,EAAYV,EAAa,QAC/B,GAAI,CAACU,EAAW,OAGhBD,EAAkB,EAGlBC,EAAU,iBAAiB,SAAUD,CAAiB,EAGtD,MAAMO,EAAiB,IAAI,eAAeP,CAAiB,EAC3D,OAAAO,EAAe,QAAQN,CAAS,EAEzB,IAAM,CACXA,EAAU,oBAAoB,SAAUD,CAAiB,EACzDO,EAAe,WAAW,CAC5B,CACF,EAAG,CAAC,CAAC,EAGL,MAAMC,EAAW,CAACC,EAAkBC,EAAS,KAAS,CACpD,MAAMT,EAAYV,EAAa,QAC1BU,GAELA,EAAU,SAAS,CACjB,KAAMQ,EACN,SAAUC,EAAS,SAAW,MAChC,CAAC,CACH,EAqBA,MAAO,CACL,aAAAnB,EACA,WAAAC,EACA,eAAAE,EACA,cAAAE,EACA,eAAAE,EACA,SAAAU,EACA,WAzBmB,CAACG,EAAS,MAAQ,CACrC,MAAMV,EAAYV,EAAa,QAC/B,GAAI,CAACU,EAAW,OAEhB,MAAMW,EAAe,KAAK,IAAI,EAAGX,EAAU,WAAaU,CAAM,EAC9DH,EAASI,CAAY,CACvB,EAoBE,YAjBoB,CAACD,EAAS,MAAQ,CACtC,MAAMV,EAAYV,EAAa,QAC/B,GAAI,CAACU,EAAW,OAEhB,MAAMI,EAAYJ,EAAU,YAAcA,EAAU,YAC9CW,EAAe,KAAK,IAAIP,EAAWJ,EAAU,WAAaU,CAAM,EACtEH,EAASI,CAAY,CACvB,CAWA,CACF",
|
|
6
|
+
"names": ["useDraggableScroll_exports", "__export", "useDraggableScroll", "__toCommonJS", "import_react", "options", "dragSpeed", "enableMomentum", "dragElastic", "containerRef", "isDragging", "setIsDragging", "scrollProgress", "setScrollProgress", "canScrollLeft", "setCanScrollLeft", "canScrollRight", "setCanScrollRight", "updateScrollState", "container", "scrollLeft", "scrollWidth", "clientWidth", "maxScroll", "progress", "resizeObserver", "scrollTo", "position", "smooth", "amount", "targetScroll"]
|
|
7
|
+
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";import{Fragment as H,jsx as a,jsxs as n}from"react/jsx-runtime";import*as l from"react";import{cn as t}from"../../helpers/index.js";import{Button as C,Badge as M,Card as _,CardContent as R,Picture as $,Text as g,Heading as c,Progress as E}from"../../components/index.js";const I=5;function j(e,o,s,m){if(e===void 0)return!0;switch(e){case"always":return!0;case"never":return!1;case"below-quantity":return o===void 0?!0:s<=o;case"below-percentage":return o===void 0?!0:s/m*100<=o;default:return!0}}const b=l.forwardRef(({product:e,className:o,showTags:s=!0,stockDisplayMode:m,stockThresholdValue:P,onLearnMore:S,onShopNow:w,onAddToCart:N,classNames:i,secondaryButtonText:p,secondaryButtonFun:y,primaryButtonText:u,primaryButtonFun:v,showOriginalPrice:B,copy:f,onProductImageClick:x},D)=>{const[L,T]=l.useState(!1),[F,z]=l.useState(!1),A=l.useMemo(()=>e?.availableForSale&&e?.quantityAvailable<=0?I:e?.availableForSale?(e?.quantityAvailable??0)/(e?.totalInventory??1)*100:0,[e?.availableForSale,e?.quantityAvailable,e?.totalInventory]),k=async(r,d)=>{if(!r)return;const h=d==="primary"?T:z;h(!0);try{switch(r){case"buyNow":await w?.(e);break;case"addCart":await N?.(e);break;case"learnMore":await S?.(e);break;default:break}}finally{h(!1)}},q=e.availableForSale&&e.quantityAvailable<=0;return a(_,{ref:D,className:t("bg-container-primary hover:bg-container-secondary-0 flex h-full flex-col overflow-hidden border-none",o,i?.productCard),children:n(R,{className:"desktop:p-6 relative flex flex-1 flex-col justify-between p-4",children:[a("div",{className:"lg-desktop:h-[28px] flex h-[24px] gap-1",children:s&&e.tags?.map((r,d)=>r.label?a(M,{size:"sm",variant:r.variant||"outline",className:t(r.variant==="promotional"?"ml-2":""),promotionalType:r.promotionalType,children:r.label},d):a(l.Fragment,{children:r},d))}),a("div",{className:"product-image-wrapper lg-desktop:size-[196px] mx-auto size-[138px] cursor-pointer overflow-hidden",children:a("a",{onClick:()=>x?.(e),...!x&&{href:e?.listingLink},rel:"noreferrer",children:a($,{source:e.image,alt:e.name,className:"aspect-square size-full object-contain",imgClassName:"w-full h-full object-contain"})})}),n("div",{className:"flex h-full flex-1 grow flex-col justify-between",children:[n("div",{className:"mb-4",children:[a(c,{as:"h3",size:2,className:t("text-info-primary mb-2 line-clamp-2 min-h-[2.4em]",i?.productTitle),html:e.custom_name||e.name}),e?.description&&a(g,{size:2,className:t("text-info-secondary desktop:line-clamp-2 desktop:min-h-[2.4em] desktop:text-[16px] lg-desktop:text-[18px] line-clamp-2 min-h-[2.4em] text-[14px]",i?.productDescription),html:e.custom_description||e.description})]}),e?.priceLabel&&e?.availableForSale&&a(g,{size:4,className:t("text-marketing-1 desktop:text-[16px] lg-desktop:text-[18px] mt-2 text-[14px]",i?.productPriceLabel),children:e.priceLabel}),n("div",{children:[a("div",{className:t("mb-2",i?.productPrice),children:a("div",{className:"flex items-baseline gap-2",children:e.availableForSale?n(H,{children:[a(c,{size:2,className:"text-info-primary",as:"h6",children:e.price}),B&&e.originalPrice&&a(c,{size:2,className:"text-info-tertiary line-through",as:"h6",children:e.originalPrice})]}):a(c,{size:2,className:"text-info-tertiary",children:f?.outOfStockLabel??"Sold Out"})})}),n("div",{className:t("lg-desktop:gap-3 tablet:flex-nowrap flex flex-wrap gap-2",i?.buttonGroup),children:[p&&a(C,{variant:"secondary",size:"base",className:t("tablet:w-fit w-full",i?.secondaryButton),onClick:()=>k(y,"secondary"),disabled:!e.availableForSale&&y!=="learnMore",loading:F,"data-headless-type-name":"ActiveShelf#ProductCard","data-headless-title-desc-button":`${e.custom_name||e.name}#${e.description||""}#${p}`,"data-headless-sku":e.sku,children:p}),u&&a(C,{variant:"primary",size:"base",className:t("tablet:w-fit w-full",i?.primaryButton),onClick:()=>k(v,"primary"),disabled:!e.availableForSale&&v!=="learnMore",loading:L,"data-headless-type-name":"ActiveShelf#ProductCard","data-headless-title-desc-button":`${e.custom_name||e.name}#${e.description||""}#${u}`,"data-headless-sku":e.sku,children:u})]}),j(m,P,e?.quantityAvailable??0,e?.totalInventory??0)&&n("div",{className:"mt-4 space-y-2",children:[a(E,{value:A,max:100,min:0,size:"base",variant:"default","aria-label":"stock progress",classNames:{root:t("bg-[var(--progress-track-bg)]",i?.stockTrack),progressBar:t("bg-brand-0 transition-all duration-300 ease-in-out",i?.stockBar)}}),a(g,{size:3,className:"text-info-tertiary text-[14px]",children:q?f?.limitedStock:f?.stockDisplayText?.replace("{count}",`${e.availableForSale?e.quantityAvailable:0}`)})]})]})]})]})})});b.displayName="ActiveShelf.ProductCard";var K=b;export{b as ProductCard,K as default};
|
|
1
|
+
"use client";import{Fragment as H,jsx as a,jsxs as n}from"react/jsx-runtime";import*as l from"react";import{cn as t}from"../../helpers/index.js";import{Button as C,Badge as M,Card as _,CardContent as R,Picture as $,Text as g,Heading as c,Progress as E}from"../../components/index.js";const I=5;function j(e,o,s,m){if(e===void 0)return!0;switch(e){case"always":return!0;case"never":return!1;case"below-quantity":return o===void 0?!0:s<=o;case"below-percentage":return o===void 0?!0:s/m*100<=o;default:return!0}}const b=l.forwardRef(({product:e,className:o,showTags:s=!0,stockDisplayMode:m,stockThresholdValue:P,onLearnMore:S,onShopNow:w,onAddToCart:N,classNames:i,secondaryButtonText:p,secondaryButtonFun:y,primaryButtonText:u,primaryButtonFun:v,showOriginalPrice:B,copy:f,onProductImageClick:x},D)=>{const[L,T]=l.useState(!1),[F,z]=l.useState(!1),A=l.useMemo(()=>e?.availableForSale&&e?.quantityAvailable<=0?I:e?.availableForSale?(e?.quantityAvailable??0)/(e?.totalInventory??1)*100:0,[e?.availableForSale,e?.quantityAvailable,e?.totalInventory]),k=async(r,d)=>{if(!r)return;const h=d==="primary"?T:z;h(!0);try{switch(r){case"buyNow":await w?.(e);break;case"addCart":await N?.(e);break;case"learnMore":await S?.(e);break;default:break}}finally{h(!1)}},q=e.availableForSale&&e.quantityAvailable<=0;return a(_,{ref:D,className:t("bg-container-primary hover:bg-container-secondary-0 flex h-full flex-col overflow-hidden border-none",o,i?.productCard),children:n(R,{className:"desktop:p-6 relative flex flex-1 flex-col justify-between p-4",children:[a("div",{className:"lg-desktop:h-[28px] flex h-[24px] gap-1",children:s&&e.tags?.map((r,d)=>r.label?a(M,{size:"sm",variant:r.variant||"outline",className:t(r.variant==="promotional"?"ml-2":""),promotionalType:r.promotionalType,children:r.label},d):a(l.Fragment,{children:r},d))}),a("div",{className:"product-image-wrapper lg-desktop:size-[196px] mx-auto size-[138px] cursor-pointer overflow-hidden",children:a("a",{onClick:()=>x?.(e),...!x&&{href:e?.listingLink},rel:"noreferrer",children:a($,{source:e.image,alt:e.name,className:"aspect-square size-full object-contain",imgClassName:"w-full h-full object-contain"})})}),n("div",{className:"flex h-full flex-1 grow flex-col justify-between",children:[n("div",{className:"mb-4",children:[a(c,{as:"h3",size:2,className:t("text-info-primary mb-2 line-clamp-2 min-h-[2.4em]",i?.productTitle),html:e.custom_name||e.name}),e?.description&&a(g,{size:2,className:t("text-info-secondary desktop:line-clamp-2 desktop:min-h-[2.4em] desktop:text-[16px] lg-desktop:text-[18px] line-clamp-2 min-h-[2.4em] text-[14px]",i?.productDescription),html:e.custom_description||e.description})]}),e?.priceLabel&&e?.availableForSale&&a(g,{size:4,className:t("text-marketing-1 desktop:text-[16px] lg-desktop:text-[18px] mt-2 text-[14px]",i?.productPriceLabel),children:e.priceLabel}),n("div",{children:[a("div",{className:t("mb-2",i?.productPrice),children:a("div",{className:"flex items-baseline gap-2",children:e.availableForSale?n(H,{children:[a(c,{size:2,className:"text-info-primary",as:"h6",children:e.price}),B&&e.originalPrice&&a(c,{size:2,className:"text-info-tertiary line-through",as:"h6",children:e.originalPrice})]}):a(c,{size:2,className:"text-info-tertiary",children:f?.outOfStockLabel??"Sold Out"})})}),n("div",{className:t("lg-desktop:gap-3 tablet:flex-nowrap flex flex-wrap gap-2",i?.buttonGroup),children:[p&&a(C,{variant:"secondary",size:"base",className:t("tablet:w-fit w-full",i?.secondaryButton),onClick:()=>k(y,"secondary"),disabled:!e.availableForSale&&y!=="learnMore",loading:F,"data-headless-type-name":"ActiveShelf#ProductCard","data-headless-title-desc-button":`${e.custom_name||e.name}#${e.description||""}#${p}`,"data-headless-sku":e.sku,children:p}),u&&a(C,{variant:"primary",size:"base",className:t("tablet:w-fit w-full",i?.primaryButton),onClick:()=>k(v,"primary"),disabled:!e.availableForSale&&v!=="learnMore",loading:L,"data-headless-type-name":"ActiveShelf#ProductCard","data-headless-title-desc-button":`${e.custom_name||e.name}#${e.description||""}#${u}`,"data-headless-sku":e.sku,children:u})]}),j(m,P,e?.quantityAvailable??0,e?.totalInventory??0)&&n("div",{className:"mt-4 space-y-2",children:[a(E,{value:A,max:100,min:0,size:"base",variant:"default","aria-label":"stock progress",classNames:{root:t("bg-[var(--progress-track-bg,rgba(0,0,0,0.2))]",i?.stockTrack),progressBar:t("bg-brand-0 transition-all duration-300 ease-in-out",i?.stockBar)}}),a(g,{size:3,className:"text-info-tertiary text-[14px]",children:q?f?.limitedStock:f?.stockDisplayText?.replace("{count}",`${e.availableForSale?e.quantityAvailable:0}`)})]})]})]})]})})});b.displayName="ActiveShelf.ProductCard";var K=b;export{b as ProductCard,K as default};
|
|
2
2
|
//# sourceMappingURL=ProductCard.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/biz-components/ActiveShelf/ProductCard.tsx"],
|
|
4
|
-
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { cn } from '../../helpers/index.js'\nimport { Button, Badge, Card, CardContent, Picture, Text, Heading, Progress } from '../../components/index.js'\n\nimport type { ButtonFunctionType, CopyConfig } from './types.js'\nimport type { BadgeProps } from '../../components/badge.js'\n\n/**\n * \u8D85\u5356\u65F6\u5E93\u5B58\u6761\u663E\u793A\u7684\u6700\u5C0F\u767E\u5206\u6BD4\n * \u9632\u6B62\u8D85\u5356\u65F6\u5E93\u5B58\u6761\u663E\u793A\u4E3A\u6EE1\u683C\uFF08100%\uFF09\u6216\u5B8C\u5168\u7A7A\uFF080%\uFF09\n */\nconst OVERSELLING_STOCK_PERCENTAGE = 5\n\n/**\n * \u8BED\u4E49\u5316\u7C7B\u540D\n */\nexport type ActiveShelfSemanticName =\n | 'root'\n | 'title'\n | 'description'\n | 'productCard'\n | 'productTitle'\n | 'productDescription'\n | 'productPriceLabel'\n | 'productPrice'\n | 'buttonGroup'\n | 'secondaryButton'\n | 'primaryButton'\n | 'stockTrack'\n | 'stockBar'\n\n/**\n * \u5E93\u5B58\u5C55\u793A\u6A21\u5F0F\n */\nexport type StockDisplayMode = 'always' | 'never' | 'below-quantity' | 'below-percentage'\n\n/**\n * \u57FA\u7840\u4EA7\u54C1\u6570\u636E\u63A5\u53E3\uFF08\u6765\u81EA\u5916\u90E8\u6570\u636E\u6E90\uFF09\n */\nexport interface BaseProductData {\n sku: string\n name: string\n image: string\n value: string\n handle: string\n shopify_id: string\n custom_name?: string\n custom_description?: string\n}\n\n/**\n * Shopify \u53D8\u4F53\u6570\u636E\u63A5\u53E3\n */\nexport interface VariantData {\n /**\n * \u4EA7\u54C1\u63CF\u8FF0\n */\n description?: string\n /**\n * \u53D8\u4F53id\n */\n variantId: string\n\n /**\n * \u4EA7\u54C1\u94FE\u63A5, \u70B9\u51FB\u56FE\u7247\u7684\u65F6\u5019\u8DF3\u8F6C\u5230\u8BE5\u94FE\u63A5\n */\n listingLink: string\n /**\n * \u539F\u4EF7\n */\n originalPrice: string\n /**\n * \u73B0\u4EF7\n */\n price: string\n /**\n * \u4EF7\u683C\u4E0A\u9762\u5C55\u793A\u7684\u6807\u7B7E\u6587\u672C\n */\n priceLabel?: string\n /**\n * \u603B\u5E93\u5B58\n */\n totalInventory: number\n /**\n * \u53EF\u7528\u5E93\u5B58\u6570\u91CF\n */\n quantityAvailable: number\n /**\n * \u662F\u5426\u53EF\u552E\n */\n availableForSale: boolean\n\n /**\n * tags \u5217\u8868(\u4F1A\u5458\u4EF7\uFF0C\u6298\u6263\uFF0Cnew, hot\u7B49\u6807\u7B7E\u4FE1\u606F)\n */\n tags: Array<\n | {\n label: string\n variant: BadgeProps['variant']\n promotionalType?: BadgeProps['promotionalType']\n }\n | React.ReactNode\n >\n /**\n * \u901A\u7528\u6298\u6263\u6570\u636E\uFF0C\u5305\u62EC\u6298\u6263title, \u7C7B\u578B\u548C\u503C\n */\n coupon: any\n}\n\n/**\n * \u5B8C\u6574\u7684\u4EA7\u54C1\u5361\u7247\u6570\u636E\u63A5\u53E3\n */\nexport interface ProductCardData extends BaseProductData, VariantData {}\n\n/**\n * \u4EA7\u54C1\u5361\u7247\u7EC4\u4EF6 Props\n */\nexport interface ProductCardProps {\n /** \u4EA7\u54C1\u6570\u636E */\n product: ProductCardData\n /** \u6837\u5F0F\u7C7B\u540D */\n className?: string\n /** \u662F\u5426\u5C55\u793A\u6807\u7B7E\u7CFB\u7EDF */\n showTags?: boolean\n /** \u5E93\u5B58\u5C55\u793A\u6A21\u5F0F */\n stockDisplayMode?: StockDisplayMode\n /** \u5E93\u5B58\u9608\u503C\uFF08\u5F53\u6A21\u5F0F\u4E3A below-quantity \u6216 below-percentage \u65F6\u4F7F\u7528\uFF09 */\n stockThresholdValue?: number\n /** \u70B9\u51FB\u4E86\u89E3\u66F4\u591A\u56DE\u8C03 */\n onLearnMore?: (product: ProductCardData) => void\n /** \u70B9\u51FB\u7ACB\u5373\u8D2D\u4E70\u56DE\u8C03 */\n onShopNow?: (product: ProductCardData) => void\n /** \u70B9\u51FB\u52A0\u5165\u8D2D\u7269\u8F66\u56DE\u8C03 */\n onAddToCart?: (product: ProductCardData) => void\n /** \u8BED\u4E49\u5316\u7C7B\u540D */\n classNames?: Partial<Record<ActiveShelfSemanticName, string>>\n /** \u4E86\u89E3\u66F4\u591A\u6309\u94AE\u6587\u672C */\n secondaryButtonText?: string\n /** \u4E86\u89E3\u66F4\u591A\u6309\u94AE\u529F\u80FD */\n secondaryButtonFun?: ButtonFunctionType\n /** \u7ACB\u5373\u8D2D\u4E70\u6309\u94AE\u6587\u672C */\n primaryButtonText?: string\n /** \u7ACB\u5373\u8D2D\u4E70\u6309\u94AE\u529F\u80FD */\n primaryButtonFun?: ButtonFunctionType\n /** \u662F\u5426\u5C55\u793A\u539F\u4EF7\uFF08\u5220\u9664\u7EBF\u4EF7\u683C\uFF09 */\n showOriginalPrice?: boolean\n /** \u6587\u6848\u914D\u7F6E */\n copy?: CopyConfig\n onProductImageClick?: (product: ProductCardData) => void\n}\n\n/**\n * \u5224\u65AD\u662F\u5426\u5E94\u8BE5\u663E\u793A\u5E93\u5B58\u4FE1\u606F\n * @param stockDisplayMode \u5E93\u5B58\u5C55\u793A\u6A21\u5F0F\n * @param stockThresholdValue \u5E93\u5B58\u9608\u503C\uFF08\u5F53\u6A21\u5F0F\u4E3A below-quantity \u6216 below-percentage \u65F6\u4F7F\u7528\uFF09\n * @param quantityAvailable \u53EF\u7528\u5E93\u5B58\u6570\u91CF\n * @param totalInventory \u603B\u5E93\u5B58\n * @returns \u662F\u5426\u663E\u793A\u5E93\u5B58\u4FE1\u606F\n */\nfunction shouldShowStock(\n stockDisplayMode: StockDisplayMode | undefined,\n stockThresholdValue: number | undefined,\n quantityAvailable: number,\n totalInventory: number\n): boolean {\n // \u672A\u914D\u7F6E\u65F6\u9ED8\u8BA4\u663E\u793A\n if (stockDisplayMode === undefined) {\n return true\n }\n\n // \u6839\u636E\u5C55\u793A\u6A21\u5F0F\u5224\u65AD\n switch (stockDisplayMode) {\n case 'always':\n // \u603B\u662F\u663E\u793A\n return true\n\n case 'never':\n // \u6C38\u4E0D\u663E\u793A\n return false\n\n case 'below-quantity':\n // \u5F53\u5E93\u5B58\u6570\u91CF\u4F4E\u4E8E\u9608\u503C\u65F6\u663E\u793A\n if (stockThresholdValue === undefined) {\n return true // \u6CA1\u6709\u8BBE\u7F6E\u9608\u503C\u65F6\u9ED8\u8BA4\u663E\u793A\n }\n\n return quantityAvailable <= stockThresholdValue\n\n case 'below-percentage':\n // \u5F53\u5E93\u5B58\u767E\u5206\u6BD4\u4F4E\u4E8E\u9608\u503C\u65F6\u663E\u793A\n if (stockThresholdValue === undefined) {\n return true // \u6CA1\u6709\u8BBE\u7F6E\u9608\u503C\u65F6\u9ED8\u8BA4\u663E\u793A\n }\n return (quantityAvailable / totalInventory) * 100 <= stockThresholdValue\n\n default:\n // \u672A\u77E5\u6A21\u5F0F\u65F6\u9ED8\u8BA4\u663E\u793A\n return true\n }\n}\n\n/**\n * \u4EA7\u54C1\u5361\u7247\u7EC4\u4EF6\n */\nconst ProductCard = React.forwardRef<HTMLDivElement, ProductCardProps>(\n (\n {\n product,\n className,\n showTags = true,\n stockDisplayMode,\n stockThresholdValue,\n onLearnMore,\n onShopNow,\n onAddToCart,\n classNames,\n secondaryButtonText,\n secondaryButtonFun,\n primaryButtonText,\n primaryButtonFun,\n showOriginalPrice,\n copy,\n onProductImageClick,\n },\n ref\n ) => {\n const [primaryLoading, setPrimaryLoading] = React.useState(false)\n const [secondaryLoading, setSecondaryLoading] = React.useState(false)\n\n const stockPercentage = React.useMemo(() => {\n if (product?.availableForSale && product?.quantityAvailable <= 0) {\n return OVERSELLING_STOCK_PERCENTAGE\n }\n // \u4E0D\u53EF\u552E\u65F6\u663E\u793A0%\n if (!product?.availableForSale) {\n return 0\n }\n return ((product?.quantityAvailable ?? 0) / (product?.totalInventory ?? 1)) * 100\n }, [product?.availableForSale, product?.quantityAvailable, product?.totalInventory])\n\n // \u6839\u636E\u6309\u94AE\u529F\u80FD\u7C7B\u578B\u8C03\u7528\u76F8\u5E94\u7684\u56DE\u8C03\u51FD\u6570\n const handleButtonClick = async (buttonFun?: ButtonFunctionType, buttonType?: 'primary' | 'secondary') => {\n if (!buttonFun) return\n\n const setLoading = buttonType === 'primary' ? setPrimaryLoading : setSecondaryLoading\n setLoading(true)\n\n try {\n switch (buttonFun) {\n case 'buyNow':\n await onShopNow?.(product)\n break\n case 'addCart':\n await onAddToCart?.(product)\n break\n case 'learnMore':\n await onLearnMore?.(product)\n break\n default:\n break\n }\n } finally {\n setLoading(false)\n }\n }\n\n const overselling = product.availableForSale && product.quantityAvailable <= 0\n\n return (\n <Card\n ref={ref}\n className={cn(\n 'bg-container-primary hover:bg-container-secondary-0 flex h-full flex-col overflow-hidden border-none',\n className,\n classNames?.productCard\n )}\n >\n <CardContent className=\"desktop:p-6 relative flex flex-1 flex-col justify-between p-4\">\n {/* \u6807\u7B7E */}\n <div className=\"lg-desktop:h-[28px] flex h-[24px] gap-1\">\n {showTags &&\n product.tags?.map((tag: any, index) =>\n (tag as any).label ? (\n <Badge\n key={index}\n size=\"sm\"\n variant={(tag.variant as any) || 'outline'}\n className={cn(tag.variant === 'promotional' ? 'ml-2' : '')}\n promotionalType={tag.promotionalType}\n >\n {tag.label}\n </Badge>\n ) : (\n <React.Fragment key={index}>{tag}</React.Fragment>\n )\n )}\n </div>\n\n {/* \u4EA7\u54C1\u56FE\u533A\u57DF */}\n <div className=\"product-image-wrapper lg-desktop:size-[196px] mx-auto size-[138px] cursor-pointer overflow-hidden\">\n <a\n onClick={() => onProductImageClick?.(product)}\n {...(!onProductImageClick && {\n href: product?.listingLink,\n })}\n rel=\"noreferrer\"\n >\n <Picture\n source={product.image}\n alt={product.name}\n className=\"aspect-square size-full object-contain\"\n imgClassName=\"w-full h-full object-contain\"\n />\n </a>\n </div>\n\n {/* \u5185\u5BB9\u533A\u57DF */}\n <div className=\"flex h-full flex-1 grow flex-col justify-between\">\n {/* \u4EA7\u54C1\u4FE1\u606F */}\n <div className=\"mb-4\">\n <Heading\n as=\"h3\"\n size={2}\n className={cn('text-info-primary mb-2 line-clamp-2 min-h-[2.4em]', classNames?.productTitle)}\n html={product.custom_name || product.name}\n />\n {product?.description && (\n <Text\n size={2}\n className={cn(\n 'text-info-secondary desktop:line-clamp-2 desktop:min-h-[2.4em] desktop:text-[16px] lg-desktop:text-[18px] line-clamp-2 min-h-[2.4em] text-[14px]',\n classNames?.productDescription\n )}\n html={product.custom_description || product.description}\n />\n )}\n </div>\n\n {/** \u4EF7\u683C\u6807\u7B7E */}\n\n {product?.priceLabel && product?.availableForSale && (\n <Text\n size={4}\n className={cn(\n 'text-marketing-1 desktop:text-[16px] lg-desktop:text-[18px] mt-2 text-[14px]',\n classNames?.productPriceLabel\n )}\n >\n {product.priceLabel}\n </Text>\n )}\n\n {/* \u4EF7\u683C\u533A\u57DF */}\n <div>\n <div className={cn('mb-2', classNames?.productPrice)}>\n <div className=\"flex items-baseline gap-2\">\n {product.availableForSale ? (\n <>\n <Heading size={2} className=\"text-info-primary\" as=\"h6\">\n {product.price}\n </Heading>\n {showOriginalPrice && product.originalPrice && (\n <Heading size={2} className=\"text-info-tertiary line-through\" as=\"h6\">\n {product.originalPrice}\n </Heading>\n )}\n </>\n ) : (\n <Heading size={2} className=\"text-info-tertiary\">\n {copy?.outOfStockLabel ?? 'Sold Out'}\n </Heading>\n )}\n </div>\n </div>\n\n {/* \u6309\u94AE\u533A\u57DF */}\n <div className={cn('lg-desktop:gap-3 tablet:flex-nowrap flex flex-wrap gap-2', classNames?.buttonGroup)}>\n {secondaryButtonText && (\n <Button\n variant=\"secondary\"\n size=\"base\"\n className={cn('tablet:w-fit w-full', classNames?.secondaryButton)}\n onClick={() => handleButtonClick(secondaryButtonFun, 'secondary')}\n disabled={!product.availableForSale && secondaryButtonFun !== 'learnMore'}\n loading={secondaryLoading}\n data-headless-type-name=\"ActiveShelf#ProductCard\"\n data-headless-title-desc-button={`${product.custom_name || product.name}#${product.description || ''}#${secondaryButtonText}`}\n data-headless-sku={product.sku}\n >\n {secondaryButtonText}\n </Button>\n )}\n {primaryButtonText && (\n <Button\n variant=\"primary\"\n size=\"base\"\n className={cn('tablet:w-fit w-full', classNames?.primaryButton)}\n onClick={() => handleButtonClick(primaryButtonFun, 'primary')}\n disabled={!product.availableForSale && primaryButtonFun !== 'learnMore'}\n loading={primaryLoading}\n data-headless-type-name=\"ActiveShelf#ProductCard\"\n data-headless-title-desc-button={`${product.custom_name || product.name}#${product.description || ''}#${primaryButtonText}`}\n data-headless-sku={product.sku}\n >\n {primaryButtonText}\n </Button>\n )}\n </div>\n\n {/* \u5E93\u5B58\u4FE1\u606F */}\n {shouldShowStock(\n stockDisplayMode,\n stockThresholdValue,\n product?.quantityAvailable ?? 0,\n product?.totalInventory ?? 0\n ) && (\n <div className=\"mt-4 space-y-2\">\n <Progress\n value={stockPercentage}\n max={100}\n min={0}\n size=\"base\"\n variant=\"default\"\n aria-label=\"stock progress\"\n classNames={{\n root: cn('bg-[var(--progress-track-bg)]', classNames?.stockTrack),\n progressBar: cn('bg-brand-0 transition-all duration-300 ease-in-out', classNames?.stockBar),\n }}\n />\n <Text size={3} className=\"text-info-tertiary text-[14px]\">\n {overselling\n ? copy?.limitedStock\n : copy?.stockDisplayText?.replace(\n '{count}',\n `${product.availableForSale ? product.quantityAvailable : 0}`\n )}\n </Text>\n </div>\n )}\n </div>\n </div>\n </CardContent>\n </Card>\n )\n }\n)\n\nProductCard.displayName = 'ActiveShelf.ProductCard'\n\nexport { ProductCard }\nexport default ProductCard\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { cn } from '../../helpers/index.js'\nimport { Button, Badge, Card, CardContent, Picture, Text, Heading, Progress } from '../../components/index.js'\n\nimport type { ButtonFunctionType, CopyConfig } from './types.js'\nimport type { BadgeProps } from '../../components/badge.js'\n\n/**\n * \u8D85\u5356\u65F6\u5E93\u5B58\u6761\u663E\u793A\u7684\u6700\u5C0F\u767E\u5206\u6BD4\n * \u9632\u6B62\u8D85\u5356\u65F6\u5E93\u5B58\u6761\u663E\u793A\u4E3A\u6EE1\u683C\uFF08100%\uFF09\u6216\u5B8C\u5168\u7A7A\uFF080%\uFF09\n */\nconst OVERSELLING_STOCK_PERCENTAGE = 5\n\n/**\n * \u8BED\u4E49\u5316\u7C7B\u540D\n */\nexport type ActiveShelfSemanticName =\n | 'root'\n | 'title'\n | 'description'\n | 'productCard'\n | 'productTitle'\n | 'productDescription'\n | 'productPriceLabel'\n | 'productPrice'\n | 'buttonGroup'\n | 'secondaryButton'\n | 'primaryButton'\n | 'stockTrack'\n | 'stockBar'\n\n/**\n * \u5E93\u5B58\u5C55\u793A\u6A21\u5F0F\n */\nexport type StockDisplayMode = 'always' | 'never' | 'below-quantity' | 'below-percentage'\n\n/**\n * \u57FA\u7840\u4EA7\u54C1\u6570\u636E\u63A5\u53E3\uFF08\u6765\u81EA\u5916\u90E8\u6570\u636E\u6E90\uFF09\n */\nexport interface BaseProductData {\n sku: string\n name: string\n image: string\n value: string\n handle: string\n shopify_id: string\n custom_name?: string\n custom_description?: string\n}\n\n/**\n * Shopify \u53D8\u4F53\u6570\u636E\u63A5\u53E3\n */\nexport interface VariantData {\n /**\n * \u4EA7\u54C1\u63CF\u8FF0\n */\n description?: string\n /**\n * \u53D8\u4F53id\n */\n variantId: string\n\n /**\n * \u4EA7\u54C1\u94FE\u63A5, \u70B9\u51FB\u56FE\u7247\u7684\u65F6\u5019\u8DF3\u8F6C\u5230\u8BE5\u94FE\u63A5\n */\n listingLink: string\n /**\n * \u539F\u4EF7\n */\n originalPrice: string\n /**\n * \u73B0\u4EF7\n */\n price: string\n /**\n * \u4EF7\u683C\u4E0A\u9762\u5C55\u793A\u7684\u6807\u7B7E\u6587\u672C\n */\n priceLabel?: string\n /**\n * \u603B\u5E93\u5B58\n */\n totalInventory: number\n /**\n * \u53EF\u7528\u5E93\u5B58\u6570\u91CF\n */\n quantityAvailable: number\n /**\n * \u662F\u5426\u53EF\u552E\n */\n availableForSale: boolean\n\n /**\n * tags \u5217\u8868(\u4F1A\u5458\u4EF7\uFF0C\u6298\u6263\uFF0Cnew, hot\u7B49\u6807\u7B7E\u4FE1\u606F)\n */\n tags: Array<\n | {\n label: string\n variant: BadgeProps['variant']\n promotionalType?: BadgeProps['promotionalType']\n }\n | React.ReactNode\n >\n /**\n * \u901A\u7528\u6298\u6263\u6570\u636E\uFF0C\u5305\u62EC\u6298\u6263title, \u7C7B\u578B\u548C\u503C\n */\n coupon: any\n}\n\n/**\n * \u5B8C\u6574\u7684\u4EA7\u54C1\u5361\u7247\u6570\u636E\u63A5\u53E3\n */\nexport interface ProductCardData extends BaseProductData, VariantData {}\n\n/**\n * \u4EA7\u54C1\u5361\u7247\u7EC4\u4EF6 Props\n */\nexport interface ProductCardProps {\n /** \u4EA7\u54C1\u6570\u636E */\n product: ProductCardData\n /** \u6837\u5F0F\u7C7B\u540D */\n className?: string\n /** \u662F\u5426\u5C55\u793A\u6807\u7B7E\u7CFB\u7EDF */\n showTags?: boolean\n /** \u5E93\u5B58\u5C55\u793A\u6A21\u5F0F */\n stockDisplayMode?: StockDisplayMode\n /** \u5E93\u5B58\u9608\u503C\uFF08\u5F53\u6A21\u5F0F\u4E3A below-quantity \u6216 below-percentage \u65F6\u4F7F\u7528\uFF09 */\n stockThresholdValue?: number\n /** \u70B9\u51FB\u4E86\u89E3\u66F4\u591A\u56DE\u8C03 */\n onLearnMore?: (product: ProductCardData) => void\n /** \u70B9\u51FB\u7ACB\u5373\u8D2D\u4E70\u56DE\u8C03 */\n onShopNow?: (product: ProductCardData) => void\n /** \u70B9\u51FB\u52A0\u5165\u8D2D\u7269\u8F66\u56DE\u8C03 */\n onAddToCart?: (product: ProductCardData) => void\n /** \u8BED\u4E49\u5316\u7C7B\u540D */\n classNames?: Partial<Record<ActiveShelfSemanticName, string>>\n /** \u4E86\u89E3\u66F4\u591A\u6309\u94AE\u6587\u672C */\n secondaryButtonText?: string\n /** \u4E86\u89E3\u66F4\u591A\u6309\u94AE\u529F\u80FD */\n secondaryButtonFun?: ButtonFunctionType\n /** \u7ACB\u5373\u8D2D\u4E70\u6309\u94AE\u6587\u672C */\n primaryButtonText?: string\n /** \u7ACB\u5373\u8D2D\u4E70\u6309\u94AE\u529F\u80FD */\n primaryButtonFun?: ButtonFunctionType\n /** \u662F\u5426\u5C55\u793A\u539F\u4EF7\uFF08\u5220\u9664\u7EBF\u4EF7\u683C\uFF09 */\n showOriginalPrice?: boolean\n /** \u6587\u6848\u914D\u7F6E */\n copy?: CopyConfig\n onProductImageClick?: (product: ProductCardData) => void\n}\n\n/**\n * \u5224\u65AD\u662F\u5426\u5E94\u8BE5\u663E\u793A\u5E93\u5B58\u4FE1\u606F\n * @param stockDisplayMode \u5E93\u5B58\u5C55\u793A\u6A21\u5F0F\n * @param stockThresholdValue \u5E93\u5B58\u9608\u503C\uFF08\u5F53\u6A21\u5F0F\u4E3A below-quantity \u6216 below-percentage \u65F6\u4F7F\u7528\uFF09\n * @param quantityAvailable \u53EF\u7528\u5E93\u5B58\u6570\u91CF\n * @param totalInventory \u603B\u5E93\u5B58\n * @returns \u662F\u5426\u663E\u793A\u5E93\u5B58\u4FE1\u606F\n */\nfunction shouldShowStock(\n stockDisplayMode: StockDisplayMode | undefined,\n stockThresholdValue: number | undefined,\n quantityAvailable: number,\n totalInventory: number\n): boolean {\n // \u672A\u914D\u7F6E\u65F6\u9ED8\u8BA4\u663E\u793A\n if (stockDisplayMode === undefined) {\n return true\n }\n\n // \u6839\u636E\u5C55\u793A\u6A21\u5F0F\u5224\u65AD\n switch (stockDisplayMode) {\n case 'always':\n // \u603B\u662F\u663E\u793A\n return true\n\n case 'never':\n // \u6C38\u4E0D\u663E\u793A\n return false\n\n case 'below-quantity':\n // \u5F53\u5E93\u5B58\u6570\u91CF\u4F4E\u4E8E\u9608\u503C\u65F6\u663E\u793A\n if (stockThresholdValue === undefined) {\n return true // \u6CA1\u6709\u8BBE\u7F6E\u9608\u503C\u65F6\u9ED8\u8BA4\u663E\u793A\n }\n\n return quantityAvailable <= stockThresholdValue\n\n case 'below-percentage':\n // \u5F53\u5E93\u5B58\u767E\u5206\u6BD4\u4F4E\u4E8E\u9608\u503C\u65F6\u663E\u793A\n if (stockThresholdValue === undefined) {\n return true // \u6CA1\u6709\u8BBE\u7F6E\u9608\u503C\u65F6\u9ED8\u8BA4\u663E\u793A\n }\n return (quantityAvailable / totalInventory) * 100 <= stockThresholdValue\n\n default:\n // \u672A\u77E5\u6A21\u5F0F\u65F6\u9ED8\u8BA4\u663E\u793A\n return true\n }\n}\n\n/**\n * \u4EA7\u54C1\u5361\u7247\u7EC4\u4EF6\n */\nconst ProductCard = React.forwardRef<HTMLDivElement, ProductCardProps>(\n (\n {\n product,\n className,\n showTags = true,\n stockDisplayMode,\n stockThresholdValue,\n onLearnMore,\n onShopNow,\n onAddToCart,\n classNames,\n secondaryButtonText,\n secondaryButtonFun,\n primaryButtonText,\n primaryButtonFun,\n showOriginalPrice,\n copy,\n onProductImageClick,\n },\n ref\n ) => {\n const [primaryLoading, setPrimaryLoading] = React.useState(false)\n const [secondaryLoading, setSecondaryLoading] = React.useState(false)\n\n const stockPercentage = React.useMemo(() => {\n if (product?.availableForSale && product?.quantityAvailable <= 0) {\n return OVERSELLING_STOCK_PERCENTAGE\n }\n // \u4E0D\u53EF\u552E\u65F6\u663E\u793A0%\n if (!product?.availableForSale) {\n return 0\n }\n return ((product?.quantityAvailable ?? 0) / (product?.totalInventory ?? 1)) * 100\n }, [product?.availableForSale, product?.quantityAvailable, product?.totalInventory])\n\n // \u6839\u636E\u6309\u94AE\u529F\u80FD\u7C7B\u578B\u8C03\u7528\u76F8\u5E94\u7684\u56DE\u8C03\u51FD\u6570\n const handleButtonClick = async (buttonFun?: ButtonFunctionType, buttonType?: 'primary' | 'secondary') => {\n if (!buttonFun) return\n\n const setLoading = buttonType === 'primary' ? setPrimaryLoading : setSecondaryLoading\n setLoading(true)\n\n try {\n switch (buttonFun) {\n case 'buyNow':\n await onShopNow?.(product)\n break\n case 'addCart':\n await onAddToCart?.(product)\n break\n case 'learnMore':\n await onLearnMore?.(product)\n break\n default:\n break\n }\n } finally {\n setLoading(false)\n }\n }\n\n const overselling = product.availableForSale && product.quantityAvailable <= 0\n\n return (\n <Card\n ref={ref}\n className={cn(\n 'bg-container-primary hover:bg-container-secondary-0 flex h-full flex-col overflow-hidden border-none',\n className,\n classNames?.productCard\n )}\n >\n <CardContent className=\"desktop:p-6 relative flex flex-1 flex-col justify-between p-4\">\n {/* \u6807\u7B7E */}\n <div className=\"lg-desktop:h-[28px] flex h-[24px] gap-1\">\n {showTags &&\n product.tags?.map((tag: any, index) =>\n (tag as any).label ? (\n <Badge\n key={index}\n size=\"sm\"\n variant={(tag.variant as any) || 'outline'}\n className={cn(tag.variant === 'promotional' ? 'ml-2' : '')}\n promotionalType={tag.promotionalType}\n >\n {tag.label}\n </Badge>\n ) : (\n <React.Fragment key={index}>{tag}</React.Fragment>\n )\n )}\n </div>\n\n {/* \u4EA7\u54C1\u56FE\u533A\u57DF */}\n <div className=\"product-image-wrapper lg-desktop:size-[196px] mx-auto size-[138px] cursor-pointer overflow-hidden\">\n <a\n onClick={() => onProductImageClick?.(product)}\n {...(!onProductImageClick && {\n href: product?.listingLink,\n })}\n rel=\"noreferrer\"\n >\n <Picture\n source={product.image}\n alt={product.name}\n className=\"aspect-square size-full object-contain\"\n imgClassName=\"w-full h-full object-contain\"\n />\n </a>\n </div>\n\n {/* \u5185\u5BB9\u533A\u57DF */}\n <div className=\"flex h-full flex-1 grow flex-col justify-between\">\n {/* \u4EA7\u54C1\u4FE1\u606F */}\n <div className=\"mb-4\">\n <Heading\n as=\"h3\"\n size={2}\n className={cn('text-info-primary mb-2 line-clamp-2 min-h-[2.4em]', classNames?.productTitle)}\n html={product.custom_name || product.name}\n />\n {product?.description && (\n <Text\n size={2}\n className={cn(\n 'text-info-secondary desktop:line-clamp-2 desktop:min-h-[2.4em] desktop:text-[16px] lg-desktop:text-[18px] line-clamp-2 min-h-[2.4em] text-[14px]',\n classNames?.productDescription\n )}\n html={product.custom_description || product.description}\n />\n )}\n </div>\n\n {/** \u4EF7\u683C\u6807\u7B7E */}\n\n {product?.priceLabel && product?.availableForSale && (\n <Text\n size={4}\n className={cn(\n 'text-marketing-1 desktop:text-[16px] lg-desktop:text-[18px] mt-2 text-[14px]',\n classNames?.productPriceLabel\n )}\n >\n {product.priceLabel}\n </Text>\n )}\n\n {/* \u4EF7\u683C\u533A\u57DF */}\n <div>\n <div className={cn('mb-2', classNames?.productPrice)}>\n <div className=\"flex items-baseline gap-2\">\n {product.availableForSale ? (\n <>\n <Heading size={2} className=\"text-info-primary\" as=\"h6\">\n {product.price}\n </Heading>\n {showOriginalPrice && product.originalPrice && (\n <Heading size={2} className=\"text-info-tertiary line-through\" as=\"h6\">\n {product.originalPrice}\n </Heading>\n )}\n </>\n ) : (\n <Heading size={2} className=\"text-info-tertiary\">\n {copy?.outOfStockLabel ?? 'Sold Out'}\n </Heading>\n )}\n </div>\n </div>\n\n {/* \u6309\u94AE\u533A\u57DF */}\n <div className={cn('lg-desktop:gap-3 tablet:flex-nowrap flex flex-wrap gap-2', classNames?.buttonGroup)}>\n {secondaryButtonText && (\n <Button\n variant=\"secondary\"\n size=\"base\"\n className={cn('tablet:w-fit w-full', classNames?.secondaryButton)}\n onClick={() => handleButtonClick(secondaryButtonFun, 'secondary')}\n disabled={!product.availableForSale && secondaryButtonFun !== 'learnMore'}\n loading={secondaryLoading}\n data-headless-type-name=\"ActiveShelf#ProductCard\"\n data-headless-title-desc-button={`${product.custom_name || product.name}#${product.description || ''}#${secondaryButtonText}`}\n data-headless-sku={product.sku}\n >\n {secondaryButtonText}\n </Button>\n )}\n {primaryButtonText && (\n <Button\n variant=\"primary\"\n size=\"base\"\n className={cn('tablet:w-fit w-full', classNames?.primaryButton)}\n onClick={() => handleButtonClick(primaryButtonFun, 'primary')}\n disabled={!product.availableForSale && primaryButtonFun !== 'learnMore'}\n loading={primaryLoading}\n data-headless-type-name=\"ActiveShelf#ProductCard\"\n data-headless-title-desc-button={`${product.custom_name || product.name}#${product.description || ''}#${primaryButtonText}`}\n data-headless-sku={product.sku}\n >\n {primaryButtonText}\n </Button>\n )}\n </div>\n\n {/* \u5E93\u5B58\u4FE1\u606F */}\n {shouldShowStock(\n stockDisplayMode,\n stockThresholdValue,\n product?.quantityAvailable ?? 0,\n product?.totalInventory ?? 0\n ) && (\n <div className=\"mt-4 space-y-2\">\n <Progress\n value={stockPercentage}\n max={100}\n min={0}\n size=\"base\"\n variant=\"default\"\n aria-label=\"stock progress\"\n classNames={{\n root: cn('bg-[var(--progress-track-bg,rgba(0,0,0,0.2))]', classNames?.stockTrack),\n progressBar: cn('bg-brand-0 transition-all duration-300 ease-in-out', classNames?.stockBar),\n }}\n />\n <Text size={3} className=\"text-info-tertiary text-[14px]\">\n {overselling\n ? copy?.limitedStock\n : copy?.stockDisplayText?.replace(\n '{count}',\n `${product.availableForSale ? product.quantityAvailable : 0}`\n )}\n </Text>\n </div>\n )}\n </div>\n </div>\n </CardContent>\n </Card>\n )\n }\n)\n\nProductCard.displayName = 'ActiveShelf.ProductCard'\n\nexport { ProductCard }\nexport default ProductCard\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["Fragment", "jsx", "jsxs", "React", "cn", "Button", "Badge", "Card", "CardContent", "Picture", "Text", "Heading", "Progress", "OVERSELLING_STOCK_PERCENTAGE", "shouldShowStock", "stockDisplayMode", "stockThresholdValue", "quantityAvailable", "totalInventory", "ProductCard", "product", "className", "showTags", "onLearnMore", "onShopNow", "onAddToCart", "classNames", "secondaryButtonText", "secondaryButtonFun", "primaryButtonText", "primaryButtonFun", "showOriginalPrice", "copy", "onProductImageClick", "ref", "primaryLoading", "setPrimaryLoading", "secondaryLoading", "setSecondaryLoading", "stockPercentage", "handleButtonClick", "buttonFun", "buttonType", "setLoading", "overselling", "tag", "index", "ProductCard_default"]
|
|
7
7
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { ActivityMechanismProps } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* ActivityMechanism - 活动机制组件
|
|
5
|
+
*
|
|
6
|
+
* @description 展示活动机制/会员权益等卡片列表的组件,支持响应式布局和主题切换
|
|
7
|
+
*/
|
|
8
|
+
declare const ActivityMechanism: React.ForwardRefExoticComponent<ActivityMechanismProps & React.RefAttributes<HTMLDivElement>>;
|
|
9
|
+
export default ActivityMechanism;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";import{jsx as s,jsxs as y}from"react/jsx-runtime";import $,{useImperativeHandle as A,useRef as M}from"react";import{Heading as R,Picture as T,Text as V,Button as C,Link as N,Container as D}from"../../components/index.js";import"../../shared/Styles.js";import{cn as r}from"../../helpers/utils.js";import{useExposure as P}from"../../hooks/useExposure.js";import{trackUrlRef as g}from"../../shared/trackUrlRef.js";import{cva as f}from"class-variance-authority";import{getLocalizedPath as k}from"../../helpers/index.js";import{useAiuiContext as w}from"../AiuiProvider/index.js";const d="image",m="activity_mechanism",H=f("line-clamp-2",{variants:{theme:{light:"text-[#080A0F]",dark:"text-white"}},defaultVariants:{theme:"light"}}),L=f("desktop:text-[16px] mt-1 line-clamp-2 text-[14px] font-bold leading-[1.4] tracking-[-0.02em]",{variants:{theme:{light:"text-[#080A0F]",dark:"text-white/80"}},defaultVariants:{theme:"light"}}),B=f("mt-2 !p-0 text-[14px]",{variants:{theme:{light:"text-[#080A0F]",dark:"text-white"}},defaultVariants:{theme:"light"}}),h={default:767,tablet:1024,laptop:1439,desktop:1919,lgDesktop:9999},z=t=>{if(!t)return"";const e=[];return t.lgDesktop?.url&&e.push(`${t.lgDesktop.url}`),t.desktop?.url&&e.push(`${t.desktop.url} ${h.desktop}`),t.laptop?.url&&e.push(`${t.laptop.url} ${h.laptop}`),t.tablet?.url&&e.push(`${t.tablet.url} ${h.tablet}`),t.default?.url&&e.push(`${t.default.url} ${h.default}`),e.join(", ")},E=t=>t&&(t.default?.alt||t.tablet?.alt||t.laptop?.alt||t.desktop?.alt||t.lgDesktop?.alt)||"",S=({item:t,theme:e,classNames:l})=>{const{title:i,description:p,linkText:o,linkHref:a,backgroundImage:c}=t,n=z(c),u=E(c),{locale:v="us"}=w();return s("div",{className:r("rounded-card relative flex flex-col overflow-hidden","desktop:px-6 h-[280px] p-4","laptop:gap-4 gap-3","laptop:h-[320px] lg-desktop:[400px]",l?.card),"data-headless-type-name":`${d}#${m}`,children:y(N,{asChild:!a,href:k(g(a,`${d}_${m}`),v),className:"no-underline",children:[n&&s(T,{source:n,alt:u||i,className:r("absolute inset-0 size-full",l?.background),imgClassName:"size-full object-cover"}),y("div",{className:"relative z-10",children:[s(R,{as:"h3",size:3,className:r(H({theme:e}),l?.title),children:i}),s(V,{as:"p",className:r(L({theme:e}),l?.description),children:p}),o&&a&&s(C,{variant:"link",as:"a",href:k(g(a,`${d}_${m}`),v),className:r(B({theme:e}),l?.link),"data-headless-title-desc-button":`${i}#${p}#${o}`,children:o})]})]})})},x=$.forwardRef(({data:t,classNames:e},l)=>{const{items:i=[],theme:p="light"}=t,o=M(null);if(A(l,()=>o.current),P(o,{componentType:d,componentName:m,componentTitle:i[0]?.title||"",componentDescription:i[0]?.description||""}),!i||i.length===0)return null;const a={1:"laptop:grid-cols-1 desktop:grid-cols-1 lg-desktop:grid-cols-1",2:"laptop:grid-cols-2 desktop:grid-cols-2 lg-desktop:grid-cols-2",3:"tablet:grid-cols-2 laptop:grid-cols-3 desktop:grid-cols-3 lg-desktop:grid-cols-3",4:"laptop:grid-cols-4 desktop:grid-cols-4 lg-desktop:grid-cols-4"},c=a[Math.min(i.length,4)]||a[4];return s(D,{"data-ui-component-id":"ActivityMechanism",className:r("activity-mechanism","w-full",e?.root),ref:o,children:s("div",{className:r("tablet:grid-cols-2 laptop:gap-4 grid grid-cols-1 gap-3",c,e?.grid),children:i.map((n,u)=>s(S,{item:n,theme:p,classNames:{...e,...i?.length===3&&{card:e?.card+" first:tablet:col-span-full first:laptop:col-span-1"}}},`${n.title}-${u}`))})})});x.displayName="ActivityMechanism";var Q=x;export{Q as default};
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/biz-components/ActivityMechanism/index.tsx"],
|
|
4
|
+
"sourcesContent": ["'use client'\nimport React, { useImperativeHandle, useRef } from 'react'\nimport { Heading, Picture, Text, Button, Link, Container } from '../../components/index.js'\nimport { withLayout } from '../../shared/Styles.js'\nimport type {\n ActivityMechanismProps,\n ActivityMechanismItem,\n ActivityMechanismSemanticName,\n ResponsiveBackgroundImage,\n} from './types.js'\nimport { cn } from '../../helpers/utils.js'\nimport { useExposure } from '../../hooks/useExposure.js'\nimport { trackUrlRef } from '../../shared/trackUrlRef.js'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { getLocalizedPath } from '../../helpers/index.js'\nimport { useAiuiContext } from '../AiuiProvider/index.js'\n\nconst componentType = 'image'\nconst componentName = 'activity_mechanism'\n\n/**\n * \u6807\u9898\u6837\u5F0F\u53D8\u4F53\n */\nconst titleVariants = cva('line-clamp-2', {\n variants: {\n theme: {\n light: 'text-[#080A0F]',\n dark: 'text-white',\n },\n },\n defaultVariants: {\n theme: 'light',\n },\n})\n\n/**\n * \u63CF\u8FF0\u6837\u5F0F\u53D8\u4F53\n */\nconst descriptionVariants = cva(\n 'desktop:text-[16px] mt-1 line-clamp-2 text-[14px] font-bold leading-[1.4] tracking-[-0.02em]',\n {\n variants: {\n theme: {\n light: 'text-[#080A0F]',\n dark: 'text-white/80',\n },\n },\n defaultVariants: {\n theme: 'light',\n },\n }\n)\n\n/**\n * \u94FE\u63A5\u6837\u5F0F\u53D8\u4F53\n */\nconst linkVariants = cva('mt-2 !p-0 text-[14px]', {\n variants: {\n theme: {\n light: 'text-[#080A0F]',\n dark: 'text-white',\n },\n },\n defaultVariants: {\n theme: 'light',\n },\n})\n\ntype ThemeVariants = VariantProps<typeof titleVariants>\n\n/**\n * \u65AD\u70B9\u914D\u7F6E\uFF08\u4E0E Tailwind \u65AD\u70B9\u5BF9\u5E94\uFF09\n * Picture \u7EC4\u4EF6\u4F7F\u7528 max-width \u5A92\u4F53\u67E5\u8BE2\uFF0C\u6240\u4EE5\u9700\u8981\u6309\u4ECE\u5C0F\u5230\u5927\u7684\u987A\u5E8F\u6392\u5217\n */\nconst BREAKPOINTS = {\n default: 767, // <768px (\u79FB\u52A8\u7AEF)\n tablet: 1024, // 768px - 1024px\n laptop: 1439, // 1025px - 1439px\n desktop: 1919, // 1440px - 1919px\n lgDesktop: 9999, // \u22651920px (\u6700\u5927\u503C\uFF0C\u4F5C\u4E3A\u9ED8\u8BA4\u56FE\u7247)\n} as const\n\n/**\n * \u5C06\u54CD\u5E94\u5F0F\u80CC\u666F\u56FE\u7247\u5BF9\u8C61\u8F6C\u6362\u4E3A Picture \u7EC4\u4EF6\u7684 source \u5B57\u7B26\u4E32\n * \u683C\u5F0F: \"url1 767, url2 1024, url3 1439, url4 1919, url5\"\n */\nconst buildResponsiveSource = (backgroundImage?: ResponsiveBackgroundImage): string => {\n if (!backgroundImage) return ''\n\n const sources: string[] = []\n\n // \u6309\u65AD\u70B9\u987A\u5E8F\u6DFB\u52A0\u56FE\u7247 URL\n // lgDesktop \u4F5C\u4E3A\u9ED8\u8BA4\u56FE\u7247\uFF0C\u4E0D\u9700\u8981\u65AD\u70B9\u503C\n if (backgroundImage.lgDesktop?.url) {\n sources.push(`${backgroundImage.lgDesktop.url}`)\n }\n if (backgroundImage.desktop?.url) {\n sources.push(`${backgroundImage.desktop.url} ${BREAKPOINTS.desktop}`)\n }\n if (backgroundImage.laptop?.url) {\n sources.push(`${backgroundImage.laptop.url} ${BREAKPOINTS.laptop}`)\n }\n if (backgroundImage.tablet?.url) {\n sources.push(`${backgroundImage.tablet.url} ${BREAKPOINTS.tablet}`)\n }\n if (backgroundImage.default?.url) {\n sources.push(`${backgroundImage.default.url} ${BREAKPOINTS.default}`)\n }\n\n return sources.join(', ')\n}\n\n/**\n * \u83B7\u53D6\u54CD\u5E94\u5F0F\u80CC\u666F\u56FE\u7247\u7684\u9ED8\u8BA4 alt \u6587\u672C\n */\nconst getDefaultAlt = (backgroundImage?: ResponsiveBackgroundImage): string => {\n if (!backgroundImage) return ''\n return (\n backgroundImage.default?.alt ||\n backgroundImage.tablet?.alt ||\n backgroundImage.laptop?.alt ||\n backgroundImage.desktop?.alt ||\n backgroundImage.lgDesktop?.alt ||\n ''\n )\n}\n\n/**\n * \u5355\u4E2A\u6D3B\u52A8\u673A\u5236\u5361\u7247\u7EC4\u4EF6\n */\nconst ActivityMechanismCard: React.FC<{\n item: ActivityMechanismItem\n theme?: ThemeVariants['theme']\n classNames?: Partial<Record<ActivityMechanismSemanticName, string>>\n}> = ({ item, theme, classNames }) => {\n const { title, description, linkText, linkHref, backgroundImage } = item\n const responsiveSource = buildResponsiveSource(backgroundImage)\n const defaultAlt = getDefaultAlt(backgroundImage)\n const { locale = 'us' } = useAiuiContext()\n\n return (\n <div\n className={cn(\n 'rounded-card relative flex flex-col overflow-hidden',\n 'desktop:px-6 h-[280px] p-4',\n 'laptop:gap-4 gap-3',\n 'laptop:h-[320px] lg-desktop:[400px]',\n classNames?.card\n )}\n data-headless-type-name={`${componentType}#${componentName}`}\n >\n <Link\n asChild={!linkHref}\n href={getLocalizedPath(trackUrlRef(linkHref, `${componentType}_${componentName}`), locale)}\n className=\"no-underline\"\n >\n {/* \u54CD\u5E94\u5F0F\u80CC\u666F\u56FE\u7247 */}\n {responsiveSource && (\n <Picture\n source={responsiveSource}\n alt={defaultAlt || title}\n className={cn('absolute inset-0 size-full', classNames?.background)}\n imgClassName=\"size-full object-cover\"\n />\n )}\n\n {/* \u6587\u672C\u5185\u5BB9\u533A\u57DF */}\n <div className=\"relative z-10\">\n <Heading as=\"h3\" size={3} className={cn(titleVariants({ theme }), classNames?.title)}>\n {title}\n </Heading>\n <Text as=\"p\" className={cn(descriptionVariants({ theme }), classNames?.description)}>\n {description}\n </Text>\n {linkText && linkHref && (\n <Button\n variant=\"link\"\n as=\"a\"\n href={getLocalizedPath(trackUrlRef(linkHref, `${componentType}_${componentName}`), locale)}\n className={cn(linkVariants({ theme }), classNames?.link)}\n data-headless-title-desc-button={`${title}#${description}#${linkText}`}\n >\n {linkText}\n </Button>\n )}\n </div>\n </Link>\n </div>\n )\n}\n\n/**\n * ActivityMechanism - \u6D3B\u52A8\u673A\u5236\u7EC4\u4EF6\n *\n * @description \u5C55\u793A\u6D3B\u52A8\u673A\u5236/\u4F1A\u5458\u6743\u76CA\u7B49\u5361\u7247\u5217\u8868\u7684\u7EC4\u4EF6\uFF0C\u652F\u6301\u54CD\u5E94\u5F0F\u5E03\u5C40\u548C\u4E3B\u9898\u5207\u6362\n */\nconst ActivityMechanism = React.forwardRef<HTMLDivElement, ActivityMechanismProps>(({ data, classNames }, ref) => {\n const { items = [], theme = 'light' } = data\n\n const innerRef = useRef<HTMLDivElement>(null)\n\n useImperativeHandle(ref, () => innerRef.current as HTMLDivElement)\n\n useExposure(innerRef, {\n componentType,\n componentName,\n componentTitle: items[0]?.title || '',\n componentDescription: items[0]?.description || '',\n })\n\n if (!items || items.length === 0) {\n return null\n }\n\n // \u6839\u636E items \u6570\u91CF\u6620\u5C04 laptop/desktop/lg-desktop \u7684\u5217\u6570\u7C7B\u540D\n // \u4F7F\u7528\u663E\u5F0F\u7C7B\u540D\u6620\u5C04\u4EE5\u786E\u4FDD Tailwind \u80FD\u6B63\u786E\u626B\u63CF\n const gridColsMap: Record<number, string> = {\n 1: 'laptop:grid-cols-1 desktop:grid-cols-1 lg-desktop:grid-cols-1',\n 2: 'laptop:grid-cols-2 desktop:grid-cols-2 lg-desktop:grid-cols-2',\n 3: 'tablet:grid-cols-2 laptop:grid-cols-3 desktop:grid-cols-3 lg-desktop:grid-cols-3',\n 4: 'laptop:grid-cols-4 desktop:grid-cols-4 lg-desktop:grid-cols-4',\n }\n const gridColsClass = gridColsMap[Math.min(items.length, 4)] || gridColsMap[4]\n\n return (\n <Container\n data-ui-component-id=\"ActivityMechanism\"\n className={cn('activity-mechanism', 'w-full', classNames?.root)}\n ref={innerRef}\n >\n <div className={cn('tablet:grid-cols-2 laptop:gap-4 grid grid-cols-1 gap-3', gridColsClass, classNames?.grid)}>\n {items.map((item, index) => (\n <ActivityMechanismCard\n key={`${item.title}-${index}`}\n item={item}\n theme={theme}\n classNames={{\n ...classNames,\n ...(items?.length === 3 && {\n card: classNames?.card + ' ' + 'first:tablet:col-span-full first:laptop:col-span-1',\n }),\n }}\n />\n ))}\n </div>\n </Container>\n )\n})\n\nActivityMechanism.displayName = 'ActivityMechanism'\n\nexport default ActivityMechanism\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["jsx", "jsxs", "React", "useImperativeHandle", "useRef", "Heading", "Picture", "Text", "Button", "Link", "Container", "cn", "useExposure", "trackUrlRef", "cva", "getLocalizedPath", "useAiuiContext", "componentType", "componentName", "titleVariants", "descriptionVariants", "linkVariants", "BREAKPOINTS", "buildResponsiveSource", "backgroundImage", "sources", "getDefaultAlt", "ActivityMechanismCard", "item", "theme", "classNames", "title", "description", "linkText", "linkHref", "responsiveSource", "defaultAlt", "locale", "ActivityMechanism", "data", "ref", "items", "innerRef", "gridColsMap", "gridColsClass", "index", "ActivityMechanism_default"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { ComponentCommonProps, Media, Theme } from '../../types/props.js';
|
|
2
|
+
/**
|
|
3
|
+
* 响应式背景图片类型
|
|
4
|
+
* 支持 5 个断点的图片配置
|
|
5
|
+
*/
|
|
6
|
+
export interface ResponsiveBackgroundImage {
|
|
7
|
+
/** 默认图片 (<768px 移动端) */
|
|
8
|
+
default?: Media;
|
|
9
|
+
/** tablet 断点图片 (≥768px) */
|
|
10
|
+
tablet?: Media;
|
|
11
|
+
/** laptop 断点图片 (≥1025px) */
|
|
12
|
+
laptop?: Media;
|
|
13
|
+
/** desktop 断点图片 (≥1440px) */
|
|
14
|
+
desktop?: Media;
|
|
15
|
+
/** lg-desktop 断点图片 (≥1920px) */
|
|
16
|
+
lgDesktop?: Media;
|
|
17
|
+
}
|
|
18
|
+
export interface ActivityMechanismItem {
|
|
19
|
+
/** 标题 */
|
|
20
|
+
title: string;
|
|
21
|
+
/** 描述文本 */
|
|
22
|
+
description: string;
|
|
23
|
+
/** 链接文本 */
|
|
24
|
+
linkText?: string;
|
|
25
|
+
/** 链接地址 */
|
|
26
|
+
linkHref?: string;
|
|
27
|
+
/** 响应式背景图片(支持 5 个断点) */
|
|
28
|
+
backgroundImage?: ResponsiveBackgroundImage;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 语义化类名
|
|
32
|
+
*/
|
|
33
|
+
export type ActivityMechanismSemanticName = 'root' | 'grid' | 'card' | 'background' | 'title' | 'description' | 'link';
|
|
34
|
+
export interface ActivityMechanismProps extends ComponentCommonProps {
|
|
35
|
+
data: {
|
|
36
|
+
/** 活动机制列表 */
|
|
37
|
+
items: ActivityMechanismItem[];
|
|
38
|
+
/** 主题 */
|
|
39
|
+
theme?: Theme;
|
|
40
|
+
};
|
|
41
|
+
/** 语义化类名 */
|
|
42
|
+
classNames?: Partial<Record<ActivityMechanismSemanticName, string>>;
|
|
43
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";import{jsx as t,jsxs as h}from"react/jsx-runtime";import*as n from"react";import{cn as r}from"../../helpers/index.js";import{Text as b,Picture as A,Heading as u,Container as N,Link as C}from"../../components/index.js";import{cva as m}from"class-variance-authority";import{Swiper as P,SwiperSlide as V}from"swiper/react";import{withLayout as z}from"../../shared/Styles.js";const I=m("rounded-card laptop:px-6 laptop:py-4 relative flex min-w-0 flex-col justify-between gap-2 overflow-hidden px-4 py-3",{variants:{state:{"active-light":"bg-gradient-to-r from-[#3555aa] to-[#6988e3]","active-dark":"bg-gradient-to-r from-[#3555aa] to-[#6988e3]","inactive-light":"bg-[#EAEAEC]","inactive-dark":"bg-[#1E2024]"},size:{small:"laptop:h-[160px] h-[120px]",large:"laptop:h-[240px] h-[200px]"}},defaultVariants:{state:"inactive-light",size:"small"}}),v=m("font-bold leading-[1.2]",{variants:{state:{"active-light":"text-white","active-dark":"text-white","inactive-light":"text-[#080A0F]","inactive-dark":"text-white"}},defaultVariants:{state:"inactive-light"}}),f=n.memo(({item:e,theme:i="light",className:d,size:o})=>{const s=e.isActive||!1,l=`${s?"active":"inactive"}-${i}`;return t("div",{className:r(I({state:l,size:o}),d),"data-ui-component-id":"ActivityScheduleCard",children:h(C,{asChild:!e?.link,href:e?.link,className:"size-full no-underline hover:text-current",children:[(s?e.activeIcon:e.inactiveIcon)&&t("div",{className:"laptop:w-[160px] aspect-1 absolute right-0 top-0 z-10 w-[120px]",children:t(A,{source:s?e.activeIcon.url:e.inactiveIcon.url,alt:s?e.activeIcon.alt:e.inactiveIcon.alt,className:"aspect-square"})}),h("div",{className:"relative z-20 flex h-full flex-col justify-between",children:[t(u,{as:"h3",size:3,html:e.title,className:r(v({state:l}))}),h("div",{className:"flex flex-col gap-1",children:[t("div",{className:"flex flex-col justify-end overflow-hidden",children:t(u,{as:"h4",size:2,html:e.subtitle,className:r(" line-clamp-2",v({state:l}))})}),o==="large"&&e.description&&t(b,{html:e.description,className:r("lg-desktop:text-[18px] desktop:text-[16px] line-clamp-3 text-[14px] leading-[1.4]",v({state:l}))})]})]})]})})});f.displayName="ActivityScheduleCard";const g=n.forwardRef(({classNames:e={},data:i,...d},o)=>{const s=i.theme||"light",l=i.size||"large",a=n.useMemo(()=>i?.scheduleList?.length||2,[i?.scheduleList]),w=n.useMemo(()=>{const c=S=>{switch(S){case"mobile":return{slidesPerView:1.17,spaceBetween:12};case"tablet":return a===2?{slidesPerView:2,spaceBetween:12}:{slidesPerView:2.4,spaceBetween:12};case"laptop":return a===2?{}:a===4?{slidesPerView:3.2,spaceBetween:16}:{slidesPerView:a,spaceBetween:16};case"desktop":return a===2?{slidesPerView:2,spaceBetween:16}:{slidesPerView:a,spaceBetween:16}}},p=c("mobile"),x=c("tablet"),y=c("laptop"),k=c("desktop");return{0:p,768:x,1024:y,1440:k}},[a]);return t(N,{ref:o,className:r(e?.root),childClassName:"overflow-hidden","data-ui-component-id":"ActivitySchedule",...d,children:t(P,{breakpoints:w,className:"w-full !overflow-visible",children:i.scheduleList.map((c,p)=>t(V,{children:t(f,{item:c,theme:s,size:l,className:e?.card})},"activityScheduleCardItem"+p))})})});g.displayName="ActivitySchedule";var R=z(g);export{R as default};
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/biz-components/ActivitySchedule/index.tsx"],
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { cn } from '../../helpers/index.js'\nimport { Text, Picture, Heading, Container, Link } from '../../components/index.js'\nimport { cva } from 'class-variance-authority'\nimport type { ActivityScheduleProps, ActivityScheduleItem } from './types.js'\nimport { Swiper, SwiperSlide } from 'swiper/react'\nimport { withLayout } from '../../shared/Styles.js'\n\n/**\n * Card style variants for activity schedule\n */\nconst activityCardVariants = cva(\n 'rounded-card laptop:px-6 laptop:py-4 relative flex min-w-0 flex-col justify-between gap-2 overflow-hidden px-4 py-3',\n {\n variants: {\n state: {\n // Active state - gradient background\n 'active-light': 'bg-gradient-to-r from-[#3555aa] to-[#6988e3]',\n 'active-dark': 'bg-gradient-to-r from-[#3555aa] to-[#6988e3]',\n // Inactive state - solid background\n 'inactive-light': 'bg-[#EAEAEC]',\n 'inactive-dark': 'bg-[#1E2024]',\n },\n size: {\n // Small size - 120px height with responsive scaling\n small: 'laptop:h-[160px] h-[120px]',\n // Large size - 200px height with responsive scaling\n large: 'laptop:h-[240px] h-[200px]',\n },\n },\n defaultVariants: {\n state: 'inactive-light',\n size: 'small',\n },\n }\n)\n\n/**\n * Text style variants for card\n */\nconst cardTextVariants = cva('font-bold leading-[1.2]', {\n variants: {\n state: {\n // Active state - white text\n 'active-light': 'text-white',\n 'active-dark': 'text-white',\n // Inactive state - dark text\n 'inactive-light': 'text-[#080A0F]',\n 'inactive-dark': 'text-white',\n },\n },\n defaultVariants: {\n state: 'inactive-light',\n },\n})\n\n/**\n * Activity Schedule Card Component\n */\nconst ActivityScheduleCard = React.memo(\n ({\n item,\n theme = 'light',\n className,\n size,\n }: {\n item: ActivityScheduleItem\n theme?: 'light' | 'dark'\n className?: string\n size: 'small' | 'large'\n }) => {\n const isActive = item.isActive || false\n\n // Calculate combined state\n const cardState = `${isActive ? 'active' : 'inactive'}-${theme}` as\n | 'active-light'\n | 'active-dark'\n | 'inactive-light'\n | 'inactive-dark'\n\n return (\n <div\n className={cn(activityCardVariants({ state: cardState, size }), className)}\n data-ui-component-id=\"ActivityScheduleCard\"\n >\n <Link asChild={!item?.link} href={item?.link} className=\"size-full no-underline hover:text-current\">\n {/* Background decoration icon - show activeIcon when active, inactiveIcon when inactive */}\n {(isActive ? item.activeIcon : item.inactiveIcon) && (\n <div className=\"laptop:w-[160px] aspect-1 absolute right-0 top-0 z-10 w-[120px]\">\n <Picture\n source={isActive ? item.activeIcon!.url : item.inactiveIcon!.url}\n alt={isActive ? item.activeIcon!.alt : item.inactiveIcon!.alt}\n className=\"aspect-square\"\n />\n </div>\n )}\n\n {/* Content area */}\n <div className=\"relative z-20 flex h-full flex-col justify-between\">\n {/* Title */}\n <Heading as=\"h3\" size={3} html={item.title} className={cn(cardTextVariants({ state: cardState }))} />\n\n <div className=\"flex flex-col gap-1\">\n {/* Subtitle */}\n <div className=\"flex flex-col justify-end overflow-hidden\">\n <Heading\n as=\"h4\"\n size={2}\n html={item.subtitle}\n className={cn(' line-clamp-2', cardTextVariants({ state: cardState }))}\n />\n </div>\n {/* Detailed description - only show when size is large */}\n {size === 'large' && item.description && (\n <Text\n html={item.description}\n className={cn(\n 'lg-desktop:text-[18px] desktop:text-[16px] line-clamp-3 text-[14px] leading-[1.4]',\n cardTextVariants({ state: cardState })\n )}\n />\n )}\n </div>\n </div>\n </Link>\n </div>\n )\n }\n)\n\nActivityScheduleCard.displayName = 'ActivityScheduleCard'\n\n/**\n * ActivitySchedule - Activity Schedule Component\n *\n * @description Display activity schedule card list with active/inactive states, theme switching, and responsive layout\n */\nconst ActivitySchedule = React.forwardRef<HTMLDivElement, ActivityScheduleProps>(\n ({ classNames = {}, data, ...rest }, ref) => {\n const theme = data.theme || 'light'\n const size = data.size || 'large'\n\n const itemsPerRow = React.useMemo(() => {\n return data?.scheduleList?.length || 2\n }, [data?.scheduleList])\n\n const swiperBreakpoints = React.useMemo(() => {\n const getBreakpointConfig = (breakpoint: 'mobile' | 'tablet' | 'laptop' | 'desktop') => {\n switch (breakpoint) {\n case 'mobile':\n return { slidesPerView: 1.17, spaceBetween: 12 }\n case 'tablet':\n if (itemsPerRow === 2) return { slidesPerView: 2, spaceBetween: 12 }\n return { slidesPerView: 2.4, spaceBetween: 12 }\n case 'laptop':\n if (itemsPerRow === 2) return {}\n if (itemsPerRow === 4) return { slidesPerView: 3.2, spaceBetween: 16 }\n return { slidesPerView: itemsPerRow, spaceBetween: 16 }\n case 'desktop':\n if (itemsPerRow === 2) return { slidesPerView: 2, spaceBetween: 16 }\n return { slidesPerView: itemsPerRow, spaceBetween: 16 }\n }\n }\n\n const mobileConfig = getBreakpointConfig('mobile')\n const tabletConfig = getBreakpointConfig('tablet')\n const laptopConfig = getBreakpointConfig('laptop')\n const desktopConfig = getBreakpointConfig('desktop')\n\n return {\n 0: mobileConfig,\n 768: tabletConfig,\n 1024: laptopConfig,\n 1440: desktopConfig,\n }\n }, [itemsPerRow])\n\n return (\n <Container\n ref={ref}\n className={cn(classNames?.root)}\n childClassName=\"overflow-hidden\"\n data-ui-component-id=\"ActivitySchedule\"\n {...rest}\n >\n <Swiper breakpoints={swiperBreakpoints} className=\"w-full !overflow-visible\">\n {data.scheduleList.map((item, index) => (\n <SwiperSlide key={'activityScheduleCardItem' + index}>\n <ActivityScheduleCard item={item} theme={theme} size={size} className={classNames?.card} />\n </SwiperSlide>\n ))}\n </Swiper>\n </Container>\n )\n }\n)\n\nActivitySchedule.displayName = 'ActivitySchedule'\n\nexport default withLayout(ActivitySchedule)\nexport type { ActivityScheduleProps, ActivityScheduleData, ActivityScheduleItem } from './types.js'\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["jsx", "jsxs", "React", "cn", "Text", "Picture", "Heading", "Container", "Link", "cva", "Swiper", "SwiperSlide", "withLayout", "activityCardVariants", "cardTextVariants", "ActivityScheduleCard", "item", "theme", "className", "size", "isActive", "cardState", "ActivitySchedule", "classNames", "data", "rest", "ref", "itemsPerRow", "swiperBreakpoints", "getBreakpointConfig", "breakpoint", "mobileConfig", "tabletConfig", "laptopConfig", "desktopConfig", "index", "ActivitySchedule_default"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { Media } from '../../types/props.js';
|
|
2
|
+
/**
|
|
3
|
+
* 活动日程项数据接口
|
|
4
|
+
*/
|
|
5
|
+
export interface ActivityScheduleItem {
|
|
6
|
+
/** 活动标题 */
|
|
7
|
+
title: string;
|
|
8
|
+
/** 活动副标题 */
|
|
9
|
+
subtitle: string;
|
|
10
|
+
/** 活动详细描述(可选,用于完整版) */
|
|
11
|
+
description?: string;
|
|
12
|
+
/** 跳转链接 */
|
|
13
|
+
link?: string;
|
|
14
|
+
/** 激活状态装饰图标 */
|
|
15
|
+
activeIcon?: Media;
|
|
16
|
+
/** 非激活状态装饰图标 */
|
|
17
|
+
inactiveIcon?: Media;
|
|
18
|
+
/** 是否为激活状态(激活状态显示渐变背景) */
|
|
19
|
+
isActive?: boolean;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 活动日程组件数据接口
|
|
23
|
+
*/
|
|
24
|
+
export interface ActivityScheduleData {
|
|
25
|
+
/** 活动列表 */
|
|
26
|
+
scheduleList: ActivityScheduleItem[];
|
|
27
|
+
/** 主题模式,默认为 light */
|
|
28
|
+
theme?: 'light' | 'dark';
|
|
29
|
+
/** 卡片尺寸,默认为 small */
|
|
30
|
+
size?: 'small' | 'large';
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* 语义化类名
|
|
34
|
+
*/
|
|
35
|
+
export type ActivityScheduleSemanticName = 'root' | 'card';
|
|
36
|
+
/**
|
|
37
|
+
* 活动日程组件 Props
|
|
38
|
+
*/
|
|
39
|
+
export interface ActivityScheduleProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
40
|
+
/** 业务数据 */
|
|
41
|
+
data: ActivityScheduleData;
|
|
42
|
+
/** 语义化类名 */
|
|
43
|
+
classNames?: Partial<Record<ActivityScheduleSemanticName, string>>;
|
|
44
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -12,6 +12,17 @@ declare const anchorNavigationVariants: (props?: ({
|
|
|
12
12
|
alignment?: "end" | "start" | "center" | null | undefined;
|
|
13
13
|
size?: "small" | "large" | null | undefined;
|
|
14
14
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
15
|
+
/**
|
|
16
|
+
* 按钮颜色配置,允许按 theme 分别覆盖默认色、激活文字色、激活指示器色
|
|
17
|
+
*/
|
|
18
|
+
export interface AnchorButtonStyle {
|
|
19
|
+
/** 默认(未激活)文字色,Tailwind class,如 'text-info-secondary' */
|
|
20
|
+
defaultColor?: string;
|
|
21
|
+
/** 激活文字色,Tailwind class,如 'text-info-primary' */
|
|
22
|
+
activeColor?: string;
|
|
23
|
+
/** 激活指示器(下划线)背景色,Tailwind class,如 'after:bg-brand-0' */
|
|
24
|
+
activeIndicatorColor?: string;
|
|
25
|
+
}
|
|
15
26
|
/**
|
|
16
27
|
* 锚点项接口
|
|
17
28
|
*/
|
|
@@ -39,6 +50,15 @@ export interface AnchorNavigationProps extends React.HTMLAttributes<HTMLDivEleme
|
|
|
39
50
|
classNames?: Partial<Record<keyof AnchorNavigationSemanticName, string>>;
|
|
40
51
|
/** 自定义点击事件,传入时会替代默认的滚动行为 */
|
|
41
52
|
onItemClick?: (item: AnchorSectionItem, index: number) => void;
|
|
53
|
+
/**
|
|
54
|
+
* 按钮颜色配置,覆盖 light/dark 主题下的默认颜色。
|
|
55
|
+
* 未传时按主题使用内置默认值。
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* // 自定义颜色
|
|
59
|
+
* buttonStyle={{ defaultColor: 'text-info-secondary', activeColor: 'text-info-primary', activeIndicatorColor: 'after:bg-brand-3' }}
|
|
60
|
+
*/
|
|
61
|
+
buttonStyle?: AnchorButtonStyle;
|
|
42
62
|
}
|
|
43
63
|
/**
|
|
44
64
|
* AnchorNavigation - 锚点导航
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";import{jsx as
|
|
1
|
+
"use client";import{jsx as p}from"react/jsx-runtime";import*as n from"react";import{cn as g}from"../../helpers/utils.js";import{cva as h}from"class-variance-authority";import S from"./useAnchorPosition.js";import{Container as w}from"../../components/container.js";const D=h("anchor-navigation-content flex items-center overflow-x-auto [&::-webkit-scrollbar]:hidden",{variants:{alignment:{start:"tablet:justify-start",center:"tablet:justify-center",end:"tablet:justify-end"},size:{small:"gap-3",large:"gap-6"}},defaultVariants:{alignment:"start",size:"small"}}),E=h("anchor-navigation-item relative shrink-0 text-sm font-bold after:absolute after:bottom-0 after:left-0 after:h-1 after:w-0 after:opacity-0 after:transition-all after:duration-300",{variants:{size:{small:"py-3",large:"py-4"}},defaultVariants:{size:"small"}}),L=h("!sticky top-0 !z-40 w-full",{variants:{theme:{light:"bg-white",dark:"bg-[#1E2024]"}},defaultVariants:{theme:"light"}}),H={defaultColor:"text-[#4A4C56]",activeColor:"text-[#080A0F]",activeIndicatorColor:"after:bg-brand-0"},k={defaultColor:"text-[#8A8D92]",activeColor:"text-white",activeIndicatorColor:"after:bg-brand-0"},y=n.forwardRef(({classNames:l={},data:a,onItemClick:I,buttonStyle:s,className:B,...N},R)=>{const{alignment:x="start",theme:C="light",size:A="small"}=a,i=S(a.sectionIds?.map(t=>t.targetId)||[]),c=n.useRef(null),f=n.useRef(null),b=n.useRef([]);n.useImperativeHandle(R,()=>c.current);const d=C==="dark"?k:H,u={defaultColor:s?.defaultColor??d.defaultColor,activeColor:s?.activeColor??d.activeColor,activeIndicatorColor:s?.activeIndicatorColor??d.activeIndicatorColor},m=n.useCallback(t=>{const e=b.current[t];if(e&&f.current){const r=f.current,o=e,v=o.offsetLeft-r.offsetWidth/2+o.offsetWidth/2;typeof r.scrollTo=="function"&&r.scrollTo({left:v,behavior:"smooth"})}},[]);return n.useEffect(()=>{if(!i)return;const t=a.sectionIds?.findIndex(e=>e.targetId===i);t!==void 0&&t!==-1&&m(t)},[i,a.sectionIds,m]),p(w,{ref:c,className:g(L({theme:C}),l?.root),...N,children:p("div",{ref:f,className:g(D({alignment:x,size:A}),"relative",l?.content),children:a.sectionIds?.map((t,e)=>{const r=i===t.targetId;return p("button",{ref:o=>{o&&(b.current[e]=o)},"aria-current":r?!0:void 0,onClick:()=>{if(m(e),I){I(t,e);return}const o=document.getElementById(t.targetId);if(o&&c.current){const v=c.current.offsetHeight,T=o.getBoundingClientRect().top+window.scrollY-v;window.scrollTo({top:T,behavior:"smooth"})}},className:g(E({size:A}),r?[u.activeColor,u.activeIndicatorColor,"after:w-full after:opacity-100"]:u.defaultColor,l?.item),children:t.label},t.targetId)})})})});y.displayName="AnchorNavigation";var q=y;export{q as default};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/biz-components/AnchorNavigation/index.tsx"],
|
|
4
|
-
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { cn } from '../../helpers/utils.js'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport useAnchorPosition from './useAnchorPosition.js'\n\nexport interface AnchorNavigationSemanticName {\n root: 'root'\n content: 'content'\n item: 'item'\n}\n\n/**\n * \u5BFC\u822A\u9879\u5BF9\u9F50\u65B9\u5411\u6837\u5F0F\u53D8\u4F53\n */\nconst anchorNavigationVariants = cva(\n 'anchor-navigation-content flex items-center overflow-x-auto [&::-webkit-scrollbar]:hidden',\n {\n variants: {\n alignment: {\n start: 'tablet:justify-start',\n center: 'tablet:justify-center',\n end: 'tablet:justify-end',\n },\n size: {\n small: 'gap-3',\n large: 'gap-6',\n },\n },\n defaultVariants: {\n alignment: 'start',\n size: 'small',\n },\n }\n)\n\n/**\n * \u5BFC\u822A\u9879\u6837\u5F0F\u53D8\u4F53\n */\nconst anchorItemVariants = cva(\n 'anchor-navigation-item
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": ["jsx", "React", "cn", "cva", "useAnchorPosition", "anchorNavigationVariants", "anchorItemVariants", "containerVariants", "AnchorNavigation", "classNames", "data", "onItemClick", "className", "rest", "ref", "alignment", "theme", "size", "activeId", "item", "rootRef", "containerRef", "sectionRefs", "autoScrollToActiveItem", "activeIdIndex", "curRef", "container", "button", "scrollLeft", "activeIndex", "index", "isActive", "
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { cn } from '../../helpers/utils.js'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport useAnchorPosition from './useAnchorPosition.js'\nimport { Container } from '../../components/container.js'\n\nexport interface AnchorNavigationSemanticName {\n root: 'root'\n content: 'content'\n item: 'item'\n}\n\n/**\n * \u5BFC\u822A\u9879\u5BF9\u9F50\u65B9\u5411\u6837\u5F0F\u53D8\u4F53\n */\nconst anchorNavigationVariants = cva(\n 'anchor-navigation-content flex items-center overflow-x-auto [&::-webkit-scrollbar]:hidden',\n {\n variants: {\n alignment: {\n start: 'tablet:justify-start',\n center: 'tablet:justify-center',\n end: 'tablet:justify-end',\n },\n size: {\n small: 'gap-3',\n large: 'gap-6',\n },\n },\n defaultVariants: {\n alignment: 'start',\n size: 'small',\n },\n }\n)\n\n/**\n * \u5BFC\u822A\u9879\u6837\u5F0F\u53D8\u4F53\uFF08\u4E0D\u542B\u989C\u8272\uFF0C\u989C\u8272\u7531 buttonStyle \u63A7\u5236\uFF09\n */\nconst anchorItemVariants = cva(\n 'anchor-navigation-item relative shrink-0 text-sm font-bold after:absolute after:bottom-0 after:left-0 after:h-1 after:w-0 after:opacity-0 after:transition-all after:duration-300',\n {\n variants: {\n size: {\n small: 'py-3',\n large: 'py-4',\n },\n },\n defaultVariants: {\n size: 'small',\n },\n }\n)\n\n/**\n * \u5BB9\u5668\u4E3B\u9898\u6837\u5F0F\u53D8\u4F53\n */\nconst containerVariants = cva('!sticky top-0 !z-40 w-full', {\n variants: {\n theme: {\n light: 'bg-white',\n dark: 'bg-[#1E2024]',\n },\n },\n defaultVariants: {\n theme: 'light',\n },\n})\n\n/**\n * \u6309\u94AE\u989C\u8272\u914D\u7F6E\uFF0C\u5141\u8BB8\u6309 theme \u5206\u522B\u8986\u76D6\u9ED8\u8BA4\u8272\u3001\u6FC0\u6D3B\u6587\u5B57\u8272\u3001\u6FC0\u6D3B\u6307\u793A\u5668\u8272\n */\nexport interface AnchorButtonStyle {\n /** \u9ED8\u8BA4\uFF08\u672A\u6FC0\u6D3B\uFF09\u6587\u5B57\u8272\uFF0CTailwind class\uFF0C\u5982 'text-info-secondary' */\n defaultColor?: string\n /** \u6FC0\u6D3B\u6587\u5B57\u8272\uFF0CTailwind class\uFF0C\u5982 'text-info-primary' */\n activeColor?: string\n /** \u6FC0\u6D3B\u6307\u793A\u5668\uFF08\u4E0B\u5212\u7EBF\uFF09\u80CC\u666F\u8272\uFF0CTailwind class\uFF0C\u5982 'after:bg-brand-0' */\n activeIndicatorColor?: string\n}\n\n/**\n * \u951A\u70B9\u9879\u63A5\u53E3\n */\nexport interface AnchorSectionItem {\n targetId: string\n label: string\n}\n\n/**\n * AnchorNavigation \u4E1A\u52A1\u7EC4\u4EF6\u6570\u636E\u63A5\u53E3\n */\nexport interface AnchorNavigationData {\n /** \u951A\u70B9\u5217\u8868 */\n sectionIds: AnchorSectionItem[]\n /** \u5BFC\u822A\u9879\u6C34\u5E73\u5BF9\u9F50\u65B9\u5F0F */\n alignment?: 'start' | 'center' | 'end'\n /** \u4E3B\u9898\u6A21\u5F0F */\n theme?: 'light' | 'dark'\n /** \u5BFC\u822A\u5927\u5C0F */\n size?: 'small' | 'large'\n}\n\nexport interface AnchorNavigationProps\n extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof anchorNavigationVariants> {\n /** \u4E1A\u52A1\u6570\u636E */\n data: AnchorNavigationData\n /** \u8BED\u4E49\u5316\u7C7B\u540D */\n classNames?: Partial<Record<keyof AnchorNavigationSemanticName, string>>\n /** \u81EA\u5B9A\u4E49\u70B9\u51FB\u4E8B\u4EF6\uFF0C\u4F20\u5165\u65F6\u4F1A\u66FF\u4EE3\u9ED8\u8BA4\u7684\u6EDA\u52A8\u884C\u4E3A */\n onItemClick?: (item: AnchorSectionItem, index: number) => void\n /**\n * \u6309\u94AE\u989C\u8272\u914D\u7F6E\uFF0C\u8986\u76D6 light/dark \u4E3B\u9898\u4E0B\u7684\u9ED8\u8BA4\u989C\u8272\u3002\n * \u672A\u4F20\u65F6\u6309\u4E3B\u9898\u4F7F\u7528\u5185\u7F6E\u9ED8\u8BA4\u503C\u3002\n *\n * @example\n * // \u81EA\u5B9A\u4E49\u989C\u8272\n * buttonStyle={{ defaultColor: 'text-info-secondary', activeColor: 'text-info-primary', activeIndicatorColor: 'after:bg-brand-3' }}\n */\n buttonStyle?: AnchorButtonStyle\n}\n\n/** light \u4E3B\u9898\u9ED8\u8BA4\u989C\u8272 */\nconst LIGHT_DEFAULTS: Required<AnchorButtonStyle> = {\n defaultColor: 'text-[#4A4C56]',\n activeColor: 'text-[#080A0F]',\n activeIndicatorColor: 'after:bg-brand-0',\n}\n\n/** dark \u4E3B\u9898\u9ED8\u8BA4\u989C\u8272 */\nconst DARK_DEFAULTS: Required<AnchorButtonStyle> = {\n defaultColor: 'text-[#8A8D92]',\n activeColor: 'text-white',\n activeIndicatorColor: 'after:bg-brand-0',\n}\n\n/**\n * AnchorNavigation - \u951A\u70B9\u5BFC\u822A\n *\n * @description \u951A\u70B9\u5BFC\u822A\n */\nconst AnchorNavigation = React.forwardRef<HTMLDivElement, AnchorNavigationProps>(\n ({ classNames = {}, data, onItemClick, buttonStyle, className, ...rest }, ref) => {\n const { alignment = 'start', theme = 'light', size = 'small' } = data\n const activeId = useAnchorPosition(data.sectionIds?.map(item => item.targetId) || [])\n const rootRef = React.useRef<HTMLDivElement>(null)\n const containerRef = React.useRef<HTMLDivElement>(null)\n const sectionRefs = React.useRef<HTMLButtonElement[]>([])\n\n // \u66B4\u9732 rootRef \u7ED9\u5916\u90E8 ref\n React.useImperativeHandle(ref, () => rootRef.current as HTMLDivElement)\n\n // \u5408\u5E76\u4E3B\u9898\u9ED8\u8BA4\u503C\u4E0E\u5916\u90E8\u4F20\u5165\u7684 buttonStyle\n const themeDefaults = theme === 'dark' ? DARK_DEFAULTS : LIGHT_DEFAULTS\n const resolvedButtonStyle: Required<AnchorButtonStyle> = {\n defaultColor: buttonStyle?.defaultColor ?? themeDefaults.defaultColor,\n activeColor: buttonStyle?.activeColor ?? themeDefaults.activeColor,\n activeIndicatorColor: buttonStyle?.activeIndicatorColor ?? themeDefaults.activeIndicatorColor,\n }\n\n const autoScrollToActiveItem = React.useCallback((activeIdIndex: number) => {\n const curRef = sectionRefs.current[activeIdIndex]\n\n if (curRef && containerRef.current) {\n const container = containerRef.current\n const button = curRef\n const scrollLeft = button.offsetLeft - container.offsetWidth / 2 + button.offsetWidth / 2\n\n // \u68C0\u67E5 scrollTo \u65B9\u6CD5\u662F\u5426\u5B58\u5728\uFF08\u517C\u5BB9\u6D4B\u8BD5\u73AF\u5883\u548C\u65E7\u6D4F\u89C8\u5668\uFF09\n if (typeof container.scrollTo === 'function') {\n container.scrollTo({\n left: scrollLeft,\n behavior: 'smooth',\n })\n }\n }\n }, [])\n\n // \u5F53\u5C4F\u5E55\u6EDA\u52A8\u5BFC\u81F4 activeId \u53D8\u5316\u65F6\uFF0C\u81EA\u52A8\u6EDA\u52A8\u5BFC\u822A\u680F\u5230\u5BF9\u5E94\u9879\n React.useEffect(() => {\n if (!activeId) return\n\n const activeIndex = data.sectionIds?.findIndex(item => item.targetId === activeId)\n if (activeIndex !== undefined && activeIndex !== -1) {\n autoScrollToActiveItem(activeIndex)\n }\n }, [activeId, data.sectionIds, autoScrollToActiveItem])\n\n return (\n <Container ref={rootRef} className={cn(containerVariants({ theme }), classNames?.root)} {...rest}>\n <div\n ref={containerRef}\n className={cn(anchorNavigationVariants({ alignment, size }), 'relative', classNames?.content)}\n >\n {data.sectionIds?.map((item, index) => {\n const isActive = activeId === item.targetId\n\n return (\n <button\n key={item.targetId}\n ref={el => {\n if (el) {\n sectionRefs.current[index] = el\n }\n }}\n aria-current={isActive ? true : undefined}\n onClick={() => {\n // \u9ED8\u8BA4\u884C\u4E3A\uFF1A\u6EDA\u52A8\u5230\u5BF9\u5E94\u951A\u70B9\n autoScrollToActiveItem(index)\n\n // \u5982\u679C\u6709\u81EA\u5B9A\u4E49\u70B9\u51FB\u4E8B\u4EF6\uFF0C\u4F7F\u7528\u81EA\u5B9A\u4E49\u4E8B\u4EF6\n if (onItemClick) {\n onItemClick(item, index)\n return\n }\n\n // \u624B\u52A8\u8BA1\u7B97\u6EDA\u52A8\u4F4D\u7F6E\uFF0C\u8003\u8651\u5BFC\u822A\u680F\u9AD8\u5EA6\n const targetElement = document.getElementById(item.targetId)\n if (targetElement && rootRef.current) {\n const navHeight = rootRef.current.offsetHeight\n const targetPosition = targetElement.getBoundingClientRect().top + window.scrollY - navHeight\n\n window.scrollTo({\n top: targetPosition,\n behavior: 'smooth',\n })\n }\n }}\n className={cn(\n anchorItemVariants({ size }),\n isActive\n ? [\n resolvedButtonStyle.activeColor,\n resolvedButtonStyle.activeIndicatorColor,\n 'after:w-full after:opacity-100',\n ]\n : resolvedButtonStyle.defaultColor,\n classNames?.item\n )}\n >\n {item.label}\n </button>\n )\n })}\n </div>\n </Container>\n )\n }\n)\n\nAnchorNavigation.displayName = 'AnchorNavigation'\nexport default AnchorNavigation\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["jsx", "React", "cn", "cva", "useAnchorPosition", "Container", "anchorNavigationVariants", "anchorItemVariants", "containerVariants", "LIGHT_DEFAULTS", "DARK_DEFAULTS", "AnchorNavigation", "classNames", "data", "onItemClick", "buttonStyle", "className", "rest", "ref", "alignment", "theme", "size", "activeId", "item", "rootRef", "containerRef", "sectionRefs", "themeDefaults", "resolvedButtonStyle", "autoScrollToActiveItem", "activeIdIndex", "curRef", "container", "button", "scrollLeft", "activeIndex", "index", "isActive", "el", "targetElement", "navHeight", "targetPosition", "AnchorNavigation_default"]
|
|
7
7
|
}
|