@jswork/react-ant-resource-form 1.0.17 → 1.0.19

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.
package/dist/main.cjs.js CHANGED
@@ -1,4 +1,2 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }var b=Object.defineProperty;var S=Object.getOwnPropertySymbols;var g=Object.prototype.hasOwnProperty,E=Object.prototype.propertyIsEnumerable;var y=(i,a,e)=>a in i?b(i,a,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[a]=e,l=(i,a)=>{for(var e in a||(a={}))g.call(a,e)&&y(i,e,a[e]);if(S)for(var e of S(a))E.call(a,e)&&y(i,e,a[e]);return i};var f=(i,a)=>b(i,"name",{value:a,configurable:!0});var w=(i,a)=>{var e={};for(var t in i)g.call(i,t)&&a.indexOf(t)<0&&(e[t]=i[t]);if(i!=null&&S)for(var t of S(i))a.indexOf(t)<0&&E.call(i,t)&&(e[t]=i[t]);return e};var h=(i,a,e)=>y(i,typeof a!="symbol"?a+"":a,e);var _classnames = require('classnames'); var _classnames2 = _interopRequireDefault(_classnames);var _react = require('react'); var _react2 = _interopRequireDefault(_react);var _antd = require('antd');var _reactantformschema = require('@jswork/react-ant-form-schema'); var _reactantformschema2 = _interopRequireDefault(_reactantformschema);var _icons = require('@ant-design/icons');var x={"zh-CN":{create:"\u521B\u5EFA",update:"\u4FDD\u5B58",create_title:"\u521B\u5EFA",update_title:"\u66F4\u65B0",create_success:"\u521B\u5EFA\u6210\u529F",update_success:"\u66F4\u65B0\u6210\u529F",submit:"\u63D0\u4EA4",back:"\u8FD4\u56DE"},"en-US":{create:"Create",update:"Save",create_title:"Create",update_title:"Update",create_success:"Create success",update_success:"Update success",submit:"Submit",back:"Back"}};var _next = require('@jswork/next'); var _next2 = _interopRequireDefault(_next);var v="react-ant-resource-form",p,B=(p=class extends _react.Component{constructor(e){super(e);h(this,"formRef",_react2.default.createRef());h(this,"_isMounted",!1);h(this,"handleBack",f(()=>{history.back()},"handleBack"));h(this,"handleFinish",f(e=>{let{params:t,name:s}=this.props,n=`${s}_update`,r=`${s}_create`;if(this.isEdit){let o=l({id:t.id},e),u=this.handleStateRequest({stage:"update",payload:o});_next2.default.$api[n](u).then(d=>{_antd.message.success(this.t("update_success")),this.handleStateResponse({stage:"update",data:d})}).finally(()=>this.setState({loading:!1}))}else{let o=l({},e),u=this.handleStateRequest({stage:"create",payload:o});_next2.default.$api[r](u).then(d=>{var m;_antd.message.success(this.t("create_success")),this.handleStateResponse({stage:"create",data:d}),(m=this.formInstance)==null||m.resetFields(),history.back()}).finally(()=>this.setState({loading:!1}))}},"handleFinish"));h(this,"handleKeydown",f(e=>{var s;if((e.ctrlKey||e.metaKey)&&(e.key==="s"||e.key==="S")&&(e.preventDefault(),!this.props.disableHotkeySave))try{(s=this.formInstance)==null||s.submit()}catch(n){}},"handleKeydown"));this.state={loading:!1},this.handleStateRequest=this.handleStateRequest.bind(this),this.handleStateResponse=this.handleStateResponse.bind(this),this.initDetailIfNeeded=this.initDetailIfNeeded.bind(this)}get isEdit(){let{params:e}=this.props;return!!(e!=null&&e.id)}get titleView(){let{title:e}=this.props;return e||(this.isEdit?this.t("update_title"):this.t("create_title"))}get extraView(){let{extra:e,backText:t,backProps:s}=this.props;return e||_react2.default.createElement(_antd.Button,l({size:"small",icon:_react2.default.createElement(_icons.ArrowLeftOutlined,null),onClick:this.handleBack},s),t||this.t("back"))}get childrenView(){let{okText:e,backText:t,okProps:s,backProps:n,children:r}=this.props,o=e||(this.isEdit?this.t("update"):this.t("create"));return r||_react2.default.createElement(_antd.Space,null,_react2.default.createElement(_antd.Button,l({htmlType:"submit",type:"primary",icon:_react2.default.createElement(_icons.SaveOutlined,null)},s),o||this.t("submit")),_react2.default.createElement(_antd.Button,l({icon:_react2.default.createElement(_icons.ArrowLeftOutlined,null),onClick:this.handleBack},n),t||this.t("back")))}get formInstance(){var e;return(e=this.formRef)==null?void 0:e.current}t(e){let{lang:t}=this.props;return x[t][e]}handleStateRequest(e){var t,s;return this.setState({loading:!0}),((s=(t=this.props).transformRequest)==null?void 0:s.call(t,e))||e.payload}handleStateResponse(e){var s,n,r,o;let{name:t}=this.props;return this.setState({loading:!1}),(n=(s=_next2.default.$event)==null?void 0:s.emit)==null||n.call(s,`${t}:refetch`),((o=(r=this.props).transformResponse)==null?void 0:o.call(r,e))||e.data}componentDidMount(){this._isMounted=!0,window.addEventListener("keydown",this.handleKeydown),this.initDetailIfNeeded()}componentDidUpdate(e){var n,r;let t=(n=e.params)==null?void 0:n.id,s=(r=this.props.params)==null?void 0:r.id;t!==s&&this.initDetailIfNeeded()}componentWillUnmount(){window.removeEventListener("keydown",this.handleKeydown),this._isMounted=!1}initDetailIfNeeded(){let{params:e,name:t}=this.props,s=`${t}_show`;if(this.isEdit){let n={id:e.id},r=this.handleStateRequest({stage:"show",payload:n});_next2.default.$api[s](r).then(o=>{var d,m;if(!this._isMounted)return;let u=this.handleStateResponse({stage:"show",data:o});try{(m=(d=this.formInstance)==null?void 0:d.setFieldsValue)==null||m.call(d,u)}catch(A){}}).finally(()=>this.setState({loading:!1}))}}render(){let _=this.props,{className:e,name:t,meta:s,children:n,lang:r,title:o,extra:u,size:d,okText:m,backText:A,okProps:O,backProps:z,classNames:F,params:K,transformRequest:U,transformResponse:H,disableHotkeySave:W}=_,q=w(_,["className","name","meta","children","lang","title","extra","size","okText","backText","okProps","backProps","classNames","params","transformRequest","transformResponse","disableHotkeySave"]);return _react2.default.createElement(_antd.Card,{title:this.titleView,extra:this.extraView,size:d,classNames:F,"data-component":v,className:_classnames2.default.call(void 0, v,e)},_react2.default.createElement(_antd.Spin,{spinning:this.state.loading},_react2.default.createElement(_reactantformschema2.default,l({meta:s,ref:this.formRef,onFinish:this.handleFinish},q),this.childrenView)))}},f(p,"ReactAntResourceForm"),h(p,"defaultProps",{lang:"zh-CN",disableHotkeySave:!1}),p),N=B;var ne=N;exports.default = ne;
2
-
3
- module.exports = exports.default;
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }var E=Object.defineProperty;var S=Object.getOwnPropertySymbols;var b=Object.prototype.hasOwnProperty,w=Object.prototype.propertyIsEnumerable;var R=(a,s,e)=>s in a?E(a,s,{enumerable:!0,configurable:!0,writable:!0,value:e}):a[s]=e,m=(a,s)=>{for(var e in s||(s={}))b.call(s,e)&&R(a,e,s[e]);if(S)for(var e of S(s))w.call(s,e)&&R(a,e,s[e]);return a};var p=(a,s)=>E(a,"name",{value:s,configurable:!0});var V=(a,s)=>{var e={};for(var t in a)b.call(a,t)&&s.indexOf(t)<0&&(e[t]=a[t]);if(a!=null&&S)for(var t of S(a))s.indexOf(t)<0&&w.call(a,t)&&(e[t]=a[t]);return e};var d=(a,s,e)=>R(a,typeof s!="symbol"?s+"":s,e);var _classnames = require('classnames'); var _classnames2 = _interopRequireDefault(_classnames);var _react = require('react'); var _react2 = _interopRequireDefault(_react);var _antd = require('antd');var _reactantformschema = require('@jswork/react-ant-form-schema'); var _reactantformschema2 = _interopRequireDefault(_reactantformschema);var _icons = require('@ant-design/icons');var x={"zh-CN":{create:"\u521B\u5EFA",update:"\u4FDD\u5B58",create_title:"\u521B\u5EFA",update_title:"\u66F4\u65B0",create_success:"\u521B\u5EFA\u6210\u529F",update_success:"\u66F4\u65B0\u6210\u529F",submit:"\u63D0\u4EA4",back:"\u8FD4\u56DE"},"en-US":{create:"Create",update:"Save",create_title:"Create",update_title:"Update",create_success:"Create success",update_success:"Update success",submit:"Submit",back:"Back"}};var _next = require('@jswork/next'); var _next2 = _interopRequireDefault(_next);var _reactrouterdom = require('react-router-dom');var _fastdeepequal = require('fast-deep-equal'); var _fastdeepequal2 = _interopRequireDefault(_fastdeepequal);var v="react-ant-resource-form",f,A=(f=class extends _react.Component{constructor(e){var t;super(e);d(this,"formRef",_react2.default.createRef());d(this,"_isMounted",!1);d(this,"_initialValues",null);d(this,"handleBack",p(()=>{history.back()},"handleBack"));d(this,"handleFinish",p(e=>{let{params:t,name:i}=this.props,n=`${i}_update`,o=`${i}_create`;if(this.isEdit){let l=m({id:t.id},e),h=this.handleStateRequest({stage:"update",payload:l});_next2.default.$api[n](h).then(c=>{_antd.message.success(this.t("update_success")),this.handleStateResponse({stage:"update",data:c})}).finally(()=>{var c;this.setState({loading:!1}),this._initialValues=((c=this.formInstance)==null?void 0:c.getFieldsValue())||{},this.handleValuesChange(null,this._initialValues)})}else{let l=m({},e),h=this.handleStateRequest({stage:"create",payload:l});_next2.default.$api[o](h).then(c=>{var u;_antd.message.success(this.t("create_success")),this.handleStateResponse({stage:"create",data:c}),(u=this.formInstance)==null||u.resetFields(),history.back()}).finally(()=>this.setState({loading:!1}))}},"handleFinish"));d(this,"handleKeydown",p(e=>{var n;let{disableHotkeySave:t}=this.props;if((e.ctrlKey||e.metaKey)&&(e.key==="s"||e.key==="S")&&(e.preventDefault(),!t))try{(n=this.formInstance)==null||n.submit()}catch(o){}},"handleKeydown"));d(this,"handleValuesChange",p((e,t)=>{this.setState({touched:_fastdeepequal2.default.call(void 0, this._initialValues,t)===!1})},"handleValuesChange"));this.state={loading:!1,touched:!1},this.handleStateRequest=this.handleStateRequest.bind(this),this.handleStateResponse=this.handleStateResponse.bind(this),this.initDetailIfNeeded=this.initDetailIfNeeded.bind(this),(t=e.onInit)==null||t.call(e,this)}get isEdit(){let{params:e}=this.props;return!!(e!=null&&e.id)}get canSave(){let{touched:e,loading:t}=this.state;return this.isEdit?e===!0&&t===!1:t===!1}get titleView(){let{title:e}=this.props,t=e||(this.isEdit?this.t("update_title"):this.t("create_title"));return _react2.default.createElement(_antd.Space,null,t,_react2.default.createElement("span",null,this.touchedView))}get touchedView(){return this.isEdit&&this.state.touched?_react2.default.createElement("em",{style:{color:"#f60"}},_react2.default.createElement(_icons.DiffOutlined,null)):null}get extraView(){let{extra:e,backText:t,backProps:i}=this.props;return e||_react2.default.createElement(_antd.Button,m({size:"small",icon:_react2.default.createElement(_icons.ArrowLeftOutlined,null),onClick:this.handleBack},i),t||this.t("back"))}get childrenView(){let{okText:e,backText:t,okProps:i,backProps:n,children:o}=this.props,l=e||(this.isEdit?this.t("update"):this.t("create"));return o||_react2.default.createElement(_antd.Space,null,_react2.default.createElement(_antd.Button,m({disabled:!this.canSave,htmlType:"submit",type:"primary",icon:_react2.default.createElement(_icons.SaveOutlined,null)},i),l||this.t("submit")),_react2.default.createElement(_antd.Button,m({icon:_react2.default.createElement(_icons.ArrowLeftOutlined,null),onClick:this.handleBack},n),t||this.t("back")))}get formInstance(){var e;return(e=this.formRef)==null?void 0:e.current}t(e){let{lang:t}=this.props;return x[t][e]}handleStateRequest(e){var t,i;return this.setState({loading:!0}),((i=(t=this.props).transformRequest)==null?void 0:i.call(t,e))||e.payload}handleStateResponse(e){var i,n,o,l;let{name:t}=this.props;return this.setState({loading:!1}),(n=(i=_next2.default.$event)==null?void 0:i.emit)==null||n.call(i,`${t}:refetch`),((l=(o=this.props).transformResponse)==null?void 0:l.call(o,e))||e.data}componentDidMount(){this._isMounted=!0,window.addEventListener("keydown",this.handleKeydown),this.initDetailIfNeeded()}componentDidUpdate(e){var n,o;let t=(n=e.params)==null?void 0:n.id,i=(o=this.props.params)==null?void 0:o.id;t!==i&&this.initDetailIfNeeded()}componentWillUnmount(){window.removeEventListener("keydown",this.handleKeydown),this._isMounted=!1}initDetailIfNeeded(){var n;let{params:e,name:t}=this.props,i=`${t}_show`;if(this.isEdit){let o={id:e.id},l=this.handleStateRequest({stage:"show",payload:o});_next2.default.$api[i](l).then(h=>{var u,g;if(!this._isMounted)return;let c=this.handleStateResponse({stage:"show",data:h});try{(g=(u=this.formInstance)==null?void 0:u.setFieldsValue)==null||g.call(u,c)}catch(D){}}).finally(()=>{var h;this.setState({loading:!1}),this._initialValues=((h=this.formInstance)==null?void 0:h.getFieldsValue())||{}})}else this._initialValues=((n=this.formInstance)==null?void 0:n.getFieldsValue())||{}}render(){let y=this.props,{className:e,name:t,meta:i,children:n,lang:o,title:l,extra:h,size:c,okText:u,backText:g,okProps:D,backProps:W,classNames:q,params:j,transformRequest:G,transformResponse:J,disableHotkeySave:Q,onInit:X}=y,L=V(y,["className","name","meta","children","lang","title","extra","size","okText","backText","okProps","backProps","classNames","params","transformRequest","transformResponse","disableHotkeySave","onInit"]);return _react2.default.createElement(_antd.Card,{title:this.titleView,extra:this.extraView,size:c,classNames:q,"data-component":v,className:_classnames2.default.call(void 0, v,e)},_react2.default.createElement(_antd.Spin,{spinning:this.state.loading},_react2.default.createElement(_reactantformschema2.default,m({meta:i,ref:this.formRef,onValuesChange:this.handleValuesChange,onFinish:this.handleFinish},L),this.childrenView)))}},p(f,"ReactAntResourceForm"),d(f,"defaultProps",{lang:"zh-CN",disableHotkeySave:!1}),f),H= exports.ReactAntResourceFormFc =p(a=>{let s=_reactrouterdom.useParams.call(void 0, );return _react2.default.createElement(A,m({params:s},a))},"ReactAntResourceFormFc"),N=A;var ue=N;exports.ReactAntResourceFormFc = H; exports.default = ue;
4
2
  //# sourceMappingURL=main.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/ap7/github/react-ant-resource-form/packages/lib/dist/main.cjs.js","../src/index.tsx","../src/locales.ts"],"names":["API_FORM_LOCALES","create","update","create_title","update_title","create_success","update_success","submit","back","CLASS_NAME","_a","ReactAntResourceForm","Component","props","formRef","React","createRef","_isMounted","handleBack","__name","history","handleFinish","values","params","name","resourceEdit"],"mappings":"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","file":"/Users/ap7/github/react-ant-resource-form/packages/lib/dist/main.cjs.js","sourcesContent":[null,"// import noop from '@jswork/noop';\nimport cx from 'classnames';\nimport React, { Component } from 'react';\nimport { Button, ButtonProps, Card, CardProps, Space, message, Spin } from 'antd';\nimport type { FormInstance } from 'antd';\nimport ReactAntdFormSchema, { ReactAntdFormSchemaProps } from '@jswork/react-ant-form-schema';\nimport { ArrowLeftOutlined, SaveOutlined } from '@ant-design/icons';\nimport { API_FORM_LOCALES } from './locales';\nimport nx from '@jswork/next';\n\ndeclare global {\n interface NxStatic {\n $api: Record<string, any>;\n $event: any;\n }\n}\n\ntype StagePayload = {\n stage: 'show' | 'create' | 'update';\n payload: any;\n};\n\ntype StageData = {\n stage: 'show' | 'create' | 'update';\n data: any;\n};\n\nexport type ReactAntResourceFormProps = {\n lang?: string;\n loading?: boolean;\n okText?: string;\n backText?: string;\n params?: Record<string, any>;\n disableHotkeySave?: boolean;\n transformRequest?: (payload: StagePayload) => any;\n transformResponse?: (res: StageData) => any;\n okProps?: ButtonProps;\n backProps?: ButtonProps;\n classNames?: CardProps['classNames'];\n size?: CardProps['size'];\n extra?: CardProps['extra'];\n title?: CardProps['title'];\n} & ReactAntdFormSchemaProps;\n\ntype IState = {\n loading: boolean;\n};\n\nconst CLASS_NAME = 'react-ant-resource-form';\n\n/**\n * 当前 card loading 不要直接使用,因为这个 loading 会导致 Card 里的 formRef 被设置成 null\n * 这个情况仅在 class component 里才会出现,function component 里不会:\n * 报错示例:\n *\n * this.formRef?: null\n * index.tsx:229 this.formRef?: {getFieldValue: ƒ, getFieldsValue: ƒ, getFieldError: ƒ, getFieldWarning: ƒ, getFieldsError: ƒ, …}\n * index.tsx:229 this.formRef?: null\n */\n\nclass ReactAntResourceForm extends Component<ReactAntResourceFormProps, IState> {\n public static defaultProps = {\n lang: 'zh-CN',\n disableHotkeySave: false,\n };\n\n private formRef = React.createRef<FormInstance>(); // 注意类型\n private _isMounted = false;\n\n get isEdit() {\n const { params } = this.props;\n return Boolean(params?.id);\n }\n\n get titleView() {\n const { title } = this.props;\n return title || (this.isEdit ? this.t('update_title') : this.t('create_title'));\n }\n\n get extraView() {\n const { extra, backText, backProps } = this.props;\n if (extra) return extra;\n return (\n <Button size=\"small\" icon={<ArrowLeftOutlined />} onClick={this.handleBack} {...backProps}>\n {backText || this.t('back')}\n </Button>\n );\n }\n\n get childrenView() {\n const { okText, backText, okProps, backProps, children } = this.props;\n const _okText = okText || (this.isEdit ? this.t('update') : this.t('create'));\n if (children) return children;\n\n return (\n <Space>\n <Button htmlType=\"submit\" type=\"primary\" icon={<SaveOutlined />} {...okProps}>\n {_okText || this.t('submit')}\n </Button>\n <Button icon={<ArrowLeftOutlined />} onClick={this.handleBack} {...backProps}>\n {backText || this.t('back')}\n </Button>\n </Space>\n );\n }\n\n get formInstance() {\n return this.formRef?.current;\n }\n\n constructor(props: ReactAntResourceFormProps) {\n super(props);\n this.state = {\n loading: false,\n };\n\n this.handleStateRequest = this.handleStateRequest.bind(this);\n this.handleStateResponse = this.handleStateResponse.bind(this);\n this.initDetailIfNeeded = this.initDetailIfNeeded.bind(this);\n }\n\n private t(key: string) {\n const { lang } = this.props;\n return API_FORM_LOCALES[lang!][key];\n }\n\n private handleBack = () => {\n history.back();\n };\n\n handleStateRequest(stagePayload: StagePayload) {\n this.setState({ loading: true });\n return this.props.transformRequest?.(stagePayload) || stagePayload.payload;\n }\n\n handleStateResponse(res: StageData) {\n const { name } = this.props;\n this.setState({ loading: false });\n nx.$event?.emit?.(`${name}:refetch`);\n return this.props.transformResponse?.(res) || res.data;\n }\n\n handleFinish = (values: any) => {\n const { params, name } = this.props;\n const resourceEdit = `${name}_update`;\n const resourceCreate = `${name}_create`;\n\n if (this.isEdit) {\n const payload = { id: params!.id, ...values };\n const _payload = this.handleStateRequest({ stage: 'update', payload });\n\n nx.$api[resourceEdit](_payload)\n .then((res: any) => {\n message.success(this.t('update_success'));\n this.handleStateResponse({ stage: 'update', data: res });\n })\n .finally(() => this.setState({ loading: false }));\n } else {\n const payload = { ...values };\n const _payload = this.handleStateRequest({ stage: 'create', payload });\n\n nx.$api[resourceCreate](_payload)\n .then((res: any) => {\n message.success(this.t('create_success'));\n this.handleStateResponse({ stage: 'create', data: res });\n this.formInstance?.resetFields();\n history.back();\n })\n .finally(() => this.setState({ loading: false }));\n }\n };\n\n // hotkey save handler (replaces useKeyboardSave hook)\n handleKeydown = (e: KeyboardEvent) => {\n const isSave = (e.ctrlKey || e.metaKey) && (e.key === 's' || e.key === 'S');\n if (isSave) {\n e.preventDefault();\n if (!this.props.disableHotkeySave) {\n // submit the form via ref\n try {\n this.formInstance?.submit();\n } catch (err) {\n // ignore if submit not available yet\n }\n }\n }\n };\n\n componentDidMount() {\n this._isMounted = true;\n // attach hotkey listener\n window.addEventListener('keydown', this.handleKeydown);\n // initialize detail if editing\n this.initDetailIfNeeded();\n }\n\n componentDidUpdate(prevProps: ReactAntResourceFormProps) {\n const prevId = prevProps.params?.id;\n const curId = this.props.params?.id;\n // re-init when id changed or from create -> edit\n if (prevId !== curId) {\n this.initDetailIfNeeded();\n }\n }\n\n componentWillUnmount() {\n window.removeEventListener('keydown', this.handleKeydown);\n this._isMounted = false;\n }\n\n initDetailIfNeeded() {\n const { params, name } = this.props;\n const resourceShow = `${name}_show`;\n\n if (this.isEdit) {\n const payload = { id: params!.id };\n const _payload = this.handleStateRequest({ stage: 'show', payload });\n\n nx.$api[resourceShow](_payload)\n .then((res: any) => {\n if (!this._isMounted) return; // 👈 关键:防止操作已卸载组件\n const data = this.handleStateResponse({ stage: 'show', data: res });\n // set fields value on the form via ref\n try {\n this.formInstance?.setFieldsValue?.(data);\n } catch (err) {\n // ignore if not available yet\n }\n })\n .finally(() => this.setState({ loading: false }));\n }\n }\n\n render() {\n const {\n className,\n name,\n meta,\n children,\n lang,\n title,\n extra,\n size,\n okText,\n backText,\n okProps,\n backProps,\n classNames,\n params,\n transformRequest,\n transformResponse,\n disableHotkeySave,\n ...rest\n } = this.props;\n\n return (\n <Card\n title={this.titleView}\n extra={this.extraView}\n size={size}\n classNames={classNames}\n data-component={CLASS_NAME}\n className={cx(CLASS_NAME, className)}>\n <Spin spinning={this.state.loading}>\n <ReactAntdFormSchema\n meta={meta}\n ref={this.formRef}\n onFinish={this.handleFinish}\n {...rest}>\n {this.childrenView}\n </ReactAntdFormSchema>\n </Spin>\n </Card>\n );\n }\n}\n\nexport default ReactAntResourceForm;\n","export const API_FORM_LOCALES = {\n 'zh-CN': {\n create: '创建',\n update: '保存',\n create_title: '创建',\n update_title: '更新',\n create_success: '创建成功',\n update_success: '更新成功',\n submit: '提交',\n back: '返回',\n },\n 'en-US': {\n create: 'Create',\n update: 'Save',\n create_title: 'Create',\n update_title: 'Update',\n create_success: 'Create success',\n update_success: 'Update success',\n submit: 'Submit',\n back: 'Back',\n },\n};\n"]}
1
+ {"version":3,"sources":["/Users/ap7/github/react-ant-resource-form/packages/lib/dist/main.cjs.js","../src/index.tsx","../src/locales.ts"],"names":["API_FORM_LOCALES","create","update","create_title","update_title","create_success","update_success","submit","back","CLASS_NAME","_a","ReactAntResourceForm","Component","props","formRef","React","createRef","_isMounted","_initialValues","handleBack","__name","history","handleFinish","values","params","name","resourceEdit"],"mappings":"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","file":"/Users/ap7/github/react-ant-resource-form/packages/lib/dist/main.cjs.js","sourcesContent":[null,"// import noop from '@jswork/noop';\nimport cx from 'classnames';\nimport React, { Component, FC } from 'react';\nimport { Button, ButtonProps, Card, CardProps, Space, message, Spin } from 'antd';\nimport type { FormInstance } from 'antd';\nimport ReactAntdFormSchema, { ReactAntdFormSchemaProps } from '@jswork/react-ant-form-schema';\nimport { ArrowLeftOutlined, DiffOutlined, SaveOutlined } from '@ant-design/icons';\nimport { API_FORM_LOCALES } from './locales';\nimport nx from '@jswork/next';\nimport { useParams } from 'react-router-dom';\nimport fde from 'fast-deep-equal';\n\ndeclare global {\n interface NxStatic {\n $api: Record<string, any>;\n $event: any;\n }\n}\n\ntype StagePayload = {\n stage: 'show' | 'create' | 'update';\n payload: any;\n};\n\ntype StageData = {\n stage: 'show' | 'create' | 'update';\n data: any;\n};\n\nexport type ReactAntResourceFormProps = {\n lang?: string;\n loading?: boolean;\n okText?: string;\n backText?: string;\n params?: Record<string, any>;\n disableHotkeySave?: boolean;\n transformRequest?: (payload: StagePayload) => any;\n transformResponse?: (res: StageData) => any;\n okProps?: ButtonProps;\n backProps?: ButtonProps;\n classNames?: CardProps['classNames'];\n size?: CardProps['size'];\n extra?: CardProps['extra'];\n title?: CardProps['title'];\n onInit?: (ctx: ReactAntResourceForm) => void;\n} & ReactAntdFormSchemaProps;\n\ntype IState = {\n loading: boolean;\n touched: boolean;\n};\n\nconst CLASS_NAME = 'react-ant-resource-form';\n\n/**\n * 当前 card loading 不要直接使用,因为这个 loading 会导致 Card 里的 formRef 被设置成 null\n * 这个情况仅在 class component 里才会出现,function component 里不会:\n * 报错示例:\n *\n * this.formRef?: null\n * index.tsx:229 this.formRef?: {getFieldValue: ƒ, getFieldsValue: ƒ, getFieldError: ƒ, getFieldWarning: ƒ, getFieldsError: ƒ, …}\n * index.tsx:229 this.formRef?: null\n */\n\nclass ReactAntResourceForm extends Component<ReactAntResourceFormProps, IState> {\n public static defaultProps = {\n lang: 'zh-CN',\n disableHotkeySave: false,\n };\n\n private formRef = React.createRef<FormInstance>(); // 注意类型\n private _isMounted = false;\n private _initialValues = null;\n\n get isEdit() {\n const { params } = this.props;\n return Boolean(params?.id);\n }\n\n get canSave() {\n const { touched, loading } = this.state;\n if (!this.isEdit) return loading === false;\n return touched === true && loading === false;\n }\n\n get titleView() {\n const { title } = this.props;\n const _title = title || (this.isEdit ? this.t('update_title') : this.t('create_title'));\n return (\n <Space>\n {_title}\n <span>{this.touchedView}</span>\n </Space>\n );\n }\n\n get touchedView() {\n if (!this.isEdit) return null;\n return this.state.touched ? (\n <em style={{ color: '#f60' }}>\n <DiffOutlined />\n </em>\n ) : null;\n }\n\n get extraView() {\n const { extra, backText, backProps } = this.props;\n if (extra) return extra;\n return (\n <Button size=\"small\" icon={<ArrowLeftOutlined />} onClick={this.handleBack} {...backProps}>\n {backText || this.t('back')}\n </Button>\n );\n }\n\n get childrenView() {\n const { okText, backText, okProps, backProps, children } = this.props;\n const _okText = okText || (this.isEdit ? this.t('update') : this.t('create'));\n if (children) return children;\n\n return (\n <Space>\n <Button\n disabled={!this.canSave}\n htmlType=\"submit\"\n type=\"primary\"\n icon={<SaveOutlined />}\n {...okProps}>\n {_okText || this.t('submit')}\n </Button>\n <Button icon={<ArrowLeftOutlined />} onClick={this.handleBack} {...backProps}>\n {backText || this.t('back')}\n </Button>\n </Space>\n );\n }\n\n get formInstance() {\n return this.formRef?.current;\n }\n\n constructor(props: ReactAntResourceFormProps) {\n super(props);\n this.state = {\n loading: false,\n touched: false,\n };\n\n this.handleStateRequest = this.handleStateRequest.bind(this);\n this.handleStateResponse = this.handleStateResponse.bind(this);\n this.initDetailIfNeeded = this.initDetailIfNeeded.bind(this);\n\n props.onInit?.(this);\n }\n\n private t(key: string) {\n const { lang } = this.props;\n return API_FORM_LOCALES[lang!][key];\n }\n\n private handleBack = () => {\n history.back();\n };\n\n handleStateRequest(stagePayload: StagePayload) {\n this.setState({ loading: true });\n return this.props.transformRequest?.(stagePayload) || stagePayload.payload;\n }\n\n handleStateResponse(res: StageData) {\n const { name } = this.props;\n this.setState({ loading: false });\n nx.$event?.emit?.(`${name}:refetch`);\n return this.props.transformResponse?.(res) || res.data;\n }\n\n handleFinish = (values: any) => {\n const { params, name } = this.props;\n const resourceEdit = `${name}_update`;\n const resourceCreate = `${name}_create`;\n\n if (this.isEdit) {\n const payload = { id: params!.id, ...values };\n const _payload = this.handleStateRequest({ stage: 'update', payload });\n\n nx.$api[resourceEdit](_payload)\n .then((res: any) => {\n message.success(this.t('update_success'));\n this.handleStateResponse({ stage: 'update', data: res });\n })\n .finally(() => {\n this.setState({ loading: false });\n this._initialValues = this.formInstance?.getFieldsValue() || {};\n this.handleValuesChange(null, this._initialValues);\n });\n } else {\n const payload = { ...values };\n const _payload = this.handleStateRequest({ stage: 'create', payload });\n\n nx.$api[resourceCreate](_payload)\n .then((res: any) => {\n message.success(this.t('create_success'));\n this.handleStateResponse({ stage: 'create', data: res });\n this.formInstance?.resetFields();\n history.back();\n })\n .finally(() => this.setState({ loading: false }));\n }\n };\n\n // hotkey save handler (replaces useKeyboardSave hook)\n handleKeydown = (e: KeyboardEvent) => {\n const { disableHotkeySave } = this.props;\n const isSave = (e.ctrlKey || e.metaKey) && (e.key === 's' || e.key === 'S');\n if (isSave) {\n e.preventDefault();\n if (!disableHotkeySave) {\n // submit the form via ref\n try {\n this.formInstance?.submit();\n } catch (err) {\n // ignore if submit not available yet\n }\n }\n }\n };\n\n handleValuesChange = (_: any, allValues: any) => {\n this.setState({\n touched: fde(this._initialValues, allValues) === false,\n });\n };\n\n componentDidMount() {\n this._isMounted = true;\n // attach hotkey listener\n window.addEventListener('keydown', this.handleKeydown);\n // initialize detail if editing\n this.initDetailIfNeeded();\n }\n\n componentDidUpdate(prevProps: ReactAntResourceFormProps) {\n const prevId = prevProps.params?.id;\n const curId = this.props.params?.id;\n // re-init when id changed or from create -> edit\n if (prevId !== curId) {\n this.initDetailIfNeeded();\n }\n }\n\n componentWillUnmount() {\n window.removeEventListener('keydown', this.handleKeydown);\n this._isMounted = false;\n }\n\n initDetailIfNeeded() {\n const { params, name } = this.props;\n const resourceShow = `${name}_show`;\n\n if (this.isEdit) {\n const payload = { id: params!.id };\n const _payload = this.handleStateRequest({ stage: 'show', payload });\n\n nx.$api[resourceShow](_payload)\n .then((res: any) => {\n if (!this._isMounted) return; // 👈 关键:防止操作已卸载组件\n const data = this.handleStateResponse({ stage: 'show', data: res });\n // set fields value on the form via ref\n try {\n this.formInstance?.setFieldsValue?.(data);\n } catch (err) {\n // ignore if not available yet\n }\n })\n .finally(() => {\n this.setState({ loading: false });\n this._initialValues = this.formInstance?.getFieldsValue() || {};\n });\n } else {\n this._initialValues = this.formInstance?.getFieldsValue() || {};\n }\n }\n\n render() {\n const {\n className,\n name,\n meta,\n children,\n lang,\n title,\n extra,\n size,\n okText,\n backText,\n okProps,\n backProps,\n classNames,\n params,\n transformRequest,\n transformResponse,\n disableHotkeySave,\n onInit,\n ...rest\n } = this.props;\n\n return (\n <Card\n title={this.titleView}\n extra={this.extraView}\n size={size}\n classNames={classNames}\n data-component={CLASS_NAME}\n className={cx(CLASS_NAME, className)}>\n <Spin spinning={this.state.loading}>\n <ReactAntdFormSchema\n meta={meta}\n ref={this.formRef}\n onValuesChange={this.handleValuesChange}\n onFinish={this.handleFinish}\n {...rest}>\n {this.childrenView}\n </ReactAntdFormSchema>\n </Spin>\n </Card>\n );\n }\n}\n\nconst ReactAntResourceFormFc: FC<ReactAntResourceFormProps> = (props) => {\n const params = useParams();\n return <ReactAntResourceForm params={params} {...props} />;\n};\n\nexport default ReactAntResourceForm;\nexport { ReactAntResourceFormFc };\n","export const API_FORM_LOCALES = {\n 'zh-CN': {\n create: '创建',\n update: '保存',\n create_title: '创建',\n update_title: '更新',\n create_success: '创建成功',\n update_success: '更新成功',\n submit: '提交',\n back: '返回',\n },\n 'en-US': {\n create: 'Create',\n update: 'Save',\n create_title: 'Create',\n update_title: 'Update',\n create_success: 'Create success',\n update_success: 'Update success',\n submit: 'Submit',\n back: 'Back',\n },\n};\n"]}
package/dist/main.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as rc_field_form_lib_interface from 'rc-field-form/lib/interface';
2
- import React, { Component } from 'react';
2
+ import React, { Component, FC } from 'react';
3
3
  import { ButtonProps, CardProps, FormInstance } from 'antd';
4
4
  import { ReactAntdFormSchemaProps } from '@jswork/react-ant-form-schema';
5
5
 
@@ -32,9 +32,11 @@ type ReactAntResourceFormProps = {
32
32
  size?: CardProps['size'];
33
33
  extra?: CardProps['extra'];
34
34
  title?: CardProps['title'];
35
+ onInit?: (ctx: ReactAntResourceForm) => void;
35
36
  } & ReactAntdFormSchemaProps;
36
37
  type IState = {
37
38
  loading: boolean;
39
+ touched: boolean;
38
40
  };
39
41
  /**
40
42
  * 当前 card loading 不要直接使用,因为这个 loading 会导致 Card 里的 formRef 被设置成 null
@@ -52,8 +54,11 @@ declare class ReactAntResourceForm extends Component<ReactAntResourceFormProps,
52
54
  };
53
55
  private formRef;
54
56
  private _isMounted;
57
+ private _initialValues;
55
58
  get isEdit(): boolean;
56
- get titleView(): any;
59
+ get canSave(): boolean;
60
+ get titleView(): React.JSX.Element;
61
+ get touchedView(): React.JSX.Element | null;
57
62
  get extraView(): string | number | true | Iterable<React.ReactNode> | React.JSX.Element;
58
63
  get childrenView(): string | number | true | Iterable<React.ReactNode> | React.JSX.Element | ((values: rc_field_form_lib_interface.Store, form: rc_field_form_lib_interface.FormInstance) => JSX.Element | React.ReactNode);
59
64
  get formInstance(): FormInstance<any> | null;
@@ -64,11 +69,13 @@ declare class ReactAntResourceForm extends Component<ReactAntResourceFormProps,
64
69
  handleStateResponse(res: StageData): any;
65
70
  handleFinish: (values: any) => void;
66
71
  handleKeydown: (e: KeyboardEvent) => void;
72
+ handleValuesChange: (_: any, allValues: any) => void;
67
73
  componentDidMount(): void;
68
74
  componentDidUpdate(prevProps: ReactAntResourceFormProps): void;
69
75
  componentWillUnmount(): void;
70
76
  initDetailIfNeeded(): void;
71
77
  render(): React.JSX.Element;
72
78
  }
79
+ declare const ReactAntResourceFormFc: FC<ReactAntResourceFormProps>;
73
80
 
74
- export { type ReactAntResourceFormProps, ReactAntResourceForm as default };
81
+ export { ReactAntResourceFormFc, type ReactAntResourceFormProps, ReactAntResourceForm as default };
package/dist/main.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as rc_field_form_lib_interface from 'rc-field-form/lib/interface';
2
- import React, { Component } from 'react';
2
+ import React, { Component, FC } from 'react';
3
3
  import { ButtonProps, CardProps, FormInstance } from 'antd';
4
4
  import { ReactAntdFormSchemaProps } from '@jswork/react-ant-form-schema';
5
5
 
@@ -32,9 +32,11 @@ type ReactAntResourceFormProps = {
32
32
  size?: CardProps['size'];
33
33
  extra?: CardProps['extra'];
34
34
  title?: CardProps['title'];
35
+ onInit?: (ctx: ReactAntResourceForm) => void;
35
36
  } & ReactAntdFormSchemaProps;
36
37
  type IState = {
37
38
  loading: boolean;
39
+ touched: boolean;
38
40
  };
39
41
  /**
40
42
  * 当前 card loading 不要直接使用,因为这个 loading 会导致 Card 里的 formRef 被设置成 null
@@ -52,8 +54,11 @@ declare class ReactAntResourceForm extends Component<ReactAntResourceFormProps,
52
54
  };
53
55
  private formRef;
54
56
  private _isMounted;
57
+ private _initialValues;
55
58
  get isEdit(): boolean;
56
- get titleView(): any;
59
+ get canSave(): boolean;
60
+ get titleView(): React.JSX.Element;
61
+ get touchedView(): React.JSX.Element | null;
57
62
  get extraView(): string | number | true | Iterable<React.ReactNode> | React.JSX.Element;
58
63
  get childrenView(): string | number | true | Iterable<React.ReactNode> | React.JSX.Element | ((values: rc_field_form_lib_interface.Store, form: rc_field_form_lib_interface.FormInstance) => JSX.Element | React.ReactNode);
59
64
  get formInstance(): FormInstance<any> | null;
@@ -64,13 +69,15 @@ declare class ReactAntResourceForm extends Component<ReactAntResourceFormProps,
64
69
  handleStateResponse(res: StageData): any;
65
70
  handleFinish: (values: any) => void;
66
71
  handleKeydown: (e: KeyboardEvent) => void;
72
+ handleValuesChange: (_: any, allValues: any) => void;
67
73
  componentDidMount(): void;
68
74
  componentDidUpdate(prevProps: ReactAntResourceFormProps): void;
69
75
  componentWillUnmount(): void;
70
76
  initDetailIfNeeded(): void;
71
77
  render(): React.JSX.Element;
72
78
  }
79
+ declare const ReactAntResourceFormFc: FC<ReactAntResourceFormProps>;
73
80
 
74
81
  // @ts-ignore
75
82
  export = ReactAntResourceForm;
76
- export type { ReactAntResourceFormProps };
83
+ export { ReactAntResourceFormFc, type ReactAntResourceFormProps };
package/dist/main.esm.js CHANGED
@@ -1,2 +1,2 @@
1
- var b=Object.defineProperty;var S=Object.getOwnPropertySymbols;var g=Object.prototype.hasOwnProperty,E=Object.prototype.propertyIsEnumerable;var y=(i,a,e)=>a in i?b(i,a,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[a]=e,l=(i,a)=>{for(var e in a||(a={}))g.call(a,e)&&y(i,e,a[e]);if(S)for(var e of S(a))E.call(a,e)&&y(i,e,a[e]);return i};var f=(i,a)=>b(i,"name",{value:a,configurable:!0});var w=(i,a)=>{var e={};for(var t in i)g.call(i,t)&&a.indexOf(t)<0&&(e[t]=i[t]);if(i!=null&&S)for(var t of S(i))a.indexOf(t)<0&&E.call(i,t)&&(e[t]=i[t]);return e};var h=(i,a,e)=>y(i,typeof a!="symbol"?a+"":a,e);import D from"classnames";import c,{Component as L}from"react";import{Button as R,Card as M,Space as $,message as C,Spin as P}from"antd";import T from"@jswork/react-ant-form-schema";import{ArrowLeftOutlined as I,SaveOutlined as V}from"@ant-design/icons";var x={"zh-CN":{create:"\u521B\u5EFA",update:"\u4FDD\u5B58",create_title:"\u521B\u5EFA",update_title:"\u66F4\u65B0",create_success:"\u521B\u5EFA\u6210\u529F",update_success:"\u66F4\u65B0\u6210\u529F",submit:"\u63D0\u4EA4",back:"\u8FD4\u56DE"},"en-US":{create:"Create",update:"Save",create_title:"Create",update_title:"Update",create_success:"Create success",update_success:"Update success",submit:"Submit",back:"Back"}};import k from"@jswork/next";var v="react-ant-resource-form",p,B=(p=class extends L{constructor(e){super(e);h(this,"formRef",c.createRef());h(this,"_isMounted",!1);h(this,"handleBack",f(()=>{history.back()},"handleBack"));h(this,"handleFinish",f(e=>{let{params:t,name:s}=this.props,n=`${s}_update`,r=`${s}_create`;if(this.isEdit){let o=l({id:t.id},e),u=this.handleStateRequest({stage:"update",payload:o});k.$api[n](u).then(d=>{C.success(this.t("update_success")),this.handleStateResponse({stage:"update",data:d})}).finally(()=>this.setState({loading:!1}))}else{let o=l({},e),u=this.handleStateRequest({stage:"create",payload:o});k.$api[r](u).then(d=>{var m;C.success(this.t("create_success")),this.handleStateResponse({stage:"create",data:d}),(m=this.formInstance)==null||m.resetFields(),history.back()}).finally(()=>this.setState({loading:!1}))}},"handleFinish"));h(this,"handleKeydown",f(e=>{var s;if((e.ctrlKey||e.metaKey)&&(e.key==="s"||e.key==="S")&&(e.preventDefault(),!this.props.disableHotkeySave))try{(s=this.formInstance)==null||s.submit()}catch(n){}},"handleKeydown"));this.state={loading:!1},this.handleStateRequest=this.handleStateRequest.bind(this),this.handleStateResponse=this.handleStateResponse.bind(this),this.initDetailIfNeeded=this.initDetailIfNeeded.bind(this)}get isEdit(){let{params:e}=this.props;return!!(e!=null&&e.id)}get titleView(){let{title:e}=this.props;return e||(this.isEdit?this.t("update_title"):this.t("create_title"))}get extraView(){let{extra:e,backText:t,backProps:s}=this.props;return e||c.createElement(R,l({size:"small",icon:c.createElement(I,null),onClick:this.handleBack},s),t||this.t("back"))}get childrenView(){let{okText:e,backText:t,okProps:s,backProps:n,children:r}=this.props,o=e||(this.isEdit?this.t("update"):this.t("create"));return r||c.createElement($,null,c.createElement(R,l({htmlType:"submit",type:"primary",icon:c.createElement(V,null)},s),o||this.t("submit")),c.createElement(R,l({icon:c.createElement(I,null),onClick:this.handleBack},n),t||this.t("back")))}get formInstance(){var e;return(e=this.formRef)==null?void 0:e.current}t(e){let{lang:t}=this.props;return x[t][e]}handleStateRequest(e){var t,s;return this.setState({loading:!0}),((s=(t=this.props).transformRequest)==null?void 0:s.call(t,e))||e.payload}handleStateResponse(e){var s,n,r,o;let{name:t}=this.props;return this.setState({loading:!1}),(n=(s=k.$event)==null?void 0:s.emit)==null||n.call(s,`${t}:refetch`),((o=(r=this.props).transformResponse)==null?void 0:o.call(r,e))||e.data}componentDidMount(){this._isMounted=!0,window.addEventListener("keydown",this.handleKeydown),this.initDetailIfNeeded()}componentDidUpdate(e){var n,r;let t=(n=e.params)==null?void 0:n.id,s=(r=this.props.params)==null?void 0:r.id;t!==s&&this.initDetailIfNeeded()}componentWillUnmount(){window.removeEventListener("keydown",this.handleKeydown),this._isMounted=!1}initDetailIfNeeded(){let{params:e,name:t}=this.props,s=`${t}_show`;if(this.isEdit){let n={id:e.id},r=this.handleStateRequest({stage:"show",payload:n});k.$api[s](r).then(o=>{var d,m;if(!this._isMounted)return;let u=this.handleStateResponse({stage:"show",data:o});try{(m=(d=this.formInstance)==null?void 0:d.setFieldsValue)==null||m.call(d,u)}catch(A){}}).finally(()=>this.setState({loading:!1}))}}render(){let _=this.props,{className:e,name:t,meta:s,children:n,lang:r,title:o,extra:u,size:d,okText:m,backText:A,okProps:O,backProps:z,classNames:F,params:K,transformRequest:U,transformResponse:H,disableHotkeySave:W}=_,q=w(_,["className","name","meta","children","lang","title","extra","size","okText","backText","okProps","backProps","classNames","params","transformRequest","transformResponse","disableHotkeySave"]);return c.createElement(M,{title:this.titleView,extra:this.extraView,size:d,classNames:F,"data-component":v,className:D(v,e)},c.createElement(P,{spinning:this.state.loading},c.createElement(T,l({meta:s,ref:this.formRef,onFinish:this.handleFinish},q),this.childrenView)))}},f(p,"ReactAntResourceForm"),h(p,"defaultProps",{lang:"zh-CN",disableHotkeySave:!1}),p),N=B;var ne=N;export{ne as default};
1
+ var E=Object.defineProperty;var S=Object.getOwnPropertySymbols;var b=Object.prototype.hasOwnProperty,w=Object.prototype.propertyIsEnumerable;var R=(a,s,e)=>s in a?E(a,s,{enumerable:!0,configurable:!0,writable:!0,value:e}):a[s]=e,m=(a,s)=>{for(var e in s||(s={}))b.call(s,e)&&R(a,e,s[e]);if(S)for(var e of S(s))w.call(s,e)&&R(a,e,s[e]);return a};var p=(a,s)=>E(a,"name",{value:s,configurable:!0});var V=(a,s)=>{var e={};for(var t in a)b.call(a,t)&&s.indexOf(t)<0&&(e[t]=a[t]);if(a!=null&&S)for(var t of S(a))s.indexOf(t)<0&&w.call(a,t)&&(e[t]=a[t]);return e};var d=(a,s,e)=>R(a,typeof s!="symbol"?s+"":s,e);import M from"classnames";import r,{Component as P}from"react";import{Button as k,Card as $,Space as I,message as C,Spin as O}from"antd";import T from"@jswork/react-ant-form-schema";import{ArrowLeftOutlined as F,DiffOutlined as B,SaveOutlined as z}from"@ant-design/icons";var x={"zh-CN":{create:"\u521B\u5EFA",update:"\u4FDD\u5B58",create_title:"\u521B\u5EFA",update_title:"\u66F4\u65B0",create_success:"\u521B\u5EFA\u6210\u529F",update_success:"\u66F4\u65B0\u6210\u529F",submit:"\u63D0\u4EA4",back:"\u8FD4\u56DE"},"en-US":{create:"Create",update:"Save",create_title:"Create",update_title:"Update",create_success:"Create success",update_success:"Update success",submit:"Submit",back:"Back"}};import _ from"@jswork/next";import{useParams as K}from"react-router-dom";import U from"fast-deep-equal";var v="react-ant-resource-form",f,A=(f=class extends P{constructor(e){var t;super(e);d(this,"formRef",r.createRef());d(this,"_isMounted",!1);d(this,"_initialValues",null);d(this,"handleBack",p(()=>{history.back()},"handleBack"));d(this,"handleFinish",p(e=>{let{params:t,name:i}=this.props,n=`${i}_update`,o=`${i}_create`;if(this.isEdit){let l=m({id:t.id},e),h=this.handleStateRequest({stage:"update",payload:l});_.$api[n](h).then(c=>{C.success(this.t("update_success")),this.handleStateResponse({stage:"update",data:c})}).finally(()=>{var c;this.setState({loading:!1}),this._initialValues=((c=this.formInstance)==null?void 0:c.getFieldsValue())||{},this.handleValuesChange(null,this._initialValues)})}else{let l=m({},e),h=this.handleStateRequest({stage:"create",payload:l});_.$api[o](h).then(c=>{var u;C.success(this.t("create_success")),this.handleStateResponse({stage:"create",data:c}),(u=this.formInstance)==null||u.resetFields(),history.back()}).finally(()=>this.setState({loading:!1}))}},"handleFinish"));d(this,"handleKeydown",p(e=>{var n;let{disableHotkeySave:t}=this.props;if((e.ctrlKey||e.metaKey)&&(e.key==="s"||e.key==="S")&&(e.preventDefault(),!t))try{(n=this.formInstance)==null||n.submit()}catch(o){}},"handleKeydown"));d(this,"handleValuesChange",p((e,t)=>{this.setState({touched:U(this._initialValues,t)===!1})},"handleValuesChange"));this.state={loading:!1,touched:!1},this.handleStateRequest=this.handleStateRequest.bind(this),this.handleStateResponse=this.handleStateResponse.bind(this),this.initDetailIfNeeded=this.initDetailIfNeeded.bind(this),(t=e.onInit)==null||t.call(e,this)}get isEdit(){let{params:e}=this.props;return!!(e!=null&&e.id)}get canSave(){let{touched:e,loading:t}=this.state;return this.isEdit?e===!0&&t===!1:t===!1}get titleView(){let{title:e}=this.props,t=e||(this.isEdit?this.t("update_title"):this.t("create_title"));return r.createElement(I,null,t,r.createElement("span",null,this.touchedView))}get touchedView(){return this.isEdit&&this.state.touched?r.createElement("em",{style:{color:"#f60"}},r.createElement(B,null)):null}get extraView(){let{extra:e,backText:t,backProps:i}=this.props;return e||r.createElement(k,m({size:"small",icon:r.createElement(F,null),onClick:this.handleBack},i),t||this.t("back"))}get childrenView(){let{okText:e,backText:t,okProps:i,backProps:n,children:o}=this.props,l=e||(this.isEdit?this.t("update"):this.t("create"));return o||r.createElement(I,null,r.createElement(k,m({disabled:!this.canSave,htmlType:"submit",type:"primary",icon:r.createElement(z,null)},i),l||this.t("submit")),r.createElement(k,m({icon:r.createElement(F,null),onClick:this.handleBack},n),t||this.t("back")))}get formInstance(){var e;return(e=this.formRef)==null?void 0:e.current}t(e){let{lang:t}=this.props;return x[t][e]}handleStateRequest(e){var t,i;return this.setState({loading:!0}),((i=(t=this.props).transformRequest)==null?void 0:i.call(t,e))||e.payload}handleStateResponse(e){var i,n,o,l;let{name:t}=this.props;return this.setState({loading:!1}),(n=(i=_.$event)==null?void 0:i.emit)==null||n.call(i,`${t}:refetch`),((l=(o=this.props).transformResponse)==null?void 0:l.call(o,e))||e.data}componentDidMount(){this._isMounted=!0,window.addEventListener("keydown",this.handleKeydown),this.initDetailIfNeeded()}componentDidUpdate(e){var n,o;let t=(n=e.params)==null?void 0:n.id,i=(o=this.props.params)==null?void 0:o.id;t!==i&&this.initDetailIfNeeded()}componentWillUnmount(){window.removeEventListener("keydown",this.handleKeydown),this._isMounted=!1}initDetailIfNeeded(){var n;let{params:e,name:t}=this.props,i=`${t}_show`;if(this.isEdit){let o={id:e.id},l=this.handleStateRequest({stage:"show",payload:o});_.$api[i](l).then(h=>{var u,g;if(!this._isMounted)return;let c=this.handleStateResponse({stage:"show",data:h});try{(g=(u=this.formInstance)==null?void 0:u.setFieldsValue)==null||g.call(u,c)}catch(D){}}).finally(()=>{var h;this.setState({loading:!1}),this._initialValues=((h=this.formInstance)==null?void 0:h.getFieldsValue())||{}})}else this._initialValues=((n=this.formInstance)==null?void 0:n.getFieldsValue())||{}}render(){let y=this.props,{className:e,name:t,meta:i,children:n,lang:o,title:l,extra:h,size:c,okText:u,backText:g,okProps:D,backProps:W,classNames:q,params:j,transformRequest:G,transformResponse:J,disableHotkeySave:Q,onInit:X}=y,L=V(y,["className","name","meta","children","lang","title","extra","size","okText","backText","okProps","backProps","classNames","params","transformRequest","transformResponse","disableHotkeySave","onInit"]);return r.createElement($,{title:this.titleView,extra:this.extraView,size:c,classNames:q,"data-component":v,className:M(v,e)},r.createElement(O,{spinning:this.state.loading},r.createElement(T,m({meta:i,ref:this.formRef,onValuesChange:this.handleValuesChange,onFinish:this.handleFinish},L),this.childrenView)))}},p(f,"ReactAntResourceForm"),d(f,"defaultProps",{lang:"zh-CN",disableHotkeySave:!1}),f),H=p(a=>{let s=K();return r.createElement(A,m({params:s},a))},"ReactAntResourceFormFc"),N=A;var ue=N;export{H as ReactAntResourceFormFc,ue as default};
2
2
  //# sourceMappingURL=main.esm.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.tsx","../src/locales.ts","../src/main.tsx"],"sourcesContent":["// import noop from '@jswork/noop';\nimport cx from 'classnames';\nimport React, { Component } from 'react';\nimport { Button, ButtonProps, Card, CardProps, Space, message, Spin } from 'antd';\nimport type { FormInstance } from 'antd';\nimport ReactAntdFormSchema, { ReactAntdFormSchemaProps } from '@jswork/react-ant-form-schema';\nimport { ArrowLeftOutlined, SaveOutlined } from '@ant-design/icons';\nimport { API_FORM_LOCALES } from './locales';\nimport nx from '@jswork/next';\n\ndeclare global {\n interface NxStatic {\n $api: Record<string, any>;\n $event: any;\n }\n}\n\ntype StagePayload = {\n stage: 'show' | 'create' | 'update';\n payload: any;\n};\n\ntype StageData = {\n stage: 'show' | 'create' | 'update';\n data: any;\n};\n\nexport type ReactAntResourceFormProps = {\n lang?: string;\n loading?: boolean;\n okText?: string;\n backText?: string;\n params?: Record<string, any>;\n disableHotkeySave?: boolean;\n transformRequest?: (payload: StagePayload) => any;\n transformResponse?: (res: StageData) => any;\n okProps?: ButtonProps;\n backProps?: ButtonProps;\n classNames?: CardProps['classNames'];\n size?: CardProps['size'];\n extra?: CardProps['extra'];\n title?: CardProps['title'];\n} & ReactAntdFormSchemaProps;\n\ntype IState = {\n loading: boolean;\n};\n\nconst CLASS_NAME = 'react-ant-resource-form';\n\n/**\n * 当前 card loading 不要直接使用,因为这个 loading 会导致 Card 里的 formRef 被设置成 null\n * 这个情况仅在 class component 里才会出现,function component 里不会:\n * 报错示例:\n *\n * this.formRef?: null\n * index.tsx:229 this.formRef?: {getFieldValue: ƒ, getFieldsValue: ƒ, getFieldError: ƒ, getFieldWarning: ƒ, getFieldsError: ƒ, …}\n * index.tsx:229 this.formRef?: null\n */\n\nclass ReactAntResourceForm extends Component<ReactAntResourceFormProps, IState> {\n public static defaultProps = {\n lang: 'zh-CN',\n disableHotkeySave: false,\n };\n\n private formRef = React.createRef<FormInstance>(); // 注意类型\n private _isMounted = false;\n\n get isEdit() {\n const { params } = this.props;\n return Boolean(params?.id);\n }\n\n get titleView() {\n const { title } = this.props;\n return title || (this.isEdit ? this.t('update_title') : this.t('create_title'));\n }\n\n get extraView() {\n const { extra, backText, backProps } = this.props;\n if (extra) return extra;\n return (\n <Button size=\"small\" icon={<ArrowLeftOutlined />} onClick={this.handleBack} {...backProps}>\n {backText || this.t('back')}\n </Button>\n );\n }\n\n get childrenView() {\n const { okText, backText, okProps, backProps, children } = this.props;\n const _okText = okText || (this.isEdit ? this.t('update') : this.t('create'));\n if (children) return children;\n\n return (\n <Space>\n <Button htmlType=\"submit\" type=\"primary\" icon={<SaveOutlined />} {...okProps}>\n {_okText || this.t('submit')}\n </Button>\n <Button icon={<ArrowLeftOutlined />} onClick={this.handleBack} {...backProps}>\n {backText || this.t('back')}\n </Button>\n </Space>\n );\n }\n\n get formInstance() {\n return this.formRef?.current;\n }\n\n constructor(props: ReactAntResourceFormProps) {\n super(props);\n this.state = {\n loading: false,\n };\n\n this.handleStateRequest = this.handleStateRequest.bind(this);\n this.handleStateResponse = this.handleStateResponse.bind(this);\n this.initDetailIfNeeded = this.initDetailIfNeeded.bind(this);\n }\n\n private t(key: string) {\n const { lang } = this.props;\n return API_FORM_LOCALES[lang!][key];\n }\n\n private handleBack = () => {\n history.back();\n };\n\n handleStateRequest(stagePayload: StagePayload) {\n this.setState({ loading: true });\n return this.props.transformRequest?.(stagePayload) || stagePayload.payload;\n }\n\n handleStateResponse(res: StageData) {\n const { name } = this.props;\n this.setState({ loading: false });\n nx.$event?.emit?.(`${name}:refetch`);\n return this.props.transformResponse?.(res) || res.data;\n }\n\n handleFinish = (values: any) => {\n const { params, name } = this.props;\n const resourceEdit = `${name}_update`;\n const resourceCreate = `${name}_create`;\n\n if (this.isEdit) {\n const payload = { id: params!.id, ...values };\n const _payload = this.handleStateRequest({ stage: 'update', payload });\n\n nx.$api[resourceEdit](_payload)\n .then((res: any) => {\n message.success(this.t('update_success'));\n this.handleStateResponse({ stage: 'update', data: res });\n })\n .finally(() => this.setState({ loading: false }));\n } else {\n const payload = { ...values };\n const _payload = this.handleStateRequest({ stage: 'create', payload });\n\n nx.$api[resourceCreate](_payload)\n .then((res: any) => {\n message.success(this.t('create_success'));\n this.handleStateResponse({ stage: 'create', data: res });\n this.formInstance?.resetFields();\n history.back();\n })\n .finally(() => this.setState({ loading: false }));\n }\n };\n\n // hotkey save handler (replaces useKeyboardSave hook)\n handleKeydown = (e: KeyboardEvent) => {\n const isSave = (e.ctrlKey || e.metaKey) && (e.key === 's' || e.key === 'S');\n if (isSave) {\n e.preventDefault();\n if (!this.props.disableHotkeySave) {\n // submit the form via ref\n try {\n this.formInstance?.submit();\n } catch (err) {\n // ignore if submit not available yet\n }\n }\n }\n };\n\n componentDidMount() {\n this._isMounted = true;\n // attach hotkey listener\n window.addEventListener('keydown', this.handleKeydown);\n // initialize detail if editing\n this.initDetailIfNeeded();\n }\n\n componentDidUpdate(prevProps: ReactAntResourceFormProps) {\n const prevId = prevProps.params?.id;\n const curId = this.props.params?.id;\n // re-init when id changed or from create -> edit\n if (prevId !== curId) {\n this.initDetailIfNeeded();\n }\n }\n\n componentWillUnmount() {\n window.removeEventListener('keydown', this.handleKeydown);\n this._isMounted = false;\n }\n\n initDetailIfNeeded() {\n const { params, name } = this.props;\n const resourceShow = `${name}_show`;\n\n if (this.isEdit) {\n const payload = { id: params!.id };\n const _payload = this.handleStateRequest({ stage: 'show', payload });\n\n nx.$api[resourceShow](_payload)\n .then((res: any) => {\n if (!this._isMounted) return; // 👈 关键:防止操作已卸载组件\n const data = this.handleStateResponse({ stage: 'show', data: res });\n // set fields value on the form via ref\n try {\n this.formInstance?.setFieldsValue?.(data);\n } catch (err) {\n // ignore if not available yet\n }\n })\n .finally(() => this.setState({ loading: false }));\n }\n }\n\n render() {\n const {\n className,\n name,\n meta,\n children,\n lang,\n title,\n extra,\n size,\n okText,\n backText,\n okProps,\n backProps,\n classNames,\n params,\n transformRequest,\n transformResponse,\n disableHotkeySave,\n ...rest\n } = this.props;\n\n return (\n <Card\n title={this.titleView}\n extra={this.extraView}\n size={size}\n classNames={classNames}\n data-component={CLASS_NAME}\n className={cx(CLASS_NAME, className)}>\n <Spin spinning={this.state.loading}>\n <ReactAntdFormSchema\n meta={meta}\n ref={this.formRef}\n onFinish={this.handleFinish}\n {...rest}>\n {this.childrenView}\n </ReactAntdFormSchema>\n </Spin>\n </Card>\n );\n }\n}\n\nexport default ReactAntResourceForm;\n","export const API_FORM_LOCALES = {\n 'zh-CN': {\n create: '创建',\n update: '保存',\n create_title: '创建',\n update_title: '更新',\n create_success: '创建成功',\n update_success: '更新成功',\n submit: '提交',\n back: '返回',\n },\n 'en-US': {\n create: 'Create',\n update: 'Save',\n create_title: 'Create',\n update_title: 'Update',\n create_success: 'Create success',\n update_success: 'Update success',\n submit: 'Submit',\n back: 'Back',\n },\n};\n","import ReactAntResourceForm from '.';\nimport type { ReactAntResourceFormProps } from '.';\n\nexport default ReactAntResourceForm;\nexport type { ReactAntResourceFormProps };\n"],"mappings":"8lBACA,OAAOA,MAAQ,aACf,OAAOC,GAASC,aAAAA,MAAiB,QACjC,OAASC,UAAAA,EAAqBC,QAAAA,EAAiBC,SAAAA,EAAOC,WAAAA,EAASC,QAAAA,MAAY,OAE3E,OAAOC,MAAuD,gCAC9D,OAASC,qBAAAA,EAAmBC,gBAAAA,MAAoB,oBCNzC,IAAMC,EAAmB,CAC9B,QAAS,CACPC,OAAQ,eACRC,OAAQ,eACRC,aAAc,eACdC,aAAc,eACdC,eAAgB,2BAChBC,eAAgB,2BAChBC,OAAQ,eACRC,KAAM,cACR,EACA,QAAS,CACPP,OAAQ,SACRC,OAAQ,OACRC,aAAc,SACdC,aAAc,SACdC,eAAgB,iBAChBC,eAAgB,iBAChBC,OAAQ,SACRC,KAAM,MACR,CACF,EDbA,OAAOC,MAAQ,eAwCf,IAAMC,EAAa,0BAhDnBC,EA4DMC,GAAND,EAAA,cAAmCE,CAAAA,CAkDjC,YAAYC,EAAkC,CAC5C,MAAMA,CAAAA,EA7CAC,EAAAA,eAAUC,EAAMC,UAAS,GACzBC,EAAAA,kBAAa,IA2DbC,EAAAA,kBAAaC,EAAA,IAAA,CACnBC,QAAQC,KAAI,CACd,EAFqB,eAgBrBC,EAAAA,oBAAeH,EAACI,GAAAA,CACd,GAAM,CAAEC,OAAAA,EAAQC,KAAAA,CAAI,EAAK,KAAKZ,MACxBa,EAAe,GAAGD,CAAAA,UAClBE,EAAiB,GAAGF,CAAAA,UAE1B,GAAI,KAAKG,OAAQ,CACf,IAAMC,EAAUC,EAAA,CAAEC,GAAIP,EAAQO,IAAOR,GAC/BS,EAAW,KAAKC,mBAAmB,CAAEC,MAAO,SAAUL,QAAAA,CAAQ,CAAA,EAEpEM,EAAGC,KAAKV,CAAAA,EAAcM,CAAAA,EACnBK,KAAMC,GAAAA,CACLC,EAAQC,QAAQ,KAAKC,EAAE,gBAAA,CAAA,EACvB,KAAKC,oBAAoB,CAAER,MAAO,SAAUS,KAAML,CAAI,CAAA,CACxD,CAAA,EACCM,QAAQ,IAAM,KAAKC,SAAS,CAAEC,QAAS,EAAM,CAAA,CAAA,CAClD,KAAO,CACL,IAAMjB,EAAUC,EAAA,GAAKP,GACfS,EAAW,KAAKC,mBAAmB,CAAEC,MAAO,SAAUL,QAAAA,CAAQ,CAAA,EAEpEM,EAAGC,KAAKT,CAAAA,EAAgBK,CAAAA,EACrBK,KAAMC,GAAAA,CAlKf,IAAA5B,EAmKU6B,EAAQC,QAAQ,KAAKC,EAAE,gBAAA,CAAA,EACvB,KAAKC,oBAAoB,CAAER,MAAO,SAAUS,KAAML,CAAI,CAAA,GACtD5B,EAAA,KAAKqC,eAAL,MAAArC,EAAmBsC,cACnB5B,QAAQC,KAAI,CACd,CAAA,EACCuB,QAAQ,IAAM,KAAKC,SAAS,CAAEC,QAAS,EAAM,CAAA,CAAA,CAClD,CACF,EA5Be,iBA+BfG,EAAAA,qBAAgB9B,EAAC+B,GAAAA,CA7KnB,IAAAxC,EA+KI,IADgBwC,EAAEC,SAAWD,EAAEE,WAAaF,EAAEG,MAAQ,KAAOH,EAAEG,MAAQ,OAErEH,EAAEI,eAAc,EACZ,CAAC,KAAKzC,MAAM0C,mBAEd,GAAI,EACF7C,EAAA,KAAKqC,eAAL,MAAArC,EAAmB8C,QACrB,OAASC,EAAK,CAEd,CAGN,EAbgB,kBA7Dd,KAAKC,MAAQ,CACXZ,QAAS,EACX,EAEA,KAAKb,mBAAqB,KAAKA,mBAAmB0B,KAAK,IAAI,EAC3D,KAAKjB,oBAAsB,KAAKA,oBAAoBiB,KAAK,IAAI,EAC7D,KAAKC,mBAAqB,KAAKA,mBAAmBD,KAAK,IAAI,CAC7D,CAlDA,IAAI/B,QAAS,CACX,GAAM,CAAEJ,OAAAA,CAAM,EAAK,KAAKX,MACxB,MAAOgD,GAAQrC,GAAAA,MAAAA,EAAQO,GACzB,CAEA,IAAI+B,WAAY,CACd,GAAM,CAAEC,MAAAA,CAAK,EAAK,KAAKlD,MACvB,OAAOkD,IAAU,KAAKnC,OAAS,KAAKa,EAAE,cAAA,EAAkB,KAAKA,EAAE,cAAA,EACjE,CAEA,IAAIuB,WAAY,CACd,GAAM,CAAEC,MAAAA,EAAOC,SAAAA,EAAUC,UAAAA,CAAS,EAAK,KAAKtD,MAC5C,OAAIoD,GAEFlD,EAAA,cAACqD,EAAAA,EAAAA,CAAOC,KAAK,QAAQC,KAAMvD,EAAA,cAACwD,EAAAA,IAAAA,EAAsBC,QAAS,KAAKtD,YAAgBiD,GAC7ED,GAAY,KAAKzB,EAAE,MAAA,CAAA,CAG1B,CAEA,IAAIgC,cAAe,CACjB,GAAM,CAAEC,OAAAA,EAAQR,SAAAA,EAAUS,QAAAA,EAASR,UAAAA,EAAWS,SAAAA,CAAQ,EAAK,KAAK/D,MAC1DgE,EAAUH,IAAW,KAAK9C,OAAS,KAAKa,EAAE,QAAA,EAAY,KAAKA,EAAE,QAAA,GACnE,OAAImC,GAGF7D,EAAA,cAAC+D,EAAAA,KACC/D,EAAA,cAACqD,EAAAA,EAAAA,CAAOW,SAAS,SAASC,KAAK,UAAUV,KAAMvD,EAAA,cAACkE,EAAAA,IAAAA,GAAqBN,GAClEE,GAAW,KAAKpC,EAAE,QAAA,CAAA,EAErB1B,EAAA,cAACqD,EAAAA,EAAAA,CAAOE,KAAMvD,EAAA,cAACwD,EAAAA,IAAAA,EAAsBC,QAAS,KAAKtD,YAAgBiD,GAChED,GAAY,KAAKzB,EAAE,MAAA,CAAA,CAAA,CAI5B,CAEA,IAAIM,cAAe,CA1GrB,IAAArC,EA2GI,OAAOA,EAAA,KAAKI,UAAL,YAAAJ,EAAcwE,OACvB,CAaQzC,EAAEY,EAAa,CACrB,GAAM,CAAE8B,KAAAA,CAAI,EAAK,KAAKtE,MACtB,OAAOuE,EAAiBD,CAAAA,EAAO9B,CAAAA,CACjC,CAMApB,mBAAmBoD,EAA4B,CAlIjD,IAAA3E,EAAA4E,EAmII,YAAKzC,SAAS,CAAEC,QAAS,EAAK,CAAA,IACvBwC,GAAA5E,EAAA,KAAKG,OAAM0E,mBAAX,YAAAD,EAAA,KAAA5E,EAA8B2E,KAAiBA,EAAaxD,OACrE,CAEAa,oBAAoBJ,EAAgB,CAvItC,IAAA5B,EAAA4E,EAAAE,EAAAC,EAwII,GAAM,CAAEhE,KAAAA,CAAI,EAAK,KAAKZ,MACtB,YAAKgC,SAAS,CAAEC,QAAS,EAAM,CAAA,GAC/BX,GAAAA,EAAAA,EAAGuD,SAAHvD,YAAAA,EAAWwD,OAAXxD,MAAAA,EAAAA,KAAAA,EAAkB,GAAGV,CAAAA,cACdgE,GAAAD,EAAA,KAAK3E,OAAM+E,oBAAX,YAAAH,EAAA,KAAAD,EAA+BlD,KAAQA,EAAIK,IACpD,CAgDAkD,mBAAoB,CAClB,KAAK5E,WAAa,GAElB6E,OAAOC,iBAAiB,UAAW,KAAK9C,aAAa,EAErD,KAAKW,mBAAkB,CACzB,CAEAoC,mBAAmBC,EAAsC,CApM3D,IAAAvF,EAAA4E,EAqMI,IAAMY,GAASD,EAAAA,EAAUzE,SAAVyE,YAAAA,EAAkBlE,GAC3BoE,GAAQb,EAAA,KAAKzE,MAAMW,SAAX,YAAA8D,EAAmBvD,GAE7BmE,IAAWC,GACb,KAAKvC,mBAAkB,CAE3B,CAEAwC,sBAAuB,CACrBN,OAAOO,oBAAoB,UAAW,KAAKpD,aAAa,EACxD,KAAKhC,WAAa,EACpB,CAEA2C,oBAAqB,CACnB,GAAM,CAAEpC,OAAAA,EAAQC,KAAAA,CAAI,EAAK,KAAKZ,MACxByF,EAAe,GAAG7E,CAAAA,QAExB,GAAI,KAAKG,OAAQ,CACf,IAAMC,EAAU,CAAEE,GAAIP,EAAQO,EAAG,EAC3BC,EAAW,KAAKC,mBAAmB,CAAEC,MAAO,OAAQL,QAAAA,CAAQ,CAAA,EAElEM,EAAGC,KAAKkE,CAAAA,EAActE,CAAAA,EACnBK,KAAMC,GAAAA,CA3Nf,IAAA5B,EAAA4E,EA4NU,GAAI,CAAC,KAAKrE,WAAY,OACtB,IAAM0B,EAAO,KAAKD,oBAAoB,CAAER,MAAO,OAAQS,KAAML,CAAI,CAAA,EAEjE,GAAI,EACFgD,GAAA5E,EAAA,KAAKqC,eAAL,YAAArC,EAAmB6F,iBAAnB,MAAAjB,EAAA,KAAA5E,EAAoCiC,EACtC,OAASc,EAAK,CAEd,CACF,CAAA,EACCb,QAAQ,IAAM,KAAKC,SAAS,CAAEC,QAAS,EAAM,CAAA,CAAA,CAClD,CACF,CAEA0D,QAAS,CACP,IAmBI9F,EAAA,KAAKG,MAlBP4F,WAAAA,EACAhF,KAAAA,EACAiF,KAAAA,EACA9B,SAAAA,EACAO,KAAAA,EACApB,MAAAA,EACAE,MAAAA,EACAI,KAAAA,EACAK,OAAAA,EACAR,SAAAA,EACAS,QAAAA,EACAR,UAAAA,EACAwC,WAAAA,EACAnF,OAAAA,EACA+D,iBAAAA,EACAK,kBAAAA,EACArC,kBAAAA,CA3PN,EA6PQ7C,EADCkG,EAAAA,EACDlG,EADCkG,CAjBHH,YACAhF,OACAiF,OACA9B,WACAO,OACApB,QACAE,QACAI,OACAK,SACAR,WACAS,UACAR,YACAwC,aACAnF,SACA+D,mBACAK,oBACArC,sBAIF,OACExC,EAAA,cAAC8F,EAAAA,CACC9C,MAAO,KAAKD,UACZG,MAAO,KAAKD,UACZK,KAAMA,EACNsC,WAAYA,EACZG,iBAAgBrG,EAChBgG,UAAWM,EAAGtG,EAAYgG,CAAAA,GAC1B1F,EAAA,cAACiG,EAAAA,CAAKC,SAAU,KAAKvD,MAAMZ,SACzB/B,EAAA,cAACmG,EAAAA,EAAAA,CACCR,KAAMA,EACNS,IAAK,KAAKrG,QACVsG,SAAU,KAAK9F,cACXsF,GACH,KAAKnC,YAAY,CAAA,CAAA,CAK5B,CACF,EAvNmC7D,EAAAA,EAAAA,wBACjCyG,EADF3G,EACgB4G,eAAe,CAC3BnC,KAAM,QACN5B,kBAAmB,EACrB,GAJF7C,GAyNA6G,EAAe5G,EElRf,IAAA6G,GAAeC","names":["cx","React","Component","Button","Card","Space","message","Spin","ReactAntdFormSchema","ArrowLeftOutlined","SaveOutlined","API_FORM_LOCALES","create","update","create_title","update_title","create_success","update_success","submit","back","nx","CLASS_NAME","_a","ReactAntResourceForm","Component","props","formRef","React","createRef","_isMounted","handleBack","__name","history","back","handleFinish","values","params","name","resourceEdit","resourceCreate","isEdit","payload","__spreadValues","id","_payload","handleStateRequest","stage","nx","$api","then","res","message","success","t","handleStateResponse","data","finally","setState","loading","formInstance","resetFields","handleKeydown","e","ctrlKey","metaKey","key","preventDefault","disableHotkeySave","submit","err","state","bind","initDetailIfNeeded","Boolean","titleView","title","extraView","extra","backText","backProps","Button","size","icon","ArrowLeftOutlined","onClick","childrenView","okText","okProps","children","_okText","Space","htmlType","type","SaveOutlined","current","lang","API_FORM_LOCALES","stagePayload","_b","transformRequest","_c","_d","$event","emit","transformResponse","componentDidMount","window","addEventListener","componentDidUpdate","prevProps","prevId","curId","componentWillUnmount","removeEventListener","resourceShow","setFieldsValue","render","className","meta","classNames","rest","Card","data-component","cx","Spin","spinning","ReactAntdFormSchema","ref","onFinish","__publicField","defaultProps","index_default","main_default","ReactAntResourceForm"]}
1
+ {"version":3,"sources":["../src/index.tsx","../src/locales.ts","../src/main.tsx"],"sourcesContent":["// import noop from '@jswork/noop';\nimport cx from 'classnames';\nimport React, { Component, FC } from 'react';\nimport { Button, ButtonProps, Card, CardProps, Space, message, Spin } from 'antd';\nimport type { FormInstance } from 'antd';\nimport ReactAntdFormSchema, { ReactAntdFormSchemaProps } from '@jswork/react-ant-form-schema';\nimport { ArrowLeftOutlined, DiffOutlined, SaveOutlined } from '@ant-design/icons';\nimport { API_FORM_LOCALES } from './locales';\nimport nx from '@jswork/next';\nimport { useParams } from 'react-router-dom';\nimport fde from 'fast-deep-equal';\n\ndeclare global {\n interface NxStatic {\n $api: Record<string, any>;\n $event: any;\n }\n}\n\ntype StagePayload = {\n stage: 'show' | 'create' | 'update';\n payload: any;\n};\n\ntype StageData = {\n stage: 'show' | 'create' | 'update';\n data: any;\n};\n\nexport type ReactAntResourceFormProps = {\n lang?: string;\n loading?: boolean;\n okText?: string;\n backText?: string;\n params?: Record<string, any>;\n disableHotkeySave?: boolean;\n transformRequest?: (payload: StagePayload) => any;\n transformResponse?: (res: StageData) => any;\n okProps?: ButtonProps;\n backProps?: ButtonProps;\n classNames?: CardProps['classNames'];\n size?: CardProps['size'];\n extra?: CardProps['extra'];\n title?: CardProps['title'];\n onInit?: (ctx: ReactAntResourceForm) => void;\n} & ReactAntdFormSchemaProps;\n\ntype IState = {\n loading: boolean;\n touched: boolean;\n};\n\nconst CLASS_NAME = 'react-ant-resource-form';\n\n/**\n * 当前 card loading 不要直接使用,因为这个 loading 会导致 Card 里的 formRef 被设置成 null\n * 这个情况仅在 class component 里才会出现,function component 里不会:\n * 报错示例:\n *\n * this.formRef?: null\n * index.tsx:229 this.formRef?: {getFieldValue: ƒ, getFieldsValue: ƒ, getFieldError: ƒ, getFieldWarning: ƒ, getFieldsError: ƒ, …}\n * index.tsx:229 this.formRef?: null\n */\n\nclass ReactAntResourceForm extends Component<ReactAntResourceFormProps, IState> {\n public static defaultProps = {\n lang: 'zh-CN',\n disableHotkeySave: false,\n };\n\n private formRef = React.createRef<FormInstance>(); // 注意类型\n private _isMounted = false;\n private _initialValues = null;\n\n get isEdit() {\n const { params } = this.props;\n return Boolean(params?.id);\n }\n\n get canSave() {\n const { touched, loading } = this.state;\n if (!this.isEdit) return loading === false;\n return touched === true && loading === false;\n }\n\n get titleView() {\n const { title } = this.props;\n const _title = title || (this.isEdit ? this.t('update_title') : this.t('create_title'));\n return (\n <Space>\n {_title}\n <span>{this.touchedView}</span>\n </Space>\n );\n }\n\n get touchedView() {\n if (!this.isEdit) return null;\n return this.state.touched ? (\n <em style={{ color: '#f60' }}>\n <DiffOutlined />\n </em>\n ) : null;\n }\n\n get extraView() {\n const { extra, backText, backProps } = this.props;\n if (extra) return extra;\n return (\n <Button size=\"small\" icon={<ArrowLeftOutlined />} onClick={this.handleBack} {...backProps}>\n {backText || this.t('back')}\n </Button>\n );\n }\n\n get childrenView() {\n const { okText, backText, okProps, backProps, children } = this.props;\n const _okText = okText || (this.isEdit ? this.t('update') : this.t('create'));\n if (children) return children;\n\n return (\n <Space>\n <Button\n disabled={!this.canSave}\n htmlType=\"submit\"\n type=\"primary\"\n icon={<SaveOutlined />}\n {...okProps}>\n {_okText || this.t('submit')}\n </Button>\n <Button icon={<ArrowLeftOutlined />} onClick={this.handleBack} {...backProps}>\n {backText || this.t('back')}\n </Button>\n </Space>\n );\n }\n\n get formInstance() {\n return this.formRef?.current;\n }\n\n constructor(props: ReactAntResourceFormProps) {\n super(props);\n this.state = {\n loading: false,\n touched: false,\n };\n\n this.handleStateRequest = this.handleStateRequest.bind(this);\n this.handleStateResponse = this.handleStateResponse.bind(this);\n this.initDetailIfNeeded = this.initDetailIfNeeded.bind(this);\n\n props.onInit?.(this);\n }\n\n private t(key: string) {\n const { lang } = this.props;\n return API_FORM_LOCALES[lang!][key];\n }\n\n private handleBack = () => {\n history.back();\n };\n\n handleStateRequest(stagePayload: StagePayload) {\n this.setState({ loading: true });\n return this.props.transformRequest?.(stagePayload) || stagePayload.payload;\n }\n\n handleStateResponse(res: StageData) {\n const { name } = this.props;\n this.setState({ loading: false });\n nx.$event?.emit?.(`${name}:refetch`);\n return this.props.transformResponse?.(res) || res.data;\n }\n\n handleFinish = (values: any) => {\n const { params, name } = this.props;\n const resourceEdit = `${name}_update`;\n const resourceCreate = `${name}_create`;\n\n if (this.isEdit) {\n const payload = { id: params!.id, ...values };\n const _payload = this.handleStateRequest({ stage: 'update', payload });\n\n nx.$api[resourceEdit](_payload)\n .then((res: any) => {\n message.success(this.t('update_success'));\n this.handleStateResponse({ stage: 'update', data: res });\n })\n .finally(() => {\n this.setState({ loading: false });\n this._initialValues = this.formInstance?.getFieldsValue() || {};\n this.handleValuesChange(null, this._initialValues);\n });\n } else {\n const payload = { ...values };\n const _payload = this.handleStateRequest({ stage: 'create', payload });\n\n nx.$api[resourceCreate](_payload)\n .then((res: any) => {\n message.success(this.t('create_success'));\n this.handleStateResponse({ stage: 'create', data: res });\n this.formInstance?.resetFields();\n history.back();\n })\n .finally(() => this.setState({ loading: false }));\n }\n };\n\n // hotkey save handler (replaces useKeyboardSave hook)\n handleKeydown = (e: KeyboardEvent) => {\n const { disableHotkeySave } = this.props;\n const isSave = (e.ctrlKey || e.metaKey) && (e.key === 's' || e.key === 'S');\n if (isSave) {\n e.preventDefault();\n if (!disableHotkeySave) {\n // submit the form via ref\n try {\n this.formInstance?.submit();\n } catch (err) {\n // ignore if submit not available yet\n }\n }\n }\n };\n\n handleValuesChange = (_: any, allValues: any) => {\n this.setState({\n touched: fde(this._initialValues, allValues) === false,\n });\n };\n\n componentDidMount() {\n this._isMounted = true;\n // attach hotkey listener\n window.addEventListener('keydown', this.handleKeydown);\n // initialize detail if editing\n this.initDetailIfNeeded();\n }\n\n componentDidUpdate(prevProps: ReactAntResourceFormProps) {\n const prevId = prevProps.params?.id;\n const curId = this.props.params?.id;\n // re-init when id changed or from create -> edit\n if (prevId !== curId) {\n this.initDetailIfNeeded();\n }\n }\n\n componentWillUnmount() {\n window.removeEventListener('keydown', this.handleKeydown);\n this._isMounted = false;\n }\n\n initDetailIfNeeded() {\n const { params, name } = this.props;\n const resourceShow = `${name}_show`;\n\n if (this.isEdit) {\n const payload = { id: params!.id };\n const _payload = this.handleStateRequest({ stage: 'show', payload });\n\n nx.$api[resourceShow](_payload)\n .then((res: any) => {\n if (!this._isMounted) return; // 👈 关键:防止操作已卸载组件\n const data = this.handleStateResponse({ stage: 'show', data: res });\n // set fields value on the form via ref\n try {\n this.formInstance?.setFieldsValue?.(data);\n } catch (err) {\n // ignore if not available yet\n }\n })\n .finally(() => {\n this.setState({ loading: false });\n this._initialValues = this.formInstance?.getFieldsValue() || {};\n });\n } else {\n this._initialValues = this.formInstance?.getFieldsValue() || {};\n }\n }\n\n render() {\n const {\n className,\n name,\n meta,\n children,\n lang,\n title,\n extra,\n size,\n okText,\n backText,\n okProps,\n backProps,\n classNames,\n params,\n transformRequest,\n transformResponse,\n disableHotkeySave,\n onInit,\n ...rest\n } = this.props;\n\n return (\n <Card\n title={this.titleView}\n extra={this.extraView}\n size={size}\n classNames={classNames}\n data-component={CLASS_NAME}\n className={cx(CLASS_NAME, className)}>\n <Spin spinning={this.state.loading}>\n <ReactAntdFormSchema\n meta={meta}\n ref={this.formRef}\n onValuesChange={this.handleValuesChange}\n onFinish={this.handleFinish}\n {...rest}>\n {this.childrenView}\n </ReactAntdFormSchema>\n </Spin>\n </Card>\n );\n }\n}\n\nconst ReactAntResourceFormFc: FC<ReactAntResourceFormProps> = (props) => {\n const params = useParams();\n return <ReactAntResourceForm params={params} {...props} />;\n};\n\nexport default ReactAntResourceForm;\nexport { ReactAntResourceFormFc };\n","export const API_FORM_LOCALES = {\n 'zh-CN': {\n create: '创建',\n update: '保存',\n create_title: '创建',\n update_title: '更新',\n create_success: '创建成功',\n update_success: '更新成功',\n submit: '提交',\n back: '返回',\n },\n 'en-US': {\n create: 'Create',\n update: 'Save',\n create_title: 'Create',\n update_title: 'Update',\n create_success: 'Create success',\n update_success: 'Update success',\n submit: 'Submit',\n back: 'Back',\n },\n};\n","import ReactAntResourceForm, { ReactAntResourceFormFc } from '.';\nimport type { ReactAntResourceFormProps } from '.';\n\nexport default ReactAntResourceForm;\nexport { ReactAntResourceFormFc };\nexport type { ReactAntResourceFormProps };\n"],"mappings":"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","names":["cx","React","Component","Button","Card","Space","message","Spin","ReactAntdFormSchema","ArrowLeftOutlined","DiffOutlined","SaveOutlined","API_FORM_LOCALES","create","update","create_title","update_title","create_success","update_success","submit","back","nx","useParams","fde","CLASS_NAME","_a","ReactAntResourceForm","Component","props","formRef","React","createRef","_isMounted","_initialValues","handleBack","__name","history","back","handleFinish","values","params","name","resourceEdit","resourceCreate","isEdit","payload","__spreadValues","id","_payload","handleStateRequest","stage","nx","$api","then","res","message","success","t","handleStateResponse","data","finally","setState","loading","formInstance","getFieldsValue","handleValuesChange","resetFields","handleKeydown","e","disableHotkeySave","ctrlKey","metaKey","key","preventDefault","submit","err","_","allValues","touched","fde","state","bind","initDetailIfNeeded","onInit","Boolean","canSave","titleView","title","_title","Space","span","touchedView","em","style","color","DiffOutlined","extraView","extra","backText","backProps","Button","size","icon","ArrowLeftOutlined","onClick","childrenView","okText","okProps","children","_okText","disabled","htmlType","type","SaveOutlined","current","lang","API_FORM_LOCALES","stagePayload","_b","transformRequest","_c","_d","$event","emit","transformResponse","componentDidMount","window","addEventListener","componentDidUpdate","prevProps","prevId","curId","componentWillUnmount","removeEventListener","resourceShow","setFieldsValue","render","className","meta","classNames","rest","Card","data-component","cx","Spin","spinning","ReactAntdFormSchema","ref","onValuesChange","onFinish","__publicField","defaultProps","ReactAntResourceFormFc","useParams","index_default","main_default","ReactAntResourceForm"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jswork/react-ant-resource-form",
3
- "version": "1.0.17",
3
+ "version": "1.0.19",
4
4
  "main": "dist/main.cjs.js",
5
5
  "module": "dist/main.esm.js",
6
6
  "types": "dist/main.d.ts",
@@ -16,10 +16,13 @@
16
16
  "postbuild": "postsass -s src/style.scss -d dist/style.css -c",
17
17
  "release": "release-it"
18
18
  },
19
+ "dependencies": {
20
+ "fast-deep-equal": "^3.1.3"
21
+ },
19
22
  "devDependencies": {
20
- "@jswork/react-ant-form-schema": "^1.0.21",
21
23
  "@ant-design/icons": "^6.1.0",
22
24
  "@jswork/next": "^1.4.2",
25
+ "@jswork/react-ant-form-schema": "^1.0.21",
23
26
  "@swc/core": "^1.3.93",
24
27
  "@types/react": "^18.2.28",
25
28
  "@types/react-dom": "^18.2.13",
@@ -29,14 +32,16 @@
29
32
  "cssnano": "^6.0.1",
30
33
  "react": "^18.2.0",
31
34
  "react-dom": "^18.2.0",
35
+ "react-router-dom": "^7.9.4",
32
36
  "tsup": "^8.2.4",
33
37
  "typescript": "^5.2.2"
34
38
  },
35
39
  "peerDependencies": {
36
40
  "@ant-design/icons": "*",
37
- "@jswork/react-ant-form-schema": "*",
38
41
  "@jswork/next": "*",
42
+ "@jswork/react-ant-form-schema": "*",
39
43
  "antd": "*",
44
+ "react-router-dom": "*",
40
45
  "classnames": "*",
41
46
  "react": "*",
42
47
  "react-dom": "*"
package/src/index.tsx CHANGED
@@ -1,12 +1,14 @@
1
1
  // import noop from '@jswork/noop';
2
2
  import cx from 'classnames';
3
- import React, { Component } from 'react';
3
+ import React, { Component, FC } from 'react';
4
4
  import { Button, ButtonProps, Card, CardProps, Space, message, Spin } from 'antd';
5
5
  import type { FormInstance } from 'antd';
6
6
  import ReactAntdFormSchema, { ReactAntdFormSchemaProps } from '@jswork/react-ant-form-schema';
7
- import { ArrowLeftOutlined, SaveOutlined } from '@ant-design/icons';
7
+ import { ArrowLeftOutlined, DiffOutlined, SaveOutlined } from '@ant-design/icons';
8
8
  import { API_FORM_LOCALES } from './locales';
9
9
  import nx from '@jswork/next';
10
+ import { useParams } from 'react-router-dom';
11
+ import fde from 'fast-deep-equal';
10
12
 
11
13
  declare global {
12
14
  interface NxStatic {
@@ -40,10 +42,12 @@ export type ReactAntResourceFormProps = {
40
42
  size?: CardProps['size'];
41
43
  extra?: CardProps['extra'];
42
44
  title?: CardProps['title'];
45
+ onInit?: (ctx: ReactAntResourceForm) => void;
43
46
  } & ReactAntdFormSchemaProps;
44
47
 
45
48
  type IState = {
46
49
  loading: boolean;
50
+ touched: boolean;
47
51
  };
48
52
 
49
53
  const CLASS_NAME = 'react-ant-resource-form';
@@ -66,15 +70,37 @@ class ReactAntResourceForm extends Component<ReactAntResourceFormProps, IState>
66
70
 
67
71
  private formRef = React.createRef<FormInstance>(); // 注意类型
68
72
  private _isMounted = false;
73
+ private _initialValues = null;
69
74
 
70
75
  get isEdit() {
71
76
  const { params } = this.props;
72
77
  return Boolean(params?.id);
73
78
  }
74
79
 
80
+ get canSave() {
81
+ const { touched, loading } = this.state;
82
+ if (!this.isEdit) return loading === false;
83
+ return touched === true && loading === false;
84
+ }
85
+
75
86
  get titleView() {
76
87
  const { title } = this.props;
77
- return title || (this.isEdit ? this.t('update_title') : this.t('create_title'));
88
+ const _title = title || (this.isEdit ? this.t('update_title') : this.t('create_title'));
89
+ return (
90
+ <Space>
91
+ {_title}
92
+ <span>{this.touchedView}</span>
93
+ </Space>
94
+ );
95
+ }
96
+
97
+ get touchedView() {
98
+ if (!this.isEdit) return null;
99
+ return this.state.touched ? (
100
+ <em style={{ color: '#f60' }}>
101
+ <DiffOutlined />
102
+ </em>
103
+ ) : null;
78
104
  }
79
105
 
80
106
  get extraView() {
@@ -94,7 +120,12 @@ class ReactAntResourceForm extends Component<ReactAntResourceFormProps, IState>
94
120
 
95
121
  return (
96
122
  <Space>
97
- <Button htmlType="submit" type="primary" icon={<SaveOutlined />} {...okProps}>
123
+ <Button
124
+ disabled={!this.canSave}
125
+ htmlType="submit"
126
+ type="primary"
127
+ icon={<SaveOutlined />}
128
+ {...okProps}>
98
129
  {_okText || this.t('submit')}
99
130
  </Button>
100
131
  <Button icon={<ArrowLeftOutlined />} onClick={this.handleBack} {...backProps}>
@@ -112,11 +143,14 @@ class ReactAntResourceForm extends Component<ReactAntResourceFormProps, IState>
112
143
  super(props);
113
144
  this.state = {
114
145
  loading: false,
146
+ touched: false,
115
147
  };
116
148
 
117
149
  this.handleStateRequest = this.handleStateRequest.bind(this);
118
150
  this.handleStateResponse = this.handleStateResponse.bind(this);
119
151
  this.initDetailIfNeeded = this.initDetailIfNeeded.bind(this);
152
+
153
+ props.onInit?.(this);
120
154
  }
121
155
 
122
156
  private t(key: string) {
@@ -154,7 +188,11 @@ class ReactAntResourceForm extends Component<ReactAntResourceFormProps, IState>
154
188
  message.success(this.t('update_success'));
155
189
  this.handleStateResponse({ stage: 'update', data: res });
156
190
  })
157
- .finally(() => this.setState({ loading: false }));
191
+ .finally(() => {
192
+ this.setState({ loading: false });
193
+ this._initialValues = this.formInstance?.getFieldsValue() || {};
194
+ this.handleValuesChange(null, this._initialValues);
195
+ });
158
196
  } else {
159
197
  const payload = { ...values };
160
198
  const _payload = this.handleStateRequest({ stage: 'create', payload });
@@ -172,10 +210,11 @@ class ReactAntResourceForm extends Component<ReactAntResourceFormProps, IState>
172
210
 
173
211
  // hotkey save handler (replaces useKeyboardSave hook)
174
212
  handleKeydown = (e: KeyboardEvent) => {
213
+ const { disableHotkeySave } = this.props;
175
214
  const isSave = (e.ctrlKey || e.metaKey) && (e.key === 's' || e.key === 'S');
176
215
  if (isSave) {
177
216
  e.preventDefault();
178
- if (!this.props.disableHotkeySave) {
217
+ if (!disableHotkeySave) {
179
218
  // submit the form via ref
180
219
  try {
181
220
  this.formInstance?.submit();
@@ -186,6 +225,12 @@ class ReactAntResourceForm extends Component<ReactAntResourceFormProps, IState>
186
225
  }
187
226
  };
188
227
 
228
+ handleValuesChange = (_: any, allValues: any) => {
229
+ this.setState({
230
+ touched: fde(this._initialValues, allValues) === false,
231
+ });
232
+ };
233
+
189
234
  componentDidMount() {
190
235
  this._isMounted = true;
191
236
  // attach hotkey listener
@@ -227,7 +272,12 @@ class ReactAntResourceForm extends Component<ReactAntResourceFormProps, IState>
227
272
  // ignore if not available yet
228
273
  }
229
274
  })
230
- .finally(() => this.setState({ loading: false }));
275
+ .finally(() => {
276
+ this.setState({ loading: false });
277
+ this._initialValues = this.formInstance?.getFieldsValue() || {};
278
+ });
279
+ } else {
280
+ this._initialValues = this.formInstance?.getFieldsValue() || {};
231
281
  }
232
282
  }
233
283
 
@@ -250,6 +300,7 @@ class ReactAntResourceForm extends Component<ReactAntResourceFormProps, IState>
250
300
  transformRequest,
251
301
  transformResponse,
252
302
  disableHotkeySave,
303
+ onInit,
253
304
  ...rest
254
305
  } = this.props;
255
306
 
@@ -265,6 +316,7 @@ class ReactAntResourceForm extends Component<ReactAntResourceFormProps, IState>
265
316
  <ReactAntdFormSchema
266
317
  meta={meta}
267
318
  ref={this.formRef}
319
+ onValuesChange={this.handleValuesChange}
268
320
  onFinish={this.handleFinish}
269
321
  {...rest}>
270
322
  {this.childrenView}
@@ -275,4 +327,10 @@ class ReactAntResourceForm extends Component<ReactAntResourceFormProps, IState>
275
327
  }
276
328
  }
277
329
 
330
+ const ReactAntResourceFormFc: FC<ReactAntResourceFormProps> = (props) => {
331
+ const params = useParams();
332
+ return <ReactAntResourceForm params={params} {...props} />;
333
+ };
334
+
278
335
  export default ReactAntResourceForm;
336
+ export { ReactAntResourceFormFc };
package/src/main.tsx CHANGED
@@ -1,5 +1,6 @@
1
- import ReactAntResourceForm from '.';
1
+ import ReactAntResourceForm, { ReactAntResourceFormFc } from '.';
2
2
  import type { ReactAntResourceFormProps } from '.';
3
3
 
4
4
  export default ReactAntResourceForm;
5
+ export { ReactAntResourceFormFc };
5
6
  export type { ReactAntResourceFormProps };
package/src/hooks.ts DELETED
@@ -1,27 +0,0 @@
1
- import { useEffect, useCallback } from 'react';
2
-
3
- /**
4
- * 这个Hook此项目已经用不到了,不过,如果后面当前组件需要改写成 functional 的形式,需要用到
5
- * 暂时可以保留
6
- * @param callback
7
- */
8
-
9
- export const useKeyboardSave = (callback: (e: KeyboardEvent) => void) => {
10
- const handler = useCallback(
11
- (e: KeyboardEvent) => {
12
- // 使用 code 更可靠(不受键盘布局或大小写影响)
13
- if ((e.ctrlKey || e.metaKey) && e.code === 'KeyS') {
14
- e.preventDefault();
15
- callback(e);
16
- }
17
- },
18
- [callback] // 确保 handler 随 callback 更新而更新
19
- );
20
-
21
- useEffect(() => {
22
- document.addEventListener('keydown', handler);
23
- return () => {
24
- document.removeEventListener('keydown', handler);
25
- };
26
- }, [handler]); // handler 是 useCallback 包装的,稳定依赖
27
- };