UNPKG

@mijadesign/mjui-react-taro

Version:

京东风格的轻量级移动端 React 组件库,支持一套代码生成 H5 和小程序

440 lines (439 loc) 16.4 kB
import { a as __awaiter, _ as __rest } from "./tslib.es6-iWu3F_1J.js"; import React, { useRef, createContext, useContext as useContext$1 } from "react"; import { Text, View } from "@tarojs/components"; import classNames from "classnames"; import { merge, recursive, toArray } from "@nutui/nutui-react-taro"; import { Context as Context$1 } from "@nutui/nutui-react-taro/dist/es/packages/form/context"; import { C as Cell } from "./cell.taro-DwViuoF7.js"; import { C as ComponentDefaults } from "./typings-DV9RBfhj.js"; import Schema from "async-validator"; function isForwardRefComponent(component) { return component.type && component.type.$$typeof && // eslint-disable-next-line react/display-name React.forwardRef( // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore () => { } ).$$typeof === component.type.$$typeof; } const SECRET = "NUT_FORM_INTERNAL"; class FormStore { constructor() { this.initialValues = {}; this.updateList = []; this.store = {}; this.fieldEntities = []; this.callbacks = {}; this.errors = {}; this.registerField = (field) => { this.fieldEntities.push(field); return () => { this.fieldEntities = this.fieldEntities.filter((item) => item !== field); }; }; this.getFieldValue = (name) => { var _a; return (_a = this.store) === null || _a === void 0 ? void 0 : _a[name]; }; this.getFieldsValue = (nameList, filterFunc) => { let names; if (nameList === true) { names = this.fieldEntities.map((e) => { var _a; return (_a = e === null || e === void 0 ? void 0 : e.props) === null || _a === void 0 ? void 0 : _a.name; }).filter((n) => n !== void 0); } else if (Array.isArray(nameList)) { names = nameList; } else { names = Object.keys(this.store); } const result = {}; const mountedNameSet = new Set(this.fieldEntities.map((e) => { var _a; return (_a = e === null || e === void 0 ? void 0 : e.props) === null || _a === void 0 ? void 0 : _a.name; }).filter((n) => n !== void 0)); names.forEach((name) => { const value = this.store[name]; if (filterFunc) { const meta = { name, value, mounted: mountedNameSet.has(name) }; if (!filterFunc(meta)) return; } result[name] = value; }); return result; }; this.setInitialValues = (initialValues, init) => { this.initialValues = initialValues || {}; if (init) { const nextStore = merge(initialValues, this.store); this.updateStore(nextStore); this.notifyWatch(); } }; this.setFieldsValue = (newStore) => { const nextStore = recursive(true, this.store, newStore); this.updateStore(nextStore); this.fieldEntities.forEach((entity) => { const { name } = entity.props; Object.keys(newStore).forEach((key) => { if (key === name) { entity.onStoreChange("update"); } }); }); this.updateList.forEach((item) => { let shouldUpdate = item.condition; if (typeof item.condition === "function") { shouldUpdate = item.condition(); } if (shouldUpdate) { item.entity.onStoreChange("update"); } }); this.notifyWatch(); }; this.setFieldValue = (name, value) => { const store = { [name]: value }; this.setFieldsValue(store); this.notifyWatch([name]); }; this.setCallback = (callback) => { this.callbacks = Object.assign(Object.assign({}, this.callbacks), callback); }; this.validateEntities = (entity, errs) => __awaiter(this, void 0, void 0, function* () { var _a; const { name, rules = [] } = entity.props; if (!name) { console.warn("Form field missing name property"); return; } const descriptor = {}; if (rules.length) { if (rules.length > 1) { descriptor[name] = []; rules.forEach((v) => { descriptor[name].push(v); }); } else { descriptor[name] = rules[0]; } } const validator = new Schema(descriptor); try { yield validator.validate({ [name]: (_a = this.store) === null || _a === void 0 ? void 0 : _a[name] }); } catch ({ errors }) { if (errors) { errs.push(...errors); this.errors[name] = errors; } } finally { if (!errs || errs.length === 0) { this.errors[name] = []; } } entity.onStoreChange("validate"); }); this.validateFields = (nameList) => __awaiter(this, void 0, void 0, function* () { let filterEntities = []; if (!nameList || nameList.length === 0) { filterEntities = this.fieldEntities; } else { filterEntities = this.fieldEntities.filter(({ props: { name } }) => nameList.includes(name)); } const errs = []; yield Promise.all(filterEntities.map((entity) => __awaiter(this, void 0, void 0, function* () { yield this.validateEntities(entity, errs); }))); return errs; }); this.submit = () => __awaiter(this, void 0, void 0, function* () { var _a, _b, _c, _d; const errors = yield this.validateFields(); if (errors.length === 0) { (_b = (_a = this.callbacks).onFinish) === null || _b === void 0 ? void 0 : _b.call(_a, this.store); } else if (errors.length > 0) { (_d = (_c = this.callbacks).onFinishFailed) === null || _d === void 0 ? void 0 : _d.call(_c, this.store, errors); } }); this.resetFields = (namePaths) => { if (namePaths && namePaths.length) { namePaths.forEach((path) => { this.errors[path] = null; this.fieldEntities.forEach((entity) => { const name = entity.props.name; if (name === path) { if (path in this.initialValues) { this.updateStore({ [path]: this.initialValues[path] }); } else { delete this.store[path]; } entity.onStoreChange("reset"); } }); }); } else { const nextStore = merge({}, this.initialValues); this.updateStore(nextStore); this.fieldEntities.forEach((entity) => { entity.onStoreChange("reset"); }); } }; this.registerUpdate = (field, shouldUpdate) => { this.updateList.push({ entity: field, condition: shouldUpdate }); return () => { this.updateList = this.updateList.filter((i) => i.entity !== field); }; }; this.dispatch = ({ name }) => { this.validateFields([name]); }; this.getInternal = (key) => { if (key === SECRET) { return { registerField: this.registerField, setCallback: this.setCallback, setInitialValues: this.setInitialValues, dispatch: this.dispatch, store: this.store, fieldEntities: this.fieldEntities, registerUpdate: this.registerUpdate, registerWatch: this.registerWatch }; } }; this.getForm = () => { return { getFieldValue: this.getFieldValue, getFieldsValue: this.getFieldsValue, setFieldsValue: this.setFieldsValue, setFieldValue: this.setFieldValue, resetFields: this.resetFields, validateFields: this.validateFields, submit: this.submit, errors: this.errors, getInternal: this.getInternal }; }; this.watchList = []; this.registerWatch = (callback) => { this.watchList.push(callback); return () => { this.watchList = this.watchList.filter((fn) => fn !== callback); }; }; this.notifyWatch = (namePath = []) => { if (this.watchList.length) { let allValues; if (!namePath || namePath.length === 0) { allValues = this.getFieldsValue(true); } else { allValues = this.getFieldsValue(namePath); } this.watchList.forEach((callback) => { callback(allValues, namePath); }); } }; this.callbacks = { onFinish: () => { }, onFinishFailed: () => { } }; } updateStore(nextStore) { this.store = nextStore; } } const useForm = (form) => { const formRef = useRef(); if (!formRef.current) { if (form) { formRef.current = form; } else { const formStore = new FormStore(); formRef.current = formStore.getForm(); } } return [formRef.current]; }; const defaultProps = Object.assign(Object.assign({}, ComponentDefaults), { required: false, name: "", label: "", rules: [{ required: false, message: "" }], errorMessageAlign: "left", shouldUpdate: false, noStyle: false }); let FormItem$1 = class FormItem extends React.Component { constructor(props) { super(props); this.getControlled = (children) => { var _a; const { setFieldsValue, getFieldValue } = this.context.formInstance; const { dispatch } = this.context.formInstance.getInternal(SECRET); const { name = "" } = this.props; if ((_a = children === null || children === void 0 ? void 0 : children.props) === null || _a === void 0 ? void 0 : _a.defaultValue) { if (process.env.NODE_ENV !== "production") { console.warn("[NutUI] FormItem:", "请通过 initialValue 设置初始值,而不是 defaultValue"); } } const fieldValue = getFieldValue(name); const controlled = Object.assign(Object.assign({}, children.props), { className: children.props.className, [this.props.valuePropName || "value"]: fieldValue !== void 0 ? fieldValue : this.props.initialValue, [this.props.trigger || "onChange"]: (...args) => { const originOnChange = children.props[this.props.trigger || "onChange"]; if (originOnChange) { originOnChange(...args); } let [next] = args; if (this.props.getValueFromEvent) { next = this.props.getValueFromEvent(...args); } setFieldsValue({ [name]: next }); } }); const { validateTrigger } = this.props; const mergedValidateTrigger = validateTrigger || this.context.validateTrigger; const validateTriggers = toArray(mergedValidateTrigger); validateTriggers.forEach((trigger) => { const originTrigger = controlled[trigger]; controlled[trigger] = (...args) => { if (originTrigger) { originTrigger(...args); } if (this.props.rules && this.props.rules.length) { dispatch({ name: this.props.name }); } }; }); if (isForwardRefComponent(children)) { controlled.ref = (componentInstance) => { const originRef = children.ref; if (originRef) { if (typeof originRef === "function") { originRef(componentInstance); } if ("current" in originRef) { originRef.current = componentInstance; } } this.componentRef = componentInstance; }; } return controlled; }; this.refresh = () => { this.setState(({ resetCount }) => ({ resetCount: resetCount + 1 })); }; this.onStoreChange = (type) => { if (type === "reset") { this.context.formInstance.errors[this.props.name] = []; this.refresh(); } else { this.forceUpdate(); } }; this.renderLayout = (childNode) => { var _a; const { label, name, required, rules, className, style, errorMessageAlign, align } = Object.assign(Object.assign({}, defaultProps), this.props); const requiredInRules = rules === null || rules === void 0 ? void 0 : rules.some((rule) => rule.required); const item = name ? this.context.formInstance.errors[name] : []; const { starPosition } = this.context.formInstance; const renderStar = (required || requiredInRules) && React.createElement(Text, { className: "nut-form-item-label-required required" }, "*"); const renderLabel = React.createElement( React.Fragment, null, React.createElement( "div", { className: "nut-form-item-labeltxt" }, starPosition === "left" ? renderStar : null, label ), starPosition === "right" ? renderStar : null ); return React.createElement( Cell, { className: `${this.getClassNameWithDirection("nut-form-item")} ${className} ${this.context.disabled ? "nut-form-item-disabled" : ""}`, style, align, onClick: (e) => this.props.onClick && this.props.onClick(e, this.componentRef), catchMove: this.context.disabled }, label ? React.createElement(View, { className: `nut-cell-title ${this.getClassNameWithDirection("nut-form-item-label")}` }, renderLabel) : null, React.createElement( View, { className: `nut-cell-value ${this.getClassNameWithDirection("nut-form-item-body")}`, catchMove: this.context.disabled }, React.createElement(View, { className: "nut-form-item-body-slots" }, childNode), React.createElement(View, { className: "nut-form-item-body-tips", style: { textAlign: errorMessageAlign, display: (item === null || item === void 0 ? void 0 : item.length) ? "initial" : "none" } }, (_a = item === null || item === void 0 ? void 0 : item[0]) === null || _a === void 0 ? void 0 : _a.message) ) ); }; this.componentRef = React.createRef(); this.state = { resetCount: 1 }; } componentDidMount() { const { store = {}, setInitialValues } = this.context.formInstance.getInternal(SECRET); if (this.props.initialValue && this.props.name && !Object.keys(store).includes(this.props.name)) { setInitialValues(Object.assign(Object.assign({}, store), { [this.props.name]: this.props.initialValue }), true); } const { registerField, registerUpdate } = this.context.formInstance.getInternal(SECRET); this.cancelRegister = registerField(this); this.eventOff = registerUpdate(this, this.props.shouldUpdate); } componentWillUnmount() { if (this.cancelRegister) { this.cancelRegister(); } if (this.eventOff) { this.eventOff(); } } getClassNameWithDirection(className) { if (className && this.context.labelPosition) { return `${className} ${className}-${this.context.labelPosition}`; } return className; } render() { const { children } = this.props; const child = Array.isArray(children) ? children[0] : children; let returnChildNode; if (!this.props.shouldUpdate) { returnChildNode = React.cloneElement(child, this.getControlled(child)); } else { returnChildNode = child(this.context.formInstance); } return React.createElement(React.Fragment, { key: this.state.resetCount }, this.props.noStyle ? returnChildNode : this.renderLayout(returnChildNode)); } }; FormItem$1.defaultProps = defaultProps; FormItem$1.contextType = Context$1; const Context = createContext({}); const Provider = Context.Provider; const useContext = () => useContext$1(Context); const FormItem2 = (props) => { const { label, labelExtra, divider: middleDivider, noStyle, className, layout = "horizontal" } = props, rest = __rest(props, ["label", "labelExtra", "divider", "noStyle", "className", "layout"]); const { divider: propsDivider } = useContext(); const divider = middleDivider !== null && middleDivider !== void 0 ? middleDivider : propsDivider; const renderLabel = labelExtra ? React.createElement( Text, { className: "mj-form-item-label-wrap" }, React.createElement(Text, { className: "mj-form-item-label" }, label), labelExtra ) : label; return React.createElement( React.Fragment, null, React.createElement(FormItem$1, Object.assign({ className: classNames("mj-form-item", className, { [`mj-form-item-${layout}`]: true, [`mj-form-item-divider`]: !!divider && !noStyle }), noStyle, label: renderLabel }, rest)) ); }; export { FormItem2 as F, Provider as P, useForm as u };