@rainbow-oh/yee-c 0.4.4 → 0.5.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 (272) hide show
  1. package/dist/cjs/Button/button.d.ts +1 -1
  2. package/dist/cjs/CSV/download.d.ts +1 -1
  3. package/dist/cjs/Carousel/carousel.d.ts +2 -2
  4. package/dist/cjs/Carousel/carousel.js +9 -2
  5. package/dist/cjs/Carousel/interface.d.ts +5 -0
  6. package/dist/cjs/Dialog/demo/basic.js +1 -1
  7. package/dist/cjs/Dialog/dialog.js +1 -1
  8. package/dist/cjs/Drawer/style/index.less +4 -0
  9. package/dist/cjs/Field/demo/validation.js +23 -3
  10. package/dist/cjs/Field/field.js +1 -1
  11. package/dist/cjs/FloatButton/float-button.d.ts +1 -1
  12. package/dist/cjs/Form/Field.js +1 -4
  13. package/dist/cjs/Form/Form.js +1 -1
  14. package/dist/cjs/Form/Group.js +36 -14
  15. package/dist/cjs/Form/List.js +23 -3
  16. package/dist/cjs/Form/demo/async-validate.d.ts +3 -0
  17. package/dist/cjs/Form/demo/async-validate.js +108 -0
  18. package/dist/cjs/Form/demo/basic.js +2 -2
  19. package/dist/cjs/Form/demo/virtual.js +1 -1
  20. package/dist/cjs/Form/form-store.d.ts +4 -4
  21. package/dist/cjs/Form/form-store.js +55 -25
  22. package/dist/cjs/Form/interface.d.ts +10 -7
  23. package/dist/cjs/Form/style/index.less +15 -0
  24. package/dist/cjs/Form/utils/validate.d.ts +23 -2
  25. package/dist/cjs/Form/utils/validate.js +59 -10
  26. package/dist/cjs/Input/style/index.less +0 -17
  27. package/dist/cjs/InputNumber/style/index.less +0 -29
  28. package/dist/cjs/PickerPanel/interface.d.ts +44 -2
  29. package/dist/cjs/PickerPanel/panels/DatePanel/DateBody.d.ts +2 -1
  30. package/dist/cjs/PickerPanel/panels/DatePanel/DateHeader.d.ts +2 -1
  31. package/dist/cjs/PickerPanel/panels/DatePanel/DateHeader.js +1 -1
  32. package/dist/cjs/PickerPanel/panels/DatePanel/index.d.ts +2 -1
  33. package/dist/cjs/PickerPanel/panels/DateTimePanel/index.d.ts +7 -1
  34. package/dist/cjs/PickerPanel/panels/DateTimePanel/index.js +18 -4
  35. package/dist/cjs/PickerPanel/panels/DecadePanel/DecadeBody.d.ts +2 -1
  36. package/dist/cjs/PickerPanel/panels/DecadePanel/DecadeBody.js +1 -1
  37. package/dist/cjs/PickerPanel/panels/DecadePanel/DecadeHeader.d.ts +2 -1
  38. package/dist/cjs/PickerPanel/panels/DecadePanel/DecadeHeader.js +1 -1
  39. package/dist/cjs/PickerPanel/panels/DecadePanel/index.d.ts +2 -1
  40. package/dist/cjs/PickerPanel/panels/DecadePanel/index.js +1 -1
  41. package/dist/cjs/PickerPanel/panels/Header.d.ts +13 -1
  42. package/dist/cjs/PickerPanel/panels/MonthPanel/MonthBody.d.ts +2 -1
  43. package/dist/cjs/PickerPanel/panels/MonthPanel/MonthHeader.d.ts +2 -1
  44. package/dist/cjs/PickerPanel/panels/MonthPanel/MonthHeader.js +1 -1
  45. package/dist/cjs/PickerPanel/panels/MonthPanel/index.d.ts +2 -1
  46. package/dist/cjs/PickerPanel/panels/MonthPanel/index.js +1 -1
  47. package/dist/cjs/PickerPanel/panels/PanelBody.d.ts +21 -1
  48. package/dist/cjs/PickerPanel/panels/PanelBody.js +3 -3
  49. package/dist/cjs/PickerPanel/panels/QuarterPanel/QuarterBody.d.ts +2 -1
  50. package/dist/cjs/PickerPanel/panels/QuarterPanel/QuarterHeader.d.ts +2 -1
  51. package/dist/cjs/PickerPanel/panels/QuarterPanel/index.d.ts +2 -1
  52. package/dist/cjs/PickerPanel/panels/RangePanel/index.d.ts +2 -1
  53. package/dist/cjs/PickerPanel/panels/RangePanel/index.js +2 -2
  54. package/dist/cjs/PickerPanel/panels/RangePanel/interface.d.ts +5 -5
  55. package/dist/cjs/PickerPanel/panels/TimePanel/TimeBody.d.ts +17 -1
  56. package/dist/cjs/PickerPanel/panels/TimePanel/TimeCell.d.ts +7 -1
  57. package/dist/cjs/PickerPanel/panels/TimePanel/TimeCell.js +1 -1
  58. package/dist/cjs/PickerPanel/panels/TimePanel/TimeColumn.d.ts +14 -1
  59. package/dist/cjs/PickerPanel/panels/TimePanel/TimeColumn.js +1 -1
  60. package/dist/cjs/PickerPanel/panels/TimePanel/TimeHeader.d.ts +4 -1
  61. package/dist/cjs/PickerPanel/panels/TimePanel/index.d.ts +9 -1
  62. package/dist/cjs/PickerPanel/panels/WeekPanel/WeekBody.d.ts +2 -1
  63. package/dist/cjs/PickerPanel/panels/WeekPanel/WeekHeader.d.ts +2 -1
  64. package/dist/cjs/PickerPanel/panels/WeekPanel/index.d.ts +2 -1
  65. package/dist/cjs/PickerPanel/panels/YearPanel/YearBody.d.ts +2 -1
  66. package/dist/cjs/PickerPanel/panels/YearPanel/YearBody.js +2 -2
  67. package/dist/cjs/PickerPanel/panels/YearPanel/YearHeader.d.ts +2 -1
  68. package/dist/cjs/PickerPanel/panels/YearPanel/YearHeader.js +7 -1
  69. package/dist/cjs/PickerPanel/panels/YearPanel/index.d.ts +2 -1
  70. package/dist/cjs/PickerPanel/panels/YearPanel/index.js +1 -1
  71. package/dist/cjs/PickerPanel/utils/pickerUtils.d.ts +7 -7
  72. package/dist/cjs/PickerPanel/utils/pickerUtils.js +2 -2
  73. package/dist/cjs/Select/demo/basic.js +1 -1
  74. package/dist/cjs/Select/demo/virtual.d.ts +3 -0
  75. package/dist/cjs/Select/demo/virtual.js +55 -0
  76. package/dist/cjs/Select/hooks/useSelectKeyboard.d.ts +7 -1
  77. package/dist/cjs/Select/hooks/useSelectKeyboard.js +16 -6
  78. package/dist/cjs/Select/interface.d.ts +44 -0
  79. package/dist/cjs/Select/option.js +3 -2
  80. package/dist/cjs/Select/options.js +115 -15
  81. package/dist/cjs/Select/select.js +20 -4
  82. package/dist/cjs/Select/style/index.less +17 -13
  83. package/dist/cjs/Selector/style/index.less +2 -137
  84. package/dist/cjs/Table/style/index.less +19 -0
  85. package/dist/cjs/TextArea/style/index.less +0 -17
  86. package/dist/cjs/hooks/index.d.ts +2 -1
  87. package/dist/cjs/hooks/index.js +3 -1
  88. package/dist/cjs/hooks/useEvent.js +4 -1
  89. package/dist/cjs/hooks/useVirtualList.d.ts +71 -0
  90. package/dist/cjs/hooks/useVirtualList.js +117 -0
  91. package/dist/cjs/style/size.css +1 -0
  92. package/dist/cjs/style/themes.css +1 -1
  93. package/dist/cjs/style/variables.css +2 -1
  94. package/dist/cjs/version.d.ts +1 -1
  95. package/dist/cjs/version.js +1 -1
  96. package/dist/esm/Button/button.d.ts +1 -1
  97. package/dist/esm/CSV/download.d.ts +1 -1
  98. package/dist/esm/Carousel/carousel.d.ts +2 -2
  99. package/dist/esm/Carousel/carousel.js +5 -1
  100. package/dist/esm/Carousel/interface.d.ts +5 -0
  101. package/dist/esm/Dialog/demo/basic.js +1 -1
  102. package/dist/esm/Dialog/dialog.js +1 -1
  103. package/dist/esm/Drawer/style/index.less +4 -0
  104. package/dist/esm/Field/demo/validation.js +30 -9
  105. package/dist/esm/Field/field.js +2 -1
  106. package/dist/esm/FloatButton/float-button.d.ts +1 -1
  107. package/dist/esm/Form/Field.js +3 -4
  108. package/dist/esm/Form/Form.js +1 -1
  109. package/dist/esm/Form/Group.js +142 -53
  110. package/dist/esm/Form/List.js +61 -42
  111. package/dist/esm/Form/demo/async-validate.d.ts +3 -0
  112. package/dist/esm/Form/demo/async-validate.js +95 -0
  113. package/dist/esm/Form/demo/basic.js +4 -2
  114. package/dist/esm/Form/demo/virtual.js +1 -1
  115. package/dist/esm/Form/form-store.d.ts +4 -4
  116. package/dist/esm/Form/form-store.js +187 -93
  117. package/dist/esm/Form/interface.d.ts +10 -7
  118. package/dist/esm/Form/style/index.less +15 -0
  119. package/dist/esm/Form/utils/validate.d.ts +23 -2
  120. package/dist/esm/Form/utils/validate.js +122 -17
  121. package/dist/esm/Input/style/index.less +0 -17
  122. package/dist/esm/InputNumber/style/index.less +0 -29
  123. package/dist/esm/PickerPanel/interface.d.ts +44 -2
  124. package/dist/esm/PickerPanel/panels/DatePanel/DateBody.d.ts +2 -1
  125. package/dist/esm/PickerPanel/panels/DatePanel/DateHeader.d.ts +2 -1
  126. package/dist/esm/PickerPanel/panels/DatePanel/DateHeader.js +1 -1
  127. package/dist/esm/PickerPanel/panels/DatePanel/index.d.ts +2 -1
  128. package/dist/esm/PickerPanel/panels/DateTimePanel/index.d.ts +7 -1
  129. package/dist/esm/PickerPanel/panels/DateTimePanel/index.js +11 -7
  130. package/dist/esm/PickerPanel/panels/DecadePanel/DecadeBody.d.ts +2 -1
  131. package/dist/esm/PickerPanel/panels/DecadePanel/DecadeBody.js +2 -1
  132. package/dist/esm/PickerPanel/panels/DecadePanel/DecadeHeader.d.ts +2 -1
  133. package/dist/esm/PickerPanel/panels/DecadePanel/DecadeHeader.js +2 -1
  134. package/dist/esm/PickerPanel/panels/DecadePanel/index.d.ts +2 -1
  135. package/dist/esm/PickerPanel/panels/DecadePanel/index.js +1 -1
  136. package/dist/esm/PickerPanel/panels/Header.d.ts +13 -1
  137. package/dist/esm/PickerPanel/panels/MonthPanel/MonthBody.d.ts +2 -1
  138. package/dist/esm/PickerPanel/panels/MonthPanel/MonthHeader.d.ts +2 -1
  139. package/dist/esm/PickerPanel/panels/MonthPanel/MonthHeader.js +2 -1
  140. package/dist/esm/PickerPanel/panels/MonthPanel/index.d.ts +2 -1
  141. package/dist/esm/PickerPanel/panels/MonthPanel/index.js +1 -1
  142. package/dist/esm/PickerPanel/panels/PanelBody.d.ts +21 -1
  143. package/dist/esm/PickerPanel/panels/PanelBody.js +2 -4
  144. package/dist/esm/PickerPanel/panels/QuarterPanel/QuarterBody.d.ts +2 -1
  145. package/dist/esm/PickerPanel/panels/QuarterPanel/QuarterHeader.d.ts +2 -1
  146. package/dist/esm/PickerPanel/panels/QuarterPanel/index.d.ts +2 -1
  147. package/dist/esm/PickerPanel/panels/RangePanel/index.d.ts +2 -1
  148. package/dist/esm/PickerPanel/panels/RangePanel/index.js +2 -2
  149. package/dist/esm/PickerPanel/panels/RangePanel/interface.d.ts +5 -5
  150. package/dist/esm/PickerPanel/panels/TimePanel/TimeBody.d.ts +17 -1
  151. package/dist/esm/PickerPanel/panels/TimePanel/TimeCell.d.ts +7 -1
  152. package/dist/esm/PickerPanel/panels/TimePanel/TimeCell.js +1 -1
  153. package/dist/esm/PickerPanel/panels/TimePanel/TimeColumn.d.ts +14 -1
  154. package/dist/esm/PickerPanel/panels/TimePanel/TimeColumn.js +1 -1
  155. package/dist/esm/PickerPanel/panels/TimePanel/TimeHeader.d.ts +4 -1
  156. package/dist/esm/PickerPanel/panels/TimePanel/index.d.ts +9 -1
  157. package/dist/esm/PickerPanel/panels/WeekPanel/WeekBody.d.ts +2 -1
  158. package/dist/esm/PickerPanel/panels/WeekPanel/WeekHeader.d.ts +2 -1
  159. package/dist/esm/PickerPanel/panels/WeekPanel/index.d.ts +2 -1
  160. package/dist/esm/PickerPanel/panels/YearPanel/YearBody.d.ts +2 -1
  161. package/dist/esm/PickerPanel/panels/YearPanel/YearBody.js +3 -2
  162. package/dist/esm/PickerPanel/panels/YearPanel/YearHeader.d.ts +2 -1
  163. package/dist/esm/PickerPanel/panels/YearPanel/YearHeader.js +2 -1
  164. package/dist/esm/PickerPanel/panels/YearPanel/index.d.ts +2 -1
  165. package/dist/esm/PickerPanel/panels/YearPanel/index.js +1 -1
  166. package/dist/esm/PickerPanel/picker-panel.js +3 -0
  167. package/dist/esm/PickerPanel/utils/pickerUtils.d.ts +7 -7
  168. package/dist/esm/PickerPanel/utils/pickerUtils.js +4 -10
  169. package/dist/esm/Select/demo/basic.js +1 -1
  170. package/dist/esm/Select/demo/virtual.d.ts +3 -0
  171. package/dist/esm/Select/demo/virtual.js +38 -0
  172. package/dist/esm/Select/hooks/useSelectKeyboard.d.ts +7 -1
  173. package/dist/esm/Select/hooks/useSelectKeyboard.js +25 -9
  174. package/dist/esm/Select/interface.d.ts +44 -0
  175. package/dist/esm/Select/option.js +4 -2
  176. package/dist/esm/Select/options.js +132 -13
  177. package/dist/esm/Select/select.js +19 -4
  178. package/dist/esm/Select/style/index.less +17 -13
  179. package/dist/esm/Selector/style/index.less +2 -137
  180. package/dist/esm/Table/style/index.less +19 -0
  181. package/dist/esm/TextArea/style/index.less +0 -17
  182. package/dist/esm/hooks/index.d.ts +2 -1
  183. package/dist/esm/hooks/index.js +2 -1
  184. package/dist/esm/hooks/useVirtualList.d.ts +71 -0
  185. package/dist/esm/hooks/useVirtualList.js +129 -0
  186. package/dist/esm/style/size.css +1 -0
  187. package/dist/esm/style/themes.css +1 -1
  188. package/dist/esm/style/variables.css +2 -1
  189. package/dist/esm/version.d.ts +1 -1
  190. package/dist/esm/version.js +1 -1
  191. package/dist/umd/yee-c.min.css +2 -2
  192. package/dist/umd/yee-c.min.js +1 -1
  193. package/package.json +1 -1
  194. package/src/Carousel/carousel.tsx +14 -3
  195. package/src/Carousel/interface.ts +6 -0
  196. package/src/Cascader/cascader.tsx +3 -1
  197. package/src/Cascader/column.tsx +1 -1
  198. package/src/Dialog/demo/basic.tsx +1 -1
  199. package/src/Dialog/dialog.tsx +1 -1
  200. package/src/Drawer/style/index.less +4 -0
  201. package/src/Dropdown/dropdown.tsx +1 -1
  202. package/src/Field/demo/validation.tsx +2 -2
  203. package/src/Field/field.tsx +2 -1
  204. package/src/Field/index.en-US.md +1 -1
  205. package/src/Field/index.zh-CN.md +1 -1
  206. package/src/FloatButton/float-button.tsx +5 -3
  207. package/src/Form/Field.tsx +3 -4
  208. package/src/Form/Form.tsx +1 -1
  209. package/src/Form/Group.tsx +15 -12
  210. package/src/Form/List.tsx +3 -3
  211. package/src/Form/demo/async-validate.tsx +71 -0
  212. package/src/Form/demo/basic.tsx +2 -2
  213. package/src/Form/demo/virtual.tsx +1 -1
  214. package/src/Form/form-store.ts +37 -21
  215. package/src/Form/index.en-US.md +6 -5
  216. package/src/Form/index.zh-CN.md +6 -5
  217. package/src/Form/interface.ts +13 -7
  218. package/src/Form/style/index.less +15 -0
  219. package/src/Form/utils/validate.ts +65 -13
  220. package/src/Input/style/index.less +0 -17
  221. package/src/InputNumber/style/index.less +0 -29
  222. package/src/PickerPanel/interface.ts +43 -2
  223. package/src/PickerPanel/panels/DatePanel/DateBody.tsx +2 -1
  224. package/src/PickerPanel/panels/DatePanel/DateHeader.tsx +3 -2
  225. package/src/PickerPanel/panels/DatePanel/index.tsx +2 -1
  226. package/src/PickerPanel/panels/DateTimePanel/index.tsx +12 -5
  227. package/src/PickerPanel/panels/DecadePanel/DecadeBody.tsx +3 -2
  228. package/src/PickerPanel/panels/DecadePanel/DecadeHeader.tsx +3 -2
  229. package/src/PickerPanel/panels/DecadePanel/index.tsx +3 -2
  230. package/src/PickerPanel/panels/Header.tsx +14 -1
  231. package/src/PickerPanel/panels/MonthPanel/MonthBody.tsx +2 -1
  232. package/src/PickerPanel/panels/MonthPanel/MonthHeader.tsx +3 -2
  233. package/src/PickerPanel/panels/MonthPanel/index.tsx +3 -2
  234. package/src/PickerPanel/panels/PanelBody.tsx +27 -5
  235. package/src/PickerPanel/panels/QuarterPanel/QuarterBody.tsx +2 -1
  236. package/src/PickerPanel/panels/QuarterPanel/QuarterHeader.tsx +2 -1
  237. package/src/PickerPanel/panels/QuarterPanel/index.tsx +2 -1
  238. package/src/PickerPanel/panels/RangePanel/index.tsx +11 -9
  239. package/src/PickerPanel/panels/RangePanel/interface.ts +5 -5
  240. package/src/PickerPanel/panels/TimePanel/TimeBody.tsx +21 -5
  241. package/src/PickerPanel/panels/TimePanel/TimeCell.tsx +9 -2
  242. package/src/PickerPanel/panels/TimePanel/TimeColumn.tsx +15 -2
  243. package/src/PickerPanel/panels/TimePanel/TimeHeader.tsx +5 -1
  244. package/src/PickerPanel/panels/TimePanel/index.tsx +10 -1
  245. package/src/PickerPanel/panels/WeekPanel/WeekBody.tsx +2 -1
  246. package/src/PickerPanel/panels/WeekPanel/WeekHeader.tsx +2 -1
  247. package/src/PickerPanel/panels/WeekPanel/index.tsx +2 -1
  248. package/src/PickerPanel/panels/YearPanel/YearBody.tsx +4 -3
  249. package/src/PickerPanel/panels/YearPanel/YearHeader.tsx +9 -3
  250. package/src/PickerPanel/panels/YearPanel/index.tsx +3 -2
  251. package/src/PickerPanel/picker-panel.tsx +5 -3
  252. package/src/PickerPanel/utils/pickerUtils.ts +17 -8
  253. package/src/Select/demo/basic.tsx +1 -1
  254. package/src/Select/demo/virtual.tsx +25 -0
  255. package/src/Select/hooks/useSelectKeyboard.ts +30 -6
  256. package/src/Select/index.en-US.md +4 -0
  257. package/src/Select/index.zh-CN.md +4 -0
  258. package/src/Select/interface.ts +48 -2
  259. package/src/Select/option.tsx +2 -1
  260. package/src/Select/options.tsx +139 -8
  261. package/src/Select/select.tsx +23 -1
  262. package/src/Select/style/index.less +17 -13
  263. package/src/Selector/style/index.less +2 -137
  264. package/src/Splitter/hooks/useMove.ts +2 -2
  265. package/src/Table/style/index.less +19 -0
  266. package/src/TextArea/style/index.less +0 -17
  267. package/src/hooks/index.ts +2 -0
  268. package/src/hooks/useEvent.ts +7 -4
  269. package/src/hooks/useMergedState.ts +6 -4
  270. package/src/hooks/useVirtualList.ts +169 -0
  271. package/src/style/size.css +1 -0
  272. package/src/version.ts +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rainbow-oh/yee-c",
3
- "version": "0.4.4",
3
+ "version": "0.5.0",
4
4
  "description": "yee basic components",
5
5
  "keywords": [
6
6
  "react",
@@ -16,13 +16,21 @@ import { GlobalContext } from '../Config-Provider';
16
16
  import useElementSize from '../hooks/useElementSize';
17
17
  import mergeContextToProps from '../utils/mergeContextToProps';
18
18
  import Item from './carousel-item';
19
- import type { CarouselProps } from './interface';
19
+ import type {
20
+ CarouselContextProps,
21
+ CarouselItemProps,
22
+ CarouselProps,
23
+ } from './interface';
20
24
 
21
25
  import './style/index.less';
22
26
 
23
27
  const DEFAULT_ANIMATION_DURATION = 500;
24
28
 
25
- export const CarouselCtx = React.createContext({} as any);
29
+ export const CarouselCtx = React.createContext<CarouselContextProps>({
30
+ prefixCls: 'yee-carousel',
31
+ effect: 'scrollx',
32
+ current: 1,
33
+ });
26
34
 
27
35
  const Carousel = React.forwardRef(
28
36
  (baseprops: CarouselProps, ref: React.Ref<HTMLDivElement>) => {
@@ -249,7 +257,10 @@ const Carousel = React.forwardRef(
249
257
 
250
258
  const renderFadeChilds = () => {
251
259
  return React.Children.map(children, (child, index) => {
252
- return React.cloneElement(child as any, { index });
260
+ return React.cloneElement(
261
+ child as React.ReactElement<CarouselItemProps>,
262
+ { index },
263
+ );
253
264
  });
254
265
  };
255
266
 
@@ -1,5 +1,11 @@
1
1
  export type SemanticDOM = 'dot' | 'prev' | 'next';
2
2
 
3
+ export interface CarouselContextProps {
4
+ prefixCls: string;
5
+ effect: 'fade' | 'scrollx';
6
+ current: number;
7
+ }
8
+
3
9
  export interface CarouselItemProps {
4
10
  index: number;
5
11
  style?: React.CSSProperties;
@@ -65,7 +65,9 @@ const Cascader = (baseprops: CascaderProps) => {
65
65
 
66
66
  // Status variables for internal use
67
67
  const [columns, setColumns] = useState<Array<FlattenOption[]>>([]);
68
- const [expandedPath, setExpandedPath] = useState<Array<any>>([]);
68
+ const [expandedPath, setExpandedPath] = useState<
69
+ Array<{ key: string; label: string }>
70
+ >([]);
69
71
  const [searchValue, setSearchValue] = useState(''); // Input field input
70
72
  // NOTE: popupVisible uses ref instead of state to avoid triggering re-renders
71
73
  // This is intentional - it's only used for side effects tracking, not for rendering
@@ -13,7 +13,7 @@ const Column = (props: ColumnProps) => {
13
13
  return (
14
14
  <ul className={`${prefixCls}-menu`} role="menu">
15
15
  {Array.isArray(data) &&
16
- data.map((item: any, idx: number) => {
16
+ data.map((item, idx: number) => {
17
17
  return (
18
18
  <Node
19
19
  {...item}
@@ -22,7 +22,7 @@ export default () => {
22
22
  setOpen(false);
23
23
  // form.resetFields();
24
24
  }}
25
- onConfirm={() => form.submit()}
25
+ onConfirm={() => void form.submit()}
26
26
  >
27
27
  <Form
28
28
  form={form}
@@ -90,7 +90,7 @@ const Dialog = (baseprops: DialogProps) => {
90
90
  });
91
91
 
92
92
  const renderFooter = () => {
93
- if (footer === false) {
93
+ if (footer === false || footer === null) {
94
94
  return null;
95
95
  }
96
96
 
@@ -37,6 +37,10 @@
37
37
  padding: var(--yee-drawer-header-padding);
38
38
  }
39
39
 
40
+ &-title {
41
+ font-weight: var(--yee-drawer-title-font-weight);
42
+ }
43
+
40
44
  &-body {
41
45
  flex: 1;
42
46
  padding: var(--yee-drawer-body-padding);
@@ -56,7 +56,7 @@ const Dropdown: FC<DropdownProps> = (baseprops) => {
56
56
  <Trigger
57
57
  {...rest}
58
58
  arrow={arrow}
59
- popup={renderPopup() as any}
59
+ popup={renderPopup() as React.ReactElement}
60
60
  placement={placement}
61
61
  popupClassName={`${prefixCls}-popup`}
62
62
  open={mergedOpen}
@@ -8,10 +8,10 @@ export default () => {
8
8
  createForm('validationForm');
9
9
  }, []);
10
10
 
11
- const handleSubmit = () => {
11
+ const handleSubmit = async () => {
12
12
  const form = getForm('validationForm');
13
13
  console.log('form: ', form);
14
- const errors = form?.submit();
14
+ const errors = await form?.submit();
15
15
  console.log('errors: ', errors);
16
16
  if (errors && errors.length === 0) {
17
17
  console.log('Submit success:', form?.getFieldsValue());
@@ -82,7 +82,8 @@ const Field: FC<FieldProps> = (props) => {
82
82
  forceUpdate();
83
83
  },
84
84
  onBlur: (event: unknown) => {
85
- validateField?.(name, 'onBlur');
85
+ // Fire-and-forget async validation; store notifies onStoreChange on completion.
86
+ void validateField?.(name, 'onBlur');
86
87
 
87
88
  // Call child component's onBlur
88
89
  if ((children.props as any).onBlur) {
@@ -49,6 +49,6 @@ A standalone form field component that works without a `<Form>` wrapper. Uses `u
49
49
  | minLength | `number` | Minimum length | - |
50
50
  | maxLength | `number` | Maximum length | - |
51
51
  | regexp | `RegExp` | Regex pattern | - |
52
- | validator | `(value: unknown) => boolean` | Custom validation function | - |
52
+ | validator | `(value: unknown) => boolean \| void \| Promise<boolean \| void>` | Custom validation function, supports sync and async (see Form.Rule) | - |
53
53
  | message | `string` | Error message (required) | - |
54
54
  | validateTrigger | `'onBlur' \| 'onChange' \| 'onSubmit' \| Array` | When to trigger validation | - |
@@ -49,6 +49,6 @@ toc: 'content'
49
49
  | minLength | `number` | 最小长度 | - |
50
50
  | maxLength | `number` | 最大长度 | - |
51
51
  | regexp | `RegExp` | 正则校验 | - |
52
- | validator | `(value: unknown) => boolean` | 自定义校验函数 | - |
52
+ | validator | `(value: unknown) => boolean \| void \| Promise<boolean \| void>` | 自定义校验函数,支持同步与异步(详见 Form.Rule) | - |
53
53
  | message | `string` | 错误提示信息(必填) | - |
54
54
  | validateTrigger | `'onBlur' \| 'onChange' \| 'onSubmit' \| Array` | 校验触发时机 | - |
@@ -8,8 +8,8 @@ import { FloatButtonGroupCtx } from './float-button-group';
8
8
  import type { FloatButtonProps } from './interface';
9
9
  import './style/index.less';
10
10
 
11
- const FloatButton = React.forwardRef(
12
- (baseprops: FloatButtonProps, ref: any) => {
11
+ const FloatButton = React.forwardRef<HTMLButtonElement, FloatButtonProps>(
12
+ (baseprops, ref) => {
13
13
  const { floatbutton } = useContext(GlobalContext);
14
14
  const props = mergeContextToProps(baseprops, floatbutton);
15
15
  const {
@@ -26,7 +26,9 @@ const FloatButton = React.forwardRef(
26
26
  ...rest
27
27
  } = props;
28
28
 
29
- const componentRef = ref || React.createRef();
29
+ const componentRef =
30
+ (ref as React.RefObject<HTMLButtonElement | null>) ||
31
+ React.createRef<HTMLButtonElement>();
30
32
 
31
33
  const onMove = (pos: { x: number; y: number }) => {
32
34
  // Check if element exists before operating
@@ -139,10 +139,9 @@ const Field: React.FC<FieldProps> = (props) => {
139
139
  props?.onChange?.(_value, ...rest);
140
140
  },
141
141
  onBlur: (event: unknown) => {
142
- const err = validateField?.(normalizedName, 'onBlur');
143
- if (err.length) {
144
- forceUpdate();
145
- }
142
+ // Fire-and-forget; the store calls onStoreChange (→ forceUpdate) when
143
+ // the (possibly async) validation completes, so the error UI refreshes.
144
+ void validateField?.(normalizedName, 'onBlur');
146
145
  props?.onBlur?.(event);
147
146
  },
148
147
  };
package/src/Form/Form.tsx CHANGED
@@ -60,7 +60,7 @@ const Form: React.FC<FormProps> = (baseprops) => {
60
60
  onSubmit={(e) => {
61
61
  e.preventDefault();
62
62
  e.stopPropagation();
63
- formInstance.submit();
63
+ void formInstance.submit();
64
64
  }}
65
65
  onReset={(e) => {
66
66
  e.preventDefault();
@@ -9,6 +9,7 @@ import React, {
9
9
  useRef,
10
10
  } from 'react';
11
11
  import Grid from '../Grid';
12
+ import { runValidator } from './utils/validate';
12
13
  import FieldContext from './FieldContext';
13
14
  import FormContext from './FormContext';
14
15
  import type { FieldGroupProps, NamePath, ValidateMessage } from './interface';
@@ -38,7 +39,9 @@ const Group: React.FC<FieldGroupProps> = (props) => {
38
39
  const [, forceValidate] = useReducer((x) => x + 1, 0); // eslint-disable-line @typescript-eslint/no-unused-vars
39
40
 
40
41
  // Group validation
41
- const validate = (force: boolean): ValidateMessage[] => {
42
+ const validate = async (
43
+ force: boolean,
44
+ ): Promise<ValidateMessage[]> => {
42
45
  if (!required && (!rules || rules.length === 0)) return [];
43
46
 
44
47
  // Skip if not touched and not forced validation
@@ -66,21 +69,21 @@ const Group: React.FC<FieldGroupProps> = (props) => {
66
69
  }
67
70
  }
68
71
 
69
- // Custom rules validation
72
+ // Custom rules validation (supports sync + async validators)
70
73
  if (rules) {
71
- rules.forEach((rule) => {
74
+ for (const rule of rules) {
72
75
  if (rule.validator) {
73
- const passed = rule.validator(values);
74
- if (!passed) {
76
+ const result = await runValidator(rule.validator, values);
77
+ if (!result.passed) {
75
78
  errors.push({
76
79
  name: childNames,
77
80
  status: 'error',
78
81
  value: values,
79
- message: rule.message || '',
82
+ message: result.message ?? rule.message ?? '',
80
83
  });
81
84
  }
82
85
  }
83
- });
86
+ }
84
87
  }
85
88
 
86
89
  return errors;
@@ -92,8 +95,8 @@ const Group: React.FC<FieldGroupProps> = (props) => {
92
95
  [],
93
96
  );
94
97
 
95
- const runValidation = () => {
96
- const result = validate(false);
98
+ const runValidation = async () => {
99
+ const result = await validate(false);
97
100
  setErrors(result);
98
101
  };
99
102
 
@@ -102,7 +105,7 @@ const Group: React.FC<FieldGroupProps> = (props) => {
102
105
  const unsubscribes = childNames.map((name) =>
103
106
  formInstance.subscribe(name, () => {
104
107
  touchedRef.current = true;
105
- runValidation();
108
+ void runValidation();
106
109
  }),
107
110
  );
108
111
  return () => unsubscribes.forEach((fn) => fn());
@@ -111,8 +114,8 @@ const Group: React.FC<FieldGroupProps> = (props) => {
111
114
  // Register group validator to FormStore
112
115
  useEffect(() => {
113
116
  const unregister = formInstance.registerGroupEntity(groupId, {
114
- validate: (force) => {
115
- const result = validate(force);
117
+ validate: async (force) => {
118
+ const result = await validate(force);
116
119
  setErrors(result);
117
120
  forceUpdate();
118
121
  return result;
package/src/Form/List.tsx CHANGED
@@ -68,7 +68,7 @@ const List: React.FC<FormListProps> = ({
68
68
 
69
69
  // List operation methods
70
70
  const operations = useMemo(() => {
71
- const add = (defaultValue?: any, insertIndex?: number) => {
71
+ const add = async (defaultValue?: any, insertIndex?: number) => {
72
72
  const currentValue = getListValue();
73
73
  const pathStr = prefixName.join('.');
74
74
 
@@ -83,8 +83,8 @@ const List: React.FC<FormListProps> = ({
83
83
  }
84
84
  });
85
85
 
86
- // Execute validation
87
- const errors = validateFields?.(fieldPaths);
86
+ // Execute validation (async — await before deciding whether to add)
87
+ const errors = await validateFields?.(fieldPaths);
88
88
 
89
89
  // If errors exist, prevent adding and show errors
90
90
  if (errors && errors.length > 0) {
@@ -0,0 +1,71 @@
1
+ import { Button, Form, Grid, Input, Space } from '@rainbow-oh/yee-c';
2
+ import React from 'react';
3
+
4
+ // Simulate an async uniqueness check against a backend API.
5
+ const TAKEN_USERNAMES = new Set(['admin', 'root', 'test']);
6
+ function checkUsernameUnique(username: string): Promise<boolean> {
7
+ return new Promise((resolve) => {
8
+ setTimeout(() => resolve(!TAKEN_USERNAMES.has(username)), 600);
9
+ });
10
+ }
11
+
12
+ export default () => {
13
+ const [form] = Form.useForm();
14
+
15
+ const onFinish = (values: Record<string, unknown>) => {
16
+ console.log('Received values:', values);
17
+ };
18
+
19
+ const onFinishFailed = (errorInfo: unknown) => {
20
+ console.log('Failed:', errorInfo);
21
+ };
22
+
23
+ return (
24
+ <Form form={form} onFinish={onFinish} onFinishFailed={onFinishFailed}>
25
+ <Grid>
26
+ <Form.Field
27
+ name="username"
28
+ label="Username"
29
+ rules={[
30
+ { required: true, message: 'Please input your username!' },
31
+ {
32
+ // Async validator: resolve to pass, throw / reject to fail.
33
+ // The thrown Error's message overrides rule.message.
34
+ validator: async (value) => {
35
+ const isUnique = await checkUsernameUnique(String(value));
36
+ if (!isUnique) {
37
+ throw new Error('This username is already taken');
38
+ }
39
+ },
40
+ // Validate on blur so we don't hit the "API" on every keystroke.
41
+ validateTrigger: 'onBlur',
42
+ },
43
+ ]}
44
+ >
45
+ <Input placeholder="Try admin / root / test (already taken)" />
46
+ </Form.Field>
47
+
48
+ <Form.Field
49
+ name="email"
50
+ label="Email"
51
+ rules={[
52
+ { required: true, message: 'Please input your email!' },
53
+ {
54
+ regexp: /^[\w.+-]+@[\w-]+\.[\w.-]+$/,
55
+ message: 'Please enter a valid email!',
56
+ },
57
+ ]}
58
+ >
59
+ <Input placeholder="Please input your email" />
60
+ </Form.Field>
61
+ </Grid>
62
+
63
+ <Space>
64
+ <Button type="primary" htmlType="submit">
65
+ Submit
66
+ </Button>
67
+ <Button htmlType="reset">Reset</Button>
68
+ </Space>
69
+ </Form>
70
+ );
71
+ };
@@ -64,7 +64,7 @@ export default () => {
64
64
  </Form.Field>
65
65
  </Grid.Item>
66
66
  <Grid.Item>
67
- <Form.Field name="gender" label="Gender" initialValue="male">
67
+ <Form.Field name="gender" label="Gender" initialValue="male" required>
68
68
  <Select
69
69
  options={[
70
70
  { label: 'male', value: 'male' },
@@ -76,7 +76,7 @@ export default () => {
76
76
  </Grid.Item>
77
77
 
78
78
  <Grid.Item>
79
- <Form.Field name="birthday" label="Birthday">
79
+ <Form.Field name="birthday" label="Birthday" required>
80
80
  <DatePicker />
81
81
  </Form.Field>
82
82
  </Grid.Item>
@@ -50,7 +50,7 @@ export default function Virtual() {
50
50
  type="primary"
51
51
  onClick={() => {
52
52
  const form = getForm('form');
53
- form.submit();
53
+ void form.submit();
54
54
  }}
55
55
  >
56
56
  Submit
@@ -145,13 +145,14 @@ export class FormStore {
145
145
  });
146
146
  }
147
147
 
148
- // Validate on onChange and onBlur
148
+ // Validate on onChange and onBlur (async — fire-and-forget so setFieldsValue
149
+ // stays synchronous for its callers; results surface via onStoreChange).
149
150
  if (
150
151
  trigger === 'onChange' ||
151
152
  trigger === 'onBlur' ||
152
153
  trigger === 'onSubmit'
153
154
  ) {
154
- this.validateFields(Object.keys(newStore), trigger);
155
+ void this.validateFields(Object.keys(newStore), trigger);
155
156
  }
156
157
 
157
158
  this.refreshField(newStore);
@@ -202,7 +203,10 @@ export class FormStore {
202
203
  this.setFieldsValue(clearStore, 'clear');
203
204
  };
204
205
 
205
- validateField = (name: Name, trigger?: TRIGGER) => {
206
+ validateField = async (
207
+ name: Name,
208
+ trigger?: TRIGGER,
209
+ ): Promise<ValidateMessage[]> => {
206
210
  const entity = this.fieldMap.get(name);
207
211
  if (!entity) {
208
212
  return [];
@@ -231,32 +235,40 @@ export class FormStore {
231
235
  });
232
236
  }
233
237
  const value = this.getFieldValue(name);
234
- mergedRules.forEach((rule) => {
235
- const mark = validate(rule, value);
236
- if (name && !mark) {
238
+ for (const rule of mergedRules) {
239
+ const result = await validate(rule, value);
240
+ if (name && !result.passed) {
237
241
  err.push({
242
+ ...rule,
238
243
  name: name,
239
244
  status: 'error',
240
245
  value,
241
- ...rule,
246
+ message: result.message ?? rule.message,
242
247
  } as ValidateMessage);
243
248
  }
244
- });
249
+ }
245
250
  if (err.length > 0) {
246
251
  this.validateMessages.set(name, err);
247
252
  } else if (this.validateMessages.has(name)) {
248
253
  this.validateMessages.delete(name);
249
254
  }
255
+ // Notify the field to re-render so async validation results surface in the UI.
256
+ entity?.onStoreChange();
250
257
  return err;
251
258
  };
252
259
 
253
- validateFields = (
260
+ validateFields = async (
254
261
  names = Array.from(this.fieldMap.keys()),
255
262
  trigger?: TRIGGER,
256
- ) => {
263
+ ): Promise<ValidateMessage[]> => {
264
+ // Validate fields in parallel; Promise.all preserves input order so error
265
+ // ordering stays stable regardless of how long each async validator takes.
266
+ const results = await Promise.all(
267
+ names.map((name) => this.validateField(name, trigger)),
268
+ );
257
269
  let err: ValidateMessage[] = [];
258
- names.forEach((name) => {
259
- const messages = this.validateField(name, trigger);
270
+ names.forEach((name, index) => {
271
+ const messages = results[index];
260
272
  err = err.concat(messages);
261
273
  if (messages.length > 0) {
262
274
  this.validateMessages.set(name, messages);
@@ -316,12 +328,16 @@ export class FormStore {
316
328
  };
317
329
  };
318
330
 
319
- validateGroups = (force = false): ValidateMessage[] => {
320
- let err: ValidateMessage[] = [];
321
- this.groupEntities.forEach((entity) => {
322
- err = err.concat(entity.validate(force));
323
- });
324
- return err;
331
+ validateGroups = async (force = false): Promise<ValidateMessage[]> => {
332
+ const results = await Promise.all(
333
+ Array.from(this.groupEntities.values()).map((entity) =>
334
+ entity.validate(force),
335
+ ),
336
+ );
337
+ return results.reduce(
338
+ (acc, messages) => acc.concat(messages),
339
+ [] as ValidateMessage[],
340
+ );
325
341
  };
326
342
 
327
343
  setCallbacks = (callbacks: Callbacks) => {
@@ -515,10 +531,10 @@ export class FormStore {
515
531
  };
516
532
  };
517
533
 
518
- submit = () => {
534
+ submit = async (): Promise<ValidateMessage[]> => {
519
535
  const { onFinish, onFinishFailed } = this.callbacks;
520
- const fieldErrors = this.validateFields();
521
- const groupErrors = this.validateGroups(true);
536
+ const fieldErrors = await this.validateFields();
537
+ const groupErrors = await this.validateGroups(true);
522
538
  const allErrors = [...fieldErrors, ...groupErrors];
523
539
  if (allErrors.length === 0) {
524
540
  onFinish?.(this.getFieldsValue());
@@ -20,6 +20,7 @@ High performance form component with data scope management.
20
20
  <code src="./demo/watch.tsx" title="Field Watch" description="useWatch monitors field value changes for conditional rendering"></code>
21
21
  <code src="./demo/layout.tsx" title="Layout" description="Different form layouts"></code>
22
22
  <code src="./demo/validate.tsx" title="Validation" description="Form validation"></code>
23
+ <code src="./demo/async-validate.tsx" title="Async Validation" description="async validator for server-side checks like uniqueness"></code>
23
24
  <code src="./demo/list.tsx" title="Form List" description="Form list field usage"></code>
24
25
  <code src="./demo/form-table.tsx" title="Form Table" description="Form table field usage"></code>
25
26
  <code src="./demo/dynamic.tsx" title="Dynamic Form" description="Dynamic form items"></code>
@@ -50,16 +51,16 @@ High performance form component with data scope management.
50
51
 
51
52
  | Property | Type | Description |
52
53
  | --------------------- | ------------------------------------------------------------------------------------------ | ------------------------- |
53
- | getFieldValidate | `(name: Name) => ValidateMessage \| null` | Get field validation |
54
+ | getFieldValidate | `(name: Name) => ValidateMessage \| null` | Get field validation (may lag before async validation completes; updates via onStoreChange) |
54
55
  | getFieldValue | `(name: Name) => StoreValue` | Get field value |
55
- | submit | `() => void` | Submit form |
56
+ | submit | `() => Promise<ValidateMessage[]>` | Submit form (async, triggers onFinish only after validation completes) |
56
57
  | getFieldsValue | `() => Values` | Get all field values |
57
58
  | setFieldsValue | `(newStore: Store, trigger?: TRIGGER) => void` | Set field values |
58
59
  | setCallbacks | `(callbacks: Callbacks) => void` | Set callbacks |
59
60
  | resetFields | `(name?: Name[]) => void` | Reset fields |
60
61
  | clearFields | `(name?: Name[]) => void` | Clear fields |
61
- | validateField | `(name: Name, trigger?: 'onChange' \| 'onBlur') => ValidateMessage[]` | Validate single field |
62
- | validateFields | `(names?: Name[], trigger?: TRIGGER) => ValidateMessage[]` | Validate multiple fields |
62
+ | validateField | `(name: Name, trigger?: 'onChange' \| 'onBlur') => Promise<ValidateMessage[]>` | Validate single field |
63
+ | validateFields | `(names?: Name[], trigger?: TRIGGER) => Promise<ValidateMessage[]>` | Validate multiple fields |
63
64
  | getCallbacks | `() => Callbacks` | Get callbacks |
64
65
  | registerFieldEntities | `(entity: FieldEntity) => void` | Register field entities |
65
66
  | initialize | `({ initialValues, callbacks }: { initialValues?: Store; callbacks?: Callbacks }) => void` | Initialize form |
@@ -117,7 +118,7 @@ High performance form component with data scope management.
117
118
  | maxLength | `number` | Maximum length |
118
119
  | regexp | `RegExp` | Regular expression |
119
120
  | message | `string` | Error message |
120
- | validator | `(value: unknown) => boolean` | Custom validator function |
121
+ | validator | `(value: unknown) => boolean \| void \| Promise<boolean \| void>` | Custom validator. Supports sync and async: sync `return false`/`throw` fails; async `resolve(false)`/`reject`/`throw` fails. When throwing/rejecting with an Error, `error.message` overrides `message` |
121
122
  | validateTrigger | `'onBlur' \| 'onChange' \| 'onSubmit' \| Array<'onBlur' \| 'onChange' \| 'onSubmit'>` | Validation trigger |
122
123
 
123
124
  ### Types
@@ -22,6 +22,7 @@ toc: 'content'
22
22
  <code src="./demo/form-table.tsx" title="表单列表" description="Form的列表字段用法"></code>
23
23
  <code src="./demo/layout.tsx" title="表单布局" description="不同的表单布局"></code>
24
24
  <code src="./demo/validate.tsx" title="表单校验" description="表单校验功能"></code>
25
+ <code src="./demo/async-validate.tsx" title="异步校验" description="async validator 实现服务端唯一性校验等异步场景"></code>
25
26
 
26
27
  ## API
27
28
 
@@ -49,16 +50,16 @@ toc: 'content'
49
50
 
50
51
  | 属性名 | 类型 | 描述 |
51
52
  | --------------------- | ------------------------------------------------------------------------------------------ | ------------------------------------------ |
52
- | getFieldValidate | `(name: Name) => ValidateMessage \| null` | 获取字段验证 |
53
+ | getFieldValidate | `(name: Name) => ValidateMessage \| null` | 获取字段验证(异步校验未完成时可能读到旧值,最终会随 onStoreChange 更新) |
53
54
  | getFieldValue | `(name: Name) => StoreValue` | 获取字段值 |
54
- | submit | `() => void` | 提交表单 |
55
+ | submit | `() => Promise<ValidateMessage[]>` | 提交表单(异步,校验完成后才触发 onFinish) |
55
56
  | getFieldsValue | `() => Values` | 获取所有字段值 |
56
57
  | setFieldsValue | `(newStore: Store, trigger?: TRIGGER) => void` | 设置字段值 |
57
58
  | setCallbacks | `(callbacks: Callbacks) => void` | 设置回调 |
58
59
  | resetFields | `(name?: Name[]) => void` | 重置字段 |
59
60
  | clearFields | `(name?: Name[]) => void` | 清空字段 |
60
- | validateField | `(name: Name, trigger?: 'onChange' \| 'onBlur') => ValidateMessage[]` | 校验单个字段 |
61
- | validateFields | `(names?: Name[], trigger?: TRIGGER) => ValidateMessage[]` | 校验多个字段 |
61
+ | validateField | `(name: Name, trigger?: 'onChange' \| 'onBlur') => Promise<ValidateMessage[]>` | 校验单个字段 |
62
+ | validateFields | `(names?: Name[], trigger?: TRIGGER) => Promise<ValidateMessage[]>` | 校验多个字段 |
62
63
  | getCallbacks | `() => Callbacks` | 获取回调 |
63
64
  | registerFieldEntities | `(entity: FieldEntity) => void` | 注册字段实体 |
64
65
  | initialize | `({ initialValues, callbacks }: { initialValues?: Store; callbacks?: Callbacks }) => void` | 初始化表单 |
@@ -116,7 +117,7 @@ toc: 'content'
116
117
  | maxLength | `number` | 最大长度 |
117
118
  | regexp | `RegExp` | 正则表达式 |
118
119
  | message | `string` | 错误信息 |
119
- | validator | `(value: unknown) => boolean` | 自定义校验函数 |
120
+ | validator | `(value: unknown) => boolean \| void \| Promise<boolean \| void>` | 自定义校验函数,支持同步与异步。同步返回 `false` 或 `throw` 表示失败;异步 `resolve(false)`/`reject`/`throw` 表示失败。`throw`/`reject` 时 `error.message` 覆盖 `message` |
120
121
  | validateTrigger | `'onBlur' \| 'onChange' \| 'onSubmit' \| Array<'onBlur' \| 'onChange' \| 'onSubmit'>` | 校验触发时机 |
121
122
 
122
123
  ### Types