@rainbow-oh/yee-c 0.1.0 → 0.2.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 (228) hide show
  1. package/dist/cjs/Alert/alert.js +10 -4
  2. package/dist/cjs/Alert/style/index.less +3 -0
  3. package/dist/cjs/Anchor/anchor-item.js +6 -4
  4. package/dist/cjs/Anchor/anchor.js +38 -22
  5. package/dist/cjs/Anchor/demo/auto.d.ts +11 -0
  6. package/dist/cjs/Anchor/demo/auto.js +85 -0
  7. package/dist/cjs/Anchor/demo/basic.js +7 -1
  8. package/dist/cjs/Anchor/demo/controlled.js +42 -30
  9. package/dist/cjs/Anchor/interface.d.ts +2 -0
  10. package/dist/cjs/Anchor/style/index.less +2 -2
  11. package/dist/cjs/Button/button.d.ts +1 -1
  12. package/dist/cjs/Checkbox/checkbox-group.js +4 -1
  13. package/dist/cjs/Checkbox/demo/group.js +1 -0
  14. package/dist/cjs/Checkbox/interface.d.ts +5 -0
  15. package/dist/cjs/Checkbox/style/index.less +21 -1
  16. package/dist/cjs/Dropdown/demo/placement.js +2 -1
  17. package/dist/cjs/Dropdown/dropdown.js +3 -0
  18. package/dist/cjs/Dropdown/style/index.less +6 -0
  19. package/dist/cjs/Form/Field.js +33 -3
  20. package/dist/cjs/Form/Group.js +3 -2
  21. package/dist/cjs/Form/demo/form-table.js +1 -8
  22. package/dist/cjs/Form/demo/tooltip.d.ts +3 -0
  23. package/dist/cjs/Form/demo/tooltip.js +84 -0
  24. package/dist/cjs/Form/interface.d.ts +34 -1
  25. package/dist/cjs/Form/style/index.less +22 -7
  26. package/dist/cjs/Popconfirm/popconfirm.js +1 -1
  27. package/dist/cjs/Popconfirm/style/index.less +6 -0
  28. package/dist/cjs/Popover/popover.js +1 -1
  29. package/dist/cjs/Popover/style/index.less +6 -0
  30. package/dist/cjs/Progress/progress.js +2 -2
  31. package/dist/cjs/Radio/style/index.less +13 -6
  32. package/dist/cjs/Select/option.js +3 -2
  33. package/dist/cjs/Select/options.js +9 -1
  34. package/dist/cjs/Select/select.js +1 -0
  35. package/dist/cjs/Skeleton/demo/basic.js +1 -1
  36. package/dist/cjs/Space/interface.d.ts +4 -0
  37. package/dist/cjs/Space/space.js +36 -16
  38. package/dist/cjs/Splitter/demo/basic.js +1 -1
  39. package/dist/cjs/Splitter/demo/vertical.js +23 -1
  40. package/dist/cjs/Splitter/index.d.ts +1 -1
  41. package/dist/cjs/Splitter/interface.d.ts +9 -3
  42. package/dist/cjs/Splitter/splitter-handler.d.ts +1 -1
  43. package/dist/cjs/Splitter/splitter-handler.js +2 -1
  44. package/dist/cjs/Splitter/splitter.d.ts +2 -9
  45. package/dist/cjs/Splitter/splitter.js +53 -50
  46. package/dist/cjs/Splitter/style/index.less +21 -0
  47. package/dist/cjs/Table/demo/size.js +1 -1
  48. package/dist/cjs/Tabs/hooks/useTabScroll.d.ts +1 -1
  49. package/dist/cjs/Tabs/interface.d.ts +1 -1
  50. package/dist/cjs/Tabs/style/index.less +4 -0
  51. package/dist/cjs/Tabs/tab-header/index.js +56 -25
  52. package/dist/cjs/Tooltip/interface.d.ts +4 -0
  53. package/dist/cjs/Tooltip/style/index.less +8 -8
  54. package/dist/cjs/Tooltip/tooltip.js +11 -3
  55. package/dist/cjs/Tree/demo/draggable.d.ts +3 -0
  56. package/dist/cjs/Tree/demo/draggable.js +88 -0
  57. package/dist/cjs/Tree/demo/expanded.js +6 -6
  58. package/dist/cjs/Tree/index.d.ts +1 -0
  59. package/dist/cjs/Tree/index.js +3 -1
  60. package/dist/cjs/Tree/interface.d.ts +26 -0
  61. package/dist/cjs/Tree/style/index.less +25 -0
  62. package/dist/cjs/Tree/tree-node.js +38 -4
  63. package/dist/cjs/Tree/tree.d.ts +12 -1
  64. package/dist/cjs/Tree/tree.js +174 -18
  65. package/dist/cjs/Tree/utils/tree-tools.d.ts +21 -0
  66. package/dist/cjs/Tree/utils/tree-tools.js +88 -0
  67. package/dist/cjs/Trigger/style/index.less +17 -0
  68. package/dist/cjs/Trigger/trigger.js +3 -1
  69. package/dist/cjs/hooks/useDebounceFunction.d.ts +1 -1
  70. package/dist/cjs/hooks/useLayoutEffect.d.ts +1 -1
  71. package/dist/cjs/style/size.css +13 -4
  72. package/dist/cjs/style/themes.css +1 -1
  73. package/dist/cjs/style/variables.css +14 -5
  74. package/dist/cjs/utils/debounce.d.ts +6 -1
  75. package/dist/cjs/utils/debounce.js +9 -1
  76. package/dist/cjs/version.d.ts +1 -1
  77. package/dist/cjs/version.js +1 -1
  78. package/dist/esm/Alert/alert.js +24 -8
  79. package/dist/esm/Alert/style/index.less +3 -0
  80. package/dist/esm/Anchor/anchor-item.js +6 -3
  81. package/dist/esm/Anchor/anchor.js +38 -19
  82. package/dist/esm/Anchor/demo/auto.d.ts +11 -0
  83. package/dist/esm/Anchor/demo/auto.js +62 -0
  84. package/dist/esm/Anchor/demo/basic.js +3 -1
  85. package/dist/esm/Anchor/demo/controlled.js +14 -9
  86. package/dist/esm/Anchor/interface.d.ts +2 -0
  87. package/dist/esm/Anchor/style/index.less +2 -2
  88. package/dist/esm/Button/button.d.ts +1 -1
  89. package/dist/esm/Checkbox/checkbox-group.js +4 -2
  90. package/dist/esm/Checkbox/demo/group.js +1 -0
  91. package/dist/esm/Checkbox/interface.d.ts +5 -0
  92. package/dist/esm/Checkbox/style/index.less +21 -1
  93. package/dist/esm/Dropdown/demo/placement.js +2 -1
  94. package/dist/esm/Dropdown/dropdown.js +6 -1
  95. package/dist/esm/Dropdown/style/index.less +6 -0
  96. package/dist/esm/Form/Field.js +43 -5
  97. package/dist/esm/Form/Group.js +4 -2
  98. package/dist/esm/Form/demo/form-table.js +8 -6
  99. package/dist/esm/Form/demo/tooltip.d.ts +3 -0
  100. package/dist/esm/Form/demo/tooltip.js +59 -0
  101. package/dist/esm/Form/interface.d.ts +34 -1
  102. package/dist/esm/Form/style/index.less +22 -7
  103. package/dist/esm/Popconfirm/popconfirm.js +3 -1
  104. package/dist/esm/Popconfirm/style/index.less +6 -0
  105. package/dist/esm/Popover/popover.js +3 -1
  106. package/dist/esm/Popover/style/index.less +6 -0
  107. package/dist/esm/Progress/progress.js +5 -5
  108. package/dist/esm/Radio/style/index.less +13 -6
  109. package/dist/esm/Select/option.js +4 -2
  110. package/dist/esm/Select/options.js +5 -3
  111. package/dist/esm/Select/select.js +1 -0
  112. package/dist/esm/Skeleton/demo/basic.js +2 -8
  113. package/dist/esm/Space/interface.d.ts +4 -0
  114. package/dist/esm/Space/space.js +24 -13
  115. package/dist/esm/Splitter/demo/basic.js +2 -0
  116. package/dist/esm/Splitter/demo/vertical.js +13 -5
  117. package/dist/esm/Splitter/index.d.ts +1 -1
  118. package/dist/esm/Splitter/interface.d.ts +9 -3
  119. package/dist/esm/Splitter/splitter-handler.d.ts +1 -1
  120. package/dist/esm/Splitter/splitter-handler.js +3 -1
  121. package/dist/esm/Splitter/splitter.d.ts +2 -9
  122. package/dist/esm/Splitter/splitter.js +59 -56
  123. package/dist/esm/Splitter/style/index.less +21 -0
  124. package/dist/esm/Table/demo/size.js +2 -7
  125. package/dist/esm/Tabs/hooks/useTabScroll.d.ts +1 -1
  126. package/dist/esm/Tabs/interface.d.ts +1 -1
  127. package/dist/esm/Tabs/style/index.less +4 -0
  128. package/dist/esm/Tabs/tab-header/index.js +11 -5
  129. package/dist/esm/Tooltip/interface.d.ts +4 -0
  130. package/dist/esm/Tooltip/style/index.less +8 -8
  131. package/dist/esm/Tooltip/tooltip.js +14 -2
  132. package/dist/esm/Tree/demo/draggable.d.ts +3 -0
  133. package/dist/esm/Tree/demo/draggable.js +61 -0
  134. package/dist/esm/Tree/demo/expanded.js +6 -6
  135. package/dist/esm/Tree/index.d.ts +1 -0
  136. package/dist/esm/Tree/index.js +1 -0
  137. package/dist/esm/Tree/interface.d.ts +26 -0
  138. package/dist/esm/Tree/style/index.less +25 -0
  139. package/dist/esm/Tree/tree-node.js +29 -4
  140. package/dist/esm/Tree/tree.d.ts +12 -1
  141. package/dist/esm/Tree/tree.js +135 -4
  142. package/dist/esm/Tree/utils/tree-tools.d.ts +21 -0
  143. package/dist/esm/Tree/utils/tree-tools.js +128 -1
  144. package/dist/esm/Trigger/style/index.less +17 -0
  145. package/dist/esm/Trigger/trigger.js +4 -3
  146. package/dist/esm/hooks/useDebounceFunction.d.ts +1 -1
  147. package/dist/esm/hooks/useLayoutEffect.d.ts +1 -1
  148. package/dist/esm/style/size.css +13 -4
  149. package/dist/esm/style/themes.css +1 -1
  150. package/dist/esm/style/variables.css +14 -5
  151. package/dist/esm/utils/debounce.d.ts +6 -1
  152. package/dist/esm/utils/debounce.js +9 -2
  153. package/dist/esm/version.d.ts +1 -1
  154. package/dist/esm/version.js +1 -1
  155. package/dist/umd/yee-c.min.css +2 -2
  156. package/dist/umd/yee-c.min.js +1 -1
  157. package/package.json +21 -23
  158. package/src/Alert/alert.tsx +10 -4
  159. package/src/Alert/style/index.less +3 -0
  160. package/src/Anchor/anchor-item.tsx +7 -2
  161. package/src/Anchor/anchor.tsx +49 -23
  162. package/src/Anchor/demo/auto.tsx +55 -0
  163. package/src/Anchor/demo/basic.tsx +7 -1
  164. package/src/Anchor/demo/controlled.tsx +18 -14
  165. package/src/Anchor/index.en-US.md +17 -0
  166. package/src/Anchor/index.zh-CN.md +17 -0
  167. package/src/Anchor/interface.ts +2 -0
  168. package/src/Anchor/style/index.less +2 -2
  169. package/src/Checkbox/checkbox-group.tsx +5 -1
  170. package/src/Checkbox/demo/group.tsx +1 -0
  171. package/src/Checkbox/interface.ts +5 -0
  172. package/src/Checkbox/style/index.less +21 -1
  173. package/src/Dropdown/demo/placement.tsx +1 -0
  174. package/src/Dropdown/dropdown.tsx +2 -0
  175. package/src/Dropdown/style/index.less +6 -0
  176. package/src/Form/Field.tsx +45 -3
  177. package/src/Form/Group.tsx +4 -1
  178. package/src/Form/demo/form-table.tsx +7 -7
  179. package/src/Form/demo/tooltip.tsx +72 -0
  180. package/src/Form/form-store.ts +1 -1
  181. package/src/Form/index.en-US.md +2 -0
  182. package/src/Form/index.zh-CN.md +83 -85
  183. package/src/Form/interface.ts +36 -1
  184. package/src/Form/style/index.less +22 -7
  185. package/src/Popconfirm/popconfirm.tsx +1 -1
  186. package/src/Popconfirm/style/index.less +6 -0
  187. package/src/Popover/popover.tsx +1 -1
  188. package/src/Popover/style/index.less +6 -0
  189. package/src/Progress/progress.tsx +2 -2
  190. package/src/Radio/style/index.less +13 -6
  191. package/src/Select/option.tsx +2 -1
  192. package/src/Select/options.tsx +7 -2
  193. package/src/Select/select.tsx +1 -0
  194. package/src/Skeleton/demo/basic.tsx +3 -3
  195. package/src/Space/interface.ts +4 -0
  196. package/src/Space/space.tsx +40 -16
  197. package/src/Splitter/demo/basic.tsx +2 -2
  198. package/src/Splitter/demo/vertical.tsx +19 -5
  199. package/src/Splitter/index.ts +5 -1
  200. package/src/Splitter/interface.ts +10 -3
  201. package/src/Splitter/splitter-handler.tsx +4 -2
  202. package/src/Splitter/splitter.tsx +55 -60
  203. package/src/Splitter/style/index.less +21 -0
  204. package/src/Table/demo/size.tsx +3 -3
  205. package/src/Table/index.zh-CN.md +50 -50
  206. package/src/Tabs/interface.ts +1 -1
  207. package/src/Tabs/style/index.less +4 -0
  208. package/src/Tabs/tab-header/index.tsx +26 -5
  209. package/src/Tooltip/index.en-US.md +1 -0
  210. package/src/Tooltip/index.zh-CN.md +1 -0
  211. package/src/Tooltip/interface.ts +4 -0
  212. package/src/Tooltip/style/index.less +8 -8
  213. package/src/Tooltip/tooltip.tsx +10 -1
  214. package/src/Tree/demo/draggable.tsx +58 -0
  215. package/src/Tree/demo/expanded.tsx +7 -7
  216. package/src/Tree/index.en-US.md +3 -0
  217. package/src/Tree/index.ts +1 -0
  218. package/src/Tree/index.zh-CN.md +3 -0
  219. package/src/Tree/interface.ts +28 -0
  220. package/src/Tree/style/index.less +25 -0
  221. package/src/Tree/tree-node.tsx +26 -0
  222. package/src/Tree/tree.tsx +183 -2
  223. package/src/Tree/utils/tree-tools.ts +107 -0
  224. package/src/Trigger/style/index.less +17 -0
  225. package/src/Trigger/trigger.tsx +3 -1
  226. package/src/style/size.css +13 -4
  227. package/src/utils/debounce.ts +22 -3
  228. package/src/version.ts +1 -1
@@ -1,10 +1,17 @@
1
1
  import clsx from 'clsx';
2
+ import { HelpCircle } from 'lucide-react';
2
3
  import { AnimatePresence, motion } from 'motion/react';
3
4
  import React, { useContext, useLayoutEffect, useMemo, useReducer } from 'react';
5
+ import Tooltip from '../Tooltip';
4
6
  import FieldContext from './FieldContext';
5
7
  import FormContext from './FormContext';
6
8
  import { ListNameContext } from './List';
7
- import type { FieldProps, InternalNamePath, NamePath } from './interface';
9
+ import type {
10
+ FieldConfigurableTooltip,
11
+ FieldProps,
12
+ InternalNamePath,
13
+ NamePath,
14
+ } from './interface';
8
15
 
9
16
  // Helper function: convert NamePath to InternalNamePath
10
17
  function getNamePath(path: NamePath): InternalNamePath {
@@ -24,9 +31,11 @@ const Field: React.FC<FieldProps> = (props) => {
24
31
  name,
25
32
  rules,
26
33
  label,
34
+ tooltip,
27
35
  required,
28
36
  disabled,
29
37
  valuePropName = 'value',
38
+ layout = 'vertical',
30
39
  formatter,
31
40
  } = props;
32
41
  const {
@@ -77,6 +86,29 @@ const Field: React.FC<FieldProps> = (props) => {
77
86
 
78
87
  const validate = getFieldValidate?.(normalizedName);
79
88
 
89
+ // Normalize tooltip into { icon, ...tooltipProps }, or null when not provided.
90
+ // Everything except `icon` is forwarded to <Tooltip>, so any Tooltip prop
91
+ // (title, color, placement, ...) is supported automatically.
92
+ const tooltipConfig = useMemo<
93
+ | { icon: React.ReactNode; tooltipProps: Omit<FieldConfigurableTooltip, 'icon'> }
94
+ | null
95
+ >(() => {
96
+ if (tooltip === undefined || tooltip === null || tooltip === false)
97
+ return null;
98
+ if (
99
+ typeof tooltip === 'object' &&
100
+ !React.isValidElement(tooltip) &&
101
+ 'title' in (tooltip as object)
102
+ ) {
103
+ const { icon, ...rest } = tooltip as FieldConfigurableTooltip;
104
+ return { icon: icon ?? <HelpCircle size={14} />, tooltipProps: rest };
105
+ }
106
+ return {
107
+ icon: <HelpCircle size={14} />,
108
+ tooltipProps: { title: tooltip as React.ReactNode },
109
+ };
110
+ }, [tooltip]);
111
+
80
112
  const getControlled = (children: React.ReactElement) => {
81
113
  const props = children.props as any;
82
114
  const _value = getFieldValue?.(normalizedName) ?? undefined;
@@ -113,12 +145,12 @@ const Field: React.FC<FieldProps> = (props) => {
113
145
  };
114
146
  return (
115
147
  <div
116
- className={clsx(`${prefixCls}-item`, {
148
+ className={clsx(`${prefixCls}-item`, `${prefixCls}-item-${layout}`, {
117
149
  [`${prefixCls}-item-${validate?.status}`]: validate && validate.status,
118
150
  })}
119
151
  >
120
152
  <div className={clsx(`${prefixCls}-item-row`)}>
121
- {label ? (
153
+ {label || tooltipConfig ? (
122
154
  <label
123
155
  htmlFor={normalizedName}
124
156
  className={clsx(`${prefixCls}-item-label`, {
@@ -126,6 +158,16 @@ const Field: React.FC<FieldProps> = (props) => {
126
158
  })}
127
159
  >
128
160
  {label}
161
+ {isRequired() ? (
162
+ <span className={`${prefixCls}-item-required-mark`}>*</span>
163
+ ) : null}
164
+ {tooltipConfig ? (
165
+ <Tooltip {...tooltipConfig.tooltipProps}>
166
+ <span className={`${prefixCls}-item-tooltip-icon`}>
167
+ {tooltipConfig.icon}
168
+ </span>
169
+ </Tooltip>
170
+ ) : null}
129
171
  </label>
130
172
  ) : null}
131
173
  <div className={`${prefixCls}-item-control`}>
@@ -76,7 +76,7 @@ const Group: React.FC<FieldGroupProps> = (props) => {
76
76
  name: childNames,
77
77
  status: 'error',
78
78
  value: values,
79
- message: rule.message,
79
+ message: rule.message || '',
80
80
  });
81
81
  }
82
82
  }
@@ -145,6 +145,9 @@ const Group: React.FC<FieldGroupProps> = (props) => {
145
145
  })}
146
146
  >
147
147
  {label}
148
+ {required ? (
149
+ <span className={`${itemCls}-required-mark`}>*</span>
150
+ ) : null}
148
151
  </label>
149
152
  )}
150
153
  <div className={`${itemCls}-control`}>{content}</div>
@@ -15,13 +15,13 @@ export default () => {
15
15
  <Form form={form} onFinish={onFinish} layout="vertical">
16
16
  <Form.List
17
17
  name="users"
18
- initialValue={[
19
- {
20
- name: '',
21
- age: '',
22
- address: '',
23
- },
24
- ]}
18
+ // initialValue={[
19
+ // {
20
+ // name: '',
21
+ // age: '',
22
+ // address: '',
23
+ // },
24
+ // ]}
25
25
  >
26
26
  {(fields, operations) => {
27
27
  // Define column config - operations are accessible here
@@ -0,0 +1,72 @@
1
+ import {
2
+ Button,
3
+ Form,
4
+ Grid,
5
+ Input,
6
+ Space,
7
+ TextArea,
8
+ } from '@rainbow-oh/yee-c';
9
+ import { Info } from 'lucide-react';
10
+ import React from 'react';
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
+ return (
20
+ <Form
21
+ form={form}
22
+ onFinish={onFinish}
23
+ layout="vertical"
24
+ data-testid="tooltip-form"
25
+ >
26
+ <Grid>
27
+ <Grid.Item>
28
+ <Form.Field
29
+ name="username"
30
+ label="Username"
31
+ tooltip="Used for login. 4-20 characters."
32
+ rules={[
33
+ { required: true, message: 'Please input your username!' },
34
+ ]}
35
+ >
36
+ <Input placeholder="Please input your username" />
37
+ </Form.Field>
38
+ </Grid.Item>
39
+
40
+ <Grid.Item>
41
+ <Form.Field
42
+ name="nickname"
43
+ label="Nickname"
44
+ // Custom trigger icon via the object form
45
+ tooltip={{
46
+ title: 'Shown publicly instead of your username.',
47
+ icon: <Info size={14} />,
48
+ }}
49
+ >
50
+ <Input placeholder="Please input your nickname" />
51
+ </Form.Field>
52
+ </Grid.Item>
53
+
54
+ <Grid.Item>
55
+ <Form.Field
56
+ name="bio"
57
+ label="Bio"
58
+ tooltip="A short introduction about yourself."
59
+ >
60
+ <TextArea />
61
+ </Form.Field>
62
+ </Grid.Item>
63
+ </Grid>
64
+ <Space style={{ marginTop: 16 }}>
65
+ <Button type="primary" htmlType="submit">
66
+ Submit
67
+ </Button>
68
+ <Button htmlType="reset">Reset</Button>
69
+ </Space>
70
+ </Form>
71
+ );
72
+ };
@@ -239,7 +239,7 @@ export class FormStore {
239
239
  status: 'error',
240
240
  value,
241
241
  ...rule,
242
- });
242
+ } as ValidateMessage);
243
243
  }
244
244
  });
245
245
  if (err.length > 0) {
@@ -15,6 +15,7 @@ High performance form component with data scope management.
15
15
  ## Code Demo
16
16
 
17
17
  <code src="./demo/basic.tsx" title="Basic" description="Basic usage of Form"></code>
18
+ <code src="./demo/tooltip.tsx" title="Label Tooltip" description="Show a help icon next to the label, with a customizable trigger icon"></code>
18
19
  <code src="./demo/group.tsx" title="Field Group" description="Field.Group with shared label and group-level validation"></code>
19
20
  <code src="./demo/watch.tsx" title="Field Watch" description="useWatch monitors field value changes for conditional rendering"></code>
20
21
  <code src="./demo/layout.tsx" title="Layout" description="Different form layouts"></code>
@@ -92,6 +93,7 @@ High performance form component with data scope management.
92
93
  | name | `NamePath` | Field name | - |
93
94
  | rules | [Rule\[\]](#rule) | Validation rules | - |
94
95
  | label | `React.ReactNode` | Label | - |
96
+ | tooltip | `ReactNode \| (Omit<TooltipProps, 'children'> & { icon?: ReactNode })` | Help tooltip next to the label. Pass a string/node to use the default icon; pass an object to customize `icon` — all other props (`title`, `color`, `placement`, ...) are forwarded to Tooltip | - |
95
97
  | required | `boolean` | Whether required | - |
96
98
  | disabled | `boolean` | Whether disabled | - |
97
99
  | initialValue | `unknown` | Initial value | - |
@@ -15,6 +15,7 @@ toc: 'content'
15
15
  ## 代码演示
16
16
 
17
17
  <code src="./demo/basic.tsx" title="基础用法" description="Form的基础用法"></code>
18
+ <code src="./demo/tooltip.tsx" title="标签帮助提示" description="在标签旁展示帮助图标,支持自定义触发图标"></code>
18
19
  <code src="./demo/group.tsx" title="字段分组" description="Field.Group 共享标签和组级别校验"></code>
19
20
  <code src="./demo/watch.tsx" title="字段监听" description="useWatch 监听字段值变化实现联动"></code>
20
21
  <code src="./demo/list.tsx" title="表单列表" description="Form的列表字段用法"></code>
@@ -22,110 +23,107 @@ toc: 'content'
22
23
  <code src="./demo/layout.tsx" title="表单布局" description="不同的表单布局"></code>
23
24
  <code src="./demo/validate.tsx" title="表单校验" description="表单校验功能"></code>
24
25
 
25
- <!-- <code src="./demo/dynamic.tsx" title="动态表单" description="动态增减表单项"></code> -->
26
-
27
- <!-- <code src="./demo/virtual.tsx" title="虚拟表单" description="虚拟表单"></code> -->
28
-
29
26
  ## API
30
27
 
31
28
  ### FormProps
32
29
 
33
- | 属性名 | 类型 | 描述 | 默认值 |
34
- | -------------------- | ------------------------------------------- | ------------------------ | ------ |
35
- | prefixCls | `string` | 自定义类名前缀 | - |
36
- | className | `string` | 自定义根类名 | - |
37
- | style | `React.CSSProperties` | 自定义根样式 | - |
38
- | children | `React.ReactNode` | 字段 | - |
39
- | name | `string` | 表单名 | - |
40
- | form | [FormInstance](#forminstance) | 表单实例 | - |
41
- | disabled | `boolean` | 是否禁用 | - |
42
- | initialValues | `Store` | 初始值 | - |
43
- | layout | `'vertical' \| 'horizontal'` | 布局 | - |
44
- | onFinish | `(values: Values) => void` | submit提交时触发事件 | - |
45
- | onFinishFailed | `(err: Values) => void` | submit提交报错时触发事件 | - |
46
- | onValuesChange | `(changedValues: Record<string, any>, values: Values) => void` | 表单字段值改变时触发事件 | - |
47
- | onValuesBeforeChange | `(changedValues: Record<string, any>, values: Values) => void \| any` | 表单字段值改变前触发事件 | - |
48
- | onReset | `() => void` | 表单重置时触发的事件 | - |
49
- | data-* | `string` | - | 支持所有 data-* 属性,透传到组件根 DOM 元素 |
30
+ | 属性名 | 类型 | 描述 | 默认值 |
31
+ | -------------------- | --------------------------------------------------------------------- | ------------------------ | -------------------------------------------- |
32
+ | prefixCls | `string` | 自定义类名前缀 | - |
33
+ | className | `string` | 自定义根类名 | - |
34
+ | style | `React.CSSProperties` | 自定义根样式 | - |
35
+ | children | `React.ReactNode` | 字段 | - |
36
+ | name | `string` | 表单名 | - |
37
+ | form | [FormInstance](#forminstance) | 表单实例 | - |
38
+ | disabled | `boolean` | 是否禁用 | - |
39
+ | initialValues | `Store` | 初始值 | - |
40
+ | layout | `'vertical' \| 'horizontal'` | 布局 | - |
41
+ | onFinish | `(values: Values) => void` | submit提交时触发事件 | - |
42
+ | onFinishFailed | `(err: Values) => void` | submit提交报错时触发事件 | - |
43
+ | onValuesChange | `(changedValues: Record<string, any>, values: Values) => void` | 表单字段值改变时触发事件 | - |
44
+ | onValuesBeforeChange | `(changedValues: Record<string, any>, values: Values) => void \| any` | 表单字段值改变前触发事件 | - |
45
+ | onReset | `() => void` | 表单重置时触发的事件 | - |
46
+ | data-\* | `string` | - | 支持所有 data-\* 属性,透传到组件根 DOM 元素 |
50
47
 
51
48
  ### FormInstance
52
49
 
53
- | 属性名 | 类型 | 描述 |
54
- | --------------------- | ------------------------------------------------------------------------------------------ | -------------- |
55
- | getFieldValidate | `(name: Name) => ValidateMessage \| null` | 获取字段验证 |
56
- | getFieldValue | `(name: Name) => StoreValue` | 获取字段值 |
57
- | submit | `() => void` | 提交表单 |
58
- | getFieldsValue | `() => Values` | 获取所有字段值 |
59
- | setFieldsValue | `(newStore: Store, trigger?: TRIGGER) => void` | 设置字段值 |
60
- | setCallbacks | `(callbacks: Callbacks) => void` | 设置回调 |
61
- | resetFields | `(name?: Name[]) => void` | 重置字段 |
62
- | clearFields | `(name?: Name[]) => void` | 清空字段 |
63
- | validateField | `(name: Name, trigger?: 'onChange' \| 'onBlur') => ValidateMessage[]` | 校验单个字段 |
64
- | validateFields | `(names?: Name[], trigger?: TRIGGER) => ValidateMessage[]` | 校验多个字段 |
65
- | getCallbacks | `() => Callbacks` | 获取回调 |
66
- | registerFieldEntities | `(entity: FieldEntity) => void` | 注册字段实体 |
67
- | initialize | `({ initialValues, callbacks }: { initialValues?: Store; callbacks?: Callbacks }) => void` | 初始化表单 |
68
- | getListFields | `(name: NamePath) => FormListField[]` | 获取列表字段 |
69
- | getListOperations | `(name: NamePath) => FormListOperation` | 获取列表操作 |
70
- | subscribe | `(namePath?: NamePath, callback?: () => void) => () => void` | 订阅字段值变化,不传 namePath 监听所有字段 |
50
+ | 属性名 | 类型 | 描述 |
51
+ | --------------------- | ------------------------------------------------------------------------------------------ | ------------------------------------------ |
52
+ | getFieldValidate | `(name: Name) => ValidateMessage \| null` | 获取字段验证 |
53
+ | getFieldValue | `(name: Name) => StoreValue` | 获取字段值 |
54
+ | submit | `() => void` | 提交表单 |
55
+ | getFieldsValue | `() => Values` | 获取所有字段值 |
56
+ | setFieldsValue | `(newStore: Store, trigger?: TRIGGER) => void` | 设置字段值 |
57
+ | setCallbacks | `(callbacks: Callbacks) => void` | 设置回调 |
58
+ | resetFields | `(name?: Name[]) => void` | 重置字段 |
59
+ | clearFields | `(name?: Name[]) => void` | 清空字段 |
60
+ | validateField | `(name: Name, trigger?: 'onChange' \| 'onBlur') => ValidateMessage[]` | 校验单个字段 |
61
+ | validateFields | `(names?: Name[], trigger?: TRIGGER) => ValidateMessage[]` | 校验多个字段 |
62
+ | getCallbacks | `() => Callbacks` | 获取回调 |
63
+ | registerFieldEntities | `(entity: FieldEntity) => void` | 注册字段实体 |
64
+ | initialize | `({ initialValues, callbacks }: { initialValues?: Store; callbacks?: Callbacks }) => void` | 初始化表单 |
65
+ | getListFields | `(name: NamePath) => FormListField[]` | 获取列表字段 |
66
+ | getListOperations | `(name: NamePath) => FormListOperation` | 获取列表操作 |
67
+ | subscribe | `(namePath?: NamePath, callback?: () => void) => () => void` | 订阅字段值变化,不传 namePath 监听所有字段 |
71
68
 
72
69
  ### Form 静态方法
73
70
 
74
- | 方法名 | 类型 | 描述 |
75
- | ---------- | ------------------------------------------------------- | -------------------------- |
76
- | Form.useWatch | `(namePath?: NamePath, form?: FormInstance) => T \| undefined` | 监听表单字段值变化,不传 namePath 返回所有值 |
71
+ | 方法名 | 类型 | 描述 |
72
+ | ------------- | -------------------------------------------------------------- | -------------------------------------------- |
73
+ | Form.useWatch | `(namePath?: NamePath, form?: FormInstance) => T \| undefined` | 监听表单字段值变化,不传 namePath 返回所有值 |
77
74
 
78
75
  ### Field.GroupProps
79
76
 
80
- | 属性名 | 类型 | 描述 | 默认值 |
81
- | -------- | --------------------- | -------- | ------ |
82
- | children | `React.ReactNode` | 子元素,通常为多个 Form.Field | - |
83
- | label | `React.ReactNode` | 组标签 | - |
84
- | required | `boolean` | 是否必填(显示必填标记) | - |
85
- | rules | [Rule\[\]](#rule) | 组级别校验规则,validator 接收子字段值的对象 | - |
86
- | cols | `number` | 子字段列数 | - |
87
- | style | `React.CSSProperties` | 自定义样式 | - |
88
- | className | `string` | 自定义类名 | - |
77
+ | 属性名 | 类型 | 描述 | 默认值 |
78
+ | --------- | --------------------- | -------------------------------------------- | ------ |
79
+ | children | `React.ReactNode` | 子元素,通常为多个 Form.Field | - |
80
+ | label | `React.ReactNode` | 组标签 | - |
81
+ | required | `boolean` | 是否必填(显示必填标记) | - |
82
+ | rules | [Rule\[\]](#rule) | 组级别校验规则,validator 接收子字段值的对象 | - |
83
+ | cols | `number` | 子字段列数 | - |
84
+ | style | `React.CSSProperties` | 自定义样式 | - |
85
+ | className | `string` | 自定义类名 | - |
89
86
 
90
87
  ### FieldProps
91
88
 
92
- | 属性名 | 类型 | 描述 | 默认值 |
93
- | -------- | --------------------- | -------- | ------ |
94
- | children | `React.ReactElement` | 子元素 | - |
95
- | name | `NamePath` | 字段名 | - |
96
- | rules | [Rule\[\]](#rule) | 校验规则 | - |
97
- | label | `React.ReactNode` | 标签 | - |
98
- | required | `boolean` | 是否必填 | - |
99
- | disabled | `boolean` | 是否禁用 | - |
100
- | initialValue | `unknown` | 初始值 | - |
101
- | valuePropName | `string` | 设置子组件值的属性名 | `'value'` |
89
+ | 属性名 | 类型 | 描述 | 默认值 |
90
+ | ------------- | -------------------- | -------------------- | --------- |
91
+ | children | `React.ReactElement` | 子元素 | - |
92
+ | name | `NamePath` | 字段名 | - |
93
+ | rules | [Rule\[\]](#rule) | 校验规则 | - |
94
+ | label | `React.ReactNode` | 标签 | - |
95
+ | tooltip | `ReactNode \| (Omit<TooltipProps, 'children'> & { icon?: ReactNode })` | 标签旁的帮助提示。传字符串/节点使用默认图标;传对象时可自定义 `icon`,其余属性透传给 Tooltip(`title`、`color`、`placement` 等) | - |
96
+ | required | `boolean` | 是否必填 | - |
97
+ | disabled | `boolean` | 是否禁用 | - |
98
+ | initialValue | `unknown` | 初始值 | - |
99
+ | valuePropName | `string` | 设置子组件值的属性名 | `'value'` |
102
100
 
103
101
  ### Rule
104
102
 
105
- | 属性名 | 类型 | 描述 |
106
- | --------------- | --------------- | ---------- |
107
- | required | `boolean` | 是否必填 |
108
- | type | `string` | 类型 |
109
- | min | `number` | 最小值 |
110
- | max | `number` | 最大值 |
111
- | minLength | `number` | 最小长度 |
112
- | maxLength | `number` | 最大长度 |
113
- | regexp | `RegExp` | 正则表达式 |
114
- | message | `string` | 错误信息 |
115
- | validator | `(value: unknown) => boolean` | 自定义校验函数 |
116
- | validateTrigger | `'onBlur' \| 'onChange' \| 'onSubmit' \| Array<'onBlur' \| 'onChange' \| 'onSubmit'>` | 校验触发时机 |
103
+ | 属性名 | 类型 | 描述 |
104
+ | --------------- | ------------------------------------------------------------------------------------- | -------------- |
105
+ | required | `boolean` | 是否必填 |
106
+ | type | `string` | 类型 |
107
+ | min | `number` | 最小值 |
108
+ | max | `number` | 最大值 |
109
+ | minLength | `number` | 最小长度 |
110
+ | maxLength | `number` | 最大长度 |
111
+ | regexp | `RegExp` | 正则表达式 |
112
+ | message | `string` | 错误信息 |
113
+ | validator | `(value: unknown) => boolean` | 自定义校验函数 |
114
+ | validateTrigger | `'onBlur' \| 'onChange' \| 'onSubmit' \| Array<'onBlur' \| 'onChange' \| 'onSubmit'>` | 校验触发时机 |
117
115
 
118
116
  ### Types
119
117
 
120
- | 类型 | 描述 |
121
- | --------------- | --------------------------------------------------------- |
122
- | StoreValue | `any` |
123
- | Store | `Record<string, StoreValue>` |
124
- | Name | `string` |
125
- | NamePath | `string \| string[] \| number \| (string \| number)[]` |
126
- | ValidateMessage | `{ name: NamePath \| NamePath[] \| undefined; message: string; value: unknown; status: 'error' \| 'success' \| 'warning' \| 'info' }` |
127
- | FieldEntity | `{ props: fieldProps & { name?: NamePath }; onStoreChange: () => void }` |
128
- | TRIGGER | `'onChange' \| 'onBlur' \| 'onSubmit' \| 'reset' \| 'clear' \| 'update'` |
129
- | FormListField | `{ key: React.Key; name: number; isListField?: boolean }` |
130
- | FormListOperation | `{ add: (defaultValue?: any, insertIndex?: number) => void; remove: (index: number \| number[]) => void; move: (from: number, to: number) => void }` |
131
- | FormListProps | `{ name: NamePath; children: (fields: FormListField[], operation: FormListOperation, meta: { errors: React.ReactNode[] }) => React.ReactNode; initialValue?: any[]; rules?: Rule[] }` |
118
+ | 类型 | 描述 |
119
+ | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
120
+ | StoreValue | `any` |
121
+ | Store | `Record<string, StoreValue>` |
122
+ | Name | `string` |
123
+ | NamePath | `string \| string[] \| number \| (string \| number)[]` |
124
+ | ValidateMessage | `{ name: NamePath \| NamePath[] \| undefined; message: string; value: unknown; status: 'error' \| 'success' \| 'warning' \| 'info' }` |
125
+ | FieldEntity | `{ props: fieldProps & { name?: NamePath }; onStoreChange: () => void }` |
126
+ | TRIGGER | `'onChange' \| 'onBlur' \| 'onSubmit' \| 'reset' \| 'clear' \| 'update'` |
127
+ | FormListField | `{ key: React.Key; name: number; isListField?: boolean }` |
128
+ | FormListOperation | `{ add: (defaultValue?: any, insertIndex?: number) => void; remove: (index: number \| number[]) => void; move: (from: number, to: number) => void }` |
129
+ | FormListProps | `{ name: NamePath; children: (fields: FormListField[], operation: FormListOperation, meta: { errors: React.ReactNode[] }) => React.ReactNode; initialValue?: any[]; rules?: Rule[] }` |
@@ -1,3 +1,4 @@
1
+ import type { TooltipProps } from '../Tooltip';
1
2
  import type { DataAttributeProps } from '../utils/types';
2
3
 
3
4
  export type StoreValue = any;
@@ -230,7 +231,7 @@ export type Rule = {
230
231
  /**
231
232
  * Error message
232
233
  */
233
- message: string;
234
+ message?: string;
234
235
  /**
235
236
  * Custom validation function, returns true for pass, false or throw for fail
236
237
  */
@@ -253,12 +254,46 @@ export type ValidateMessage = {
253
254
  status: 'error' | 'success' | 'warning' | 'info';
254
255
  };
255
256
 
257
+ export type FieldConfigurableTooltip = Omit<TooltipProps, 'children'> & {
258
+ /**
259
+ * Custom trigger icon (defaults to a built-in help icon)
260
+ */
261
+ icon?: React.ReactNode;
262
+ };
263
+
264
+ export type FieldTooltip = React.ReactNode | FieldConfigurableTooltip;
265
+
256
266
  export type FieldProps = {
267
+ /**
268
+ * Child nodes
269
+ * */
257
270
  children: React.ReactElement;
271
+ /**
272
+ * Field name
273
+ * */
258
274
  name: NamePath;
275
+ /**
276
+ * Validation rules
277
+ * */
259
278
  rules?: Rule[];
279
+ /***
280
+ * Field label
281
+ */
260
282
  label?: React.ReactNode;
283
+ /**
284
+ * Tooltip shown next to the label (a help icon).
285
+ * Pass a string/node to use the default icon, or an object to customize the icon.
286
+ * */
287
+ tooltip?: FieldTooltip;
288
+ /**
289
+ * Whether required (shows required mark)
290
+ * */
261
291
  required?: boolean;
292
+ /**
293
+ * Layout of label and control
294
+ * @default 'vertical'
295
+ * */
296
+ layout?: 'vertical' | 'horizontal';
262
297
  /**
263
298
  * Format value before passing to children
264
299
  * */
@@ -18,17 +18,32 @@
18
18
  // padding-bottom: var(--yee-form-item-padding-bottom);
19
19
 
20
20
  &-label {
21
- display: inline-block;
21
+ display: inline-flex;
22
+ align-items: center;
23
+ gap: 2px;
22
24
  margin-bottom: var(--yee-form-item-label-mb, 4px);
23
25
  line-height: var(--yee-form-item-label-line-height);
24
26
  }
25
27
 
26
- &-required {
27
- &::after {
28
- color: var(--yee-input-required-font-color);
29
- content: '*';
30
- margin-inline-start: var(--yee-form-item-required-margin-inline-start);
31
- }
28
+ // The required asterisk is rendered as a real node via &-required-mark so it
29
+ // stays glued to the label text regardless of what else sits inside the label.
30
+ // The `item-required` className is still applied to the label (see Field/Group)
31
+ // as an opt-in styling hook; the mark itself lives in &-required-mark below.
32
+ &-required-mark {
33
+ color: var(--yee-input-required-font-color);
34
+ margin-inline-start: var(--yee-form-item-required-margin-inline-start);
35
+ line-height: 1;
36
+ }
37
+
38
+ &-tooltip-icon {
39
+ display: inline-flex;
40
+ align-items: center;
41
+ margin-inline-start: 4px;
42
+ color: var(
43
+ --yee-form-item-tooltip-icon-color,
44
+ var(--yee-text-color-secondary, #999)
45
+ );
46
+ cursor: pointer;
32
47
  }
33
48
 
34
49
  &-control {
@@ -27,7 +27,7 @@ const Popconfirm: React.FC<PopconfirmProps> = (baseprops) => {
27
27
  defaultOpen,
28
28
  title,
29
29
  description,
30
- arrow = true,
30
+ arrow = { className: `${prefixCls}-arrow` },
31
31
  placement = 'top',
32
32
  confirmText = popconfirmLocale.okText,
33
33
  cancelText = popconfirmLocale.cancelText,
@@ -20,4 +20,10 @@
20
20
  &-footer {
21
21
  margin-top: var(--yee-popconfirm-footer-margin-top);
22
22
  }
23
+
24
+ &-arrow {
25
+ &::after {
26
+ background-color: var(--yee-popconfirm-bg-font-color);
27
+ }
28
+ }
23
29
  }
@@ -19,7 +19,7 @@ const Popover = (baseprops: PopoverProps) => {
19
19
  children,
20
20
  title,
21
21
  content,
22
- arrow = true,
22
+ arrow = { className: `${prefixCls}-arrow` },
23
23
  placement = 'top',
24
24
  trigger = 'hover',
25
25
  style,
@@ -14,4 +14,10 @@
14
14
  line-height: var(--yee-popover-header-line-height);
15
15
  background-color: var(--yee-popover-header-bg-color);
16
16
  }
17
+
18
+ &-arrow {
19
+ &::after {
20
+ background-color: var(--yee-popover-bg-color);
21
+ }
22
+ }
17
23
  }
@@ -75,13 +75,13 @@ const Progress = React.forwardRef<HTMLDivElement, ProgressProps>(
75
75
  let progress;
76
76
  if (type === 'line') {
77
77
  progress = (
78
- <Line prefixCls={prefixCls} percent={percent}>
78
+ <Line {...rest} prefixCls={prefixCls} percent={percent}>
79
79
  {progressInfo}
80
80
  </Line>
81
81
  );
82
82
  } else {
83
83
  progress = (
84
- <Circle prefixCls={prefixCls} percent={percent}>
84
+ <Circle {...rest} prefixCls={prefixCls} percent={percent}>
85
85
  {progressInfo}
86
86
  </Circle>
87
87
  );