FormInput.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. /* eslint-disable react/jsx-props-no-spreading */
  2. /* eslint-disable no-shadow */
  3. /* eslint-disable no-underscore-dangle */
  4. /* eslint-disable no-restricted-syntax */
  5. import * as WebBrowser from "expo-web-browser";
  6. import * as React from "react";
  7. import { View, StyleSheet, TouchableWithoutFeedback } from "react-native";
  8. import {
  9. Layout,
  10. Input,
  11. Button,
  12. Icon,
  13. Text,
  14. SelectItem,
  15. } from "@ui-kitten/components";
  16. import { Cascader, BottomModal } from "beeshell";
  17. import { useCreation } from "@umijs/hooks";
  18. import { useModel } from "flooks";
  19. import moment from "moment";
  20. import OpenTime from "./OpenTime";
  21. import Datepicker from "./Datepicker";
  22. import UpLoadImage from "./UpLoadImage";
  23. import Actionsheet from "./Actionsheet";
  24. const styles = StyleSheet.create({
  25. inputContainer: {
  26. flexDirection: "row",
  27. alignItems: "center",
  28. paddingVertical: 10,
  29. paddingHorizontal: 4,
  30. },
  31. input: {
  32. flex: 1,
  33. },
  34. label: {
  35. width: 80,
  36. marginRight: 19,
  37. flexShrink: 0,
  38. },
  39. labelleft: {
  40. width: 73,
  41. flexShrink: 0,
  42. },
  43. right: {
  44. flexDirection: "row",
  45. },
  46. code: {
  47. paddingHorizontal: 5,
  48. marginLeft: 5,
  49. },
  50. selectContent: {
  51. backgroundColor: "#F0F0F0",
  52. },
  53. titleStyle: {
  54. fontSize: 15,
  55. },
  56. leftLabelTextStyle: {
  57. fontSize: 13,
  58. },
  59. rightLabelTextStyle: {
  60. fontSize: 13,
  61. },
  62. sub: {
  63. color: "#787878",
  64. position: "absolute",
  65. left: 90,
  66. zIndex: 2,
  67. },
  68. upload: {
  69. marginTop: 20,
  70. width: 67,
  71. height: 67,
  72. },
  73. });
  74. function* flattenSelect(array, key) {
  75. for (const item of array) {
  76. const _array = key ? item[key] : item;
  77. if (Array.isArray(_array) && _array.length > 0) {
  78. yield* flattenSelect(_array, key);
  79. } else {
  80. yield item;
  81. }
  82. }
  83. }
  84. function getInputProps(
  85. type,
  86. value,
  87. placeholder,
  88. onChange,
  89. secureTextEntry,
  90. renderIcon
  91. ) {
  92. let _props = {
  93. defaultValue: value || "",
  94. placeholder,
  95. };
  96. if (type === "phone") {
  97. _props = {
  98. ..._props,
  99. dataDetectorTypes: "phoneNumber",
  100. maxLength: 11,
  101. keyboardType: "phone-pad",
  102. };
  103. } else if (type === "password") {
  104. _props = {
  105. ..._props,
  106. accessoryRight: ImageProps => renderIcon(ImageProps),
  107. secureTextEntry,
  108. };
  109. } else if (type === "code") {
  110. _props = {
  111. ..._props,
  112. maxLength: 6,
  113. keyboardType: "numeric",
  114. };
  115. } else if (type === "amount" || type === "money") {
  116. _props = {
  117. ..._props,
  118. keyboardType: "numeric",
  119. };
  120. }
  121. if (onChange) {
  122. _props = {
  123. ..._props,
  124. onChangeText: nextValue => onChange(nextValue),
  125. };
  126. }
  127. return _props;
  128. }
  129. const ForwardIcon = props => <Icon {...props} name="arrow-ios-forward" />;
  130. const Label = ({ type, labelStyle, label, appearance }) => {
  131. return (
  132. <View
  133. style={[
  134. appearance === "inner" ? styles.labelleft : styles.label,
  135. type === "img" ? { alignSelf: "flex-start" } : {},
  136. labelStyle || {},
  137. ]}
  138. >
  139. <Text
  140. category="c1"
  141. style={{
  142. textAlign: appearance !== "inner" ? "right" : "left",
  143. }}
  144. >
  145. {label}
  146. </Text>
  147. </View>
  148. );
  149. };
  150. const Btn = ({ btnText }) => (
  151. <Button
  152. appearance="ghost"
  153. size="tiny"
  154. style={{ paddingVertical: 8, marginLeft: 5 }}
  155. >
  156. {btnText}
  157. </Button>
  158. );
  159. const FormInput = React.memo(props => {
  160. const {
  161. placeholder,
  162. appearance,
  163. type,
  164. selectList,
  165. value,
  166. style,
  167. sub,
  168. onChange,
  169. labelStyle,
  170. label,
  171. } = props;
  172. const [secureTextEntry, setSecureTextEntry] = React.useState(true);
  173. const { cancel, confirm } = useModel("wordsModel");
  174. const toggleSecureEntry = () => {
  175. setSecureTextEntry(!secureTextEntry);
  176. };
  177. // eslint-disable-next-line no-shadow
  178. const renderIcon = props => (
  179. <TouchableWithoutFeedback onPress={toggleSecureEntry}>
  180. <Icon {...props} name={secureTextEntry ? "eye-off" : "eye"} />
  181. </TouchableWithoutFeedback>
  182. );
  183. const inputProps = useCreation(() => {
  184. return getInputProps(
  185. type,
  186. value,
  187. placeholder,
  188. onChange,
  189. secureTextEntry,
  190. renderIcon
  191. );
  192. }, [type, value, placeholder, onChange, secureTextEntry, renderIcon]);
  193. // const [bottomModalX, changeBottomModalx] = React.useState("");
  194. const bottomRef = React.useRef();
  195. const [selectVal, setSelectVal] = React.useState("");
  196. const selectInfo = useCreation(() => {
  197. if (type === "select" && props.value && selectList) {
  198. const childrens = [...flattenSelect(selectList, "children")];
  199. return (
  200. childrens.find(item => {
  201. return item.id === props.value;
  202. }) || { name: " " }
  203. );
  204. }
  205. return { name: " " };
  206. }, [value, type, selectList]);
  207. function getMain(type, props, inputProps) {
  208. if (type === "select") {
  209. return (
  210. <>
  211. <SelectItem
  212. appearance="form"
  213. style={{ flex: 1 }}
  214. accessoryRight={ForwardIcon}
  215. title={selectInfo.name}
  216. onPress={() => {
  217. bottomRef.current.open();
  218. }}
  219. />
  220. <BottomModal
  221. ref={bottomRef}
  222. title={props.selectTitle}
  223. titleStyle={styles.titleStyle}
  224. cancelable
  225. leftLabelText={cancel}
  226. leftLabelTextStyle={styles.leftLabelTextStyle}
  227. rightLabelText={confirm}
  228. rightLabelTextStyle={styles.rightLabelTextStyle}
  229. rightCallback={() => {
  230. props.onChange(selectVal);
  231. }}
  232. >
  233. <Cascader
  234. style={{
  235. width: "100%",
  236. height: 200,
  237. marginBottom: 50,
  238. minHeight: 200,
  239. }}
  240. data={selectList}
  241. fieldKeys={{
  242. labelKey: "name",
  243. idKey: "id",
  244. activeKey: "choose",
  245. }}
  246. onChange={value => {
  247. setSelectVal(value[0]);
  248. }}
  249. />
  250. </BottomModal>
  251. </>
  252. );
  253. }
  254. if (type === "openTime") {
  255. return (
  256. <OpenTime
  257. submit={(week, startTime, endTime) => {
  258. props.onChange(week, startTime, endTime);
  259. }}
  260. week={props.week}
  261. startTime={props.startTime}
  262. endTime={props.endTime}
  263. />
  264. );
  265. }
  266. if (type === "date") {
  267. return <Datepicker chooseDate={props.onChange} value={props.value} />;
  268. }
  269. if (type === "url") {
  270. return (
  271. <SelectItem
  272. appearance="form"
  273. style={{ flex: 1 }}
  274. accessoryRight={ForwardIcon}
  275. title={props.value || " "}
  276. onPress={props.changePath}
  277. />
  278. );
  279. }
  280. if (type === "actionSheet") {
  281. return (
  282. <>
  283. <Actionsheet
  284. list={props.list}
  285. value={props.value}
  286. onChange={props.onChange}
  287. />
  288. </>
  289. );
  290. }
  291. if (type === "img") {
  292. return (
  293. <UpLoadImage
  294. style={styles.upload}
  295. value={props.value}
  296. changeIcon={props.onChange}
  297. aspect={[1, 1]}
  298. />
  299. );
  300. }
  301. if (appearance === "inner" && type === "code") {
  302. return (
  303. <Input
  304. {...inputProps}
  305. accessoryLeft={() => (
  306. <Label
  307. type={type}
  308. labelStyle={labelStyle}
  309. label={label}
  310. appearance={appearance}
  311. />
  312. )}
  313. accessoryRight={() => <Btn btnText={props.btnText} />}
  314. size="small"
  315. style={styles.input}
  316. appearance="innerCode"
  317. />
  318. );
  319. }
  320. if (appearance === "inner") {
  321. return (
  322. <Input
  323. {...inputProps}
  324. accessoryLeft={() => (
  325. <Label
  326. type={type}
  327. labelStyle={labelStyle}
  328. label={label}
  329. appearance={appearance}
  330. />
  331. )}
  332. size="small"
  333. style={styles.input}
  334. appearance="inner"
  335. />
  336. );
  337. }
  338. if (type === "label") {
  339. return null;
  340. }
  341. return <Input {...inputProps} size="small" style={styles.input} />;
  342. }
  343. return (
  344. <Layout
  345. level="1"
  346. style={[
  347. styles.inputContainer,
  348. { ...style },
  349. type === "img" ? { flexDirection: "column" } : {},
  350. { paddingVertical: appearance === "inner" ? 0 : 10 },
  351. ]}
  352. >
  353. {appearance !== "inner" && (
  354. <Label
  355. type={type}
  356. labelStyle={labelStyle}
  357. label={label}
  358. appearance={appearance}
  359. />
  360. )}
  361. {(!value || value === " ") && (
  362. <Text category="c1" style={styles.sub}>
  363. {sub}
  364. </Text>
  365. )}
  366. {getMain(type, props, inputProps)}
  367. {appearance !== "inner" && type === "code" && Btn(props)}
  368. </Layout>
  369. );
  370. });
  371. export default FormInput;