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 @@