UNPKG

mobx-easy-form

Version:

Simple and performant form library built with MobX

285 lines (273 loc) 8.09 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } var mobx = require('mobx'); var React = _interopDefault(require('react')); var useMemoOne = require('use-memo-one'); function isPromise(value) { return !!(value && typeof value === "object" && "then" in value && typeof value.then === "function"); } function mapValues(object, callbackFn) { return Object.fromEntries(Object.entries(object).map(function (_ref) { var key = _ref[0], value = _ref[1]; return [key, callbackFn(value)]; })); } function createForm(_ref) { var onSubmit = _ref.onSubmit; var fields = mobx.observable({}); var state = mobx.observable({ isSubmitting: false, valuesAtLastSubmit: undefined, submitCount: 0 }); var computed = mobx.observable({ get isDirty() { return Object.values(fields).some(function (field) { return field.computed.isDirty; }); }, get errorList() { return Object.values(fields).map(function (field) { return field.computed.error; }).filter(function (error) { return error !== undefined; }); }, get isError() { return Object.values(fields).some(function (field) { return !!field.computed.error; }); }, get isValid() { return !this.isError; }, get valueList() { return String(Object.values(fields).map(function (field) { return field.state.value; })); }, get isChangedSinceLastSubmit() { if (state.submitCount === 0) return this.isDirty; return this.valueList !== state.valuesAtLastSubmit; } }); var actions = { add: function add(field) { fields[field.state.id] = field; }, submit: mobx.action(function submit() { state.isSubmitting = true; state.submitCount++; state.valuesAtLastSubmit = computed.valueList; for (var fieldId in fields) { var field = fields[fieldId]; field.state.wasEverFocused = true; field.state.wasEverBlurred = true; } if (computed.isError) { state.isSubmitting = false; return; } var maybePromise = onSubmit({ fields: fields, rawValues: mapValues(fields, function (field) { return field.state.value; }), values: mapValues(fields, function (field) { return field.computed.parsed; }) }); if (isPromise(maybePromise)) { return Promise.resolve(maybePromise)["finally"](function () { mobx.runInAction(function () { state.isSubmitting = false; }); }); } else { mobx.runInAction(function () { state.isSubmitting = false; }); } return maybePromise; }) }; return { fields: fields, state: state, computed: computed, actions: actions }; } function _extends() { _extends = Object.assign ? Object.assign.bind() : 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); } function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } var _excluded = ["id", "initialValue", "initialError", "form"]; function createField(_ref) { var id = _ref.id, initialValue = _ref.initialValue, initialError = _ref.initialError, form = _ref.form, validationProps = _objectWithoutPropertiesLoose(_ref, _excluded); function getValidateFunction() { if ("validate" in validationProps && validationProps.validate) { return validationProps.validate; } if ("validationSchema" in validationProps && validationProps.validationSchema) { return function validate(value) { if (!validationProps.validationSchema) throw new Error("Missing validation schema"); try { var parsed = validationProps.validationSchema.validateSync(value === "" ? undefined : value, { abortEarly: true }); return { parsed: parsed, error: undefined }; } catch (error) { if (error instanceof Error && error.name === "ValidationError") { return { parsed: undefined, error: error }; } throw error; } }; } return function validate(value) { return { parsed: value, error: undefined }; }; } var runValidation = getValidateFunction(); var state = mobx.observable({ id: id, errorOverride: initialError, value: initialValue, isFocused: false, wasEverFocused: false, wasEverBlurred: false }); var computed = mobx.observable({ get parsed() { var result = runValidation(state.value); if (result.error) return undefined; return result.parsed; }, get isDirty() { // TODO: Add ability to provide custom equality function. return JSON.stringify(state.value) !== JSON.stringify(initialValue); }, get error() { var _runValidation = runValidation(state.value), error = _runValidation.error; if (state.errorOverride) { return state.errorOverride; } if (error instanceof Error && error.name === "ValidationError") { var _ref2, _err$message$value, _err$message; var err = error; return String((_ref2 = (_err$message$value = (_err$message = err.message) == null ? void 0 : _err$message.value) != null ? _err$message$value : err.message) != null ? _ref2 : error); } if (error instanceof Error) { return error.message; } return error; }, get ifWasEverFocusedThenError() { if (!state.wasEverFocused) return undefined; if (!computed.error) return undefined; return String(computed.error); }, get ifWasEverBlurredThenError() { if (!state.wasEverBlurred) return undefined; if (!computed.error) return undefined; return String(computed.error); } }); var actions = { onFocus: mobx.action(function onFocus() { state.isFocused = true; state.wasEverFocused = true; }), onBlur: mobx.action(function onBlur() { state.isFocused = false; state.wasEverBlurred = true; }), onChange: mobx.action(function onChange(value) { if (state.errorOverride) state.errorOverride = undefined; state.value = value; }), setError: mobx.action(function setError(value) { state.errorOverride = value; }) }; var field = { state: state, computed: computed, actions: actions }; form.actions.add(field); return field; } function useEvent(handler) { var handlerRef = React.useRef(null); React.useLayoutEffect(function () { handlerRef.current = handler; }); return React.useCallback(function () { var fn = handlerRef.current; return fn.apply(void 0, arguments); }, []); } function useForm(args, deps) { if (deps === void 0) { deps = []; } var onSubmit = useEvent(args.onSubmit); return useMemoOne.useMemoOne(function () { return createForm(_extends({}, args, { onSubmit: onSubmit })); }, deps); } function useField(args, deps) { if (deps === void 0) { deps = []; } return useMemoOne.useMemoOne(function () { return createField(args); }, deps); } exports.createField = createField; exports.createForm = createForm; exports.useField = useField; exports.useForm = useForm; //# sourceMappingURL=mobx-easy-form.cjs.development.js.map