zmp-react
Version:
Build full featured iOS & Android apps using ZMP & React
449 lines (391 loc) • 14.4 kB
JavaScript
import _extends from "@babel/runtime/helpers/extends";
import React, { forwardRef, useRef, useImperativeHandle, useState } from 'react';
import { useIsomorphicLayoutEffect } from '../shared/use-isomorphic-layout-effect';
import { classNames, getExtraAttrs, getSlots, emit, extend } from '../shared/utils';
import { colorClasses } from '../shared/mixins';
import { zmpready, zmp } from '../shared/zmp';
import { watchProp } from '../shared/watch-prop';
import Toggle from './toggle';
import Range from './range';
import TextEditor from './text-editor';
var Input = /*#__PURE__*/forwardRef(function (props, ref) {
var className = props.className,
id = props.id,
style = props.style,
type = props.type,
name = props.name,
value = props.value,
defaultValue = props.defaultValue,
inputmode = props.inputmode,
placeholder = props.placeholder,
inputId = props.inputId,
size = props.size,
accept = props.accept,
autocomplete = props.autocomplete,
autocorrect = props.autocorrect,
autocapitalize = props.autocapitalize,
spellcheck = props.spellcheck,
autofocus = props.autofocus,
autosave = props.autosave,
checked = props.checked,
disabled = props.disabled,
max = props.max,
min = props.min,
step = props.step,
maxlength = props.maxlength,
minlength = props.minlength,
multiple = props.multiple,
readonly = props.readonly,
required = props.required,
inputStyle = props.inputStyle,
pattern = props.pattern,
validate = props.validate,
validateOnBlur = props.validateOnBlur,
onValidate = props.onValidate,
tabindex = props.tabindex,
resizable = props.resizable,
clearButton = props.clearButton,
noFormStoreData = props.noFormStoreData,
noStoreData = props.noStoreData,
ignoreStoreData = props.ignoreStoreData,
errorMessage = props.errorMessage,
errorMessageForce = props.errorMessageForce,
info = props.info,
outline = props.outline,
_props$wrap = props.wrap,
wrap = _props$wrap === void 0 ? true : _props$wrap,
_props$dropdown = props.dropdown,
dropdown = _props$dropdown === void 0 ? 'auto' : _props$dropdown,
calendarParams = props.calendarParams,
colorPickerParams = props.colorPickerParams,
textEditorParams = props.textEditorParams,
rows = props.rows;
var _useState = useState(false),
inputInvalid = _useState[0],
setInputInvalid = _useState[1];
var _useState2 = useState(false),
inputFocused = _useState2[0],
setInputFocused = _useState2[1];
var extraAttrs = getExtraAttrs(props);
var zmpCalendar = useRef(null);
var zmpColorPicker = useRef(null);
var elRef = useRef(null);
var inputElRef = useRef(null);
var updateInputOnDidUpdate = useRef(false);
var getDomValue = function getDomValue() {
if (!inputElRef.current) return undefined;
return inputElRef.current.value;
};
var isInputHasValue = function isInputHasValue() {
if (type === 'datepicker' && Array.isArray(value) && value.length === 0) {
return false;
}
var domValue = getDomValue();
return typeof value === 'undefined' ? domValue || domValue === 0 : value || value === 0;
};
var validateInput = function validateInput() {
if (!zmp || !inputElRef.current) return;
var validity = inputElRef.current.validity;
if (!validity) return;
if (!validity.valid) {
if (onValidate) onValidate(false);
if (inputInvalid !== true) {
setInputInvalid(true);
}
} else {
if (onValidate) onValidate(true);
if (inputInvalid !== false) {
setInputInvalid(false);
}
}
};
var onTextareaResize = function onTextareaResize(event) {
emit(props, 'textareaResize', event);
};
var onInputNotEmpty = function onInputNotEmpty(event) {
emit(props, 'inputNotEmpty', event);
};
var onInputEmpty = function onInputEmpty(event) {
emit(props, 'inputEmpty', event);
};
var onInputClear = function onInputClear(event) {
emit(props, 'inputClear', event);
};
var onInput = function onInput() {
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
emit.apply(void 0, [props, 'input'].concat(args));
if (!(validateOnBlur || validateOnBlur === '') && (validate || validate === '') && inputElRef.current) {
validateInput();
}
};
var onFocus = function onFocus() {
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
emit.apply(void 0, [props, 'focus'].concat(args));
setInputFocused(true);
};
var onBlur = function onBlur() {
for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
args[_key3] = arguments[_key3];
}
emit.apply(void 0, [props, 'blur'].concat(args));
if ((validate || validate === '' || validateOnBlur || validateOnBlur === '') && inputElRef.current) {
validateInput();
}
setInputFocused(false);
};
var onChange = function onChange() {
for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {
args[_key4] = arguments[_key4];
}
emit.apply(void 0, [props, 'change'].concat(args));
if (type === 'texteditor') {
emit(props, 'textEditorChange', args[0]);
}
};
useImperativeHandle(ref, function () {
return {
el: elRef.current
};
});
var onMount = function onMount() {
zmpready(function () {
if (type === 'range' || type === 'toggle') return;
if (!inputElRef.current) return;
inputElRef.current.addEventListener('input:notempty', onInputNotEmpty, false);
if (type === 'textarea' && resizable) {
inputElRef.current.addEventListener('textarea:resize', onTextareaResize, false);
}
if (clearButton) {
inputElRef.current.addEventListener('input:empty', onInputEmpty, false);
inputElRef.current.addEventListener('input:clear', onInputClear, false);
}
if (type === 'datepicker') {
zmpCalendar.current = zmp.calendar.create(_extends({
inputEl: inputElRef.current,
value: value,
on: {
change: function change(calendar, calendarValue) {
emit(props, 'calendarChange', calendarValue);
}
}
}, calendarParams || {}));
}
if (type === 'colorpicker') {
zmpColorPicker.current = zmp.colorPicker.create(_extends({
inputEl: inputElRef.current,
value: value,
on: {
change: function change(colorPicker, colorPickerValue) {
emit(props, 'colorPickerChange', colorPickerValue);
}
}
}, colorPickerParams || {}));
}
zmp.input.checkEmptyState(inputElRef.current);
if (!(validateOnBlur || validateOnBlur === '') && (validate || validate === '') && (typeof value !== 'undefined' && value !== null && value !== '' || typeof defaultValue !== 'undefined' && defaultValue !== null && defaultValue !== '')) {
setTimeout(function () {
validateInput();
}, 0);
}
if (resizable) {
zmp.input.resizeTextarea(inputElRef.current);
}
});
};
var onDestroy = function onDestroy() {
if (type === 'range' || type === 'toggle') return;
if (!inputElRef.current) return;
inputElRef.current.removeEventListener('input:notempty', onInputNotEmpty, false);
if (type === 'textarea' && resizable) {
inputElRef.current.removeEventListener('textarea:resize', onTextareaResize, false);
}
if (clearButton) {
inputElRef.current.removeEventListener('input:empty', onInputEmpty, false);
inputElRef.current.removeEventListener('input:clear', onInputClear, false);
}
if (zmpCalendar.current && zmpCalendar.current.destroy) {
zmpCalendar.current.destroy();
zmpCalendar.current = null;
}
if (zmpColorPicker.current && zmpColorPicker.current.destroy) {
zmpColorPicker.current.destroy();
zmpColorPicker.current = null;
}
};
useIsomorphicLayoutEffect(function () {
onMount();
return onDestroy;
}, []);
useIsomorphicLayoutEffect(function () {
if (!zmp) return;
if (updateInputOnDidUpdate.current) {
if (!inputElRef.current) return;
updateInputOnDidUpdate.current = false;
zmp.input.checkEmptyState(inputElRef.current);
if (validate && !validateOnBlur) {
validateInput();
}
if (resizable) {
zmp.input.resizeTextarea(inputElRef.current);
}
}
});
watchProp(colorPickerParams, function (newValue) {
if (!zmp || !zmpColorPicker.current) return;
extend(zmpColorPicker.current.params, newValue || {});
});
watchProp(calendarParams, function (newValue) {
if (!zmp || !zmpCalendar.current) return;
extend(zmpCalendar.current.params, newValue || {});
});
watchProp(value, function (newValue) {
if (type === 'range' || type === 'toggle') return;
if (!zmp) return;
updateInputOnDidUpdate.current = true;
if (zmpCalendar.current) {
zmpCalendar.current.setValue(newValue);
}
if (zmpColorPicker.current) {
zmpColorPicker.current.setValue(newValue);
}
});
var domValue = getDomValue();
var inputHasValue = isInputHasValue();
var slots = getSlots(props);
var inputEl;
var createInput = function createInput(InputTag, children) {
var needsValue = type !== 'file' && type !== 'datepicker' && type !== 'colorpicker';
var needsType = InputTag === 'input';
var inputType = type;
if (inputType === 'datepicker' || inputType === 'colorpicker') {
inputType = 'text';
}
var inputClassName = classNames(!wrap && className, {
resizable: inputType === 'textarea' && resizable,
'no-store-data': noFormStoreData || noStoreData || ignoreStoreData,
'input-invalid': errorMessage && errorMessageForce || inputInvalid,
'input-with-value': inputHasValue,
'input-focused': inputFocused
});
var inputValue;
if (needsValue) {
if (typeof value !== 'undefined') inputValue = value;else inputValue = domValue;
}
var valueProps = {};
if (type !== 'datepicker' && type !== 'colorpicker') {
if ('value' in props) valueProps.value = inputValue;
if ('defaultValue' in props) valueProps.defaultValue = defaultValue;
}
return /*#__PURE__*/React.createElement(InputTag, _extends({
ref: inputElRef,
style: inputStyle,
name: name,
type: needsType ? inputType : undefined,
placeholder: placeholder,
inputMode: inputmode,
id: inputId,
size: size,
accept: accept,
autoComplete: autocomplete,
autoCorrect: autocorrect,
autoCapitalize: autocapitalize,
spellCheck: spellcheck,
autoFocus: autofocus,
autoSave: autosave,
checked: checked,
disabled: disabled,
max: max,
maxLength: maxlength,
min: min,
minLength: minlength,
step: step,
multiple: multiple,
readOnly: readonly,
required: required,
pattern: pattern,
validate: typeof validate === 'string' && validate.length ? validate : undefined,
"data-validate": validate === true || validate === '' || validateOnBlur === true || validateOnBlur === '' ? true : undefined,
"data-validate-on-blur": validateOnBlur === true || validateOnBlur === '' ? true : undefined,
tabIndex: tabindex,
"data-error-message": errorMessageForce ? undefined : errorMessage,
className: inputClassName,
onFocus: onFocus,
onBlur: onBlur,
onInput: onInput,
onChange: onChange,
rows: rows
}, valueProps), children);
};
if (type === 'select' || type === 'textarea' || type === 'file') {
if (type === 'select') {
inputEl = createInput('select', slots.default);
} else if (type === 'file') {
inputEl = createInput('input');
} else {
inputEl = createInput('textarea');
}
} else if (slots.default && slots.default.length > 0 || !type) {
inputEl = slots.default;
} else if (type === 'toggle') {
inputEl = /*#__PURE__*/React.createElement(Toggle, {
checked: checked,
readonly: readonly,
name: name,
value: value,
disabled: disabled,
id: inputId,
onChange: onChange
});
} else if (type === 'range') {
inputEl = /*#__PURE__*/React.createElement(Range, {
value: value,
disabled: disabled,
min: min,
max: max,
step: step,
name: name,
id: inputId,
input: true,
onRangeChange: onChange
});
} else if (type === 'texteditor') {
inputEl = /*#__PURE__*/React.createElement(TextEditor, _extends({
value: value,
resizable: resizable,
placeholder: placeholder,
onTextEditorFocus: onFocus,
onTextEditorBlur: onBlur,
onTextEditorInput: onInput,
onTextEditorChange: onChange
}, textEditorParams));
} else {
inputEl = createInput('input');
}
if (wrap) {
var wrapClasses = classNames(className, 'input', {
'input-outline': outline,
'input-dropdown': dropdown === 'auto' ? type === 'select' : dropdown,
'input-invalid': errorMessage && errorMessageForce || inputInvalid,
'input-with-value': inputHasValue
}, colorClasses(props));
return /*#__PURE__*/React.createElement("div", _extends({
id: id,
className: wrapClasses,
style: style,
ref: elRef
}, extraAttrs), inputEl, (errorMessage || slots['error-message'] && slots['error-message'].length) && errorMessageForce && /*#__PURE__*/React.createElement("div", {
className: "input-error-message"
}, errorMessage, slots['error-message']), clearButton && /*#__PURE__*/React.createElement("span", {
className: "input-clear-button"
}), (info || slots.info && slots.info.length) && /*#__PURE__*/React.createElement("div", {
className: "input-info"
}, info, slots.info));
}
return inputEl;
});
Input.displayName = 'zmp-input';
export default Input;