deepsea-components 2.8.0-beta.20240516105156 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/AutoScroll.d.ts +14 -15
- package/dist/cjs/components/AutoScroll.js +59 -42
- package/dist/cjs/components/AutoScroll.js.map +2 -2
- package/dist/cjs/components/Scroll.d.ts +1 -9
- package/dist/cjs/components/Scroll.js +1 -1
- package/dist/cjs/components/Scroll.js.map +2 -2
- package/dist/esm/components/AutoScroll.d.ts +14 -15
- package/dist/esm/components/AutoScroll.js +60 -57
- package/dist/esm/components/AutoScroll.js.map +1 -1
- package/dist/esm/components/Scroll.d.ts +1 -9
- package/dist/esm/components/Scroll.js +0 -6
- package/dist/esm/components/Scroll.js.map +1 -1
- package/package.json +1 -1
- package/src/components/AutoScroll.tsx +65 -72
- package/src/components/Scroll.tsx +1 -9
|
@@ -1,22 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
export interface SwiperScrollProps
|
|
1
|
+
import { CSSProperties, FC } from "react";
|
|
2
|
+
import { ScrollProps } from "./Scroll";
|
|
3
|
+
export interface SwiperScrollProps extends Omit<ScrollProps, "scrollbar"> {
|
|
4
|
+
/** 轮播的数据 */
|
|
4
5
|
count: number;
|
|
5
|
-
/**
|
|
6
|
+
/** 轮播元素的高度 */
|
|
6
7
|
itemHeight: number;
|
|
7
|
-
/** 轮播的数据 */
|
|
8
|
-
data: T[];
|
|
9
|
-
/** key 生成器 */
|
|
10
|
-
keyExtractor?: (item: T, index: number, data: T[]) => string | number;
|
|
11
|
-
/** 轮播元素的渲染函数 */
|
|
12
|
-
render: (item: T, index: number, data: T[]) => ReactNode;
|
|
13
8
|
/** 轮播动画的时间 */
|
|
14
|
-
|
|
9
|
+
animation: number;
|
|
15
10
|
/** 每个元素的停留时间 */
|
|
16
|
-
|
|
11
|
+
duration: number;
|
|
17
12
|
/** 元素之间的间距 */
|
|
18
13
|
gap?: number;
|
|
19
|
-
/**
|
|
20
|
-
|
|
14
|
+
/** 容器类名 */
|
|
15
|
+
containerClassName?: string;
|
|
16
|
+
/** 容器样式 */
|
|
17
|
+
containerStyle?: CSSProperties;
|
|
18
|
+
/** 在鼠标移入时是否继续播放 */
|
|
19
|
+
playOnMouseEnter?: boolean;
|
|
21
20
|
}
|
|
22
|
-
export declare
|
|
21
|
+
export declare const AutoScroll: FC<SwiperScrollProps>;
|
|
@@ -22,66 +22,83 @@ __export(AutoScroll_exports, {
|
|
|
22
22
|
AutoScroll: () => AutoScroll
|
|
23
23
|
});
|
|
24
24
|
module.exports = __toCommonJS(AutoScroll_exports);
|
|
25
|
+
var import_css = require("@emotion/css");
|
|
26
|
+
var import_ahooks = require("ahooks");
|
|
27
|
+
var import_deepsea_tools = require("deepsea-tools");
|
|
25
28
|
var import_react = require("react");
|
|
26
29
|
var import_Scroll = require("./Scroll");
|
|
27
|
-
var
|
|
28
|
-
|
|
29
|
-
const { style, itemHeight, count, data, render, animationTime, period, keyExtractor, options, onMouseEnter, onMouseLeave, gap = 0, ...rest } = props;
|
|
30
|
-
const [offset, setOffset] = (0, import_react.useState)(0);
|
|
31
|
-
const offsetRef = (0, import_ahooks.useLatest)(offset);
|
|
32
|
-
const targetRef = (0, import_react.useRef)(0);
|
|
33
|
-
const [paused, setPaused] = (0, import_react.useState)(false);
|
|
34
|
-
const pausedRef = (0, import_ahooks.useLatest)(paused);
|
|
35
|
-
const periodRef = (0, import_ahooks.useLatest)(period);
|
|
36
|
-
const height = (itemHeight + gap) * count - gap;
|
|
30
|
+
var AutoScroll = (props) => {
|
|
31
|
+
const { count, itemHeight, animation, duration, onMouseEnter, onMouseLeave, gap = 0, containerClassName, containerStyle, children, playOnMouseEnter, ...rest } = props;
|
|
37
32
|
const bar = (0, import_react.useRef)(null);
|
|
38
33
|
const timeout = (0, import_react.useRef)(void 0);
|
|
34
|
+
const ele = (0, import_react.useRef)(null);
|
|
35
|
+
const size = (0, import_ahooks.useSize)(ele);
|
|
36
|
+
const pause = (0, import_react.useRef)(false);
|
|
39
37
|
(0, import_react.useEffect)(() => {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
38
|
+
if (playOnMouseEnter)
|
|
39
|
+
pause.current = false;
|
|
40
|
+
}, [playOnMouseEnter]);
|
|
41
|
+
(0, import_react.useEffect)(() => {
|
|
42
|
+
if (!size || count === 0)
|
|
43
|
+
return;
|
|
44
|
+
const { height } = size;
|
|
45
|
+
const range = (0, import_deepsea_tools.getArray)(count, (index) => (itemHeight + gap) * (index + 1) - (index === count - 1 ? gap : 0));
|
|
46
|
+
const scrollHeight = range[range.length - 1];
|
|
47
|
+
if (height >= scrollHeight)
|
|
48
|
+
return;
|
|
49
|
+
function scroll(target) {
|
|
48
50
|
clearTimeout(timeout.current);
|
|
49
51
|
timeout.current = setTimeout(() => {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
+
if (pause.current)
|
|
53
|
+
return scroll(target);
|
|
54
|
+
bar.current?.scrollTo(0, target, animation);
|
|
55
|
+
}, duration);
|
|
56
|
+
}
|
|
57
|
+
scroll(range[0]);
|
|
58
|
+
function listener(status) {
|
|
59
|
+
const { y } = status.offset;
|
|
60
|
+
const scrollToBottom = Math.abs(y + height - scrollHeight) / itemHeight <= 0.05;
|
|
61
|
+
const target = scrollToBottom ? 0 : range.find((item) => item > y);
|
|
62
|
+
scroll(target);
|
|
52
63
|
}
|
|
53
64
|
bar.current?.addListener(listener);
|
|
54
65
|
return () => {
|
|
66
|
+
clearTimeout(timeout.current);
|
|
55
67
|
bar.current?.removeListener(listener);
|
|
68
|
+
bar.current?.scrollTo(0, 0);
|
|
56
69
|
};
|
|
57
|
-
}, []);
|
|
58
|
-
(0, import_react.useEffect)(() => {
|
|
59
|
-
if (data.length <= count || paused === true)
|
|
60
|
-
return;
|
|
61
|
-
targetRef.current = (offset + 1) % (data.length + 1 - count);
|
|
62
|
-
timeout.current = setTimeout(() => {
|
|
63
|
-
setOffset(targetRef.current);
|
|
64
|
-
}, periodRef.current);
|
|
65
|
-
return () => clearTimeout(timeout.current);
|
|
66
|
-
}, [count, data.length, offset, paused]);
|
|
67
|
-
(0, import_react.useEffect)(() => {
|
|
68
|
-
setOffset(0);
|
|
69
|
-
}, [itemHeight, count, data.length, animationTime, period, gap]);
|
|
70
|
-
(0, import_react.useEffect)(() => {
|
|
71
|
-
if (pausedRef.current)
|
|
72
|
-
return;
|
|
73
|
-
bar.current?.scrollTo(0, offset * (itemHeight + gap), animationTime);
|
|
74
|
-
}, [offset]);
|
|
70
|
+
}, [size, count, itemHeight, gap, duration, animation]);
|
|
75
71
|
function onContainerMouseEnter(e) {
|
|
76
|
-
|
|
72
|
+
if (playOnMouseEnter)
|
|
73
|
+
return;
|
|
74
|
+
pause.current = true;
|
|
77
75
|
onMouseEnter?.(e);
|
|
78
76
|
}
|
|
79
77
|
function onContainerMouseLeave(e) {
|
|
80
|
-
|
|
78
|
+
if (playOnMouseEnter)
|
|
79
|
+
return;
|
|
80
|
+
pause.current = false;
|
|
81
81
|
onMouseLeave?.(e);
|
|
82
82
|
}
|
|
83
|
-
return /* @__PURE__ */ React.createElement(import_Scroll.Scroll, {
|
|
84
|
-
|
|
83
|
+
return /* @__PURE__ */ React.createElement(import_Scroll.Scroll, { ref: ele, scrollbar: bar, onMouseEnter: onContainerMouseEnter, onMouseLeave: onContainerMouseLeave, ...rest }, /* @__PURE__ */ React.createElement(
|
|
84
|
+
"div",
|
|
85
|
+
{
|
|
86
|
+
className: (0, import_deepsea_tools.clsx)(
|
|
87
|
+
import_css.css`
|
|
88
|
+
display: flex;
|
|
89
|
+
flex-direction: column;
|
|
90
|
+
gap: var(--gap, 0);
|
|
91
|
+
& > * {
|
|
92
|
+
flex: none;
|
|
93
|
+
}
|
|
94
|
+
`,
|
|
95
|
+
containerClassName
|
|
96
|
+
),
|
|
97
|
+
style: { "--gap": `${gap}px`, ...containerStyle }
|
|
98
|
+
},
|
|
99
|
+
children
|
|
100
|
+
));
|
|
101
|
+
};
|
|
85
102
|
// Annotate the CommonJS export names for ESM import in node:
|
|
86
103
|
0 && (module.exports = {
|
|
87
104
|
AutoScroll
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/components/AutoScroll.tsx"],
|
|
4
|
-
"sourcesContent": ["import {
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,
|
|
4
|
+
"sourcesContent": ["import { css } from \"@emotion/css\"\r\nimport { useSize } from \"ahooks\"\r\nimport { clsx, getArray } from \"deepsea-tools\"\r\nimport { CSSProperties, FC, MouseEvent as ReactMouseEvent, useEffect, useRef } from \"react\"\r\nimport Scrollbar from \"smooth-scrollbar\"\r\nimport { ScrollStatus } from \"smooth-scrollbar/interfaces/scrollbar\"\r\nimport { Scroll, ScrollProps } from \"./Scroll\"\r\n\r\nexport interface SwiperScrollProps extends Omit<ScrollProps, \"scrollbar\"> {\r\n /** 轮播的数据 */\r\n count: number\r\n\r\n /** 轮播元素的高度 */\r\n itemHeight: number\r\n\r\n /** 轮播动画的时间 */\r\n animation: number\r\n\r\n /** 每个元素的停留时间 */\r\n duration: number\r\n\r\n /** 元素之间的间距 */\r\n gap?: number\r\n\r\n /** 容器类名 */\r\n containerClassName?: string\r\n\r\n /** 容器样式 */\r\n containerStyle?: CSSProperties\r\n\r\n /** 在鼠标移入时是否继续播放 */\r\n playOnMouseEnter?: boolean\r\n}\r\n\r\nexport const AutoScroll: FC<SwiperScrollProps> = props => {\r\n const { count, itemHeight, animation, duration, onMouseEnter, onMouseLeave, gap = 0, containerClassName, containerStyle, children, playOnMouseEnter, ...rest } = props\r\n const bar = useRef<Scrollbar | null>(null)\r\n const timeout = useRef<NodeJS.Timeout | undefined>(undefined)\r\n const ele = useRef<HTMLDivElement>(null)\r\n const size = useSize(ele)\r\n const pause = useRef(false)\r\n\r\n useEffect(() => {\r\n if (playOnMouseEnter) pause.current = false\r\n }, [playOnMouseEnter])\r\n\r\n useEffect(() => {\r\n if (!size || count === 0) return\r\n const { height } = size\r\n const range = getArray(count, index => (itemHeight + gap) * (index + 1) - (index === count - 1 ? gap : 0))\r\n const scrollHeight = range[range.length - 1]\r\n if (height >= scrollHeight) return\r\n function scroll(target: number) {\r\n clearTimeout(timeout.current)\r\n timeout.current = setTimeout(() => {\r\n if (pause.current) return scroll(target)\r\n bar.current?.scrollTo(0, target, animation)\r\n }, duration)\r\n }\r\n scroll(range[0])\r\n function listener(status: ScrollStatus) {\r\n const { y } = status.offset\r\n const scrollToBottom = Math.abs(y + height - scrollHeight) / itemHeight <= 0.05\r\n const target = scrollToBottom ? 0 : range.find(item => item > y)!\r\n scroll(target)\r\n }\r\n bar.current?.addListener(listener)\r\n return () => {\r\n clearTimeout(timeout.current)\r\n bar.current?.removeListener(listener)\r\n bar.current?.scrollTo(0, 0)\r\n }\r\n }, [size, count, itemHeight, gap, duration, animation])\r\n\r\n function onContainerMouseEnter(e: ReactMouseEvent<HTMLDivElement, MouseEvent>) {\r\n if (playOnMouseEnter) return\r\n pause.current = true\r\n onMouseEnter?.(e)\r\n }\r\n\r\n function onContainerMouseLeave(e: ReactMouseEvent<HTMLDivElement, MouseEvent>) {\r\n if (playOnMouseEnter) return\r\n pause.current = false\r\n onMouseLeave?.(e)\r\n }\r\n\r\n return (\r\n <Scroll ref={ele} scrollbar={bar} onMouseEnter={onContainerMouseEnter} onMouseLeave={onContainerMouseLeave} {...rest}>\r\n <div\r\n className={clsx(\r\n css`\r\n display: flex;\r\n flex-direction: column;\r\n gap: var(--gap, 0);\r\n & > * {\r\n flex: none;\r\n }\r\n `,\r\n containerClassName\r\n )}\r\n style={{ \"--gap\": `${gap}px`, ...containerStyle } as CSSProperties}>\r\n {children}\r\n </div>\r\n </Scroll>\r\n )\r\n}\r\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAAoB;AACpB,oBAAwB;AACxB,2BAA+B;AAC/B,mBAAoF;AAGpF,oBAAoC;AA4B7B,IAAM,aAAoC,WAAS;AACtD,QAAM,EAAE,OAAO,YAAY,WAAW,UAAU,cAAc,cAAc,MAAM,GAAG,oBAAoB,gBAAgB,UAAU,kBAAkB,GAAG,KAAK,IAAI;AACjK,QAAM,UAAM,qBAAyB,IAAI;AACzC,QAAM,cAAU,qBAAmC,MAAS;AAC5D,QAAM,UAAM,qBAAuB,IAAI;AACvC,QAAM,WAAO,uBAAQ,GAAG;AACxB,QAAM,YAAQ,qBAAO,KAAK;AAE1B,8BAAU,MAAM;AACZ,QAAI;AAAkB,YAAM,UAAU;AAAA,EAC1C,GAAG,CAAC,gBAAgB,CAAC;AAErB,8BAAU,MAAM;AACZ,QAAI,CAAC,QAAQ,UAAU;AAAG;AAC1B,UAAM,EAAE,OAAO,IAAI;AACnB,UAAM,YAAQ,+BAAS,OAAO,YAAU,aAAa,QAAQ,QAAQ,MAAM,UAAU,QAAQ,IAAI,MAAM,EAAE;AACzG,UAAM,eAAe,MAAM,MAAM,SAAS,CAAC;AAC3C,QAAI,UAAU;AAAc;AAC5B,aAAS,OAAO,QAAgB;AAC5B,mBAAa,QAAQ,OAAO;AAC5B,cAAQ,UAAU,WAAW,MAAM;AAC/B,YAAI,MAAM;AAAS,iBAAO,OAAO,MAAM;AACvC,YAAI,SAAS,SAAS,GAAG,QAAQ,SAAS;AAAA,MAC9C,GAAG,QAAQ;AAAA,IACf;AACA,WAAO,MAAM,CAAC,CAAC;AACf,aAAS,SAAS,QAAsB;AACpC,YAAM,EAAE,EAAE,IAAI,OAAO;AACrB,YAAM,iBAAiB,KAAK,IAAI,IAAI,SAAS,YAAY,IAAI,cAAc;AAC3E,YAAM,SAAS,iBAAiB,IAAI,MAAM,KAAK,UAAQ,OAAO,CAAC;AAC/D,aAAO,MAAM;AAAA,IACjB;AACA,QAAI,SAAS,YAAY,QAAQ;AACjC,WAAO,MAAM;AACT,mBAAa,QAAQ,OAAO;AAC5B,UAAI,SAAS,eAAe,QAAQ;AACpC,UAAI,SAAS,SAAS,GAAG,CAAC;AAAA,IAC9B;AAAA,EACJ,GAAG,CAAC,MAAM,OAAO,YAAY,KAAK,UAAU,SAAS,CAAC;AAEtD,WAAS,sBAAsB,GAAgD;AAC3E,QAAI;AAAkB;AACtB,UAAM,UAAU;AAChB,mBAAe,CAAC;AAAA,EACpB;AAEA,WAAS,sBAAsB,GAAgD;AAC3E,QAAI;AAAkB;AACtB,UAAM,UAAU;AAChB,mBAAe,CAAC;AAAA,EACpB;AAEA,SACI,oCAAC,wBAAO,KAAK,KAAK,WAAW,KAAK,cAAc,uBAAuB,cAAc,uBAAwB,GAAG,QAC5G;AAAA,IAAC;AAAA;AAAA,MACG,eAAW;AAAA,QACP;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAQA;AAAA,MACJ;AAAA,MACA,OAAO,EAAE,SAAS,GAAG,SAAS,GAAG,eAAe;AAAA;AAAA,IAC/C;AAAA,EACL,CACJ;AAER;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ForwardedRef, HTMLAttributes } from "react";
|
|
2
2
|
import Scrollbar from "smooth-scrollbar";
|
|
3
3
|
import type { ScrollbarOptions, ScrollListener } from "smooth-scrollbar/interfaces";
|
|
4
4
|
export { default as Scrollbar } from "smooth-scrollbar";
|
|
@@ -10,17 +10,9 @@ export interface ScrollOptions extends Partial<ScrollbarOptions> {
|
|
|
10
10
|
export interface ScrollProps extends HTMLAttributes<HTMLDivElement> {
|
|
11
11
|
/** 滚动的配置 */
|
|
12
12
|
options?: ScrollOptions;
|
|
13
|
-
/** 容器宽度 */
|
|
14
|
-
containerClassName?: string;
|
|
15
|
-
/** 容器样式 */
|
|
16
|
-
containerStyle?: CSSProperties;
|
|
17
13
|
/** 滚动条实例 */
|
|
18
14
|
scrollbar?: ForwardedRef<Scrollbar>;
|
|
19
15
|
/** 滚动条滚动事件 */
|
|
20
16
|
onScrollbar?: ScrollListener;
|
|
21
17
|
}
|
|
22
|
-
/**
|
|
23
|
-
* 滚动条组件
|
|
24
|
-
* @description 注意 children 不是直接渲染在组件上的,而是渲染在内部的容器上
|
|
25
|
-
*/
|
|
26
18
|
export declare const Scroll: import("react").ForwardRefExoticComponent<ScrollProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -41,7 +41,7 @@ var import_smooth_scrollbar = __toESM(require("smooth-scrollbar"));
|
|
|
41
41
|
var import_smooth_scrollbar2 = __toESM(require("smooth-scrollbar"));
|
|
42
42
|
__reExport(Scroll_exports, require("smooth-scrollbar/interfaces"), module.exports);
|
|
43
43
|
var Scroll = (0, import_react.forwardRef)((props, ref) => {
|
|
44
|
-
const { children,
|
|
44
|
+
const { children, options, className, style, scrollbar, onScrollbar, ...rest } = props;
|
|
45
45
|
const { thumbWidth, ...scrollbarOptions } = options || {};
|
|
46
46
|
const ele = (0, import_react.useRef)(null);
|
|
47
47
|
const bar = (0, import_react.useRef)(null);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/components/Scroll.tsx"],
|
|
4
|
-
"sourcesContent": ["import { css } from \"@emotion/css\"\r\nimport { clsx } from \"deepsea-tools\"\r\nimport { CSSProperties, ForwardedRef, forwardRef, HTMLAttributes, useEffect, useImperativeHandle, useRef } from \"react\"\r\nimport Scrollbar from \"smooth-scrollbar\"\r\nimport type { ScrollbarOptions, ScrollListener } from \"smooth-scrollbar/interfaces\"\r\nexport { default as Scrollbar } from \"smooth-scrollbar\"\r\nexport * from \"smooth-scrollbar/interfaces\"\r\n\r\nexport interface ScrollOptions extends Partial<ScrollbarOptions> {\r\n /** 滑块宽度 */\r\n thumbWidth?: number\r\n}\r\n\r\nexport interface ScrollProps extends HTMLAttributes<HTMLDivElement> {\r\n /** 滚动的配置 */\r\n options?: ScrollOptions\r\n /**
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAAoB;AACpB,2BAAqB;AACrB,mBAAgH;AAChH,8BAAsB;AAEtB,IAAAA,2BAAqC;AACrC,2BAAc,wCANd;
|
|
4
|
+
"sourcesContent": ["import { css } from \"@emotion/css\"\r\nimport { clsx } from \"deepsea-tools\"\r\nimport { CSSProperties, ForwardedRef, forwardRef, HTMLAttributes, useEffect, useImperativeHandle, useRef } from \"react\"\r\nimport Scrollbar from \"smooth-scrollbar\"\r\nimport type { ScrollbarOptions, ScrollListener } from \"smooth-scrollbar/interfaces\"\r\nexport { default as Scrollbar } from \"smooth-scrollbar\"\r\nexport * from \"smooth-scrollbar/interfaces\"\r\n\r\nexport interface ScrollOptions extends Partial<ScrollbarOptions> {\r\n /** 滑块宽度 */\r\n thumbWidth?: number\r\n}\r\n\r\nexport interface ScrollProps extends HTMLAttributes<HTMLDivElement> {\r\n /** 滚动的配置 */\r\n options?: ScrollOptions\r\n /** 滚动条实例 */\r\n scrollbar?: ForwardedRef<Scrollbar>\r\n /** 滚动条滚动事件 */\r\n onScrollbar?: ScrollListener\r\n}\r\n\r\nexport const Scroll = forwardRef<HTMLDivElement, ScrollProps>((props, ref) => {\r\n const { children, options, className, style, scrollbar, onScrollbar, ...rest } = props\r\n const { thumbWidth, ...scrollbarOptions } = options || {}\r\n const ele = useRef<HTMLDivElement>(null)\r\n const bar = useRef<Scrollbar | null>(null)\r\n\r\n useImperativeHandle(ref, () => ele.current!, [])\r\n\r\n useEffect(() => {\r\n bar.current = Scrollbar.init(ele.current!, scrollbarOptions)\r\n return () => bar.current?.destroy()\r\n }, [])\r\n\r\n useEffect(() => {\r\n if (!scrollbar) return\r\n if (typeof scrollbar === \"function\") {\r\n scrollbar(bar.current)\r\n return () => scrollbar(null)\r\n }\r\n scrollbar.current = bar.current\r\n return () => (scrollbar.current = null)\r\n }, [scrollbar])\r\n\r\n useEffect(() => {\r\n if (!onScrollbar) return\r\n bar.current?.addListener(onScrollbar)\r\n return () => bar.current?.removeListener(onScrollbar)\r\n }, [onScrollbar])\r\n\r\n return (\r\n <div\r\n ref={ele}\r\n className={clsx(\r\n typeof thumbWidth === \"number\" &&\r\n css`\r\n .scrollbar-track.scrollbar-track-x {\r\n height: var(--thumb-width);\r\n }\r\n\r\n .scrollbar-thumb.scrollbar-thumb-x {\r\n height: var(--thumb-width);\r\n }\r\n\r\n .scrollbar-track.scrollbar-track-y {\r\n width: var(--thumb-width);\r\n }\r\n\r\n .scrollbar-thumb.scrollbar-thumb-y {\r\n width: var(--thumb-width);\r\n }\r\n `,\r\n className\r\n )}\r\n style={\r\n {\r\n \"--thumb-width\": typeof thumbWidth === \"number\" ? `${thumbWidth}px` : undefined,\r\n ...style\r\n } as CSSProperties\r\n }\r\n {...rest}>\r\n {children}\r\n </div>\r\n )\r\n})\r\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAAoB;AACpB,2BAAqB;AACrB,mBAAgH;AAChH,8BAAsB;AAEtB,IAAAA,2BAAqC;AACrC,2BAAc,wCANd;AAsBO,IAAM,aAAS,yBAAwC,CAAC,OAAO,QAAQ;AAC1E,QAAM,EAAE,UAAU,SAAS,WAAW,OAAO,WAAW,aAAa,GAAG,KAAK,IAAI;AACjF,QAAM,EAAE,YAAY,GAAG,iBAAiB,IAAI,WAAW,CAAC;AACxD,QAAM,UAAM,qBAAuB,IAAI;AACvC,QAAM,UAAM,qBAAyB,IAAI;AAEzC,wCAAoB,KAAK,MAAM,IAAI,SAAU,CAAC,CAAC;AAE/C,8BAAU,MAAM;AACZ,QAAI,UAAU,wBAAAC,QAAU,KAAK,IAAI,SAAU,gBAAgB;AAC3D,WAAO,MAAM,IAAI,SAAS,QAAQ;AAAA,EACtC,GAAG,CAAC,CAAC;AAEL,8BAAU,MAAM;AACZ,QAAI,CAAC;AAAW;AAChB,QAAI,OAAO,cAAc,YAAY;AACjC,gBAAU,IAAI,OAAO;AACrB,aAAO,MAAM,UAAU,IAAI;AAAA,IAC/B;AACA,cAAU,UAAU,IAAI;AACxB,WAAO,MAAO,UAAU,UAAU;AAAA,EACtC,GAAG,CAAC,SAAS,CAAC;AAEd,8BAAU,MAAM;AACZ,QAAI,CAAC;AAAa;AAClB,QAAI,SAAS,YAAY,WAAW;AACpC,WAAO,MAAM,IAAI,SAAS,eAAe,WAAW;AAAA,EACxD,GAAG,CAAC,WAAW,CAAC;AAEhB,SACI;AAAA,IAAC;AAAA;AAAA,MACG,KAAK;AAAA,MACL,eAAW;AAAA,QACP,OAAO,eAAe,YAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAiBJ;AAAA,MACJ;AAAA,MACA,OACI;AAAA,QACI,iBAAiB,OAAO,eAAe,WAAW,GAAG,iBAAiB;AAAA,QACtE,GAAG;AAAA,MACP;AAAA,MAEH,GAAG;AAAA;AAAA,IACH;AAAA,EACL;AAER,CAAC;",
|
|
6
6
|
"names": ["import_smooth_scrollbar", "Scrollbar"]
|
|
7
7
|
}
|
|
@@ -1,22 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
export interface SwiperScrollProps
|
|
1
|
+
import { CSSProperties, FC } from "react";
|
|
2
|
+
import { ScrollProps } from "./Scroll";
|
|
3
|
+
export interface SwiperScrollProps extends Omit<ScrollProps, "scrollbar"> {
|
|
4
|
+
/** 轮播的数据 */
|
|
4
5
|
count: number;
|
|
5
|
-
/**
|
|
6
|
+
/** 轮播元素的高度 */
|
|
6
7
|
itemHeight: number;
|
|
7
|
-
/** 轮播的数据 */
|
|
8
|
-
data: T[];
|
|
9
|
-
/** key 生成器 */
|
|
10
|
-
keyExtractor?: (item: T, index: number, data: T[]) => string | number;
|
|
11
|
-
/** 轮播元素的渲染函数 */
|
|
12
|
-
render: (item: T, index: number, data: T[]) => ReactNode;
|
|
13
8
|
/** 轮播动画的时间 */
|
|
14
|
-
|
|
9
|
+
animation: number;
|
|
15
10
|
/** 每个元素的停留时间 */
|
|
16
|
-
|
|
11
|
+
duration: number;
|
|
17
12
|
/** 元素之间的间距 */
|
|
18
13
|
gap?: number;
|
|
19
|
-
/**
|
|
20
|
-
|
|
14
|
+
/** 容器类名 */
|
|
15
|
+
containerClassName?: string;
|
|
16
|
+
/** 容器样式 */
|
|
17
|
+
containerStyle?: CSSProperties;
|
|
18
|
+
/** 在鼠标移入时是否继续播放 */
|
|
19
|
+
playOnMouseEnter?: boolean;
|
|
21
20
|
}
|
|
22
|
-
export declare
|
|
21
|
+
export declare const AutoScroll: FC<SwiperScrollProps>;
|
|
@@ -1,91 +1,94 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { css } from "@emotion/css";
|
|
2
|
+
import { useSize } from "ahooks";
|
|
3
|
+
import { clsx, getArray } from "deepsea-tools";
|
|
4
|
+
import { useEffect, useRef } from "react";
|
|
2
5
|
import { Scroll } from "./Scroll";
|
|
3
|
-
import { useLatest } from "ahooks";
|
|
4
6
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
5
|
-
export
|
|
7
|
+
export const AutoScroll = props => {
|
|
6
8
|
const {
|
|
7
|
-
style,
|
|
8
|
-
itemHeight,
|
|
9
9
|
count,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
period,
|
|
14
|
-
keyExtractor,
|
|
15
|
-
options,
|
|
10
|
+
itemHeight,
|
|
11
|
+
animation,
|
|
12
|
+
duration,
|
|
16
13
|
onMouseEnter,
|
|
17
14
|
onMouseLeave,
|
|
18
15
|
gap = 0,
|
|
16
|
+
containerClassName,
|
|
17
|
+
containerStyle,
|
|
18
|
+
children,
|
|
19
|
+
playOnMouseEnter,
|
|
19
20
|
...rest
|
|
20
21
|
} = props;
|
|
21
|
-
const [offset, setOffset] = useState(0);
|
|
22
|
-
const offsetRef = useLatest(offset);
|
|
23
|
-
const targetRef = useRef(0);
|
|
24
|
-
const [paused, setPaused] = useState(false);
|
|
25
|
-
const pausedRef = useLatest(paused);
|
|
26
|
-
const periodRef = useLatest(period);
|
|
27
|
-
const height = (itemHeight + gap) * count - gap;
|
|
28
22
|
const bar = useRef(null);
|
|
29
23
|
const timeout = useRef(undefined);
|
|
24
|
+
const ele = useRef(null);
|
|
25
|
+
const size = useSize(ele);
|
|
26
|
+
const pause = useRef(false);
|
|
30
27
|
useEffect(() => {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
28
|
+
if (playOnMouseEnter) pause.current = false;
|
|
29
|
+
}, [playOnMouseEnter]);
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
if (!size || count === 0) return;
|
|
32
|
+
const {
|
|
33
|
+
height
|
|
34
|
+
} = size;
|
|
35
|
+
const range = getArray(count, index => (itemHeight + gap) * (index + 1) - (index === count - 1 ? gap : 0));
|
|
36
|
+
const scrollHeight = range[range.length - 1];
|
|
37
|
+
if (height >= scrollHeight) return;
|
|
38
|
+
function scroll(target) {
|
|
39
39
|
clearTimeout(timeout.current);
|
|
40
40
|
timeout.current = setTimeout(() => {
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
if (pause.current) return scroll(target);
|
|
42
|
+
bar.current?.scrollTo(0, target, animation);
|
|
43
|
+
}, duration);
|
|
44
|
+
}
|
|
45
|
+
scroll(range[0]);
|
|
46
|
+
function listener(status) {
|
|
47
|
+
const {
|
|
48
|
+
y
|
|
49
|
+
} = status.offset;
|
|
50
|
+
const scrollToBottom = Math.abs(y + height - scrollHeight) / itemHeight <= 0.05;
|
|
51
|
+
const target = scrollToBottom ? 0 : range.find(item => item > y);
|
|
52
|
+
scroll(target);
|
|
43
53
|
}
|
|
44
54
|
bar.current?.addListener(listener);
|
|
45
55
|
return () => {
|
|
56
|
+
clearTimeout(timeout.current);
|
|
46
57
|
bar.current?.removeListener(listener);
|
|
58
|
+
bar.current?.scrollTo(0, 0);
|
|
47
59
|
};
|
|
48
|
-
}, []);
|
|
49
|
-
useEffect(() => {
|
|
50
|
-
if (data.length <= count || paused === true) return;
|
|
51
|
-
targetRef.current = (offset + 1) % (data.length + 1 - count);
|
|
52
|
-
timeout.current = setTimeout(() => {
|
|
53
|
-
setOffset(targetRef.current);
|
|
54
|
-
}, periodRef.current);
|
|
55
|
-
return () => clearTimeout(timeout.current);
|
|
56
|
-
}, [count, data.length, offset, paused]);
|
|
57
|
-
useEffect(() => {
|
|
58
|
-
setOffset(0);
|
|
59
|
-
}, [itemHeight, count, data.length, animationTime, period, gap]);
|
|
60
|
-
useEffect(() => {
|
|
61
|
-
if (pausedRef.current) return;
|
|
62
|
-
bar.current?.scrollTo(0, offset * (itemHeight + gap), animationTime);
|
|
63
|
-
}, [offset]);
|
|
60
|
+
}, [size, count, itemHeight, gap, duration, animation]);
|
|
64
61
|
function onContainerMouseEnter(e) {
|
|
65
|
-
|
|
62
|
+
if (playOnMouseEnter) return;
|
|
63
|
+
pause.current = true;
|
|
66
64
|
onMouseEnter?.(e);
|
|
67
65
|
}
|
|
68
66
|
function onContainerMouseLeave(e) {
|
|
69
|
-
|
|
67
|
+
if (playOnMouseEnter) return;
|
|
68
|
+
pause.current = false;
|
|
70
69
|
onMouseLeave?.(e);
|
|
71
70
|
}
|
|
72
71
|
return /*#__PURE__*/_jsx(Scroll, {
|
|
72
|
+
ref: ele,
|
|
73
73
|
scrollbar: bar,
|
|
74
|
-
options: options,
|
|
75
|
-
style: {
|
|
76
|
-
height,
|
|
77
|
-
...style
|
|
78
|
-
},
|
|
79
74
|
onMouseEnter: onContainerMouseEnter,
|
|
80
75
|
onMouseLeave: onContainerMouseLeave,
|
|
81
76
|
...rest,
|
|
82
|
-
children:
|
|
77
|
+
children: /*#__PURE__*/_jsx("div", {
|
|
78
|
+
className: clsx(css`
|
|
79
|
+
display: flex;
|
|
80
|
+
flex-direction: column;
|
|
81
|
+
gap: var(--gap, 0);
|
|
82
|
+
& > * {
|
|
83
|
+
flex: none;
|
|
84
|
+
}
|
|
85
|
+
`, containerClassName),
|
|
83
86
|
style: {
|
|
84
|
-
|
|
85
|
-
|
|
87
|
+
"--gap": `${gap}px`,
|
|
88
|
+
...containerStyle
|
|
86
89
|
},
|
|
87
|
-
children:
|
|
88
|
-
}
|
|
90
|
+
children: children
|
|
91
|
+
})
|
|
89
92
|
});
|
|
90
|
-
}
|
|
93
|
+
};
|
|
91
94
|
//# sourceMappingURL=AutoScroll.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["
|
|
1
|
+
{"version":3,"names":["css","useSize","clsx","getArray","useEffect","useRef","Scroll","jsx","_jsx","AutoScroll","props","count","itemHeight","animation","duration","onMouseEnter","onMouseLeave","gap","containerClassName","containerStyle","children","playOnMouseEnter","rest","bar","timeout","undefined","ele","size","pause","current","height","range","index","scrollHeight","length","scroll","target","clearTimeout","setTimeout","scrollTo","listener","status","y","offset","scrollToBottom","Math","abs","find","item","addListener","removeListener","onContainerMouseEnter","e","onContainerMouseLeave","ref","scrollbar","className","style"],"sources":["../../../src/components/AutoScroll.tsx"],"sourcesContent":["import { css } from \"@emotion/css\"\r\nimport { useSize } from \"ahooks\"\r\nimport { clsx, getArray } from \"deepsea-tools\"\r\nimport { CSSProperties, FC, MouseEvent as ReactMouseEvent, useEffect, useRef } from \"react\"\r\nimport Scrollbar from \"smooth-scrollbar\"\r\nimport { ScrollStatus } from \"smooth-scrollbar/interfaces/scrollbar\"\r\nimport { Scroll, ScrollProps } from \"./Scroll\"\r\n\r\nexport interface SwiperScrollProps extends Omit<ScrollProps, \"scrollbar\"> {\r\n /** 轮播的数据 */\r\n count: number\r\n\r\n /** 轮播元素的高度 */\r\n itemHeight: number\r\n\r\n /** 轮播动画的时间 */\r\n animation: number\r\n\r\n /** 每个元素的停留时间 */\r\n duration: number\r\n\r\n /** 元素之间的间距 */\r\n gap?: number\r\n\r\n /** 容器类名 */\r\n containerClassName?: string\r\n\r\n /** 容器样式 */\r\n containerStyle?: CSSProperties\r\n\r\n /** 在鼠标移入时是否继续播放 */\r\n playOnMouseEnter?: boolean\r\n}\r\n\r\nexport const AutoScroll: FC<SwiperScrollProps> = props => {\r\n const { count, itemHeight, animation, duration, onMouseEnter, onMouseLeave, gap = 0, containerClassName, containerStyle, children, playOnMouseEnter, ...rest } = props\r\n const bar = useRef<Scrollbar | null>(null)\r\n const timeout = useRef<NodeJS.Timeout | undefined>(undefined)\r\n const ele = useRef<HTMLDivElement>(null)\r\n const size = useSize(ele)\r\n const pause = useRef(false)\r\n\r\n useEffect(() => {\r\n if (playOnMouseEnter) pause.current = false\r\n }, [playOnMouseEnter])\r\n\r\n useEffect(() => {\r\n if (!size || count === 0) return\r\n const { height } = size\r\n const range = getArray(count, index => (itemHeight + gap) * (index + 1) - (index === count - 1 ? gap : 0))\r\n const scrollHeight = range[range.length - 1]\r\n if (height >= scrollHeight) return\r\n function scroll(target: number) {\r\n clearTimeout(timeout.current)\r\n timeout.current = setTimeout(() => {\r\n if (pause.current) return scroll(target)\r\n bar.current?.scrollTo(0, target, animation)\r\n }, duration)\r\n }\r\n scroll(range[0])\r\n function listener(status: ScrollStatus) {\r\n const { y } = status.offset\r\n const scrollToBottom = Math.abs(y + height - scrollHeight) / itemHeight <= 0.05\r\n const target = scrollToBottom ? 0 : range.find(item => item > y)!\r\n scroll(target)\r\n }\r\n bar.current?.addListener(listener)\r\n return () => {\r\n clearTimeout(timeout.current)\r\n bar.current?.removeListener(listener)\r\n bar.current?.scrollTo(0, 0)\r\n }\r\n }, [size, count, itemHeight, gap, duration, animation])\r\n\r\n function onContainerMouseEnter(e: ReactMouseEvent<HTMLDivElement, MouseEvent>) {\r\n if (playOnMouseEnter) return\r\n pause.current = true\r\n onMouseEnter?.(e)\r\n }\r\n\r\n function onContainerMouseLeave(e: ReactMouseEvent<HTMLDivElement, MouseEvent>) {\r\n if (playOnMouseEnter) return\r\n pause.current = false\r\n onMouseLeave?.(e)\r\n }\r\n\r\n return (\r\n <Scroll ref={ele} scrollbar={bar} onMouseEnter={onContainerMouseEnter} onMouseLeave={onContainerMouseLeave} {...rest}>\r\n <div\r\n className={clsx(\r\n css`\r\n display: flex;\r\n flex-direction: column;\r\n gap: var(--gap, 0);\r\n & > * {\r\n flex: none;\r\n }\r\n `,\r\n containerClassName\r\n )}\r\n style={{ \"--gap\": `${gap}px`, ...containerStyle } as CSSProperties}>\r\n {children}\r\n </div>\r\n </Scroll>\r\n )\r\n}\r\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ForwardedRef, HTMLAttributes } from "react";
|
|
2
2
|
import Scrollbar from "smooth-scrollbar";
|
|
3
3
|
import type { ScrollbarOptions, ScrollListener } from "smooth-scrollbar/interfaces";
|
|
4
4
|
export { default as Scrollbar } from "smooth-scrollbar";
|
|
@@ -10,17 +10,9 @@ export interface ScrollOptions extends Partial<ScrollbarOptions> {
|
|
|
10
10
|
export interface ScrollProps extends HTMLAttributes<HTMLDivElement> {
|
|
11
11
|
/** 滚动的配置 */
|
|
12
12
|
options?: ScrollOptions;
|
|
13
|
-
/** 容器宽度 */
|
|
14
|
-
containerClassName?: string;
|
|
15
|
-
/** 容器样式 */
|
|
16
|
-
containerStyle?: CSSProperties;
|
|
17
13
|
/** 滚动条实例 */
|
|
18
14
|
scrollbar?: ForwardedRef<Scrollbar>;
|
|
19
15
|
/** 滚动条滚动事件 */
|
|
20
16
|
onScrollbar?: ScrollListener;
|
|
21
17
|
}
|
|
22
|
-
/**
|
|
23
|
-
* 滚动条组件
|
|
24
|
-
* @description 注意 children 不是直接渲染在组件上的,而是渲染在内部的容器上
|
|
25
|
-
*/
|
|
26
18
|
export declare const Scroll: import("react").ForwardRefExoticComponent<ScrollProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -5,15 +5,9 @@ import Scrollbar from "smooth-scrollbar";
|
|
|
5
5
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
6
6
|
export { default as Scrollbar } from "smooth-scrollbar";
|
|
7
7
|
export * from "smooth-scrollbar/interfaces";
|
|
8
|
-
/**
|
|
9
|
-
* 滚动条组件
|
|
10
|
-
* @description 注意 children 不是直接渲染在组件上的,而是渲染在内部的容器上
|
|
11
|
-
*/
|
|
12
8
|
export const Scroll = /*#__PURE__*/forwardRef((props, ref) => {
|
|
13
9
|
const {
|
|
14
10
|
children,
|
|
15
|
-
containerClassName,
|
|
16
|
-
containerStyle,
|
|
17
11
|
options,
|
|
18
12
|
className,
|
|
19
13
|
style,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["css","clsx","forwardRef","useEffect","useImperativeHandle","useRef","Scrollbar","jsx","_jsx","default","Scroll","props","ref","children","
|
|
1
|
+
{"version":3,"names":["css","clsx","forwardRef","useEffect","useImperativeHandle","useRef","Scrollbar","jsx","_jsx","default","Scroll","props","ref","children","options","className","style","scrollbar","onScrollbar","rest","thumbWidth","scrollbarOptions","ele","bar","current","init","destroy","addListener","removeListener","undefined"],"sources":["../../../src/components/Scroll.tsx"],"sourcesContent":["import { css } from \"@emotion/css\"\r\nimport { clsx } from \"deepsea-tools\"\r\nimport { CSSProperties, ForwardedRef, forwardRef, HTMLAttributes, useEffect, useImperativeHandle, useRef } from \"react\"\r\nimport Scrollbar from \"smooth-scrollbar\"\r\nimport type { ScrollbarOptions, ScrollListener } from \"smooth-scrollbar/interfaces\"\r\nexport { default as Scrollbar } from \"smooth-scrollbar\"\r\nexport * from \"smooth-scrollbar/interfaces\"\r\n\r\nexport interface ScrollOptions extends Partial<ScrollbarOptions> {\r\n /** 滑块宽度 */\r\n thumbWidth?: number\r\n}\r\n\r\nexport interface ScrollProps extends HTMLAttributes<HTMLDivElement> {\r\n /** 滚动的配置 */\r\n options?: ScrollOptions\r\n /** 滚动条实例 */\r\n scrollbar?: ForwardedRef<Scrollbar>\r\n /** 滚动条滚动事件 */\r\n onScrollbar?: ScrollListener\r\n}\r\n\r\nexport const Scroll = forwardRef<HTMLDivElement, ScrollProps>((props, ref) => {\r\n const { children, options, className, style, scrollbar, onScrollbar, ...rest } = props\r\n const { thumbWidth, ...scrollbarOptions } = options || {}\r\n const ele = useRef<HTMLDivElement>(null)\r\n const bar = useRef<Scrollbar | null>(null)\r\n\r\n useImperativeHandle(ref, () => ele.current!, [])\r\n\r\n useEffect(() => {\r\n bar.current = Scrollbar.init(ele.current!, scrollbarOptions)\r\n return () => bar.current?.destroy()\r\n }, [])\r\n\r\n useEffect(() => {\r\n if (!scrollbar) return\r\n if (typeof scrollbar === \"function\") {\r\n scrollbar(bar.current)\r\n return () => scrollbar(null)\r\n }\r\n scrollbar.current = bar.current\r\n return () => (scrollbar.current = null)\r\n }, [scrollbar])\r\n\r\n useEffect(() => {\r\n if (!onScrollbar) return\r\n bar.current?.addListener(onScrollbar)\r\n return () => bar.current?.removeListener(onScrollbar)\r\n }, [onScrollbar])\r\n\r\n return (\r\n <div\r\n ref={ele}\r\n className={clsx(\r\n typeof thumbWidth === \"number\" &&\r\n css`\r\n .scrollbar-track.scrollbar-track-x {\r\n height: var(--thumb-width);\r\n }\r\n\r\n .scrollbar-thumb.scrollbar-thumb-x {\r\n height: var(--thumb-width);\r\n }\r\n\r\n .scrollbar-track.scrollbar-track-y {\r\n width: var(--thumb-width);\r\n }\r\n\r\n .scrollbar-thumb.scrollbar-thumb-y {\r\n width: var(--thumb-width);\r\n }\r\n `,\r\n className\r\n )}\r\n style={\r\n {\r\n \"--thumb-width\": typeof thumbWidth === \"number\" ? `${thumbWidth}px` : undefined,\r\n ...style\r\n } as CSSProperties\r\n }\r\n {...rest}>\r\n {children}\r\n </div>\r\n )\r\n})\r\n"],"mappings":"AAAA,SAASA,GAAG,QAAQ,cAAc;AAClC,SAASC,IAAI,QAAQ,eAAe;AACpC,SAAsCC,UAAU,EAAkBC,SAAS,EAAEC,mBAAmB,EAAEC,MAAM,QAAQ,OAAO;AACvH,OAAOC,SAAS,MAAM,kBAAkB;AAAA,SAAAC,GAAA,IAAAC,IAAA;AAExC,SAASC,OAAO,IAAIH,SAAS,QAAQ,kBAAkB;AACvD,cAAc,6BAA6B;AAgB3C,OAAO,MAAMI,MAAM,gBAAGR,UAAU,CAA8B,CAACS,KAAK,EAAEC,GAAG,KAAK;EAC1E,MAAM;IAAEC,QAAQ;IAAEC,OAAO;IAAEC,SAAS;IAAEC,KAAK;IAAEC,SAAS;IAAEC,WAAW;IAAE,GAAGC;EAAK,CAAC,GAAGR,KAAK;EACtF,MAAM;IAAES,UAAU;IAAE,GAAGC;EAAiB,CAAC,GAAGP,OAAO,IAAI,CAAC,CAAC;EACzD,MAAMQ,GAAG,GAAGjB,MAAM,CAAiB,IAAI,CAAC;EACxC,MAAMkB,GAAG,GAAGlB,MAAM,CAAmB,IAAI,CAAC;EAE1CD,mBAAmB,CAACQ,GAAG,EAAE,MAAMU,GAAG,CAACE,OAAQ,EAAE,EAAE,CAAC;EAEhDrB,SAAS,CAAC,MAAM;IACZoB,GAAG,CAACC,OAAO,GAAGlB,SAAS,CAACmB,IAAI,CAACH,GAAG,CAACE,OAAO,EAAGH,gBAAgB,CAAC;IAC5D,OAAO,MAAME,GAAG,CAACC,OAAO,EAAEE,OAAO,CAAC,CAAC;EACvC,CAAC,EAAE,EAAE,CAAC;EAENvB,SAAS,CAAC,MAAM;IACZ,IAAI,CAACc,SAAS,EAAE;IAChB,IAAI,OAAOA,SAAS,KAAK,UAAU,EAAE;MACjCA,SAAS,CAACM,GAAG,CAACC,OAAO,CAAC;MACtB,OAAO,MAAMP,SAAS,CAAC,IAAI,CAAC;IAChC;IACAA,SAAS,CAACO,OAAO,GAAGD,GAAG,CAACC,OAAO;IAC/B,OAAO,MAAOP,SAAS,CAACO,OAAO,GAAG,IAAK;EAC3C,CAAC,EAAE,CAACP,SAAS,CAAC,CAAC;EAEfd,SAAS,CAAC,MAAM;IACZ,IAAI,CAACe,WAAW,EAAE;IAClBK,GAAG,CAACC,OAAO,EAAEG,WAAW,CAACT,WAAW,CAAC;IACrC,OAAO,MAAMK,GAAG,CAACC,OAAO,EAAEI,cAAc,CAACV,WAAW,CAAC;EACzD,CAAC,EAAE,CAACA,WAAW,CAAC,CAAC;EAEjB,oBACIV,IAAA;IACII,GAAG,EAAEU,GAAI;IACTP,SAAS,EAAEd,IAAI,CACX,OAAOmB,UAAU,KAAK,QAAQ,IAC1BpB,GAAI;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB,EACLe,SACJ,CAAE;IACFC,KAAK,EACD;MACI,eAAe,EAAE,OAAOI,UAAU,KAAK,QAAQ,GAAI,GAAEA,UAAW,IAAG,GAAGS,SAAS;MAC/E,GAAGb;IACP,CACH;IAAA,GACGG,IAAI;IAAAN,QAAA,EACPA;EAAQ,CACR,CAAC;AAEd,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,113 +1,106 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { css } from "@emotion/css"
|
|
2
|
+
import { useSize } from "ahooks"
|
|
3
|
+
import { clsx, getArray } from "deepsea-tools"
|
|
4
|
+
import { CSSProperties, FC, MouseEvent as ReactMouseEvent, useEffect, useRef } from "react"
|
|
2
5
|
import Scrollbar from "smooth-scrollbar"
|
|
3
6
|
import { ScrollStatus } from "smooth-scrollbar/interfaces/scrollbar"
|
|
4
|
-
import { Scroll,
|
|
5
|
-
import { useLatest } from "ahooks"
|
|
7
|
+
import { Scroll, ScrollProps } from "./Scroll"
|
|
6
8
|
|
|
7
|
-
export interface SwiperScrollProps
|
|
9
|
+
export interface SwiperScrollProps extends Omit<ScrollProps, "scrollbar"> {
|
|
10
|
+
/** 轮播的数据 */
|
|
8
11
|
count: number
|
|
9
12
|
|
|
10
|
-
/**
|
|
13
|
+
/** 轮播元素的高度 */
|
|
11
14
|
itemHeight: number
|
|
12
15
|
|
|
13
|
-
/** 轮播的数据 */
|
|
14
|
-
data: T[]
|
|
15
|
-
|
|
16
|
-
/** key 生成器 */
|
|
17
|
-
keyExtractor?: (item: T, index: number, data: T[]) => string | number
|
|
18
|
-
|
|
19
|
-
/** 轮播元素的渲染函数 */
|
|
20
|
-
render: (item: T, index: number, data: T[]) => ReactNode
|
|
21
|
-
|
|
22
16
|
/** 轮播动画的时间 */
|
|
23
|
-
|
|
17
|
+
animation: number
|
|
24
18
|
|
|
25
19
|
/** 每个元素的停留时间 */
|
|
26
|
-
|
|
20
|
+
duration: number
|
|
27
21
|
|
|
28
22
|
/** 元素之间的间距 */
|
|
29
23
|
gap?: number
|
|
30
24
|
|
|
31
|
-
/**
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export function AutoScroll<T>(props: SwiperScrollProps<T>) {
|
|
36
|
-
const { style, itemHeight, count, data, render, animationTime, period, keyExtractor, options, onMouseEnter, onMouseLeave, gap = 0, ...rest } = props
|
|
25
|
+
/** 容器类名 */
|
|
26
|
+
containerClassName?: string
|
|
37
27
|
|
|
38
|
-
|
|
28
|
+
/** 容器样式 */
|
|
29
|
+
containerStyle?: CSSProperties
|
|
39
30
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const [paused, setPaused] = useState(false)
|
|
45
|
-
|
|
46
|
-
const pausedRef = useLatest(paused)
|
|
47
|
-
|
|
48
|
-
const periodRef = useLatest(period)
|
|
49
|
-
|
|
50
|
-
const height = (itemHeight + gap) * count - gap
|
|
31
|
+
/** 在鼠标移入时是否继续播放 */
|
|
32
|
+
playOnMouseEnter?: boolean
|
|
33
|
+
}
|
|
51
34
|
|
|
35
|
+
export const AutoScroll: FC<SwiperScrollProps> = props => {
|
|
36
|
+
const { count, itemHeight, animation, duration, onMouseEnter, onMouseLeave, gap = 0, containerClassName, containerStyle, children, playOnMouseEnter, ...rest } = props
|
|
52
37
|
const bar = useRef<Scrollbar | null>(null)
|
|
53
|
-
|
|
54
38
|
const timeout = useRef<NodeJS.Timeout | undefined>(undefined)
|
|
39
|
+
const ele = useRef<HTMLDivElement>(null)
|
|
40
|
+
const size = useSize(ele)
|
|
41
|
+
const pause = useRef(false)
|
|
55
42
|
|
|
56
43
|
useEffect(() => {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
44
|
+
if (playOnMouseEnter) pause.current = false
|
|
45
|
+
}, [playOnMouseEnter])
|
|
46
|
+
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
if (!size || count === 0) return
|
|
49
|
+
const { height } = size
|
|
50
|
+
const range = getArray(count, index => (itemHeight + gap) * (index + 1) - (index === count - 1 ? gap : 0))
|
|
51
|
+
const scrollHeight = range[range.length - 1]
|
|
52
|
+
if (height >= scrollHeight) return
|
|
53
|
+
function scroll(target: number) {
|
|
65
54
|
clearTimeout(timeout.current)
|
|
66
55
|
timeout.current = setTimeout(() => {
|
|
67
|
-
|
|
68
|
-
|
|
56
|
+
if (pause.current) return scroll(target)
|
|
57
|
+
bar.current?.scrollTo(0, target, animation)
|
|
58
|
+
}, duration)
|
|
59
|
+
}
|
|
60
|
+
scroll(range[0])
|
|
61
|
+
function listener(status: ScrollStatus) {
|
|
62
|
+
const { y } = status.offset
|
|
63
|
+
const scrollToBottom = Math.abs(y + height - scrollHeight) / itemHeight <= 0.05
|
|
64
|
+
const target = scrollToBottom ? 0 : range.find(item => item > y)!
|
|
65
|
+
scroll(target)
|
|
69
66
|
}
|
|
70
67
|
bar.current?.addListener(listener)
|
|
71
68
|
return () => {
|
|
69
|
+
clearTimeout(timeout.current)
|
|
72
70
|
bar.current?.removeListener(listener)
|
|
71
|
+
bar.current?.scrollTo(0, 0)
|
|
73
72
|
}
|
|
74
|
-
}, [])
|
|
75
|
-
|
|
76
|
-
useEffect(() => {
|
|
77
|
-
if (data.length <= count || paused === true) return
|
|
78
|
-
targetRef.current = (offset + 1) % (data.length + 1 - count)
|
|
79
|
-
timeout.current = setTimeout(() => {
|
|
80
|
-
setOffset(targetRef.current)
|
|
81
|
-
}, periodRef.current)
|
|
82
|
-
return () => clearTimeout(timeout.current)
|
|
83
|
-
}, [count, data.length, offset, paused])
|
|
84
|
-
|
|
85
|
-
useEffect(() => {
|
|
86
|
-
setOffset(0)
|
|
87
|
-
}, [itemHeight, count, data.length, animationTime, period, gap])
|
|
88
|
-
|
|
89
|
-
useEffect(() => {
|
|
90
|
-
if (pausedRef.current) return
|
|
91
|
-
bar.current?.scrollTo(0, offset * (itemHeight + gap), animationTime)
|
|
92
|
-
}, [offset])
|
|
73
|
+
}, [size, count, itemHeight, gap, duration, animation])
|
|
93
74
|
|
|
94
75
|
function onContainerMouseEnter(e: ReactMouseEvent<HTMLDivElement, MouseEvent>) {
|
|
95
|
-
|
|
76
|
+
if (playOnMouseEnter) return
|
|
77
|
+
pause.current = true
|
|
96
78
|
onMouseEnter?.(e)
|
|
97
79
|
}
|
|
98
80
|
|
|
99
81
|
function onContainerMouseLeave(e: ReactMouseEvent<HTMLDivElement, MouseEvent>) {
|
|
100
|
-
|
|
82
|
+
if (playOnMouseEnter) return
|
|
83
|
+
pause.current = false
|
|
101
84
|
onMouseLeave?.(e)
|
|
102
85
|
}
|
|
103
86
|
|
|
104
87
|
return (
|
|
105
|
-
<Scroll
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
88
|
+
<Scroll ref={ele} scrollbar={bar} onMouseEnter={onContainerMouseEnter} onMouseLeave={onContainerMouseLeave} {...rest}>
|
|
89
|
+
<div
|
|
90
|
+
className={clsx(
|
|
91
|
+
css`
|
|
92
|
+
display: flex;
|
|
93
|
+
flex-direction: column;
|
|
94
|
+
gap: var(--gap, 0);
|
|
95
|
+
& > * {
|
|
96
|
+
flex: none;
|
|
97
|
+
}
|
|
98
|
+
`,
|
|
99
|
+
containerClassName
|
|
100
|
+
)}
|
|
101
|
+
style={{ "--gap": `${gap}px`, ...containerStyle } as CSSProperties}>
|
|
102
|
+
{children}
|
|
103
|
+
</div>
|
|
111
104
|
</Scroll>
|
|
112
105
|
)
|
|
113
106
|
}
|
|
@@ -14,22 +14,14 @@ export interface ScrollOptions extends Partial<ScrollbarOptions> {
|
|
|
14
14
|
export interface ScrollProps extends HTMLAttributes<HTMLDivElement> {
|
|
15
15
|
/** 滚动的配置 */
|
|
16
16
|
options?: ScrollOptions
|
|
17
|
-
/** 容器宽度 */
|
|
18
|
-
containerClassName?: string
|
|
19
|
-
/** 容器样式 */
|
|
20
|
-
containerStyle?: CSSProperties
|
|
21
17
|
/** 滚动条实例 */
|
|
22
18
|
scrollbar?: ForwardedRef<Scrollbar>
|
|
23
19
|
/** 滚动条滚动事件 */
|
|
24
20
|
onScrollbar?: ScrollListener
|
|
25
21
|
}
|
|
26
22
|
|
|
27
|
-
/**
|
|
28
|
-
* 滚动条组件
|
|
29
|
-
* @description 注意 children 不是直接渲染在组件上的,而是渲染在内部的容器上
|
|
30
|
-
*/
|
|
31
23
|
export const Scroll = forwardRef<HTMLDivElement, ScrollProps>((props, ref) => {
|
|
32
|
-
const { children,
|
|
24
|
+
const { children, options, className, style, scrollbar, onScrollbar, ...rest } = props
|
|
33
25
|
const { thumbWidth, ...scrollbarOptions } = options || {}
|
|
34
26
|
const ele = useRef<HTMLDivElement>(null)
|
|
35
27
|
const bar = useRef<Scrollbar | null>(null)
|