diff --git a/build/rollup.config.js b/build/rollup.config.js index 4bf540f..96e1df4 100644 --- a/build/rollup.config.js +++ b/build/rollup.config.js @@ -9,10 +9,11 @@ export default { exports: 'named', globals: { 'is-plain-object': 'isPlainObject', - 'nanoid': 'nanoid' + 'nanoid': 'nanoid', + 'is-url': 'isUrl' } }, - external: ['is-plain-object', 'nanoid'], + external: ['is-plain-object', 'nanoid', 'is-url'], plugins: [ commonjs(), vue({ diff --git a/dist/formulate.esm.js b/dist/formulate.esm.js index 1383921..98ba914 100644 --- a/dist/formulate.esm.js +++ b/dist/formulate.esm.js @@ -1,3 +1,4 @@ +import isUrl from 'is-url'; import isPlainObject from 'is-plain-object'; import nanoid from 'nanoid'; @@ -160,6 +161,291 @@ function arrayify (item) { return [] } +/** + * Given an array or string return an array of callables. + * @param {array|string} validation + * @param {array} rules and array of functions + * @return {array} an array of functions + */ +function parseRules (validation, rules) { + if (typeof validation === 'string') { + return parseRules(validation.split('|'), rules) + } + if (!Array.isArray(validation)) { + return [] + } + return validation.map(function (rule) { return parseRule(rule, rules); }).filter(function (f) { return !!f; }) +} + +/** + * Given a string or function, parse it and return the an array in the format + * [fn, [...arguments]] + * @param {string|function} rule + */ +function parseRule (rule, rules) { + if (typeof rule === 'function') { + return [rule, []] + } + if (Array.isArray(rule) && rule.length) { + if (typeof rule[0] === 'string' && rules.hasOwnProperty(rule[0])) { + return [rules[rule.shift()], rule] + } + if (typeof rule[0] === 'function') { + return [rule.shift(), rule] + } + } + if (typeof rule === 'string') { + var segments = rule.split(':'); + var functionName = segments.shift(); + if (rules.hasOwnProperty(functionName)) { + return [rules[functionName], segments.length ? segments.join(':').split(',') : []] + } else { + throw new Error(("Unknown validation rule " + rule)) + } + } + return false +} + +/** + * Library of rules + */ +var rules = { + /** + * Rule: the value must be "yes", "on", "1", or true + */ + accepted: function (value) { + return Promise.resolve(['yes', 'on', '1', 1, true, 'true'].includes(value)) + }, + + /** + * Rule: must be a value + */ + required: function (value, isRequired) { + if ( isRequired === void 0 ) isRequired = true; + + return Promise.resolve((function () { + if (!isRequired || ['no', 'false'].includes(isRequired)) { + return true + } + if (Array.isArray(value)) { + return !!value.length + } + if (typeof value === 'string') { + return !!value + } + if (typeof value === 'object') { + return (!value) ? false : !!Object.keys(value).length + } + return true + })()) + }, + + /** + * Rule: Value is in an array (stack). + */ + in: function (value) { + var stack = [], len = arguments.length - 1; + while ( len-- > 0 ) stack[ len ] = arguments[ len + 1 ]; + + return Promise.resolve(stack.find(function (item) { + if (typeof item === 'object') { + return shallowEqualObjects(item, value) + } + return item === value + }) !== undefined) + }, + + /** + * Rule: Value is not in stack. + */ + not: function (value) { + var stack = [], len = arguments.length - 1; + while ( len-- > 0 ) stack[ len ] = arguments[ len + 1 ]; + + return Promise.resolve(stack.find(function (item) { + if (typeof item === 'object') { + return shallowEqualObjects(item, value) + } + return item === value + }) === undefined) + }, + + /** + * Rule: Match the value against a (stack) of patterns or strings + */ + matches: function (value) { + var stack = [], len = arguments.length - 1; + while ( len-- > 0 ) stack[ len ] = arguments[ len + 1 ]; + + return Promise.resolve(!!stack.find(function (pattern) { + if (pattern instanceof RegExp) { + return pattern.test(value) + } + return pattern === value + })) + }, + + /** + * Rule: checks if a string is a valid url + */ + url: function (value) { + return Promise.resolve(isUrl(value)) + }, + + /** + * Rule: ensures the value is a date according to Date.parse() + */ + date: function (value) { + return Promise.resolve(!isNaN(Date.parse(value))) + }, + + /** + * Rule: checks if a value is after a given date. Defaults to current time + */ + after: function (value, compare) { + if ( compare === void 0 ) compare = false; + + var timestamp = Date.parse(compare || new Date()); + var fieldValue = Date.parse(value); + return Promise.resolve(isNaN(fieldValue) ? false : (fieldValue > timestamp)) + }, + + /** + * Rule: checks if a value is after a given date. Defaults to current time + */ + before: function (value, compare) { + if ( compare === void 0 ) compare = false; + + var timestamp = Date.parse(compare || new Date()); + var fieldValue = Date.parse(value); + return Promise.resolve(isNaN(fieldValue) ? false : (fieldValue < timestamp)) + }, + + /** + * Rule: checks if the value is only alpha numeric + */ + alpha: function (value, set) { + if ( set === void 0 ) set = 'default'; + + var sets = { + default: /^[a-zA-ZÀ-ÖØ-öø-ÿ]+$/, + latin: /^[a-z][A-Z]$/ + }; + var selectedSet = sets.hasOwnProperty(set) ? set : 'default'; + return Promise.resolve(sets[selectedSet].test(value)) + }, + + /** + * Rule: checks if the value is only alpha numeric + */ + number: function (value) { + return Promise.resolve(!isNaN(value)) + }, + + /** + * Rule: checks if the value is alpha numeric + */ + alphanumeric: function (value, set) { + if ( set === void 0 ) set = 'default'; + + var sets = { + default: /^[a-zA-Z0-9À-ÖØ-öø-ÿ]+$/, + latin: /^[a-zA-Z0-9]$/ + }; + var selectedSet = sets.hasOwnProperty(set) ? set : 'default'; + return Promise.resolve(sets[selectedSet].test(value)) + }, + + /** + * Rule: checks if the value is between two other values + */ + between: function (value, from, to) { + return Promise.resolve((function () { + if (from === null || to === null || isNaN(from) || isNaN(to)) { + return false + } + from = Number(from); + to = Number(to); + if (!isNaN(value)) { + value = Number(value); + return (value > from && value < to) + } + if (typeof value === 'string') { + return value.length > from && value.length < to + } + return false + })()) + }, + + /** + * Rule: tests + */ + email: function (value) { + // eslint-disable-next-line + var isEmail = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i; + return Promise.resolve(isEmail.test(value)) + }, + + /** + * Check the file type is correct. + */ + mime: function (files) { + var types = [], len = arguments.length - 1; + while ( len-- > 0 ) types[ len ] = arguments[ len + 1 ]; + + return Promise.resolve((function () { + if (typeof window !== 'undefined' && typeof FileReader !== 'undefined' && typeof Blob !== 'undefined') { + for (var i in files) { + if (!types.includes(files[i].type)) { + return false + } + } + } + return true + })()) + }, + + /** + * Check the minimum value of a particular. + */ + min: function (value, minimum) { + return Promise.resolve((function () { + minimum = Number(minimum); + if (!isNaN(value)) { + value = Number(value); + return value >= minimum + } + if (typeof value === 'string') { + return value.length >= minimum + } + if (Array.isArray(value)) { + return value.length >= minimum + } + return false + })()) + }, + + /** + * Check the minimum value of a particular. + */ + max: function (value, minimum) { + return Promise.resolve((function () { + minimum = Number(minimum); + if (!isNaN(value)) { + value = Number(value); + return value <= minimum + } + if (typeof value === 'string') { + return value.length <= minimum + } + if (Array.isArray(value)) { + return value.length <= minimum + } + return false + })()) + } +}; + /** * For a single instance of an input, export all of the context needed to fully * render that element. @@ -186,7 +472,8 @@ var context = { elementAttributes: elementAttributes, logicalLabelPosition: logicalLabelPosition, isVmodeled: isVmodeled, - mergedErrors: mergedErrors + mergedErrors: mergedErrors, + hasErrors: hasErrors }; /** @@ -299,6 +586,13 @@ function mergedErrors () { .reduce(function (errors, err) { return !errors.includes(err) ? errors.concat(err) : errors; }, []) } +/** + * Does this computed property have errors. + */ +function hasErrors () { + return !!this.mergedErrors.length +} + /** * Defines the model used throughout the existing context. * @param {object} context @@ -397,6 +691,17 @@ var script = { type: [String, Array, Boolean], default: false }, + validation: { + type: [String, Boolean, Array], + default: false + }, + validationBehavior: { + type: String, + default: 'blur', + validator: function (value) { + return ['blur', 'live'].includes(value) + } + }, error: { type: [String, Boolean], default: false @@ -406,7 +711,8 @@ var script = { return { defaultId: nanoid(9), localAttributes: {}, - internalModelProxy: this.formulateValue + internalModelProxy: this.formulateValue, + validationErrors: [] } }, computed: Object.assign({}, context, @@ -425,6 +731,7 @@ var script = { deep: true }, internalModelProxy: function internalModelProxy (newValue, oldValue) { + this.performValidation(); if (!this.isVmodeled && !shallowEqualObjects(newValue, oldValue)) { this.context.model = newValue; } @@ -440,12 +747,29 @@ var script = { this.formulateFormRegister(this.nameOrFallback, this); } this.updateLocalAttributes(this.$attrs); + this.performValidation(); }, methods: { updateLocalAttributes: function updateLocalAttributes (value) { if (!shallowEqualObjects(value, this.localAttributes)) { this.localAttributes = value; } + }, + performValidation: function performValidation () { + var this$1 = this; + + var rules = parseRules(this.validation, this.$formulate.rules()); + Promise.all( + rules.map(function (ref) { + var rule = ref[0]; + var args = ref[1]; + + return rule.apply(void 0, [ this$1.context.model ].concat( args )) + .then(function (res) { return res ? false : 'Validation error!'; }) + }) + ) + .then(function (result) { return result.filter(function (result) { return result; }); }) + .then(function (errorMessages) { this$1.validationErrors = errorMessages; }); } } }; @@ -539,6 +863,7 @@ var __vue_render__ = function() { staticClass: "formulate-input", attrs: { "data-classification": _vm.classification, + "data-has-errors": _vm.hasErrors, "data-type": _vm.type } }, @@ -1601,7 +1926,8 @@ var Formulate = function Formulate () { FormulateInputSelect: FormulateInputSelect, FormulateInputTextArea: FormulateInputTextArea }, - library: library + library: library, + rules: rules }; }; @@ -1663,6 +1989,14 @@ Formulate.prototype.component = function component (type) { return false }; +/** + * Get validation rules. + * @return {object} object of validation functions + */ +Formulate.prototype.rules = function rules () { + return this.options.rules +}; + var Formulate$1 = new Formulate(); export default Formulate$1; diff --git a/dist/formulate.min.js b/dist/formulate.min.js index b3fa2e1..71dca1f 100644 --- a/dist/formulate.min.js +++ b/dist/formulate.min.js @@ -1,6 +1,7 @@ -var Formulate = (function (exports, isPlainObject, nanoid) { +var Formulate = (function (exports, isUrl, isPlainObject, nanoid) { 'use strict'; + isUrl = isUrl && isUrl.hasOwnProperty('default') ? isUrl['default'] : isUrl; isPlainObject = isPlainObject && isPlainObject.hasOwnProperty('default') ? isPlainObject['default'] : isPlainObject; nanoid = nanoid && nanoid.hasOwnProperty('default') ? nanoid['default'] : nanoid; @@ -163,6 +164,291 @@ var Formulate = (function (exports, isPlainObject, nanoid) { return [] } + /** + * Given an array or string return an array of callables. + * @param {array|string} validation + * @param {array} rules and array of functions + * @return {array} an array of functions + */ + function parseRules (validation, rules) { + if (typeof validation === 'string') { + return parseRules(validation.split('|'), rules) + } + if (!Array.isArray(validation)) { + return [] + } + return validation.map(function (rule) { return parseRule(rule, rules); }).filter(function (f) { return !!f; }) + } + + /** + * Given a string or function, parse it and return the an array in the format + * [fn, [...arguments]] + * @param {string|function} rule + */ + function parseRule (rule, rules) { + if (typeof rule === 'function') { + return [rule, []] + } + if (Array.isArray(rule) && rule.length) { + if (typeof rule[0] === 'string' && rules.hasOwnProperty(rule[0])) { + return [rules[rule.shift()], rule] + } + if (typeof rule[0] === 'function') { + return [rule.shift(), rule] + } + } + if (typeof rule === 'string') { + var segments = rule.split(':'); + var functionName = segments.shift(); + if (rules.hasOwnProperty(functionName)) { + return [rules[functionName], segments.length ? segments.join(':').split(',') : []] + } else { + throw new Error(("Unknown validation rule " + rule)) + } + } + return false + } + + /** + * Library of rules + */ + var rules = { + /** + * Rule: the value must be "yes", "on", "1", or true + */ + accepted: function (value) { + return Promise.resolve(['yes', 'on', '1', 1, true, 'true'].includes(value)) + }, + + /** + * Rule: must be a value + */ + required: function (value, isRequired) { + if ( isRequired === void 0 ) isRequired = true; + + return Promise.resolve((function () { + if (!isRequired || ['no', 'false'].includes(isRequired)) { + return true + } + if (Array.isArray(value)) { + return !!value.length + } + if (typeof value === 'string') { + return !!value + } + if (typeof value === 'object') { + return (!value) ? false : !!Object.keys(value).length + } + return true + })()) + }, + + /** + * Rule: Value is in an array (stack). + */ + in: function (value) { + var stack = [], len = arguments.length - 1; + while ( len-- > 0 ) stack[ len ] = arguments[ len + 1 ]; + + return Promise.resolve(stack.find(function (item) { + if (typeof item === 'object') { + return shallowEqualObjects(item, value) + } + return item === value + }) !== undefined) + }, + + /** + * Rule: Value is not in stack. + */ + not: function (value) { + var stack = [], len = arguments.length - 1; + while ( len-- > 0 ) stack[ len ] = arguments[ len + 1 ]; + + return Promise.resolve(stack.find(function (item) { + if (typeof item === 'object') { + return shallowEqualObjects(item, value) + } + return item === value + }) === undefined) + }, + + /** + * Rule: Match the value against a (stack) of patterns or strings + */ + matches: function (value) { + var stack = [], len = arguments.length - 1; + while ( len-- > 0 ) stack[ len ] = arguments[ len + 1 ]; + + return Promise.resolve(!!stack.find(function (pattern) { + if (pattern instanceof RegExp) { + return pattern.test(value) + } + return pattern === value + })) + }, + + /** + * Rule: checks if a string is a valid url + */ + url: function (value) { + return Promise.resolve(isUrl(value)) + }, + + /** + * Rule: ensures the value is a date according to Date.parse() + */ + date: function (value) { + return Promise.resolve(!isNaN(Date.parse(value))) + }, + + /** + * Rule: checks if a value is after a given date. Defaults to current time + */ + after: function (value, compare) { + if ( compare === void 0 ) compare = false; + + var timestamp = Date.parse(compare || new Date()); + var fieldValue = Date.parse(value); + return Promise.resolve(isNaN(fieldValue) ? false : (fieldValue > timestamp)) + }, + + /** + * Rule: checks if a value is after a given date. Defaults to current time + */ + before: function (value, compare) { + if ( compare === void 0 ) compare = false; + + var timestamp = Date.parse(compare || new Date()); + var fieldValue = Date.parse(value); + return Promise.resolve(isNaN(fieldValue) ? false : (fieldValue < timestamp)) + }, + + /** + * Rule: checks if the value is only alpha numeric + */ + alpha: function (value, set) { + if ( set === void 0 ) set = 'default'; + + var sets = { + default: /^[a-zA-ZÀ-ÖØ-öø-ÿ]+$/, + latin: /^[a-z][A-Z]$/ + }; + var selectedSet = sets.hasOwnProperty(set) ? set : 'default'; + return Promise.resolve(sets[selectedSet].test(value)) + }, + + /** + * Rule: checks if the value is only alpha numeric + */ + number: function (value) { + return Promise.resolve(!isNaN(value)) + }, + + /** + * Rule: checks if the value is alpha numeric + */ + alphanumeric: function (value, set) { + if ( set === void 0 ) set = 'default'; + + var sets = { + default: /^[a-zA-Z0-9À-ÖØ-öø-ÿ]+$/, + latin: /^[a-zA-Z0-9]$/ + }; + var selectedSet = sets.hasOwnProperty(set) ? set : 'default'; + return Promise.resolve(sets[selectedSet].test(value)) + }, + + /** + * Rule: checks if the value is between two other values + */ + between: function (value, from, to) { + return Promise.resolve((function () { + if (from === null || to === null || isNaN(from) || isNaN(to)) { + return false + } + from = Number(from); + to = Number(to); + if (!isNaN(value)) { + value = Number(value); + return (value > from && value < to) + } + if (typeof value === 'string') { + return value.length > from && value.length < to + } + return false + })()) + }, + + /** + * Rule: tests + */ + email: function (value) { + // eslint-disable-next-line + var isEmail = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i; + return Promise.resolve(isEmail.test(value)) + }, + + /** + * Check the file type is correct. + */ + mime: function (files) { + var types = [], len = arguments.length - 1; + while ( len-- > 0 ) types[ len ] = arguments[ len + 1 ]; + + return Promise.resolve((function () { + if (typeof window !== 'undefined' && typeof FileReader !== 'undefined' && typeof Blob !== 'undefined') { + for (var i in files) { + if (!types.includes(files[i].type)) { + return false + } + } + } + return true + })()) + }, + + /** + * Check the minimum value of a particular. + */ + min: function (value, minimum) { + return Promise.resolve((function () { + minimum = Number(minimum); + if (!isNaN(value)) { + value = Number(value); + return value >= minimum + } + if (typeof value === 'string') { + return value.length >= minimum + } + if (Array.isArray(value)) { + return value.length >= minimum + } + return false + })()) + }, + + /** + * Check the minimum value of a particular. + */ + max: function (value, minimum) { + return Promise.resolve((function () { + minimum = Number(minimum); + if (!isNaN(value)) { + value = Number(value); + return value <= minimum + } + if (typeof value === 'string') { + return value.length <= minimum + } + if (Array.isArray(value)) { + return value.length <= minimum + } + return false + })()) + } + }; + /** * For a single instance of an input, export all of the context needed to fully * render that element. @@ -189,7 +475,8 @@ var Formulate = (function (exports, isPlainObject, nanoid) { elementAttributes: elementAttributes, logicalLabelPosition: logicalLabelPosition, isVmodeled: isVmodeled, - mergedErrors: mergedErrors + mergedErrors: mergedErrors, + hasErrors: hasErrors }; /** @@ -302,6 +589,13 @@ var Formulate = (function (exports, isPlainObject, nanoid) { .reduce(function (errors, err) { return !errors.includes(err) ? errors.concat(err) : errors; }, []) } + /** + * Does this computed property have errors. + */ + function hasErrors () { + return !!this.mergedErrors.length + } + /** * Defines the model used throughout the existing context. * @param {object} context @@ -400,6 +694,17 @@ var Formulate = (function (exports, isPlainObject, nanoid) { type: [String, Array, Boolean], default: false }, + validation: { + type: [String, Boolean, Array], + default: false + }, + validationBehavior: { + type: String, + default: 'blur', + validator: function (value) { + return ['blur', 'live'].includes(value) + } + }, error: { type: [String, Boolean], default: false @@ -409,7 +714,8 @@ var Formulate = (function (exports, isPlainObject, nanoid) { return { defaultId: nanoid(9), localAttributes: {}, - internalModelProxy: this.formulateValue + internalModelProxy: this.formulateValue, + validationErrors: [] } }, computed: Object.assign({}, context, @@ -428,6 +734,7 @@ var Formulate = (function (exports, isPlainObject, nanoid) { deep: true }, internalModelProxy: function internalModelProxy (newValue, oldValue) { + this.performValidation(); if (!this.isVmodeled && !shallowEqualObjects(newValue, oldValue)) { this.context.model = newValue; } @@ -443,12 +750,29 @@ var Formulate = (function (exports, isPlainObject, nanoid) { this.formulateFormRegister(this.nameOrFallback, this); } this.updateLocalAttributes(this.$attrs); + this.performValidation(); }, methods: { updateLocalAttributes: function updateLocalAttributes (value) { if (!shallowEqualObjects(value, this.localAttributes)) { this.localAttributes = value; } + }, + performValidation: function performValidation () { + var this$1 = this; + + var rules = parseRules(this.validation, this.$formulate.rules()); + Promise.all( + rules.map(function (ref) { + var rule = ref[0]; + var args = ref[1]; + + return rule.apply(void 0, [ this$1.context.model ].concat( args )) + .then(function (res) { return res ? false : 'Validation error!'; }) + }) + ) + .then(function (result) { return result.filter(function (result) { return result; }); }) + .then(function (errorMessages) { this$1.validationErrors = errorMessages; }); } } }; @@ -542,6 +866,7 @@ var Formulate = (function (exports, isPlainObject, nanoid) { staticClass: "formulate-input", attrs: { "data-classification": _vm.classification, + "data-has-errors": _vm.hasErrors, "data-type": _vm.type } }, @@ -1604,7 +1929,8 @@ var Formulate = (function (exports, isPlainObject, nanoid) { FormulateInputSelect: FormulateInputSelect, FormulateInputTextArea: FormulateInputTextArea }, - library: library + library: library, + rules: rules }; }; @@ -1666,10 +1992,18 @@ var Formulate = (function (exports, isPlainObject, nanoid) { return false }; + /** + * Get validation rules. + * @return {object} object of validation functions + */ + Formulate.prototype.rules = function rules () { + return this.options.rules + }; + var Formulate$1 = new Formulate(); exports.default = Formulate$1; return exports; -}({}, isPlainObject, nanoid)); +}({}, isUrl, isPlainObject, nanoid)); diff --git a/dist/formulate.umd.js b/dist/formulate.umd.js index d47d5ba..15cd246 100644 --- a/dist/formulate.umd.js +++ b/dist/formulate.umd.js @@ -1,9 +1,10 @@ (function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('is-plain-object'), require('nanoid')) : - typeof define === 'function' && define.amd ? define(['exports', 'is-plain-object', 'nanoid'], factory) : - (global = global || self, factory(global.Formulate = {}, global.isPlainObject, global.nanoid)); -}(this, (function (exports, isPlainObject, nanoid) { 'use strict'; + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('is-url'), require('is-plain-object'), require('nanoid')) : + typeof define === 'function' && define.amd ? define(['exports', 'is-url', 'is-plain-object', 'nanoid'], factory) : + (global = global || self, factory(global.Formulate = {}, global.isUrl, global.isPlainObject, global.nanoid)); +}(this, (function (exports, isUrl, isPlainObject, nanoid) { 'use strict'; + isUrl = isUrl && isUrl.hasOwnProperty('default') ? isUrl['default'] : isUrl; isPlainObject = isPlainObject && isPlainObject.hasOwnProperty('default') ? isPlainObject['default'] : isPlainObject; nanoid = nanoid && nanoid.hasOwnProperty('default') ? nanoid['default'] : nanoid; @@ -166,6 +167,291 @@ return [] } + /** + * Given an array or string return an array of callables. + * @param {array|string} validation + * @param {array} rules and array of functions + * @return {array} an array of functions + */ + function parseRules (validation, rules) { + if (typeof validation === 'string') { + return parseRules(validation.split('|'), rules) + } + if (!Array.isArray(validation)) { + return [] + } + return validation.map(function (rule) { return parseRule(rule, rules); }).filter(function (f) { return !!f; }) + } + + /** + * Given a string or function, parse it and return the an array in the format + * [fn, [...arguments]] + * @param {string|function} rule + */ + function parseRule (rule, rules) { + if (typeof rule === 'function') { + return [rule, []] + } + if (Array.isArray(rule) && rule.length) { + if (typeof rule[0] === 'string' && rules.hasOwnProperty(rule[0])) { + return [rules[rule.shift()], rule] + } + if (typeof rule[0] === 'function') { + return [rule.shift(), rule] + } + } + if (typeof rule === 'string') { + var segments = rule.split(':'); + var functionName = segments.shift(); + if (rules.hasOwnProperty(functionName)) { + return [rules[functionName], segments.length ? segments.join(':').split(',') : []] + } else { + throw new Error(("Unknown validation rule " + rule)) + } + } + return false + } + + /** + * Library of rules + */ + var rules = { + /** + * Rule: the value must be "yes", "on", "1", or true + */ + accepted: function (value) { + return Promise.resolve(['yes', 'on', '1', 1, true, 'true'].includes(value)) + }, + + /** + * Rule: must be a value + */ + required: function (value, isRequired) { + if ( isRequired === void 0 ) isRequired = true; + + return Promise.resolve((function () { + if (!isRequired || ['no', 'false'].includes(isRequired)) { + return true + } + if (Array.isArray(value)) { + return !!value.length + } + if (typeof value === 'string') { + return !!value + } + if (typeof value === 'object') { + return (!value) ? false : !!Object.keys(value).length + } + return true + })()) + }, + + /** + * Rule: Value is in an array (stack). + */ + in: function (value) { + var stack = [], len = arguments.length - 1; + while ( len-- > 0 ) stack[ len ] = arguments[ len + 1 ]; + + return Promise.resolve(stack.find(function (item) { + if (typeof item === 'object') { + return shallowEqualObjects(item, value) + } + return item === value + }) !== undefined) + }, + + /** + * Rule: Value is not in stack. + */ + not: function (value) { + var stack = [], len = arguments.length - 1; + while ( len-- > 0 ) stack[ len ] = arguments[ len + 1 ]; + + return Promise.resolve(stack.find(function (item) { + if (typeof item === 'object') { + return shallowEqualObjects(item, value) + } + return item === value + }) === undefined) + }, + + /** + * Rule: Match the value against a (stack) of patterns or strings + */ + matches: function (value) { + var stack = [], len = arguments.length - 1; + while ( len-- > 0 ) stack[ len ] = arguments[ len + 1 ]; + + return Promise.resolve(!!stack.find(function (pattern) { + if (pattern instanceof RegExp) { + return pattern.test(value) + } + return pattern === value + })) + }, + + /** + * Rule: checks if a string is a valid url + */ + url: function (value) { + return Promise.resolve(isUrl(value)) + }, + + /** + * Rule: ensures the value is a date according to Date.parse() + */ + date: function (value) { + return Promise.resolve(!isNaN(Date.parse(value))) + }, + + /** + * Rule: checks if a value is after a given date. Defaults to current time + */ + after: function (value, compare) { + if ( compare === void 0 ) compare = false; + + var timestamp = Date.parse(compare || new Date()); + var fieldValue = Date.parse(value); + return Promise.resolve(isNaN(fieldValue) ? false : (fieldValue > timestamp)) + }, + + /** + * Rule: checks if a value is after a given date. Defaults to current time + */ + before: function (value, compare) { + if ( compare === void 0 ) compare = false; + + var timestamp = Date.parse(compare || new Date()); + var fieldValue = Date.parse(value); + return Promise.resolve(isNaN(fieldValue) ? false : (fieldValue < timestamp)) + }, + + /** + * Rule: checks if the value is only alpha numeric + */ + alpha: function (value, set) { + if ( set === void 0 ) set = 'default'; + + var sets = { + default: /^[a-zA-ZÀ-ÖØ-öø-ÿ]+$/, + latin: /^[a-z][A-Z]$/ + }; + var selectedSet = sets.hasOwnProperty(set) ? set : 'default'; + return Promise.resolve(sets[selectedSet].test(value)) + }, + + /** + * Rule: checks if the value is only alpha numeric + */ + number: function (value) { + return Promise.resolve(!isNaN(value)) + }, + + /** + * Rule: checks if the value is alpha numeric + */ + alphanumeric: function (value, set) { + if ( set === void 0 ) set = 'default'; + + var sets = { + default: /^[a-zA-Z0-9À-ÖØ-öø-ÿ]+$/, + latin: /^[a-zA-Z0-9]$/ + }; + var selectedSet = sets.hasOwnProperty(set) ? set : 'default'; + return Promise.resolve(sets[selectedSet].test(value)) + }, + + /** + * Rule: checks if the value is between two other values + */ + between: function (value, from, to) { + return Promise.resolve((function () { + if (from === null || to === null || isNaN(from) || isNaN(to)) { + return false + } + from = Number(from); + to = Number(to); + if (!isNaN(value)) { + value = Number(value); + return (value > from && value < to) + } + if (typeof value === 'string') { + return value.length > from && value.length < to + } + return false + })()) + }, + + /** + * Rule: tests + */ + email: function (value) { + // eslint-disable-next-line + var isEmail = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i; + return Promise.resolve(isEmail.test(value)) + }, + + /** + * Check the file type is correct. + */ + mime: function (files) { + var types = [], len = arguments.length - 1; + while ( len-- > 0 ) types[ len ] = arguments[ len + 1 ]; + + return Promise.resolve((function () { + if (typeof window !== 'undefined' && typeof FileReader !== 'undefined' && typeof Blob !== 'undefined') { + for (var i in files) { + if (!types.includes(files[i].type)) { + return false + } + } + } + return true + })()) + }, + + /** + * Check the minimum value of a particular. + */ + min: function (value, minimum) { + return Promise.resolve((function () { + minimum = Number(minimum); + if (!isNaN(value)) { + value = Number(value); + return value >= minimum + } + if (typeof value === 'string') { + return value.length >= minimum + } + if (Array.isArray(value)) { + return value.length >= minimum + } + return false + })()) + }, + + /** + * Check the minimum value of a particular. + */ + max: function (value, minimum) { + return Promise.resolve((function () { + minimum = Number(minimum); + if (!isNaN(value)) { + value = Number(value); + return value <= minimum + } + if (typeof value === 'string') { + return value.length <= minimum + } + if (Array.isArray(value)) { + return value.length <= minimum + } + return false + })()) + } + }; + /** * For a single instance of an input, export all of the context needed to fully * render that element. @@ -192,7 +478,8 @@ elementAttributes: elementAttributes, logicalLabelPosition: logicalLabelPosition, isVmodeled: isVmodeled, - mergedErrors: mergedErrors + mergedErrors: mergedErrors, + hasErrors: hasErrors }; /** @@ -305,6 +592,13 @@ .reduce(function (errors, err) { return !errors.includes(err) ? errors.concat(err) : errors; }, []) } + /** + * Does this computed property have errors. + */ + function hasErrors () { + return !!this.mergedErrors.length + } + /** * Defines the model used throughout the existing context. * @param {object} context @@ -403,6 +697,17 @@ type: [String, Array, Boolean], default: false }, + validation: { + type: [String, Boolean, Array], + default: false + }, + validationBehavior: { + type: String, + default: 'blur', + validator: function (value) { + return ['blur', 'live'].includes(value) + } + }, error: { type: [String, Boolean], default: false @@ -412,7 +717,8 @@ return { defaultId: nanoid(9), localAttributes: {}, - internalModelProxy: this.formulateValue + internalModelProxy: this.formulateValue, + validationErrors: [] } }, computed: Object.assign({}, context, @@ -431,6 +737,7 @@ deep: true }, internalModelProxy: function internalModelProxy (newValue, oldValue) { + this.performValidation(); if (!this.isVmodeled && !shallowEqualObjects(newValue, oldValue)) { this.context.model = newValue; } @@ -446,12 +753,29 @@ this.formulateFormRegister(this.nameOrFallback, this); } this.updateLocalAttributes(this.$attrs); + this.performValidation(); }, methods: { updateLocalAttributes: function updateLocalAttributes (value) { if (!shallowEqualObjects(value, this.localAttributes)) { this.localAttributes = value; } + }, + performValidation: function performValidation () { + var this$1 = this; + + var rules = parseRules(this.validation, this.$formulate.rules()); + Promise.all( + rules.map(function (ref) { + var rule = ref[0]; + var args = ref[1]; + + return rule.apply(void 0, [ this$1.context.model ].concat( args )) + .then(function (res) { return res ? false : 'Validation error!'; }) + }) + ) + .then(function (result) { return result.filter(function (result) { return result; }); }) + .then(function (errorMessages) { this$1.validationErrors = errorMessages; }); } } }; @@ -545,6 +869,7 @@ staticClass: "formulate-input", attrs: { "data-classification": _vm.classification, + "data-has-errors": _vm.hasErrors, "data-type": _vm.type } }, @@ -1607,7 +1932,8 @@ FormulateInputSelect: FormulateInputSelect, FormulateInputTextArea: FormulateInputTextArea }, - library: library + library: library, + rules: rules }; }; @@ -1669,6 +1995,14 @@ return false }; + /** + * Get validation rules. + * @return {object} object of validation functions + */ + Formulate.prototype.rules = function rules () { + return this.options.rules + }; + var Formulate$1 = new Formulate(); exports.default = Formulate$1; diff --git a/dist/snow.css b/dist/snow.css index dae8954..ca42800 100644 --- a/dist/snow.css +++ b/dist/snow.css @@ -12,7 +12,7 @@ .formulate-input .formulate-input-help { color: #6d6d6d; font-size: .7em; - font-weight: 300; + font-weight: 400; line-height: 1.5; margin-bottom: .25em; } .formulate-input .formulate-input-errors { diff --git a/dist/snow.min.css b/dist/snow.min.css index fbb25f0..3aaa52e 100644 --- a/dist/snow.min.css +++ b/dist/snow.min.css @@ -1,2 +1,2 @@ -.formulate-input{margin-bottom:2em}.formulate-input .formulate-input-label{display:block;line-height:1.5;font-size:.9em;font-weight:600;margin-bottom:.1em}.formulate-input .formulate-input-element{max-width:20em;margin-bottom:.1em}.formulate-input .formulate-input-help{color:#6d6d6d;font-size:.7em;font-weight:300;line-height:1.5;margin-bottom:.25em}.formulate-input .formulate-input-errors{list-style-type:none;padding:0;margin:0}.formulate-input .formulate-input-error{color:#960505;font-size:.8em;font-weight:300;line-height:1.5;margin-bottom:.25em}.formulate-input .formulate-input-group-item{margin-bottom:.5em}.formulate-input:last-child{margin-bottom:0}.formulate-input[data-classification=text] input{-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:.3em;border:1px solid #cecece;box-sizing:border-box;background-color:transparent;font-size:.9em;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;padding:.75em;display:block;width:100%;font-weight:400}.formulate-input[data-classification=text] input::-webkit-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=text] input::-moz-placeholder{color:#a8a8a8}.formulate-input[data-classification=text] input:-ms-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=text] input::-ms-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=text] input::placeholder{color:#a8a8a8}.formulate-input[data-classification=text] input:focus{outline:0;border:1px solid #41b883}.formulate-input[data-classification=textarea] textarea{-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:.3em;border:1px solid #cecece;box-sizing:border-box;background-color:transparent;font-size:.9em;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;padding:.75em;display:block;width:100%;font-weight:400}.formulate-input[data-classification=textarea] textarea::-webkit-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=textarea] textarea::-moz-placeholder{color:#a8a8a8}.formulate-input[data-classification=textarea] textarea:-ms-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=textarea] textarea::-ms-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=textarea] textarea::placeholder{color:#a8a8a8}.formulate-input[data-classification=textarea] textarea:focus{outline:0;border:1px solid #41b883}.formulate-input[data-classification=select] .formulate-input-element{position:relative}.formulate-input[data-classification=select] .formulate-input-element:before{content:"";width:0;height:0;border-color:#cecece transparent transparent;border-style:solid;border-width:.3em .3em 0;top:50%;margin-top:-.1em;right:1em;position:absolute}.formulate-input[data-classification=select] select{-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:.3em;border:1px solid #cecece;box-sizing:border-box;background-color:transparent;font-size:.9em;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;display:block;width:100%;font-weight:400;padding:.75em 2em .75em .75em}.formulate-input[data-classification=select] select::-webkit-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=select] select::-moz-placeholder{color:#a8a8a8}.formulate-input[data-classification=select] select:-ms-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=select] select::-ms-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=select] select::placeholder{color:#a8a8a8}.formulate-input[data-classification=select] select:focus{outline:0;border:1px solid #41b883}.formulate-input[data-classification=select] select[data-placeholder-selected]{color:#a8a8a8}.formulate-input[data-classification=box] .formulate-input-element,.formulate-input[data-classification=box] .formulate-input-wrapper{display:-webkit-box;display:flex;-webkit-box-align:center;align-items:center}.formulate-input[data-classification=box] .formulate-input-element{overflow:hidden}.formulate-input[data-classification=box] .formulate-input-element input{position:absolute;left:-999px}.formulate-input[data-classification=box] .formulate-input-element-decorator{display:block;width:1em;height:1em;border-radius:.25em;border:1px solid #cecece;position:relative}.formulate-input[data-classification=box] .formulate-input-element-decorator:before{content:"";display:block;background-size:contain;background-position:100%;width:calc(100% - .125em);height:calc(100% - .125em);box-sizing:border-box;position:absolute;top:.0625em;left:.0625em}.formulate-input[data-classification=box] .formulate-input-element[data-type=radio] .formulate-input-element-decorator{border-radius:1em}.formulate-input[data-classification=box] .formulate-input-element[data-type=radio] .formulate-input-element-decorator:before{border-radius:1em;width:calc(100% - .5em);height:calc(100% - .5em);top:.25em;left:.25em}.formulate-input[data-classification=box] .formulate-input-element input[type=checkbox]:checked~.formulate-input-element-decorator{border-color:#41b883}.formulate-input[data-classification=box] .formulate-input-element input[type=checkbox]:checked~.formulate-input-element-decorator:before{background-image:url('data:image/svg+xml;utf8,')}.formulate-input[data-classification=box] .formulate-input-element input[type=radio]:checked~.formulate-input-element-decorator{border-color:#41b883}.formulate-input[data-classification=box] .formulate-input-element input[type=radio]:checked~.formulate-input-element-decorator:before{background-color:#41b883}.formulate-input[data-classification=box] .formulate-input-element input:focus~.formulate-input-element-decorator{border-color:#41b883}.formulate-input[data-classification=box] .formulate-input-label--after{margin-left:.5em}.formulate-input[data-classification=box] .formulate-input-label--before{margin-right:.5em}.formulate-input[data-classification=group]>.formulate-input-wrapper>.formulate-input-label{margin-bottom:.5em} -/*# sourceMappingURL=data:application/json;base64,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SUFDRSxvQkFBdUIsQ0FDdkIsdUlBQ0Usd0JBQTJCLENBQy9CLGtIQUNFLG9CQUF1QixDQUMzQix3RUFDRSxnQkFBbUIsQ0FDckIseUVBQ0UsaUJBQW9CLENBQ3RCLDRGQUNFLGtCQUFxQiIsImZpbGUiOiJzdGRpbiIsInNvdXJjZXNDb250ZW50IjpbIi5mb3JtdWxhdGUtaW5wdXQge1xuICBtYXJnaW4tYm90dG9tOiAyZW07IH1cbiAgLmZvcm11bGF0ZS1pbnB1dCAuZm9ybXVsYXRlLWlucHV0LWxhYmVsIHtcbiAgICBkaXNwbGF5OiBibG9jaztcbiAgICBsaW5lLWhlaWdodDogMS41O1xuICAgIGZvbnQtc2l6ZTogLjllbTtcbiAgICBmb250LXdlaWdodDogNjAwO1xuICAgIG1hcmdpbi1ib3R0b206IC4xZW07IH1cbiAgLmZvcm11bGF0ZS1pbnB1dCAuZm9ybXVsYXRlLWlucHV0LWVsZW1lbnQge1xuICAgIG1heC13aWR0aDogMjBlbTtcbiAgICBtYXJnaW4tYm90dG9tOiAuMWVtOyB9XG4gIC5mb3JtdWxhdGUtaW5wdXQgLmZvcm11bGF0ZS1pbnB1dC1oZWxwIHtcbiAgICBjb2xvcjogIzZkNmQ2ZDtcbiAgICBmb250LXNpemU6IC43ZW07XG4gICAgZm9udC13ZWlnaHQ6IDMwMDtcbiAgICBsaW5lLWhlaWdodDogMS41O1xuICAgIG1hcmdpbi1ib3R0b206IC4yNWVtOyB9XG4gIC5mb3JtdWxhdGUtaW5wdXQgLmZvcm11bGF0ZS1pbnB1dC1lcnJvcnMge1xuICAgIGxpc3Qtc3R5bGUtdHlwZTogbm9uZTtcbiAgICBwYWRkaW5nOiAwO1xuICAgIG1hcmdpbjogMDsgfVxuICAuZm9ybXVsYXRlLWlucHV0IC5mb3JtdWxhdGUtaW5wdXQtZXJyb3Ige1xuICAgIGNvbG9yOiAjOTYwNTA1O1xuICAgIGZvbnQtc2l6ZTogLjhlbTtcbiAgICBmb250LXdlaWdodDogMzAwO1xuICAgIGxpbmUtaGVpZ2h0OiAxLjU7XG4gICAgbWFyZ2luLWJvdHRvbTogLjI1ZW07IH1cbiAgLmZvcm11bGF0ZS1pbnB1dCAuZm9ybXVsYXRlLWlucHV0LWdyb3VwLWl0ZW0ge1xuICAgIG1hcmdpbi1ib3R0b206IC41ZW07IH1cbiAgLmZvcm11bGF0ZS1pbnB1dDpsYXN0LWNoaWxkIHtcbiAgICBtYXJnaW4tYm90dG9tOiAwOyB9XG4gIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0ndGV4dCddIGlucHV0IHtcbiAgICBhcHBlYXJhbmNlOiBub25lO1xuICAgIGJvcmRlci1yYWRpdXM6IC4zZW07XG4gICAgYm9yZGVyOiAxcHggc29saWQgI2NlY2VjZTtcbiAgICBib3gtc2l6aW5nOiBib3JkZXItYm94O1xuICAgIGJhY2tncm91bmQtY29sb3I6IHRyYW5zcGFyZW50O1xuICAgIGZvbnQtc2l6ZTogLjllbTtcbiAgICBmb250LWZhbWlseTogLWFwcGxlLXN5c3RlbSwgQmxpbmtNYWNTeXN0ZW1Gb250LCBcIlNlZ29lIFVJXCIsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiwgXCJBcHBsZSBDb2xvciBFbW9qaVwiLCBcIlNlZ29lIFVJIEVtb2ppXCIsIFwiU2Vnb2UgVUkgU3ltYm9sXCI7XG4gICAgcGFkZGluZzogLjc1ZW07XG4gICAgZGlzcGxheTogYmxvY2s7XG4gICAgd2lkdGg6IDEwMCU7XG4gICAgZm9udC13ZWlnaHQ6IDQwMDsgfVxuICAgIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0ndGV4dCddIGlucHV0OjpwbGFjZWhvbGRlciB7XG4gICAgICBjb2xvcjogI2E4YThhODsgfVxuICAgIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0ndGV4dCddIGlucHV0OmZvY3VzIHtcbiAgICAgIG91dGxpbmU6IDA7XG4gICAgICBib3JkZXI6IDFweCBzb2xpZCAjNDFiODgzOyB9XG4gIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0ndGV4dGFyZWEnXSB0ZXh0YXJlYSB7XG4gICAgYXBwZWFyYW5jZTogbm9uZTtcbiAgICBib3JkZXItcmFkaXVzOiAuM2VtO1xuICAgIGJvcmRlcjogMXB4IHNvbGlkICNjZWNlY2U7XG4gICAgYm94LXNpemluZzogYm9yZGVyLWJveDtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiB0cmFuc3BhcmVudDtcbiAgICBmb250LXNpemU6IC45ZW07XG4gICAgZm9udC1mYW1pbHk6IC1hcHBsZS1zeXN0ZW0sIEJsaW5rTWFjU3lzdGVtRm9udCwgXCJTZWdvZSBVSVwiLCBSb2JvdG8sIEhlbHZldGljYSwgQXJpYWwsIHNhbnMtc2VyaWYsIFwiQXBwbGUgQ29sb3IgRW1vamlcIiwgXCJTZWdvZSBVSSBFbW9qaVwiLCBcIlNlZ29lIFVJIFN5bWJvbFwiO1xuICAgIHBhZGRpbmc6IC43NWVtO1xuICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgIHdpZHRoOiAxMDAlO1xuICAgIGZvbnQtd2VpZ2h0OiA0MDA7IH1cbiAgICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J3RleHRhcmVhJ10gdGV4dGFyZWE6OnBsYWNlaG9sZGVyIHtcbiAgICAgIGNvbG9yOiAjYThhOGE4OyB9XG4gICAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPSd0ZXh0YXJlYSddIHRleHRhcmVhOmZvY3VzIHtcbiAgICAgIG91dGxpbmU6IDA7XG4gICAgICBib3JkZXI6IDFweCBzb2xpZCAjNDFiODgzOyB9XG4gIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nc2VsZWN0J10gLmZvcm11bGF0ZS1pbnB1dC1lbGVtZW50IHtcbiAgICBwb3NpdGlvbjogcmVsYXRpdmU7IH1cbiAgICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J3NlbGVjdCddIC5mb3JtdWxhdGUtaW5wdXQtZWxlbWVudDo6YmVmb3JlIHtcbiAgICAgIGNvbnRlbnQ6ICcnO1xuICAgICAgd2lkdGg6IDA7XG4gICAgICBoZWlnaHQ6IDA7XG4gICAgICBib3JkZXI6IC4zZW0gc29saWQgdHJhbnNwYXJlbnQ7XG4gICAgICBib3JkZXItdG9wLWNvbG9yOiAjY2VjZWNlO1xuICAgICAgYm9yZGVyLWJvdHRvbS13aWR0aDogMDtcbiAgICAgIHRvcDogNTAlO1xuICAgICAgbWFyZ2luLXRvcDogLS4xZW07XG4gICAgICByaWdodDogMWVtO1xuICAgICAgcG9zaXRpb246IGFic29sdXRlOyB9XG4gIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nc2VsZWN0J10gc2VsZWN0IHtcbiAgICBhcHBlYXJhbmNlOiBub25lO1xuICAgIGJvcmRlci1yYWRpdXM6IC4zZW07XG4gICAgYm9yZGVyOiAxcHggc29saWQgI2NlY2VjZTtcbiAgICBib3gtc2l6aW5nOiBib3JkZXItYm94O1xuICAgIGJhY2tncm91bmQtY29sb3I6IHRyYW5zcGFyZW50O1xuICAgIGZvbnQtc2l6ZTogLjllbTtcbiAgICBmb250LWZhbWlseTogLWFwcGxlLXN5c3RlbSwgQmxpbmtNYWNTeXN0ZW1Gb250LCBcIlNlZ29lIFVJXCIsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiwgXCJBcHBsZSBDb2xvciBFbW9qaVwiLCBcIlNlZ29lIFVJIEVtb2ppXCIsIFwiU2Vnb2UgVUkgU3ltYm9sXCI7XG4gICAgcGFkZGluZzogLjc1ZW07XG4gICAgZGlzcGxheTogYmxvY2s7XG4gICAgd2lkdGg6IDEwMCU7XG4gICAgZm9udC13ZWlnaHQ6IDQwMDtcbiAgICBwYWRkaW5nLXJpZ2h0OiAyZW07IH1cbiAgICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J3NlbGVjdCddIHNlbGVjdDo6cGxhY2Vob2xkZXIge1xuICAgICAgY29sb3I6ICNhOGE4YTg7IH1cbiAgICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J3NlbGVjdCddIHNlbGVjdDpmb2N1cyB7XG4gICAgICBvdXRsaW5lOiAwO1xuICAgICAgYm9yZGVyOiAxcHggc29saWQgIzQxYjg4MzsgfVxuICAgIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nc2VsZWN0J10gc2VsZWN0W2RhdGEtcGxhY2Vob2xkZXItc2VsZWN0ZWRdIHtcbiAgICAgIGNvbG9yOiAjYThhOGE4OyB9XG4gIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nYm94J10gLmZvcm11bGF0ZS1pbnB1dC13cmFwcGVyIHtcbiAgICBkaXNwbGF5OiBmbGV4O1xuICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7IH1cbiAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPSdib3gnXSAuZm9ybXVsYXRlLWlucHV0LWVsZW1lbnQge1xuICAgIG92ZXJmbG93OiBoaWRkZW47XG4gICAgZGlzcGxheTogZmxleDtcbiAgICBhbGlnbi1pdGVtczogY2VudGVyOyB9XG4gICAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPSdib3gnXSAuZm9ybXVsYXRlLWlucHV0LWVsZW1lbnQgaW5wdXQge1xuICAgICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgICAgbGVmdDogLTk5OXB4OyB9XG4gICAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPSdib3gnXSAuZm9ybXVsYXRlLWlucHV0LWVsZW1lbnQtZGVjb3JhdG9yIHtcbiAgICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgICAgd2lkdGg6IDFlbTtcbiAgICAgIGhlaWdodDogMWVtO1xuICAgICAgYm9yZGVyLXJhZGl1czogLjI1ZW07XG4gICAgICBib3JkZXI6IDFweCBzb2xpZCAjY2VjZWNlO1xuICAgICAgcG9zaXRpb246IHJlbGF0aXZlOyB9XG4gICAgICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J2JveCddIC5mb3JtdWxhdGUtaW5wdXQtZWxlbWVudC1kZWNvcmF0b3I6OmJlZm9yZSB7XG4gICAgICAgIGNvbnRlbnQ6ICcnO1xuICAgICAgICBkaXNwbGF5OiBibG9jaztcbiAgICAgICAgYmFja2dyb3VuZC1zaXplOiBjb250YWluO1xuICAgICAgICBiYWNrZ3JvdW5kLXBvc2l0aW9uOiByaWdodDtcbiAgICAgICAgd2lkdGg6IGNhbGMoMTAwJSAtIC4xMjVlbSk7XG4gICAgICAgIGhlaWdodDogY2FsYygxMDAlIC0gLjEyNWVtKTtcbiAgICAgICAgYm94LXNpemluZzogYm9yZGVyLWJveDtcbiAgICAgICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgICAgICB0b3A6IC4wNjI1ZW07XG4gICAgICAgIGxlZnQ6IC4wNjI1ZW07IH1cbiAgICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J2JveCddIC5mb3JtdWxhdGUtaW5wdXQtZWxlbWVudFtkYXRhLXR5cGU9XCJyYWRpb1wiXSAuZm9ybXVsYXRlLWlucHV0LWVsZW1lbnQtZGVjb3JhdG9yIHtcbiAgICAgIGJvcmRlci1yYWRpdXM6IDFlbTsgfVxuICAgICAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPSdib3gnXSAuZm9ybXVsYXRlLWlucHV0LWVsZW1lbnRbZGF0YS10eXBlPVwicmFkaW9cIl0gLmZvcm11bGF0ZS1pbnB1dC1lbGVtZW50LWRlY29yYXRvcjo6YmVmb3JlIHtcbiAgICAgICAgYm9yZGVyLXJhZGl1czogMWVtO1xuICAgICAgICB3aWR0aDogY2FsYygxMDAlIC0gLjVlbSk7XG4gICAgICAgIGhlaWdodDogY2FsYygxMDAlIC0gLjVlbSk7XG4gICAgICAgIHRvcDogLjI1ZW07XG4gICAgICAgIGxlZnQ6IC4yNWVtOyB9XG4gICAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPSdib3gnXSAuZm9ybXVsYXRlLWlucHV0LWVsZW1lbnQgaW5wdXRbdHlwZT1cImNoZWNrYm94XCJdOmNoZWNrZWQgfiAuZm9ybXVsYXRlLWlucHV0LWVsZW1lbnQtZGVjb3JhdG9yIHtcbiAgICAgIGJvcmRlci1jb2xvcjogIzQxYjg4MzsgfVxuICAgICAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPSdib3gnXSAuZm9ybXVsYXRlLWlucHV0LWVsZW1lbnQgaW5wdXRbdHlwZT1cImNoZWNrYm94XCJdOmNoZWNrZWQgfiAuZm9ybXVsYXRlLWlucHV0LWVsZW1lbnQtZGVjb3JhdG9yOjpiZWZvcmUge1xuICAgICAgICBiYWNrZ3JvdW5kLWltYWdlOiB1cmwoJ2RhdGE6aW1hZ2Uvc3ZnK3htbDt1dGY4LDxzdmcgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiIHZpZXdCb3g9XCIwIDAgMTAwIDEwMFwiIGZpbGw9XCIlMjM0MWI4ODNcIj48cGF0aCBkPVwiTTguNzYsNTYuMmMtNi4zOC02LjM0LDMuMjYtMTYsOS42NC05LjY5TDM4LDY1Ljg4LDgwLjU2LDIzLjI5YzYuMzgtNi4zOCwxNi4wNywzLjMyLDkuNjksOS42OUw0Mi44NCw4MC4zN2E2LjgzLDYuODMsMCwwLDEtOS42NSwwWlwiLz48L3N2Zz4nKTsgfVxuICAgIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nYm94J10gLmZvcm11bGF0ZS1pbnB1dC1lbGVtZW50IGlucHV0W3R5cGU9XCJyYWRpb1wiXTpjaGVja2VkIH4gLmZvcm11bGF0ZS1pbnB1dC1lbGVtZW50LWRlY29yYXRvciB7XG4gICAgICBib3JkZXItY29sb3I6ICM0MWI4ODM7IH1cbiAgICAgIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nYm94J10gLmZvcm11bGF0ZS1pbnB1dC1lbGVtZW50IGlucHV0W3R5cGU9XCJyYWRpb1wiXTpjaGVja2VkIH4gLmZvcm11bGF0ZS1pbnB1dC1lbGVtZW50LWRlY29yYXRvcjo6YmVmb3JlIHtcbiAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogIzQxYjg4MzsgfVxuICAgIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nYm94J10gLmZvcm11bGF0ZS1pbnB1dC1lbGVtZW50IGlucHV0OmZvY3VzIH4gLmZvcm11bGF0ZS1pbnB1dC1lbGVtZW50LWRlY29yYXRvciB7XG4gICAgICBib3JkZXItY29sb3I6ICM0MWI4ODM7IH1cbiAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPSdib3gnXSAuZm9ybXVsYXRlLWlucHV0LWxhYmVsLS1hZnRlciB7XG4gICAgbWFyZ2luLWxlZnQ6IC41ZW07IH1cbiAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPSdib3gnXSAuZm9ybXVsYXRlLWlucHV0LWxhYmVsLS1iZWZvcmUge1xuICAgIG1hcmdpbi1yaWdodDogLjVlbTsgfVxuICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249XCJncm91cFwiXSA+IC5mb3JtdWxhdGUtaW5wdXQtd3JhcHBlciA+IC5mb3JtdWxhdGUtaW5wdXQtbGFiZWwge1xuICAgIG1hcmdpbi1ib3R0b206IC41ZW07IH1cbiJdfQ== */ \ No newline at end of file +.formulate-input{margin-bottom:2em}.formulate-input .formulate-input-label{display:block;line-height:1.5;font-size:.9em;font-weight:600;margin-bottom:.1em}.formulate-input .formulate-input-element{max-width:20em;margin-bottom:.1em}.formulate-input .formulate-input-help{color:#6d6d6d;font-size:.7em;font-weight:400;line-height:1.5;margin-bottom:.25em}.formulate-input .formulate-input-errors{list-style-type:none;padding:0;margin:0}.formulate-input .formulate-input-error{color:#960505;font-size:.8em;font-weight:300;line-height:1.5;margin-bottom:.25em}.formulate-input .formulate-input-group-item{margin-bottom:.5em}.formulate-input:last-child{margin-bottom:0}.formulate-input[data-classification=text] input{-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:.3em;border:1px solid #cecece;box-sizing:border-box;background-color:transparent;font-size:.9em;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;padding:.75em;display:block;width:100%;font-weight:400}.formulate-input[data-classification=text] input::-webkit-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=text] input::-moz-placeholder{color:#a8a8a8}.formulate-input[data-classification=text] input:-ms-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=text] input::-ms-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=text] input::placeholder{color:#a8a8a8}.formulate-input[data-classification=text] input:focus{outline:0;border:1px solid #41b883}.formulate-input[data-classification=textarea] textarea{-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:.3em;border:1px solid #cecece;box-sizing:border-box;background-color:transparent;font-size:.9em;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;padding:.75em;display:block;width:100%;font-weight:400}.formulate-input[data-classification=textarea] textarea::-webkit-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=textarea] textarea::-moz-placeholder{color:#a8a8a8}.formulate-input[data-classification=textarea] textarea:-ms-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=textarea] textarea::-ms-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=textarea] textarea::placeholder{color:#a8a8a8}.formulate-input[data-classification=textarea] textarea:focus{outline:0;border:1px solid #41b883}.formulate-input[data-classification=select] .formulate-input-element{position:relative}.formulate-input[data-classification=select] .formulate-input-element:before{content:"";width:0;height:0;border-color:#cecece transparent transparent;border-style:solid;border-width:.3em .3em 0;top:50%;margin-top:-.1em;right:1em;position:absolute}.formulate-input[data-classification=select] select{-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:.3em;border:1px solid #cecece;box-sizing:border-box;background-color:transparent;font-size:.9em;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;display:block;width:100%;font-weight:400;padding:.75em 2em .75em .75em}.formulate-input[data-classification=select] select::-webkit-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=select] select::-moz-placeholder{color:#a8a8a8}.formulate-input[data-classification=select] select:-ms-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=select] select::-ms-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=select] select::placeholder{color:#a8a8a8}.formulate-input[data-classification=select] select:focus{outline:0;border:1px solid #41b883}.formulate-input[data-classification=select] select[data-placeholder-selected]{color:#a8a8a8}.formulate-input[data-classification=box] .formulate-input-element,.formulate-input[data-classification=box] .formulate-input-wrapper{display:-webkit-box;display:flex;-webkit-box-align:center;align-items:center}.formulate-input[data-classification=box] .formulate-input-element{overflow:hidden}.formulate-input[data-classification=box] .formulate-input-element input{position:absolute;left:-999px}.formulate-input[data-classification=box] .formulate-input-element-decorator{display:block;width:1em;height:1em;border-radius:.25em;border:1px solid #cecece;position:relative}.formulate-input[data-classification=box] .formulate-input-element-decorator:before{content:"";display:block;background-size:contain;background-position:100%;width:calc(100% - .125em);height:calc(100% - .125em);box-sizing:border-box;position:absolute;top:.0625em;left:.0625em}.formulate-input[data-classification=box] .formulate-input-element[data-type=radio] .formulate-input-element-decorator{border-radius:1em}.formulate-input[data-classification=box] .formulate-input-element[data-type=radio] .formulate-input-element-decorator:before{border-radius:1em;width:calc(100% - .5em);height:calc(100% - .5em);top:.25em;left:.25em}.formulate-input[data-classification=box] .formulate-input-element input[type=checkbox]:checked~.formulate-input-element-decorator{border-color:#41b883}.formulate-input[data-classification=box] .formulate-input-element input[type=checkbox]:checked~.formulate-input-element-decorator:before{background-image:url('data:image/svg+xml;utf8,')}.formulate-input[data-classification=box] .formulate-input-element input[type=radio]:checked~.formulate-input-element-decorator{border-color:#41b883}.formulate-input[data-classification=box] .formulate-input-element input[type=radio]:checked~.formulate-input-element-decorator:before{background-color:#41b883}.formulate-input[data-classification=box] .formulate-input-element input:focus~.formulate-input-element-decorator{border-color:#41b883}.formulate-input[data-classification=box] .formulate-input-label--after{margin-left:.5em}.formulate-input[data-classification=box] .formulate-input-label--before{margin-right:.5em}.formulate-input[data-classification=group]>.formulate-input-wrapper>.formulate-input-label{margin-bottom:.5em} +/*# sourceMappingURL=data:application/json;base64,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SUFDRSxvQkFBdUIsQ0FDdkIsdUlBQ0Usd0JBQTJCLENBQy9CLGtIQUNFLG9CQUF1QixDQUMzQix3RUFDRSxnQkFBbUIsQ0FDckIseUVBQ0UsaUJBQW9CLENBQ3RCLDRGQUNFLGtCQUFxQiIsImZpbGUiOiJzdGRpbiIsInNvdXJjZXNDb250ZW50IjpbIi5mb3JtdWxhdGUtaW5wdXQge1xuICBtYXJnaW4tYm90dG9tOiAyZW07IH1cbiAgLmZvcm11bGF0ZS1pbnB1dCAuZm9ybXVsYXRlLWlucHV0LWxhYmVsIHtcbiAgICBkaXNwbGF5OiBibG9jaztcbiAgICBsaW5lLWhlaWdodDogMS41O1xuICAgIGZvbnQtc2l6ZTogLjllbTtcbiAgICBmb250LXdlaWdodDogNjAwO1xuICAgIG1hcmdpbi1ib3R0b206IC4xZW07IH1cbiAgLmZvcm11bGF0ZS1pbnB1dCAuZm9ybXVsYXRlLWlucHV0LWVsZW1lbnQge1xuICAgIG1heC13aWR0aDogMjBlbTtcbiAgICBtYXJnaW4tYm90dG9tOiAuMWVtOyB9XG4gIC5mb3JtdWxhdGUtaW5wdXQgLmZvcm11bGF0ZS1pbnB1dC1oZWxwIHtcbiAgICBjb2xvcjogIzZkNmQ2ZDtcbiAgICBmb250LXNpemU6IC43ZW07XG4gICAgZm9udC13ZWlnaHQ6IDQwMDtcbiAgICBsaW5lLWhlaWdodDogMS41O1xuICAgIG1hcmdpbi1ib3R0b206IC4yNWVtOyB9XG4gIC5mb3JtdWxhdGUtaW5wdXQgLmZvcm11bGF0ZS1pbnB1dC1lcnJvcnMge1xuICAgIGxpc3Qtc3R5bGUtdHlwZTogbm9uZTtcbiAgICBwYWRkaW5nOiAwO1xuICAgIG1hcmdpbjogMDsgfVxuICAuZm9ybXVsYXRlLWlucHV0IC5mb3JtdWxhdGUtaW5wdXQtZXJyb3Ige1xuICAgIGNvbG9yOiAjOTYwNTA1O1xuICAgIGZvbnQtc2l6ZTogLjhlbTtcbiAgICBmb250LXdlaWdodDogMzAwO1xuICAgIGxpbmUtaGVpZ2h0OiAxLjU7XG4gICAgbWFyZ2luLWJvdHRvbTogLjI1ZW07IH1cbiAgLmZvcm11bGF0ZS1pbnB1dCAuZm9ybXVsYXRlLWlucHV0LWdyb3VwLWl0ZW0ge1xuICAgIG1hcmdpbi1ib3R0b206IC41ZW07IH1cbiAgLmZvcm11bGF0ZS1pbnB1dDpsYXN0LWNoaWxkIHtcbiAgICBtYXJnaW4tYm90dG9tOiAwOyB9XG4gIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0ndGV4dCddIGlucHV0IHtcbiAgICBhcHBlYXJhbmNlOiBub25lO1xuICAgIGJvcmRlci1yYWRpdXM6IC4zZW07XG4gICAgYm9yZGVyOiAxcHggc29saWQgI2NlY2VjZTtcbiAgICBib3gtc2l6aW5nOiBib3JkZXItYm94O1xuICAgIGJhY2tncm91bmQtY29sb3I6IHRyYW5zcGFyZW50O1xuICAgIGZvbnQtc2l6ZTogLjllbTtcbiAgICBmb250LWZhbWlseTogLWFwcGxlLXN5c3RlbSwgQmxpbmtNYWNTeXN0ZW1Gb250LCBcIlNlZ29lIFVJXCIsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiwgXCJBcHBsZSBDb2xvciBFbW9qaVwiLCBcIlNlZ29lIFVJIEVtb2ppXCIsIFwiU2Vnb2UgVUkgU3ltYm9sXCI7XG4gICAgcGFkZGluZzogLjc1ZW07XG4gICAgZGlzcGxheTogYmxvY2s7XG4gICAgd2lkdGg6IDEwMCU7XG4gICAgZm9udC13ZWlnaHQ6IDQwMDsgfVxuICAgIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0ndGV4dCddIGlucHV0OjpwbGFjZWhvbGRlciB7XG4gICAgICBjb2xvcjogI2E4YThhODsgfVxuICAgIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0ndGV4dCddIGlucHV0OmZvY3VzIHtcbiAgICAgIG91dGxpbmU6IDA7XG4gICAgICBib3JkZXI6IDFweCBzb2xpZCAjNDFiODgzOyB9XG4gIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0ndGV4dGFyZWEnXSB0ZXh0YXJlYSB7XG4gICAgYXBwZWFyYW5jZTogbm9uZTtcbiAgICBib3JkZXItcmFkaXVzOiAuM2VtO1xuICAgIGJvcmRlcjogMXB4IHNvbGlkICNjZWNlY2U7XG4gICAgYm94LXNpemluZzogYm9yZGVyLWJveDtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiB0cmFuc3BhcmVudDtcbiAgICBmb250LXNpemU6IC45ZW07XG4gICAgZm9udC1mYW1pbHk6IC1hcHBsZS1zeXN0ZW0sIEJsaW5rTWFjU3lzdGVtRm9udCwgXCJTZWdvZSBVSVwiLCBSb2JvdG8sIEhlbHZldGljYSwgQXJpYWwsIHNhbnMtc2VyaWYsIFwiQXBwbGUgQ29sb3IgRW1vamlcIiwgXCJTZWdvZSBVSSBFbW9qaVwiLCBcIlNlZ29lIFVJIFN5bWJvbFwiO1xuICAgIHBhZGRpbmc6IC43NWVtO1xuICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgIHdpZHRoOiAxMDAlO1xuICAgIGZvbnQtd2VpZ2h0OiA0MDA7IH1cbiAgICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J3RleHRhcmVhJ10gdGV4dGFyZWE6OnBsYWNlaG9sZGVyIHtcbiAgICAgIGNvbG9yOiAjYThhOGE4OyB9XG4gICAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPSd0ZXh0YXJlYSddIHRleHRhcmVhOmZvY3VzIHtcbiAgICAgIG91dGxpbmU6IDA7XG4gICAgICBib3JkZXI6IDFweCBzb2xpZCAjNDFiODgzOyB9XG4gIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nc2VsZWN0J10gLmZvcm11bGF0ZS1pbnB1dC1lbGVtZW50IHtcbiAgICBwb3NpdGlvbjogcmVsYXRpdmU7IH1cbiAgICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J3NlbGVjdCddIC5mb3JtdWxhdGUtaW5wdXQtZWxlbWVudDo6YmVmb3JlIHtcbiAgICAgIGNvbnRlbnQ6ICcnO1xuICAgICAgd2lkdGg6IDA7XG4gICAgICBoZWlnaHQ6IDA7XG4gICAgICBib3JkZXI6IC4zZW0gc29saWQgdHJhbnNwYXJlbnQ7XG4gICAgICBib3JkZXItdG9wLWNvbG9yOiAjY2VjZWNlO1xuICAgICAgYm9yZGVyLWJvdHRvbS13aWR0aDogMDtcbiAgICAgIHRvcDogNTAlO1xuICAgICAgbWFyZ2luLXRvcDogLS4xZW07XG4gICAgICByaWdodDogMWVtO1xuICAgICAgcG9zaXRpb246IGFic29sdXRlOyB9XG4gIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nc2VsZWN0J10gc2VsZWN0IHtcbiAgICBhcHBlYXJhbmNlOiBub25lO1xuICAgIGJvcmRlci1yYWRpdXM6IC4zZW07XG4gICAgYm9yZGVyOiAxcHggc29saWQgI2NlY2VjZTtcbiAgICBib3gtc2l6aW5nOiBib3JkZXItYm94O1xuICAgIGJhY2tncm91bmQtY29sb3I6IHRyYW5zcGFyZW50O1xuICAgIGZvbnQtc2l6ZTogLjllbTtcbiAgICBmb250LWZhbWlseTogLWFwcGxlLXN5c3RlbSwgQmxpbmtNYWNTeXN0ZW1Gb250LCBcIlNlZ29lIFVJXCIsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiwgXCJBcHBsZSBDb2xvciBFbW9qaVwiLCBcIlNlZ29lIFVJIEVtb2ppXCIsIFwiU2Vnb2UgVUkgU3ltYm9sXCI7XG4gICAgcGFkZGluZzogLjc1ZW07XG4gICAgZGlzcGxheTogYmxvY2s7XG4gICAgd2lkdGg6IDEwMCU7XG4gICAgZm9udC13ZWlnaHQ6IDQwMDtcbiAgICBwYWRkaW5nLXJpZ2h0OiAyZW07IH1cbiAgICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J3NlbGVjdCddIHNlbGVjdDo6cGxhY2Vob2xkZXIge1xuICAgICAgY29sb3I6ICNhOGE4YTg7IH1cbiAgICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J3NlbGVjdCddIHNlbGVjdDpmb2N1cyB7XG4gICAgICBvdXRsaW5lOiAwO1xuICAgICAgYm9yZGVyOiAxcHggc29saWQgIzQxYjg4MzsgfVxuICAgIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nc2VsZWN0J10gc2VsZWN0W2RhdGEtcGxhY2Vob2xkZXItc2VsZWN0ZWRdIHtcbiAgICAgIGNvbG9yOiAjYThhOGE4OyB9XG4gIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nYm94J10gLmZvcm11bGF0ZS1pbnB1dC13cmFwcGVyIHtcbiAgICBkaXNwbGF5OiBmbGV4O1xuICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7IH1cbiAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPSdib3gnXSAuZm9ybXVsYXRlLWlucHV0LWVsZW1lbnQge1xuICAgIG92ZXJmbG93OiBoaWRkZW47XG4gICAgZGlzcGxheTogZmxleDtcbiAgICBhbGlnbi1pdGVtczogY2VudGVyOyB9XG4gICAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPSdib3gnXSAuZm9ybXVsYXRlLWlucHV0LWVsZW1lbnQgaW5wdXQge1xuICAgICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgICAgbGVmdDogLTk5OXB4OyB9XG4gICAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPSdib3gnXSAuZm9ybXVsYXRlLWlucHV0LWVsZW1lbnQtZGVjb3JhdG9yIHtcbiAgICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgICAgd2lkdGg6IDFlbTtcbiAgICAgIGhlaWdodDogMWVtO1xuICAgICAgYm9yZGVyLXJhZGl1czogLjI1ZW07XG4gICAgICBib3JkZXI6IDFweCBzb2xpZCAjY2VjZWNlO1xuICAgICAgcG9zaXRpb246IHJlbGF0aXZlOyB9XG4gICAgICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J2JveCddIC5mb3JtdWxhdGUtaW5wdXQtZWxlbWVudC1kZWNvcmF0b3I6OmJlZm9yZSB7XG4gICAgICAgIGNvbnRlbnQ6ICcnO1xuICAgICAgICBkaXNwbGF5OiBibG9jaztcbiAgICAgICAgYmFja2dyb3VuZC1zaXplOiBjb250YWluO1xuICAgICAgICBiYWNrZ3JvdW5kLXBvc2l0aW9uOiByaWdodDtcbiAgICAgICAgd2lkdGg6IGNhbGMoMTAwJSAtIC4xMjVlbSk7XG4gICAgICAgIGhlaWdodDogY2FsYygxMDAlIC0gLjEyNWVtKTtcbiAgICAgICAgYm94LXNpemluZzogYm9yZGVyLWJveDtcbiAgICAgICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgICAgICB0b3A6IC4wNjI1ZW07XG4gICAgICAgIGxlZnQ6IC4wNjI1ZW07IH1cbiAgICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J2JveCddIC5mb3JtdWxhdGUtaW5wdXQtZWxlbWVudFtkYXRhLXR5cGU9XCJyYWRpb1wiXSAuZm9ybXVsYXRlLWlucHV0LWVsZW1lbnQtZGVjb3JhdG9yIHtcbiAgICAgIGJvcmRlci1yYWRpdXM6IDFlbTsgfVxuICAgICAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPSdib3gnXSAuZm9ybXVsYXRlLWlucHV0LWVsZW1lbnRbZGF0YS10eXBlPVwicmFkaW9cIl0gLmZvcm11bGF0ZS1pbnB1dC1lbGVtZW50LWRlY29yYXRvcjo6YmVmb3JlIHtcbiAgICAgICAgYm9yZGVyLXJhZGl1czogMWVtO1xuICAgICAgICB3aWR0aDogY2FsYygxMDAlIC0gLjVlbSk7XG4gICAgICAgIGhlaWdodDogY2FsYygxMDAlIC0gLjVlbSk7XG4gICAgICAgIHRvcDogLjI1ZW07XG4gICAgICAgIGxlZnQ6IC4yNWVtOyB9XG4gICAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPSdib3gnXSAuZm9ybXVsYXRlLWlucHV0LWVsZW1lbnQgaW5wdXRbdHlwZT1cImNoZWNrYm94XCJdOmNoZWNrZWQgfiAuZm9ybXVsYXRlLWlucHV0LWVsZW1lbnQtZGVjb3JhdG9yIHtcbiAgICAgIGJvcmRlci1jb2xvcjogIzQxYjg4MzsgfVxuICAgICAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPSdib3gnXSAuZm9ybXVsYXRlLWlucHV0LWVsZW1lbnQgaW5wdXRbdHlwZT1cImNoZWNrYm94XCJdOmNoZWNrZWQgfiAuZm9ybXVsYXRlLWlucHV0LWVsZW1lbnQtZGVjb3JhdG9yOjpiZWZvcmUge1xuICAgICAgICBiYWNrZ3JvdW5kLWltYWdlOiB1cmwoJ2RhdGE6aW1hZ2Uvc3ZnK3htbDt1dGY4LDxzdmcgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiIHZpZXdCb3g9XCIwIDAgMTAwIDEwMFwiIGZpbGw9XCIlMjM0MWI4ODNcIj48cGF0aCBkPVwiTTguNzYsNTYuMmMtNi4zOC02LjM0LDMuMjYtMTYsOS42NC05LjY5TDM4LDY1Ljg4LDgwLjU2LDIzLjI5YzYuMzgtNi4zOCwxNi4wNywzLjMyLDkuNjksOS42OUw0Mi44NCw4MC4zN2E2LjgzLDYuODMsMCwwLDEtOS42NSwwWlwiLz48L3N2Zz4nKTsgfVxuICAgIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nYm94J10gLmZvcm11bGF0ZS1pbnB1dC1lbGVtZW50IGlucHV0W3R5cGU9XCJyYWRpb1wiXTpjaGVja2VkIH4gLmZvcm11bGF0ZS1pbnB1dC1lbGVtZW50LWRlY29yYXRvciB7XG4gICAgICBib3JkZXItY29sb3I6ICM0MWI4ODM7IH1cbiAgICAgIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nYm94J10gLmZvcm11bGF0ZS1pbnB1dC1lbGVtZW50IGlucHV0W3R5cGU9XCJyYWRpb1wiXTpjaGVja2VkIH4gLmZvcm11bGF0ZS1pbnB1dC1lbGVtZW50LWRlY29yYXRvcjo6YmVmb3JlIHtcbiAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogIzQxYjg4MzsgfVxuICAgIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nYm94J10gLmZvcm11bGF0ZS1pbnB1dC1lbGVtZW50IGlucHV0OmZvY3VzIH4gLmZvcm11bGF0ZS1pbnB1dC1lbGVtZW50LWRlY29yYXRvciB7XG4gICAgICBib3JkZXItY29sb3I6ICM0MWI4ODM7IH1cbiAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPSdib3gnXSAuZm9ybXVsYXRlLWlucHV0LWxhYmVsLS1hZnRlciB7XG4gICAgbWFyZ2luLWxlZnQ6IC41ZW07IH1cbiAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPSdib3gnXSAuZm9ybXVsYXRlLWlucHV0LWxhYmVsLS1iZWZvcmUge1xuICAgIG1hcmdpbi1yaWdodDogLjVlbTsgfVxuICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249XCJncm91cFwiXSA+IC5mb3JtdWxhdGUtaW5wdXQtd3JhcHBlciA+IC5mb3JtdWxhdGUtaW5wdXQtbGFiZWwge1xuICAgIG1hcmdpbi1ib3R0b206IC41ZW07IH1cbiJdfQ== */ \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index b176d7f..3760e0e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1129,7 +1129,8 @@ "version": "7.0.7", "resolved": "https://registry.npmjs.org/@types/babel-types/-/babel-types-7.0.7.tgz", "integrity": "sha512-dBtBbrc+qTHy1WdfHYjBwRln4+LWqASWakLHsWHR2NWHIFkv4W3O070IGoGLEBrJBvct3r0L1BUPuvURi7kYUQ==", - "dev": true + "dev": true, + "optional": true }, "@types/babel__core": { "version": "7.1.3", @@ -1177,6 +1178,7 @@ "resolved": "https://registry.npmjs.org/@types/babylon/-/babylon-6.16.5.tgz", "integrity": "sha512-xH2e58elpj1X4ynnKp9qSnWlsRTIs6n3tgLGNfwAGHwePw0mulHQllV34n0T25uYSu1k0hRKkWXF890B1yS47w==", "dev": true, + "optional": true, "requires": { "@types/babel-types": "*" } @@ -1412,6 +1414,7 @@ "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", "dev": true, + "optional": true, "requires": { "kind-of": "^3.0.2", "longest": "^1.0.1", @@ -1423,6 +1426,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, + "optional": true, "requires": { "is-buffer": "^1.1.5" } @@ -2441,7 +2445,8 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true + "dev": true, + "optional": true }, "to-regex-range": { "version": "5.0.1", @@ -2692,6 +2697,7 @@ "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-3.1.2.tgz", "integrity": "sha512-yePcBqEFhLOqSBtwYOGGS1exHo/s1xjekXiinh4itpNQGCu4KA1euPh1fg07N2wMITZXQkBz75Ntdt1ctGZouw==", "dev": true, + "optional": true, "requires": { "@types/babel-types": "^7.0.0", "@types/babylon": "^6.16.2", @@ -4226,7 +4232,8 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -4247,12 +4254,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -4267,17 +4276,20 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -4394,7 +4406,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -4406,6 +4419,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -4420,6 +4434,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -4427,12 +4442,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -4451,6 +4468,7 @@ "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -4531,7 +4549,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -4543,6 +4562,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -4628,7 +4648,8 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -4664,6 +4685,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -4683,6 +4705,7 @@ "version": "3.0.1", "bundled": true, "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -4726,12 +4749,14 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true } } }, @@ -5645,6 +5670,11 @@ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "dev": true }, + "is-url": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", + "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==" + }, "is-utf8": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", @@ -6241,7 +6271,8 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", "integrity": "sha1-Fzb939lyTyijaCrcYjCufk6Weds=", - "dev": true + "dev": true, + "optional": true }, "js-tokens": { "version": "4.0.0", @@ -6548,7 +6579,8 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", - "dev": true + "dev": true, + "optional": true }, "loose-envify": { "version": "1.4.0", @@ -7559,7 +7591,8 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.1.0.tgz", "integrity": "sha512-uhnEDzAbrcJ8R3g2fANnSuXZMBtkpSjxTTgn2LeSiQlfmq72enQJWdQllXW24MBLYnA1SBD2vfvx2o0Zw3Ielw==", - "dev": true + "dev": true, + "optional": true }, "pify": { "version": "2.3.0", @@ -8723,7 +8756,8 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-1.3.3.tgz", "integrity": "sha512-qE3YhESP2mRAWMFJgKdtT5D7ckThRScXRwkfo+Erqga7dyJdY3ZquspprMCj/9sJ2ijm5hXFWQE/A3l4poMWiQ==", - "dev": true + "dev": true, + "optional": true }, "pug-filters": { "version": "3.1.1", @@ -8843,7 +8877,8 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-2.0.5.tgz", "integrity": "sha512-P+rXKn9un4fQY77wtpcuFyvFaBww7/91f3jHa154qU26qFAnOe6SW1CbIDcxiG5lLK9HazYrMCCuDvNgDQNptw==", - "dev": true + "dev": true, + "optional": true }, "pug-strip-comments": { "version": "1.0.4", @@ -8859,7 +8894,8 @@ "version": "1.1.8", "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-1.1.8.tgz", "integrity": "sha512-GMu3M5nUL3fju4/egXwZO0XLi6fW/K3T3VTgFQ14GxNi8btlxgT5qZL//JwZFm/2Fa64J/PNS8AZeys3wiMkVA==", - "dev": true + "dev": true, + "optional": true }, "pump": { "version": "3.0.0", diff --git a/package.json b/package.json index ff6033d..3f4abcb 100644 --- a/package.json +++ b/package.json @@ -77,6 +77,7 @@ }, "dependencies": { "is-plain-object": "^3.0.0", + "is-url": "^1.2.4", "nanoid": "^2.1.6" } } diff --git a/src/Formulate.js b/src/Formulate.js index cf8dde0..e38728b 100644 --- a/src/Formulate.js +++ b/src/Formulate.js @@ -1,4 +1,5 @@ import library from './libs/library' +import rules from './libs/rules' import isPlainObject from 'is-plain-object' import FormulateInput from './FormulateInput.vue' import FormulateForm from './FormulateForm.vue' @@ -8,6 +9,7 @@ import FormulateInputBox from './inputs/FormulateInputBox.vue' import FormulateInputText from './inputs/FormulateInputText.vue' import FormulateInputSelect from './inputs/FormulateInputSelect.vue' import FormulateInputTextArea from './inputs/FormulateInputTextArea.vue' + /** * The base formulate library. */ @@ -27,7 +29,8 @@ class Formulate { FormulateInputSelect, FormulateInputTextArea }, - library + library, + rules } } @@ -88,6 +91,14 @@ class Formulate { } return false } + + /** + * Get validation rules. + * @return {object} object of validation functions + */ + rules () { + return this.options.rules + } } export default new Formulate() diff --git a/src/FormulateInput.vue b/src/FormulateInput.vue index 9a278bf..5d32636 100644 --- a/src/FormulateInput.vue +++ b/src/FormulateInput.vue @@ -48,7 +48,7 @@