UNPKG

zmp-react

Version:

Build full featured iOS & Android apps using ZMP & React

452 lines (396 loc) 15.5 kB
import _extends from "@babel/runtime/helpers/extends"; import React, { forwardRef, useRef, useImperativeHandle, useState, useContext } from 'react'; import { useIsomorphicLayoutEffect } from '../shared/use-isomorphic-layout-effect'; import { classNames, getExtraAttrs, emit, getSlots, extend } from '../shared/utils'; import { colorClasses } from '../shared/mixins'; import { zmpready, zmp } from '../shared/zmp'; import TextEditor from './text-editor'; import { watchProp } from '../shared/watch-prop'; import { ListContext } from '../shared/list-context'; var ListInput = /*#__PURE__*/forwardRef(function (props, ref) { var className = props.className, id = props.id, style = props.style, sortable = props.sortable, media = props.media, _props$dropdown = props.dropdown, dropdown = _props$dropdown === void 0 ? 'auto' : _props$dropdown, _props$wrap = props.wrap, wrap = _props$wrap === void 0 ? true : _props$wrap, _props$input = props.input, renderInput = _props$input === void 0 ? true : _props$input, _props$type = props.type, type = _props$type === void 0 ? 'text' : _props$type, name = props.name, value = props.value, defaultValue = props.defaultValue, inputmode = props.inputmode, readonly = props.readonly, required = props.required, disabled = props.disabled, 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, max = props.max, min = props.min, step = props.step, maxlength = props.maxlength, minlength = props.minlength, multiple = props.multiple, 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, label = props.label, inlineLabel = props.inlineLabel, floatingLabel = props.floatingLabel, 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 listContext = useContext(ListContext); var _ref = listContext || {}, _ref$listIsSortable = _ref.listIsSortable, listIsSortable = _ref$listIsSortable === void 0 ? false : _ref$listIsSortable; var extraAttrs = getExtraAttrs(props); var zmpCalendar = useRef(null); var zmpColorPicker = useRef(null); var elRef = useRef(null); var inputElRef = useRef(null); var itemContentElRef = 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(inputElRef.current); } }; 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(inputElRef.current); } 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() { if (!elRef.current && !itemContentElRef.current) return; zmpready(function () { if (!inputElRef.current) return; inputElRef.current.addEventListener('input:notempty', onInputNotEmpty, false); inputElRef.current.addEventListener('textarea:resize', onTextareaResize, false); 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, 'colorpicker:change colorPickerChange', colorPickerValue); } } }, colorPickerParams || {})); } if (!(validateOnBlur || validateOnBlur === '') && (validate || validate === '') && (typeof value !== 'undefined' && value !== null && value !== '' || typeof defaultValue !== 'undefined' && defaultValue !== null && defaultValue !== '')) { setTimeout(function () { validateInput(); }, 0); } if (type === 'textarea' && resizable) { zmp.input.resizeTextarea(inputElRef.current); } }); }; var onDestroy = function onDestroy() { if (inputElRef.current) { inputElRef.current.removeEventListener('input:notempty', onInputNotEmpty, false); inputElRef.current.removeEventListener('textarea:resize', onTextareaResize, false); 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; if (validate && !validateOnBlur) { validateInput(); } if (type === 'textarea' && 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 (!zmp) return; updateInputOnDidUpdate.current = true; if (zmpCalendar.current) { zmpCalendar.current.setValue(newValue); } if (zmpColorPicker.current) { zmpColorPicker.current.setValue(newValue); } }); var slots = getSlots(props); var domValue = getDomValue(); var inputHasValue = isInputHasValue(); var isSortableComputed = sortable || listIsSortable; 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({ 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, 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 (renderInput) { 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 (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'); } } var hasErrorMessage = !!errorMessage || slots['error-message'] && slots['error-message'].length; var ItemContent = /*#__PURE__*/React.createElement("div", { ref: itemContentElRef, className: classNames('item-content item-input', !wrap && className, !wrap && { disabled: disabled }, !wrap && colorClasses(props), { 'inline-label': inlineLabel, 'item-input-outline': outline, 'item-input-focused': inputFocused, 'item-input-with-info': !!info || slots.info && slots.info.length, 'item-input-with-value': inputHasValue, 'item-input-with-error-message': hasErrorMessage && errorMessageForce || inputInvalid, 'item-input-invalid': hasErrorMessage && errorMessageForce || inputInvalid }) }, slots['content-start'], (media || slots.media) && /*#__PURE__*/React.createElement("div", { className: "item-media" }, media && /*#__PURE__*/React.createElement("img", { src: media }), slots.media), /*#__PURE__*/React.createElement("div", { className: "item-inner" }, slots['inner-start'], (label || slots.label) && /*#__PURE__*/React.createElement("div", { className: classNames('item-title item-label', { 'item-floating-label': floatingLabel }) }, label, slots.label), /*#__PURE__*/React.createElement("div", { className: classNames('item-input-wrap', { 'input-dropdown': dropdown === 'auto' ? type === 'select' : dropdown }) }, inputEl, slots.input, hasErrorMessage && errorMessageForce && /*#__PURE__*/React.createElement("div", { className: "item-input-error-message" }, errorMessage, slots['error-message']), clearButton && /*#__PURE__*/React.createElement("span", { className: "input-clear-button" }), (info || slots.info) && /*#__PURE__*/React.createElement("div", { className: "item-input-info" }, info, slots.info)), slots.inner, slots['inner-end']), slots.content, slots['content-end']); if (!wrap) { return ItemContent; } return /*#__PURE__*/React.createElement("li", _extends({ ref: elRef, id: id, style: style, className: classNames(className, { disabled: disabled }, colorClasses(props)) }, extraAttrs), slots['root-start'], ItemContent, isSortableComputed && /*#__PURE__*/React.createElement("div", { className: "sortable-handler" }), slots.root, slots['root-end']); }); ListInput.displayName = 'zmp-list-input'; export default ListInput;