UNPKG

zmp-react

Version:

Build full featured iOS & Android apps using ZMP & React

449 lines (391 loc) 14.4 kB
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;