123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. import {
  2. AutoComplete,
  3. Button,
  4. Cascader,
  5. Checkbox,
  6. Col,
  7. Form,
  8. Input,
  9. InputNumber,
  10. Row,
  11. Select,
  12. Card,
  13. } from 'antd';
  14. import React, { useState } from 'react';
  15. const { Option } = Select;
  16. const residences = [
  17. {
  18. value: 'zhejiang',
  19. label: 'Zhejiang',
  20. children: [
  21. {
  22. value: 'hangzhou',
  23. label: 'Hangzhou',
  24. children: [
  25. {
  26. value: 'xihu',
  27. label: 'West Lake',
  28. },
  29. ],
  30. },
  31. ],
  32. },
  33. {
  34. value: 'jiangsu',
  35. label: 'Jiangsu',
  36. children: [
  37. {
  38. value: 'nanjing',
  39. label: 'Nanjing',
  40. children: [
  41. {
  42. value: 'zhonghuamen',
  43. label: 'Zhong Hua Men',
  44. },
  45. ],
  46. },
  47. ],
  48. },
  49. ];
  50. const formItemLayout = {
  51. labelCol: {
  52. xs: {
  53. span: 24,
  54. },
  55. sm: {
  56. span: 8,
  57. },
  58. },
  59. wrapperCol: {
  60. xs: {
  61. span: 24,
  62. },
  63. sm: {
  64. span: 16,
  65. },
  66. },
  67. };
  68. const tailFormItemLayout = {
  69. wrapperCol: {
  70. xs: {
  71. span: 24,
  72. offset: 0,
  73. },
  74. sm: {
  75. span: 16,
  76. offset: 8,
  77. },
  78. },
  79. };
  80. const BasicForm = () => {
  81. const [form] = Form.useForm();
  82. const onFinish = (values) => {
  83. console.log('Received values of form: ', values);
  84. };
  85. const prefixSelector = (
  86. <Form.Item name="prefix" noStyle>
  87. <Select
  88. style={{
  89. width: 70,
  90. }}
  91. >
  92. <Option value="86">+86</Option>
  93. <Option value="87">+87</Option>
  94. </Select>
  95. </Form.Item>
  96. );
  97. const suffixSelector = (
  98. <Form.Item name="suffix" noStyle>
  99. <Select
  100. style={{
  101. width: 70,
  102. }}
  103. >
  104. <Option value="USD">$</Option>
  105. <Option value="CNY">¥</Option>
  106. </Select>
  107. </Form.Item>
  108. );
  109. const [autoCompleteResult, setAutoCompleteResult] = useState([]);
  110. const onWebsiteChange = (value) => {
  111. if (!value) {
  112. setAutoCompleteResult([]);
  113. } else {
  114. setAutoCompleteResult(['.com', '.org', '.net'].map((domain) => `${value}${domain}`));
  115. }
  116. };
  117. const websiteOptions = autoCompleteResult.map((website) => ({
  118. label: website,
  119. value: website,
  120. }));
  121. return (
  122. <Form
  123. {...formItemLayout}
  124. form={form}
  125. name="register"
  126. onFinish={onFinish}
  127. initialValues={{
  128. residence: ['zhejiang', 'hangzhou', 'xihu'],
  129. prefix: '86',
  130. }}
  131. scrollToFirstError
  132. style={{ background: '#fff', boxSizing: 'border-box', padding: '24px' }}
  133. >
  134. <Form.Item
  135. name="email"
  136. label="E-mail"
  137. rules={[
  138. {
  139. type: 'email',
  140. message: 'The input is not valid E-mail!',
  141. },
  142. {
  143. required: true,
  144. message: 'Please input your E-mail!',
  145. },
  146. ]}
  147. >
  148. <Input />
  149. </Form.Item>
  150. <Form.Item
  151. name="password"
  152. label="Password"
  153. rules={[
  154. {
  155. required: true,
  156. message: 'Please input your password!',
  157. },
  158. ]}
  159. hasFeedback
  160. >
  161. <Input.Password />
  162. </Form.Item>
  163. <Form.Item
  164. name="confirm"
  165. label="Confirm Password"
  166. dependencies={['password']}
  167. hasFeedback
  168. rules={[
  169. {
  170. required: true,
  171. message: 'Please confirm your password!',
  172. },
  173. ({ getFieldValue }) => ({
  174. validator(_, value) {
  175. if (!value || getFieldValue('password') === value) {
  176. return Promise.resolve();
  177. }
  178. return Promise.reject(new Error('The two passwords that you entered do not match!'));
  179. },
  180. }),
  181. ]}
  182. >
  183. <Input.Password />
  184. </Form.Item>
  185. <Form.Item
  186. name="nickname"
  187. label="Nickname"
  188. tooltip="What do you want others to call you?"
  189. rules={[
  190. {
  191. required: true,
  192. message: 'Please input your nickname!',
  193. whitespace: true,
  194. },
  195. ]}
  196. >
  197. <Input />
  198. </Form.Item>
  199. <Form.Item
  200. name="residence"
  201. label="Habitual Residence"
  202. rules={[
  203. {
  204. type: 'array',
  205. required: true,
  206. message: 'Please select your habitual residence!',
  207. },
  208. ]}
  209. >
  210. <Cascader options={residences} />
  211. </Form.Item>
  212. <Form.Item
  213. name="phone"
  214. label="Phone Number"
  215. rules={[
  216. {
  217. required: true,
  218. message: 'Please input your phone number!',
  219. },
  220. ]}
  221. >
  222. <Input
  223. addonBefore={prefixSelector}
  224. style={{
  225. width: '100%',
  226. }}
  227. />
  228. </Form.Item>
  229. <Form.Item
  230. name="donation"
  231. label="Donation"
  232. rules={[
  233. {
  234. required: true,
  235. message: 'Please input donation amount!',
  236. },
  237. ]}
  238. >
  239. <InputNumber
  240. addonAfter={suffixSelector}
  241. style={{
  242. width: '100%',
  243. }}
  244. />
  245. </Form.Item>
  246. <Form.Item
  247. name="website"
  248. label="Website"
  249. rules={[
  250. {
  251. required: true,
  252. message: 'Please input website!',
  253. },
  254. ]}
  255. >
  256. <AutoComplete options={websiteOptions} onChange={onWebsiteChange} placeholder="website">
  257. <Input />
  258. </AutoComplete>
  259. </Form.Item>
  260. <Form.Item
  261. name="intro"
  262. label="Intro"
  263. rules={[
  264. {
  265. required: true,
  266. message: 'Please input Intro',
  267. },
  268. ]}
  269. >
  270. <Input.TextArea showCount maxLength={100} />
  271. </Form.Item>
  272. <Form.Item
  273. name="gender"
  274. label="Gender"
  275. rules={[
  276. {
  277. required: true,
  278. message: 'Please select gender!',
  279. },
  280. ]}
  281. >
  282. <Select placeholder="select your gender">
  283. <Option value="male">Male</Option>
  284. <Option value="female">Female</Option>
  285. <Option value="other">Other</Option>
  286. </Select>
  287. </Form.Item>
  288. <Form.Item label="Captcha" extra="We must make sure that your are a human.">
  289. <Row gutter={8}>
  290. <Col span={12}>
  291. <Form.Item
  292. name="captcha"
  293. noStyle
  294. rules={[
  295. {
  296. required: true,
  297. message: 'Please input the captcha you got!',
  298. },
  299. ]}
  300. >
  301. <Input />
  302. </Form.Item>
  303. </Col>
  304. <Col span={12}>
  305. <Button>Get captcha</Button>
  306. </Col>
  307. </Row>
  308. </Form.Item>
  309. <Form.Item
  310. name="agreement"
  311. valuePropName="checked"
  312. rules={[
  313. {
  314. validator: (_, value) =>
  315. value ? Promise.resolve() : Promise.reject(new Error('Should accept agreement')),
  316. },
  317. ]}
  318. {...tailFormItemLayout}
  319. >
  320. <Checkbox>
  321. I have read the <a href="">agreement</a>
  322. </Checkbox>
  323. </Form.Item>
  324. <Form.Item {...tailFormItemLayout}>
  325. <Button type="primary" htmlType="submit">
  326. Register
  327. </Button>
  328. </Form.Item>
  329. </Form>
  330. );
  331. };
  332. export default () => <Card><BasicForm /></Card>;