deepsea-components 5.15.21 → 5.15.23

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 (58) hide show
  1. package/README.md +23 -23
  2. package/dist/components/AutoFit.cjs +7 -7
  3. package/dist/components/AutoFit.js +7 -7
  4. package/dist/components/AutoScroll.cjs +7 -7
  5. package/dist/components/AutoScroll.js +7 -7
  6. package/dist/components/AutoSizeTextarea.cjs +4 -4
  7. package/dist/components/AutoSizeTextarea.js +4 -4
  8. package/dist/components/Flow.cjs +16 -16
  9. package/dist/components/Flow.js +16 -16
  10. package/dist/components/FormLabel.cjs +1 -1
  11. package/dist/components/FormLabel.js +1 -1
  12. package/dist/components/InfiniteScroll.cjs +13 -13
  13. package/dist/components/InfiniteScroll.js +13 -13
  14. package/dist/components/LoopSwiper.cjs +33 -33
  15. package/dist/components/LoopSwiper.js +33 -33
  16. package/dist/components/Scroll.cjs +13 -13
  17. package/dist/components/Scroll.js +13 -13
  18. package/dist/components/ScrollMask.module.cjs +2 -2
  19. package/dist/components/ScrollMask.module.js +2 -2
  20. package/dist/components/Skeleton.cjs +17 -17
  21. package/dist/components/Skeleton.js +17 -17
  22. package/dist/components/TransitionNum.cjs +1 -1
  23. package/dist/components/TransitionNum.js +1 -1
  24. package/dist/components/Trapezium.cjs +4 -4
  25. package/dist/components/Trapezium.js +4 -4
  26. package/package.json +4 -3
  27. package/src/components/AutoFit.tsx +104 -104
  28. package/src/components/AutoScroll.tsx +150 -150
  29. package/src/components/AutoSizeTextarea.tsx +50 -50
  30. package/src/components/CircleText.tsx +81 -81
  31. package/src/components/CopyButton.tsx +31 -31
  32. package/src/components/Echart.tsx +69 -69
  33. package/src/components/Flow.tsx +271 -271
  34. package/src/components/FormLabel.tsx +41 -41
  35. package/src/components/HlsPlayer.tsx +34 -34
  36. package/src/components/IconFileType.tsx +162 -162
  37. package/src/components/InfiniteScroll.tsx +163 -163
  38. package/src/components/InputFile.tsx +93 -93
  39. package/src/components/InputFileButton.tsx +122 -122
  40. package/src/components/LoopSwiper.tsx +125 -125
  41. package/src/components/ReadExcel.tsx +13 -13
  42. package/src/components/ReadSheet.tsx +17 -17
  43. package/src/components/Ring.tsx +30 -30
  44. package/src/components/Scroll.tsx +97 -97
  45. package/src/components/ScrollMask.module.css +87 -87
  46. package/src/components/ScrollMask.tsx +68 -68
  47. package/src/components/SectionRing.tsx +40 -40
  48. package/src/components/Skeleton.tsx +45 -45
  49. package/src/components/Title.tsx +27 -27
  50. package/src/components/TransitionBox.tsx +44 -44
  51. package/src/components/TransitionNum.tsx +54 -54
  52. package/src/components/Trapezium.tsx +60 -60
  53. package/src/components/Unify.tsx +38 -38
  54. package/src/components/WriteExcel.tsx +13 -13
  55. package/src/components/WriteSheet.tsx +25 -25
  56. package/src/utils/getReactVersion.ts +7 -7
  57. package/src/utils/index.ts +33 -33
  58. package/tsconfig.json +16 -16
@@ -1,122 +1,122 @@
1
- "use client"
2
-
3
- import {
4
- ComponentProps,
5
- ComponentRef,
6
- DragEvent,
7
- Fragment,
8
- JSX,
9
- JSXElementConstructor,
10
- MouseEvent as ReactMouseEvent,
11
- createElement,
12
- useImperativeHandle,
13
- useRef,
14
- useState,
15
- } from "react"
16
-
17
- import { FileType, InputFile, InputFileBaseProps, InputFileDataType, InputFileDataTypeMap, InputFileExtraProps, ValueType, getFileData } from "./InputFile"
18
-
19
- export type InputFileButtonProps<
20
- Multiple extends boolean = false,
21
- Type extends InputFileDataType = "file",
22
- AS extends keyof JSX.IntrinsicElements | JSXElementConstructor<any> = "button",
23
- > = Omit<ComponentProps<AS>, "as" | "type" | "disabled"> &
24
- InputFileExtraProps<Multiple, Type> & {
25
- disabled?: boolean
26
- inputProps?: Omit<InputFileBaseProps, "accept">
27
- accept?: string
28
- dragFile?: boolean
29
- as?: AS
30
- }
31
-
32
- /** 专用于读取文件的 button 组件 */
33
- export function InputFileButton<
34
- Multiple extends boolean = false,
35
- Type extends InputFileDataType = "file",
36
- AS extends keyof JSX.IntrinsicElements | JSXElementConstructor<any> = "button",
37
- >(props: InputFileButtonProps<Multiple, Type, AS>) {
38
- const {
39
- as = "button",
40
- onClick: _onClick,
41
- inputProps = {},
42
- accept,
43
- onDrop: _onDrop,
44
- onDragOver: _onDragOver,
45
- dragFile,
46
- disabled: _disabled,
47
- type = "file",
48
- multiple,
49
- onValueChange,
50
- onFileChange,
51
- clearAfterChange,
52
- ...rest
53
- } = props
54
-
55
- const { ref, style, disabled: __disabled, ...restInputProps } = inputProps
56
- const [disabled, setDisabled] = useState(false)
57
- const input = useRef<HTMLInputElement>(null)
58
-
59
- useImperativeHandle(ref, () => input.current!, [input.current])
60
-
61
- function onClick(e: ReactMouseEvent<ComponentRef<AS>, MouseEvent>) {
62
- input.current?.click()
63
- _onClick?.(e as any)
64
- }
65
-
66
- async function onDrop(e: DragEvent<ComponentRef<AS>>) {
67
- _onDrop?.(e as any)
68
- if (disabled || !dragFile) return
69
- e.preventDefault()
70
- const { files } = e.dataTransfer
71
- if (!files || files.length === 0) return
72
- setDisabled(true)
73
- try {
74
- if (multiple) {
75
- const files2: File[] = Array.from(files)
76
- const values: InputFileDataTypeMap[Type][] = []
77
- for (const file of files2) {
78
- const value = (await getFileData(file, type)) as InputFileDataTypeMap[Type]
79
- values.push(value)
80
- }
81
- onFileChange?.(files2 as FileType<Multiple>)
82
- onValueChange?.(values as ValueType<Multiple, Type>)
83
- } else {
84
- const file = files[0]
85
- onFileChange?.(file as FileType<Multiple>)
86
- onValueChange?.((await getFileData(file, type)) as ValueType<Multiple, Type>)
87
- }
88
- } finally {
89
- setDisabled(false)
90
- }
91
- }
92
-
93
- function onDragOver(e: DragEvent<ComponentRef<AS>>) {
94
- _onDragOver?.(e as any)
95
- if (disabled || !dragFile) return
96
- e.preventDefault()
97
- }
98
-
99
- return (
100
- <Fragment>
101
- <InputFile<Multiple, Type>
102
- ref={input}
103
- disabled={disabled || _disabled || __disabled}
104
- style={{ display: "none", ...style }}
105
- multiple={multiple}
106
- accept={accept}
107
- type={type as Type}
108
- onValueChange={onValueChange}
109
- onFileChange={onFileChange}
110
- clearAfterChange={clearAfterChange}
111
- {...restInputProps}
112
- />
113
- {createElement(as, {
114
- disabled: disabled || _disabled,
115
- onClick,
116
- onDrop,
117
- onDragOver,
118
- ...rest,
119
- })}
120
- </Fragment>
121
- )
122
- }
1
+ "use client"
2
+
3
+ import {
4
+ ComponentProps,
5
+ ComponentRef,
6
+ DragEvent,
7
+ Fragment,
8
+ JSX,
9
+ JSXElementConstructor,
10
+ MouseEvent as ReactMouseEvent,
11
+ createElement,
12
+ useImperativeHandle,
13
+ useRef,
14
+ useState,
15
+ } from "react"
16
+
17
+ import { FileType, InputFile, InputFileBaseProps, InputFileDataType, InputFileDataTypeMap, InputFileExtraProps, ValueType, getFileData } from "./InputFile"
18
+
19
+ export type InputFileButtonProps<
20
+ Multiple extends boolean = false,
21
+ Type extends InputFileDataType = "file",
22
+ AS extends keyof JSX.IntrinsicElements | JSXElementConstructor<any> = "button",
23
+ > = Omit<ComponentProps<AS>, "as" | "type" | "disabled"> &
24
+ InputFileExtraProps<Multiple, Type> & {
25
+ disabled?: boolean
26
+ inputProps?: Omit<InputFileBaseProps, "accept">
27
+ accept?: string
28
+ dragFile?: boolean
29
+ as?: AS
30
+ }
31
+
32
+ /** 专用于读取文件的 button 组件 */
33
+ export function InputFileButton<
34
+ Multiple extends boolean = false,
35
+ Type extends InputFileDataType = "file",
36
+ AS extends keyof JSX.IntrinsicElements | JSXElementConstructor<any> = "button",
37
+ >(props: InputFileButtonProps<Multiple, Type, AS>) {
38
+ const {
39
+ as = "button",
40
+ onClick: _onClick,
41
+ inputProps = {},
42
+ accept,
43
+ onDrop: _onDrop,
44
+ onDragOver: _onDragOver,
45
+ dragFile,
46
+ disabled: _disabled,
47
+ type = "file",
48
+ multiple,
49
+ onValueChange,
50
+ onFileChange,
51
+ clearAfterChange,
52
+ ...rest
53
+ } = props
54
+
55
+ const { ref, style, disabled: __disabled, ...restInputProps } = inputProps
56
+ const [disabled, setDisabled] = useState(false)
57
+ const input = useRef<HTMLInputElement>(null)
58
+
59
+ useImperativeHandle(ref, () => input.current!, [input.current])
60
+
61
+ function onClick(e: ReactMouseEvent<ComponentRef<AS>, MouseEvent>) {
62
+ input.current?.click()
63
+ _onClick?.(e as any)
64
+ }
65
+
66
+ async function onDrop(e: DragEvent<ComponentRef<AS>>) {
67
+ _onDrop?.(e as any)
68
+ if (disabled || !dragFile) return
69
+ e.preventDefault()
70
+ const { files } = e.dataTransfer
71
+ if (!files || files.length === 0) return
72
+ setDisabled(true)
73
+ try {
74
+ if (multiple) {
75
+ const files2: File[] = Array.from(files)
76
+ const values: InputFileDataTypeMap[Type][] = []
77
+ for (const file of files2) {
78
+ const value = (await getFileData(file, type)) as InputFileDataTypeMap[Type]
79
+ values.push(value)
80
+ }
81
+ onFileChange?.(files2 as FileType<Multiple>)
82
+ onValueChange?.(values as ValueType<Multiple, Type>)
83
+ } else {
84
+ const file = files[0]
85
+ onFileChange?.(file as FileType<Multiple>)
86
+ onValueChange?.((await getFileData(file, type)) as ValueType<Multiple, Type>)
87
+ }
88
+ } finally {
89
+ setDisabled(false)
90
+ }
91
+ }
92
+
93
+ function onDragOver(e: DragEvent<ComponentRef<AS>>) {
94
+ _onDragOver?.(e as any)
95
+ if (disabled || !dragFile) return
96
+ e.preventDefault()
97
+ }
98
+
99
+ return (
100
+ <Fragment>
101
+ <InputFile<Multiple, Type>
102
+ ref={input}
103
+ disabled={disabled || _disabled || __disabled}
104
+ style={{ display: "none", ...style }}
105
+ multiple={multiple}
106
+ accept={accept}
107
+ type={type as Type}
108
+ onValueChange={onValueChange}
109
+ onFileChange={onFileChange}
110
+ clearAfterChange={clearAfterChange}
111
+ {...restInputProps}
112
+ />
113
+ {createElement(as, {
114
+ disabled: disabled || _disabled,
115
+ onClick,
116
+ onDrop,
117
+ onDragOver,
118
+ ...rest,
119
+ })}
120
+ </Fragment>
121
+ )
122
+ }
@@ -1,125 +1,125 @@
1
- "use client"
2
-
3
- import { css } from "@emotion/css"
4
- import { clsx } from "deepsea-tools"
5
- import { CSSProperties, HTMLAttributes, forwardRef, useEffect, useImperativeHandle, useRef, useState } from "react"
6
-
7
- export interface LoopSwiperProps extends HTMLAttributes<HTMLDivElement> {
8
- direction?: "horizontal" | "vertical"
9
- reverse?: boolean
10
- period: number
11
- gap?: CSSProperties["gap"]
12
- }
13
-
14
- /** 循环播放组件 */
15
- export const LoopSwiper = forwardRef<HTMLDivElement, LoopSwiperProps>((props, ref) => {
16
- const { className, style, children, direction, period, reverse, gap, ...rest } = props
17
- const wrapper = useRef<HTMLDivElement>(null)
18
- const container = useRef<HTMLDivElement>(null)
19
- const [swiper, setSwiper] = useState(false)
20
- const directionRef = useRef(direction)
21
- directionRef.current = direction
22
- const flexDirection: CSSProperties["flexDirection"] = direction === "vertical" ? (reverse ? "column-reverse" : "column") : reverse ? "row-reverse" : "row"
23
- const animationName = swiper
24
- ? direction === "vertical"
25
- ? reverse
26
- ? "deepsea-reverse-vertical-loop-swipe"
27
- : "deepsea-vertical-loop-swipe"
28
- : reverse
29
- ? "deepsea-reverse-horizontal-loop-swipe"
30
- : "deepsea-horizontal-loop-swipe"
31
- : "none"
32
- const animationDuration = `${period}ms`
33
- const animationTimingFunction = "linear"
34
- const animationIterationCount = "infinite"
35
-
36
- useImperativeHandle(ref, () => wrapper.current!, [])
37
-
38
- useEffect(() => {
39
- const wrapperEle = wrapper.current!
40
- const containerEle = container.current!
41
- let wrapperWidth = 0
42
- let wrapperHeight = 0
43
- let containerWidth = 0
44
- let containerHeight = 0
45
- const observer = new ResizeObserver(entries => {
46
- entries.forEach(entry => {
47
- if (entry.target === wrapperEle) {
48
- wrapperWidth = entry.contentRect.width
49
- wrapperHeight = entry.contentRect.height
50
- } else if (entry.target === containerEle) {
51
- containerWidth = entry.contentRect.width
52
- containerHeight = entry.contentRect.height
53
- }
54
- })
55
- setSwiper(directionRef.current === "vertical" ? containerHeight > wrapperHeight : containerWidth > wrapperWidth)
56
- })
57
- observer.observe(wrapperEle)
58
- observer.observe(containerEle)
59
- }, [])
60
-
61
- return (
62
- <div
63
- ref={wrapper}
64
- className={clsx(
65
- css`
66
- @keyframes deepsea-horizontal-loop-swipe {
67
- from {
68
- transform: translateX(0);
69
- }
70
- to {
71
- transform: translateX(-100%);
72
- }
73
- }
74
- @keyframes deepsea-reverse-horizontal-loop-swipe {
75
- from {
76
- transform: translateX(0);
77
- }
78
- to {
79
- transform: translateX(100%);
80
- }
81
- }
82
- @keyframes deepsea-vertical-loop-swipe {
83
- from {
84
- transform: translateY(0);
85
- }
86
- to {
87
- transform: translateY(-100%);
88
- }
89
- }
90
- @keyframes deepsea-reverse-vertical-loop-swipe {
91
- from {
92
- transform: translateY(0);
93
- }
94
- to {
95
- transform: translateY(100%);
96
- }
97
- }
98
- `,
99
- className,
100
- )}
101
- style={{ display: "flex", flexDirection, gap, ...style }}
102
- {...rest}
103
- >
104
- <div
105
- ref={container}
106
- style={{ display: "flex", flexDirection, gap, animationName, animationTimingFunction, animationDuration, animationIterationCount }}
107
- >
108
- {children}
109
- </div>
110
- <div
111
- style={{
112
- display: swiper ? "flex" : "none",
113
- flexDirection,
114
- gap,
115
- animationName,
116
- animationTimingFunction,
117
- animationDuration,
118
- animationIterationCount,
119
- }}
120
- >
121
- {children}
122
- </div>
123
- </div>
124
- )
125
- })
1
+ "use client"
2
+
3
+ import { css } from "@emotion/css"
4
+ import { clsx } from "deepsea-tools"
5
+ import { CSSProperties, HTMLAttributes, forwardRef, useEffect, useImperativeHandle, useRef, useState } from "react"
6
+
7
+ export interface LoopSwiperProps extends HTMLAttributes<HTMLDivElement> {
8
+ direction?: "horizontal" | "vertical"
9
+ reverse?: boolean
10
+ period: number
11
+ gap?: CSSProperties["gap"]
12
+ }
13
+
14
+ /** 循环播放组件 */
15
+ export const LoopSwiper = forwardRef<HTMLDivElement, LoopSwiperProps>((props, ref) => {
16
+ const { className, style, children, direction, period, reverse, gap, ...rest } = props
17
+ const wrapper = useRef<HTMLDivElement>(null)
18
+ const container = useRef<HTMLDivElement>(null)
19
+ const [swiper, setSwiper] = useState(false)
20
+ const directionRef = useRef(direction)
21
+ directionRef.current = direction
22
+ const flexDirection: CSSProperties["flexDirection"] = direction === "vertical" ? (reverse ? "column-reverse" : "column") : reverse ? "row-reverse" : "row"
23
+ const animationName = swiper
24
+ ? direction === "vertical"
25
+ ? reverse
26
+ ? "deepsea-reverse-vertical-loop-swipe"
27
+ : "deepsea-vertical-loop-swipe"
28
+ : reverse
29
+ ? "deepsea-reverse-horizontal-loop-swipe"
30
+ : "deepsea-horizontal-loop-swipe"
31
+ : "none"
32
+ const animationDuration = `${period}ms`
33
+ const animationTimingFunction = "linear"
34
+ const animationIterationCount = "infinite"
35
+
36
+ useImperativeHandle(ref, () => wrapper.current!, [])
37
+
38
+ useEffect(() => {
39
+ const wrapperEle = wrapper.current!
40
+ const containerEle = container.current!
41
+ let wrapperWidth = 0
42
+ let wrapperHeight = 0
43
+ let containerWidth = 0
44
+ let containerHeight = 0
45
+ const observer = new ResizeObserver(entries => {
46
+ entries.forEach(entry => {
47
+ if (entry.target === wrapperEle) {
48
+ wrapperWidth = entry.contentRect.width
49
+ wrapperHeight = entry.contentRect.height
50
+ } else if (entry.target === containerEle) {
51
+ containerWidth = entry.contentRect.width
52
+ containerHeight = entry.contentRect.height
53
+ }
54
+ })
55
+ setSwiper(directionRef.current === "vertical" ? containerHeight > wrapperHeight : containerWidth > wrapperWidth)
56
+ })
57
+ observer.observe(wrapperEle)
58
+ observer.observe(containerEle)
59
+ }, [])
60
+
61
+ return (
62
+ <div
63
+ ref={wrapper}
64
+ className={clsx(
65
+ css`
66
+ @keyframes deepsea-horizontal-loop-swipe {
67
+ from {
68
+ transform: translateX(0);
69
+ }
70
+ to {
71
+ transform: translateX(-100%);
72
+ }
73
+ }
74
+ @keyframes deepsea-reverse-horizontal-loop-swipe {
75
+ from {
76
+ transform: translateX(0);
77
+ }
78
+ to {
79
+ transform: translateX(100%);
80
+ }
81
+ }
82
+ @keyframes deepsea-vertical-loop-swipe {
83
+ from {
84
+ transform: translateY(0);
85
+ }
86
+ to {
87
+ transform: translateY(-100%);
88
+ }
89
+ }
90
+ @keyframes deepsea-reverse-vertical-loop-swipe {
91
+ from {
92
+ transform: translateY(0);
93
+ }
94
+ to {
95
+ transform: translateY(100%);
96
+ }
97
+ }
98
+ `,
99
+ className,
100
+ )}
101
+ style={{ display: "flex", flexDirection, gap, ...style }}
102
+ {...rest}
103
+ >
104
+ <div
105
+ ref={container}
106
+ style={{ display: "flex", flexDirection, gap, animationName, animationTimingFunction, animationDuration, animationIterationCount }}
107
+ >
108
+ {children}
109
+ </div>
110
+ <div
111
+ style={{
112
+ display: swiper ? "flex" : "none",
113
+ flexDirection,
114
+ gap,
115
+ animationName,
116
+ animationTimingFunction,
117
+ animationDuration,
118
+ animationIterationCount,
119
+ }}
120
+ >
121
+ {children}
122
+ </div>
123
+ </div>
124
+ )
125
+ })
@@ -1,13 +1,13 @@
1
- "use client"
2
-
3
- import { ReadSheet, ReadSheetProps } from "./ReadSheet"
4
-
5
- /**
6
- * @deprecated 请使用 ReadSheetProps 代替
7
- */
8
- export type ReadExcelProps = ReadSheetProps
9
-
10
- /**
11
- * @deprecated 请使用 ReadSheet 代替
12
- */
13
- export const ReadExcel = ReadSheet
1
+ "use client"
2
+
3
+ import { ReadSheet, ReadSheetProps } from "./ReadSheet"
4
+
5
+ /**
6
+ * @deprecated 请使用 ReadSheetProps 代替
7
+ */
8
+ export type ReadExcelProps = ReadSheetProps
9
+
10
+ /**
11
+ * @deprecated 请使用 ReadSheet 代替
12
+ */
13
+ export const ReadExcel = ReadSheet
@@ -1,17 +1,17 @@
1
- "use client"
2
-
3
- import { WorkBookData, WorkSheetData, readSheet } from "deepsea-tools"
4
- import { FC } from "react"
5
-
6
- import { InputFile, InputFileProps } from "./InputFile"
7
-
8
- export interface ReadSheetProps extends Omit<InputFileProps<false, "arrayBuffer">, "multiple" | "accept" | "type" | "onValueChange"> {
9
- onValueChange?: <Sheet = WorkSheetData>(data: WorkBookData<Sheet>) => void
10
- }
11
-
12
- /** 专门用于读取 excel 的组件 */
13
- export const ReadSheet: FC<ReadSheetProps> = props => {
14
- const { onValueChange, ...rest } = props
15
-
16
- return <InputFile accept=".xlsx" type="arrayBuffer" onValueChange={data => onValueChange?.(readSheet(data))} {...rest} />
17
- }
1
+ "use client"
2
+
3
+ import { WorkBookData, WorkSheetData, readSheet } from "deepsea-tools"
4
+ import { FC } from "react"
5
+
6
+ import { InputFile, InputFileProps } from "./InputFile"
7
+
8
+ export interface ReadSheetProps extends Omit<InputFileProps<false, "arrayBuffer">, "multiple" | "accept" | "type" | "onValueChange"> {
9
+ onValueChange?: <Sheet = WorkSheetData>(data: WorkBookData<Sheet>) => void
10
+ }
11
+
12
+ /** 专门用于读取 excel 的组件 */
13
+ export const ReadSheet: FC<ReadSheetProps> = props => {
14
+ const { onValueChange, ...rest } = props
15
+
16
+ return <InputFile accept=".xlsx" type="arrayBuffer" onValueChange={data => onValueChange?.(readSheet(data))} {...rest} />
17
+ }
@@ -1,30 +1,30 @@
1
- "use client"
2
-
3
- import { HTMLAttributes, forwardRef } from "react"
4
-
5
- export interface RingProps extends HTMLAttributes<HTMLDivElement> {
6
- outerWidth: number
7
- innerWidth: number
8
- }
9
-
10
- /** 环形组件 */
11
- export const Ring = forwardRef<HTMLDivElement, RingProps>((props, ref) => {
12
- const { outerWidth, innerWidth, style, ...rest } = props
13
-
14
- const outerRadius = outerWidth / 2
15
-
16
- const innerRadius = innerWidth / 2
17
-
18
- return (
19
- <div
20
- ref={ref}
21
- style={{
22
- ...style,
23
- width: `${outerWidth}px`,
24
- height: `${outerWidth}px`,
25
- clipPath: `path("M0,${outerRadius} a${outerRadius},${outerRadius},0,1,0,${outerWidth},0 a${outerRadius},${outerRadius},0,1,0,-${outerWidth},0 l${outerRadius - innerRadius},0 a${innerRadius},${innerRadius},0,0,1,${innerRadius * 2},0 a${innerRadius},${innerRadius},0,0,1,-${innerRadius * 2},0 Z")`,
26
- }}
27
- {...rest}
28
- />
29
- )
30
- })
1
+ "use client"
2
+
3
+ import { HTMLAttributes, forwardRef } from "react"
4
+
5
+ export interface RingProps extends HTMLAttributes<HTMLDivElement> {
6
+ outerWidth: number
7
+ innerWidth: number
8
+ }
9
+
10
+ /** 环形组件 */
11
+ export const Ring = forwardRef<HTMLDivElement, RingProps>((props, ref) => {
12
+ const { outerWidth, innerWidth, style, ...rest } = props
13
+
14
+ const outerRadius = outerWidth / 2
15
+
16
+ const innerRadius = innerWidth / 2
17
+
18
+ return (
19
+ <div
20
+ ref={ref}
21
+ style={{
22
+ ...style,
23
+ width: `${outerWidth}px`,
24
+ height: `${outerWidth}px`,
25
+ clipPath: `path("M0,${outerRadius} a${outerRadius},${outerRadius},0,1,0,${outerWidth},0 a${outerRadius},${outerRadius},0,1,0,-${outerWidth},0 l${outerRadius - innerRadius},0 a${innerRadius},${innerRadius},0,0,1,${innerRadius * 2},0 a${innerRadius},${innerRadius},0,0,1,-${innerRadius * 2},0 Z")`,
26
+ }}
27
+ {...rest}
28
+ />
29
+ )
30
+ })