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.
- package/README.md +23 -23
- package/dist/cjs/components/AutoFit.js +3 -1
- package/dist/cjs/components/AutoFit.js.map +2 -2
- package/dist/cjs/components/AutoScroll.js +16 -1
- package/dist/cjs/components/AutoScroll.js.map +2 -2
- package/dist/cjs/components/AutoSizeTextarea.js.map +1 -1
- package/dist/cjs/components/CircleText.js +31 -2
- package/dist/cjs/components/CircleText.js.map +2 -2
- package/dist/cjs/components/CopyButton.d.ts +9 -0
- package/dist/cjs/components/CopyButton.js +59 -0
- package/dist/cjs/components/CopyButton.js.map +7 -0
- package/dist/cjs/components/Echart.js.map +2 -2
- package/dist/cjs/components/Flow.js +56 -3
- package/dist/cjs/components/Flow.js.map +2 -2
- package/dist/cjs/components/FormLabel.js.map +1 -1
- package/dist/cjs/components/HlsPlayer.js.map +1 -1
- package/dist/cjs/components/InfiniteScroll.js +15 -1
- package/dist/cjs/components/InfiniteScroll.js.map +2 -2
- package/dist/cjs/components/InputFile.js.map +1 -1
- package/dist/cjs/components/LoopSwiper.js +23 -2
- package/dist/cjs/components/LoopSwiper.js.map +2 -2
- package/dist/cjs/components/Ring.js +13 -1
- package/dist/cjs/components/Ring.js.map +2 -2
- package/dist/cjs/components/Scroll.js.map +2 -2
- package/dist/cjs/components/SectionRing.js +3 -1
- package/dist/cjs/components/SectionRing.js.map +2 -2
- package/dist/cjs/components/Skeleton.js.map +2 -2
- package/dist/cjs/components/Title.js.map +2 -2
- package/dist/cjs/components/TransitionBox.js +9 -1
- package/dist/cjs/components/TransitionBox.js.map +2 -2
- package/dist/cjs/components/TransitionNum.js.map +1 -1
- package/dist/cjs/components/Trapezium.js.map +1 -1
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/index.js +2 -0
- package/dist/cjs/index.js.map +2 -2
- package/dist/cjs/utils/getReactVersion.js.map +1 -1
- package/dist/cjs/utils/index.js.map +1 -1
- package/dist/esm/components/AutoFit.js +9 -9
- package/dist/esm/components/AutoFit.js.map +1 -1
- package/dist/esm/components/AutoScroll.js.map +1 -1
- package/dist/esm/components/AutoSizeTextarea.js +2 -2
- package/dist/esm/components/AutoSizeTextarea.js.map +1 -1
- package/dist/esm/components/CircleText.js.map +1 -1
- package/dist/esm/components/CopyButton.d.ts +9 -0
- package/dist/esm/components/CopyButton.js +29 -0
- package/dist/esm/components/CopyButton.js.map +1 -0
- package/dist/esm/components/Echart.js.map +1 -1
- package/dist/esm/components/Flow.js.map +1 -1
- package/dist/esm/components/FormLabel.js +2 -2
- package/dist/esm/components/FormLabel.js.map +1 -1
- package/dist/esm/components/HlsPlayer.js.map +1 -1
- package/dist/esm/components/InfiniteScroll.js +4 -4
- package/dist/esm/components/InfiniteScroll.js.map +1 -1
- package/dist/esm/components/InputFile.js.map +1 -1
- package/dist/esm/components/LoopSwiper.js.map +1 -1
- package/dist/esm/components/Ring.js.map +1 -1
- package/dist/esm/components/Scroll.js.map +1 -1
- package/dist/esm/components/SectionRing.js.map +1 -1
- package/dist/esm/components/Skeleton.js.map +1 -1
- package/dist/esm/components/Title.js.map +1 -1
- package/dist/esm/components/TransitionBox.js.map +1 -1
- package/dist/esm/components/TransitionNum.js.map +1 -1
- package/dist/esm/components/Trapezium.js.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/utils/getReactVersion.js.map +1 -1
- package/dist/esm/utils/index.js.map +1 -1
- package/package.json +4 -2
- package/src/components/AutoFit.tsx +103 -101
- package/src/components/AutoScroll.tsx +148 -132
- package/src/components/AutoSizeTextarea.tsx +49 -49
- package/src/components/CircleText.tsx +81 -56
- package/src/components/CopyButton.tsx +29 -0
- package/src/components/Echart.tsx +67 -44
- package/src/components/Flow.tsx +270 -214
- package/src/components/FormLabel.tsx +38 -38
- package/src/components/HlsPlayer.tsx +34 -34
- package/src/components/InfiniteScroll.tsx +161 -135
- package/src/components/InputFile.tsx +234 -234
- package/src/components/LoopSwiper.tsx +125 -101
- package/src/components/Ring.tsx +30 -19
- package/src/components/Scroll.tsx +96 -95
- package/src/components/SectionRing.tsx +39 -36
- package/src/components/Skeleton.tsx +47 -46
- package/src/components/Title.tsx +23 -24
- package/src/components/TransitionBox.tsx +44 -36
- package/src/components/TransitionNum.tsx +54 -54
- package/src/components/Trapezium.tsx +59 -59
- package/src/index.ts +1 -0
- package/src/utils/getReactVersion.ts +7 -7
- package/src/utils/index.ts +33 -33
|
@@ -1,44 +1,67 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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>
|
package/src/components/Flow.tsx
CHANGED
|
@@ -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 {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
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
|
+
}
|