@alifd/next
Version:
A configurable component library for web built on React.
293 lines (292 loc) • 14.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var react_1 = tslib_1.__importStar(require("react"));
var prop_types_1 = tslib_1.__importDefault(require("prop-types"));
var classnames_1 = tslib_1.__importDefault(require("classnames"));
var grid_1 = tslib_1.__importDefault(require("../grid"));
var responsive_grid_1 = tslib_1.__importDefault(require("../responsive-grid"));
var util_1 = require("../util");
var error_1 = tslib_1.__importDefault(require("./error"));
var enhance_1 = require("./enhance");
var Row = grid_1.default.Row, Col = grid_1.default.Col;
var Cell = responsive_grid_1.default.Cell;
var isNil = util_1.obj.isNil;
var Item = /** @class */ (function (_super) {
tslib_1.__extends(Item, _super);
function Item() {
return _super !== null && _super.apply(this, arguments) || this;
}
/**
* 从子元素里面提取表单组件。TODO: 2.x 中改为只获取一个元素
*/
Item.prototype.getNames = function (children) {
var name = this.props.name;
var childrenList = react_1.Children.toArray(children);
var nameList = childrenList
.filter(function (c) {
return c.props && ('name' in c.props || 'data-meta' in c.props);
})
.map(function (c) {
return c.props.name || c.props.id;
});
if (nameList.length) {
return nameList;
}
else if (name) {
return [name];
}
return [];
};
Item.prototype.getHelper = function (children) {
var _a = this.props, help = _a.help, preferMarginToDisplayHelp = _a.preferMarginToDisplayHelp;
var _b = this.context, _formField = _b._formField, _formMarginToDisplayHelp = _b._formMarginToDisplayHelp;
var useMargin = typeof preferMarginToDisplayHelp !== 'undefined'
? preferMarginToDisplayHelp
: _formMarginToDisplayHelp;
return (react_1.default.createElement(error_1.default, { name: help === undefined ? this.getNames(children) : undefined, field: _formField, preferMarginToDisplayHelp: useMargin }, help));
};
Item.prototype.getState = function (children) {
var validateState = this.props.validateState;
if (validateState) {
return validateState;
}
if (this.context._formField) {
var getState = this.context._formField.getState;
var names = this.getNames(children);
if (!names.length) {
return '';
}
// get first name
return getState(names[0]);
}
return undefined;
};
Item.prototype.getSize = function () {
return this.props.size || this.context._formSize;
};
Item.prototype.getDisabled = function () {
return 'disabled' in this.props ? this.props.disabled : this.context._formDisabled;
};
Item.prototype.getIsPreview = function () {
return 'isPreview' in this.props ? this.props.isPreview : this.context._formPreview;
};
Item.prototype.getFullWidth = function () {
return isNil(this.props.fullWidth) ? !!this.context._formFullWidth : this.props.fullWidth;
};
Item.prototype.getLabelForErrorMessage = function () {
var _a = this.props, errorMessageName = _a.errorMessageName, label = _a.label, useLabelForErrorMessage = _a.useLabelForErrorMessage;
if (errorMessageName) {
return errorMessageName;
}
if (!label || typeof label !== 'string') {
return null;
}
var newLabel = label.replace(':', '').replace(':', '');
var labelForErrorMessage = useLabelForErrorMessage !== undefined
? useLabelForErrorMessage
: this.context._formLabelForErrorMessage;
if (labelForErrorMessage && newLabel) {
return newLabel;
}
return null;
};
Item.prototype.getItemLabel = function (children) {
var _a;
var _b = this.props, id = _b.id, required = _b.required, _c = _b.asterisk, asterisk = _c === void 0 ? required : _c, label = _b.label, labelCol = _b.labelCol, wrapperCol = _b.wrapperCol, prefix = _b.prefix, responsive = _b.responsive, labelWidth = _b.labelWidth, labelTextAlign = _b.labelTextAlign, colon = _b.colon;
var labelAlign = this.getLabelAlign(this.props.labelAlign, this.props.device);
if (!label) {
return null;
}
var ele = (
// @ts-expect-error label 上不存在 required,所以会有 TS 报错
react_1.default.createElement("label", { htmlFor: id || this.getNames(children)[0], required: asterisk, key: "label" }, label));
var cls = (0, classnames_1.default)((_a = {},
_a["".concat(prefix, "form-item-label")] = true,
_a['has-colon'] = colon,
_a["".concat(prefix, "left")] = labelTextAlign === 'left',
_a));
if (responsive && labelWidth && labelAlign !== 'top') {
return (react_1.default.createElement("div", { className: cls, style: { width: labelWidth } }, ele));
}
if ((wrapperCol || labelCol) && labelAlign !== 'top') {
return (react_1.default.createElement(Col, tslib_1.__assign({}, labelCol, { className: cls }), ele));
}
return react_1.default.createElement("div", { className: cls }, ele);
};
Item.prototype.getItemWrapper = function (children) {
var _this = this;
var _a = this.props, hasFeedback = _a.hasFeedback, labelCol = _a.labelCol, wrapperCol = _a.wrapperCol, extra = _a.extra, prefix = _a.prefix, renderPreview = _a.renderPreview, name = _a.name;
var labelAlign = this.getLabelAlign(this.props.labelAlign, this.props.device);
var state = this.getState(children);
var isPreview = this.getIsPreview();
var childrenProps = {
size: this.getSize(),
};
if (isPreview) {
childrenProps.isPreview = true;
}
if ('renderPreview' in this.props && typeof renderPreview === 'function') {
childrenProps.renderPreview = renderPreview;
}
if (state && (state === 'error' || hasFeedback)) {
childrenProps.state = state;
}
if (labelAlign === 'inset') {
childrenProps.label = this.getItemLabel(children);
}
if (this.getDisabled()) {
childrenProps.disabled = true;
}
var labelForErrorMessage = this.getLabelForErrorMessage();
var ele = react_1.Children.map(children, function (child, idx) {
if (child &&
['function', 'object'].indexOf(typeof child.type) > -1 &&
child.type._typeMark !== 'form_item' &&
child.type._typeMark !== 'form_error') {
var extraProps = childrenProps;
// 自己直接使用 field.init 会在 props 上面留下 data-meta
// name 挪到 FormItem 上面,默认把第一个元素当做 Form 组件
if (_this.context._formField &&
!('data-meta' in child.props) &&
('name' in child.props || (name && idx === 0)) //TODO:1.x 为了不 BR, 2.x 中把优先级调换下,优先取 FormItem 的 name
) {
var initName = 'name' in child.props && child.props.name ? child.props.name : name;
extraProps = _this.context._formField.init(initName, tslib_1.__assign(tslib_1.__assign({}, (0, enhance_1.getFieldInitCfg)(_this.props, child.type.displayName, labelForErrorMessage)), { props: tslib_1.__assign(tslib_1.__assign({}, child.props), { ref: child.ref }) }), childrenProps);
}
else {
extraProps = Object.assign({}, child.props, extraProps);
}
return (0, react_1.cloneElement)(child, extraProps);
}
return child;
});
var help = this.getHelper(children);
if ((wrapperCol || labelCol) && labelAlign !== 'top') {
return (react_1.default.createElement(Col, tslib_1.__assign({}, wrapperCol, { className: "".concat(prefix, "form-item-control"), key: "item" }),
ele,
" ",
help,
" ",
extra));
}
return (react_1.default.createElement("div", { className: "".concat(prefix, "form-item-control") },
ele,
" ",
help,
" ",
extra));
};
Item.prototype.getLabelAlign = function (labelAlign, device) {
if (device === 'phone') {
return 'top';
}
return labelAlign;
};
Item.prototype.render = function () {
var _a;
var _b = this.props, className = _b.className, style = _b.style, prefix = _b.prefix, wrapperCol = _b.wrapperCol, labelCol = _b.labelCol, responsive = _b.responsive, children = _b.children;
var labelAlign = this.getLabelAlign(this.props.labelAlign, this.props.device);
var childrenNode = children;
if (typeof children === 'function' && this.context._formField) {
childrenNode = children(this.context._formField.getValues());
}
var state = this.getState(childrenNode);
var size = this.getSize();
var fullWidth = this.getFullWidth();
var isPreview = this.getIsPreview();
var itemClassName = (0, classnames_1.default)((_a = {},
_a["".concat(prefix, "form-item")] = true,
_a["".concat(prefix).concat(labelAlign)] = labelAlign,
_a["has-".concat(state)] = !!state,
_a["".concat(prefix).concat(size)] = !!size,
_a["".concat(prefix, "form-item-fullwidth")] = fullWidth,
_a["".concat(className)] = !!className,
_a["".concat(prefix, "form-preview")] = isPreview,
_a));
// 垂直模式并且左对齐才用到
var Tag = responsive
? Cell
: (wrapperCol || labelCol) && labelAlign !== 'top'
? Row
: 'div';
var label = labelAlign === 'inset' ? null : this.getItemLabel(childrenNode);
return (react_1.default.createElement(Tag, tslib_1.__assign({}, util_1.obj.pickOthers(Item.propTypes, this.props), { className: itemClassName, style: style }),
label,
this.getItemWrapper(childrenNode)));
};
Item.displayName = 'Item';
Item.propTypes = {
prefix: prop_types_1.default.string,
rtl: prop_types_1.default.bool,
label: prop_types_1.default.node,
labelCol: prop_types_1.default.object,
wrapperCol: prop_types_1.default.object,
help: prop_types_1.default.node,
name: prop_types_1.default.string,
extra: prop_types_1.default.node,
validateState: prop_types_1.default.oneOf(['error', 'success', 'loading', 'warning']),
hasFeedback: prop_types_1.default.bool, //TODO: hasFeedback => validateStatus=[error,success,loading]
style: prop_types_1.default.object,
id: prop_types_1.default.string,
children: prop_types_1.default.oneOfType([prop_types_1.default.node, prop_types_1.default.func]),
size: prop_types_1.default.oneOf(['large', 'small', 'medium']),
fullWidth: prop_types_1.default.bool,
labelAlign: prop_types_1.default.oneOf(['top', 'left', 'inset']),
labelTextAlign: prop_types_1.default.oneOf(['left', 'right']),
className: prop_types_1.default.string,
required: prop_types_1.default.bool,
asterisk: prop_types_1.default.bool,
requiredMessage: prop_types_1.default.string,
requiredTrigger: prop_types_1.default.oneOfType([prop_types_1.default.string, prop_types_1.default.array]),
min: prop_types_1.default.number,
max: prop_types_1.default.number,
minmaxMessage: prop_types_1.default.string,
minmaxTrigger: prop_types_1.default.oneOfType([prop_types_1.default.string, prop_types_1.default.array]),
minLength: prop_types_1.default.number,
maxLength: prop_types_1.default.number,
minmaxLengthMessage: prop_types_1.default.string,
minmaxLengthTrigger: prop_types_1.default.oneOfType([prop_types_1.default.string, prop_types_1.default.array]),
length: prop_types_1.default.number,
lengthMessage: prop_types_1.default.string,
lengthTrigger: prop_types_1.default.oneOfType([prop_types_1.default.string, prop_types_1.default.array]),
pattern: prop_types_1.default.any,
patternMessage: prop_types_1.default.string,
patternTrigger: prop_types_1.default.oneOfType([prop_types_1.default.string, prop_types_1.default.array]),
format: prop_types_1.default.oneOf(['number', 'email', 'url', 'tel']),
formatMessage: prop_types_1.default.string,
formatTrigger: prop_types_1.default.oneOfType([prop_types_1.default.string, prop_types_1.default.array]),
validator: prop_types_1.default.func,
validatorTrigger: prop_types_1.default.oneOfType([prop_types_1.default.string, prop_types_1.default.array]),
autoValidate: prop_types_1.default.bool,
device: prop_types_1.default.oneOf(['phone', 'tablet', 'desktop']),
responsive: prop_types_1.default.bool,
colSpan: prop_types_1.default.number,
labelWidth: prop_types_1.default.oneOfType([prop_types_1.default.string, prop_types_1.default.number]),
isPreview: prop_types_1.default.bool,
renderPreview: prop_types_1.default.func,
errorMessageName: prop_types_1.default.string,
useLabelForErrorMessage: prop_types_1.default.bool,
preferMarginToDisplayHelp: prop_types_1.default.bool,
colon: prop_types_1.default.bool,
disabled: prop_types_1.default.bool,
valueName: prop_types_1.default.string,
};
Item.defaultProps = {
prefix: 'next-',
hasFeedback: false,
labelWidth: 100,
};
Item.contextTypes = {
_formField: prop_types_1.default.object,
_formSize: prop_types_1.default.oneOf(['large', 'small', 'medium']),
_formDisabled: prop_types_1.default.bool,
_formPreview: prop_types_1.default.bool,
_formFullWidth: prop_types_1.default.bool,
_formLabelForErrorMessage: prop_types_1.default.bool,
_formMarginToDisplayHelp: prop_types_1.default.bool,
};
Item._typeMark = 'form_item';
return Item;
}(react_1.Component));
exports.default = Item;