xxf_react 0.6.1 → 0.6.3
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 +21 -3
- package/dist/layout/button/XButton.d.ts +99 -0
- package/dist/layout/button/XButton.d.ts.map +1 -0
- package/dist/layout/button/XButton.js +131 -0
- package/dist/layout/index.d.ts +2 -0
- package/dist/layout/index.d.ts.map +1 -1
- package/dist/layout/index.js +2 -0
- package/dist/layout/spinner/XSpinner.d.ts +43 -0
- package/dist/layout/spinner/XSpinner.d.ts.map +1 -0
- package/dist/layout/spinner/XSpinner.js +47 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
# @xxf/react
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
React 工具库,提供常用的组件、Hooks 和工具函数。
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
4
6
|
|
|
5
7
|
```bash
|
|
6
8
|
bun install
|
|
7
9
|
```
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
## 运行
|
|
10
12
|
|
|
11
13
|
```bash
|
|
12
14
|
bun run src/index.ts
|
|
@@ -14,6 +16,22 @@ bun run src/index.ts
|
|
|
14
16
|
|
|
15
17
|
This project was created using `bun init` in bun v1.3.2. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime.
|
|
16
18
|
|
|
17
|
-
##
|
|
19
|
+
## 模块文档
|
|
20
|
+
|
|
21
|
+
| 模块 | 说明 |
|
|
22
|
+
|------|------|
|
|
23
|
+
| [event-bus](./src/event-bus/README.md) | 事件总线,支持跨 Tab 通信 |
|
|
24
|
+
| [fetch](./src/fetch/README.md) | 带超时控制的 fetch 封装 |
|
|
25
|
+
| [flow](./src/flow/README.md) | Promise 扩展,全局错误处理 |
|
|
26
|
+
| [foundation](./src/foundation/README.md) | 基础工具,性能监控 |
|
|
27
|
+
| [layout](./src/layout/README.md) | 布局组件,悬浮交互 |
|
|
28
|
+
| [media](./src/media/README.md) | 媒体组件,视频播放 |
|
|
29
|
+
| [models](./src/models/README.md) | 数据模型,API 响应类型 |
|
|
30
|
+
| [refresh](./src/refresh/README.md) | 刷新加载,分页加载更多 |
|
|
31
|
+
| [responsive](./src/responsive/README.md) | 响应式布局,设备检测 |
|
|
32
|
+
| [sse](./src/sse/README.md) | Server-Sent Events 连接管理 |
|
|
33
|
+
| [utils](./src/utils/README.md) | 工具函数,滚动定位、组件刷新 |
|
|
34
|
+
|
|
35
|
+
## 详细文档
|
|
18
36
|
|
|
19
37
|
- [PlaybackQueue 播放队列状态管理](./src/media/playback-queue-store.md)
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import React, { ButtonHTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* 加载指示器位置
|
|
4
|
+
* - `start`: 指示器在内容左侧
|
|
5
|
+
* - `center`: 指示器居中,内容隐藏(保持宽度)
|
|
6
|
+
* - `end`: 指示器在内容右侧
|
|
7
|
+
*/
|
|
8
|
+
export type LoadingGravity = 'start' | 'center' | 'end';
|
|
9
|
+
/**
|
|
10
|
+
* XButton 组件属性
|
|
11
|
+
* @extends ButtonHTMLAttributes<HTMLButtonElement> 继承原生 button 所有属性
|
|
12
|
+
*/
|
|
13
|
+
export interface XButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
14
|
+
/**
|
|
15
|
+
* 加载状态
|
|
16
|
+
* - 为 `true` 时按钮不可点击,显示加载指示器
|
|
17
|
+
* @default false
|
|
18
|
+
*/
|
|
19
|
+
loading?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* 加载指示器位置
|
|
22
|
+
* - `start`: 左侧
|
|
23
|
+
* - `center`: 居中(隐藏内容,保持宽度避免抖动)
|
|
24
|
+
* - `end`: 右侧
|
|
25
|
+
* @default 'start'
|
|
26
|
+
*/
|
|
27
|
+
loadingGravity?: LoadingGravity;
|
|
28
|
+
/**
|
|
29
|
+
* 自定义加载指示器(回调形式,懒创建)
|
|
30
|
+
* - 只有 loading=true 时才会调用
|
|
31
|
+
* - 不传则使用默认的 XSpinner
|
|
32
|
+
* - 尺寸建议使用 `em` 单位以跟随字体大小
|
|
33
|
+
* @example () => <MySpinner className="w-5 h-5" />
|
|
34
|
+
*/
|
|
35
|
+
loadingIndicator?: () => ReactNode;
|
|
36
|
+
/**
|
|
37
|
+
* 指示器与内容的间距(像素)
|
|
38
|
+
* - 仅在 `loadingGravity` 为 `start` 或 `end` 时生效
|
|
39
|
+
* @default 8
|
|
40
|
+
*/
|
|
41
|
+
loadingGap?: number;
|
|
42
|
+
/**
|
|
43
|
+
* 点击防抖等待时间(毫秒)
|
|
44
|
+
* - 防止用户快速连续点击
|
|
45
|
+
* - 使用 leading 模式:首次点击立即执行,后续点击在等待时间内被忽略
|
|
46
|
+
* - 设为 0 时禁用防抖
|
|
47
|
+
* @default 500
|
|
48
|
+
*/
|
|
49
|
+
debounceWait?: number;
|
|
50
|
+
/**
|
|
51
|
+
* 是否阻止事件冒泡
|
|
52
|
+
* @default false
|
|
53
|
+
*/
|
|
54
|
+
stopPropagation?: boolean;
|
|
55
|
+
/** 按钮内容,支持任意 ReactNode(文本、元素、组件等) */
|
|
56
|
+
children?: ReactNode;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* XButton - 支持加载状态的按钮组件
|
|
60
|
+
*
|
|
61
|
+
* @description
|
|
62
|
+
* 封装了常见的按钮加载交互:
|
|
63
|
+
* - 加载时自动禁用点击
|
|
64
|
+
* - 支持自定义加载指示器位置(左/中/右)
|
|
65
|
+
* - 居中模式保持按钮宽度,避免布局抖动
|
|
66
|
+
* - 支持 ref 转发
|
|
67
|
+
* - 支持点击防抖,防止重复提交
|
|
68
|
+
* - 不依赖外部库,纯内联样式实现
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```tsx
|
|
72
|
+
* // 基本用法
|
|
73
|
+
* <XButton loading={isLoading} onClick={handleSubmit}>
|
|
74
|
+
* 提交
|
|
75
|
+
* </XButton>
|
|
76
|
+
*
|
|
77
|
+
* // 加载指示器在左侧
|
|
78
|
+
* <XButton loading loadingGravity="start">
|
|
79
|
+
* 加载中...
|
|
80
|
+
* </XButton>
|
|
81
|
+
*
|
|
82
|
+
* // 自定义加载指示器(回调形式,懒创建)
|
|
83
|
+
* <XButton loading loadingIndicator={() => <MySpinner />}>
|
|
84
|
+
* 处理中
|
|
85
|
+
* </XButton>
|
|
86
|
+
*
|
|
87
|
+
* // 防抖点击(500ms 内只响应第一次)
|
|
88
|
+
* <XButton debounceWait={500} onClick={handleSubmit}>
|
|
89
|
+
* 提交订单
|
|
90
|
+
* </XButton>
|
|
91
|
+
*
|
|
92
|
+
* // 阻止冒泡 + 防抖
|
|
93
|
+
* <XButton debounceWait={500} stopPropagation onClick={handleSubmit}>
|
|
94
|
+
* 提交
|
|
95
|
+
* </XButton>
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
export declare const XButton: React.ForwardRefExoticComponent<XButtonProps & React.RefAttributes<HTMLButtonElement>>;
|
|
99
|
+
//# sourceMappingURL=XButton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"XButton.d.ts","sourceRoot":"","sources":["../../../src/layout/button/XButton.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAAa,oBAAoB,EAAE,SAAS,EAAgB,MAAM,OAAO,CAAC;AAIxF;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;AAExD;;;GAGG;AACH,MAAM,WAAW,YAAa,SAAQ,oBAAoB,CAAC,iBAAiB,CAAC;IACzE;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;IAEhC;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,MAAM,SAAS,CAAC;IAEnC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B,qCAAqC;IACrC,QAAQ,CAAC,EAAE,SAAS,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,eAAO,MAAM,OAAO,wFA6InB,CAAC"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import React, { forwardRef } from 'react';
|
|
3
|
+
import { useDebouncedCallback } from 'use-debounce';
|
|
4
|
+
import { XSpinner } from "../spinner/XSpinner";
|
|
5
|
+
/**
|
|
6
|
+
* XButton - 支持加载状态的按钮组件
|
|
7
|
+
*
|
|
8
|
+
* @description
|
|
9
|
+
* 封装了常见的按钮加载交互:
|
|
10
|
+
* - 加载时自动禁用点击
|
|
11
|
+
* - 支持自定义加载指示器位置(左/中/右)
|
|
12
|
+
* - 居中模式保持按钮宽度,避免布局抖动
|
|
13
|
+
* - 支持 ref 转发
|
|
14
|
+
* - 支持点击防抖,防止重复提交
|
|
15
|
+
* - 不依赖外部库,纯内联样式实现
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```tsx
|
|
19
|
+
* // 基本用法
|
|
20
|
+
* <XButton loading={isLoading} onClick={handleSubmit}>
|
|
21
|
+
* 提交
|
|
22
|
+
* </XButton>
|
|
23
|
+
*
|
|
24
|
+
* // 加载指示器在左侧
|
|
25
|
+
* <XButton loading loadingGravity="start">
|
|
26
|
+
* 加载中...
|
|
27
|
+
* </XButton>
|
|
28
|
+
*
|
|
29
|
+
* // 自定义加载指示器(回调形式,懒创建)
|
|
30
|
+
* <XButton loading loadingIndicator={() => <MySpinner />}>
|
|
31
|
+
* 处理中
|
|
32
|
+
* </XButton>
|
|
33
|
+
*
|
|
34
|
+
* // 防抖点击(500ms 内只响应第一次)
|
|
35
|
+
* <XButton debounceWait={500} onClick={handleSubmit}>
|
|
36
|
+
* 提交订单
|
|
37
|
+
* </XButton>
|
|
38
|
+
*
|
|
39
|
+
* // 阻止冒泡 + 防抖
|
|
40
|
+
* <XButton debounceWait={500} stopPropagation onClick={handleSubmit}>
|
|
41
|
+
* 提交
|
|
42
|
+
* </XButton>
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export const XButton = forwardRef(function XButton({ loading = false, loadingGravity = 'start', loadingIndicator, loadingGap = 8, debounceWait = 500, stopPropagation = false, children, onClick, disabled, style, type = 'button', ...rest }, ref) {
|
|
46
|
+
/**
|
|
47
|
+
* 获取加载指示器(懒创建)
|
|
48
|
+
* - 只在 loading=true 时才实际创建节点
|
|
49
|
+
*/
|
|
50
|
+
const getIndicator = () => { var _a; return (_a = loadingIndicator === null || loadingIndicator === void 0 ? void 0 : loadingIndicator()) !== null && _a !== void 0 ? _a : React.createElement(XSpinner, null); };
|
|
51
|
+
/**
|
|
52
|
+
* 防抖处理后的点击回调
|
|
53
|
+
* - leading: true 首次点击立即执行
|
|
54
|
+
* - trailing: false 等待时间结束后不再执行
|
|
55
|
+
*/
|
|
56
|
+
const debouncedOnClick = useDebouncedCallback((e) => {
|
|
57
|
+
onClick === null || onClick === void 0 ? void 0 : onClick(e);
|
|
58
|
+
}, debounceWait, { leading: true, trailing: false });
|
|
59
|
+
/**
|
|
60
|
+
* 点击事件处理
|
|
61
|
+
* - 阻止冒泡(可选)
|
|
62
|
+
* - loading 或 disabled 时拦截
|
|
63
|
+
* - debounceWait > 0 时使用防抖回调
|
|
64
|
+
*/
|
|
65
|
+
const handleClick = (e) => {
|
|
66
|
+
// 阻止冒泡
|
|
67
|
+
if (stopPropagation) {
|
|
68
|
+
e.stopPropagation();
|
|
69
|
+
}
|
|
70
|
+
// loading 或 disabled 时拦截
|
|
71
|
+
if (loading || disabled) {
|
|
72
|
+
e.preventDefault();
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
// 根据 debounceWait 决定是否使用防抖
|
|
76
|
+
if (debounceWait > 0) {
|
|
77
|
+
debouncedOnClick(e);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
onClick === null || onClick === void 0 ? void 0 : onClick(e);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
/** 按钮基础样式,使用 flexbox 布局 */
|
|
84
|
+
const baseStyle = {
|
|
85
|
+
display: 'inline-flex',
|
|
86
|
+
alignItems: 'center',
|
|
87
|
+
justifyContent: 'center',
|
|
88
|
+
position: 'relative',
|
|
89
|
+
// 仅在 start/end 模式下应用 gap
|
|
90
|
+
gap: loading && loadingGravity !== 'center' ? loadingGap : undefined,
|
|
91
|
+
...style,
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* 渲染按钮内容
|
|
95
|
+
* - 非加载状态:直接渲染 children
|
|
96
|
+
* - start:指示器 + children
|
|
97
|
+
* - end:children + 指示器
|
|
98
|
+
* - center:children 隐藏占位 + 指示器绝对定位居中
|
|
99
|
+
*/
|
|
100
|
+
const renderContent = () => {
|
|
101
|
+
if (!loading) {
|
|
102
|
+
return children;
|
|
103
|
+
}
|
|
104
|
+
const indicator = getIndicator();
|
|
105
|
+
switch (loadingGravity) {
|
|
106
|
+
case 'start':
|
|
107
|
+
return (React.createElement(React.Fragment, null,
|
|
108
|
+
indicator,
|
|
109
|
+
children));
|
|
110
|
+
case 'end':
|
|
111
|
+
return (React.createElement(React.Fragment, null,
|
|
112
|
+
children,
|
|
113
|
+
indicator));
|
|
114
|
+
case 'center':
|
|
115
|
+
default:
|
|
116
|
+
// children 保持可见,indicator 绝对定位叠加在上面
|
|
117
|
+
// 背景透明,可以看到 children 内容
|
|
118
|
+
return (React.createElement(React.Fragment, null,
|
|
119
|
+
children,
|
|
120
|
+
React.createElement("div", { style: {
|
|
121
|
+
position: 'absolute',
|
|
122
|
+
inset: 0,
|
|
123
|
+
display: 'flex',
|
|
124
|
+
alignItems: 'center',
|
|
125
|
+
justifyContent: 'center',
|
|
126
|
+
backgroundColor: 'transparent',
|
|
127
|
+
} }, indicator)));
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
return (React.createElement("button", { ref: ref, type: type, ...rest, style: baseStyle, disabled: disabled || loading, onClick: handleClick, "aria-busy": loading, "aria-disabled": disabled || loading }, renderContent()));
|
|
131
|
+
});
|
package/dist/layout/index.d.ts
CHANGED
|
@@ -7,4 +7,6 @@ export * from './image/XImage';
|
|
|
7
7
|
export * from './visibility/ElementVisibilityHooks';
|
|
8
8
|
export * from './virtualized/VirtualizedConfig';
|
|
9
9
|
export * from './hover/XHover';
|
|
10
|
+
export * from './button/XButton';
|
|
11
|
+
export * from './spinner/XSpinner';
|
|
10
12
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/layout/index.ts"],"names":[],"mappings":"AAAA,cAAc,gCAAgC,CAAA;AAC9C,cAAc,kCAAkC,CAAA;AAChD,cAAc,kCAAkC,CAAA;AAChD,cAAc,8BAA8B,CAAA;AAC5C,cAAc,2BAA2B,CAAA;AACzC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,qCAAqC,CAAA;AACnD,cAAc,iCAAiC,CAAA;AAC/C,cAAc,gBAAgB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/layout/index.ts"],"names":[],"mappings":"AAAA,cAAc,gCAAgC,CAAA;AAC9C,cAAc,kCAAkC,CAAA;AAChD,cAAc,kCAAkC,CAAA;AAChD,cAAc,8BAA8B,CAAA;AAC5C,cAAc,2BAA2B,CAAA;AACzC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,qCAAqC,CAAA;AACnD,cAAc,iCAAiC,CAAA;AAC/C,cAAc,gBAAgB,CAAA;AAC9B,cAAc,kBAAkB,CAAA;AAChC,cAAc,oBAAoB,CAAA"}
|
package/dist/layout/index.js
CHANGED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* XSpinner 组件属性
|
|
4
|
+
*/
|
|
5
|
+
export interface XSpinnerProps {
|
|
6
|
+
/**
|
|
7
|
+
* 自定义样式类名
|
|
8
|
+
* - 可覆盖默认的尺寸、颜色、动画等样式
|
|
9
|
+
* @example "w-8 h-8 border-blue-500"
|
|
10
|
+
*/
|
|
11
|
+
className?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* XSpinner - 轻量级加载指示器组件
|
|
15
|
+
*
|
|
16
|
+
* @description
|
|
17
|
+
* 使用 CSS border + rotate 动画实现的高性能 spinner:
|
|
18
|
+
* - 基于 div + Tailwind CSS,无 SVG 解析开销
|
|
19
|
+
* - 尺寸使用 `1em`,自动跟随父元素字体大小
|
|
20
|
+
* - 默认白色边框,适合深色背景
|
|
21
|
+
* - 可通过 className 完全自定义样式
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```tsx
|
|
25
|
+
* // 基本用法(跟随父元素字体大小)
|
|
26
|
+
* <XSpinner />
|
|
27
|
+
*
|
|
28
|
+
* // 自定义尺寸
|
|
29
|
+
* <XSpinner className="w-8 h-8" />
|
|
30
|
+
*
|
|
31
|
+
* // 自定义颜色(深色主题)
|
|
32
|
+
* <XSpinner className="border-gray-800 border-t-transparent" />
|
|
33
|
+
*
|
|
34
|
+
* // 在按钮中使用
|
|
35
|
+
* <button className="text-lg">
|
|
36
|
+
* <XSpinner /> 加载中...
|
|
37
|
+
* </button>
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* @see XButton - 内置 XSpinner 作为默认加载指示器
|
|
41
|
+
*/
|
|
42
|
+
export declare const XSpinner: ({ className }?: XSpinnerProps) => React.JSX.Element;
|
|
43
|
+
//# sourceMappingURL=XSpinner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"XSpinner.d.ts","sourceRoot":"","sources":["../../../src/layout/spinner/XSpinner.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B;;GAEG;AACH,MAAM,WAAW,aAAa;IAC1B;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,QAAQ,GAAI,gBAAa,aAAkB,sBAoBvD,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { cn } from "tailwind-variants";
|
|
4
|
+
/**
|
|
5
|
+
* XSpinner - 轻量级加载指示器组件
|
|
6
|
+
*
|
|
7
|
+
* @description
|
|
8
|
+
* 使用 CSS border + rotate 动画实现的高性能 spinner:
|
|
9
|
+
* - 基于 div + Tailwind CSS,无 SVG 解析开销
|
|
10
|
+
* - 尺寸使用 `1em`,自动跟随父元素字体大小
|
|
11
|
+
* - 默认白色边框,适合深色背景
|
|
12
|
+
* - 可通过 className 完全自定义样式
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```tsx
|
|
16
|
+
* // 基本用法(跟随父元素字体大小)
|
|
17
|
+
* <XSpinner />
|
|
18
|
+
*
|
|
19
|
+
* // 自定义尺寸
|
|
20
|
+
* <XSpinner className="w-8 h-8" />
|
|
21
|
+
*
|
|
22
|
+
* // 自定义颜色(深色主题)
|
|
23
|
+
* <XSpinner className="border-gray-800 border-t-transparent" />
|
|
24
|
+
*
|
|
25
|
+
* // 在按钮中使用
|
|
26
|
+
* <button className="text-lg">
|
|
27
|
+
* <XSpinner /> 加载中...
|
|
28
|
+
* </button>
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* @see XButton - 内置 XSpinner 作为默认加载指示器
|
|
32
|
+
*/
|
|
33
|
+
export const XSpinner = ({ className } = {}) => (React.createElement("div", { style: {
|
|
34
|
+
// 使用内联样式确保 em 单位正确跟随 font-size
|
|
35
|
+
width: '1em',
|
|
36
|
+
height: '1em',
|
|
37
|
+
// 边框粗细也跟随字体大小
|
|
38
|
+
borderWidth: '0.125em',
|
|
39
|
+
}, className: cn(
|
|
40
|
+
// 边框样式:白色圆环,顶部透明形成缺口
|
|
41
|
+
"border-solid border-current border-t-transparent rounded-full",
|
|
42
|
+
// 动画:无限旋转
|
|
43
|
+
"animate-spin",
|
|
44
|
+
// 透明度:略微降低避免过亮
|
|
45
|
+
"opacity-80",
|
|
46
|
+
// 用户自定义类名
|
|
47
|
+
className) }));
|