deepsea-components 5.6.0 → 5.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/README.md +23 -23
  2. package/dist/cjs/components/AutoFit.js +3 -1
  3. package/dist/cjs/components/AutoFit.js.map +2 -2
  4. package/dist/cjs/components/AutoScroll.js +16 -1
  5. package/dist/cjs/components/AutoScroll.js.map +2 -2
  6. package/dist/cjs/components/AutoSizeTextarea.js.map +1 -1
  7. package/dist/cjs/components/CircleText.js +31 -2
  8. package/dist/cjs/components/CircleText.js.map +2 -2
  9. package/dist/cjs/components/CopyButton.d.ts +9 -0
  10. package/dist/cjs/components/CopyButton.js +59 -0
  11. package/dist/cjs/components/CopyButton.js.map +7 -0
  12. package/dist/cjs/components/Echart.js.map +2 -2
  13. package/dist/cjs/components/Flow.js +56 -3
  14. package/dist/cjs/components/Flow.js.map +2 -2
  15. package/dist/cjs/components/FormLabel.js.map +1 -1
  16. package/dist/cjs/components/HlsPlayer.js.map +1 -1
  17. package/dist/cjs/components/InfiniteScroll.js +15 -1
  18. package/dist/cjs/components/InfiniteScroll.js.map +2 -2
  19. package/dist/cjs/components/InputFile.js.map +1 -1
  20. package/dist/cjs/components/LoopSwiper.js +23 -2
  21. package/dist/cjs/components/LoopSwiper.js.map +2 -2
  22. package/dist/cjs/components/Ring.js +13 -1
  23. package/dist/cjs/components/Ring.js.map +2 -2
  24. package/dist/cjs/components/Scroll.js.map +2 -2
  25. package/dist/cjs/components/SectionRing.js +3 -1
  26. package/dist/cjs/components/SectionRing.js.map +2 -2
  27. package/dist/cjs/components/Skeleton.js.map +2 -2
  28. package/dist/cjs/components/Title.js.map +2 -2
  29. package/dist/cjs/components/TransitionBox.js +9 -1
  30. package/dist/cjs/components/TransitionBox.js.map +2 -2
  31. package/dist/cjs/components/TransitionNum.js.map +1 -1
  32. package/dist/cjs/components/Trapezium.js.map +1 -1
  33. package/dist/cjs/index.d.ts +1 -0
  34. package/dist/cjs/index.js +2 -0
  35. package/dist/cjs/index.js.map +2 -2
  36. package/dist/cjs/utils/getReactVersion.js.map +1 -1
  37. package/dist/cjs/utils/index.js.map +1 -1
  38. package/dist/esm/components/AutoFit.js +9 -9
  39. package/dist/esm/components/AutoFit.js.map +1 -1
  40. package/dist/esm/components/AutoScroll.js.map +1 -1
  41. package/dist/esm/components/AutoSizeTextarea.js +2 -2
  42. package/dist/esm/components/AutoSizeTextarea.js.map +1 -1
  43. package/dist/esm/components/CircleText.js.map +1 -1
  44. package/dist/esm/components/CopyButton.d.ts +9 -0
  45. package/dist/esm/components/CopyButton.js +29 -0
  46. package/dist/esm/components/CopyButton.js.map +1 -0
  47. package/dist/esm/components/Echart.js.map +1 -1
  48. package/dist/esm/components/Flow.js.map +1 -1
  49. package/dist/esm/components/FormLabel.js +2 -2
  50. package/dist/esm/components/FormLabel.js.map +1 -1
  51. package/dist/esm/components/HlsPlayer.js.map +1 -1
  52. package/dist/esm/components/InfiniteScroll.js +4 -4
  53. package/dist/esm/components/InfiniteScroll.js.map +1 -1
  54. package/dist/esm/components/InputFile.js.map +1 -1
  55. package/dist/esm/components/LoopSwiper.js.map +1 -1
  56. package/dist/esm/components/Ring.js.map +1 -1
  57. package/dist/esm/components/Scroll.js.map +1 -1
  58. package/dist/esm/components/SectionRing.js.map +1 -1
  59. package/dist/esm/components/Skeleton.js.map +1 -1
  60. package/dist/esm/components/Title.js.map +1 -1
  61. package/dist/esm/components/TransitionBox.js.map +1 -1
  62. package/dist/esm/components/TransitionNum.js.map +1 -1
  63. package/dist/esm/components/Trapezium.js.map +1 -1
  64. package/dist/esm/index.d.ts +1 -0
  65. package/dist/esm/index.js +1 -0
  66. package/dist/esm/index.js.map +1 -1
  67. package/dist/esm/utils/getReactVersion.js.map +1 -1
  68. package/dist/esm/utils/index.js.map +1 -1
  69. package/package.json +4 -2
  70. package/src/components/AutoFit.tsx +103 -101
  71. package/src/components/AutoScroll.tsx +148 -132
  72. package/src/components/AutoSizeTextarea.tsx +49 -49
  73. package/src/components/CircleText.tsx +81 -56
  74. package/src/components/CopyButton.tsx +29 -0
  75. package/src/components/Echart.tsx +67 -44
  76. package/src/components/Flow.tsx +270 -214
  77. package/src/components/FormLabel.tsx +38 -38
  78. package/src/components/HlsPlayer.tsx +34 -34
  79. package/src/components/InfiniteScroll.tsx +161 -135
  80. package/src/components/InputFile.tsx +234 -234
  81. package/src/components/LoopSwiper.tsx +125 -101
  82. package/src/components/Ring.tsx +30 -19
  83. package/src/components/Scroll.tsx +96 -95
  84. package/src/components/SectionRing.tsx +39 -36
  85. package/src/components/Skeleton.tsx +47 -46
  86. package/src/components/Title.tsx +23 -24
  87. package/src/components/TransitionBox.tsx +44 -36
  88. package/src/components/TransitionNum.tsx +54 -54
  89. package/src/components/Trapezium.tsx +59 -59
  90. package/src/index.ts +1 -0
  91. package/src/utils/getReactVersion.ts +7 -7
  92. package/src/utils/index.ts +33 -33
@@ -1,44 +1,67 @@
1
- import { BarSeriesOption, ComposeOption, DatasetComponentOption, ECharts, GridComponentOption, init, LineSeriesOption, PieSeriesOption, TitleComponentOption, TooltipComponentOption } from "echarts"
2
- import { ComponentProps, ForwardedRef, forwardRef, ForwardRefExoticComponent, RefAttributes, useEffect, useImperativeHandle, useLayoutEffect, useRef } from "react"
3
-
4
- export type PieOption = ComposeOption<PieSeriesOption | TitleComponentOption | DatasetComponentOption | GridComponentOption | TooltipComponentOption>
5
-
6
- export type BarOption = ComposeOption<BarSeriesOption | TitleComponentOption | DatasetComponentOption | GridComponentOption | TooltipComponentOption>
7
-
8
- export type LineOption = ComposeOption<LineSeriesOption | TitleComponentOption | DatasetComponentOption | GridComponentOption | TooltipComponentOption>
9
-
10
- export interface EchartProps<T extends any = any> extends Omit<ComponentProps<"div">, "children"> {
11
- width: number
12
- height: number
13
- option: T
14
- chart?: ForwardedRef<ECharts>
15
- }
16
-
17
- export type EchartComponent<T extends PieOption | BarOption | LineOption> = ForwardRefExoticComponent<Omit<EchartProps<T>, "ref"> & RefAttributes<HTMLDivElement>>
18
-
19
- const Echart = forwardRef<HTMLDivElement, EchartProps>((props, ref) => {
20
- const { width, height, option, chart, ...rest } = props
21
- const container = useRef<HTMLDivElement>(null)
22
- const chartRef = useRef<ECharts | null>(null)
23
-
24
- useLayoutEffect(() => {
25
- const ele = container.current!
26
- chartRef.current = init(ele, option, { width, height })
27
- return () => chartRef.current?.dispose()
28
- }, [])
29
-
30
- useImperativeHandle(ref, () => container.current!, [])
31
-
32
- useImperativeHandle(chart, () => chartRef.current!, [])
33
-
34
- useEffect(() => {
35
- chartRef.current?.setOption(option)
36
- chartRef.current?.resize({ width, height })
37
- })
38
-
39
- return <div ref={container} {...rest} />
40
- })
41
-
42
- export const Pie = Echart as EchartComponent<PieOption>
43
- export const Bar = Echart as EchartComponent<BarOption>
44
- export const Line = Echart as EchartComponent<LineOption>
1
+ import {
2
+ BarSeriesOption,
3
+ ComposeOption,
4
+ DatasetComponentOption,
5
+ ECharts,
6
+ GridComponentOption,
7
+ init,
8
+ LineSeriesOption,
9
+ PieSeriesOption,
10
+ TitleComponentOption,
11
+ TooltipComponentOption,
12
+ } from "echarts"
13
+ import {
14
+ ComponentProps,
15
+ ForwardedRef,
16
+ forwardRef,
17
+ ForwardRefExoticComponent,
18
+ RefAttributes,
19
+ useEffect,
20
+ useImperativeHandle,
21
+ useLayoutEffect,
22
+ useRef,
23
+ } from "react"
24
+
25
+ export type PieOption = ComposeOption<PieSeriesOption | TitleComponentOption | DatasetComponentOption | GridComponentOption | TooltipComponentOption>
26
+
27
+ export type BarOption = ComposeOption<BarSeriesOption | TitleComponentOption | DatasetComponentOption | GridComponentOption | TooltipComponentOption>
28
+
29
+ export type LineOption = ComposeOption<LineSeriesOption | TitleComponentOption | DatasetComponentOption | GridComponentOption | TooltipComponentOption>
30
+
31
+ export interface EchartProps<T extends any = any> extends Omit<ComponentProps<"div">, "children"> {
32
+ width: number
33
+ height: number
34
+ option: T
35
+ chart?: ForwardedRef<ECharts>
36
+ }
37
+
38
+ export type EchartComponent<T extends PieOption | BarOption | LineOption> = ForwardRefExoticComponent<
39
+ Omit<EchartProps<T>, "ref"> & RefAttributes<HTMLDivElement>
40
+ >
41
+
42
+ const Echart = forwardRef<HTMLDivElement, EchartProps>((props, ref) => {
43
+ const { width, height, option, chart, ...rest } = props
44
+ const container = useRef<HTMLDivElement>(null)
45
+ const chartRef = useRef<ECharts | null>(null)
46
+
47
+ useLayoutEffect(() => {
48
+ const ele = container.current!
49
+ chartRef.current = init(ele, option, { width, height })
50
+ return () => chartRef.current?.dispose()
51
+ }, [])
52
+
53
+ useImperativeHandle(ref, () => container.current!, [])
54
+
55
+ useImperativeHandle(chart, () => chartRef.current!, [])
56
+
57
+ useEffect(() => {
58
+ chartRef.current?.setOption(option)
59
+ chartRef.current?.resize({ width, height })
60
+ })
61
+
62
+ return <div ref={container} {...rest} />
63
+ })
64
+
65
+ export const Pie = Echart as EchartComponent<PieOption>
66
+ export const Bar = Echart as EchartComponent<BarOption>
67
+ export const Line = Echart as EchartComponent<LineOption>
@@ -1,214 +1,270 @@
1
- "use client"
2
-
3
- import { css } from "@emotion/css"
4
- import { useSize } from "ahooks"
5
- import { clsx } from "deepsea-tools"
6
- import { CSSProperties, HTMLAttributes, Key, ReactNode, RefObject, useEffect, useImperativeHandle, useRef, useState } from "react"
7
- import { px, transformCSSVariable } from "../utils"
8
-
9
- export interface FlowSizeData {
10
- /** 容器宽度 */
11
- width: number
12
- /** 容器高度 */
13
- height: number
14
- /** 元素宽度 */
15
- itemWidth: number
16
- /** 元素高度 */
17
- itemHeight: number
18
- /** 列间距 */
19
- columnGap: number
20
- /** 列数 */
21
- columnCount: number
22
- /** 行间距 */
23
- rowGap: number
24
- /** 行数 */
25
- rowCount: number
26
- /** 元素格数 */
27
- itemCount: number
28
- /** 最大行数 */
29
- maxRows: number | null
30
- /** 是否有元素被隐藏 */
31
- overflow: boolean
32
- }
33
-
34
- export interface FlowProps<T> extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
35
- /** 元素宽度 */
36
- itemWidth: number
37
- /** 元素高度 */
38
- itemHeight: number
39
- /**
40
- * 列间距
41
- * 1. 如果是数字,表示列间距是固定的
42
- * 2. 如果是 auto,表示会在尽可能放进更多列的情况下,列间距是平均的
43
- * 2. 如果是数组,表示列间距是区间的,第一个元素是最小值,第二个元素是最大值
44
- */
45
- columnGap?: number | "auto" | [number | "auto", number | "auto"]
46
- /** 行间距 */
47
- rowGap?: number
48
- gap?: number
49
- /** 最大行数 */
50
- maxRows?: number | null
51
- /** 源数据 */
52
- data?: T[]
53
- /** 渲染 */
54
- render: (item: T, index: number, arr: T[]) => ReactNode
55
- /** key释放器,默认为 index */
56
- keyExactor?: (item: T, index: number, arr: T[]) => Key
57
- /**
58
- * 渲染的元素由两层容器包裹,外层容器类名
59
- */
60
- wrapperClassName?: string
61
- /**
62
- * 渲染的元素由两层容器包裹,外层容器样式
63
- */
64
- wrapperStyle?: CSSProperties
65
- /**
66
- * 渲染的元素由两层容器包裹,内层容器类名
67
- */
68
- containerClassName?: string
69
- /**
70
- * 渲染的元素由两层容器包裹,内层容器样式
71
- */
72
- containerStyle?: CSSProperties
73
- /** 节流时间,单位毫秒,默认200ms,传入 0 不节流 */
74
- throttle?: number
75
- /** 动画时间,单位毫秒,默认400ms,传入 0 不展示动画 */
76
- transitionDuration?: number
77
- /** 变化的回调函数 */
78
- onSizeChange?: (sizeData: FlowSizeData) => void
79
- element?: RefObject<HTMLDivElement>
80
- }
81
-
82
- export function getGapRange(gap?: undefined | number | "auto" | (number | "auto")[]): [number, number | "auto"] {
83
- if (typeof gap === "number") return [gap, gap]
84
- if (Array.isArray(gap)) return [typeof gap[0] === "number" ? gap[0] : 0, gap[1]]
85
- return [0, "auto"]
86
- }
87
-
88
- export interface GapAndCount {
89
- count: number
90
- gap: number
91
- }
92
-
93
- export function getGapCountAndSize(width: number, itemWidth: number, minGap: number, maxGap: number | "auto"): GapAndCount {
94
- const count = Math.floor((width + minGap) / (itemWidth + minGap)) || 1
95
- if (count === 1) return { count, gap: 0 }
96
- const averageGap = (width - itemWidth * count) / (count - 1)
97
- if (averageGap < minGap) return { count, gap: minGap }
98
- if (maxGap !== "auto" && averageGap > maxGap) return { count, gap: maxGap }
99
- return { count, gap: averageGap }
100
- }
101
-
102
- export interface ManualFlowProps<T> extends FlowProps<T> {
103
- /** 组件宽度,必须指定 */
104
- width: number
105
- }
106
-
107
- /** 手动组件,由外界指定宽度,性能更好 */
108
- export function ManualFlow<T>(props: ManualFlowProps<T>) {
109
- let { itemWidth, itemHeight, columnGap, rowGap, maxRows, data = [], render, keyExactor, className, style, wrapperClassName, wrapperStyle, throttle, transitionDuration, onSizeChange, containerClassName, containerStyle, gap = 0, width, element, ...rest } = props
110
- rowGap ??= gap
111
- columnGap ??= gap
112
- const [minColumnGap, maxColumnGap] = getGapRange(columnGap)
113
- const [{ count: columnCount, gap: columnGapSize }, setGapAndCount] = useState(() => getGapCountAndSize(width, itemWidth, minColumnGap, maxColumnGap))
114
- const ele = useRef<HTMLDivElement>(null)
115
- const contentRows = Math.ceil(data.length / columnCount)
116
- const contentShownRows = typeof maxRows === "number" ? Math.min(contentRows, maxRows) : contentRows
117
- const height = contentShownRows > 0 ? contentShownRows * (itemHeight + rowGap) - rowGap : 0
118
-
119
- function getPosition(index: number) {
120
- const y = Math.floor(index / columnCount)
121
- const x = index - y * columnCount
122
- return {
123
- left: x * (itemWidth + columnGapSize),
124
- top: y * (itemHeight + rowGap!)
125
- }
126
- }
127
-
128
- function getHidden(index: number) {
129
- if (typeof maxRows !== "number") return false
130
- return index >= maxRows * columnCount
131
- }
132
-
133
- useImperativeHandle(element, () => ele.current!, [ele.current])
134
-
135
- useEffect(() => {
136
- function task() {
137
- setGapAndCount(getGapCountAndSize(width, itemWidth, minColumnGap, maxColumnGap))
138
- }
139
- if (throttle === 0) return task()
140
- const timeout = setTimeout(task, throttle || 200)
141
- return () => clearTimeout(timeout)
142
- }, [width, itemWidth, throttle, minColumnGap, maxColumnGap])
143
-
144
- useEffect(() => {
145
- onSizeChange?.({ width, height, itemWidth, itemHeight, columnGap: columnGapSize, columnCount, rowGap: rowGap!, rowCount: contentShownRows, overflow: data.length > contentShownRows * columnCount, itemCount: data.length, maxRows: maxRows ?? null })
146
- }, [width, height, columnGapSize, columnCount, rowGap, contentShownRows, data.length, itemWidth, itemHeight, maxRows])
147
-
148
- return (
149
- <div
150
- ref={ele}
151
- className={clsx(
152
- css`
153
- position: relative;
154
- height: var(--height);
155
- overflow: hidden;
156
- `,
157
- className
158
- )}
159
- style={transformCSSVariable({ height: px(height) }, style)}
160
- {...rest}>
161
- {data.map((item, index, arr) => (
162
- <div
163
- key={keyExactor ? keyExactor(item, index, arr) : index}
164
- className={clsx(
165
- css`
166
- position: absolute;
167
- width: var(--width);
168
- height: var(--height);
169
- transition: var(--transition);
170
- left: 0;
171
- top: 0;
172
- transform: translate(var(--left), var(--top));
173
- `,
174
- wrapperClassName
175
- )}
176
- style={transformCSSVariable(
177
- {
178
- width: px(itemWidth),
179
- height: px(itemHeight),
180
- transition: transitionDuration === 0 ? "none" : `all ${transitionDuration || 400}ms`,
181
- left: px(getPosition(index).left),
182
- top: px(getPosition(index).top)
183
- },
184
- wrapperStyle
185
- )}>
186
- <div
187
- className={clsx(
188
- css`
189
- width: 100%;
190
- height: 100%;
191
- display: var(--display);
192
- `,
193
- containerClassName
194
- )}
195
- style={transformCSSVariable({ display: getHidden(index) ? "none" : "block" }, containerStyle)}>
196
- {render(item, index, arr)}
197
- </div>
198
- </div>
199
- ))}
200
- </div>
201
- )
202
- }
203
-
204
- /** 自适应浮动组件 */
205
- export function Flow<T>(props: FlowProps<T>) {
206
- const { itemWidth, itemHeight, columnGap, rowGap, gap, maxRows, data, render, keyExactor, wrapperClassName, wrapperStyle, containerClassName, containerStyle, throttle, transitionDuration, onSizeChange, element, ...rest } = props
207
- const ele = useRef<HTMLDivElement>(null)
208
- const size = useSize(ele)
209
- const width = useRef(size?.width || 0)
210
- if (size && size.width !== 0) width.current = size.width
211
- useImperativeHandle(element, () => ele.current!, [ele.current])
212
- if (width.current === 0) return <div ref={ele} {...rest} />
213
- return <ManualFlow element={ele} {...props} width={width.current} />
214
- }
1
+ "use client"
2
+
3
+ import { css } from "@emotion/css"
4
+ import { useSize } from "ahooks"
5
+ import { clsx } from "deepsea-tools"
6
+ import { CSSProperties, HTMLAttributes, Key, ReactNode, RefObject, useEffect, useImperativeHandle, useRef, useState } from "react"
7
+ import { px, transformCSSVariable } from "../utils"
8
+
9
+ export interface FlowSizeData {
10
+ /** 容器宽度 */
11
+ width: number
12
+ /** 容器高度 */
13
+ height: number
14
+ /** 元素宽度 */
15
+ itemWidth: number
16
+ /** 元素高度 */
17
+ itemHeight: number
18
+ /** 列间距 */
19
+ columnGap: number
20
+ /** 列数 */
21
+ columnCount: number
22
+ /** 行间距 */
23
+ rowGap: number
24
+ /** 行数 */
25
+ rowCount: number
26
+ /** 元素格数 */
27
+ itemCount: number
28
+ /** 最大行数 */
29
+ maxRows: number | null
30
+ /** 是否有元素被隐藏 */
31
+ overflow: boolean
32
+ }
33
+
34
+ export interface FlowProps<T> extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
35
+ /** 元素宽度 */
36
+ itemWidth: number
37
+ /** 元素高度 */
38
+ itemHeight: number
39
+ /**
40
+ * 列间距
41
+ * 1. 如果是数字,表示列间距是固定的
42
+ * 2. 如果是 auto,表示会在尽可能放进更多列的情况下,列间距是平均的
43
+ * 2. 如果是数组,表示列间距是区间的,第一个元素是最小值,第二个元素是最大值
44
+ */
45
+ columnGap?: number | "auto" | [number | "auto", number | "auto"]
46
+ /** 行间距 */
47
+ rowGap?: number
48
+ gap?: number
49
+ /** 最大行数 */
50
+ maxRows?: number | null
51
+ /** 源数据 */
52
+ data?: T[]
53
+ /** 渲染 */
54
+ render: (item: T, index: number, arr: T[]) => ReactNode
55
+ /** key释放器,默认为 index */
56
+ keyExactor?: (item: T, index: number, arr: T[]) => Key
57
+ /**
58
+ * 渲染的元素由两层容器包裹,外层容器类名
59
+ */
60
+ wrapperClassName?: string
61
+ /**
62
+ * 渲染的元素由两层容器包裹,外层容器样式
63
+ */
64
+ wrapperStyle?: CSSProperties
65
+ /**
66
+ * 渲染的元素由两层容器包裹,内层容器类名
67
+ */
68
+ containerClassName?: string
69
+ /**
70
+ * 渲染的元素由两层容器包裹,内层容器样式
71
+ */
72
+ containerStyle?: CSSProperties
73
+ /** 节流时间,单位毫秒,默认200ms,传入 0 不节流 */
74
+ throttle?: number
75
+ /** 动画时间,单位毫秒,默认400ms,传入 0 不展示动画 */
76
+ transitionDuration?: number
77
+ /** 变化的回调函数 */
78
+ onSizeChange?: (sizeData: FlowSizeData) => void
79
+ element?: RefObject<HTMLDivElement>
80
+ }
81
+
82
+ export function getGapRange(gap?: undefined | number | "auto" | (number | "auto")[]): [number, number | "auto"] {
83
+ if (typeof gap === "number") return [gap, gap]
84
+ if (Array.isArray(gap)) return [typeof gap[0] === "number" ? gap[0] : 0, gap[1]]
85
+ return [0, "auto"]
86
+ }
87
+
88
+ export interface GapAndCount {
89
+ count: number
90
+ gap: number
91
+ }
92
+
93
+ export function getGapCountAndSize(width: number, itemWidth: number, minGap: number, maxGap: number | "auto"): GapAndCount {
94
+ const count = Math.floor((width + minGap) / (itemWidth + minGap)) || 1
95
+ if (count === 1) return { count, gap: 0 }
96
+ const averageGap = (width - itemWidth * count) / (count - 1)
97
+ if (averageGap < minGap) return { count, gap: minGap }
98
+ if (maxGap !== "auto" && averageGap > maxGap) return { count, gap: maxGap }
99
+ return { count, gap: averageGap }
100
+ }
101
+
102
+ export interface ManualFlowProps<T> extends FlowProps<T> {
103
+ /** 组件宽度,必须指定 */
104
+ width: number
105
+ }
106
+
107
+ /** 手动组件,由外界指定宽度,性能更好 */
108
+ export function ManualFlow<T>(props: ManualFlowProps<T>) {
109
+ let {
110
+ itemWidth,
111
+ itemHeight,
112
+ columnGap,
113
+ rowGap,
114
+ maxRows,
115
+ data = [],
116
+ render,
117
+ keyExactor,
118
+ className,
119
+ style,
120
+ wrapperClassName,
121
+ wrapperStyle,
122
+ throttle,
123
+ transitionDuration,
124
+ onSizeChange,
125
+ containerClassName,
126
+ containerStyle,
127
+ gap = 0,
128
+ width,
129
+ element,
130
+ ...rest
131
+ } = props
132
+ rowGap ??= gap
133
+ columnGap ??= gap
134
+ const [minColumnGap, maxColumnGap] = getGapRange(columnGap)
135
+ const [{ count: columnCount, gap: columnGapSize }, setGapAndCount] = useState(() => getGapCountAndSize(width, itemWidth, minColumnGap, maxColumnGap))
136
+ const ele = useRef<HTMLDivElement>(null)
137
+ const contentRows = Math.ceil(data.length / columnCount)
138
+ const contentShownRows = typeof maxRows === "number" ? Math.min(contentRows, maxRows) : contentRows
139
+ const height = contentShownRows > 0 ? contentShownRows * (itemHeight + rowGap) - rowGap : 0
140
+
141
+ function getPosition(index: number) {
142
+ const y = Math.floor(index / columnCount)
143
+ const x = index - y * columnCount
144
+ return {
145
+ left: x * (itemWidth + columnGapSize),
146
+ top: y * (itemHeight + rowGap!),
147
+ }
148
+ }
149
+
150
+ function getHidden(index: number) {
151
+ if (typeof maxRows !== "number") return false
152
+ return index >= maxRows * columnCount
153
+ }
154
+
155
+ useImperativeHandle(element, () => ele.current!, [ele.current])
156
+
157
+ useEffect(() => {
158
+ function task() {
159
+ setGapAndCount(getGapCountAndSize(width, itemWidth, minColumnGap, maxColumnGap))
160
+ }
161
+ if (throttle === 0) return task()
162
+ const timeout = setTimeout(task, throttle || 200)
163
+ return () => clearTimeout(timeout)
164
+ }, [width, itemWidth, throttle, minColumnGap, maxColumnGap])
165
+
166
+ useEffect(() => {
167
+ onSizeChange?.({
168
+ width,
169
+ height,
170
+ itemWidth,
171
+ itemHeight,
172
+ columnGap: columnGapSize,
173
+ columnCount,
174
+ rowGap: rowGap!,
175
+ rowCount: contentShownRows,
176
+ overflow: data.length > contentShownRows * columnCount,
177
+ itemCount: data.length,
178
+ maxRows: maxRows ?? null,
179
+ })
180
+ }, [width, height, columnGapSize, columnCount, rowGap, contentShownRows, data.length, itemWidth, itemHeight, maxRows])
181
+
182
+ return (
183
+ <div
184
+ ref={ele}
185
+ className={clsx(
186
+ css`
187
+ position: relative;
188
+ height: var(--height);
189
+ overflow: hidden;
190
+ `,
191
+ className,
192
+ )}
193
+ style={transformCSSVariable({ height: px(height) }, style)}
194
+ {...rest}
195
+ >
196
+ {data.map((item, index, arr) => (
197
+ <div
198
+ key={keyExactor ? keyExactor(item, index, arr) : index}
199
+ className={clsx(
200
+ css`
201
+ position: absolute;
202
+ width: var(--width);
203
+ height: var(--height);
204
+ transition: var(--transition);
205
+ left: 0;
206
+ top: 0;
207
+ transform: translate(var(--left), var(--top));
208
+ `,
209
+ wrapperClassName,
210
+ )}
211
+ style={transformCSSVariable(
212
+ {
213
+ width: px(itemWidth),
214
+ height: px(itemHeight),
215
+ transition: transitionDuration === 0 ? "none" : `all ${transitionDuration || 400}ms`,
216
+ left: px(getPosition(index).left),
217
+ top: px(getPosition(index).top),
218
+ },
219
+ wrapperStyle,
220
+ )}
221
+ >
222
+ <div
223
+ className={clsx(
224
+ css`
225
+ width: 100%;
226
+ height: 100%;
227
+ display: var(--display);
228
+ `,
229
+ containerClassName,
230
+ )}
231
+ style={transformCSSVariable({ display: getHidden(index) ? "none" : "block" }, containerStyle)}
232
+ >
233
+ {render(item, index, arr)}
234
+ </div>
235
+ </div>
236
+ ))}
237
+ </div>
238
+ )
239
+ }
240
+
241
+ /** 自适应浮动组件 */
242
+ export function Flow<T>(props: FlowProps<T>) {
243
+ const {
244
+ itemWidth,
245
+ itemHeight,
246
+ columnGap,
247
+ rowGap,
248
+ gap,
249
+ maxRows,
250
+ data,
251
+ render,
252
+ keyExactor,
253
+ wrapperClassName,
254
+ wrapperStyle,
255
+ containerClassName,
256
+ containerStyle,
257
+ throttle,
258
+ transitionDuration,
259
+ onSizeChange,
260
+ element,
261
+ ...rest
262
+ } = props
263
+ const ele = useRef<HTMLDivElement>(null)
264
+ const size = useSize(ele)
265
+ const width = useRef(size?.width || 0)
266
+ if (size && size.width !== 0) width.current = size.width
267
+ useImperativeHandle(element, () => ele.current!, [ele.current])
268
+ if (width.current === 0) return <div ref={ele} {...rest} />
269
+ return <ManualFlow element={ele} {...props} width={width.current} />
270
+ }