@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
@@ -0,0 +1 @@
1
+ import "./index.css";
@@ -0,0 +1 @@
1
+ import "../../styles/components/dialog/_index.scss";
package/dialog/type.ts ADDED
@@ -0,0 +1,241 @@
1
+ import { KeyboardEvent, MouseEvent } from "react";
2
+ import { ButtonProps } from "../button";
3
+ import { AttachNode, Styles, TNode } from "../common";
4
+
5
+ export interface TdDialogProps {
6
+ /**
7
+ * 对话框挂载的节点。数据类型为 String 时,会被当作选择器处理,进行节点查询。示例:'body' 或 () => document.body
8
+ */
9
+ attach?: AttachNode;
10
+ /**
11
+ * 对话框内容
12
+ */
13
+ body?: TNode;
14
+ /**
15
+ * 取消按钮,可自定义。值为 null 则不显示取消按钮。值类型为字符串,则表示自定义按钮文本,值类型为 Object 则表示透传 Button 组件属性。使用 TNode 自定义按钮时,需自行控制取消事件
16
+ */
17
+ cancelBtn?: ButtonProps | TNode | null;
18
+ /**
19
+ * 对话框内容,同 body
20
+ */
21
+ children?: TNode;
22
+ /**
23
+ * 关闭按钮,可以自定义。值为 true 显示默认关闭按钮,值为 false 不显示关闭按钮。值类型为 string 则直接显示值,如:“关闭”。值类型为 TNode,则表示呈现自定义按钮示例
24
+ * @default true
25
+ */
26
+ closeBtn?: TNode;
27
+ /**
28
+ * 按下 ESC 时是否触发对话框关闭事件
29
+ */
30
+ closeOnEscKeydown?: boolean;
31
+ /**
32
+ * 点击蒙层时是否触发关闭事件
33
+ */
34
+ closeOnOverlayClick?: boolean;
35
+ /**
36
+ * 确认按钮。值为 null 则不显示确认按钮。值类型为字符串,则表示自定义按钮文本,值类型为 Object 则表示透传 Button 组件属性。使用 TNode 自定义按钮时,需自行控制确认事件
37
+ */
38
+ confirmBtn?: ButtonProps | TNode | null;
39
+ /**
40
+ * 确认按钮加载状态
41
+ */
42
+ confirmLoading?: boolean;
43
+ /**
44
+ * 是否在按下回车键时,触发确认事件
45
+ */
46
+ confirmOnEnter?: boolean;
47
+ /**
48
+ * 是否在关闭弹框的时候销毁子元素
49
+ * @default false
50
+ */
51
+ destroyOnClose?: boolean;
52
+ /**
53
+ * 弹框元素类名,示例:'t-class-dialog-first t-class-dialog-second'
54
+ * @default ''
55
+ */
56
+ dialogClassName?: string;
57
+ /**
58
+ * 对话框是否可以拖拽(仅在非模态对话框时有效)
59
+ * @default false
60
+ */
61
+ draggable?: boolean;
62
+ /**
63
+ * 底部操作栏,默认会有“确认”和“取消”两个按钮。值为 true 显示默认操作按钮,值为 false 不显示任何内容,值类型为 Function 表示自定义底部内容
64
+ * @default true
65
+ */
66
+ footer?: TNode;
67
+ /**
68
+ * 是否强制渲染 Dialog,请使用 lazy 代替
69
+ * @default false
70
+ * @deprecated
71
+ */
72
+ forceRender?: boolean;
73
+ /**
74
+ * 头部内容。值为 true 显示空白头部,值为 false 不显示任何内容,值类型为 string 则直接显示值,值类型为 Function 表示自定义头部内容
75
+ * @default true
76
+ */
77
+ header?: TNode;
78
+ /**
79
+ * 是否启用对话框懒加载,启用时对话框内的内容不渲染
80
+ * @default true
81
+ */
82
+ lazy?: boolean;
83
+ /**
84
+ * 对话框类型,有 3 种:模态对话框、非模态对话框、全屏对话框。弹出「模态对话框」时,只能操作对话框里面的内容,不能操作其他内容。弹出「非模态对话框」时,则可以操作页面内所有内容。「普通对话框」是指没有脱离文档流的对话框,可以在这个基础上开发更多的插件
85
+ * @default modal
86
+ */
87
+ mode?: "modal" | "modeless" | "full-screen";
88
+ /**
89
+ * 对话框位置,内置两种:垂直水平居中显示 和 靠近顶部(top:20%)显示。默认情况,为避免贴顶或贴底,顶部和底部距离最小为 `48px`,可通过调整 `top` 覆盖默认大小
90
+ * @default top
91
+ */
92
+ placement?: "top" | "center";
93
+ /**
94
+ * 防止滚动穿透
95
+ * @default true
96
+ */
97
+ preventScrollThrough?: boolean;
98
+ /**
99
+ * 仅在挂载元素中显示抽屉,默认在浏览器可视区域显示。父元素需要有定位属性,如:position: relative
100
+ * @default false
101
+ */
102
+ showInAttachedElement?: boolean;
103
+ /**
104
+ * 是否显示遮罩层
105
+ * @default true
106
+ */
107
+ showOverlay?: boolean;
108
+ /**
109
+ * 对话框风格
110
+ * @default default
111
+ */
112
+ theme?: "default" | "info" | "warning" | "danger" | "success";
113
+ /**
114
+ * 用于弹框具体窗口顶部的距离,优先级大于 placement
115
+ */
116
+ top?: string | number;
117
+ /**
118
+ * 控制对话框是否显示
119
+ */
120
+ visible?: boolean;
121
+ /**
122
+ * 对话框宽度,示例:320, '500px', '80%'
123
+ */
124
+ width?: string | number;
125
+ /**
126
+ * 对话框层级,Web 侧样式默认为 2500,移动端和小程序样式默认为 1500
127
+ */
128
+ zIndex?: number;
129
+ /**
130
+ * 对话框执行消失动画效果前触发
131
+ */
132
+ onBeforeClose?: () => void;
133
+ /**
134
+ * 对话框执行弹出动画效果前触发
135
+ */
136
+ onBeforeOpen?: () => void;
137
+ /**
138
+ * 如果“取消”按钮存在,则点击“取消”按钮时触发,同时触发关闭事件
139
+ */
140
+ onCancel?: (context: { e: MouseEvent<HTMLButtonElement> }) => void;
141
+ /**
142
+ * 关闭事件,点击取消按钮、点击关闭按钮、点击蒙层、按下 ESC 等场景下触发
143
+ */
144
+ onClose?: (context: DialogCloseContext) => void;
145
+ /**
146
+ * 点击右上角关闭按钮时触发
147
+ */
148
+ onCloseBtnClick?: (context: { e: MouseEvent<HTMLDivElement> }) => void;
149
+ /**
150
+ * 对话框消失动画效果结束后触发
151
+ */
152
+ onClosed?: () => void;
153
+ /**
154
+ * 如果“确认”按钮存在,则点击“确认”按钮时触发,或者键盘按下回车键时触发
155
+ */
156
+ onConfirm?: (context: { e: MouseEvent<HTMLButtonElement> | KeyboardEvent<HTMLDivElement> }) => void;
157
+ /**
158
+ * 按下 ESC 时触发事件
159
+ */
160
+ onEscKeydown?: (context: { e: KeyboardEvent<HTMLDivElement> }) => void;
161
+ /**
162
+ * 对话框弹出动画效果结束后触发
163
+ */
164
+ onOpened?: () => void;
165
+ /**
166
+ * 如果蒙层存在,点击蒙层时触发
167
+ */
168
+ onOverlayClick?: (context: { e: MouseEvent<HTMLDivElement> }) => void;
169
+ }
170
+
171
+ export interface TdDialogCardProps
172
+ extends Pick<
173
+ TdDialogProps,
174
+ | "body"
175
+ | "cancelBtn"
176
+ | "closeBtn"
177
+ | "confirmBtn"
178
+ | "footer"
179
+ | "header"
180
+ | "theme"
181
+ | "onCancel"
182
+ | "onCloseBtnClick"
183
+ | "onConfirm"
184
+ | "confirmLoading"
185
+ > {
186
+ // Additional properties specific to DialogCard can be added here
187
+ [key: string]: unknown;
188
+ }
189
+
190
+ export interface DialogOptions extends Omit<TdDialogProps, "attach"> {
191
+ /**
192
+ * 对话框挂载的节点。数据类型为 String 时,会被当作选择器处理,进行节点查询。示例:'body' 或 () => document.body
193
+ * @default 'body'
194
+ */
195
+ attach?: AttachNode;
196
+ /**
197
+ * 弹框类名,示例:'t-class-dialog-first t-class-dialog-second'
198
+ * @default ''
199
+ */
200
+ className?: string;
201
+ /**
202
+ * 弹框 style 属性,输入 [CSSStyleDeclaration.cssText](https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleDeclaration/cssText)
203
+ */
204
+ style?: Styles;
205
+ }
206
+
207
+ export interface DialogInstance {
208
+ /**
209
+ * 销毁弹框
210
+ */
211
+ destroy: () => void;
212
+ /**
213
+ * 隐藏弹框
214
+ */
215
+ hide: () => void;
216
+ /**
217
+ * 设置确认按钮加载状态
218
+ */
219
+ setConfirmLoading: (loading: boolean) => void;
220
+ /**
221
+ * 显示弹框
222
+ */
223
+ show: () => void;
224
+ /**
225
+ * 更新弹框内容
226
+ */
227
+ update: (props: DialogOptions) => void;
228
+ }
229
+
230
+ export type DialogEventSource = "esc" | "close-btn" | "cancel" | "overlay";
231
+
232
+ export interface DialogCloseContext {
233
+ trigger: DialogEventSource;
234
+ e: MouseEvent<HTMLElement> | KeyboardEvent;
235
+ }
236
+
237
+ export type DialogMethod = (options?: DialogOptions) => DialogInstance;
238
+
239
+ export type DialogConfirmMethod = (options?: DialogOptions) => DialogInstance;
240
+
241
+ export type DialogAlertMethod = (options?: Omit<DialogOptions, "cancelBtn">) => DialogInstance;
@@ -0,0 +1,4 @@
1
+ export function parseValueToPx(value: number | string) {
2
+ if (typeof value === "number") return `${value}px`;
3
+ return value;
4
+ }
package/form/Form.tsx ADDED
@@ -0,0 +1,136 @@
1
+ import React, { useRef, useImperativeHandle } from "react";
2
+ import classNames from "classnames";
3
+ import useConfig from "../hooks/useConfig";
4
+ import noop from "../utils/noop";
5
+ import forwardRefWithStatics from "../utils/forwardRefWithStatics";
6
+ import type { FormInstanceFunctions, TdFormProps } from "./type";
7
+ import useInstance from "./hooks/useInstance";
8
+ import useForm, { HOOK_MARK } from "./hooks/useForm";
9
+ import useWatch from "./hooks/useWatch";
10
+ import { StyledProps } from "../common";
11
+ // 表单上下文对象 FormList上下文对象
12
+ import FormContext from "./FormContext";
13
+ import FormItem from "./FormItem";
14
+ import FormList from "./FormList";
15
+ import { formDefaultProps } from "./defaultProps";
16
+ import useDefaultProps from "../hooks/useDefaultProps";
17
+
18
+ export interface FormProps extends TdFormProps, StyledProps {
19
+ children?: React.ReactNode;
20
+ }
21
+
22
+ const Form = forwardRefWithStatics<FormProps, FormInstanceFunctions>(
23
+ (originalProps: FormProps, ref) => {
24
+ const { classPrefix, form: globalFormConfig } = useConfig();
25
+ const props = useDefaultProps<FormProps>(originalProps, formDefaultProps);
26
+ const {
27
+ style,
28
+ className,
29
+ labelWidth,
30
+ statusIcon,
31
+ labelAlign,
32
+ layout,
33
+ colon,
34
+ initialData,
35
+ requiredMark = globalFormConfig.requiredMark,
36
+ requiredMarkPosition = globalFormConfig.requiredMarkPosition,
37
+ scrollToFirstError,
38
+ showErrorMessage,
39
+ resetType,
40
+ rules,
41
+ errorMessage = globalFormConfig.errorMessage,
42
+ preventSubmitDefault,
43
+ disabled,
44
+ children,
45
+ id,
46
+ onReset,
47
+ onValuesChange = noop
48
+ } = props;
49
+
50
+ const formClass = classNames(`${classPrefix}-form`, className, {
51
+ [`${classPrefix}-form-inline`]: layout === "inline"
52
+ });
53
+
54
+ const [form] = useForm(props.form); // 内部与外部共享 form 实例,外部不传则内部创建
55
+ const formRef = useRef<HTMLFormElement>(null);
56
+ const formMapRef = useRef(new Map()); // 收集所有包含 name 属性 formItem 实例
57
+ const floatingFormDataRef = useRef({}); // 储存游离值的 formData
58
+ const formInstance = useInstance(props, formRef, formMapRef, floatingFormDataRef);
59
+
60
+ const exposedFormInstance = formInstance as unknown as FormInstanceFunctions;
61
+
62
+ useImperativeHandle(ref, () => exposedFormInstance);
63
+ Object.assign(form, { ...exposedFormInstance });
64
+ form?.getInternalHooks?.(HOOK_MARK)?.setForm?.(exposedFormInstance);
65
+
66
+ // form 初始化后清空队列
67
+ React.useEffect(() => {
68
+ form?.getInternalHooks?.(HOOK_MARK)?.flashQueue?.();
69
+ }, [form]);
70
+
71
+ function onResetHandler(e: React.FormEvent<HTMLFormElement>) {
72
+ [...formMapRef.current.values()].forEach((formItemRef) => {
73
+ formItemRef?.current.resetField();
74
+ });
75
+ form?.getInternalHooks?.(HOOK_MARK)?.notifyWatch?.([]);
76
+ form.store = {};
77
+ onReset?.({ e });
78
+ }
79
+
80
+ function onFormItemValueChange(changedValue: Record<string, unknown>) {
81
+ const allFields = formInstance.getFieldsValue(true);
82
+ onValuesChange(changedValue, allFields);
83
+ }
84
+
85
+ function onKeyDownHandler(e: React.KeyboardEvent<HTMLFormElement>) {
86
+ // 禁用 input 输入框回车自动提交 form
87
+ if ((e.target as Element).tagName.toLowerCase() !== "input") return;
88
+ if (preventSubmitDefault && e.key === "Enter") {
89
+ e.preventDefault?.();
90
+ e.stopPropagation?.();
91
+ }
92
+ }
93
+
94
+ return (
95
+ <FormContext.Provider
96
+ value={{
97
+ form,
98
+ labelWidth,
99
+ statusIcon,
100
+ labelAlign,
101
+ layout,
102
+ colon,
103
+ initialData,
104
+ requiredMark,
105
+ requiredMarkPosition,
106
+ errorMessage,
107
+ showErrorMessage,
108
+ scrollToFirstError,
109
+ resetType,
110
+ rules,
111
+ disabled,
112
+ formMapRef,
113
+ floatingFormDataRef,
114
+ onFormItemValueChange
115
+ }}
116
+ >
117
+ <form
118
+ ref={formRef}
119
+ id={id}
120
+ style={style}
121
+ className={formClass}
122
+ onSubmit={formInstance.submit}
123
+ onReset={onResetHandler}
124
+ onKeyDown={onKeyDownHandler}
125
+ >
126
+ {children}
127
+ </form>
128
+ </FormContext.Provider>
129
+ );
130
+ },
131
+ { useForm, useWatch, FormItem, FormList }
132
+ );
133
+
134
+ Form.displayName = "Form";
135
+
136
+ export default Form;
@@ -0,0 +1,64 @@
1
+ import React from "react";
2
+ import { TdFormProps, TdFormListProps, NamePath } from "./type";
3
+ import { FormItemInstance } from "./FormItem";
4
+ import { InternalFormInstance } from "./hooks/interface";
5
+
6
+ const FormContext = React.createContext<{
7
+ form?: InternalFormInstance;
8
+ labelWidth?: TdFormProps["labelWidth"];
9
+ statusIcon?: TdFormProps["statusIcon"];
10
+ labelAlign: TdFormProps["labelAlign"];
11
+ layout: TdFormProps["layout"];
12
+ colon: TdFormProps["colon"];
13
+ initialData: TdFormProps["initialData"];
14
+ requiredMark: TdFormProps["requiredMark"];
15
+ requiredMarkPosition: TdFormProps["requiredMarkPosition"];
16
+ scrollToFirstError: TdFormProps["scrollToFirstError"];
17
+ showErrorMessage: TdFormProps["showErrorMessage"];
18
+ resetType: TdFormProps["resetType"];
19
+ disabled: TdFormProps["disabled"];
20
+ rules: TdFormProps["rules"];
21
+ errorMessage: TdFormProps["errorMessage"];
22
+ formMapRef: React.RefObject<Map<NamePath, React.RefObject<FormItemInstance>>>;
23
+ floatingFormDataRef: React.RefObject<Record<string, unknown>>;
24
+ onFormItemValueChange: (changedValue: Record<string, unknown>) => void;
25
+ }>({
26
+ form: undefined,
27
+ labelWidth: "100px",
28
+ labelAlign: "right",
29
+ layout: "vertical",
30
+ colon: false,
31
+ initialData: {},
32
+ requiredMark: undefined,
33
+ requiredMarkPosition: undefined,
34
+ scrollToFirstError: undefined,
35
+ showErrorMessage: undefined,
36
+ resetType: "empty",
37
+ disabled: undefined,
38
+ rules: undefined,
39
+ errorMessage: undefined,
40
+ statusIcon: undefined,
41
+ onFormItemValueChange: undefined,
42
+ formMapRef: undefined,
43
+ floatingFormDataRef: undefined
44
+ });
45
+
46
+ export const useFormContext = () => React.useContext(FormContext);
47
+
48
+ export default FormContext;
49
+
50
+ export const FormListContext = React.createContext<{
51
+ name: NamePath;
52
+ rules: TdFormListProps["rules"];
53
+ formListMapRef: React.RefObject<Map<NamePath, React.RefObject<FormItemInstance>>>;
54
+ initialData: TdFormListProps["initialData"];
55
+ form?: InternalFormInstance;
56
+ }>({
57
+ name: undefined,
58
+ rules: undefined,
59
+ formListMapRef: undefined,
60
+ initialData: [],
61
+ form: undefined
62
+ });
63
+
64
+ export const useFormListContext = () => React.useContext(FormListContext);