nornj-react
Version:
React bindings for NornJ template engine.
216 lines (178 loc) • 6.08 kB
JavaScript
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
import nj, { registerExtension } from 'nornj';
import React, { useRef } from 'react';
import { toJS } from 'mobx';
import extensionConfigs from '../../../mobx/extensionConfig';
import { debounce } from '../../utils';
const FORMDATA_NOT_TRIGGER = ['valueChange', 'none'];
const MobxBindWrap = React.forwardRef(({
MobxBindTag,
mobxBindDirectiveOptions: {
tagName,
context: {
$this
},
props: directiveProps
},
_mobxBindValue: value,
...props
}, ref) => {
let valuePropName = 'value';
let changeEventName = 'onChange';
let componentConfig = nj.getComponentConfig(tagName) || {};
if (typeof componentConfig === 'function') {
componentConfig = componentConfig(props);
}
const args = directiveProps && directiveProps.arguments;
const debounceArg = _hasArg(args, 'debounce');
if (componentConfig.valuePropName != null) {
valuePropName = componentConfig.valuePropName;
}
if (componentConfig.changeEventName != null) {
changeEventName = componentConfig.changeEventName;
}
let _value = value.value;
const isMultipleSelect = tagName === 'select' && props.multiple;
if (componentConfig.needToJS || isMultipleSelect) {
_value = toJS(_value);
}
const changeEvent = props[changeEventName];
let emitChangeDebounced;
if (debounceArg) {
const {
modifiers
} = debounceArg;
emitChangeDebounced = useRef(debounce(args => {
changeEvent && changeEvent.apply($this, args);
}, modifiers && +modifiers[0] || 100));
}
const compProps = {};
if (componentConfig.hasEventObject) {
const targetPropName = componentConfig.targetPropName || 'value';
const isRadio = tagName === 'input' && props.type === 'radio';
const isCheckbox = tagName === 'input' && props.type === 'checkbox';
if (isRadio) {
compProps.checked = props.value === _value;
} else if (isCheckbox) {
compProps.checked = _value != null && (nj.isArrayLike(_value) ? _value.indexOf(props.value) >= 0 : _value);
} else {
compProps[valuePropName] = _value;
}
compProps[changeEventName] = function (e) {
e && e.persist && e.persist();
_setValue(e.target[targetPropName], {
target: e.target,
value,
args: arguments,
changeEventName,
changeEvent,
valuePropName,
emitChangeDebounced,
isMultipleSelect,
isCheckbox
}, $this);
};
} else {
const getValueFromEvent = componentConfig.getValueFromEvent;
compProps[valuePropName] = _value;
compProps[changeEventName] = function (...args) {
_setValue(getValueFromEvent ? getValueFromEvent(...args) : args[0], {
value,
args,
changeEventName,
changeEvent,
valuePropName,
emitChangeDebounced
}, $this);
};
}
_formDataTrigger(value, changeEventName, componentConfig, true, props, compProps, $this);
return React.createElement(MobxBindTag, _extends({}, props, compProps, {
ref: ref
}));
});
function _formDataTrigger(value, changeEventName, componentConfig, notDirect, props, compProps, $this) {
const formData = value === null || value === void 0 ? void 0 : value.source;
if (formData === null || formData === void 0 ? void 0 : formData._njMobxFormData) {
const fieldName = value.prop;
const fieldData = formData.fieldDatas.get(fieldName);
const fieldDefaultRule = componentConfig === null || componentConfig === void 0 ? void 0 : componentConfig.fieldDefaultRule;
if (fieldDefaultRule) {
fieldData.setDefaultRule(fieldDefaultRule);
}
const trigger = fieldData.trigger;
if (FORMDATA_NOT_TRIGGER.indexOf(trigger) > -1) {
return;
}
if (!notDirect) {
if (trigger === changeEventName) {
formData.validate(fieldName).catch(nj.noop);
}
} else if (trigger !== changeEventName) {
const triggerEvent = props[trigger];
compProps[trigger] = function (e) {
e && e.persist && e.persist();
formData.validate(fieldName).catch(nj.noop);
triggerEvent && triggerEvent.apply($this, arguments);
};
}
}
}
function _setValue(value, params, $this) {
let _value = value;
if (params.isMultipleSelect) {
_value = nj.arraySlice(params.target.options).filter(option => option.selected).map(option => option.value);
} else if (params.isCheckbox) {
const checkboxValue = params.value.value;
if (nj.isArrayLike(checkboxValue)) {
if (params.target.checked) {
checkboxValue.push(value);
} else {
checkboxValue.splice(checkboxValue.indexOf(value), 1);
}
_value = checkboxValue;
} else {
_value = params.target.checked;
}
}
const setter = params.value.source[`set${nj.upperFirst(params.value.prop)}`];
if (setter) {
setter(_value, params.args);
} else {
params.value.source[params.value.prop] = _value;
}
_formDataTrigger(params.value, params.changeEventName);
if (params.emitChangeDebounced) {
params.emitChangeDebounced.current(params.args);
} else if (params.changeEvent) {
params.changeEvent.apply($this, params.args);
}
}
function _hasArg(args, name) {
let ret;
args && args.every(arg => {
if (arg.name == name) {
ret = arg;
return false;
}
return true;
});
return ret;
}
registerExtension('mobxBind', options => {
const ret = options.value();
if (ret == null) {
return ret;
}
const {
tagName,
setTagName,
tagProps,
props
} = options;
setTagName(MobxBindWrap);
tagProps.MobxBindTag = tagName;
tagProps.mobxBindDirectiveOptions = options;
tagProps._mobxBindValue = ret;
}, extensionConfigs.mobxBind);
nj.extensions.mstBind = nj.extensions.mobxBind;