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.
@@ -1,22 +1,21 @@
1
- import { HTMLAttributes, ReactNode } from "react";
2
- import { ScrollOptions } from "./Scroll";
3
- export interface SwiperScrollProps<T> extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
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
- animationTime: number;
9
+ animation: number;
15
10
  /** 每个元素的停留时间 */
16
- period: number;
11
+ duration: number;
17
12
  /** 元素之间的间距 */
18
13
  gap?: number;
19
- /** 滚动条选项 */
20
- options?: ScrollOptions;
14
+ /** 容器类名 */
15
+ containerClassName?: string;
16
+ /** 容器样式 */
17
+ containerStyle?: CSSProperties;
18
+ /** 在鼠标移入时是否继续播放 */
19
+ playOnMouseEnter?: boolean;
21
20
  }
22
- export declare function AutoScroll<T>(props: SwiperScrollProps<T>): import("react/jsx-runtime").JSX.Element;
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 import_ahooks = require("ahooks");
28
- function AutoScroll(props) {
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
- function listener(status) {
41
- const y = status.offset.y;
42
- const a = y / (itemHeight + gap);
43
- if (a % 1 <= 0.05) {
44
- targetRef.current = Math.floor(a);
45
- } else {
46
- targetRef.current = Math.ceil(a);
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
- setOffset(targetRef.current);
51
- }, periodRef.current);
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
- setPaused(true);
72
+ if (playOnMouseEnter)
73
+ return;
74
+ pause.current = true;
77
75
  onMouseEnter?.(e);
78
76
  }
79
77
  function onContainerMouseLeave(e) {
80
- setPaused(false);
78
+ if (playOnMouseEnter)
79
+ return;
80
+ pause.current = false;
81
81
  onMouseLeave?.(e);
82
82
  }
83
- return /* @__PURE__ */ React.createElement(import_Scroll.Scroll, { scrollbar: bar, options, style: { height, ...style }, onMouseEnter: onContainerMouseEnter, onMouseLeave: onContainerMouseLeave, ...rest }, data.map((item, index, arr) => /* @__PURE__ */ React.createElement("div", { key: keyExtractor?.(item, index, arr) ?? index, style: { height: itemHeight, marginTop: index === 0 ? 0 : `${gap}px` } }, render(item, index, arr))));
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 { HTMLAttributes, ReactNode, useEffect, useRef, useState, MouseEvent as ReactMouseEvent } from \"react\"\r\nimport Scrollbar from \"smooth-scrollbar\"\r\nimport { ScrollStatus } from \"smooth-scrollbar/interfaces/scrollbar\"\r\nimport { Scroll, ScrollOptions } from \"./Scroll\"\r\nimport { useLatest } from \"ahooks\"\r\n\r\nexport interface SwiperScrollProps<T> extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\r\n count: number\r\n\r\n /** 轮播元素的长度 */\r\n itemHeight: number\r\n\r\n /** 轮播的数据 */\r\n data: T[]\r\n\r\n /** key 生成器 */\r\n keyExtractor?: (item: T, index: number, data: T[]) => string | number\r\n\r\n /** 轮播元素的渲染函数 */\r\n render: (item: T, index: number, data: T[]) => ReactNode\r\n\r\n /** 轮播动画的时间 */\r\n animationTime: number\r\n\r\n /** 每个元素的停留时间 */\r\n period: number\r\n\r\n /** 元素之间的间距 */\r\n gap?: number\r\n\r\n /** 滚动条选项 */\r\n options?: ScrollOptions\r\n}\r\n\r\nexport function AutoScroll<T>(props: SwiperScrollProps<T>) {\r\n const { style, itemHeight, count, data, render, animationTime, period, keyExtractor, options, onMouseEnter, onMouseLeave, gap = 0, ...rest } = props\r\n\r\n const [offset, setOffset] = useState(0)\r\n\r\n const offsetRef = useLatest(offset)\r\n\r\n const targetRef = useRef(0)\r\n\r\n const [paused, setPaused] = useState(false)\r\n\r\n const pausedRef = useLatest(paused)\r\n\r\n const periodRef = useLatest(period)\r\n\r\n const height = (itemHeight + gap) * count - gap\r\n\r\n const bar = useRef<Scrollbar | null>(null)\r\n\r\n const timeout = useRef<NodeJS.Timeout | undefined>(undefined)\r\n\r\n useEffect(() => {\r\n function listener(status: ScrollStatus) {\r\n const y = status.offset.y\r\n const a = y / (itemHeight + gap)\r\n if (a % 1 <= 0.05) {\r\n targetRef.current = Math.floor(a)\r\n } else {\r\n targetRef.current = Math.ceil(a)\r\n }\r\n clearTimeout(timeout.current)\r\n timeout.current = setTimeout(() => {\r\n setOffset(targetRef.current)\r\n }, periodRef.current)\r\n }\r\n bar.current?.addListener(listener)\r\n return () => {\r\n bar.current?.removeListener(listener)\r\n }\r\n }, [])\r\n\r\n useEffect(() => {\r\n if (data.length <= count || paused === true) return\r\n targetRef.current = (offset + 1) % (data.length + 1 - count)\r\n timeout.current = setTimeout(() => {\r\n setOffset(targetRef.current)\r\n }, periodRef.current)\r\n return () => clearTimeout(timeout.current)\r\n }, [count, data.length, offset, paused])\r\n\r\n useEffect(() => {\r\n setOffset(0)\r\n }, [itemHeight, count, data.length, animationTime, period, gap])\r\n\r\n useEffect(() => {\r\n if (pausedRef.current) return\r\n bar.current?.scrollTo(0, offset * (itemHeight + gap), animationTime)\r\n }, [offset])\r\n\r\n function onContainerMouseEnter(e: ReactMouseEvent<HTMLDivElement, MouseEvent>) {\r\n setPaused(true)\r\n onMouseEnter?.(e)\r\n }\r\n\r\n function onContainerMouseLeave(e: ReactMouseEvent<HTMLDivElement, MouseEvent>) {\r\n setPaused(false)\r\n onMouseLeave?.(e)\r\n }\r\n\r\n return (\r\n <Scroll scrollbar={bar} options={options} style={{ height, ...style }} onMouseEnter={onContainerMouseEnter} onMouseLeave={onContainerMouseLeave} {...rest}>\r\n {data.map((item, index, arr) => (\r\n <div key={keyExtractor?.(item, index, arr) ?? index} style={{ height: itemHeight, marginTop: index === 0 ? 0 : `${gap}px` }}>\r\n {render(item, index, arr)}\r\n </div>\r\n ))}\r\n </Scroll>\r\n )\r\n}\r\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAsG;AAGtG,oBAAsC;AACtC,oBAA0B;AA8BnB,SAAS,WAAc,OAA6B;AACvD,QAAM,EAAE,OAAO,YAAY,OAAO,MAAM,QAAQ,eAAe,QAAQ,cAAc,SAAS,cAAc,cAAc,MAAM,GAAG,GAAG,KAAK,IAAI;AAE/I,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAAS,CAAC;AAEtC,QAAM,gBAAY,yBAAU,MAAM;AAElC,QAAM,gBAAY,qBAAO,CAAC;AAE1B,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAAS,KAAK;AAE1C,QAAM,gBAAY,yBAAU,MAAM;AAElC,QAAM,gBAAY,yBAAU,MAAM;AAElC,QAAM,UAAU,aAAa,OAAO,QAAQ;AAE5C,QAAM,UAAM,qBAAyB,IAAI;AAEzC,QAAM,cAAU,qBAAmC,MAAS;AAE5D,8BAAU,MAAM;AACZ,aAAS,SAAS,QAAsB;AACpC,YAAM,IAAI,OAAO,OAAO;AACxB,YAAM,IAAI,KAAK,aAAa;AAC5B,UAAI,IAAI,KAAK,MAAM;AACf,kBAAU,UAAU,KAAK,MAAM,CAAC;AAAA,MACpC,OAAO;AACH,kBAAU,UAAU,KAAK,KAAK,CAAC;AAAA,MACnC;AACA,mBAAa,QAAQ,OAAO;AAC5B,cAAQ,UAAU,WAAW,MAAM;AAC/B,kBAAU,UAAU,OAAO;AAAA,MAC/B,GAAG,UAAU,OAAO;AAAA,IACxB;AACA,QAAI,SAAS,YAAY,QAAQ;AACjC,WAAO,MAAM;AACT,UAAI,SAAS,eAAe,QAAQ;AAAA,IACxC;AAAA,EACJ,GAAG,CAAC,CAAC;AAEL,8BAAU,MAAM;AACZ,QAAI,KAAK,UAAU,SAAS,WAAW;AAAM;AAC7C,cAAU,WAAW,SAAS,MAAM,KAAK,SAAS,IAAI;AACtD,YAAQ,UAAU,WAAW,MAAM;AAC/B,gBAAU,UAAU,OAAO;AAAA,IAC/B,GAAG,UAAU,OAAO;AACpB,WAAO,MAAM,aAAa,QAAQ,OAAO;AAAA,EAC7C,GAAG,CAAC,OAAO,KAAK,QAAQ,QAAQ,MAAM,CAAC;AAEvC,8BAAU,MAAM;AACZ,cAAU,CAAC;AAAA,EACf,GAAG,CAAC,YAAY,OAAO,KAAK,QAAQ,eAAe,QAAQ,GAAG,CAAC;AAE/D,8BAAU,MAAM;AACZ,QAAI,UAAU;AAAS;AACvB,QAAI,SAAS,SAAS,GAAG,UAAU,aAAa,MAAM,aAAa;AAAA,EACvE,GAAG,CAAC,MAAM,CAAC;AAEX,WAAS,sBAAsB,GAAgD;AAC3E,cAAU,IAAI;AACd,mBAAe,CAAC;AAAA,EACpB;AAEA,WAAS,sBAAsB,GAAgD;AAC3E,cAAU,KAAK;AACf,mBAAe,CAAC;AAAA,EACpB;AAEA,SACI,oCAAC,wBAAO,WAAW,KAAK,SAAkB,OAAO,EAAE,QAAQ,GAAG,MAAM,GAAG,cAAc,uBAAuB,cAAc,uBAAwB,GAAG,QAChJ,KAAK,IAAI,CAAC,MAAM,OAAO,QACpB,oCAAC,SAAI,KAAK,eAAe,MAAM,OAAO,GAAG,KAAK,OAAO,OAAO,EAAE,QAAQ,YAAY,WAAW,UAAU,IAAI,IAAI,GAAG,QAAQ,KACrH,OAAO,MAAM,OAAO,GAAG,CAC5B,CACH,CACL;AAER;",
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 { CSSProperties, ForwardedRef, HTMLAttributes } from "react";
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, containerClassName, containerStyle, options, className, style, scrollbar, onScrollbar, ...rest } = props;
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 /** 容器宽度 */\r\n containerClassName?: string\r\n /** 容器样式 */\r\n containerStyle?: CSSProperties\r\n /** 滚动条实例 */\r\n scrollbar?: ForwardedRef<Scrollbar>\r\n /** 滚动条滚动事件 */\r\n onScrollbar?: ScrollListener\r\n}\r\n\r\n/**\r\n * 滚动条组件\r\n * @description 注意 children 不是直接渲染在组件上的,而是渲染在内部的容器上\r\n */\r\nexport const Scroll = forwardRef<HTMLDivElement, ScrollProps>((props, ref) => {\r\n const { children, containerClassName, containerStyle, 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;AA8BO,IAAM,aAAS,yBAAwC,CAAC,OAAO,QAAQ;AAC1E,QAAM,EAAE,UAAU,oBAAoB,gBAAgB,SAAS,WAAW,OAAO,WAAW,aAAa,GAAG,KAAK,IAAI;AACrH,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;",
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 { HTMLAttributes, ReactNode } from "react";
2
- import { ScrollOptions } from "./Scroll";
3
- export interface SwiperScrollProps<T> extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
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
- animationTime: number;
9
+ animation: number;
15
10
  /** 每个元素的停留时间 */
16
- period: number;
11
+ duration: number;
17
12
  /** 元素之间的间距 */
18
13
  gap?: number;
19
- /** 滚动条选项 */
20
- options?: ScrollOptions;
14
+ /** 容器类名 */
15
+ containerClassName?: string;
16
+ /** 容器样式 */
17
+ containerStyle?: CSSProperties;
18
+ /** 在鼠标移入时是否继续播放 */
19
+ playOnMouseEnter?: boolean;
21
20
  }
22
- export declare function AutoScroll<T>(props: SwiperScrollProps<T>): import("react/jsx-runtime").JSX.Element;
21
+ export declare const AutoScroll: FC<SwiperScrollProps>;
@@ -1,91 +1,94 @@
1
- import { useEffect, useRef, useState } from "react";
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 function AutoScroll(props) {
7
+ export const AutoScroll = props => {
6
8
  const {
7
- style,
8
- itemHeight,
9
9
  count,
10
- data,
11
- render,
12
- animationTime,
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
- function listener(status) {
32
- const y = status.offset.y;
33
- const a = y / (itemHeight + gap);
34
- if (a % 1 <= 0.05) {
35
- targetRef.current = Math.floor(a);
36
- } else {
37
- targetRef.current = Math.ceil(a);
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
- setOffset(targetRef.current);
42
- }, periodRef.current);
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
- setPaused(true);
62
+ if (playOnMouseEnter) return;
63
+ pause.current = true;
66
64
  onMouseEnter?.(e);
67
65
  }
68
66
  function onContainerMouseLeave(e) {
69
- setPaused(false);
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: data.map((item, index, arr) => /*#__PURE__*/_jsx("div", {
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
- height: itemHeight,
85
- marginTop: index === 0 ? 0 : `${gap}px`
87
+ "--gap": `${gap}px`,
88
+ ...containerStyle
86
89
  },
87
- children: render(item, index, arr)
88
- }, keyExtractor?.(item, index, arr) ?? index))
90
+ children: children
91
+ })
89
92
  });
90
- }
93
+ };
91
94
  //# sourceMappingURL=AutoScroll.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["useEffect","useRef","useState","Scroll","useLatest","jsx","_jsx","AutoScroll","props","style","itemHeight","count","data","render","animationTime","period","keyExtractor","options","onMouseEnter","onMouseLeave","gap","rest","offset","setOffset","offsetRef","targetRef","paused","setPaused","pausedRef","periodRef","height","bar","timeout","undefined","listener","status","y","a","current","Math","floor","ceil","clearTimeout","setTimeout","addListener","removeListener","length","scrollTo","onContainerMouseEnter","e","onContainerMouseLeave","scrollbar","children","map","item","index","arr","marginTop"],"sources":["../../../src/components/AutoScroll.tsx"],"sourcesContent":["import { HTMLAttributes, ReactNode, useEffect, useRef, useState, MouseEvent as ReactMouseEvent } from \"react\"\r\nimport Scrollbar from \"smooth-scrollbar\"\r\nimport { ScrollStatus } from \"smooth-scrollbar/interfaces/scrollbar\"\r\nimport { Scroll, ScrollOptions } from \"./Scroll\"\r\nimport { useLatest } from \"ahooks\"\r\n\r\nexport interface SwiperScrollProps<T> extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\r\n count: number\r\n\r\n /** 轮播元素的长度 */\r\n itemHeight: number\r\n\r\n /** 轮播的数据 */\r\n data: T[]\r\n\r\n /** key 生成器 */\r\n keyExtractor?: (item: T, index: number, data: T[]) => string | number\r\n\r\n /** 轮播元素的渲染函数 */\r\n render: (item: T, index: number, data: T[]) => ReactNode\r\n\r\n /** 轮播动画的时间 */\r\n animationTime: number\r\n\r\n /** 每个元素的停留时间 */\r\n period: number\r\n\r\n /** 元素之间的间距 */\r\n gap?: number\r\n\r\n /** 滚动条选项 */\r\n options?: ScrollOptions\r\n}\r\n\r\nexport function AutoScroll<T>(props: SwiperScrollProps<T>) {\r\n const { style, itemHeight, count, data, render, animationTime, period, keyExtractor, options, onMouseEnter, onMouseLeave, gap = 0, ...rest } = props\r\n\r\n const [offset, setOffset] = useState(0)\r\n\r\n const offsetRef = useLatest(offset)\r\n\r\n const targetRef = useRef(0)\r\n\r\n const [paused, setPaused] = useState(false)\r\n\r\n const pausedRef = useLatest(paused)\r\n\r\n const periodRef = useLatest(period)\r\n\r\n const height = (itemHeight + gap) * count - gap\r\n\r\n const bar = useRef<Scrollbar | null>(null)\r\n\r\n const timeout = useRef<NodeJS.Timeout | undefined>(undefined)\r\n\r\n useEffect(() => {\r\n function listener(status: ScrollStatus) {\r\n const y = status.offset.y\r\n const a = y / (itemHeight + gap)\r\n if (a % 1 <= 0.05) {\r\n targetRef.current = Math.floor(a)\r\n } else {\r\n targetRef.current = Math.ceil(a)\r\n }\r\n clearTimeout(timeout.current)\r\n timeout.current = setTimeout(() => {\r\n setOffset(targetRef.current)\r\n }, periodRef.current)\r\n }\r\n bar.current?.addListener(listener)\r\n return () => {\r\n bar.current?.removeListener(listener)\r\n }\r\n }, [])\r\n\r\n useEffect(() => {\r\n if (data.length <= count || paused === true) return\r\n targetRef.current = (offset + 1) % (data.length + 1 - count)\r\n timeout.current = setTimeout(() => {\r\n setOffset(targetRef.current)\r\n }, periodRef.current)\r\n return () => clearTimeout(timeout.current)\r\n }, [count, data.length, offset, paused])\r\n\r\n useEffect(() => {\r\n setOffset(0)\r\n }, [itemHeight, count, data.length, animationTime, period, gap])\r\n\r\n useEffect(() => {\r\n if (pausedRef.current) return\r\n bar.current?.scrollTo(0, offset * (itemHeight + gap), animationTime)\r\n }, [offset])\r\n\r\n function onContainerMouseEnter(e: ReactMouseEvent<HTMLDivElement, MouseEvent>) {\r\n setPaused(true)\r\n onMouseEnter?.(e)\r\n }\r\n\r\n function onContainerMouseLeave(e: ReactMouseEvent<HTMLDivElement, MouseEvent>) {\r\n setPaused(false)\r\n onMouseLeave?.(e)\r\n }\r\n\r\n return (\r\n <Scroll scrollbar={bar} options={options} style={{ height, ...style }} onMouseEnter={onContainerMouseEnter} onMouseLeave={onContainerMouseLeave} {...rest}>\r\n {data.map((item, index, arr) => (\r\n <div key={keyExtractor?.(item, index, arr) ?? index} style={{ height: itemHeight, marginTop: index === 0 ? 0 : `${gap}px` }}>\r\n {render(item, index, arr)}\r\n </div>\r\n ))}\r\n </Scroll>\r\n )\r\n}\r\n"],"mappings":"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"}
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 { CSSProperties, ForwardedRef, HTMLAttributes } from "react";
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","containerClassName","containerStyle","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 containerClassName?: string\r\n /** 容器样式 */\r\n containerStyle?: CSSProperties\r\n /** 滚动条实例 */\r\n scrollbar?: ForwardedRef<Scrollbar>\r\n /** 滚动条滚动事件 */\r\n onScrollbar?: ScrollListener\r\n}\r\n\r\n/**\r\n * 滚动条组件\r\n * @description 注意 children 不是直接渲染在组件上的,而是渲染在内部的容器上\r\n */\r\nexport const Scroll = forwardRef<HTMLDivElement, ScrollProps>((props, ref) => {\r\n const { children, containerClassName, containerStyle, 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;AAoB3C;AACA;AACA;AACA;AACA,OAAO,MAAMI,MAAM,gBAAGR,UAAU,CAA8B,CAACS,KAAK,EAAEC,GAAG,KAAK;EAC1E,MAAM;IAAEC,QAAQ;IAAEC,kBAAkB;IAAEC,cAAc;IAAEC,OAAO;IAAEC,SAAS;IAAEC,KAAK;IAAEC,SAAS;IAAEC,WAAW;IAAE,GAAGC;EAAK,CAAC,GAAGV,KAAK;EAC1H,MAAM;IAAEW,UAAU;IAAE,GAAGC;EAAiB,CAAC,GAAGP,OAAO,IAAI,CAAC,CAAC;EACzD,MAAMQ,GAAG,GAAGnB,MAAM,CAAiB,IAAI,CAAC;EACxC,MAAMoB,GAAG,GAAGpB,MAAM,CAAmB,IAAI,CAAC;EAE1CD,mBAAmB,CAACQ,GAAG,EAAE,MAAMY,GAAG,CAACE,OAAQ,EAAE,EAAE,CAAC;EAEhDvB,SAAS,CAAC,MAAM;IACZsB,GAAG,CAACC,OAAO,GAAGpB,SAAS,CAACqB,IAAI,CAACH,GAAG,CAACE,OAAO,EAAGH,gBAAgB,CAAC;IAC5D,OAAO,MAAME,GAAG,CAACC,OAAO,EAAEE,OAAO,CAAC,CAAC;EACvC,CAAC,EAAE,EAAE,CAAC;EAENzB,SAAS,CAAC,MAAM;IACZ,IAAI,CAACgB,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;EAEfhB,SAAS,CAAC,MAAM;IACZ,IAAI,CAACiB,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,oBACIZ,IAAA;IACII,GAAG,EAAEY,GAAI;IACTP,SAAS,EAAEhB,IAAI,CACX,OAAOqB,UAAU,KAAK,QAAQ,IAC1BtB,GAAI;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB,EACLiB,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;IAAAR,QAAA,EACPA;EAAQ,CACR,CAAC;AAEd,CAAC,CAAC"}
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,6 +1,6 @@
1
1
  {
2
2
  "name": "deepsea-components",
3
- "version": "2.8.0-beta.20240516105156",
3
+ "version": "2.8.0",
4
4
  "description": "格数科技自用组件库",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -1,113 +1,106 @@
1
- import { HTMLAttributes, ReactNode, useEffect, useRef, useState, MouseEvent as ReactMouseEvent } from "react"
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, ScrollOptions } from "./Scroll"
5
- import { useLatest } from "ahooks"
7
+ import { Scroll, ScrollProps } from "./Scroll"
6
8
 
7
- export interface SwiperScrollProps<T> extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
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
- animationTime: number
17
+ animation: number
24
18
 
25
19
  /** 每个元素的停留时间 */
26
- period: number
20
+ duration: number
27
21
 
28
22
  /** 元素之间的间距 */
29
23
  gap?: number
30
24
 
31
- /** 滚动条选项 */
32
- options?: ScrollOptions
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
- const [offset, setOffset] = useState(0)
28
+ /** 容器样式 */
29
+ containerStyle?: CSSProperties
39
30
 
40
- const offsetRef = useLatest(offset)
41
-
42
- const targetRef = useRef(0)
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
- function listener(status: ScrollStatus) {
58
- const y = status.offset.y
59
- const a = y / (itemHeight + gap)
60
- if (a % 1 <= 0.05) {
61
- targetRef.current = Math.floor(a)
62
- } else {
63
- targetRef.current = Math.ceil(a)
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
- setOffset(targetRef.current)
68
- }, periodRef.current)
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
- setPaused(true)
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
- setPaused(false)
82
+ if (playOnMouseEnter) return
83
+ pause.current = false
101
84
  onMouseLeave?.(e)
102
85
  }
103
86
 
104
87
  return (
105
- <Scroll scrollbar={bar} options={options} style={{ height, ...style }} onMouseEnter={onContainerMouseEnter} onMouseLeave={onContainerMouseLeave} {...rest}>
106
- {data.map((item, index, arr) => (
107
- <div key={keyExtractor?.(item, index, arr) ?? index} style={{ height: itemHeight, marginTop: index === 0 ? 0 : `${gap}px` }}>
108
- {render(item, index, arr)}
109
- </div>
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, containerClassName, containerStyle, options, className, style, scrollbar, onScrollbar, ...rest } = props
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)