@tendaui/components 1.0.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.
Files changed (245) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +176 -0
  3. package/alert/Alert.tsx +147 -0
  4. package/alert/defaultProps.ts +3 -0
  5. package/alert/index.ts +9 -0
  6. package/alert/style/css.js +1 -0
  7. package/alert/style/index.js +1 -0
  8. package/alert/type.ts +44 -0
  9. package/badge/Badge.tsx +85 -0
  10. package/badge/defaultProps.ts +10 -0
  11. package/badge/index.ts +9 -0
  12. package/badge/style/css.js +1 -0
  13. package/badge/style/index.js +1 -0
  14. package/badge/type.ts +51 -0
  15. package/button/Button.tsx +95 -0
  16. package/button/defaultProps.ts +13 -0
  17. package/button/index.ts +7 -0
  18. package/button/style/css.js +1 -0
  19. package/button/style/index.js +1 -0
  20. package/button/type.ts +82 -0
  21. package/checkbox/Checkbox.tsx +19 -0
  22. package/checkbox/CheckboxGroup.tsx +207 -0
  23. package/checkbox/defaultProps.ts +14 -0
  24. package/checkbox/index.ts +10 -0
  25. package/checkbox/style/css.js +1 -0
  26. package/checkbox/style/index.js +1 -0
  27. package/checkbox/type.ts +117 -0
  28. package/common/Check.tsx +131 -0
  29. package/common/FakeArrow.tsx +36 -0
  30. package/common/PluginContainer.tsx +21 -0
  31. package/common/Portal.tsx +67 -0
  32. package/common.ts +76 -0
  33. package/config-provider/ConfigContext.tsx +21 -0
  34. package/config-provider/ConfigProvider.tsx +53 -0
  35. package/config-provider/index.ts +9 -0
  36. package/config-provider/type.ts +1062 -0
  37. package/dialog/Dialog.tsx +254 -0
  38. package/dialog/DialogCard.tsx +152 -0
  39. package/dialog/defaultProps.ts +25 -0
  40. package/dialog/hooks/useDialogDrag.ts +50 -0
  41. package/dialog/hooks/useDialogEsc.ts +31 -0
  42. package/dialog/hooks/useDialogPosition.ts +36 -0
  43. package/dialog/hooks/useLockStyle.ts +54 -0
  44. package/dialog/index.ts +13 -0
  45. package/dialog/plugin.tsx +78 -0
  46. package/dialog/style/css.js +1 -0
  47. package/dialog/style/index.js +1 -0
  48. package/dialog/type.ts +241 -0
  49. package/dialog/utils.ts +4 -0
  50. package/form/Form.tsx +136 -0
  51. package/form/FormContext.tsx +64 -0
  52. package/form/FormItem.tsx +554 -0
  53. package/form/FormList.tsx +303 -0
  54. package/form/const.ts +6 -0
  55. package/form/defaultProps.ts +26 -0
  56. package/form/formModel.ts +117 -0
  57. package/form/hooks/interface.ts +20 -0
  58. package/form/hooks/useForm.ts +122 -0
  59. package/form/hooks/useFormItemInitialData.ts +95 -0
  60. package/form/hooks/useFormItemStyle.tsx +122 -0
  61. package/form/hooks/useInstance.tsx +275 -0
  62. package/form/hooks/useWatch.ts +42 -0
  63. package/form/index.ts +11 -0
  64. package/form/style/css.js +1 -0
  65. package/form/style/index.js +1 -0
  66. package/form/type.ts +519 -0
  67. package/form/utils/index.ts +69 -0
  68. package/hooks/useAttach.ts +24 -0
  69. package/hooks/useCommonClassName.ts +45 -0
  70. package/hooks/useConfig.ts +3 -0
  71. package/hooks/useControlled.ts +39 -0
  72. package/hooks/useDefaultProps.ts +16 -0
  73. package/hooks/useDomCallback.ts +13 -0
  74. package/hooks/useDomRefCallback.ts +12 -0
  75. package/hooks/useDragSorter.tsx +151 -0
  76. package/hooks/useEventCallback.ts +47 -0
  77. package/hooks/useGlobalConfig.ts +14 -0
  78. package/hooks/useGlobalIcon.ts +14 -0
  79. package/hooks/useLastest.ts +13 -0
  80. package/hooks/useLayoutEffect.ts +7 -0
  81. package/hooks/useMouseEvent.ts +142 -0
  82. package/hooks/useMutationObserver.ts +56 -0
  83. package/hooks/usePopper.ts +189 -0
  84. package/hooks/useRipple.ts +0 -0
  85. package/hooks/useSetState.ts +25 -0
  86. package/hooks/useVirtualScroll.ts +246 -0
  87. package/hooks/useWindowSize.ts +31 -0
  88. package/index.ts +70 -0
  89. package/input/Input.tsx +383 -0
  90. package/input/InputGroup.tsx +29 -0
  91. package/input/defaultProps.ts +22 -0
  92. package/input/index.ts +11 -0
  93. package/input/style/css.js +1 -0
  94. package/input/style/index.js +1 -0
  95. package/input/type.ts +219 -0
  96. package/loading/Gradient.tsx +36 -0
  97. package/loading/Loading.tsx +169 -0
  98. package/loading/circleAdapter.ts +44 -0
  99. package/loading/defaultProps.ts +12 -0
  100. package/loading/index.ts +13 -0
  101. package/loading/style/css.js +1 -0
  102. package/loading/style/index.js +1 -0
  103. package/loading/type.ts +71 -0
  104. package/loading/utils/setStyle.ts +13 -0
  105. package/myform/index.ts +0 -0
  106. package/notification/Notify.ts +24 -0
  107. package/notification/NotifyContainer.tsx +90 -0
  108. package/notification/NotifyContext.tsx +173 -0
  109. package/notification/NotifyItem.tsx +121 -0
  110. package/notification/index.ts +3 -0
  111. package/notification/style/css.js +1 -0
  112. package/notification/style/index.js +1 -0
  113. package/notification/type.ts +23 -0
  114. package/package.json +52 -0
  115. package/popup/Popup.tsx +264 -0
  116. package/popup/defaultProps.ts +13 -0
  117. package/popup/hooks/useTrigger.ts +276 -0
  118. package/popup/index.ts +6 -0
  119. package/popup/style/css.js +1 -0
  120. package/popup/style/index.js +1 -0
  121. package/popup/type.ts +130 -0
  122. package/portal/Portal.tsx +63 -0
  123. package/portal/index.ts +1 -0
  124. package/select/Option.tsx +162 -0
  125. package/select/OptionGroup.tsx +30 -0
  126. package/select/PopupContent.tsx +271 -0
  127. package/select/Select.tsx +586 -0
  128. package/select/defaultProps.ts +27 -0
  129. package/select/hooks/useOptions.ts +120 -0
  130. package/select/hooks/usePanelVirtualScroll.ts +111 -0
  131. package/select/index.ts +9 -0
  132. package/select/style/css.js +1 -0
  133. package/select/style/index.js +2 -0
  134. package/select/type.ts +382 -0
  135. package/select/utils/helper.ts +256 -0
  136. package/select-input/SelectInput.tsx +98 -0
  137. package/select-input/defaultProps.ts +15 -0
  138. package/select-input/hook/useMultiple.tsx +100 -0
  139. package/select-input/hook/useOverlayInnerStyle.ts +84 -0
  140. package/select-input/hook/useSingle.tsx +112 -0
  141. package/select-input/index.ts +6 -0
  142. package/select-input/interface.ts +18 -0
  143. package/select-input/style/css.js +1 -0
  144. package/select-input/style/index.js +1 -0
  145. package/select-input/type.ts +280 -0
  146. package/space/defaultProps.ts +0 -0
  147. package/space/index.ts +0 -0
  148. package/space/type.ts +0 -0
  149. package/style/index.js +2 -0
  150. package/styles/_global.scss +39 -0
  151. package/styles/_vars.scss +386 -0
  152. package/styles/components/alert/_index.scss +175 -0
  153. package/styles/components/alert/_vars.scss +39 -0
  154. package/styles/components/badge/_index.scss +70 -0
  155. package/styles/components/badge/_vars.scss +25 -0
  156. package/styles/components/button/_index.scss +511 -0
  157. package/styles/components/button/_mixins.scss +39 -0
  158. package/styles/components/button/_vars.scss +122 -0
  159. package/styles/components/checkbox/_index.scss +158 -0
  160. package/styles/components/checkbox/_mixin.scss +0 -0
  161. package/styles/components/checkbox/_var.scss +60 -0
  162. package/styles/components/dialog/_animate.scss +135 -0
  163. package/styles/components/dialog/_index.scss +311 -0
  164. package/styles/components/dialog/_mixins.scss +0 -0
  165. package/styles/components/dialog/_vars.scss +59 -0
  166. package/styles/components/form/_index.scss +174 -0
  167. package/styles/components/form/_mixins.scss +76 -0
  168. package/styles/components/form/_vars.scss +100 -0
  169. package/styles/components/input/_index.scss +349 -0
  170. package/styles/components/input/_map.scss +0 -0
  171. package/styles/components/input/_mixins.scss +116 -0
  172. package/styles/components/input/_vars.scss +134 -0
  173. package/styles/components/loading/_index.scss +112 -0
  174. package/styles/components/loading/_vars.scss +39 -0
  175. package/styles/components/notification/_index.scss +160 -0
  176. package/styles/components/notification/_mixins.scss +12 -0
  177. package/styles/components/notification/_vars.scss +59 -0
  178. package/styles/components/popup/_index.scss +82 -0
  179. package/styles/components/popup/_mixin.scss +149 -0
  180. package/styles/components/popup/_var.scss +31 -0
  181. package/styles/components/select/_index.scss +290 -0
  182. package/styles/components/select/_var.scss +65 -0
  183. package/styles/components/select-input/_index.scss +5 -0
  184. package/styles/components/select-input/_var.scss +3 -0
  185. package/styles/components/switch/_index.scss +279 -0
  186. package/styles/components/switch/_mixins.scss +0 -0
  187. package/styles/components/switch/_vars.scss +61 -0
  188. package/styles/components/tag/_index.scss +316 -0
  189. package/styles/components/tag/_var.scss +85 -0
  190. package/styles/components/tag-input/_index.scss +163 -0
  191. package/styles/components/tag-input/_vars.scss +16 -0
  192. package/styles/globals.css +250 -0
  193. package/styles/mixins/_focus.scss +7 -0
  194. package/styles/mixins/_layout.scss +32 -0
  195. package/styles/mixins/_reset.scss +10 -0
  196. package/styles/mixins/_scrollbar.scss +31 -0
  197. package/styles/mixins/_text.scss +48 -0
  198. package/styles/rillple.css +16 -0
  199. package/styles/scrollbar.css +42 -0
  200. package/styles/themes/_dark.scss +191 -0
  201. package/styles/themes/_font.scss +79 -0
  202. package/styles/themes/_index.scss +5 -0
  203. package/styles/themes/_light.scss +190 -0
  204. package/styles/themes/_radius.scss +9 -0
  205. package/styles/themes/_size.scss +68 -0
  206. package/styles/themes.css +66 -0
  207. package/styles/utilities/_animation.scss +57 -0
  208. package/styles/utilities/_tips.scss +9 -0
  209. package/switch/Switch.tsx +120 -0
  210. package/switch/defaultProps.ts +3 -0
  211. package/switch/index.ts +7 -0
  212. package/switch/style/css.js +1 -0
  213. package/switch/style/index.js +1 -0
  214. package/switch/type.ts +46 -0
  215. package/tag/Tag.tsx +149 -0
  216. package/tag/defaultProps.ts +19 -0
  217. package/tag/index.ts +8 -0
  218. package/tag/style/css.js +1 -0
  219. package/tag/style/index.js +1 -0
  220. package/tag/type.ts +170 -0
  221. package/tag-input/TagInput.tsx +215 -0
  222. package/tag-input/defaultProps.ts +15 -0
  223. package/tag-input/hooks/useHover.ts +28 -0
  224. package/tag-input/hooks/useTagList.tsx +131 -0
  225. package/tag-input/hooks/useTagScroll.ts +105 -0
  226. package/tag-input/index.ts +9 -0
  227. package/tag-input/style/css.js +1 -0
  228. package/tag-input/style/index.js +1 -0
  229. package/tag-input/type.ts +224 -0
  230. package/tag-input/useTagList.tsx +131 -0
  231. package/utils/composeRefs.ts +14 -0
  232. package/utils/dom.ts +29 -0
  233. package/utils/forwardRefWithStatics.ts +12 -0
  234. package/utils/getScrollbarWidth.ts +11 -0
  235. package/utils/helper.ts +161 -0
  236. package/utils/isFragment.ts +22 -0
  237. package/utils/listener.ts +37 -0
  238. package/utils/noop.ts +3 -0
  239. package/utils/parentTNode.ts +38 -0
  240. package/utils/parseTNode.ts +38 -0
  241. package/utils/react-render.ts +108 -0
  242. package/utils/ref.ts +6 -0
  243. package/utils/refs.ts +81 -0
  244. package/utils/style.ts +60 -0
  245. package/utils/transition.ts +28 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 TendaUI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,176 @@
1
+ # @tendaui/components
2
+
3
+ TendaUI React 组件库的源代码包,包含所有 UI 组件的实现。
4
+
5
+ ## 📦 安装
6
+
7
+ 在 monorepo 的其他包中使用 `workspace` 协议安装:
8
+
9
+ ```bash
10
+ pnpm add @tendaui/components@workspace:*
11
+ ```
12
+
13
+ ## 🔗 在其他包中使用
14
+
15
+ ### 1. 在 package.json 中添加依赖
16
+
17
+ ```json
18
+ {
19
+ "dependencies": {
20
+ "@tendaui/components": "workspace:*"
21
+ }
22
+ }
23
+ ```
24
+
25
+ ### 2. 在代码中导入使用
26
+
27
+ #### 导入单个组件
28
+
29
+ ```tsx
30
+ import { Button } from "@tendaui/components";
31
+ import "@tendaui/components/button/style";
32
+
33
+ function App() {
34
+ return <Button type="primary">点击我</Button>;
35
+ }
36
+ ```
37
+
38
+ #### 导入多个组件
39
+
40
+ ```tsx
41
+ import { Button, Input, Form } from "@tendaui/components";
42
+ import "@tendaui/components/styles/globals.css";
43
+
44
+ function App() {
45
+ return (
46
+ <Form>
47
+ <Input placeholder="请输入" />
48
+ <Button type="primary">提交</Button>
49
+ </Form>
50
+ );
51
+ }
52
+ ```
53
+
54
+ #### 按需导入组件
55
+
56
+ ```tsx
57
+ // 导入单个组件的所有导出
58
+ import Button from "@tendaui/components/button";
59
+ import "@tendaui/components/button/style";
60
+
61
+ // 或者导入特定文件
62
+ import { Button } from "@tendaui/components/button";
63
+ ```
64
+
65
+ #### 导入 Hooks
66
+
67
+ ```tsx
68
+ import { useConfig, useControlled } from "@tendaui/components/hooks";
69
+ ```
70
+
71
+ #### 导入工具函数
72
+
73
+ ```tsx
74
+ import { composeRefs, parseTNode } from "@tendaui/components/utils";
75
+ ```
76
+
77
+ ## 📝 TypeScript 支持
78
+
79
+ 如果需要在 TypeScript 项目中使用,可以在 `tsconfig.json` 中添加路径映射:
80
+
81
+ ```json
82
+ {
83
+ "compilerOptions": {
84
+ "paths": {
85
+ "@tendaui/components": ["../../packages/components"],
86
+ "@tendaui/components/*": ["../../packages/components/*"]
87
+ }
88
+ }
89
+ }
90
+ ```
91
+
92
+ ## 🎯 使用场景
93
+
94
+ ### 场景 1: 在 `tendaui-react` 包中使用
95
+
96
+ `tendaui-react` 包可以依赖 `@tendaui/components` 来构建最终发布的包:
97
+
98
+ ```json
99
+ {
100
+ "name": "tendaui-react",
101
+ "dependencies": {
102
+ "@tendaui/components": "workspace:*"
103
+ }
104
+ }
105
+ ```
106
+
107
+ ### 场景 2: 在文档包中使用
108
+
109
+ 在 Storybook 或其他文档工具中直接使用组件:
110
+
111
+ ```tsx
112
+ import { Button } from "@tendaui/components";
113
+ import { Meta, Story } from "@storybook/react";
114
+
115
+ export default {
116
+ title: "Components/Button",
117
+ component: Button
118
+ } as Meta;
119
+ ```
120
+
121
+ ### 场景 3: 在测试中使用
122
+
123
+ 在测试文件中导入组件进行测试:
124
+
125
+ ```tsx
126
+ import { render, screen } from "@testing-library/react";
127
+ import { Button } from "@tendaui/components";
128
+
129
+ test("renders button", () => {
130
+ render(<Button>Test</Button>);
131
+ expect(screen.getByText("Test")).toBeInTheDocument();
132
+ });
133
+ ```
134
+
135
+ ## 📋 可用组件
136
+
137
+ - `Alert` - 警告提示
138
+ - `Badge` - 徽标
139
+ - `Button` - 按钮
140
+ - `Checkbox` - 复选框
141
+ - `ConfigProvider` - 全局配置
142
+ - `Dialog` - 对话框
143
+ - `Form` - 表单
144
+ - `Input` - 输入框
145
+ - `Loading` - 加载中
146
+ - `Notification` - 通知
147
+ - `Popup` - 弹出层
148
+ - `Select` - 选择器
149
+ - `SelectInput` - 选择输入框
150
+ - `Switch` - 开关
151
+ - `Tag` - 标签
152
+ - `TagInput` - 标签输入框
153
+
154
+ ## 🔧 开发
155
+
156
+ ### 本地开发
157
+
158
+ 由于这是一个源代码包,修改组件代码后,使用它的包会自动看到更改(如果配置了正确的构建工具)。
159
+
160
+ ### 构建
161
+
162
+ 如果需要构建这个包,可以添加构建脚本:
163
+
164
+ ```json
165
+ {
166
+ "scripts": {
167
+ "build": "tsc --build"
168
+ }
169
+ }
170
+ ```
171
+
172
+ ## 📚 相关文档
173
+
174
+ - [Monorepo 最佳实践](../../MONOREPO.md)
175
+ - [发布指南](../../PUBLISH.md)
176
+ - [Lerna 使用指南](../../LERNA.md)
@@ -0,0 +1,147 @@
1
+ import React, { forwardRef, useRef } from "react";
2
+ import classNames from "classnames";
3
+ import {
4
+ IconClose as TdCloseIcon,
5
+ IconInfoCircle as TdInfoCircleFilledIcon,
6
+ IconCheckCircleStroked as TdCheckCircleFilledIcon,
7
+ IconAlertTriangle as TdErrorCircleFilledIcon
8
+ } from "@tendaui/icons";
9
+
10
+ import { CSSTransition } from "react-transition-group";
11
+ import parseTNode from "../utils/parseTNode";
12
+ import noop from "../utils/noop";
13
+
14
+ import useConfig from "../hooks/useConfig";
15
+ import useGlobalIcon from "../hooks/useGlobalIcon";
16
+ import { TdAlertProps } from "./type";
17
+ import { StyledProps } from "../common";
18
+ import { alertDefaultProps } from "./defaultProps";
19
+ import composeRefs from "../utils/composeRefs";
20
+ import useDefaultProps from "../hooks/useDefaultProps";
21
+
22
+ const transitionTime = 200;
23
+
24
+ export interface AlertProps extends TdAlertProps, StyledProps {}
25
+
26
+ const Alert = forwardRef<HTMLDivElement, AlertProps>((props, ref) => {
27
+ const { classPrefix } = useConfig();
28
+ // const [local, t] = useLocaleReceiver('alert');
29
+ const { CloseIcon, InfoCircleFilledIcon, CheckCircleFilledIcon, ErrorCircleFilledIcon } = useGlobalIcon({
30
+ CloseIcon: TdCloseIcon,
31
+ InfoCircleFilledIcon: TdInfoCircleFilledIcon,
32
+ CheckCircleFilledIcon: TdCheckCircleFilledIcon,
33
+ ErrorCircleFilledIcon: TdErrorCircleFilledIcon
34
+ });
35
+
36
+ const {
37
+ message,
38
+ title,
39
+ operation,
40
+ theme,
41
+ icon,
42
+ closeBtn,
43
+ maxLine,
44
+ onClose,
45
+ className,
46
+ onClosed = noop,
47
+ ...alertProps
48
+ } = useDefaultProps(props, alertDefaultProps);
49
+
50
+ const [closed, setClosed] = React.useState(false);
51
+ const [collapsed, setCollapsed] = React.useState(true);
52
+ const nodeRef = useRef<HTMLDivElement>(null);
53
+
54
+ const iconMap = {
55
+ success: CheckCircleFilledIcon,
56
+ info: InfoCircleFilledIcon,
57
+ error: ErrorCircleFilledIcon,
58
+ warning: ErrorCircleFilledIcon
59
+ };
60
+
61
+ const handleClose = (e: React.MouseEvent<HTMLDivElement>) => {
62
+ setClosed(true);
63
+ onClose?.({ e });
64
+ };
65
+
66
+ const handleCollapse = () => {
67
+ setCollapsed((collapsed) => !collapsed);
68
+ };
69
+
70
+ const renderIconNode = () => {
71
+ if (React.isValidElement(icon)) return icon;
72
+ return React.createElement(iconMap[theme], { className: "t-icon" });
73
+ };
74
+
75
+ const renderMessage = () => {
76
+ if (+maxLine > 0 && Array.isArray(message)) {
77
+ return (
78
+ <div className={`${classPrefix}-alert__description`}>
79
+ {message.map((item, index) => {
80
+ if (collapsed) {
81
+ if (index < +maxLine) {
82
+ return <div key={index}>{item}</div>;
83
+ }
84
+ } else {
85
+ return <div key={index}>{item}</div>;
86
+ }
87
+ return true;
88
+ })}
89
+ {+maxLine < message.length && (
90
+ <div className={`${classPrefix}-alert__collapse`} onClick={handleCollapse}>
91
+ {collapsed ? "展开" : "收起"}
92
+ </div>
93
+ )}
94
+ </div>
95
+ );
96
+ }
97
+ return <div className={`${classPrefix}-alert__description`}>{message}</div>;
98
+ };
99
+
100
+ // close 属性变更为 closeBtn,close废弃后可删除。(需兼容标签上直接写close和closeBtn的场景)
101
+ const isUsingClose = Reflect.has(props, "close");
102
+ const closeNode = isUsingClose ? props.closeBtn : closeBtn;
103
+ if (isUsingClose) {
104
+ console.warn("TAlert", "prop `close` is going to be deprecated, please use `closeBtn` instead.");
105
+ }
106
+ const renderClose = () => {
107
+ if (closeNode === false) return null;
108
+ return (
109
+ <div className={`${classPrefix}-alert__close`} onClick={handleClose}>
110
+ {parseTNode(closeNode, undefined, <CloseIcon className="t-icon"></CloseIcon>)}
111
+ </div>
112
+ );
113
+ };
114
+
115
+ return (
116
+ <CSSTransition
117
+ in={!closed}
118
+ unmountOnExit
119
+ classNames={{
120
+ exitActive: `${classPrefix}-alert--closing`
121
+ }}
122
+ nodeRef={nodeRef}
123
+ timeout={transitionTime}
124
+ onExited={onClosed}
125
+ >
126
+ <div
127
+ ref={composeRefs(ref, nodeRef)}
128
+ className={classNames(`${classPrefix}-alert`, `${classPrefix}-alert--${theme}`, className)}
129
+ {...alertProps}
130
+ >
131
+ <div className={`${classPrefix}-alert__icon`}>{renderIconNode()}</div>
132
+ <div className={`${classPrefix}-alert__content`}>
133
+ {title ? <div className={`${classPrefix}-alert__title`}>{title}</div> : null}
134
+ <div className={`${classPrefix}-alert__message`}>
135
+ {renderMessage()}
136
+ {operation ? <div className={`${classPrefix}-alert__operation`}>{parseTNode(operation)}</div> : null}
137
+ </div>
138
+ </div>
139
+ {renderClose()}
140
+ </div>
141
+ </CSSTransition>
142
+ );
143
+ });
144
+
145
+ Alert.displayName = "Alert";
146
+
147
+ export default Alert;
@@ -0,0 +1,3 @@
1
+ import { TdAlertProps } from "./type";
2
+
3
+ export const alertDefaultProps: TdAlertProps = { closeBtn: false, maxLine: 0, theme: "info" };
package/alert/index.ts ADDED
@@ -0,0 +1,9 @@
1
+ import _Alert from "./Alert";
2
+
3
+ import "./style/index.js";
4
+
5
+ export type { AlertProps } from "./Alert";
6
+ export * from "./type";
7
+
8
+ export const Alert = _Alert;
9
+ export default Alert;
@@ -0,0 +1 @@
1
+ import "./index.css";
@@ -0,0 +1 @@
1
+ import "../../styles/components/alert/_index.scss";
package/alert/type.ts ADDED
@@ -0,0 +1,44 @@
1
+ import { TNode, TElement } from "../common";
2
+ import { MouseEvent } from "react";
3
+
4
+ export interface TdAlertProps {
5
+ /**
6
+ * 关闭按钮。值为 true 则显示默认关闭按钮;值为 false 则不显示按钮;值类型为 string 则直接显示;值类型为 Function 则可以自定关闭按钮
7
+ * @default false
8
+ */
9
+ closeBtn?: TNode;
10
+ /**
11
+ * 图标
12
+ */
13
+ icon?: TElement;
14
+ /**
15
+ * 内容显示最大行数,超出的内容会折叠收起,用户点击后再展开。值为 0 表示不折叠
16
+ * @default 0
17
+ */
18
+ maxLine?: number;
19
+ /**
20
+ * 内容(子元素)
21
+ */
22
+ message?: TNode;
23
+ /**
24
+ * 跟在告警内容后面的操作区
25
+ */
26
+ operation?: TElement;
27
+ /**
28
+ * 组件风格
29
+ * @default info
30
+ */
31
+ theme?: "success" | "info" | "warning" | "error";
32
+ /**
33
+ * 标题
34
+ */
35
+ title?: TNode;
36
+ /**
37
+ * 关闭按钮点击时触发
38
+ */
39
+ onClose?: (context: { e: MouseEvent<HTMLDivElement> }) => void;
40
+ /**
41
+ * 告警提示框关闭动画结束后触发
42
+ */
43
+ onClosed?: () => void;
44
+ }
@@ -0,0 +1,85 @@
1
+ import React, { forwardRef } from "react";
2
+ import classNames from "classnames";
3
+ import { StyledProps } from "../common";
4
+ import useConfig from "../hooks/useConfig";
5
+ import { TdBadgeProps } from "./type";
6
+ import { badgeDefaultProps } from "./defaultProps";
7
+ import useDefaultProps from "../hooks/useDefaultProps";
8
+
9
+ export interface BadgeProps extends TdBadgeProps, StyledProps {}
10
+
11
+ const Badge = forwardRef<HTMLSpanElement, BadgeProps>((props, ref) => {
12
+ const {
13
+ color,
14
+ dot,
15
+ maxCount,
16
+ count,
17
+ size,
18
+ shape,
19
+ showZero,
20
+ offset,
21
+ className,
22
+ content,
23
+ children,
24
+ style,
25
+ ...restProps
26
+ } = useDefaultProps<BadgeProps>(props, badgeDefaultProps);
27
+ const { classPrefix } = useConfig();
28
+
29
+ const childNode = content || children;
30
+
31
+ const badgeClassName = classNames(
32
+ !childNode && `${classPrefix}-badge--static`,
33
+ dot ? `${classPrefix}-badge--dot` : `${classPrefix}-badge--${shape}`,
34
+ size === "small" && `${classPrefix}-size-s`,
35
+ !childNode && className
36
+ );
37
+ const getDisplayCount = () => {
38
+ if (typeof count === "number" && count > maxCount) {
39
+ return `${maxCount}+`;
40
+ }
41
+ return count;
42
+ };
43
+
44
+ let isHidden = !count;
45
+ if (typeof count === "number") {
46
+ isHidden = count < 1 && !showZero;
47
+ }
48
+
49
+ const getStyle = () => {
50
+ const mergedStyle: React.CSSProperties = { ...style };
51
+ if (color) {
52
+ mergedStyle.backgroundColor = color;
53
+ }
54
+ if (offset) {
55
+ if (offset[0]) {
56
+ mergedStyle.right = +offset[0];
57
+ }
58
+ if (offset[1]) {
59
+ mergedStyle.marginTop = +offset[1];
60
+ }
61
+ }
62
+ return mergedStyle;
63
+ };
64
+
65
+ const badge = !isHidden ? (
66
+ <span {...(childNode ? {} : restProps)} className={badgeClassName} style={getStyle()}>
67
+ {!dot ? getDisplayCount() : null}
68
+ </span>
69
+ ) : null;
70
+
71
+ if (!childNode) {
72
+ return badge;
73
+ }
74
+
75
+ return (
76
+ <span {...restProps} className={classNames(`${classPrefix}-badge`, className)} ref={ref}>
77
+ {childNode}
78
+ {badge}
79
+ </span>
80
+ );
81
+ });
82
+
83
+ Badge.displayName = "Badge";
84
+
85
+ export default Badge;
@@ -0,0 +1,10 @@
1
+ import { TdBadgeProps } from "./type";
2
+
3
+ export const badgeDefaultProps: TdBadgeProps = {
4
+ count: 0,
5
+ dot: false,
6
+ maxCount: 99,
7
+ shape: "circle",
8
+ showZero: false,
9
+ size: "medium"
10
+ };
package/badge/index.ts ADDED
@@ -0,0 +1,9 @@
1
+ import _Badge from "./Badge";
2
+
3
+ import "./style/index.js";
4
+
5
+ export type { BadgeProps } from "./Badge";
6
+ export * from "./type";
7
+
8
+ export const Badge = _Badge;
9
+ export default Badge;
@@ -0,0 +1 @@
1
+ import "./index.css";
@@ -0,0 +1 @@
1
+ import "../../styles/components/badge/_index.scss";
package/badge/type.ts ADDED
@@ -0,0 +1,51 @@
1
+ import { TNode } from "../common";
2
+
3
+ export interface TdBadgeProps {
4
+ /**
5
+ * 徽标内容,同 content
6
+ */
7
+ children?: TNode;
8
+ /**
9
+ * 颜色
10
+ * @default ''
11
+ */
12
+ color?: string;
13
+ /**
14
+ * 徽标内容
15
+ */
16
+ content?: TNode;
17
+ /**
18
+ * 徽标右上角内容。可以是数字,也可以是文字。如:'new'/3/99+
19
+ * @default 0
20
+ */
21
+ count?: TNode;
22
+ /**
23
+ * 是否为红点
24
+ * @default false
25
+ */
26
+ dot?: boolean;
27
+ /**
28
+ * 封顶的数字值
29
+ * @default 99
30
+ */
31
+ maxCount?: number;
32
+ /**
33
+ * 设置状态点的位置偏移,示例:[-10, 20] 或 ['10em', '8rem']
34
+ */
35
+ offset?: Array<string | number>;
36
+ /**
37
+ * 形状
38
+ * @default circle
39
+ */
40
+ shape?: "circle" | "round";
41
+ /**
42
+ * 当数值为 0 时,是否展示徽标
43
+ * @default false
44
+ */
45
+ showZero?: boolean;
46
+ /**
47
+ * 尺寸
48
+ * @default medium
49
+ */
50
+ size?: "small" | "medium";
51
+ }
@@ -0,0 +1,95 @@
1
+ import React, { useMemo, forwardRef } from "react";
2
+ import classNames from "classnames";
3
+ import useConfig from "../hooks/useConfig";
4
+ import Loading from "../loading";
5
+ import { TdButtonProps } from "./type";
6
+ import { buttonDefaultProps } from "./defaultProps";
7
+ import parseTNode from "../utils/parseTNode";
8
+ import useDefaultProps from "../hooks/useDefaultProps";
9
+
10
+ export interface ButtonProps
11
+ extends Omit<React.AllHTMLAttributes<HTMLElement>, "content" | "shape" | "size" | "type" | "children">,
12
+ TdButtonProps {}
13
+
14
+ const Button = forwardRef((originProps: ButtonProps, ref: React.ForwardedRef<HTMLElement>) => {
15
+ const props = useDefaultProps(originProps, buttonDefaultProps);
16
+ const {
17
+ type,
18
+ theme,
19
+ variant,
20
+ icon,
21
+ disabled,
22
+ loading,
23
+ size,
24
+ block,
25
+ ghost,
26
+ shape,
27
+ children,
28
+ content,
29
+ className,
30
+ suffix,
31
+ href,
32
+ tag,
33
+ onClick,
34
+ ...buttonProps
35
+ } = props;
36
+
37
+ const { classPrefix } = useConfig();
38
+
39
+ const renderChildren = content ?? children;
40
+
41
+ let iconNode = icon;
42
+ if (loading) iconNode = <Loading loading={loading} inheritColor={true} />;
43
+
44
+ const renderTheme = useMemo(() => {
45
+ if (!theme) {
46
+ if (variant === "base") return "primary";
47
+ return "default";
48
+ }
49
+ return theme;
50
+ }, [theme, variant]);
51
+
52
+ const renderTag = useMemo(() => {
53
+ if (!tag && href && !disabled) return "a";
54
+ if (!tag && disabled) return "div";
55
+ return tag || "button";
56
+ }, [tag, href, disabled]);
57
+
58
+ return React.createElement(
59
+ renderTag,
60
+ {
61
+ ...buttonProps,
62
+ href,
63
+ type,
64
+ ref,
65
+ disabled: disabled || loading,
66
+ className: classNames(
67
+ className,
68
+ [
69
+ `${classPrefix}-button`,
70
+ `${classPrefix}-button--theme-${renderTheme}`,
71
+ `${classPrefix}-button--variant-${variant}`
72
+ ],
73
+ {
74
+ [`${classPrefix}-button--shape-${shape}`]: shape !== "rectangle",
75
+ [`${classPrefix}-button--ghost`]: ghost,
76
+ [`${classPrefix}-is-loading`]: loading,
77
+ [`${classPrefix}-is-disabled`]: disabled,
78
+ [`${classPrefix}-size-s`]: size === "small",
79
+ [`${classPrefix}-size-l`]: size === "large",
80
+ [`${classPrefix}-size-full-width`]: block
81
+ }
82
+ ),
83
+ onClick: !disabled && !loading ? onClick : undefined
84
+ },
85
+ <>
86
+ {iconNode}
87
+ {renderChildren && <span className={`${classPrefix}-button__text`}>{renderChildren}</span>}
88
+ {suffix && <span className={`${classPrefix}-button__suffix`}>{parseTNode(suffix)}</span>}
89
+ </>
90
+ );
91
+ });
92
+
93
+ Button.displayName = "Button";
94
+
95
+ export default Button;
@@ -0,0 +1,13 @@
1
+ import { TdButtonProps } from "./type";
2
+
3
+ export const buttonDefaultProps: TdButtonProps = {
4
+ block: false,
5
+ disabled: false,
6
+ form: undefined,
7
+ ghost: false,
8
+ loading: false,
9
+ shape: "rectangle",
10
+ size: "medium",
11
+ type: "button",
12
+ variant: "base"
13
+ };
@@ -0,0 +1,7 @@
1
+ import _Button from "./Button";
2
+
3
+ import "./style/index";
4
+ export type { ButtonProps } from "./Button";
5
+ export const Button = _Button;
6
+ export * from "./type";
7
+ export default Button;
@@ -0,0 +1 @@
1
+ import "./index.css";