UNPKG

@spaceavocado/svelte-form

Version:

Simple Svelte form model handler and input validations.

486 lines (407 loc) 10.7 kB
import tc from '@spaceavocado/type-check'; import { writable, derived, get } from 'svelte/store'; function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } function _iterableToArrayLimit(arr, i) { if (!(Symbol.iterator in Object(arr) || Object.prototype.toString.call(arr) === "[object Arguments]")) { return; } var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } /** * Svelte Form validation rules module. * @module svelte-form/rule/required */ /** * Required rule * @param {string} msg error message. * @return {boolean|string} true when valid, error message otherwise. */ var required = (function (msg) { return function (value) { if (tc.isNullOrUndefined(value) || tc.isObject(value) || tc.isFunction(value)) { return msg; } if (tc.isString(value)) { value = value.trim(); if (value.length == 0) { return msg; } } return true; }; }); /** * Svelte Form validation rules module. * @module svelte-form/rule/ignore */ var BREAK_FLAG = Symbol('Break Validation'); /** * Ignore empty rule * This rule causes to break the validation chain for empty values. * @return {boolean|string} true when valid, error message otherwise. */ var ignoreEmpty = (function () { var req = required(''); return function (value) { if (req(value) !== true) { return BREAK_FLAG; } return true; }; }); /** * Svelte Form validation rules module. * @module svelte-form/rule/email */ /** * Email rule * @param {string} msg error message. * @return {boolean|string} true when valid, error message otherwise. */ var email = (function (msg) { return function (value) { if (tc.isNullOrUndefined(value) || tc.not.isString(value)) { return msg; } var rule = /^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$/; if (value.match(rule) == null) { return msg; } return true; }; }); /** * Svelte Form validation rules module. * @module svelte-form/rule/url */ /** * URL rule * @param {string} msg error message. * @return {boolean|string} true when valid, error message otherwise. */ var url = (function (msg) { return function (value) { if (tc.isNullOrUndefined(value) || tc.not.isString(value)) { return msg; } if (value.match(/^https?:\/\/[^\s]*/i) == null) { return msg; } return true; }; }); /** * Svelte Form validation rules module. * @module svelte-form/rule/equal */ /** * Equal rule. * @param {string} msg error message. * @param {mixed|function} arg a matcher object or * matcher function = fn(val) returning true|false. * @return {boolean|string} true when valid, error message otherwise. */ var equal = (function (msg, arg) { var customMatcher = tc.isFunction(arg); return function (value) { if (customMatcher === false && tc.isNullOrUndefined(value)) { return msg; } if (customMatcher) { if (arg(value) === false) { return msg; } } else if (value !== arg) { return msg; } return true; }; }); /** * Svelte Form validation rules module. * @module svelte-form/rule/min */ /** * Min rule * @param {string} msg error message. * @param {number} arg min number. * @return {boolean|string} true when valid, error message otherwise. */ var min = (function (msg, arg) { return function (value) { if (tc.isNullOrUndefined(value) || tc.not.isNumber(value) || tc.isNullOrUndefined(arg)) { return msg; } if (value < arg) { return msg; } return true; }; }); /** * Svelte Form validation rules module. * @module svelte-form/rule/max */ /** * Max rule * @param {string} msg error message. * @param {number} arg max number. * @return {boolean|string} true when valid, error message otherwise. */ var max = (function (msg, arg) { return function (value) { if (tc.isNullOrUndefined(value) || tc.not.isNumber(value) || tc.isNullOrUndefined(arg)) { return msg; } if (value > arg) { return msg; } return true; }; }); /** * Svelte Form validation rules module. * @module svelte-form/rule/between */ /** * Between numbers rule * @param {string} msg error message. * @param {number} arg1 min number. * @param {number} arg2 max number. * @return {boolean|string} true when valid, error message otherwise. */ var between = (function (msg, arg1, arg2) { return function (value) { if (min('', arg1)(value) !== true || max('', arg2)(value) !== true) { return msg; } return true; }; }); /** * Svelte Form validation rules module. * @module svelte-form/rule/rx */ /** * Custom regex rule. * @param {string} msg error message. * @param {number} arg Regular expression. * @return {boolean|string} true when valid, error message otherwise. */ var rx = (function (msg, arg) { return function (value) { if (tc.isNullOrUndefined(value) || tc.not.isString(value)) { return msg; } if (value.match(arg) == null) { return msg; } return true; }; }); /** * Svelte Form validation rules module. * @module svelte-form/rule/exclude */ /** * Max rule * @param {string} msg error message. * @param {number[]|string[]} arg exclusion list. * @return {boolean|string} true when valid, error message otherwise. */ var exclude = (function (msg, arg) { return function (value) { if (tc.isNullOrUndefined(value) || tc.not.isString(value) && tc.not.isNumber(value) || tc.isNullOrUndefined(arg)) { return msg; } if (arg.indexOf(value) > -1) { return msg; } return true; }; }); /** * Svelte Form validation rules module. * @module svelte-form/rule/include */ /** * Include rule * @param {string} msg error message. * @param {number[]|string[]} arg inclusion list. * @return {boolean|string} true when valid, error message otherwise. */ var include = (function (msg, arg) { return function (value) { if (tc.isNullOrUndefined(value) || tc.not.isString(value) && tc.not.isNumber(value) || tc.isNullOrUndefined(arg)) { return msg; } if (arg.indexOf(value) == -1) { return msg; } return true; }; }); /** * Get input validation rules * @private * @param {string} key input key. * @param {object} validation rules. * @return {function[]} validation rules. */ function validationRules(key, validation) { validation = validation || {}; if (tc.isNullOrUndefined(validation[key])) { return []; } if (tc.isArray(validation[key])) { return validation[key]; } return [validation[key]]; } /** * Validate field * @private * @param {mixed} value field value. * @param {function[]} rules filed validation rules. * @return {boolean|string} true = no error, string = error message. */ function validate(value, rules) { for (var i = 0; i < rules.length; i++) { var err = rules[i](value); if (err === BREAK_FLAG) { return true; } else if (err !== true) { return err; } } return true; } /** * Form object * @typedef Form * @property {function} subscribe Svelte store, context {valid: boolean}. * @property {function} field Get form field observable value and state. * Signature fn(key), returns {module:svelte-form~FormField}. * @property {function} validate Trigger all fields validation. * @property {function} data Get all form fields data. Signature fn(). */ /** * FormField object * @typedef FormField * @property {function} value Writeable Svelte store, context: mixed value. * @property {function} state Readonly Svelte store, * context: {valid: boolean, error: string}. */ /** * Create a new form store * @param {object} fields Form fields. * @param {object} validation Validation rules mapping. * Where each key is a fn(val)->boolean validation function or * an array of fn(val)->boolean validation functions. * @param {object} opts Form options. * @param {boolean} opts.onCreateValidation Validate form fields * when the form is created. Defaults to false. * @return {module:svelte-form~Form} */ function index (fields, validation, opts) { opts = opts || {}; opts.onCreateValidation = opts.onCreateValidation || false; var _fields = {}; var form = writable(Date.now()); // Field wrapper structure var field = function field(key, rules) { var firstPass = true; var value = writable(fields[key]); var state = derived([value, form], function (_ref) { var _ref2 = _slicedToArray(_ref, 1), $value = _ref2[0]; if (firstPass) { firstPass = false; if (opts.onCreateValidation === false) { return { valid: true, error: '' }; } } var res = validate($value, rules); return { valid: res === true, error: res === true ? '' : res }; }); return { value: value, state: state }; }; // Convert all inputs into field wrappers var key; for (key in fields) { if (fields.hasOwnProperty(key)) { _fields[key] = field(key, validationRules(key, validation)); } } // Overall valid state var _derived = derived(Object.values(_fields).map(function (f) { return f.state; }), function ($states) { return { valid: $states.every(function (s) { return s.valid === true; }) }; }), subscribe = _derived.subscribe; return { subscribe: subscribe, field: function field(key) { if (tc.isNullOrUndefined(_fields[key])) { return undefined; } return { value: _fields[key].value, state: _fields[key].state }; }, validate: function validate() { form.set(Date.now()); }, data: function data() { var data = {}; var key; for (key in _fields) { if (_fields.hasOwnProperty(key)) { data[key] = get(_fields[key].value); } } return data; } }; } export default index; export { between, email, equal, exclude, ignoreEmpty, include, max, min, required, rx, url, validate, validationRules };