diff --git a/README.md b/README.md index 6e05280..acfb9c2 100644 --- a/README.md +++ b/README.md @@ -34,26 +34,22 @@ npm i --save @kne/react-form-antd ```jsx const {Button} = antd; -const {Form, Select, Input, Group, GroupList, SubmitButton, DatePickerToday, Rate, Slider} = reactFormAntd; +const {default: Form, Select, Input, Group, GroupList, SubmitButton, DatePickerToday, Rate, Slider} = reactFormAntd; const {useRef} = React; const Example = () => { const addButton = useRef(); - return
+ return
- - - - - - - - + + + +
- {(key, {onRemove}) => { + {({onRemove}) => { return
@@ -74,7 +70,7 @@ const Example = () => { }; -render(); +render(); ``` diff --git a/doc/base.js b/doc/base.js index 227087e..e9a172e 100644 --- a/doc/base.js +++ b/doc/base.js @@ -1,24 +1,20 @@ const {Button} = antd; -const {Form, Select, Input, Group, GroupList, SubmitButton, DatePickerToday, Rate, Slider} = reactFormAntd; +const {default: Form, Select, Input, Group, GroupList, SubmitButton, DatePickerToday, Rate, Slider} = reactFormAntd; const {useRef} = React; const Example = () => { const addButton = useRef(); - return
+ return
- - - - - - - - + + + +
- {(key, {onRemove}) => { + {({onRemove}) => { return
@@ -39,4 +35,4 @@ const Example = () => { }; -render(); +render(); diff --git a/package.json b/package.json index 54841ef..6a21423 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@kne/react-form-antd", - "version": "3.1.5", + "version": "4.0.0-alpha.0", "syntax": { "esmodules": true }, @@ -9,21 +9,22 @@ "module": "dist/index.modern.js", "source": "src/index.js", "scripts": { + "init": "husky && npm run init-example", + "start": "run-p start:lib start:md start:example", + "build": "run-s build:lib build:md build:example", "init-example": "modules-dev-libs-init", - "create-fields": "node ./scripts/createIndex.mjs", - "start": "run-p start:lib start:example", - "build": "run-s create-fields build:lib build:example", + "build:md": "npx @kne/md-doc", + "start:md": "npx @kne/md-doc --watch", "build:lib": "microbundle --no-compress --format modern,cjs --jsx React.createElement --jsxFragment React.Fragment", "start:lib": "microbundle watch --no-compress --format modern,cjs --jsx React.createElement --jsxFragment React.Fragment", - "test": "run-s test:unit test:lint test:build", + "build:example": "cd example && npm run build", + "start:example": "cd example && npm run start", "test:build": "run-s build", "test:lint": "eslint .", "test:unit": "cross-env CI=1 react-scripts test --env=jsdom", "test:watch": "react-scripts test --env=jsdom", - "build:example": "cd example && npm run build", - "start:example": "cd example && npm run start", - "deploy": "gh-pages -d example/build", - "prettier": "prettier --config .prettierrc --write 'src/**/*.{js,jsx,ts,tsx,json,css,scss,md}'" + "prettier": "prettier --config .prettierrc --write '{src/**/*,index,prompts}.{js,jsx,ts,tsx,json,css,scss}'", + "lint-staged": "npx lint-staged" }, "repository": { "type": "git", @@ -55,40 +56,25 @@ }, "homepage": "https://github.com/kne-union/react-form-antd#readme", "peerDependencies": { - "@kne/react-fetch": "1.x", "antd": ">=5.x", - "prop-types": ">=15.x", - "react": ">=16.x" + "react": ">=18.x" }, "dependencies": { - "@ant-design/icons": "^4.2.1", - "@babel/runtime": "^7.10.3", - "@kne/react-form": "^2.1.16", - "@kne/react-form-helper": "^1.0.36", + "@kne/react-form": "3.1.0-alpha.5", + "@kne/react-form-helper": "3.0.0-alpha.0", "@kne/use-control-value": "^0.1.1", - "@kne/use-event": "^0.1.3", - "@kne/with-layer": "^0.1.5", "classnames": "^2.2.6", "dayjs": "^1.11.7", - "lodash": "^4.17.15", - "react-avatar-editor": "^13.0.0" + "lodash": "^4.17.15" }, "devDependencies": { - "@craco/craco": "^7.1.0", - "@kne/microbundle": "^0.15.4", - "@kne/modules-dev": "^2.0.3", - "@kne/react-fetch": "^0.1.12", - "antd": "^5.0.2", - "axios": "^0.21.4", + "@kne/microbundle": "^0.15.5", + "@kne/modules-dev": "^2.0.19", + "@kne/react-form": "^3.1.0-alpha.4", "cross-env": "^7.0.3", - "fs-extra": "^9.0.1", - "gh-pages": "^3.2.3", - "glob": "^10.3.3", - "husky": "^7.0.2", - "sass": "1.75.0", + "husky": "^9.0.11", "npm-run-all": "^4.1.5", - "pify": "^5.0.0", - "prettier": "^2.4.1", + "prettier": "^3.2.5", "react": "^18.2.0", "react-dom": "^18.2.0" } diff --git a/src/assets/full.js b/src/assets/full.js deleted file mode 100644 index 795bab7..0000000 --- a/src/assets/full.js +++ /dev/null @@ -1,5 +0,0 @@ -import * as React from "react"; - -const FullIcon = props => {"\u5145\u6EE1"}; - -export default FullIcon; \ No newline at end of file diff --git a/src/assets/index.scss b/src/assets/index.scss index 32fd8e3..309c237 100644 --- a/src/assets/index.scss +++ b/src/assets/index.scss @@ -217,22 +217,6 @@ } } -.react-form-avatar { - .preview { - width: 85px; - height: 85px; - overflow: hidden; - display: flex; - justify-content: center; - align-items: center; - - img { - max-width: 100%; - max-height: 100%; - } - } -} - .data_range_picker { color: rgba(0, 0, 0, 0.85); position: relative; @@ -258,31 +242,3 @@ } } } - -.svg_box { - display: flex; - align-items: center; - color: rgba(0, 0, 0, 0.5); - margin: 0 4px; - - svg { - width: 16px; - height: 16px; - } -} - -.react-form-avatar-btn { - cursor: pointer; - padding: 5px; - box-sizing: content-box; - border-radius: 2px; - &:hover { - background: #F8F8F8; - } -} - -.react-form-avatar-tips { - margin-bottom: 14px; - color: #999; - font-size: 12px; -} diff --git a/src/assets/rotate.js b/src/assets/rotate.js deleted file mode 100644 index f10ec02..0000000 --- a/src/assets/rotate.js +++ /dev/null @@ -1,5 +0,0 @@ -import * as React from "react"; - -const RotateIcon = props => {"\u65CB\u8F6C"}; - -export default RotateIcon; \ No newline at end of file diff --git a/src/common/getPopupContainer.js b/src/common/getPopupContainer.js deleted file mode 100644 index d910bc5..0000000 --- a/src/common/getPopupContainer.js +++ /dev/null @@ -1,15 +0,0 @@ -const getPopupContainer = (triggerNode) => { - const findAntdPopupContainer = (el) => { - if (el === document.body || !el.parentElement) { - return document.body - } - const targetEl = [].slice.call(el.classList, 0).find((className) => ['ant-modal-body', 'ant-modal-content', 'ant-popover-content'].indexOf(className) > -1); - if (targetEl) { - return el; - } - return findAntdPopupContainer(el.parentElement); - }; - return findAntdPopupContainer(triggerNode); -}; - -export default getPopupContainer; diff --git a/src/common/withFetch.js b/src/common/withFetch.js deleted file mode 100644 index 4103eea..0000000 --- a/src/common/withFetch.js +++ /dev/null @@ -1,85 +0,0 @@ -import React, {forwardRef, useImperativeHandle, useEffect, useRef} from 'react'; -import useEvent from "@kne/use-event"; -import {hooks} from "@kne/react-form-helper"; -import {withFetch as withReactFetch} from '@kne/react-fetch'; - -const {useOnChange} = hooks; - -const withFetch = (WrappedComponent) => { - const FieldInner = withReactFetch(({ - data, - setData, - send, - loadMore, - isComplete, - refresh, - reload, - fetchEmitter, - isLoading, - children, - onLoaded, - fetchProps, - requestParams, - ...props - }) => { - const refreshRef = useRef(refresh); - refreshRef.current = refresh; - const reloadRef = useRef(reload); - reloadRef.current = reload - const setDataRef = useRef(setData); - setDataRef.current = setData; - const dataRef = useRef(data); - useEffect(() => { - const token1 = fetchEmitter.addListener('select-fetch-refresh', () => refreshRef.current()); - const token2 = fetchEmitter.addListener('select-fetch-reload', () => reloadRef.current()); - const token3 = fetchEmitter.addListener('select-fetch-set-data', () => setDataRef.current()); - return () => { - token1 && token1.remove(); - token2 && token2.remove(); - token3 && token3.remove(); - }; - }, [fetchEmitter]); - useEffect(() => { - onLoaded && onLoaded(dataRef.current); - }, []); - return ; - }); - - const useFetchEmitter = (ref) => { - const emitter = useEvent(); - useImperativeHandle(ref, () => { - return { - refresh: () => emitter.emit('select-fetch-refresh'), - reload: () => emitter.emit('select-fetch-reload'), - setData: (data) => emitter.emit('select-fetch-set-data', data) - }; - }, [emitter]); - return emitter; - }; - - const Fetch = forwardRef((props, ref) => { - const emitter = useFetchEmitter(ref); - const render = useOnChange(Object.assign({placeholder: `请选择${props.label}`}, props, {fetchEmitter: emitter})); - return render(FieldInner); - }); - - Fetch.field = forwardRef((props, ref) => { - const emitter = useFetchEmitter(ref); - - return ; - }); - - return Fetch; -}; - -export default withFetch; diff --git a/src/fields/Avatar.js b/src/fields/Avatar.js deleted file mode 100644 index d4c6f6f..0000000 --- a/src/fields/Avatar.js +++ /dev/null @@ -1,232 +0,0 @@ -import React, {useState, useRef, useEffect, forwardRef} from "react"; -import {Upload, message, Modal, Slider, Row, Col, Tooltip, App} from "antd"; -import withLayer from '@kne/with-layer'; -import {globalParams} from "../preset"; -import classnames from "classnames"; -import { - PlusOutlined, LoadingOutlined -} from "@ant-design/icons"; -import AvatarEditor from "react-avatar-editor"; -import {hooks} from "@kne/react-form-helper"; -import {merge, omit} from 'lodash'; -import Rotate from '../assets/rotate'; -import Full from '../assets/full'; -import getPopupContainer from '../common/getPopupContainer'; - -const {useOnChange} = hooks; -const avatarParams = globalParams.field.avatar; - -const createAvatarEditor = withLayer(({close, file, editor, onComplete, ...props}) => { - const editorRef = useRef(null); - const [rotate, setRotate] = useState(0); - const [scale, setScale] = useState(() => { - if (editor.width === editor.height) { - return 1; - } - return 0.35; - }); - const {modal} = App.useApp(); - - return { - onComplete && onComplete(editorRef.current.getImage().toDataURL()); - close(); - }}> - {editor.tips ?
{editor.tips}
: null} -
- - - { - setRotate((rotate) => { - return (rotate - 90) % 360; - }); - }}/> - { - setScale(1); - }}/> - - '大小', getPopupContainer - }} value={scale} step={0.05} min={0.2} max={3} onChange={setScale}/> - - -
-
-}); - - -const _Avatar = ({ - className, - value: imageUrl, - onChange: propsChange, - beforeUpload: onBeforeUpload, - transformResponse, - action, - imageType, - fileSize: size, - children, - extraRender, - onError, - openEditor, - editorTips, - editor: targetEditor, - previewImg, - previewRender - }) => { - const [loading, setLoading] = useState(false); - const [showImageUrl, setImageUrl] = useState(imageUrl); - const editorRef = useRef(); - - const defaultEditor = { - open: false, - width: 250, - height: 250, - borderRadius: 1, - text: "确定", - cancelText: '取消', - title: "裁剪图片", - tips: null - }; - const editor = merge({}, defaultEditor, {open: openEditor, tips: editorTips}, targetEditor); - - useEffect(() => { - setImageUrl(imageUrl); - }, [imageUrl]); - - /* base64转blob */ - const dataURLtoBlob = (dataurl) => { - let arr = dataurl.split(","); - // 注意base64的最后面中括号和引号是不转译的 - let _arr = arr[1].substring(0, arr[1].length - 2); - let mime = arr[0].match(/:(.*?);/)[1], bstr = atob(_arr), n = bstr.length, u8arr = new Uint8Array(n); - while (n--) { - u8arr[n] = bstr.charCodeAt(n); - } - return new Blob([u8arr], { - type: mime - }); - }; - - const uploadButton = (
- {loading ? : } - {children} -
); - - const beforeUpload = async (file) => { - return new Promise((resolve, reject) => { - const isJpgOrPng = imageType.indexOf(file.type) > -1; - if (!isJpgOrPng) { - onError(`只支持${imageType.map((str) => str.replace("image/", "")).join("/")}格式图片!`, "typeError", { - type: imageType, fileType: file.type - }); - reject(); - return false; - } - const isLt = file.size / 1024 / 1024 < size; - if (!isLt) { - onError(`图片不能超过${size}MB!`, "sizeError", {size, fileSize: file.size}); - reject(); - return false; - } - - /*剪切图像*/ - // editor:{open:false,width:250,height:250,borderRadius:0-100,text:'剪切'} - if (editor.open) { - createAvatarEditor({ - editor, - file, - title: editor.title, - icon: "", - width: editor.width * 2, - cancelText: editor.cancelText, - okText: editor.text, - onComplete: (base64) => { - setImageUrl(base64); - let blob = dataURLtoBlob(base64); - const files = new window.File([blob], file.name, {type: file.type}); - onBeforeUpload && onBeforeUpload(files); - resolve(files); - } - }); - } else { - onBeforeUpload && onBeforeUpload(file); - resolve(file); - } - }); - - }; - - const onChange = (info) => { - if (info.file.status === "uploading") { - setLoading(true); - return; - } - if (info.file.status === "done") { - setLoading(false); - const response = (transformResponse || avatarParams.transformResponse)(info.file.response); - if (response.code === 200) { - propsChange(response.results); - } else { - onError(response.msg, "xhrError", response); - } - } - }; - - const headers = Object.assign({}, avatarParams.headers); - - if (typeof avatarParams.getHeaders === 'function') { - Object.assign(headers, avatarParams.getHeaders()) - } - - return (<> - -
- {previewImg && showImageUrl ? previewRender ? previewRender(showImageUrl) : -
avatar
: uploadButton} - {extraRender ? extraRender(showImageUrl) : ''} -
-
- ); -}; - -_Avatar.defaultProps = { - imageType: ["image/jpeg", "image/png"], - fileSize: 2, // 单位MB - children:
点击上传
, - extraRender: null, - onError: (info) => message.error(info), - previewImg: true, - previewRender: null, - openEditor: false -}; - -const AvatarInput = (props) => { - const render = useOnChange(props); - return render(_Avatar); -}; - -AvatarInput.defaultProps = { - fieldName: 'avatar' -}; - -AvatarInput.field = _Avatar; - -export default AvatarInput; diff --git a/src/fields/Cascader.js b/src/fields/Cascader.js index 7a789dc..79a8f22 100644 --- a/src/fields/Cascader.js +++ b/src/fields/Cascader.js @@ -4,13 +4,14 @@ import {hooks} from '@kne/react-form-helper'; const {useOnChange} = hooks; const Cascader = (props) => { + props = Object.assign({}, { + fieldName: 'cascader' + }, props); const render = useOnChange(props); return render(_Cascader); }; -Cascader.defaultProps = { - fieldName: 'cascader' -}; +Cascader.Field = _Cascader; export default Cascader; diff --git a/src/fields/Checkbox.js b/src/fields/Checkbox.js index 1aa79fb..05d9195 100644 --- a/src/fields/Checkbox.js +++ b/src/fields/Checkbox.js @@ -7,6 +7,9 @@ const {withChecked} = hoc; const WithCheckbox = withChecked(_Checkbox); const Checkbox = (props) => { + props = Object.assign({}, { + fieldName: 'checkbox' + }, props); const checkedProps = useCheckedToValue(Object.assign({}, props, { onChange: (e) => { e.target.type = 'checkbox'; @@ -17,8 +20,5 @@ const Checkbox = (props) => { return render(WithCheckbox); }; -Checkbox.defaultProps = { - fieldName: 'checkbox' -}; - +Checkbox.Field = _Checkbox; export default Checkbox; diff --git a/src/fields/CheckboxGroup.js b/src/fields/CheckboxGroup.js index 3013397..7b55714 100644 --- a/src/fields/CheckboxGroup.js +++ b/src/fields/CheckboxGroup.js @@ -6,14 +6,14 @@ const {useOnChange} = hooks; const _CheckboxGroup = Checkbox.Group; const CheckboxGroup = (props) => { + props = Object.assign({}, { + fieldName: 'checkboxGroup' + }, props); const render = useOnChange(props); return render(_CheckboxGroup); }; CheckboxGroup.Checkbox = Checkbox; - -CheckboxGroup.defaultProps = { - fieldName: 'checkboxGroup' -}; +CheckboxGroup.Field = _CheckboxGroup; export default CheckboxGroup; diff --git a/src/fields/DatePicker.js b/src/fields/DatePicker.js index b62442b..83b24d2 100644 --- a/src/fields/DatePicker.js +++ b/src/fields/DatePicker.js @@ -6,40 +6,44 @@ const {useOnChange} = hooks; const {MonthPicker, RangePicker, WeekPicker} = DatePicker; const _DatePicker = (props) => { + props = Object.assign({}, { + fieldName: 'datePicker' + }, props); const render = useOnChange(Object.assign({placeholder: `请选择${props.label || ''}`}, props)); return render(DatePicker); }; -_DatePicker.defaultProps = { - fieldName: 'datePicker' -}; +_DatePicker.Field = DatePicker; const _MonthPicker = (props) => { + props = Object.assign({}, { + fieldName: 'monthDatePicker' + }, props); const render = useOnChange(Object.assign({placeholder: ['开始时间', '结束时间']}, props)); return render(MonthPicker); }; -_MonthPicker.defaultProps = { - fieldName: 'monthDatePicker' -}; +_MonthPicker.Field = MonthPicker; const _RangePicker = (props) => { + props = Object.assign({}, { + fieldName: 'rangeDatePicker' + }, props); const render = useOnChange(Object.assign({placeholder: ['开始时间', '结束时间']}, props)); return render(RangePicker); }; -_RangePicker.defaultProps = { - fieldName: 'rangeDatePicker' -}; +_RangePicker.Field = RangePicker; const _WeekPicker = (props) => { + props = Object.assign({}, { + fieldName: 'weekDatePicker' + }, props); const render = useOnChange(Object.assign({placeholder: ['开始时间', '结束时间']}, props)); return render(WeekPicker); }; -_WeekPicker.defaultProps = { - fieldName: 'weekDatePicker' -}; +_WeekPicker.Field = WeekPicker; _DatePicker.MonthPicker = _MonthPicker; _DatePicker.RangePicker = _RangePicker; diff --git a/src/fields/DatePickerToday.js b/src/fields/DatePickerToday.js index 655108d..a4ce66b 100644 --- a/src/fields/DatePickerToday.js +++ b/src/fields/DatePickerToday.js @@ -41,51 +41,46 @@ const PickerToday = ({soFarText, startProps, endProps, ...props}) => { }; const foot = () => { - return ( - - ) + return () } - return ( -
- -
- -
-
- {soFarText || '至今'} - -
+ return (
+ +
+
- ); +
+ {soFarText || '至今'} + +
+
); } const RangePickerToday = (props) => { + props = Object.assign({}, { + fieldName: 'rangePickerToday' + }, props); const render = useOnChange(props); return render(PickerToday); }; -RangePickerToday.defaultProps = { - fieldName: 'rangePickerToday' -}; - -RangePickerToday.field = PickerToday; +RangePickerToday.Field = PickerToday; export default RangePickerToday; diff --git a/src/fields/Input.js b/src/fields/Input.js index e83ee8b..b746df4 100644 --- a/src/fields/Input.js +++ b/src/fields/Input.js @@ -4,23 +4,23 @@ import {hooks} from '@kne/react-form-helper'; const {useDecorator} = hooks; const InputField = (props) => { + props = Object.assign({}, { + fieldName: 'input', autoComplete: 'off' + }, props); const render = useDecorator(Object.assign({placeholder: `请输入${props.label}`}, props)); return render(Input); }; +InputField.Field = Input; + InputField.Password = (props) => { + props = Object.assign({}, { + fieldName: 'password', autoComplete: 'off' + }, props); const render = useDecorator(Object.assign({placeholder: `请输入${props.label}`}, props)); return render(Input.Password); }; -InputField.defaultProps = { - fieldName: 'input', - autoComplete: 'off' -}; - -InputField.Password.defaultProps = { - fieldName: 'password', - autoComplete: 'off' -}; +InputField.Password.Field = Input.Password; export default InputField; diff --git a/src/fields/InputNumber.js b/src/fields/InputNumber.js index a54c837..c07c184 100644 --- a/src/fields/InputNumber.js +++ b/src/fields/InputNumber.js @@ -4,13 +4,13 @@ import {hooks} from '@kne/react-form-helper'; const {useDecorator} = hooks; const InputNumberField = (props) => { + props = Object.assign({}, { + fieldName: 'inputNumber', autoComplete: 'off' + }, props); const render = useDecorator(Object.assign({placeholder: `请输入${props.label}`}, props)); return render(InputNumber); }; -InputNumberField.defaultProps = { - fieldName: 'inputNumber', - autoComplete: 'off' -}; +InputNumberField.Field = InputNumber; export default InputNumberField; diff --git a/src/fields/RadioGroup.js b/src/fields/RadioGroup.js index 1d42ded..639784d 100644 --- a/src/fields/RadioGroup.js +++ b/src/fields/RadioGroup.js @@ -5,6 +5,9 @@ import {hooks} from '@kne/react-form-helper'; const {useOnChange} = hooks; const RadioGroup = ({onChange, ...props}) => { + props = Object.assign({}, { + fieldName: 'radioGroup' + }, props); const handler = useCallback((e) => { onChange && onChange(e.target.value); }, [onChange]); @@ -16,10 +19,7 @@ const _RadioGroup = (props) => { return render(RadioGroup); }; -_RadioGroup.defaultProps = { - fieldName: 'radioGroup' -}; - +_RadioGroup.Field = RadioGroup; _RadioGroup.Radio = Radio; export default _RadioGroup; diff --git a/src/fields/Rate.js b/src/fields/Rate.js index c26d70c..b382429 100644 --- a/src/fields/Rate.js +++ b/src/fields/Rate.js @@ -4,12 +4,13 @@ import {hooks} from '@kne/react-form-helper'; const {useOnChange} = hooks; const Rate = (props) => { + props = Object.assign({}, { + fieldName: 'rate' + }, props); const render = useOnChange(Object.assign({}, props)); return render(_Rate); }; -Rate.defaultProps = { - fieldName: 'rate' -}; +Rate.Field = _Rate; export default Rate; diff --git a/src/fields/Select.js b/src/fields/Select.js index 40823f4..c7d697d 100644 --- a/src/fields/Select.js +++ b/src/fields/Select.js @@ -1,21 +1,17 @@ import {Select} from 'antd'; import {hooks} from '@kne/react-form-helper'; -import withFetch from '../common/withFetch'; const {useOnChange} = hooks; const _Select = (props) => { + props = Object.assign({}, { + fieldName: 'select' + }, props); const render = useOnChange(Object.assign({placeholder: `请选择${props.label || ''}`}, props)); return render(Select); }; - -_Select.Fetch = withFetch(Select); - +_Select.Field = Select; _Select.Option = Select.Option; _Select.OptGroup = Select.OptGroup; -_Select.defaultProps = _Select.Fetch.defaultProps = { - fieldName: 'select' -}; - export default _Select; diff --git a/src/fields/Slider.js b/src/fields/Slider.js index 77dbdeb..8914efc 100644 --- a/src/fields/Slider.js +++ b/src/fields/Slider.js @@ -4,12 +4,13 @@ import {hooks} from '@kne/react-form-helper'; const {useOnChange} = hooks; const Slider = (props) => { + props = Object.assign({}, { + fieldName: 'slider' + }, props); const render = useOnChange(Object.assign({}, props)); return render(_Slider); }; -Slider.defaultProps = { - fieldName: 'slider' -}; +Slider.Field = _Slider; export default Slider; diff --git a/src/fields/Switch.js b/src/fields/Switch.js index 8db14fe..8581955 100644 --- a/src/fields/Switch.js +++ b/src/fields/Switch.js @@ -6,13 +6,14 @@ const {withChecked} = hoc; const WithSwitch = withChecked(_Switch); const Switch = (props) => { + props = Object.assign({}, { + fieldName: 'switch' + }, props); const checkedProps = useCheckedToValue(props); const render = useOnChange(checkedProps); return render(WithSwitch); }; -Switch.defaultProps = { - fieldName: 'switch' -}; +Switch.Field = _Switch; export default Switch; diff --git a/src/fields/TextArea.js b/src/fields/TextArea.js index b77b6d5..1c7c9c0 100644 --- a/src/fields/TextArea.js +++ b/src/fields/TextArea.js @@ -4,12 +4,13 @@ import {hooks} from '@kne/react-form-helper'; const {useDecorator} = hooks; const TextArea = (props) => { + props = Object.assign({}, { + fieldName: 'textArea' + }, props); const render = useDecorator(Object.assign({placeholder: `请输入${props.label}`}, props)); return render(Input.TextArea); }; -TextArea.defaultProps = { - fieldName: 'textArea' -}; +TextArea.Field = Input.TextArea; export default TextArea; diff --git a/src/fields/TimePicker.js b/src/fields/TimePicker.js index 15d484b..163b497 100644 --- a/src/fields/TimePicker.js +++ b/src/fields/TimePicker.js @@ -6,22 +6,24 @@ const {useOnChange} = hooks; const {RangePicker} = TimePicker; const _TimePicker = (props) => { + props = Object.assign({}, { + fieldName: 'timePicker' + }, props); const render = useOnChange(Object.assign({placeholder: `请选择${props.label || ''}`}, props)); return render(TimePicker); }; -_TimePicker.defaultProps = { - fieldName: 'timePicker' -}; +_TimePicker.Field = TimePicker; const _RangePicker = (props) => { + props = Object.assign({}, { + fieldName: 'rangeTimePicker' + }, props); const render = useOnChange(Object.assign({placeholder: `请选择${props.label || ''}`}, props)); return render(RangePicker); }; -_RangePicker.defaultProps = { - fieldName: 'rangeTimePicker' -}; +_RangePicker.Field = RangePicker; _TimePicker.RangePicker = _RangePicker; diff --git a/src/fields/TreeSelect.js b/src/fields/TreeSelect.js index 541f9a4..0f6d8ff 100644 --- a/src/fields/TreeSelect.js +++ b/src/fields/TreeSelect.js @@ -1,19 +1,17 @@ import {TreeSelect} from 'antd'; import {hooks} from '@kne/react-form-helper'; -import withFetch from "../common/withFetch"; const {useOnChange} = hooks; const _TreeSelect = (props) => { + props = Object.assign({}, { + fieldName: 'treeSelect' + }, props); const render = useOnChange(Object.assign({placeholder: `请选择${props.label || ''}`}, props)); return render(TreeSelect); }; -_TreeSelect.Fetch = withFetch(TreeSelect); - -_TreeSelect.defaultProps = _TreeSelect.Fetch.defaultProps = { - fieldName: 'treeSelect' -}; +_TreeSelect.Field = TreeSelect; _TreeSelect.TreeNode = TreeSelect.TreeNode; diff --git a/src/fields/Upload.js b/src/fields/Upload.js deleted file mode 100644 index d2f3d87..0000000 --- a/src/fields/Upload.js +++ /dev/null @@ -1,173 +0,0 @@ -import React, {useState, useMemo} from 'react'; -import {Upload, message, Button} from 'antd'; -import { - UploadOutlined -} from '@ant-design/icons'; -import {get, groupBy, uniqueId, omit} from 'lodash'; -import {hooks} from '@kne/react-form-helper'; -import {globalParams} from "../preset"; -import AvatarInput from "./Avatar.js"; - -const {useOnChange} = hooks; - -const {Dragger} = Upload; - -const uploadParams = globalParams.field.upload; - -const decodeURIComponentSafe = (str) => { - try { - return decodeURIComponent(str); - } catch (e) { - return str; - } -}; - -const computedFilename = (path, displayFilename = 'filename') => { - const strArray = path.split('?'); - if (strArray[1]) { - const query = {}; - strArray[1].split('&').forEach((str) => { - const [key, value] = str.split('='); - query[key] = value; - }); - if (query[displayFilename]) { - return decodeURIComponentSafe(query[displayFilename]); - } - } - return path; -}; - -const valueToList = (value, displayFilename) => { - if (!value) { - return []; - } - return value.map((item) => { - return { - uid: uniqueId(), - name: computedFilename(item.substr(item.lastIndexOf('/') + 1), displayFilename), - status: 'done', - response: {code: 200, results: item} - } - }); -}; - -const listToValue = (value) => { - return (value || []).slice(0).filter(({status}) => status === 'done').map(({response}) => response.results); -}; - -const _Upload = ({ - action, - value, - onChange, - drag, - children, - displayFilename, - accept, - fileSize: size, - onError, - onUploadComplete, - onBeforeUpload, - maxLength, - transformResponse, - ...props - }) => { - displayFilename = displayFilename || uploadParams.displayFilename; - value = value || []; - const [list, setList] = useState([]); - const valueList = useMemo(() => { - return valueToList(value.filter((url) => { - return !list.find((file) => decodeURIComponentSafe(get(file, 'response.results', '')) === decodeURIComponentSafe(url)); - }), displayFilename).concat(list); - }, [list, value, displayFilename]); - const changeHandler = (info) => { - if (['uploading', 'done', 'error', 'removed'].indexOf(info.file.status) === -1) { - return; - } - if (info.fileList?.length > maxLength) { - if (JSON.stringify(info.file) === JSON.stringify(info.fileList[info.fileList?.length - 1])) { - onError(`上传文件不能超过最大允许数量${maxLength}`, 'lengthError', maxLength); - } - return; - } - if (info.file.status === 'done' && info.fileList.find(({uid}) => uid === info.file.uid)) { - info.file.response = (transformResponse || uploadParams.transformResponse)(info.file.response); - if (info.file.response.code === 200) { - info.file.name = computedFilename(info.file.response.results.substr(info.file.response.results.lastIndexOf('/') + 1), displayFilename); - onUploadComplete(info); - } else { - info.file.status = 'error'; - onError(info.file.response.msg, 'xhrError', info.file.response); - } - } - const {done} = groupBy(info.fileList, (file) => file.status === 'done' ? 'done' : 'uploading'); - if (['done', 'removed'].indexOf(info.file.status) > -1) { - onChange(listToValue(done)); - } - setList((list) => { - const newList = list.slice(0); - const index = list.findIndex(({uid}) => uid === info.file.uid); - if (info.file.status === 'removed') { - index > -1 && newList.splice(index, 1); - return newList; - } - if (index === -1) { - newList.push(info.file); - return newList; - } - newList.splice(index, 1, info.file); - return newList; - }); - }; - const beforeUploadHandler = (file) => { - const isLt = file.size / 1024 / 1024 < size; - if (!isLt) { - onError(`文件不能超过${size}MB!`, 'sizeError', {size, fileSize: file.size}); - return false; - } - if (maxLength === 1) { - onChange([]); - setList([]); - } - return onBeforeUpload && onBeforeUpload(file); - }; - - const headers = Object.assign({}, uploadParams.headers); - - if (typeof uploadParams.getHeaders === 'function') { - Object.assign(headers, uploadParams.getHeaders()) - } - - const UploadComponent = drag ? Dragger : Upload; - return - {typeof children === 'function' ? children({size: props.size}) : children} - -}; - -_Upload.defaultProps = { - value: [], - accept: [], - fileSize: 2, - maxLength: 1, - children: ({size}) => , - onError: (info) => message.error(info), - onUploadComplete: () => { - } -}; - -const UploadInput = (props) => { - const render = useOnChange(props); - return render(_Upload); -}; - -UploadInput.defaultProps = { - fieldName: 'upload' -}; - - -UploadInput.Field = AvatarInput.Field = _Upload; - -export default UploadInput; diff --git a/src/index.js b/src/index.js index 881a7e7..743e990 100644 --- a/src/index.js +++ b/src/index.js @@ -1,6 +1,4 @@ import Form from './Form'; - -import Upload from './fields/Upload'; import TreeSelect from './fields/TreeSelect'; import TimePicker from './fields/TimePicker'; import TextArea from './fields/TextArea'; @@ -14,7 +12,6 @@ import DatePicker from './fields/DatePicker'; import CheckboxGroup from './fields/CheckboxGroup'; import Checkbox from './fields/Checkbox'; import Cascader from './fields/Cascader'; -import Avatar from './fields/Avatar'; import Rate from './fields/Rate'; import Slider from './fields/Slider'; @@ -26,7 +23,6 @@ export {default as ResetButton} from './ResetButton'; export {default as SubmitButton} from './SubmitButton'; export {default as CancelButton} from './CancelButton'; export { - Upload, TreeSelect, TimePicker, TextArea, @@ -40,13 +36,11 @@ export { CheckboxGroup, Checkbox, Cascader, - Avatar, Rate, Slider }; export const fields = { - Upload, TreeSelect, TimePicker, TextArea, @@ -60,7 +54,6 @@ export const fields = { CheckboxGroup, Checkbox, Cascader, - Avatar, Rate, Slider }; diff --git a/src/preset.js b/src/preset.js index 88a54ee..3b56f27 100644 --- a/src/preset.js +++ b/src/preset.js @@ -1,27 +1,9 @@ import {preset as presetRules} from '@kne/react-form'; -import {merge, get} from 'lodash'; +import merge from 'lodash/merge'; import {preset as formHelperPreset} from '@kne/react-form-helper'; export const globalParams = { - type: 'default', size: 'middle', rules: {}, formModal: {}, resetButton: {}, submitButton: {}, field: { - upload: { - displayFilename: 'filename', action: '/upload', transformResponse: (response) => { - const targetPath = get(response, 'results[0].targetPath'); - const filename = get(response, 'results[0].filename'); - return { - code: response.code, - msg: response.msg, - results: targetPath + (filename ? `?${globalParams.field.upload.displayFilename}=` + encodeURIComponent(filename) : '') - }; - } - }, avatar: { - transformResponse: (response) => { - return { - code: response.code, results: response.results, msg: response.msg - } - }, action: '/upload' - } - } + type: 'default', size: 'middle', rules: {}, formModal: {}, resetButton: {}, submitButton: {}, field: {} }; export default (props) => {