zarm-web
Version:
基于 React 的桌面端UI库
255 lines (222 loc) • 6.53 kB
JavaScript
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import React, { PureComponent, createRef } from 'react';
import PropTypes from 'prop-types';
import Schema from 'async-validator';
import classnames from 'classnames';
import { FormContext, FormItemContext } from './createContext';
import Icon from '../icon';
import { noop } from '../utils';
import Transition from '../transition';
Schema.warning = noop;
class FormItem extends PureComponent {
constructor(props) {
super(props);
this.initialData = void 0;
this.validateMessage = void 0;
this.formItemInstance = void 0;
this.handleFieldBlur = () => {
Promise.resolve('blur').then(this.validateItem.bind(this));
};
this.handleFieldChange = () => {
Promise.resolve('change').then(this.validateItem.bind(this));
};
this.formItemInstance = createRef();
this.validateMessage = '';
this.state = {
validateStatus: ''
};
}
componentDidMount() {
this.initialData = this.recordInitialData();
this.addFormItem();
}
componentWillUnmount() {
this.removeFormItem();
}
get fieldValue() {
const {
model
} = this.context;
const {
prop
} = this.props;
const propArr = prop.split('.');
return propArr.length > 1 ? model[propArr[0]][propArr[1]] : model[prop];
}
getRules() {
const {
rules,
prop
} = this.props;
const {
rules: contextRules
} = this.context;
let formRules = contextRules;
const formItemRules = rules;
formRules = formRules ? formRules[prop] : [];
return [].concat(formItemRules || formRules || []);
}
getFilteredRules(trigger) {
const rules = this.getRules();
const filteredRules = rules.filter(rule => !rule.trigger || rule.trigger.includes(trigger));
return filteredRules;
}
getId() {
const {
children
} = this.props;
if (children.props) {
return children.props.id;
}
}
getControlNode() {
return this.formItemInstance.current;
}
validateItem(trigger, callback = () => {}) {
const {
prop
} = this.props;
const rules = this.getFilteredRules(trigger);
if (!rules || rules.length === 0) {
return true;
}
const descriptor = {
[prop]: rules
};
const validator = new Schema(descriptor);
const model = {
[prop]: this.fieldValue
};
validator.validate(model, {
firstFields: true
}, errors => {
this.validateMessage = errors ? errors[0].message : '';
this.setState({
validateStatus: !errors ? 'success' : 'error'
}, () => {
callback(this.validateMessage);
});
});
}
resetItem() {
const {
prop
} = this.props;
const {
model
} = this.context;
this.setState({
validateStatus: ''
});
this.validateMessage = '';
if (Array.isArray(this.fieldValue) && this.fieldValue.length > 0) {
model[prop] = [];
} else {
model[prop] = this.initialData;
}
}
recordInitialData() {
const {
model
} = this.context;
if (!model) {
return;
}
const {
prop
} = this.props;
const value = model[prop];
return value === undefined ? undefined : JSON.parse(JSON.stringify(value));
}
addFormItem() {
const {
fields
} = this.context;
if (this.props.prop) {
fields.push(this);
}
}
removeFormItem() {
const {
fields
} = this.context;
if (this.props.prop) {
const index = fields.indexOf(this);
fields.splice(index, 1);
}
}
renderLabel() {
const {
id,
label,
prefixCls,
prop,
rules,
required
} = this.props;
const {
labelWidth
} = this.context;
const styleObj = {};
const star = required || prop || rules ? React.createElement("span", {
className: `${prefixCls}-item--required`
}, React.createElement(Icon, {
type: "required"
})) : null;
if (labelWidth) {
styleObj.width = parseInt(labelWidth, 10);
}
return 'label' in this.props ? React.createElement("label", {
className: "za-form-item__label",
style: _objectSpread({}, styleObj),
htmlFor: id || this.getId()
}, star, label) : null;
}
render() {
const {
validateStatus
} = this.state;
const {
className,
children,
style,
prefixCls
} = this.props;
const cls = classnames({
[`${prefixCls}-item`]: true,
'has-error': validateStatus === 'error',
[className]: !!className
});
const controlCls = classnames({
[`${prefixCls}-item__control`]: true
});
return React.createElement(FormItemContext.Provider, {
value: this
}, React.createElement("div", {
className: cls,
style: style,
ref: this.formItemInstance
}, this.renderLabel(), React.createElement("div", {
className: controlCls,
onBlur: this.handleFieldBlur,
onChange: this.handleFieldChange
}, children, React.createElement(Transition, {
name: "scaleDown",
visible: validateStatus === 'error'
}, React.createElement("div", {
className: `${prefixCls}-item__error`
}, this.validateMessage)))));
}
}
FormItem.contextType = FormContext;
FormItem.defaultProps = {
prefixCls: 'za-form',
required: false
};
FormItem.propTypes = {
prefixCls: PropTypes.string,
required: PropTypes.bool
};
export default FormItem;