@fjyueke/bify-mcp 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 (210) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +34 -0
  3. package/dist/index.d.ts +1 -0
  4. package/dist/index.js +248 -0
  5. package/metaData/components/action-sheet/api.md +74 -0
  6. package/metaData/components/action-sheet/doc.md +243 -0
  7. package/metaData/components/action-sheet/example/index.tsx +116 -0
  8. package/metaData/components/area-picker/api.md +25 -0
  9. package/metaData/components/area-picker/doc.md +132 -0
  10. package/metaData/components/area-picker/example/index.tsx +60 -0
  11. package/metaData/components/avatar/api.md +19 -0
  12. package/metaData/components/avatar/doc.md +170 -0
  13. package/metaData/components/avatar/example/index.tsx +76 -0
  14. package/metaData/components/back-top/api.md +21 -0
  15. package/metaData/components/back-top/doc.md +142 -0
  16. package/metaData/components/back-top/example/index.tsx +96 -0
  17. package/metaData/components/backdrop/api.md +20 -0
  18. package/metaData/components/backdrop/doc.md +98 -0
  19. package/metaData/components/backdrop/example/index.tsx +33 -0
  20. package/metaData/components/badge/api.md +10 -0
  21. package/metaData/components/badge/doc.md +169 -0
  22. package/metaData/components/badge/example/index.tsx +81 -0
  23. package/metaData/components/button/api.md +31 -0
  24. package/metaData/components/button/doc.md +235 -0
  25. package/metaData/components/button/example/index.tsx +235 -0
  26. package/metaData/components/calendar/api.md +62 -0
  27. package/metaData/components/calendar/doc.md +516 -0
  28. package/metaData/components/calendar/example/index.tsx +501 -0
  29. package/metaData/components/cascader/api.md +55 -0
  30. package/metaData/components/cascader/doc.md +358 -0
  31. package/metaData/components/cascader/example/index.tsx +159 -0
  32. package/metaData/components/cell/api.md +37 -0
  33. package/metaData/components/cell/doc.md +158 -0
  34. package/metaData/components/cell/example/index.tsx +44 -0
  35. package/metaData/components/checkbox/api.md +35 -0
  36. package/metaData/components/checkbox/doc.md +203 -0
  37. package/metaData/components/checkbox/example/index.tsx +94 -0
  38. package/metaData/components/circle/api.md +17 -0
  39. package/metaData/components/circle/doc.md +123 -0
  40. package/metaData/components/circle/example/index.tsx +81 -0
  41. package/metaData/components/collapse/api.md +31 -0
  42. package/metaData/components/collapse/doc.md +142 -0
  43. package/metaData/components/collapse/example/index.tsx +81 -0
  44. package/metaData/components/config-provider/api.md +7 -0
  45. package/metaData/components/config-provider/doc.md +193 -0
  46. package/metaData/components/config-provider/example/index.tsx +54 -0
  47. package/metaData/components/countdown/api.md +46 -0
  48. package/metaData/components/countdown/doc.md +167 -0
  49. package/metaData/components/countdown/example/index.tsx +70 -0
  50. package/metaData/components/datetime-picker/api.md +25 -0
  51. package/metaData/components/datetime-picker/doc.md +317 -0
  52. package/metaData/components/datetime-picker/example/index.tsx +265 -0
  53. package/metaData/components/dialog/api.md +66 -0
  54. package/metaData/components/dialog/doc.md +292 -0
  55. package/metaData/components/dialog/example/index.tsx +138 -0
  56. package/metaData/components/divider/api.md +15 -0
  57. package/metaData/components/divider/doc.md +108 -0
  58. package/metaData/components/divider/example/index.tsx +45 -0
  59. package/metaData/components/dropdown-menu/api.md +37 -0
  60. package/metaData/components/dropdown-menu/doc.md +279 -0
  61. package/metaData/components/dropdown-menu/example/index.tsx +182 -0
  62. package/metaData/components/empty/api.md +20 -0
  63. package/metaData/components/empty/doc.md +126 -0
  64. package/metaData/components/empty/example/index.tsx +66 -0
  65. package/metaData/components/field/api.md +10 -0
  66. package/metaData/components/field/doc.md +274 -0
  67. package/metaData/components/field/example/index.tsx +203 -0
  68. package/metaData/components/fixed-nav/api.md +21 -0
  69. package/metaData/components/fixed-nav/doc.md +196 -0
  70. package/metaData/components/fixed-nav/example/index.tsx +80 -0
  71. package/metaData/components/fixed-view/api.md +10 -0
  72. package/metaData/components/fixed-view/doc.md +25 -0
  73. package/metaData/components/fixed-view/example/index.tsx +12 -0
  74. package/metaData/components/flex/api.md +18 -0
  75. package/metaData/components/flex/doc.md +103 -0
  76. package/metaData/components/flex/example/index.tsx +58 -0
  77. package/metaData/components/floating-bubble/api.md +18 -0
  78. package/metaData/components/floating-bubble/doc.md +94 -0
  79. package/metaData/components/floating-bubble/example/index.tsx +55 -0
  80. package/metaData/components/floating-panel/api.md +19 -0
  81. package/metaData/components/floating-panel/doc.md +174 -0
  82. package/metaData/components/floating-panel/example/index.tsx +131 -0
  83. package/metaData/components/form/api.md +124 -0
  84. package/metaData/components/form/doc.md +759 -0
  85. package/metaData/components/form/example/index.tsx +222 -0
  86. package/metaData/components/grid/api.md +28 -0
  87. package/metaData/components/grid/doc.md +167 -0
  88. package/metaData/components/grid/example/index.tsx +80 -0
  89. package/metaData/components/image/api.md +42 -0
  90. package/metaData/components/image/doc.md +117 -0
  91. package/metaData/components/image/example/index.tsx +76 -0
  92. package/metaData/components/index-list/api.md +39 -0
  93. package/metaData/components/index-list/doc.md +176 -0
  94. package/metaData/components/index-list/example/index.tsx +110 -0
  95. package/metaData/components/list/api.md +30 -0
  96. package/metaData/components/list/doc.md +317 -0
  97. package/metaData/components/list/example/index.tsx +218 -0
  98. package/metaData/components/loading/api.md +10 -0
  99. package/metaData/components/loading/doc.md +113 -0
  100. package/metaData/components/loading/example/index.tsx +47 -0
  101. package/metaData/components/navbar/api.md +26 -0
  102. package/metaData/components/navbar/doc.md +85 -0
  103. package/metaData/components/navbar/example/index.tsx +28 -0
  104. package/metaData/components/notice-bar/api.md +28 -0
  105. package/metaData/components/notice-bar/doc.md +154 -0
  106. package/metaData/components/notice-bar/example/index.tsx +107 -0
  107. package/metaData/components/notify/api.md +28 -0
  108. package/metaData/components/notify/doc.md +140 -0
  109. package/metaData/components/notify/example/index.tsx +89 -0
  110. package/metaData/components/number-keyboard/api.md +21 -0
  111. package/metaData/components/number-keyboard/doc.md +247 -0
  112. package/metaData/components/number-keyboard/example/index.tsx +201 -0
  113. package/metaData/components/pagination/api.md +18 -0
  114. package/metaData/components/pagination/doc.md +113 -0
  115. package/metaData/components/pagination/example/index.tsx +73 -0
  116. package/metaData/components/password-input/api.md +25 -0
  117. package/metaData/components/password-input/doc.md +126 -0
  118. package/metaData/components/password-input/example/index.tsx +124 -0
  119. package/metaData/components/picker/api.md +61 -0
  120. package/metaData/components/picker/doc.md +336 -0
  121. package/metaData/components/picker/example/index.tsx +232 -0
  122. package/metaData/components/popup/api.md +48 -0
  123. package/metaData/components/popup/doc.md +150 -0
  124. package/metaData/components/popup/example/index.tsx +214 -0
  125. package/metaData/components/progress/api.md +11 -0
  126. package/metaData/components/progress/doc.md +105 -0
  127. package/metaData/components/progress/example/index.tsx +58 -0
  128. package/metaData/components/pull-refresh/api.md +18 -0
  129. package/metaData/components/pull-refresh/doc.md +198 -0
  130. package/metaData/components/pull-refresh/example/index.tsx +153 -0
  131. package/metaData/components/radio/api.md +26 -0
  132. package/metaData/components/radio/doc.md +201 -0
  133. package/metaData/components/radio/example/index.tsx +103 -0
  134. package/metaData/components/rate/api.md +23 -0
  135. package/metaData/components/rate/doc.md +122 -0
  136. package/metaData/components/rate/example/index.tsx +36 -0
  137. package/metaData/components/rolling-text/api.md +23 -0
  138. package/metaData/components/rolling-text/doc.md +153 -0
  139. package/metaData/components/rolling-text/example/index.tsx +150 -0
  140. package/metaData/components/safe-area/api.md +8 -0
  141. package/metaData/components/safe-area/doc.md +30 -0
  142. package/metaData/components/safe-area/example/index.tsx +16 -0
  143. package/metaData/components/search/api.md +35 -0
  144. package/metaData/components/search/doc.md +185 -0
  145. package/metaData/components/search/example/index.tsx +101 -0
  146. package/metaData/components/share-sheet/api.md +48 -0
  147. package/metaData/components/share-sheet/doc.md +215 -0
  148. package/metaData/components/share-sheet/example/index.tsx +143 -0
  149. package/metaData/components/sidebar/api.md +28 -0
  150. package/metaData/components/sidebar/doc.md +122 -0
  151. package/metaData/components/sidebar/example/index.tsx +58 -0
  152. package/metaData/components/signature/api.md +19 -0
  153. package/metaData/components/signature/doc.md +115 -0
  154. package/metaData/components/signature/example/index.tsx +56 -0
  155. package/metaData/components/skeleton/api.md +45 -0
  156. package/metaData/components/skeleton/doc.md +131 -0
  157. package/metaData/components/skeleton/example/index.tsx +80 -0
  158. package/metaData/components/slider/api.md +28 -0
  159. package/metaData/components/slider/doc.md +151 -0
  160. package/metaData/components/slider/example/index.tsx +54 -0
  161. package/metaData/components/space/api.md +12 -0
  162. package/metaData/components/space/doc.md +125 -0
  163. package/metaData/components/space/example/index.tsx +75 -0
  164. package/metaData/components/stepper/api.md +37 -0
  165. package/metaData/components/stepper/doc.md +152 -0
  166. package/metaData/components/stepper/example/index.tsx +45 -0
  167. package/metaData/components/steps/api.md +9 -0
  168. package/metaData/components/steps/doc.md +143 -0
  169. package/metaData/components/steps/example/index.tsx +93 -0
  170. package/metaData/components/sticky/api.md +16 -0
  171. package/metaData/components/sticky/doc.md +87 -0
  172. package/metaData/components/sticky/example/index.tsx +62 -0
  173. package/metaData/components/swipe-cell/api.md +19 -0
  174. package/metaData/components/swipe-cell/doc.md +105 -0
  175. package/metaData/components/swipe-cell/example/index.tsx +62 -0
  176. package/metaData/components/swiper/api.md +22 -0
  177. package/metaData/components/swiper/doc.md +228 -0
  178. package/metaData/components/swiper/example/index.tsx +118 -0
  179. package/metaData/components/switch/api.md +17 -0
  180. package/metaData/components/switch/doc.md +110 -0
  181. package/metaData/components/switch/example/index.tsx +57 -0
  182. package/metaData/components/tabbar/api.md +27 -0
  183. package/metaData/components/tabbar/doc.md +160 -0
  184. package/metaData/components/tabbar/example/index.tsx +99 -0
  185. package/metaData/components/tabs/api.md +36 -0
  186. package/metaData/components/tabs/doc.md +307 -0
  187. package/metaData/components/tabs/example/index.tsx +231 -0
  188. package/metaData/components/tag/api.md +17 -0
  189. package/metaData/components/tag/doc.md +162 -0
  190. package/metaData/components/tag/example/index.tsx +84 -0
  191. package/metaData/components/text-ellipsis/api.md +26 -0
  192. package/metaData/components/text-ellipsis/doc.md +135 -0
  193. package/metaData/components/text-ellipsis/example/index.tsx +44 -0
  194. package/metaData/components/timeline/api.md +20 -0
  195. package/metaData/components/timeline/doc.md +210 -0
  196. package/metaData/components/timeline/example/index.tsx +145 -0
  197. package/metaData/components/toast/api.md +39 -0
  198. package/metaData/components/toast/doc.md +256 -0
  199. package/metaData/components/toast/example/index.tsx +136 -0
  200. package/metaData/components/tree-select/api.md +19 -0
  201. package/metaData/components/tree-select/doc.md +185 -0
  202. package/metaData/components/tree-select/example/index.tsx +112 -0
  203. package/metaData/components/uploader/api.md +32 -0
  204. package/metaData/components/uploader/doc.md +340 -0
  205. package/metaData/components/uploader/example/index.tsx +222 -0
  206. package/metaData/components/watermark/api.md +18 -0
  207. package/metaData/components/watermark/doc.md +97 -0
  208. package/metaData/components/watermark/example/index.tsx +62 -0
  209. package/metaData/components-index.json +274 -0
  210. package/package.json +56 -0
@@ -0,0 +1,759 @@
1
+ # Form 表单
2
+
3
+ ### 介绍
4
+
5
+ 用于数据录入、校验,支持输入框、单选框、复选框、文件上传等类型。
6
+
7
+ ### 引入
8
+
9
+ ```tsx
10
+ import { Form } from "@fjyueke/bify-core"
11
+ ```
12
+
13
+ ## 代码演示
14
+
15
+ ### 基础用法
16
+
17
+ 在表单中,每个 `Form.Item` 代表一个表单项
18
+
19
+ ```tsx
20
+ function BasicForm() {
21
+ const onSubmit = (event: BaseEventOrig<FormProps.onSubmitEventDetail>) => {
22
+ Toast.open(JSON.stringify(event.detail.value))
23
+ }
24
+
25
+ return (
26
+ <Form onSubmit={onSubmit}>
27
+ <Toast id="toast" />
28
+ <Cell.Group inset>
29
+ <Form.Item name="username" rules={[{ required: true, message: "请填写用户名" }]}>
30
+ <Form.Label>用户名</Form.Label>
31
+ <Form.Control>
32
+ <Input placeholder="用户名" />
33
+ </Form.Control>
34
+ </Form.Item>
35
+ <Form.Item name="password" rules={[{ required: true, message: "请填写密码" }]}>
36
+ <Form.Label>密码</Form.Label>
37
+ <Form.Control>
38
+ <Input password placeholder="密码" />
39
+ </Form.Control>
40
+ </Form.Item>
41
+ <Field
42
+ name="text"
43
+ label={{ align: "left", children: "文本" }}
44
+ rules={[{ required: true, message: "请填写文本" }]}
45
+ >
46
+ <Input placeholder="请输入文本" />
47
+ </Field>
48
+ </Cell.Group>
49
+ <View style={{ margin: "16px" }}>
50
+ <Button shape="round" block color="primary" formType="submit">
51
+ 提交
52
+ </Button>
53
+ </View>
54
+ </Form>
55
+ )
56
+ }
57
+ ```
58
+
59
+ 使用`Field`组件
60
+
61
+ ```tsx
62
+ function BasicForm() {
63
+ const onSubmit = (event: BaseEventOrig<FormProps.onSubmitEventDetail>) => {
64
+ Toast.open(JSON.stringify(event.detail.value))
65
+ }
66
+
67
+ return (
68
+ <Form onSubmit={onSubmit}>
69
+ <Toast id="toast" />
70
+ <Cell.Group inset>
71
+ <Field label="用户名" name="username" rules={[{ required: true, message: "请填写用户名" }]}>
72
+ <Input placeholder="用户名" />
73
+ </Field>
74
+ <Field label="密码" name="password" rules={[{ required: true, message: "请填写密码" }]}>
75
+ <Input password placeholder="密码" />
76
+ </Field>
77
+ </Cell.Group>
78
+ <View style={{ margin: "16px" }}>
79
+ <Button shape="round" block color="primary" formType="submit">
80
+ 提交
81
+ </Button>
82
+ </View>
83
+ </Form>
84
+ )
85
+ }
86
+ ```
87
+
88
+ ### 校验规则
89
+
90
+ 通过 `rules` 定义表单校验规则,所有可用字段见[下方表格](#rule-%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84)。
91
+
92
+ ```tsx
93
+ function FormWithRules() {
94
+ const asyncValidator = (val: any) =>
95
+ new Promise<boolean>((resolve) => {
96
+ Toast.loading("验证中...")
97
+
98
+ setTimeout(() => {
99
+ Toast.close("toast")
100
+ resolve(/\d{6}/.test(val))
101
+ }, 1000)
102
+ })
103
+
104
+ function onValidate(errors: FormValidError[]) {
105
+ Toast.open({
106
+ style: {
107
+ textAlign: "left",
108
+ },
109
+ message: JSON.stringify(errors, undefined, 2),
110
+ })
111
+ }
112
+
113
+ return (
114
+ <Form defaultValues={{ validatorMessage: "abc" }} onValidate={onValidate}>
115
+ <Toast id="toast" />
116
+ <Cell.Group inset>
117
+ <Field
118
+ label="文本"
119
+ name="pattern"
120
+ rules={[{ pattern: /\d{6}/, message: "请输入正确内容" }]}
121
+ >
122
+ <Input placeholder="正则校验" />
123
+ </Field>
124
+ <Field
125
+ label="文本"
126
+ name="validator"
127
+ rules={[{ validator: (val) => /1\d{10}/.test(val), message: "请输入正确内容" }]}
128
+ >
129
+ <Input placeholder="函数校验" />
130
+ </Field>
131
+ <Field
132
+ label="文本"
133
+ name="validatorMessage"
134
+ rules={[{ validator: (val) => `${val ?? ""} 不合法,请重新输入` }]}
135
+ >
136
+ <Input placeholder="校验函数返回错误提示" />
137
+ </Field>
138
+ <Field
139
+ label="文本"
140
+ name="asyncValidator"
141
+ rules={[{ validator: asyncValidator, message: "请输入正确内容" }]}
142
+ >
143
+ <Input placeholder="异步函数校验" />
144
+ </Field>
145
+ </Cell.Group>
146
+ <View style={{ margin: "16px" }}>
147
+ <Button shape="round" block color="primary" formType="submit">
148
+ 提交
149
+ </Button>
150
+ </View>
151
+ </Form>
152
+ )
153
+ }
154
+ ```
155
+
156
+ ### 禁用表单
157
+
158
+ 设置 `disabled` 后,会为 `Form` 内部的 `taroify` 组件 `Input`, `Textarea`, `Checkbox`, `Switch`, `Checkbox.Group`, `Radio.Group`, `Rate`, `Slider`, `Stepper`, `Uploader` 设置 `disabled` <br>
159
+
160
+ form 设置 disabled 后,也可以单独为表单项和组件设置 disabled={false}, 优先级:表单 < 表单项 < 组件
161
+
162
+ ### 表单项类型 - 开关
163
+
164
+ 在表单中使用 [Switch 组件](/components/switch)。
165
+
166
+ ```tsx
167
+ <Field label="开关" name="switch">
168
+ <Switch size={20} />
169
+ </Field>
170
+ ```
171
+
172
+ ### 表单项类型 - 复选框
173
+
174
+ 在表单中使用 [Checkbox 组件](/components/checkbox)。
175
+
176
+ ```tsx
177
+ <Field label="复选框" name="checkbox">
178
+ <Checkbox shape="square" />
179
+ </Field>
180
+ <Field label="复选框组" name="checkboxGroup">
181
+ <Checkbox.Group direction="horizontal">
182
+ <Checkbox name="1" shape="square">
183
+ 复选框 1
184
+ </Checkbox>
185
+ <Checkbox name="2" shape="square">
186
+ 复选框 2
187
+ </Checkbox>
188
+ </Checkbox.Group>
189
+ </Field>
190
+ ```
191
+
192
+ ### 表单项类型 - 单选框
193
+
194
+ 在表单中使用 [Radio 组件](/components/radio)。
195
+
196
+ ```tsx
197
+ <Field label="单选框" name="radio">
198
+ <Radio.Group direction="horizontal">
199
+ <Radio name="1">单选框 1</Radio>
200
+ <Radio name="2">单选框 2</Radio>
201
+ </Radio.Group>
202
+ </Field>
203
+ ```
204
+
205
+ ### 表单项类型 - 步进器
206
+
207
+ 在表单中使用 [Stepper 组件](/components/stepper)。
208
+
209
+ ```tsx
210
+ <Field label="步进器" name="stepper">
211
+ <Stepper />
212
+ </Field>
213
+ ```
214
+
215
+ ### 表单项类型 - 评分
216
+
217
+ 在表单中使用 [Rate 组件](/components/rate)。
218
+
219
+ ```tsx
220
+ <Field label="评分" name="rate">
221
+ <Rate />
222
+ </Field>
223
+ ```
224
+
225
+ ### 表单项类型 - 滑块
226
+
227
+ 在表单中使用 [Slider 组件](/components/slider)。
228
+
229
+ ```tsx
230
+ <Field label="滑块" name="slider">
231
+ <Slider />
232
+ </Field>
233
+ ```
234
+
235
+ ### 表单项类型 - 文件上传
236
+
237
+ 在表单中使用 [Uploader 组件](/components/uploader)。
238
+
239
+ ```tsx
240
+ function UploaderField() {
241
+ const itemRef = useRef<FormItemInstance>()
242
+
243
+ function onUpload() {
244
+ chooseImage({
245
+ count: 1,
246
+ sizeType: ["original", "compressed"],
247
+ sourceType: ["album", "camera"],
248
+ }).then(({ tempFiles }) => {
249
+ itemRef.current?.setValue([
250
+ ...(itemRef.current?.getValue() ? [...itemRef.current?.getValue()] : []),
251
+ {
252
+ url: tempFiles[0].path,
253
+ type: tempFiles[0].type,
254
+ name: tempFiles[0].originalFileObj?.name,
255
+ },
256
+ ])
257
+ })
258
+ }
259
+
260
+ return (
261
+ <Field label="文件上传" ref={itemRef} name="uploader">
262
+ <Uploader multiple maxFiles={2} onUpload={onUpload} />
263
+ </Field>
264
+ )
265
+ }
266
+ ```
267
+
268
+ ### 表单项类型 - 选择器
269
+
270
+ 在表单中使用 [Picker 组件](/components/picker)。
271
+
272
+ ```tsx
273
+ function PickerField() {
274
+ const itemRef = useRef<FormItemInstance>()
275
+ const [open, setOpen] = useState(false)
276
+ const columns = useMemo(
277
+ () => [
278
+ { label: "杭州", value: "Hangzhou" },
279
+ { label: "宁波", value: "Ningbo" },
280
+ { label: "温州", value: "Wenzhou" },
281
+ { label: "绍兴", value: "Shaoxing" },
282
+ { label: "湖州", value: "Huzhou" },
283
+ ],
284
+ [],
285
+ )
286
+
287
+ return (
288
+ <>
289
+ <Field label="选择器" ref={itemRef} name="picker" clickable isLink>
290
+ <Input readonly placeholder="点击选择城市" onClick={() => setOpen(true)} />
291
+ </Field>
292
+ <Popup open={open} rounded placement="bottom" onClose={setOpen}>
293
+ <Picker
294
+ title="选择城市"
295
+ columns={columns}
296
+ onCancel={() => setOpen(false)}
297
+ onConfirm={(newValue) => {
298
+ itemRef.current?.setValue(newValue)
299
+ setOpen(false)
300
+ }}
301
+ ></Picker>
302
+ </Popup>
303
+ </>
304
+ )
305
+ }
306
+ ```
307
+
308
+ ### 表单项类型 - 时间选择器
309
+
310
+ 在表单中使用 [DatetimePicker 组件](/components/datetime-picker)。
311
+
312
+ ```tsx
313
+ function DatetimePickerField() {
314
+ const itemRef = useRef<FormItemInstance>()
315
+ const [open, setOpen] = useState(false)
316
+
317
+ const formatDate = (date: any) => {
318
+ if (date) {
319
+ const hours = _.padStart(_.toString(date?.getHours()), 2, "0")
320
+ const minutes = _.padStart(_.toString(date?.getMinutes()), 2, "0")
321
+ return `${hours}:${minutes}`
322
+ }
323
+ }
324
+
325
+ return (
326
+ <>
327
+ <Field label="时间选择" ref={itemRef} name="datetimePicker" clickable isLink>
328
+ {(controller) => (
329
+ <Input
330
+ value={formatDate(controller.value)}
331
+ disabled={controller.disabled}
332
+ readonly
333
+ placeholder="点击选择时间"
334
+ onClick={() => setOpen(true)}
335
+ />
336
+ )}
337
+ </Field>
338
+ <Popup open={open} rounded placement="bottom" onClose={setOpen}>
339
+ <DatetimePicker
340
+ type="hour-minute"
341
+ onCancel={() => setOpen(false)}
342
+ onConfirm={(newValue) => {
343
+ itemRef.current?.setValue(newValue)
344
+ setOpen(false)
345
+ }}
346
+ ></DatetimePicker>
347
+ </Popup>
348
+ </>
349
+ )
350
+ }
351
+ ```
352
+
353
+ ### 表单项类型 - 日历
354
+
355
+ 在表单中使用 [Calendar 组件](/components/calendar)。
356
+
357
+ ```tsx
358
+ function CalendarField() {
359
+ const itemRef = useRef<FormItemInstance>()
360
+ const [open, setOpen] = useState(false)
361
+
362
+ const formatDate = (date: any) => {
363
+ if (date) {
364
+ const months = _.padStart(_.toString(date?.getMonth() + 1), 2, "0")
365
+ const days = _.padStart(_.toString(date?.getDate()), 2, "0")
366
+ return `${months}-${days}`
367
+ }
368
+ }
369
+
370
+ return (
371
+ <>
372
+ <Field label="日历" ref={itemRef} name="calendar" clickable isLink>
373
+ {(controller) => (
374
+ <Input
375
+ value={formatDate(controller.value)}
376
+ disabled={controller.disabled}
377
+ readonly
378
+ placeholder="点击选择日期"
379
+ onClick={() => setOpen(true)}
380
+ />
381
+ )}
382
+ </Field>
383
+ <Calendar
384
+ type="single"
385
+ poppable
386
+ showPopup={open}
387
+ onCancel={() => setOpen(false)}
388
+ onConfirm={(newValue) => {
389
+ itemRef.current?.setValue(newValue)
390
+ setOpen(false)
391
+ }}
392
+ ></Calendar>
393
+ </>
394
+ )
395
+ }
396
+ ```
397
+
398
+ ### 动态增减表单项
399
+
400
+ 通过 Form.List 动态增减表单项 `v0.1.1-alpha.3`
401
+
402
+ ```tsx
403
+ function DynamicForm() {
404
+ const ref = useRef<FormInstance>(null)
405
+ const onManual = () => {
406
+ ref.current?.setValues({
407
+ contacts: [
408
+ { name: "小红", phone: "10000" },
409
+ { name: "小绿", phone: "10086" },
410
+ ],
411
+ })
412
+ }
413
+ return (
414
+ <Form
415
+ ref={ref}
416
+ onSubmit={(e) => {
417
+ Toast.open(JSON.stringify(e.detail.value, undefined, 2))
418
+ }}
419
+ >
420
+ <Form.List name="contacts" defaultValue={[{ name: "小明", phone: "10086" }]}>
421
+ {(fields, { add, remove }) => (
422
+ <Cell.Group inset>
423
+ {fields.map((field, idx) => (
424
+ <Fragment key={field.key}>
425
+ <Field label="姓名" name={`${field.name}.name`} key={`${field.key}.name`}>
426
+ {({ value, onChange }) => (
427
+ <>
428
+ <Input
429
+ placeholder="请输入姓名"
430
+ value={value}
431
+ onChange={(e) => {
432
+ onChange?.(e.detail.value)
433
+ }}
434
+ />
435
+ <View
436
+ style={{ flexShrink: 0 }}
437
+ onClick={() => {
438
+ remove(idx)
439
+ }}
440
+ >
441
+ 删除
442
+ </View>
443
+ </>
444
+ )}
445
+ </Field>
446
+ <Field
447
+ label="电话"
448
+ name={`${field.name}.phone`}
449
+ key={`${field.key}.phone`}
450
+ rules={[{ required: true, message: "必填" }]}
451
+ >
452
+ <Input placeholder="请输入电话" />
453
+ </Field>
454
+ </Fragment>
455
+ ))}
456
+ <Button variant="text" color="primary" onClick={() => add({})}>
457
+ 添加联系人
458
+ </Button>
459
+ </Cell.Group>
460
+ )}
461
+ </Form.List>
462
+ <View style={{ margin: "16px" }}>
463
+ <Button shape="round" block color="primary" formType="submit">
464
+ 提交
465
+ </Button>
466
+ <Button style={{ marginTop: "16px" }} shape="round" block color="info" onClick={onManual}>
467
+ 手动
468
+ </Button>
469
+ <Button style={{ marginTop: "16px" }} shape="round" block color="warning" formType="reset">
470
+ 重置
471
+ </Button>
472
+ </View>
473
+ </Form>
474
+ )
475
+ }
476
+ ```
477
+
478
+ ### 依赖与自动更新
479
+
480
+ 通过 dependencies 自动触发校验
481
+
482
+ ```tsx
483
+ function DependenciesDemo() {
484
+ const formRef = useRef<FormInstance>()
485
+ const onSubmit = (event: BaseEventOrig<FormProps.onSubmitEventDetail>) => {
486
+ Toast.open(JSON.stringify(event.detail.value))
487
+ }
488
+
489
+ return (
490
+ <Form ref={formRef} onSubmit={onSubmit} validateTrigger="onChange">
491
+ <Toast id="toast" />
492
+ <Cell.Group inset>
493
+ <Form.Item name="username" rules={[{ required: true, message: "请输入用户名" }]}>
494
+ <Form.Label>用户名</Form.Label>
495
+ <Form.Control>
496
+ <Input placeholder="用户名" />
497
+ </Form.Control>
498
+ </Form.Item>
499
+ <Form.Item name="password" rules={[{ required: true, message: "请输入密码" }]}>
500
+ <Form.Label>密码</Form.Label>
501
+ <Form.Control>
502
+ <Input placeholder="密码" />
503
+ </Form.Control>
504
+ </Form.Item>
505
+ <Form.Item
506
+ name="confirmPassword"
507
+ dependencies={["password"]}
508
+ rules={[
509
+ { required: true, message: "请再次输入密码" },
510
+ {
511
+ validator: (val) => {
512
+ return formRef.current?.getValues<any>()?.password === val ? true : "密码不一致"
513
+ },
514
+ },
515
+ ]}
516
+ >
517
+ <Form.Label>确认密码</Form.Label>
518
+ <Form.Control>
519
+ <Input placeholder="确认密码" />
520
+ </Form.Control>
521
+ </Form.Item>
522
+ </Cell.Group>
523
+ <View style={{ margin: "16px" }}>
524
+ <Button shape="round" block color="primary" formType="submit">
525
+ 提交
526
+ </Button>
527
+ </View>
528
+ </Form>
529
+ )
530
+ }
531
+ ```
532
+
533
+ 通过 shouldUpdate 和 noStyle 触发重新渲染, Form.Item 里包裹的子组件必须由函数返回,否则 shouldUpdate 不会起作用, Field 暂不支持
534
+
535
+ ```tsx
536
+ function ShouldUpdateDemo() {
537
+ const formRef = useRef<FormInstance>()
538
+ return (
539
+ <Form
540
+ ref={formRef}
541
+ onSubmit={(e) => {
542
+ Toast.open(JSON.stringify(e.detail.value, undefined, 2))
543
+ }}
544
+ >
545
+ <Toast id="toast" />
546
+ <Cell.Group inset>
547
+ <Form.Item name="type">
548
+ <Form.Label>复选框</Form.Label>
549
+ <Form.Control>
550
+ <Checkbox shape="square" />
551
+ </Form.Control>
552
+ </Form.Item>
553
+ <Form.Item name="radio">
554
+ <Form.Label>单选框</Form.Label>
555
+ <Form.Control>
556
+ <Radio.Group direction="horizontal">
557
+ <Radio name="1">单选框 1</Radio>
558
+ <Radio name="2">单选框 2</Radio>
559
+ </Radio.Group>
560
+ </Form.Control>
561
+ </Form.Item>
562
+ <Form.Item noStyle shouldUpdate={(prev, cur) => prev.type !== cur.type}>
563
+ {() => {
564
+ const type = formRef.current?.getValues<any>()?.type
565
+ if (type) {
566
+ return (
567
+ <Form.Item name="a1">
568
+ <Form.Label>复选框选中</Form.Label>
569
+ <Form.Control>
570
+ <Input />
571
+ </Form.Control>
572
+ </Form.Item>
573
+ )
574
+ } else {
575
+ return (
576
+ <>
577
+ <Form.Item name="a2">
578
+ <Form.Label>复选框未选中</Form.Label>
579
+ <Form.Control>
580
+ <Input />
581
+ </Form.Control>
582
+ </Form.Item>
583
+ <Form.Item name="a3">
584
+ <Form.Label>复选框未选中</Form.Label>
585
+ <Form.Control>
586
+ <Input />
587
+ </Form.Control>
588
+ </Form.Item>
589
+ </>
590
+ )
591
+ }
592
+ }}
593
+ </Form.Item>
594
+ <Form.Item noStyle shouldUpdate={(prev, cur) => prev.radio !== cur.radio}>
595
+ {() => (
596
+ <Field name="cc" label={`单选框${formRef.current?.getValues<any>()?.radio}`}>
597
+ <Input placeholder={`结果${JSON.stringify(formRef.current?.getValues<any>())}`} />
598
+ </Field>
599
+ )}
600
+ </Form.Item>
601
+ </Cell.Group>
602
+ <View style={{ margin: "16px" }}>
603
+ <Button shape="round" block color="primary" formType="submit">
604
+ 提交
605
+ </Button>
606
+ </View>
607
+ </Form>
608
+ )
609
+ }
610
+ ```
611
+
612
+ ## API
613
+
614
+ ### Form Props
615
+
616
+ | 参数 | 说明 | 类型 | 默认值 |
617
+ | ----------------------------- | ----------------------------------------------------------- | --------- | -------- |
618
+ | defaultValues | 表单默认值 | _object_ | |
619
+ | labelAlign | 表单项 label 对齐方式,可选值为 `center` `right` | _string_ | `left` |
620
+ | controlAlign | 表单项 control 对齐方式,可选值为 `center` `right` | _string_ | `left` |
621
+ | validateTrigger | 表单校验触发时机,可选值为 `onChange`、`onSubmit`,详见下表 | _string_ | `onBlur` |
622
+ | colon | 是否在 label 后面添加冒号 | _boolean_ | `false` |
623
+ | disabled <br>`v0.3.1-alpha.0` | 是否禁用表单 | _boolean_ | `false` |
624
+
625
+ ### Form Events
626
+
627
+ | 事件名 | 说明 | 回调参数 |
628
+ | -------------- | -------------------------- | ----------------------------------------------------- |
629
+ | onSubmit | 提交表单且验证通过后触发 | _event: BaseEventOrig<FormProps.onSubmitEventDetail>_ |
630
+ | onReset | 重置表单后触发 | _event: BaseEventOrig_ |
631
+ | onValidate | 提交表单且验证不通过后触发 | _errors: { name: string, errors: string[] }[]_ |
632
+ | onValuesChange | 字段值更新后触发 | _changedValues: object, allValues: object_ |
633
+
634
+ ### Form Methods
635
+
636
+ 通过 ref 可以获取到 Form 实例并调用实例方法。
637
+
638
+ | 方法名 | 说明 | 参数 | 返回值 |
639
+ | --------------------------- | ------------------------------------------------------------ | --------------------------- | ------------------ |
640
+ | setValues | 设置表单值(浅合并) | _object_ | - |
641
+ | getValues | 获得表单值,支持传入 `name` 来获得单个或部分表单项 | _name?: string \| string[]_ | _object_ |
642
+ | setErrors | 设置表单验证错误信息(浅合并) | _FormValidError[]_ | _void_ |
643
+ | getErrors | 获得表单验证错误信息,支持传入 `name` 来获得单个或部分表单项 | _name?: string \| string[]_ | _FormValidError[]_ |
644
+ | validate | 验证表单,支持传入 `name` 来验证单个或部分表单项 | _name?: string \| string[]_ | _Promise_ |
645
+ | submit <br>`v0.3.1-alpha.0` | 提交表单,与点击提交按钮的效果等价 | - | - |
646
+ | reset | 重置表单 | - | _void_ |
647
+
648
+ ### validateTrigger 可选值
649
+
650
+ 通过 `validateTrigger` 属性可以自定义表单校验的触发时机。
651
+
652
+ | 值 | 描述 |
653
+ | -------- | ------------------------------------ |
654
+ | onSubmit | 仅在提交表单时触发校验 |
655
+ | onBlur | 在提交表单和输入框失焦时触发校验 |
656
+ | onChange | 在提交表单和输入框内容变化时触发校验 |
657
+
658
+ ### Form.Item Props
659
+
660
+ | 参数 | 说明 | 类型 | 默认值 |
661
+ | --------------------------------- | ------------------------------------ | --------------------------------------------- | ------- |
662
+ | name | 表单项名称,提交表单的标识符 | _string_ | - |
663
+ | defaultValue | 表单项默认值 | _any_ | - |
664
+ | required | 是否显示表单必填星号 | _boolean_ | `false` |
665
+ | rules | 表单校验规则 | _FormRule[]_ | - |
666
+ | dependencies <br>`v0.1.6-alpha.0` | 当依赖的字段值改变时,触发自身的校验 | _string[]_ | - |
667
+ | shouldUpdate <br>`v0.1.6-alpha.0` | 当值为 true 时,触发当前区域重新渲染 | _boolean\|(prevValues, curValues) => boolean_ | - |
668
+ | noStyle <br>`v0.1.6-alpha.0` | 直接渲染 children | boolean | - |
669
+
670
+ > 属性继承自 Cell 组件,更多属性参见:[Cell 组件](/components/cell/#cell-props)
671
+
672
+ ### Rule 数据结构
673
+
674
+ 使用 Form.Item 的 `rules` 属性可以定义校验规则,可选属性如下:
675
+
676
+ | 键名 | 说明 | 类型 |
677
+ | --- | --- | --- |
678
+ | required | 是否为必选字段,当值为空字符串、空数组、`undefined`、`null` 时,校验不通过 | _boolean_ |
679
+ | message | 错误提示文案 | _string \| (value, rule) => string_ |
680
+ | validator | 通过函数进行校验 | _(value, rule) => boolean \| string \| Promise_ |
681
+ | validateFirst `v0.5.0-alpha.0` | 当某一规则校验不通过时,是否停止剩下的规则的校验。 | _boolean_ | `false` |
682
+ | pattern | 通过正则表达式进行校验 | _RegExp_ |
683
+ | trigger | 本项规则的触发时机,可选值为 `onChange`、`onBlur` | _string_ |
684
+ | formatter | 格式化函数,将表单项的值转换后进行校验 | _(value, rule) => any_ |
685
+
686
+ ### Form.Label Props
687
+
688
+ | 参数 | 说明 | 类型 | 默认值 |
689
+ | ----- | ----------------------------------- | --------- | ------- |
690
+ | align | 对齐方式,可选值为 `center` `right` | _string_ | `left` |
691
+ | colon | 是否在 label 后面添加冒号 | _boolean_ | `false` |
692
+
693
+ ### Form.Feedback Props
694
+
695
+ | 参数 | 说明 | 类型 | 默认值 |
696
+ | ------ | ---------------------------------------------- | -------- | ------ |
697
+ | align | 对齐方式,可选值为 `center` `right` | _string_ | `left` |
698
+ | status | 反馈状态,可选值为 `valid` `warning` `invalid` | _string_ | - |
699
+
700
+ ### Form.Control Props
701
+
702
+ | 参数 | 说明 | 类型 | 默认值 |
703
+ | -------- | ----------------------------------- | ----------------------------------------------------------- | ------ |
704
+ | align | 对齐方式,可选值为 `center` `right` | _string_ | `left` |
705
+ | children | 内容 | _ReactNode\|((controller: FormController<V>) => ReactNode)_ | -- |
706
+
707
+ ```tsx
708
+ interface FormController<V> {
709
+ value?: V // 当前表单项值
710
+ validateStatus?: FormValidateStatus // 当前表单项验证状态
711
+ disabled?: boolean // 当前表单项是否禁用
712
+
713
+ onChange?(value: V): void // 改变当前表单项值
714
+
715
+ onBlur?(value: V): void // 触发onBlur当前表单项校验
716
+ }
717
+ ```
718
+
719
+ > Tips: 使用 onBlur 触发表单验证,自定义表单项时,要手动调用 onBlur,才能触发校验
720
+
721
+ ### Form.List
722
+
723
+ | 参数 | 说明 | 类型 |
724
+ | ------------ | ---------------------------- | ------------------------------------------------------------------------------------ | --- |
725
+ | children | 渲染函数 | _(fields: { key: string, name: string }[], operation: { add, remove }) => ReactNode_ | \_ |
726
+ | name | 表单项名称,提交表单的标识符 | _string_ |
727
+ | defaultValue | 表单项默认值 | _any_ |
728
+
729
+ ### 类型定义
730
+
731
+ 通过`@fjyueke/bify-core/form`导入组件类型:
732
+
733
+ ```tsx
734
+ import { FormRule, FormItemInstance, FormListInstance, FormInstance } from "@fjyueke/bify-core/form"
735
+ ```
736
+
737
+ ## 主题定制
738
+
739
+ ### 样式变量
740
+
741
+ 组件提供了下列 CSS 变量,可用于自定义样式,使用方法请参考 [ConfigProvider](/components/config-provider/) 组件。
742
+
743
+ | 名称 | 默认值 | 描述 |
744
+ | ---------------------------------- | ------------------------- | ---- |
745
+ | form-label-width | _6.2em_ | - |
746
+ | form-label-color | _var(--gray-7)_ | - |
747
+ | form-label-margin-right | _var(--padding-sm)_ | - |
748
+ | form-label-disabled-color | _var(--gray-5)_ | - |
749
+ | form-item-icon-size | _16px \* $hd_ | - |
750
+ | form-item-right-icon-color | _var(--gray-6)_ | - |
751
+ | form-item-right-icon-padding | _0 var(--padding-xs)_ | - |
752
+ | form-item-right-icon-margin-right | _-8px \* $hd_ | - |
753
+ | form-item-right-button-margin-left | _var(--padding-xs)_ | - |
754
+ | form-control-color | _var(--text-color)_ | - |
755
+ | form-control-min-height | _var(--cell-line-height)_ | - |
756
+ | form-feedback-font-size | _var(--font-size-sm)_ | - |
757
+ | form-feedback-valid-color | _var(--success-color)_ | - |
758
+ | form-feedback-warning-color | _var(--warning-color)_ | - |
759
+ | form-feedback-invalid-color | _var(--danger-color)_ | - |