diff --git a/dist/formulario.esm.js b/dist/formulario.esm.js index b7bd3e6..977f5ca 100644 --- a/dist/formulario.esm.js +++ b/dist/formulario.esm.js @@ -1,7 +1,7 @@ import isPlainObject from 'is-plain-object'; import isUrl from 'is-url'; import Vue from 'vue'; -import { Model, Prop, Provide, Watch, Component, Inject } from 'vue-property-decorator'; +import { Inject, Model, Prop, Watch, Component, Provide } from 'vue-property-decorator'; /** * Shorthand for Object.prototype.hasOwnProperty.call (space saving) @@ -44,63 +44,222 @@ function merge(a, b, concatArrays = true) { return merged; } -/** - * Converts to array. - * If given parameter is not string, object ot array, result will be an empty array. - * @param {*} item - */ -function arrayify(item) { - if (!item) { - return []; - } - if (typeof item === 'string') { - return [item]; - } - if (Array.isArray(item)) { - return item; - } - if (typeof item === 'object') { - return Object.values(item); - } - return []; -} +const registry = new Map(); +var id = (prefix) => { + const current = registry.get(prefix) || 0; + const next = current + 1; + registry.set(prefix, next); + return `${prefix}-${next}`; +}; -function isScalar(data) { - switch (typeof data) { +var TYPE; +(function (TYPE) { + TYPE["ARRAY"] = "ARRAY"; + TYPE["BIGINT"] = "BIGINT"; + TYPE["BOOLEAN"] = "BOOLEAN"; + TYPE["DATE"] = "DATE"; + TYPE["FUNCTION"] = "FUNCTION"; + TYPE["NUMBER"] = "NUMBER"; + TYPE["RECORD"] = "RECORD"; + TYPE["STRING"] = "STRING"; + TYPE["SYMBOL"] = "SYMBOL"; + TYPE["UNDEFINED"] = "UNDEFINED"; + TYPE["NULL"] = "NULL"; +})(TYPE || (TYPE = {})); +function typeOf(value) { + switch (typeof value) { + case 'bigint': + return TYPE.BIGINT; + case 'boolean': + return TYPE.BOOLEAN; + case 'function': + return TYPE.FUNCTION; + case 'number': + return TYPE.NUMBER; + case 'string': + return TYPE.STRING; case 'symbol': + return TYPE.SYMBOL; + case 'undefined': + return TYPE.UNDEFINED; + case 'object': + if (value === null) { + return TYPE.NULL; + } + if (value instanceof Date) { + return TYPE.DATE; + } + if (Array.isArray(value)) { + return TYPE.ARRAY; + } + if (value.constructor.name === 'Object') { + return TYPE.RECORD; + } + return 'InstanceOf<' + value.constructor.name + '>'; + } + throw new Error(); +} +function isRecordLike(value) { + return typeof value === 'object' && value !== null && ['Array', 'Object'].includes(value.constructor.name); +} +function isScalar(value) { + switch (typeof value) { + case 'bigint': + case 'boolean': case 'number': case 'string': - case 'boolean': + case 'symbol': case 'undefined': return true; default: - return data === null; + return value === null; } } +const cloneInstance = (original) => { + return Object.assign(Object.create(Object.getPrototypeOf(original)), original); +}; /** * A simple (somewhat non-comprehensive) clone function, valid for our use * case of needing to unbind reactive watchers. */ function clone(value) { - if (typeof value !== 'object') { + if (isScalar(value)) { return value; } - const copy = Array.isArray(value) ? [] : {}; - for (const key in value) { - if (has(value, key)) { - if (isScalar(value[key])) { - copy[key] = value[key]; - } - else if (value instanceof Date) { - copy[key] = new Date(copy[key]); - } - else { - copy[key] = clone(value[key]); - } - } + if (value instanceof Date) { + return new Date(value); } + if (!isRecordLike(value)) { + return cloneInstance(value); + } + if (Array.isArray(value)) { + return value.slice().map(clone); + } + const source = value; + return Object.keys(source).reduce((copy, key) => (Object.assign(Object.assign({}, copy), { [key]: clone(source[key]) })), {}); +} + +/*! ***************************************************************************** +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +***************************************************************************** */ + +function __rest(s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { + if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) + t[p[i]] = s[p[i]]; + } + return t; +} + +function __decorate(decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +} + +const extractIntOrNaN = (value) => { + const numeric = parseInt(value); + return numeric.toString() === value ? numeric : NaN; +}; +const extractPath = (raw) => { + const path = []; + raw.split('.').forEach(key => { + if (/(.*)\[(\d+)]$/.test(key)) { + path.push(...key.substr(0, key.length - 1).split('[').filter(k => k.length)); + } + else { + path.push(key); + } + }); + return path; +}; +function get(state, rawOrPath, fallback = undefined) { + const path = typeof rawOrPath === 'string' ? extractPath(rawOrPath) : rawOrPath; + if (isScalar(state) || path.length === 0) { + return fallback; + } + const key = path.shift(); + const index = extractIntOrNaN(key); + if (!isNaN(index)) { + if (Array.isArray(state) && index >= 0 && index < state.length) { + return path.length === 0 ? state[index] : get(state[index], path, fallback); + } + return undefined; + } + if (has(state, key)) { + const values = state; + return path.length === 0 ? values[key] : get(values[key], path, fallback); + } + return undefined; +} +function set(state, rawOrPath, value) { + const path = typeof rawOrPath === 'string' ? extractPath(rawOrPath) : rawOrPath; + if (path.length === 0) { + return value; + } + const key = path.shift(); + const index = extractIntOrNaN(key); + if (!isRecordLike(state)) { + return set(!isNaN(index) ? [] : {}, [key, ...path], value); + } + if (!isNaN(index) && Array.isArray(state)) { + const slice = [...state]; + slice[index] = path.length === 0 ? value : set(slice[index], path, value); + return slice; + } + const slice = Object.assign({}, state); + slice[key] = path.length === 0 ? value : set(slice[key], path, value); + return slice; +} +const unsetInRecord = (record, prop) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const _a = record, _b = prop, _ = _a[_b], copy = __rest(_a, [typeof _b === "symbol" ? _b : _b + ""]); return copy; +}; +function unset(state, rawOrPath) { + if (!isRecordLike(state)) { + return state; + } + const path = typeof rawOrPath === 'string' ? extractPath(rawOrPath) : rawOrPath; + if (path.length === 0) { + return state; + } + const key = path.shift(); + const index = extractIntOrNaN(key); + if (!isNaN(index) && Array.isArray(state) && index >= 0 && index < state.length) { + const slice = [...state]; + if (path.length === 0) { + slice.splice(index, 1); + } + else { + slice[index] = unset(slice[index], path); + } + return slice; + } + if (has(state, key)) { + const slice = Object.assign({}, state); + return path.length === 0 + ? unsetInRecord(slice, key) + : Object.assign(Object.assign({}, slice), { [key]: unset(slice[key], path) }); + } + return state; } /** @@ -127,31 +286,47 @@ function regexForFormat(format) { }, escaped)); } -function shallowEqualObjects(objA, objB) { - if (objA === objB) { - return true; - } - if (!objA || !objB) { +function datesEquals(a, b) { + return a.getTime() === b.getTime(); +} +function arraysEquals(a, b, predicate) { + if (a.length !== b.length) { return false; } - const aKeys = Object.keys(objA); - const bKeys = Object.keys(objB); - if (bKeys.length !== aKeys.length) { - return false; - } - if (objA instanceof Date && objB instanceof Date) { - return objA.getTime() === objB.getTime(); - } - if (aKeys.length === 0) { - return objA === objB; - } - for (let i = 0; i < aKeys.length; i++) { - const key = aKeys[i]; - if (objA[key] !== objB[key]) { + for (let i = 0; i < a.length; i++) { + if (!predicate(a[i], b[i])) { return false; } } return true; +} +function recordsEquals(a, b, predicate) { + if (Object.keys(a).length !== Object.keys(b).length) { + return false; + } + for (const prop in a) { + if (!has(b, prop) || !predicate(a[prop], b[prop])) { + return false; + } + } + return true; +} +function strictEquals(a, b) { + return a === b; +} +function equals(a, b, predicate) { + const typeOfA = typeOf(a); + const typeOfB = typeOf(b); + return typeOfA === typeOfB && ((typeOfA === TYPE.ARRAY && arraysEquals(a, b, predicate)) || + (typeOfA === TYPE.DATE && datesEquals(a, b)) || + (typeOfA === TYPE.RECORD && recordsEquals(a, b, predicate)) || + (typeOfA.includes('InstanceOf') && equals(Object.entries(a), Object.entries(b), predicate))); +} +function deepEquals(a, b) { + return a === b || equals(a, b, deepEquals); +} +function shallowEquals(a, b) { + return a === b || equals(a, b, strictEquals); } /** @@ -166,68 +341,6 @@ function snakeToCamel(string) { }); } -function getNested(obj, field) { - const fieldParts = field.split('.'); - let result = obj; - for (const key in fieldParts) { - const matches = fieldParts[key].match(/(.+)\[(\d+)\]$/); - if (result === undefined) { - return null; - } - if (matches) { - result = result[matches[1]]; - if (result === undefined) { - return null; - } - result = result[matches[2]]; - } - else { - result = result[fieldParts[key]]; - } - } - return result; -} -function setNested(obj, field, value) { - const fieldParts = field.split('.'); - let subProxy = obj; - for (let i = 0; i < fieldParts.length; i++) { - const fieldPart = fieldParts[i]; - const matches = fieldPart.match(/(.+)\[(\d+)\]$/); - if (subProxy === undefined) { - break; - } - if (matches) { - if (subProxy[matches[1]] === undefined) { - subProxy[matches[1]] = []; - } - subProxy = subProxy[matches[1]]; - if (i === fieldParts.length - 1) { - subProxy[matches[2]] = value; - break; - } - else { - subProxy = subProxy[matches[2]]; - } - } - else { - if (subProxy === undefined) { - break; - } - if (i === fieldParts.length - 1) { - subProxy[fieldPart] = value; - break; - } - else { - // eslint-disable-next-line max-depth - if (subProxy[fieldPart] === undefined) { - subProxy[fieldPart] = {}; - } - subProxy = subProxy[fieldPart]; - } - } - } -} - const rules = { /** * Rule: the value must be "yes", "on", "1", or true @@ -333,7 +446,7 @@ const rules = { * Rule: Value is in an array (stack). */ in({ value }, ...stack) { - return stack.some(item => typeof item === 'object' ? shallowEqualObjects(item, value) : item === value); + return stack.some(item => shallowEquals(item, value)); }, /** * Rule: Match the value against a (stack) of patterns or strings @@ -389,7 +502,7 @@ const rules = { * Rule: Value is not in stack. */ not({ value }, ...stack) { - return !stack.some(item => typeof item === 'object' ? shallowEqualObjects(item, value) : item === value); + return !stack.some(item => shallowEquals(item, value)); }, /** * Rule: checks if the value is only alpha numeric @@ -431,6 +544,9 @@ const rules = { * Rule: checks if a string is a valid url */ url({ value }) { + if (!value) { + return true; + } return isUrl(value); }, /** @@ -547,6 +663,7 @@ class Formulario { constructor(options) { this.validationRules = {}; this.validationMessages = {}; + this.registry = new Map(); this.validationRules = rules; this.validationMessages = messages; this.extend(options || {}); @@ -560,16 +677,51 @@ class Formulario { this.validationMessages = merge(this.validationMessages, extendWith.validationMessages || {}); return this; } - throw new Error(`[Formulario]: Formulario.extend() should be passed an object (was ${typeof extendWith})`); + throw new Error(`[Formulario]: Formulario.extend(): should be passed an object (was ${typeof extendWith})`); + } + runValidation(id) { + if (!this.registry.has(id)) { + throw new Error(`[Formulario]: Formulario.runValidation(): no forms with id "${id}"`); + } + const form = this.registry.get(id); + return form.runValidation(); + } + resetValidation(id) { + if (!this.registry.has(id)) { + return; + } + const form = this.registry.get(id); + form.resetValidation(); + } + /** + * Used by forms instances to add themselves into a registry + * @internal + */ + register(id, form) { + if (this.registry.has(id)) { + throw new Error(`[Formulario]: Formulario.register(): id "${id}" is already in use`); + } + this.registry.set(id, form); + } + /** + * Used by forms instances to remove themselves from a registry + * @internal + */ + unregister(id) { + if (this.registry.has(id)) { + this.registry.delete(id); + } } /** * Get validation rules by merging any passed in with global rules. + * @internal */ getRules(extendWith = {}) { return merge(this.validationRules, extendWith); } /** * Get validation messages by merging any passed in with global messages. + * @internal */ getMessages(vm, extendWith) { const raw = merge(this.validationMessages || {}, extendWith); @@ -583,583 +735,6 @@ class Formulario { } } -/*! ***************************************************************************** -Copyright (c) Microsoft Corporation. - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THIS SOFTWARE. -***************************************************************************** */ - -function __rest(s, e) { - var t = {}; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) - t[p] = s[p]; - if (s != null && typeof Object.getOwnPropertySymbols === "function") - for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { - if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) - t[p[i]] = s[p[i]]; - } - return t; -} - -function __decorate(decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; - return c > 3 && r && Object.defineProperty(target, key, r), r; -} - -/** - * Component registry with inherent depth to handle complex nesting. This is - * important for features such as grouped fields. - */ -class Registry { - /** - * Create a new registry of components. - * @param {FormularioForm} ctx The host vm context of the registry. - */ - constructor(ctx) { - this.registry = new Map(); - this.ctx = ctx; - } - /** - * Fully register a component. - * @param {string} field name of the field. - * @param {FormularioForm} component the actual component instance. - */ - add(field, component) { - if (this.registry.has(field)) { - return; - } - this.registry.set(field, component); - // @ts-ignore - const value = getNested(this.ctx.initialValues, field); - const hasModel = has(component.$options.propsData || {}, 'value'); - // @ts-ignore - if (!hasModel && this.ctx.hasInitialValue && value !== undefined) { - // In the case that the form is carrying an initial value and the - // element is not, set it directly. - // @ts-ignore - component.context.model = value; - // @ts-ignore - } - else if (hasModel && !shallowEqualObjects(component.proxy, value)) { - // In this case, the field is v-modeled or has an initial value and the - // form has no value or a different value, so use the field value - // @ts-ignore - this.ctx.setFieldValueAndEmit(field, component.proxy); - } - } - /** - * Remove an item from the registry. - */ - remove(name) { - this.registry.delete(name); - // @ts-ignore - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const _a = this.ctx.proxy, _b = name, value = _a[_b], newProxy = __rest(_a, [typeof _b === "symbol" ? _b : _b + ""]); - // @ts-ignore - this.ctx.proxy = newProxy; - } - /** - * Check if the registry has the given key. - */ - has(key) { - return this.registry.has(key); - } - /** - * Check if the registry has elements, that equals or nested given key - */ - hasNested(key) { - for (const i of this.registry.keys()) { - if (i === key || i.includes(key + '.')) { - return true; - } - } - return false; - } - /** - * Get a particular registry value. - */ - get(key) { - return this.registry.get(key); - } - /** - * Get registry value for key or nested to given key - */ - getNested(key) { - const result = new Map(); - for (const i of this.registry.keys()) { - const objectKey = key + '.'; - const arrayKey = key + '['; - if (i === key || - i.substring(0, objectKey.length) === objectKey || - i.substring(0, arrayKey.length) === arrayKey) { - result.set(i, this.registry.get(i)); - } - } - return result; - } - /** - * Map over the registry (recursively). - */ - forEach(callback) { - this.registry.forEach((component, field) => { - callback(component, field); - }); - } - /** - * Return the keys of the registry. - */ - keys() { - return Array.from(this.registry.keys()); - } - /** - * Reduce the registry. - * @param {function} callback - * @param accumulator - */ - reduce(callback, accumulator) { - this.registry.forEach((component, field) => { - accumulator = callback(accumulator, component, field); - }); - return accumulator; - } -} - -class ErrorObserverRegistry { - constructor(observers = []) { - this.observers = []; - this.observers = observers; - } - add(observer) { - if (!this.observers.some(o => o.callback === observer.callback)) { - this.observers.push(observer); - } - } - remove(handler) { - this.observers = this.observers.filter(o => o.callback !== handler); - } - filter(predicate) { - return new ErrorObserverRegistry(this.observers.filter(predicate)); - } - some(predicate) { - return this.observers.some(predicate); - } - observe(errors) { - this.observers.forEach(observer => { - if (observer.type === 'form') { - observer.callback(errors); - } - else if (observer.field && - !Array.isArray(errors)) { - if (has(errors, observer.field)) { - observer.callback(errors[observer.field]); - } - else { - observer.callback([]); - } - } - }); - } -} - -let FormularioForm = class FormularioForm extends Vue { - constructor() { - super(...arguments); - this.path = ''; - this.proxy = {}; - this.registry = new Registry(this); - this.errorObserverRegistry = new ErrorObserverRegistry(); - // Local error messages are temporal, they wiped each resetValidation call - this.localFormErrors = []; - this.localFieldErrors = {}; - } - get initialValues() { - if (this.hasModel && typeof this.formularioValue === 'object') { - // If there is a v-model on the form/group, use those values as first priority - return Object.assign({}, this.formularioValue); // @todo - use a deep clone to detach reference types - } - return {}; - } - get mergedFormErrors() { - return [...this.formErrors, ...this.localFormErrors]; - } - get mergedFieldErrors() { - return merge(this.errors || {}, this.localFieldErrors); - } - get hasModel() { - return has(this.$options.propsData || {}, 'formularioValue'); - } - get hasInitialValue() { - return this.formularioValue && typeof this.formularioValue === 'object'; - } - onFormularioValueChanged(values) { - if (this.hasModel && values && typeof values === 'object') { - this.setValues(values); - } - } - onMergedFormErrorsChanged(errors) { - this.errorObserverRegistry.filter(o => o.type === 'form').observe(errors); - } - onMergedFieldErrorsChanged(errors) { - this.errorObserverRegistry.filter(o => o.type === 'input').observe(errors); - } - created() { - this.initProxy(); - } - getFormValues() { - return this.proxy; - } - onFormSubmit() { - return this.hasValidationErrors() - .then(hasErrors => hasErrors ? undefined : clone(this.proxy)) - .then(data => { - if (typeof data !== 'undefined') { - this.$emit('submit', data); - } - else { - this.$emit('error'); - } - }); - } - onFormularioFieldValidation(payload) { - this.$emit('validation', payload); - } - addErrorObserver(observer) { - this.errorObserverRegistry.add(observer); - if (observer.type === 'form') { - observer.callback(this.mergedFormErrors); - } - else if (observer.field && has(this.mergedFieldErrors, observer.field)) { - observer.callback(this.mergedFieldErrors[observer.field]); - } - } - removeErrorObserver(observer) { - this.errorObserverRegistry.remove(observer); - } - register(field, component) { - this.registry.add(field, component); - } - deregister(field) { - this.registry.remove(field); - } - initProxy() { - if (this.hasInitialValue) { - this.proxy = this.initialValues; - } - } - setValues(values) { - const keys = Array.from(new Set([...Object.keys(values), ...Object.keys(this.proxy)])); - let proxyHasChanges = false; - keys.forEach(field => { - if (!this.registry.hasNested(field)) { - return; - } - this.registry.getNested(field).forEach((registryField, registryKey) => { - const $input = this.registry.get(registryKey); - const oldValue = getNested(this.proxy, registryKey); - const newValue = getNested(values, registryKey); - if (!shallowEqualObjects(newValue, oldValue)) { - this.setFieldValue(registryKey, newValue); - proxyHasChanges = true; - } - if (!shallowEqualObjects(newValue, $input.proxy)) { - $input.context.model = newValue; - } - }); - }); - this.initProxy(); - if (proxyHasChanges) { - this.$emit('input', Object.assign({}, this.proxy)); - } - } - setFieldValue(field, value) { - if (value === undefined) { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const _a = this.proxy, _b = field, value = _a[_b], proxy = __rest(_a, [typeof _b === "symbol" ? _b : _b + ""]); - this.proxy = proxy; - } - else { - setNested(this.proxy, field, value); - } - } - setFieldValueAndEmit(field, value) { - this.setFieldValue(field, value); - this.$emit('input', Object.assign({}, this.proxy)); - } - setErrors({ formErrors, inputErrors }) { - this.localFormErrors = formErrors || []; - this.localFieldErrors = inputErrors || {}; - } - hasValidationErrors() { - return Promise.all(this.registry.reduce((resolvers, input) => { - resolvers.push(input.runValidation() && input.hasValidationErrors()); - return resolvers; - }, [])).then(results => results.some(hasErrors => hasErrors)); - } - resetValidation() { - this.localFormErrors = []; - this.localFieldErrors = {}; - this.registry.forEach((input) => { - input.resetValidation(); - }); - } -}; -__decorate([ - Model('input', { default: () => ({}) }) -], FormularioForm.prototype, "formularioValue", void 0); -__decorate([ - Prop({ default: () => ({}) }) -], FormularioForm.prototype, "errors", void 0); -__decorate([ - Prop({ default: () => ([]) }) -], FormularioForm.prototype, "formErrors", void 0); -__decorate([ - Provide() -], FormularioForm.prototype, "path", void 0); -__decorate([ - Watch('formularioValue', { deep: true }) -], FormularioForm.prototype, "onFormularioValueChanged", null); -__decorate([ - Watch('mergedFormErrors') -], FormularioForm.prototype, "onMergedFormErrorsChanged", null); -__decorate([ - Watch('mergedFieldErrors', { deep: true, immediate: true }) -], FormularioForm.prototype, "onMergedFieldErrorsChanged", null); -__decorate([ - Provide() -], FormularioForm.prototype, "getFormValues", null); -__decorate([ - Provide() -], FormularioForm.prototype, "onFormularioFieldValidation", null); -__decorate([ - Provide() -], FormularioForm.prototype, "addErrorObserver", null); -__decorate([ - Provide() -], FormularioForm.prototype, "removeErrorObserver", null); -__decorate([ - Provide('formularioRegister') -], FormularioForm.prototype, "register", null); -__decorate([ - Provide('formularioDeregister') -], FormularioForm.prototype, "deregister", null); -__decorate([ - Provide('formularioSetter') -], FormularioForm.prototype, "setFieldValueAndEmit", null); -FormularioForm = __decorate([ - Component({ name: 'FormularioForm' }) -], FormularioForm); -var script = FormularioForm; - -function normalizeComponent(template, style, script, scopeId, isFunctionalTemplate, moduleIdentifier /* server only */, shadowMode, createInjector, createInjectorSSR, createInjectorShadow) { - if (typeof shadowMode !== 'boolean') { - createInjectorSSR = createInjector; - createInjector = shadowMode; - shadowMode = false; - } - // Vue.extend constructor export interop. - const options = typeof script === 'function' ? script.options : script; - // render functions - if (template && template.render) { - options.render = template.render; - options.staticRenderFns = template.staticRenderFns; - options._compiled = true; - // functional template - if (isFunctionalTemplate) { - options.functional = true; - } - } - // scopedId - if (scopeId) { - options._scopeId = scopeId; - } - let hook; - if (moduleIdentifier) { - // server build - hook = function (context) { - // 2.3 injection - context = - context || // cached call - (this.$vnode && this.$vnode.ssrContext) || // stateful - (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext); // functional - // 2.2 with runInNewContext: true - if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') { - context = __VUE_SSR_CONTEXT__; - } - // inject component styles - if (style) { - style.call(this, createInjectorSSR(context)); - } - // register component module identifier for async chunk inference - if (context && context._registeredComponents) { - context._registeredComponents.add(moduleIdentifier); - } - }; - // used by ssr in case component is cached and beforeCreate - // never gets called - options._ssrRegister = hook; - } - else if (style) { - hook = shadowMode - ? function (context) { - style.call(this, createInjectorShadow(context, this.$root.$options.shadowRoot)); - } - : function (context) { - style.call(this, createInjector(context)); - }; - } - if (hook) { - if (options.functional) { - // register for functional component in vue file - const originalRender = options.render; - options.render = function renderWithStyleInjection(h, context) { - hook.call(context); - return originalRender(h, context); - }; - } - else { - // inject component registration as beforeCreate hook - const existing = options.beforeCreate; - options.beforeCreate = existing ? [].concat(existing, hook) : [hook]; - } - } - return script; -} - -/* script */ -const __vue_script__ = script; - -/* template */ -var __vue_render__ = function() { - var _vm = this; - var _h = _vm.$createElement; - var _c = _vm._self._c || _h; - return _c( - "form", - { - on: { - submit: function($event) { - $event.preventDefault(); - return _vm.onFormSubmit($event) - } - } - }, - [_vm._t("default", null, { errors: _vm.mergedFormErrors })], - 2 - ) -}; -var __vue_staticRenderFns__ = []; -__vue_render__._withStripped = true; - - /* style */ - const __vue_inject_styles__ = undefined; - /* scoped */ - const __vue_scope_id__ = undefined; - /* module identifier */ - const __vue_module_identifier__ = undefined; - /* functional template */ - const __vue_is_functional_template__ = false; - /* style inject */ - - /* style inject SSR */ - - /* style inject shadow dom */ - - - - const __vue_component__ = /*#__PURE__*/normalizeComponent( - { render: __vue_render__, staticRenderFns: __vue_staticRenderFns__ }, - __vue_inject_styles__, - __vue_script__, - __vue_scope_id__, - __vue_is_functional_template__, - __vue_module_identifier__, - false, - undefined, - undefined, - undefined - ); - -let FormularioGrouping = class FormularioGrouping extends Vue { - get groupPath() { - if (this.isArrayItem) { - return `${this.path}[${this.name}]`; - } - if (this.path === '') { - return this.name; - } - return `${this.path}.${this.name}`; - } -}; -__decorate([ - Inject({ default: '' }) -], FormularioGrouping.prototype, "path", void 0); -__decorate([ - Prop({ required: true }) -], FormularioGrouping.prototype, "name", void 0); -__decorate([ - Prop({ default: false }) -], FormularioGrouping.prototype, "isArrayItem", void 0); -__decorate([ - Provide('path') -], FormularioGrouping.prototype, "groupPath", null); -FormularioGrouping = __decorate([ - Component({ name: 'FormularioGrouping' }) -], FormularioGrouping); -var script$1 = FormularioGrouping; - -/* script */ -const __vue_script__$1 = script$1; - -/* template */ -var __vue_render__$1 = function() { - var _vm = this; - var _h = _vm.$createElement; - var _c = _vm._self._c || _h; - return _c("div", [_vm._t("default")], 2) -}; -var __vue_staticRenderFns__$1 = []; -__vue_render__$1._withStripped = true; - - /* style */ - const __vue_inject_styles__$1 = undefined; - /* scoped */ - const __vue_scope_id__$1 = undefined; - /* module identifier */ - const __vue_module_identifier__$1 = undefined; - /* functional template */ - const __vue_is_functional_template__$1 = false; - /* style inject */ - - /* style inject SSR */ - - /* style inject shadow dom */ - - - - const __vue_component__$1 = /*#__PURE__*/normalizeComponent( - { render: __vue_render__$1, staticRenderFns: __vue_staticRenderFns__$1 }, - __vue_inject_styles__$1, - __vue_script__$1, - __vue_scope_id__$1, - __vue_is_functional_template__$1, - __vue_module_identifier__$1, - false, - undefined, - undefined, - undefined - ); - function createValidator(ruleFn, ruleName, ruleArgs, messageFn) { return (context) => { return Promise.resolve(ruleFn(context, ...ruleArgs)).then(valid => { @@ -1309,42 +884,35 @@ const VALIDATION_BEHAVIOR = { LIVE: 'live', SUBMIT: 'submit', }; -let FormularioInput = class FormularioInput extends Vue { +let FormularioField = class FormularioField extends Vue { constructor() { super(...arguments); - this.proxy = this.getInitialValue(); + this.proxy = this.hasModel ? this.value : ''; this.localErrors = []; this.violations = []; - this.validationRun = Promise.resolve(); + this.validationRun = Promise.resolve([]); } - get fullQualifiedName() { - return this.path !== '' ? `${this.path}.${this.name}` : this.name; + get fullPath() { + return this.__Formulario_path !== '' ? `${this.__Formulario_path}.${this.name}` : this.name; } - get model() { - const model = this.hasModel ? 'value' : 'proxy'; - return this.modelGetConverter(this[model]); - } - set model(value) { - value = this.modelSetConverter(value, this.proxy); - if (!shallowEqualObjects(value, this.proxy)) { - this.proxy = value; - } - this.$emit('input', value); - if (typeof this.formularioSetter === 'function') { - this.formularioSetter(this.context.name, value); - } + /** + * Determines if this formulario element is v-modeled or not. + */ + get hasModel() { + return has(this.$options.propsData || {}, 'value'); } get context() { return Object.defineProperty({ - name: this.fullQualifiedName, + name: this.fullPath, + path: this.fullPath, runValidation: this.runValidation.bind(this), violations: this.violations, errors: this.localErrors, allErrors: [...this.localErrors, ...this.violations.map(v => v.message)], }, 'model', { - get: () => this.model, + get: () => this.modelGetConverter(this.proxy), set: (value) => { - this.model = value; + this.syncProxy(this.modelSetConverter(value, this.proxy)); }, }); } @@ -1362,84 +930,67 @@ let FormularioInput = class FormularioInput extends Vue { }); return messages; } - /** - * Determines if this formulario element is v-modeled or not. - */ - get hasModel() { - return has(this.$options.propsData || {}, 'value'); + onValueChange() { + this.syncProxy(this.value); } - onProxyChanged(newValue, oldValue) { - if (!this.hasModel && !shallowEqualObjects(newValue, oldValue)) { - this.context.model = newValue; - } + onProxyChange() { if (this.validationBehavior === VALIDATION_BEHAVIOR.LIVE) { this.runValidation(); } else { - this.violations = []; - } - } - onValueChanged(newValue, oldValue) { - if (this.hasModel && !shallowEqualObjects(newValue, oldValue)) { - this.context.model = newValue; + this.resetValidation(); } } + /** + * @internal + */ created() { - this.initProxy(); - if (typeof this.formularioRegister === 'function') { - this.formularioRegister(this.fullQualifiedName, this); - } - if (typeof this.addErrorObserver === 'function' && !this.errorsDisabled) { - this.addErrorObserver({ callback: this.setErrors, type: 'input', field: this.fullQualifiedName }); + if (typeof this.__FormularioForm_register === 'function') { + this.__FormularioForm_register(this.fullPath, this); } if (this.validationBehavior === VALIDATION_BEHAVIOR.LIVE) { this.runValidation(); } } - // noinspection JSUnusedGlobalSymbols + /** + * @internal + */ beforeDestroy() { - if (!this.errorsDisabled && typeof this.removeErrorObserver === 'function') { - this.removeErrorObserver(this.setErrors); - } - if (typeof this.formularioDeregister === 'function') { - this.formularioDeregister(this.fullQualifiedName); + if (typeof this.__FormularioForm_unregister === 'function') { + this.__FormularioForm_unregister(this.fullPath); } } - getInitialValue() { - return has(this.$options.propsData || {}, 'value') ? this.value : ''; - } - initProxy() { - // This should only be run immediately on created and ensures that the - // proxy and the model are both the same before any additional registration. - if (!shallowEqualObjects(this.context.model, this.proxy)) { - this.context.model = this.proxy; + syncProxy(value) { + if (!deepEquals(value, this.proxy)) { + this.proxy = value; + this.$emit('input', value); + if (typeof this.__FormularioForm_set === 'function') { + this.__FormularioForm_set(this.fullPath, value); + this.__FormularioForm_emitInput(); + } } } runValidation() { this.validationRun = this.validate().then(violations => { - const validationChanged = !shallowEqualObjects(violations, this.violations); this.violations = violations; - if (validationChanged) { - const payload = { - name: this.context.name, - violations: this.violations, - }; - this.$emit('validation', payload); - if (typeof this.onFormularioFieldValidation === 'function') { - this.onFormularioFieldValidation(payload); - } - } + this.emitValidation(this.fullPath, violations); return this.violations; }); return this.validationRun; } validate() { return validate(processConstraints(this.validation, this.$formulario.getRules(this.normalizedValidationRules), this.$formulario.getMessages(this, this.normalizedValidationMessages)), { - value: this.context.model, - name: this.context.name, - formValues: this.getFormValues(), + value: this.proxy, + name: this.fullPath, + formValues: this.__FormularioForm_getState(), }); } + emitValidation(path, violations) { + this.$emit('validation', { path, violations }); + if (typeof this.__FormularioForm_emitValidation === 'function') { + this.__FormularioForm_emitValidation(path, violations); + } + } hasValidationErrors() { return new Promise(resolve => { this.$nextTick(() => { @@ -1447,81 +998,448 @@ let FormularioInput = class FormularioInput extends Vue { }); }); } + /** + * @internal + */ setErrors(errors) { - this.localErrors = arrayify(errors); + if (!this.errorsDisabled) { + this.localErrors = errors; + } } + /** + * @internal + */ resetValidation() { this.localErrors = []; this.violations = []; } }; +__decorate([ + Inject({ default: '' }) +], FormularioField.prototype, "__Formulario_path", void 0); __decorate([ Inject({ default: undefined }) -], FormularioInput.prototype, "formularioSetter", void 0); +], FormularioField.prototype, "__FormularioForm_set", void 0); __decorate([ Inject({ default: () => () => { } }) -], FormularioInput.prototype, "onFormularioFieldValidation", void 0); +], FormularioField.prototype, "__FormularioForm_emitInput", void 0); +__decorate([ + Inject({ default: () => () => { } }) +], FormularioField.prototype, "__FormularioForm_emitValidation", void 0); __decorate([ Inject({ default: undefined }) -], FormularioInput.prototype, "formularioRegister", void 0); +], FormularioField.prototype, "__FormularioForm_register", void 0); __decorate([ Inject({ default: undefined }) -], FormularioInput.prototype, "formularioDeregister", void 0); +], FormularioField.prototype, "__FormularioForm_unregister", void 0); __decorate([ Inject({ default: () => () => ({}) }) -], FormularioInput.prototype, "getFormValues", void 0); -__decorate([ - Inject({ default: undefined }) -], FormularioInput.prototype, "addErrorObserver", void 0); -__decorate([ - Inject({ default: undefined }) -], FormularioInput.prototype, "removeErrorObserver", void 0); -__decorate([ - Inject({ default: '' }) -], FormularioInput.prototype, "path", void 0); +], FormularioField.prototype, "__FormularioForm_getState", void 0); __decorate([ Model('input', { default: '' }) -], FormularioInput.prototype, "value", void 0); +], FormularioField.prototype, "value", void 0); __decorate([ Prop({ required: true, validator: (name) => typeof name === 'string' && name.length > 0, }) -], FormularioInput.prototype, "name", void 0); +], FormularioField.prototype, "name", void 0); __decorate([ Prop({ default: '' }) -], FormularioInput.prototype, "validation", void 0); +], FormularioField.prototype, "validation", void 0); __decorate([ Prop({ default: () => ({}) }) -], FormularioInput.prototype, "validationRules", void 0); +], FormularioField.prototype, "validationRules", void 0); __decorate([ Prop({ default: () => ({}) }) -], FormularioInput.prototype, "validationMessages", void 0); +], FormularioField.prototype, "validationMessages", void 0); __decorate([ Prop({ default: VALIDATION_BEHAVIOR.DEMAND, validator: behavior => Object.values(VALIDATION_BEHAVIOR).includes(behavior) }) -], FormularioInput.prototype, "validationBehavior", void 0); +], FormularioField.prototype, "validationBehavior", void 0); __decorate([ Prop({ default: false }) -], FormularioInput.prototype, "errorsDisabled", void 0); +], FormularioField.prototype, "errorsDisabled", void 0); __decorate([ Prop({ default: () => (value) => value }) -], FormularioInput.prototype, "modelGetConverter", void 0); +], FormularioField.prototype, "modelGetConverter", void 0); __decorate([ Prop({ default: () => (value) => value }) -], FormularioInput.prototype, "modelSetConverter", void 0); -__decorate([ - Watch('proxy') -], FormularioInput.prototype, "onProxyChanged", null); +], FormularioField.prototype, "modelSetConverter", void 0); __decorate([ Watch('value') -], FormularioInput.prototype, "onValueChanged", null); -FormularioInput = __decorate([ - Component({ name: 'FormularioInput', inheritAttrs: false }) -], FormularioInput); -var script$2 = FormularioInput; +], FormularioField.prototype, "onValueChange", null); +__decorate([ + Watch('proxy') +], FormularioField.prototype, "onProxyChange", null); +FormularioField = __decorate([ + Component({ name: 'FormularioField', inheritAttrs: false }) +], FormularioField); +var script = FormularioField; + +function normalizeComponent(template, style, script, scopeId, isFunctionalTemplate, moduleIdentifier /* server only */, shadowMode, createInjector, createInjectorSSR, createInjectorShadow) { + if (typeof shadowMode !== 'boolean') { + createInjectorSSR = createInjector; + createInjector = shadowMode; + shadowMode = false; + } + // Vue.extend constructor export interop. + const options = typeof script === 'function' ? script.options : script; + // render functions + if (template && template.render) { + options.render = template.render; + options.staticRenderFns = template.staticRenderFns; + options._compiled = true; + // functional template + if (isFunctionalTemplate) { + options.functional = true; + } + } + // scopedId + if (scopeId) { + options._scopeId = scopeId; + } + let hook; + if (moduleIdentifier) { + // server build + hook = function (context) { + // 2.3 injection + context = + context || // cached call + (this.$vnode && this.$vnode.ssrContext) || // stateful + (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext); // functional + // 2.2 with runInNewContext: true + if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') { + context = __VUE_SSR_CONTEXT__; + } + // inject component styles + if (style) { + style.call(this, createInjectorSSR(context)); + } + // register component module identifier for async chunk inference + if (context && context._registeredComponents) { + context._registeredComponents.add(moduleIdentifier); + } + }; + // used by ssr in case component is cached and beforeCreate + // never gets called + options._ssrRegister = hook; + } + else if (style) { + hook = shadowMode + ? function (context) { + style.call(this, createInjectorShadow(context, this.$root.$options.shadowRoot)); + } + : function (context) { + style.call(this, createInjector(context)); + }; + } + if (hook) { + if (options.functional) { + // register for functional component in vue file + const originalRender = options.render; + options.render = function renderWithStyleInjection(h, context) { + hook.call(context); + return originalRender(h, context); + }; + } + else { + // inject component registration as beforeCreate hook + const existing = options.beforeCreate; + options.beforeCreate = existing ? [].concat(existing, hook) : [hook]; + } + } + return script; +} + +/* script */ +const __vue_script__ = script; + +/* template */ +var __vue_render__ = function() { + var _vm = this; + var _h = _vm.$createElement; + var _c = _vm._self._c || _h; + return _c( + "div", + _vm._b({}, "div", _vm.$attrs, false), + [_vm._t("default", null, { context: _vm.context })], + 2 + ) +}; +var __vue_staticRenderFns__ = []; +__vue_render__._withStripped = true; + + /* style */ + const __vue_inject_styles__ = undefined; + /* scoped */ + const __vue_scope_id__ = undefined; + /* module identifier */ + const __vue_module_identifier__ = undefined; + /* functional template */ + const __vue_is_functional_template__ = false; + /* style inject */ + + /* style inject SSR */ + + /* style inject shadow dom */ + + + + const __vue_component__ = /*#__PURE__*/normalizeComponent( + { render: __vue_render__, staticRenderFns: __vue_staticRenderFns__ }, + __vue_inject_styles__, + __vue_script__, + __vue_scope_id__, + __vue_is_functional_template__, + __vue_module_identifier__, + false, + undefined, + undefined, + undefined + ); + +let FormularioFieldGroup = class FormularioFieldGroup extends Vue { + get fullPath() { + const path = `${this.name}`; + if (parseInt(path).toString() === path) { + return `${this.__Formulario_path}[${path}]`; + } + if (this.__Formulario_path === '') { + return path; + } + return `${this.__Formulario_path}.${path}`; + } +}; +__decorate([ + Inject({ default: '' }) +], FormularioFieldGroup.prototype, "__Formulario_path", void 0); +__decorate([ + Prop({ required: true }) +], FormularioFieldGroup.prototype, "name", void 0); +__decorate([ + Provide('__Formulario_path') +], FormularioFieldGroup.prototype, "fullPath", null); +FormularioFieldGroup = __decorate([ + Component({ name: 'FormularioFieldGroup' }) +], FormularioFieldGroup); +var script$1 = FormularioFieldGroup; + +/* script */ +const __vue_script__$1 = script$1; + +/* template */ +var __vue_render__$1 = function() { + var _vm = this; + var _h = _vm.$createElement; + var _c = _vm._self._c || _h; + return _c("div", [_vm._t("default")], 2) +}; +var __vue_staticRenderFns__$1 = []; +__vue_render__$1._withStripped = true; + + /* style */ + const __vue_inject_styles__$1 = undefined; + /* scoped */ + const __vue_scope_id__$1 = undefined; + /* module identifier */ + const __vue_module_identifier__$1 = undefined; + /* functional template */ + const __vue_is_functional_template__$1 = false; + /* style inject */ + + /* style inject SSR */ + + /* style inject shadow dom */ + + + + const __vue_component__$1 = /*#__PURE__*/normalizeComponent( + { render: __vue_render__$1, staticRenderFns: __vue_staticRenderFns__$1 }, + __vue_inject_styles__$1, + __vue_script__$1, + __vue_scope_id__$1, + __vue_is_functional_template__$1, + __vue_module_identifier__$1, + false, + undefined, + undefined, + undefined + ); + +const update = (state, path, value) => { + if (value === undefined) { + return unset(state, path); + } + return set(state, path, value); +}; +let FormularioForm = class FormularioForm extends Vue { + constructor() { + super(...arguments); + this.proxy = {}; + this.registry = new Map(); + // Local error messages are temporal, they wiped each resetValidation call + this.localFieldsErrors = {}; + this.localFormErrors = []; + } + get fieldsErrorsComputed() { + return merge(this.fieldsErrors || {}, this.localFieldsErrors); + } + get formErrorsComputed() { + return [...this.formErrors, ...this.localFormErrors]; + } + register(path, field) { + if (!this.registry.has(path)) { + this.registry.set(path, field); + } + const value = get(this.proxy, path); + if (!field.hasModel) { + if (value !== undefined) { + field.proxy = value; + } + else { + this.setFieldValue(path, null); + this.emitInput(); + } + } + else if (!deepEquals(field.proxy, value)) { + this.setFieldValue(path, field.proxy); + this.emitInput(); + } + if (has(this.fieldsErrorsComputed, path)) { + field.setErrors(this.fieldsErrorsComputed[path]); + } + } + unregister(path) { + if (this.registry.has(path)) { + this.registry.delete(path); + this.proxy = unset(this.proxy, path); + this.emitInput(); + } + } + getState() { + return this.proxy; + } + setFieldValue(path, value) { + this.proxy = update(this.proxy, path, value); + } + emitInput() { + this.$emit('input', clone(this.proxy)); + } + emitValidation(path, violations) { + this.$emit('validation', { path, violations }); + } + onStateChange(newState) { + const newProxy = clone(newState); + const oldProxy = this.proxy; + let proxyHasChanges = false; + this.registry.forEach((field, path) => { + const newValue = get(newState, path, null); + const oldValue = get(oldProxy, path, null); + field.proxy = newValue; + if (!deepEquals(newValue, oldValue)) { + field.$emit('input', newValue); + update(newProxy, path, newValue); + proxyHasChanges = true; + } + }); + this.proxy = newProxy; + if (proxyHasChanges) { + this.emitInput(); + } + } + onFieldsErrorsChange(fieldsErrors) { + this.registry.forEach((field, path) => { + field.setErrors(fieldsErrors[path] || []); + }); + } + created() { + this.$formulario.register(this.id, this); + if (typeof this.state === 'object') { + this.proxy = clone(this.state); + } + } + beforeDestroy() { + this.$formulario.unregister(this.id); + } + runValidation() { + const runs = []; + const violations = {}; + this.registry.forEach((field, path) => { + runs.push(field.runValidation().then(v => { violations[path] = v; })); + }); + return Promise.all(runs).then(() => violations); + } + hasValidationErrors() { + return this.runValidation().then(violations => { + return Object.keys(violations).some(path => violations[path].length > 0); + }); + } + setErrors({ fieldsErrors, formErrors }) { + this.localFieldsErrors = fieldsErrors || {}; + this.localFormErrors = formErrors || []; + } + resetValidation() { + this.localFieldsErrors = {}; + this.localFormErrors = []; + this.registry.forEach((field) => { + field.resetValidation(); + }); + } + onSubmit() { + return this.runValidation().then(violations => { + const hasErrors = Object.keys(violations).some(path => violations[path].length > 0); + if (!hasErrors) { + this.$emit('submit', clone(this.proxy)); + } + else { + this.$emit('error', violations); + } + }); + } +}; +__decorate([ + Model('input', { default: () => ({}) }) +], FormularioForm.prototype, "state", void 0); +__decorate([ + Prop({ default: () => id('formulario-form') }) +], FormularioForm.prototype, "id", void 0); +__decorate([ + Prop({ default: () => ({}) }) +], FormularioForm.prototype, "fieldsErrors", void 0); +__decorate([ + Prop({ default: () => ([]) }) +], FormularioForm.prototype, "formErrors", void 0); +__decorate([ + Provide('__FormularioForm_register') +], FormularioForm.prototype, "register", null); +__decorate([ + Provide('__FormularioForm_unregister') +], FormularioForm.prototype, "unregister", null); +__decorate([ + Provide('__FormularioForm_getState') +], FormularioForm.prototype, "getState", null); +__decorate([ + Provide('__FormularioForm_set') +], FormularioForm.prototype, "setFieldValue", null); +__decorate([ + Provide('__FormularioForm_emitInput') +], FormularioForm.prototype, "emitInput", null); +__decorate([ + Provide('__FormularioForm_emitValidation') +], FormularioForm.prototype, "emitValidation", null); +__decorate([ + Watch('state', { deep: true }) +], FormularioForm.prototype, "onStateChange", null); +__decorate([ + Watch('fieldsErrorsComputed', { deep: true, immediate: true }) +], FormularioForm.prototype, "onFieldsErrorsChange", null); +FormularioForm = __decorate([ + Component({ name: 'FormularioForm' }) +], FormularioForm); +var script$2 = FormularioForm; /* script */ const __vue_script__$2 = script$2; @@ -1532,9 +1450,16 @@ var __vue_render__$2 = function() { var _h = _vm.$createElement; var _c = _vm._self._c || _h; return _c( - "div", - { staticClass: "formulario-input" }, - [_vm._t("default", null, { context: _vm.context })], + "form", + { + on: { + submit: function($event) { + $event.preventDefault(); + return _vm.onSubmit($event) + } + } + }, + [_vm._t("default", null, { errors: _vm.formErrorsComputed })], 2 ) }; @@ -1571,10 +1496,15 @@ __vue_render__$2._withStripped = true; ); var index = { + Formulario, install(Vue, options) { - Vue.component('FormularioForm', __vue_component__); + Vue.component('FormularioField', __vue_component__); + Vue.component('FormularioFieldGroup', __vue_component__$1); + Vue.component('FormularioForm', __vue_component__$2); + // @deprecated Use FormularioField instead + Vue.component('FormularioInput', __vue_component__); + // @deprecated Use FormularioFieldGroup instead Vue.component('FormularioGrouping', __vue_component__$1); - Vue.component('FormularioInput', __vue_component__$2); Vue.mixin({ beforeCreate() { const o = this.$options; diff --git a/dist/formulario.min.js b/dist/formulario.min.js index 5a1d030..8e2b17a 100644 --- a/dist/formulario.min.js +++ b/dist/formulario.min.js @@ -12,7 +12,7 @@ function e(t){return!0==(null!=(e=t)&&"object"==typeof e&&!1===Array.isArray(e)) * Copyright (c) 2014-2017, Jon Schlinkert. * Released under the MIT License. */ -var e}function r(t){var r,o;return!1!==e(t)&&("function"==typeof(r=t.constructor)&&(!1!==e(o=r.prototype)&&!1!==o.hasOwnProperty("isPrototypeOf")))}function o(t,e){return Object.prototype.hasOwnProperty.call(t,e)}function i(t,e,n=!0){const a={};for(const s in t)o(e,s)?r(e[s])&&r(t[s])?a[s]=i(t[s],e[s],n):n&&Array.isArray(t[s])&&Array.isArray(e[s])?a[s]=t[s].concat(e[s]):a[s]=e[s]:a[s]=t[s];for(const t in e)o(a,t)||(a[t]=e[t]);return a}t=t&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t;var n=function(t){if("string"!=typeof t)return!1;var e=t.match(a);if(!e)return!1;var r=e[1];if(!r)return!1;if(s.test(r)||l.test(r))return!0;return!1},a=/^(?:\w+:)?\/\/(\S+)$/,s=/^localhost[\:?\d]*(?:[^\:?\d]\S*)?$/,l=/^[^\s\.]+\.\S{2,}$/;function u(t){switch(typeof t){case"symbol":case"number":case"string":case"boolean":case"undefined":return!0;default:return null===t}}function c(t,e){if(t===e)return!0;if(!t||!e)return!1;const r=Object.keys(t);if(Object.keys(e).length!==r.length)return!1;if(t instanceof Date&&e instanceof Date)return t.getTime()===e.getTime();if(0===r.length)return t===e;for(let o=0;o0!==t.indexOf(e)&&"_"!==t[t.indexOf(e)-1]?e.toUpperCase().replace("_",""):e)}function f(t,e){const r=e.split(".");let o=t;for(const t in r){const e=r[t].match(/(.+)\[(\d+)\]$/);if(void 0===o)return null;if(e){if(o=o[e[1]],void 0===o)return null;o=o[e[2]]}else o=o[r[t]]}return o}const h={accepted:({value:t})=>["yes","on","1",1,!0,"true"].includes(t),after({value:t},e=!1){const r=!1!==e?Date.parse(e):Date.now(),o=t instanceof Date?t.getTime():Date.parse(t);return!isNaN(o)&&o>r},alpha({value:t},e="default"){const r={default:/^[a-zA-ZÀ-ÖØ-öø-ÿ]+$/,latin:/^[a-zA-Z]+$/};return"string"==typeof t&&r[o(r,e)?e:"default"].test(t)},alphanumeric({value:t},e="default"){const r={default:/^[a-zA-Z0-9À-ÖØ-öø-ÿ]+$/,latin:/^[a-zA-Z0-9]+$/};return"string"==typeof t&&r[o(r,e)?e:"default"].test(t)},before({value:t},e=!1){const r=!1!==e?Date.parse(e):Date.now(),o=t instanceof Date?t.getTime():Date.parse(t);return!isNaN(o)&&onull!==e&&null!==r&&!isNaN(e)&&!isNaN(r)&&(!isNaN(Number(t))&&"length"!==o||"value"===o?(t=Number(t))>Number(e)&&te&&t.lengthe?function(t){const e=`^${r=t,r.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}$`;var r;const o={MM:"(0[1-9]|1[012])",M:"([1-9]|1[012])",DD:"([012][1-9]|3[01])",D:"([012]?[1-9]|3[01])",YYYY:"\\d{4}",YY:"\\d{2}"};return new RegExp(Object.keys(o).reduce((t,e)=>t.replace(e,o[e]),e))}(e).test(t):!isNaN(Date.parse(t)),email({value:t}){if(!t)return!0;return/^(([^<>()\[\].,;:\s@"]+(\.[^<>()\[\].,;:\s@"]+)*)|(".+"))@(([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{2,})$/i.test(t)},endsWith:({value:t},...e)=>!t||"string"==typeof t&&(0===e.length||e.some(e=>t.endsWith(e))),in:({value:t},...e)=>e.some(e=>"object"==typeof e?c(e,t):e===t),matches:({value:t},...e)=>!!e.find(e=>("string"==typeof e&&"/"===e.substr(0,1)&&"/"===e.substr(-1)&&(e=new RegExp(e.substr(1,e.length-2))),e instanceof RegExp?e.test(t):e===t)),max:({value:t},e=10,r)=>Array.isArray(t)?(e=isNaN(Number(e))?e:Number(e),t.length<=e):!isNaN(t)&&"length"!==r||"value"===r?(t=isNaN(t)?t:Number(t))<=e:("string"==typeof t||"length"===r)&&(t=isNaN(t)?t:t.toString()).length<=e,min:({value:t},e=1,r)=>Array.isArray(t)?(e=isNaN(e)?e:Number(e),t.length>=e):!isNaN(t)&&"length"!==r||"value"===r?(t=isNaN(t)?t:Number(t))>=e:("string"==typeof t||"length"===r)&&(t=isNaN(t)?t:t.toString()).length>=e,not:({value:t},...e)=>!e.some(e=>"object"==typeof e?c(e,t):e===t),number:({value:t})=>String(t).length>0&&!isNaN(Number(t)),required:({value:t},e=!0)=>!(e&&!["no","false"].includes(e))||(Array.isArray(t)?!!t.length:"string"==typeof t?!!t:"object"!=typeof t||!!t&&!!Object.keys(t).length),startsWith:({value:t},...e)=>!t||"string"==typeof t&&(0===e.length||e.some(e=>t.startsWith(e))),url:({value:t})=>n(t),bail:()=>!0},p={default:(t,e)=>t.$t("validation.default",e),accepted:(t,e)=>t.$t("validation.accepted",e),after:(t,e,r=!1)=>"string"==typeof r&&r.length?t.$t("validation.after.compare",e):t.$t("validation.after.default",e),alpha:(t,e)=>t.$t("validation.alpha",e),alphanumeric:(t,e)=>t.$t("validation.alphanumeric",e),before:(t,e,r=!1)=>"string"==typeof r&&r.length?t.$t("validation.before.compare",e):t.$t("validation.before.default",e),between(t,e,r=0,o=10,i){const n=Object.assign(Object.assign({},e),{from:r,to:o});return!isNaN(e.value)&&"length"!==i||"value"===i?t.$t("validation.between.force",n):t.$t("validation.between.default",n)},confirm:(t,e)=>t.$t("validation.confirm",e),date:(t,e,r=!1)=>"string"==typeof r&&r.length?t.$t("validation.date.format",e):t.$t("validation.date.default",e),email:(t,e)=>t.$t("validation.email.default",e),endsWith:(t,e)=>t.$t("validation.endsWith.default",e),in:(t,e)=>"string"==typeof e.value&&e.value?t.$t("validation.in.string",e):t.$t("validation.in.default",e),matches:(t,e)=>t.$t("validation.matches.default",e),max:(t,e,r=10,o)=>Array.isArray(e.value)?t.$tc("validation.max.array",r,e):!isNaN(e.value)&&"length"!==o||"value"===o?t.$tc("validation.max.force",r,e):t.$tc("validation.max.default",r,e),min:(t,e,r=1,o)=>Array.isArray(e.value)?t.$tc("validation.min.array",r,e):!isNaN(e.value)&&"length"!==o||"value"===o?t.$tc("validation.min.force",r,e):t.$tc("validation.min.default",r,e),not:(t,e)=>t.$t("validation.not.default",e),number:(t,e)=>t.$t("validation.number.default",e),required:(t,e)=>t.$t("validation.required.default",e),startsWith:(t,e)=>t.$t("validation.startsWith.default",e),url:(t,e)=>t.$t("validation.url.default",e)};class v{constructor(t){this.validationRules={},this.validationMessages={},this.validationRules=h,this.validationMessages=p,this.extend(t||{})}extend(t){if("object"==typeof t)return this.validationRules=i(this.validationRules,t.validationRules||{}),this.validationMessages=i(this.validationMessages,t.validationMessages||{}),this;throw new Error(`[Formulario]: Formulario.extend() should be passed an object (was ${typeof t})`)}getRules(t={}){return i(this.validationRules,t)}getMessages(t,e){const r=i(this.validationMessages||{},e),o={};for(const e in r)o[e]=(o,...i)=>"string"==typeof r[e]?r[e]:r[e](t,o,...i);return o}} +var e}function r(t){var r,o;return!1!==e(t)&&("function"==typeof(r=t.constructor)&&(!1!==e(o=r.prototype)&&!1!==o.hasOwnProperty("isPrototypeOf")))}function o(t,e){return Object.prototype.hasOwnProperty.call(t,e)}function n(t,e,i=!0){const a={};for(const s in t)o(e,s)?r(e[s])&&r(t[s])?a[s]=n(t[s],e[s],i):i&&Array.isArray(t[s])&&Array.isArray(e[s])?a[s]=t[s].concat(e[s]):a[s]=e[s]:a[s]=t[s];for(const t in e)o(a,t)||(a[t]=e[t]);return a}t=t&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t;var i=function(t){if("string"!=typeof t)return!1;var e=t.match(a);if(!e)return!1;var r=e[1];if(!r)return!1;if(s.test(r)||l.test(r))return!0;return!1},a=/^(?:\w+:)?\/\/(\S+)$/,s=/^localhost[\:?\d]*(?:[^\:?\d]\S*)?$/,l=/^[^\s\.]+\.\S{2,}$/;const u=new Map;var c;function f(t){switch(typeof t){case"bigint":return c.BIGINT;case"boolean":return c.BOOLEAN;case"function":return c.FUNCTION;case"number":return c.NUMBER;case"string":return c.STRING;case"symbol":return c.SYMBOL;case"undefined":return c.UNDEFINED;case"object":return null===t?c.NULL:t instanceof Date?c.DATE:Array.isArray(t)?c.ARRAY:"Object"===t.constructor.name?c.RECORD:"InstanceOf<"+t.constructor.name+">"}throw new Error}function d(t){return"object"==typeof t&&null!==t&&["Array","Object"].includes(t.constructor.name)}function p(t){switch(typeof t){case"bigint":case"boolean":case"number":case"string":case"symbol":case"undefined":return!0;default:return null===t}}!function(t){t.ARRAY="ARRAY",t.BIGINT="BIGINT",t.BOOLEAN="BOOLEAN",t.DATE="DATE",t.FUNCTION="FUNCTION",t.NUMBER="NUMBER",t.RECORD="RECORD",t.STRING="STRING",t.SYMBOL="SYMBOL",t.UNDEFINED="UNDEFINED",t.NULL="NULL"}(c||(c={}));function h(t){if(p(t))return t;if(t instanceof Date)return new Date(t);if(!d(t))return e=t,Object.assign(Object.create(Object.getPrototypeOf(e)),e);var e;if(Array.isArray(t))return t.slice().map(h);const r=t;return Object.keys(r).reduce(((t,e)=>Object.assign(Object.assign({},t),{[e]:h(r[e])})),{})} /*! ***************************************************************************** Copyright (c) Microsoft Corporation. @@ -26,9 +26,9 @@ var e}function r(t){var r,o;return!1!==e(t)&&("function"==typeof(r=t.constructor LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - ***************************************************************************** */function m(t,e){var r={};for(var o in t)Object.prototype.hasOwnProperty.call(t,o)&&e.indexOf(o)<0&&(r[o]=t[o]);if(null!=t&&"function"==typeof Object.getOwnPropertySymbols){var i=0;for(o=Object.getOwnPropertySymbols(t);i=0;s--)(i=t[s])&&(a=(n<3?i(a):n>3?i(e,r,a):i(e,r))||a);return n>3&&a&&Object.defineProperty(e,r,a),a + ***************************************************************************** */function m(t,e,r,o){var n,i=arguments.length,a=i<3?e:null===o?o=Object.getOwnPropertyDescriptor(e,r):o;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)a=Reflect.decorate(t,e,r,o);else for(var s=t.length-1;s>=0;s--)(n=t[s])&&(a=(i<3?n(a):i>3?n(e,r,a):n(e,r))||a);return i>3&&a&&Object.defineProperty(e,r,a),a}const y=t=>{const e=parseInt(t);return e.toString()===t?e:NaN},v=t=>{const e=[];return t.split(".").forEach((t=>{/(.*)\[(\d+)]$/.test(t)?e.push(...t.substr(0,t.length-1).split("[").filter((t=>t.length))):e.push(t)})),e};function g(t,e,r){const n="string"==typeof e?v(e):e;if(p(t)||0===n.length)return r;const i=n.shift(),a=y(i);if(!isNaN(a))return Array.isArray(t)&&a>=0&&a{const r=t,o=e;r[o];return function(t,e){var r={};for(var o in t)Object.prototype.hasOwnProperty.call(t,o)&&e.indexOf(o)<0&&(r[o]=t[o]);if(null!=t&&"function"==typeof Object.getOwnPropertySymbols){var n=0;for(o=Object.getOwnPropertySymbols(t);n=0&&i0!==t.indexOf(e)&&"_"!==t[t.indexOf(e)-1]?e.toUpperCase().replace("_",""):e))}const w={accepted:({value:t})=>["yes","on","1",1,!0,"true"].includes(t),after({value:t},e=!1){const r=!1!==e?Date.parse(e):Date.now(),o=t instanceof Date?t.getTime():Date.parse(t);return!isNaN(o)&&o>r},alpha({value:t},e="default"){const r={default:/^[a-zA-ZÀ-ÖØ-öø-ÿ]+$/,latin:/^[a-zA-Z]+$/};return"string"==typeof t&&r[o(r,e)?e:"default"].test(t)},alphanumeric({value:t},e="default"){const r={default:/^[a-zA-Z0-9À-ÖØ-öø-ÿ]+$/,latin:/^[a-zA-Z0-9]+$/};return"string"==typeof t&&r[o(r,e)?e:"default"].test(t)},before({value:t},e=!1){const r=!1!==e?Date.parse(e):Date.now(),o=t instanceof Date?t.getTime():Date.parse(t);return!isNaN(o)&&onull!==e&&null!==r&&!isNaN(e)&&!isNaN(r)&&(!isNaN(Number(t))&&"length"!==o||"value"===o?(t=Number(t))>Number(e)&&te&&t.lengthe?function(t){const e=`^${r=t,r.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}$`;var r;const o={MM:"(0[1-9]|1[012])",M:"([1-9]|1[012])",DD:"([012][1-9]|3[01])",D:"([012]?[1-9]|3[01])",YYYY:"\\d{4}",YY:"\\d{2}"};return new RegExp(Object.keys(o).reduce(((t,e)=>t.replace(e,o[e])),e))}(e).test(t):!isNaN(Date.parse(t)),email({value:t}){if(!t)return!0;return/^(([^<>()\[\].,;:\s@"]+(\.[^<>()\[\].,;:\s@"]+)*)|(".+"))@(([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{2,})$/i.test(t)},endsWith:({value:t},...e)=>!t||"string"==typeof t&&(0===e.length||e.some((e=>t.endsWith(e)))),in:({value:t},...e)=>e.some((e=>$(e,t))),matches:({value:t},...e)=>!!e.find((e=>("string"==typeof e&&"/"===e.substr(0,1)&&"/"===e.substr(-1)&&(e=new RegExp(e.substr(1,e.length-2))),e instanceof RegExp?e.test(t):e===t))),max:({value:t},e=10,r)=>Array.isArray(t)?(e=isNaN(Number(e))?e:Number(e),t.length<=e):!isNaN(t)&&"length"!==r||"value"===r?(t=isNaN(t)?t:Number(t))<=e:("string"==typeof t||"length"===r)&&(t=isNaN(t)?t:t.toString()).length<=e,min:({value:t},e=1,r)=>Array.isArray(t)?(e=isNaN(e)?e:Number(e),t.length>=e):!isNaN(t)&&"length"!==r||"value"===r?(t=isNaN(t)?t:Number(t))>=e:("string"==typeof t||"length"===r)&&(t=isNaN(t)?t:t.toString()).length>=e,not:({value:t},...e)=>!e.some((e=>$(e,t))),number:({value:t})=>String(t).length>0&&!isNaN(Number(t)),required:({value:t},e=!0)=>!(e&&!["no","false"].includes(e))||(Array.isArray(t)?!!t.length:"string"==typeof t?!!t:"object"!=typeof t||!!t&&!!Object.keys(t).length),startsWith:({value:t},...e)=>!t||"string"==typeof t&&(0===e.length||e.some((e=>t.startsWith(e)))),url:({value:t})=>!t||i(t),bail:()=>!0},R={default:(t,e)=>t.$t("validation.default",e),accepted:(t,e)=>t.$t("validation.accepted",e),after:(t,e,r=!1)=>"string"==typeof r&&r.length?t.$t("validation.after.compare",e):t.$t("validation.after.default",e),alpha:(t,e)=>t.$t("validation.alpha",e),alphanumeric:(t,e)=>t.$t("validation.alphanumeric",e),before:(t,e,r=!1)=>"string"==typeof r&&r.length?t.$t("validation.before.compare",e):t.$t("validation.before.default",e),between(t,e,r=0,o=10,n){const i=Object.assign(Object.assign({},e),{from:r,to:o});return!isNaN(e.value)&&"length"!==n||"value"===n?t.$t("validation.between.force",i):t.$t("validation.between.default",i)},confirm:(t,e)=>t.$t("validation.confirm",e),date:(t,e,r=!1)=>"string"==typeof r&&r.length?t.$t("validation.date.format",e):t.$t("validation.date.default",e),email:(t,e)=>t.$t("validation.email.default",e),endsWith:(t,e)=>t.$t("validation.endsWith.default",e),in:(t,e)=>"string"==typeof e.value&&e.value?t.$t("validation.in.string",e):t.$t("validation.in.default",e),matches:(t,e)=>t.$t("validation.matches.default",e),max:(t,e,r=10,o)=>Array.isArray(e.value)?t.$tc("validation.max.array",r,e):!isNaN(e.value)&&"length"!==o||"value"===o?t.$tc("validation.max.force",r,e):t.$tc("validation.max.default",r,e),min:(t,e,r=1,o)=>Array.isArray(e.value)?t.$tc("validation.min.array",r,e):!isNaN(e.value)&&"length"!==o||"value"===o?t.$tc("validation.min.force",r,e):t.$tc("validation.min.default",r,e),not:(t,e)=>t.$t("validation.not.default",e),number:(t,e)=>t.$t("validation.number.default",e),required:(t,e)=>t.$t("validation.required.default",e),startsWith:(t,e)=>t.$t("validation.startsWith.default",e),url:(t,e)=>t.$t("validation.url.default",e)};class A{constructor(t){this.validationRules={},this.validationMessages={},this.registry=new Map,this.validationRules=w,this.validationMessages=R,this.extend(t||{})}extend(t){if("object"==typeof t)return this.validationRules=n(this.validationRules,t.validationRules||{}),this.validationMessages=n(this.validationMessages,t.validationMessages||{}),this;throw new Error(`[Formulario]: Formulario.extend(): should be passed an object (was ${typeof t})`)}runValidation(t){if(!this.registry.has(t))throw new Error(`[Formulario]: Formulario.runValidation(): no forms with id "${t}"`);return this.registry.get(t).runValidation()}resetValidation(t){if(!this.registry.has(t))return;this.registry.get(t).resetValidation()}register(t,e){if(this.registry.has(t))throw new Error(`[Formulario]: Formulario.register(): id "${t}" is already in use`);this.registry.set(t,e)}unregister(t){this.registry.has(t)&&this.registry.delete(t)}getRules(t={}){return n(this.validationRules,t)}getMessages(t,e){const r=n(this.validationMessages||{},e),o={};for(const e in r)o[e]=(o,...n)=>"string"==typeof r[e]?r[e]:r[e](t,o,...n);return o}} /** * vue-class-component v7.2.3 * (c) 2015-present Evan You * @license MIT - */}function g(t){return(g="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function b(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}function O(t){return function(t){if(Array.isArray(t)){for(var e=0,r=new Array(t.length);e0&&N("Component class must inherit Vue or its descendant class when class property is used."),n}var V=["data","beforeCreate","created","beforeMount","mounted","beforeDestroy","destroyed","beforeUpdate","updated","activated","deactivated","render","errorCaptured","serverPrefetch"];function F(e){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};r.name=r.name||e._componentTag||e.name;var o=e.prototype;Object.getOwnPropertyNames(o).forEach((function(t){if("constructor"!==t)if(V.indexOf(t)>-1)r[t]=o[t];else{var e=Object.getOwnPropertyDescriptor(o,t);void 0!==e.value?"function"==typeof e.value?(r.methods||(r.methods={}))[t]=e.value:(r.mixins||(r.mixins=[])).push({data:function(){return b({},t,e.value)}}):(e.get||e.set)&&((r.computed||(r.computed={}))[t]={get:e.get,set:e.set})}})),(r.mixins||(r.mixins=[])).push({data:function(){return w(this,e)}});var i=e.__decorators__;i&&(i.forEach((function(t){return t(r)})),delete e.__decorators__);var n=Object.getPrototypeOf(e.prototype),a=n instanceof t?n.constructor:t,s=a.extend(r);return M(s,e,a),E()&&x(s,e),s}var R=["cid","super","options","superOptions","extendOptions","sealedOptions","component","directive","filter"],A={prototype:!0,arguments:!0,callee:!0,caller:!0};function M(t,e,r){Object.getOwnPropertyNames(e).forEach((function(o){if(!A[o]){var i=Object.getOwnPropertyDescriptor(t,o);if(!i||i.configurable){var n,a,s=Object.getOwnPropertyDescriptor(e,o);if(!_){if("cid"===o)return;var l=Object.getOwnPropertyDescriptor(r,o);if(n=s.value,a=g(n),null!=n&&("object"===a||"function"===a)&&l&&l.value===s.value)return}"production"!==process.env.NODE_ENV&&R.indexOf(o)>=0&&N("Static property name '".concat(o,"' declared on class '").concat(e.name,"' ")+"conflicts with reserved property name of Vue internal. It may cause unexpected behavior of the component. Consider renaming the property."),Object.defineProperty(t,o,s)}}}))}function P(t){return"function"==typeof t?F(t):function(e){return F(e,t)}}P.registerHooks=function(t){V.push.apply(V,O(t))};function D(t){return j((function(e,r){void 0===e.inject&&(e.inject={}),Array.isArray(e.inject)||(e.inject[r]=t||r)}))}function S(t){return j((function(e,r){var o,i=e.provide;("function"!=typeof(o=i)||!o.managed&&!o.managedReactive)&&(i=e.provide=function(t){var e=function(){var r=this,o="function"==typeof t?t.call(this):t;for(var i in(o=Object.create(o||null)).__reactiveInject__=this.__reactiveInject__||{},e.managed)o[e.managed[i]]=this[i];var n=function(t){o[e.managedReactive[t]]=a[t],Object.defineProperty(o.__reactiveInject__,e.managedReactive[t],{enumerable:!0,get:function(){return r[t]}})},a=this;for(var i in e.managedReactive)n(i);return o};return e.managed={},e.managedReactive={},e}(i)),i.managed[r]=t||r}))}var C="undefined"!=typeof Reflect&&void 0!==Reflect.getMetadata;function k(t,e,r){if(C&&!Array.isArray(t)&&"function"!=typeof t&&void 0===t.type){var o=Reflect.getMetadata("design:type",e,r);o!==Object&&(t.type=o)}}function I(t,e){return void 0===e&&(e={}),function(r,o){k(e,r,o),j((function(r,o){(r.props||(r.props={}))[o]=e,r.model={prop:o,event:t||o}}))(r,o)}}function T(t){return void 0===t&&(t={}),function(e,r){k(t,e,r),j((function(e,r){(e.props||(e.props={}))[r]=t}))(e,r)}}function z(t,e){void 0===e&&(e={});var r=e.deep,o=void 0!==r&&r,i=e.immediate,n=void 0!==i&&i;return j((function(e,r){"object"!=typeof e.watch&&(e.watch=Object.create(null));var i=e.watch;"object"!=typeof i[t]||Array.isArray(i[t])?void 0===i[t]&&(i[t]=[]):i[t]=[i[t]],i[t].push({handler:r,deep:o,immediate:n})}))}class W{constructor(t){this.registry=new Map,this.ctx=t}add(t,e){if(this.registry.has(t))return;this.registry.set(t,e);const r=f(this.ctx.initialValues,t),i=o(e.$options.propsData||{},"value");!i&&this.ctx.hasInitialValue&&void 0!==r?e.context.model=r:i&&!c(e.proxy,r)&&this.ctx.setFieldValueAndEmit(t,e.proxy)}remove(t){this.registry.delete(t);const e=this.ctx.proxy,r=t,o=(e[r],m(e,["symbol"==typeof r?r:r+""]));this.ctx.proxy=o}has(t){return this.registry.has(t)}hasNested(t){for(const e of this.registry.keys())if(e===t||e.includes(t+"."))return!0;return!1}get(t){return this.registry.get(t)}getNested(t){const e=new Map;for(const r of this.registry.keys()){const o=t+".",i=t+"[";r!==t&&r.substring(0,o.length)!==o&&r.substring(0,i.length)!==i||e.set(r,this.registry.get(r))}return e}forEach(t){this.registry.forEach((e,r)=>{t(e,r)})}keys(){return Array.from(this.registry.keys())}reduce(t,e){return this.registry.forEach((r,o)=>{e=t(e,r,o)}),e}}class Y{constructor(t=[]){this.observers=[],this.observers=t}add(t){this.observers.some(e=>e.callback===t.callback)||this.observers.push(t)}remove(t){this.observers=this.observers.filter(e=>e.callback!==t)}filter(t){return new Y(this.observers.filter(t))}some(t){return this.observers.some(t)}observe(t){this.observers.forEach(e=>{"form"===e.type?e.callback(t):e.field&&!Array.isArray(t)&&(o(t,e.field)?e.callback(t[e.field]):e.callback([]))})}}let q=class extends t{constructor(){super(...arguments),this.path="",this.proxy={},this.registry=new W(this),this.errorObserverRegistry=new Y,this.localFormErrors=[],this.localFieldErrors={}}get initialValues(){return this.hasModel&&"object"==typeof this.formularioValue?Object.assign({},this.formularioValue):{}}get mergedFormErrors(){return[...this.formErrors,...this.localFormErrors]}get mergedFieldErrors(){return i(this.errors||{},this.localFieldErrors)}get hasModel(){return o(this.$options.propsData||{},"formularioValue")}get hasInitialValue(){return this.formularioValue&&"object"==typeof this.formularioValue}onFormularioValueChanged(t){this.hasModel&&t&&"object"==typeof t&&this.setValues(t)}onMergedFormErrorsChanged(t){this.errorObserverRegistry.filter(t=>"form"===t.type).observe(t)}onMergedFieldErrorsChanged(t){this.errorObserverRegistry.filter(t=>"input"===t.type).observe(t)}created(){this.initProxy()}getFormValues(){return this.proxy}onFormSubmit(){return this.hasValidationErrors().then(t=>t?void 0:function t(e){if("object"!=typeof e)return e;const r=Array.isArray(e)?[]:{};for(const i in e)o(e,i)&&(u(e[i])?r[i]=e[i]:e instanceof Date?r[i]=new Date(r[i]):r[i]=t(e[i]));return r}(this.proxy)).then(t=>{void 0!==t?this.$emit("submit",t):this.$emit("error")})}onFormularioFieldValidation(t){this.$emit("validation",t)}addErrorObserver(t){this.errorObserverRegistry.add(t),"form"===t.type?t.callback(this.mergedFormErrors):t.field&&o(this.mergedFieldErrors,t.field)&&t.callback(this.mergedFieldErrors[t.field])}removeErrorObserver(t){this.errorObserverRegistry.remove(t)}register(t,e){this.registry.add(t,e)}deregister(t){this.registry.remove(t)}initProxy(){this.hasInitialValue&&(this.proxy=this.initialValues)}setValues(t){const e=Array.from(new Set([...Object.keys(t),...Object.keys(this.proxy)]));let r=!1;e.forEach(e=>{this.registry.hasNested(e)&&this.registry.getNested(e).forEach((e,o)=>{const i=this.registry.get(o),n=f(this.proxy,o),a=f(t,o);c(a,n)||(this.setFieldValue(o,a),r=!0),c(a,i.proxy)||(i.context.model=a)})}),this.initProxy(),r&&this.$emit("input",Object.assign({},this.proxy))}setFieldValue(t,e){if(void 0===e){const e=this.proxy,r=t,o=(e[r],m(e,["symbol"==typeof r?r:r+""]));this.proxy=o}else!function(t,e,r){const o=e.split(".");let i=t;for(let t=0;t(t.push(e.runValidation()&&e.hasValidationErrors()),t),[])).then(t=>t.some(t=>t))}resetValidation(){this.localFormErrors=[],this.localFieldErrors={},this.registry.forEach(t=>{t.resetValidation()})}};function Q(t,e,r,o,i,n,a,s,l,u){"boolean"!=typeof a&&(l=s,s=a,a=!1);const c="function"==typeof r?r.options:r;let d;if(t&&t.render&&(c.render=t.render,c.staticRenderFns=t.staticRenderFns,c._compiled=!0,i&&(c.functional=!0)),o&&(c._scopeId=o),n?(d=function(t){(t=t||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext)||"undefined"==typeof __VUE_SSR_CONTEXT__||(t=__VUE_SSR_CONTEXT__),e&&e.call(this,l(t)),t&&t._registeredComponents&&t._registeredComponents.add(n)},c._ssrRegister=d):e&&(d=a?function(t){e.call(this,u(t,this.$root.$options.shadowRoot))}:function(t){e.call(this,s(t))}),d)if(c.functional){const t=c.render;c.render=function(e,r){return d.call(r),t(e,r)}}else{const t=c.beforeCreate;c.beforeCreate=t?[].concat(t,d):[d]}return r}y([I("input",{default:()=>({})})],q.prototype,"formularioValue",void 0),y([T({default:()=>({})})],q.prototype,"errors",void 0),y([T({default:()=>[]})],q.prototype,"formErrors",void 0),y([S()],q.prototype,"path",void 0),y([z("formularioValue",{deep:!0})],q.prototype,"onFormularioValueChanged",null),y([z("mergedFormErrors")],q.prototype,"onMergedFormErrorsChanged",null),y([z("mergedFieldErrors",{deep:!0,immediate:!0})],q.prototype,"onMergedFieldErrorsChanged",null),y([S()],q.prototype,"getFormValues",null),y([S()],q.prototype,"onFormularioFieldValidation",null),y([S()],q.prototype,"addErrorObserver",null),y([S()],q.prototype,"removeErrorObserver",null),y([S("formularioRegister")],q.prototype,"register",null),y([S("formularioDeregister")],q.prototype,"deregister",null),y([S("formularioSetter")],q.prototype,"setFieldValueAndEmit",null),q=y([P({name:"FormularioForm"})],q);const U=q;var B=function(){var t=this,e=t.$createElement;return(t._self._c||e)("form",{on:{submit:function(e){return e.preventDefault(),t.onFormSubmit(e)}}},[t._t("default",null,{errors:t.mergedFormErrors})],2)};B._withStripped=!0;const G=Q({render:B,staticRenderFns:[]},void 0,U,void 0,!1,void 0,!1,void 0,void 0,void 0);let L=class extends t{get groupPath(){return this.isArrayItem?`${this.path}[${this.name}]`:""===this.path?this.name:`${this.path}.${this.name}`}};y([D({default:""})],L.prototype,"path",void 0),y([T({required:!0})],L.prototype,"name",void 0),y([T({default:!1})],L.prototype,"isArrayItem",void 0),y([S("path")],L.prototype,"groupPath",null),L=y([P({name:"FormularioGrouping"})],L);const Z=L;var K=function(){var t=this.$createElement;return(this._self._c||t)("div",[this._t("default")],2)};K._withStripped=!0;const X=Q({render:K,staticRenderFns:[]},void 0,Z,void 0,!1,void 0,!1,void 0,void 0,void 0);function H(t,e,r,o){return i=>Promise.resolve(t(i,...r)).then(t=>t?null:{rule:e,args:r,context:i,message:o(i,...r)})}function J(t){return/^[\^]/.test(t.charAt(0))?[d(t.substr(1)),t.charAt(0)]:[d(t),null]}function tt(t,e,r){return"function"==typeof t?[t,null,null]:Array.isArray(t)&&t.length?function(t,e,r){const i=t.slice(),n=i.shift();if("function"==typeof n)return[n,null,null];if("string"!=typeof n)throw new Error("[Formulario]: For array constraint first element must be rule name or Validator function");const[a,s]=J(n);if(o(e,a))return[H(e[a],a,i,r[a]||r.default),a,s];throw new Error("[Formulario] Can't create validator for constraint: "+JSON.stringify(t))}(t,e,r):"string"==typeof t?function(t,e,r){const i=t.split(":"),[n,a]=J(i.shift()||"");if(o(e,n))return[H(e[n],n,i.length?i.join(":").split(","):[],r[n]||r.default),n,a];throw new Error("[Formulario] Can't create validator for constraint: "+t)}(t,e,r):[()=>Promise.resolve(null),null,null]}function et(t){const e=[];if(t.length){let r=t.shift();e.push(r),t.forEach(t=>{t.bail||t.bail!==r.bail?(r=Object.assign({},t),e.push(r)):r.validators.push(...t.validators)})}return e}function rt(t,e){return new Promise(r=>{const o=(t,i=[])=>{if(t.length){const n=t.shift();(function(t,e){return Promise.all(t.validators.map(t=>t(e))).then(t=>t.filter(t=>null!==t))})(n,e).then(e=>0!==e.length&&n.bail||!t.length?r(i.concat(e)):o(t,i.concat(e)))}else r([])};o(function(t){const e=([t,,e])=>({validators:[t],bail:"^"===e}),r=[],o=t.findIndex(([,t])=>t&&"bail"===t.toLowerCase());return o>=0?(r.push(...et(t.splice(0,o+1).slice(0,-1).map(e))),r.push(...t.map(([t])=>({validators:[t],bail:!0})))):r.push(...et(t.map(e))),r}(t))})}const ot={DEMAND:"demand",LIVE:"live",SUBMIT:"submit"};let it=class extends t{constructor(){super(...arguments),this.proxy=this.getInitialValue(),this.localErrors=[],this.violations=[],this.validationRun=Promise.resolve()}get fullQualifiedName(){return""!==this.path?`${this.path}.${this.name}`:this.name}get model(){const t=this.hasModel?"value":"proxy";return this.modelGetConverter(this[t])}set model(t){c(t=this.modelSetConverter(t,this.proxy),this.proxy)||(this.proxy=t),this.$emit("input",t),"function"==typeof this.formularioSetter&&this.formularioSetter(this.context.name,t)}get context(){return Object.defineProperty({name:this.fullQualifiedName,runValidation:this.runValidation.bind(this),violations:this.violations,errors:this.localErrors,allErrors:[...this.localErrors,...this.violations.map(t=>t.message)]},"model",{get:()=>this.model,set:t=>{this.model=t}})}get normalizedValidationRules(){const t={};return Object.keys(this.validationRules).forEach(e=>{t[d(e)]=this.validationRules[e]}),t}get normalizedValidationMessages(){const t={};return Object.keys(this.validationMessages).forEach(e=>{t[d(e)]=this.validationMessages[e]}),t}get hasModel(){return o(this.$options.propsData||{},"value")}onProxyChanged(t,e){this.hasModel||c(t,e)||(this.context.model=t),this.validationBehavior===ot.LIVE?this.runValidation():this.violations=[]}onValueChanged(t,e){this.hasModel&&!c(t,e)&&(this.context.model=t)}created(){this.initProxy(),"function"==typeof this.formularioRegister&&this.formularioRegister(this.fullQualifiedName,this),"function"!=typeof this.addErrorObserver||this.errorsDisabled||this.addErrorObserver({callback:this.setErrors,type:"input",field:this.fullQualifiedName}),this.validationBehavior===ot.LIVE&&this.runValidation()}beforeDestroy(){this.errorsDisabled||"function"!=typeof this.removeErrorObserver||this.removeErrorObserver(this.setErrors),"function"==typeof this.formularioDeregister&&this.formularioDeregister(this.fullQualifiedName)}getInitialValue(){return o(this.$options.propsData||{},"value")?this.value:""}initProxy(){c(this.context.model,this.proxy)||(this.context.model=this.proxy)}runValidation(){return this.validationRun=this.validate().then(t=>{const e=!c(t,this.violations);if(this.violations=t,e){const t={name:this.context.name,violations:this.violations};this.$emit("validation",t),"function"==typeof this.onFormularioFieldValidation&&this.onFormularioFieldValidation(t)}return this.violations}),this.validationRun}validate(){return rt(function t(e,r,o){return"string"==typeof e?t(e.split("|").filter(t=>t.length),r,o):Array.isArray(e)?e.map(t=>tt(t,r,o)):[]}(this.validation,this.$formulario.getRules(this.normalizedValidationRules),this.$formulario.getMessages(this,this.normalizedValidationMessages)),{value:this.context.model,name:this.context.name,formValues:this.getFormValues()})}hasValidationErrors(){return new Promise(t=>{this.$nextTick(()=>{this.validationRun.then(()=>t(this.violations.length>0))})})}setErrors(t){var e;this.localErrors=(e=t)?"string"==typeof e?[e]:Array.isArray(e)?e:"object"==typeof e?Object.values(e):[]:[]}resetValidation(){this.localErrors=[],this.violations=[]}};y([D({default:void 0})],it.prototype,"formularioSetter",void 0),y([D({default:()=>()=>{}})],it.prototype,"onFormularioFieldValidation",void 0),y([D({default:void 0})],it.prototype,"formularioRegister",void 0),y([D({default:void 0})],it.prototype,"formularioDeregister",void 0),y([D({default:()=>()=>({})})],it.prototype,"getFormValues",void 0),y([D({default:void 0})],it.prototype,"addErrorObserver",void 0),y([D({default:void 0})],it.prototype,"removeErrorObserver",void 0),y([D({default:""})],it.prototype,"path",void 0),y([I("input",{default:""})],it.prototype,"value",void 0),y([T({required:!0,validator:t=>"string"==typeof t&&t.length>0})],it.prototype,"name",void 0),y([T({default:""})],it.prototype,"validation",void 0),y([T({default:()=>({})})],it.prototype,"validationRules",void 0),y([T({default:()=>({})})],it.prototype,"validationMessages",void 0),y([T({default:ot.DEMAND,validator:t=>Object.values(ot).includes(t)})],it.prototype,"validationBehavior",void 0),y([T({default:!1})],it.prototype,"errorsDisabled",void 0),y([T({default:()=>t=>t})],it.prototype,"modelGetConverter",void 0),y([T({default:()=>t=>t})],it.prototype,"modelSetConverter",void 0),y([z("proxy")],it.prototype,"onProxyChanged",null),y([z("value")],it.prototype,"onValueChanged",null),it=y([P({name:"FormularioInput",inheritAttrs:!1})],it);const nt=it;var at=function(){var t=this.$createElement;return(this._self._c||t)("div",{staticClass:"formulario-input"},[this._t("default",null,{context:this.context})],2)};at._withStripped=!0;const st=Q({render:at,staticRenderFns:[]},void 0,nt,void 0,!1,void 0,!1,void 0,void 0,void 0);return{install(t,e){t.component("FormularioForm",G),t.component("FormularioGrouping",X),t.component("FormularioInput",st),t.mixin({beforeCreate(){const t=this.$options;"function"==typeof t.formulario?this.$formulario=t.formulario():t.parent&&t.parent.$formulario?this.$formulario=t.parent.$formulario:this.$formulario=new v(e)}})}}}(Vue); + */function x(t){return(x="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function V(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}function P(t){return function(t){if(Array.isArray(t)){for(var e=0,r=new Array(t.length);e0&&T("Component class must inherit Vue or its descendant class when class property is used."),i}var B=["data","beforeCreate","created","beforeMount","mounted","beforeDestroy","destroyed","beforeUpdate","updated","activated","deactivated","render","errorCaptured","serverPrefetch"];function L(e){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};r.name=r.name||e._componentTag||e.name;var o=e.prototype;Object.getOwnPropertyNames(o).forEach((function(t){if("constructor"!==t)if(B.indexOf(t)>-1)r[t]=o[t];else{var e=Object.getOwnPropertyDescriptor(o,t);void 0!==e.value?"function"==typeof e.value?(r.methods||(r.methods={}))[t]=e.value:(r.mixins||(r.mixins=[])).push({data:function(){return V({},t,e.value)}}):(e.get||e.set)&&((r.computed||(r.computed={}))[t]={get:e.get,set:e.set})}})),(r.mixins||(r.mixins=[])).push({data:function(){return U(this,e)}});var n=e.__decorators__;n&&(n.forEach((function(t){return t(r)})),delete e.__decorators__);var i=Object.getPrototypeOf(e.prototype),a=i instanceof t?i.constructor:t,s=a.extend(r);return G(s,e,a),D()&&S(s,e),s}var k=["cid","super","options","superOptions","extendOptions","sealedOptions","component","directive","filter"],Y={prototype:!0,arguments:!0,callee:!0,caller:!0};function G(t,e,r){Object.getOwnPropertyNames(e).forEach((function(o){if(!Y[o]){var n=Object.getOwnPropertyDescriptor(t,o);if(!n||n.configurable){var i,a,s=Object.getOwnPropertyDescriptor(e,o);if(!M){if("cid"===o)return;var l=Object.getOwnPropertyDescriptor(r,o);if(i=s.value,a=x(i),null!=i&&("object"===a||"function"===a)&&l&&l.value===s.value)return}"production"!==process.env.NODE_ENV&&k.indexOf(o)>=0&&T("Static property name '".concat(o,"' declared on class '").concat(e.name,"' ")+"conflicts with reserved property name of Vue internal. It may cause unexpected behavior of the component. Consider renaming the property."),Object.defineProperty(t,o,s)}}}))}function z(t){return"function"==typeof t?L(t):function(e){return L(e,t)}}z.registerHooks=function(t){B.push.apply(B,P(t))};function W(t){return I((function(e,r){void 0===e.inject&&(e.inject={}),Array.isArray(e.inject)||(e.inject[r]=t||r)}))}function q(t){return I((function(e,r){var o,n=e.provide;("function"!=typeof(o=n)||!o.managed&&!o.managedReactive)&&(n=e.provide=function(t){var e=function(){var r=this,o="function"==typeof t?t.call(this):t;for(var n in(o=Object.create(o||null)).__reactiveInject__=this.__reactiveInject__||{},e.managed)o[e.managed[n]]=this[n];var i=function(t){o[e.managedReactive[t]]=a[t],Object.defineProperty(o.__reactiveInject__,e.managedReactive[t],{enumerable:!0,get:function(){return r[t]}})},a=this;for(var n in e.managedReactive)i(n);return o};return e.managed={},e.managedReactive={},e}(n)),n.managed[r]=t||r}))}var Z="undefined"!=typeof Reflect&&void 0!==Reflect.getMetadata;function K(t,e,r){if(Z&&!Array.isArray(t)&&"function"!=typeof t&&void 0===t.type){var o=Reflect.getMetadata("design:type",e,r);o!==Object&&(t.type=o)}}function X(t,e){return void 0===e&&(e={}),function(r,o){K(e,r,o),I((function(r,o){(r.props||(r.props={}))[o]=e,r.model={prop:o,event:t||o}}))(r,o)}}function H(t){return void 0===t&&(t={}),function(e,r){K(t,e,r),I((function(e,r){(e.props||(e.props={}))[r]=t}))(e,r)}}function J(t,e){void 0===e&&(e={});var r=e.deep,o=void 0!==r&&r,n=e.immediate,i=void 0!==n&&n;return I((function(e,r){"object"!=typeof e.watch&&(e.watch=Object.create(null));var n=e.watch;"object"!=typeof n[t]||Array.isArray(n[t])?void 0===n[t]&&(n[t]=[]):n[t]=[n[t]],n[t].push({handler:r,deep:o,immediate:i})}))}function Q(t,e,r,o){return n=>Promise.resolve(t(n,...r)).then((t=>t?null:{rule:e,args:r,context:n,message:o(n,...r)}))}function tt(t){return/^[\^]/.test(t.charAt(0))?[j(t.substr(1)),t.charAt(0)]:[j(t),null]}function et(t,e,r){return"function"==typeof t?[t,null,null]:Array.isArray(t)&&t.length?function(t,e,r){const n=t.slice(),i=n.shift();if("function"==typeof i)return[i,null,null];if("string"!=typeof i)throw new Error("[Formulario]: For array constraint first element must be rule name or Validator function");const[a,s]=tt(i);if(o(e,a))return[Q(e[a],a,n,r[a]||r.default),a,s];throw new Error("[Formulario] Can't create validator for constraint: "+JSON.stringify(t))}(t,e,r):"string"==typeof t?function(t,e,r){const n=t.split(":"),[i,a]=tt(n.shift()||"");if(o(e,i))return[Q(e[i],i,n.length?n.join(":").split(","):[],r[i]||r.default),i,a];throw new Error("[Formulario] Can't create validator for constraint: "+t)}(t,e,r):[()=>Promise.resolve(null),null,null]}function rt(t,e,r){return"string"==typeof t?rt(t.split("|").filter((t=>t.length)),e,r):Array.isArray(t)?t.map((t=>et(t,e,r))):[]}function ot(t){const e=[];if(t.length){let r=t.shift();e.push(r),t.forEach((t=>{t.bail||t.bail!==r.bail?(r=Object.assign({},t),e.push(r)):r.validators.push(...t.validators)}))}return e}function nt(t,e){return new Promise((r=>{const o=(t,n=[])=>{if(t.length){const i=t.shift();(function(t,e){return Promise.all(t.validators.map((t=>t(e)))).then((t=>t.filter((t=>null!==t))))})(i,e).then((e=>0!==e.length&&i.bail||!t.length?r(n.concat(e)):o(t,n.concat(e))))}else r([])};o(function(t){const e=([t,,e])=>({validators:[t],bail:"^"===e}),r=[],o=t.findIndex((([,t])=>t&&"bail"===t.toLowerCase()));return o>=0?(r.push(...ot(t.splice(0,o+1).slice(0,-1).map(e))),r.push(...t.map((([t])=>({validators:[t],bail:!0}))))):r.push(...ot(t.map(e))),r}(t))}))}const it={DEMAND:"demand",LIVE:"live",SUBMIT:"submit"};let at=class extends t{constructor(){super(...arguments),this.proxy=this.hasModel?this.value:"",this.localErrors=[],this.violations=[],this.validationRun=Promise.resolve([])}get fullPath(){return""!==this.__Formulario_path?`${this.__Formulario_path}.${this.name}`:this.name}get hasModel(){return o(this.$options.propsData||{},"value")}get context(){return Object.defineProperty({name:this.fullPath,path:this.fullPath,runValidation:this.runValidation.bind(this),violations:this.violations,errors:this.localErrors,allErrors:[...this.localErrors,...this.violations.map((t=>t.message))]},"model",{get:()=>this.modelGetConverter(this.proxy),set:t=>{this.syncProxy(this.modelSetConverter(t,this.proxy))}})}get normalizedValidationRules(){const t={};return Object.keys(this.validationRules).forEach((e=>{t[j(e)]=this.validationRules[e]})),t}get normalizedValidationMessages(){const t={};return Object.keys(this.validationMessages).forEach((e=>{t[j(e)]=this.validationMessages[e]})),t}onValueChange(){this.syncProxy(this.value)}onProxyChange(){this.validationBehavior===it.LIVE?this.runValidation():this.resetValidation()}created(){"function"==typeof this.__FormularioForm_register&&this.__FormularioForm_register(this.fullPath,this),this.validationBehavior===it.LIVE&&this.runValidation()}beforeDestroy(){"function"==typeof this.__FormularioForm_unregister&&this.__FormularioForm_unregister(this.fullPath)}syncProxy(t){E(t,this.proxy)||(this.proxy=t,this.$emit("input",t),"function"==typeof this.__FormularioForm_set&&(this.__FormularioForm_set(this.fullPath,t),this.__FormularioForm_emitInput()))}runValidation(){return this.validationRun=this.validate().then((t=>(this.violations=t,this.emitValidation(this.fullPath,t),this.violations))),this.validationRun}validate(){return nt(rt(this.validation,this.$formulario.getRules(this.normalizedValidationRules),this.$formulario.getMessages(this,this.normalizedValidationMessages)),{value:this.proxy,name:this.fullPath,formValues:this.__FormularioForm_getState()})}emitValidation(t,e){this.$emit("validation",{path:t,violations:e}),"function"==typeof this.__FormularioForm_emitValidation&&this.__FormularioForm_emitValidation(t,e)}hasValidationErrors(){return new Promise((t=>{this.$nextTick((()=>{this.validationRun.then((()=>t(this.violations.length>0)))}))}))}setErrors(t){this.errorsDisabled||(this.localErrors=t)}resetValidation(){this.localErrors=[],this.violations=[]}};function st(t,e,r,o,n,i,a,s,l,u){"boolean"!=typeof a&&(l=s,s=a,a=!1);const c="function"==typeof r?r.options:r;let f;if(t&&t.render&&(c.render=t.render,c.staticRenderFns=t.staticRenderFns,c._compiled=!0,n&&(c.functional=!0)),o&&(c._scopeId=o),i?(f=function(t){(t=t||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext)||"undefined"==typeof __VUE_SSR_CONTEXT__||(t=__VUE_SSR_CONTEXT__),e&&e.call(this,l(t)),t&&t._registeredComponents&&t._registeredComponents.add(i)},c._ssrRegister=f):e&&(f=a?function(t){e.call(this,u(t,this.$root.$options.shadowRoot))}:function(t){e.call(this,s(t))}),f)if(c.functional){const t=c.render;c.render=function(e,r){return f.call(r),t(e,r)}}else{const t=c.beforeCreate;c.beforeCreate=t?[].concat(t,f):[f]}return r}m([W({default:""})],at.prototype,"__Formulario_path",void 0),m([W({default:void 0})],at.prototype,"__FormularioForm_set",void 0),m([W({default:()=>()=>{}})],at.prototype,"__FormularioForm_emitInput",void 0),m([W({default:()=>()=>{}})],at.prototype,"__FormularioForm_emitValidation",void 0),m([W({default:void 0})],at.prototype,"__FormularioForm_register",void 0),m([W({default:void 0})],at.prototype,"__FormularioForm_unregister",void 0),m([W({default:()=>()=>({})})],at.prototype,"__FormularioForm_getState",void 0),m([X("input",{default:""})],at.prototype,"value",void 0),m([H({required:!0,validator:t=>"string"==typeof t&&t.length>0})],at.prototype,"name",void 0),m([H({default:""})],at.prototype,"validation",void 0),m([H({default:()=>({})})],at.prototype,"validationRules",void 0),m([H({default:()=>({})})],at.prototype,"validationMessages",void 0),m([H({default:it.DEMAND,validator:t=>Object.values(it).includes(t)})],at.prototype,"validationBehavior",void 0),m([H({default:!1})],at.prototype,"errorsDisabled",void 0),m([H({default:()=>t=>t})],at.prototype,"modelGetConverter",void 0),m([H({default:()=>t=>t})],at.prototype,"modelSetConverter",void 0),m([J("value")],at.prototype,"onValueChange",null),m([J("proxy")],at.prototype,"onProxyChange",null),at=m([z({name:"FormularioField",inheritAttrs:!1})],at);const lt=at;var ut=function(){var t=this,e=t.$createElement;return(t._self._c||e)("div",t._b({},"div",t.$attrs,!1),[t._t("default",null,{context:t.context})],2)};ut._withStripped=!0;const ct=st({render:ut,staticRenderFns:[]},undefined,lt,undefined,false,undefined,!1,void 0,void 0,void 0);let ft=class extends t{get fullPath(){const t=""+this.name;return parseInt(t).toString()===t?`${this.__Formulario_path}[${t}]`:""===this.__Formulario_path?t:`${this.__Formulario_path}.${t}`}};m([W({default:""})],ft.prototype,"__Formulario_path",void 0),m([H({required:!0})],ft.prototype,"name",void 0),m([q("__Formulario_path")],ft.prototype,"fullPath",null),ft=m([z({name:"FormularioFieldGroup"})],ft);const dt=ft;var pt=function(){var t=this,e=t.$createElement;return(t._self._c||e)("div",[t._t("default")],2)};pt._withStripped=!0;const ht=st({render:pt,staticRenderFns:[]},undefined,dt,undefined,false,undefined,!1,void 0,void 0,void 0),mt=(t,e,r)=>void 0===r?O(t,e):_(t,e,r);let yt=class extends t{constructor(){super(...arguments),this.proxy={},this.registry=new Map,this.localFieldsErrors={},this.localFormErrors=[]}get fieldsErrorsComputed(){return n(this.fieldsErrors||{},this.localFieldsErrors)}get formErrorsComputed(){return[...this.formErrors,...this.localFormErrors]}register(t,e){this.registry.has(t)||this.registry.set(t,e);const r=g(this.proxy,t);e.hasModel?E(e.proxy,r)||(this.setFieldValue(t,e.proxy),this.emitInput()):void 0!==r?e.proxy=r:(this.setFieldValue(t,null),this.emitInput()),o(this.fieldsErrorsComputed,t)&&e.setErrors(this.fieldsErrorsComputed[t])}unregister(t){this.registry.has(t)&&(this.registry.delete(t),this.proxy=O(this.proxy,t),this.emitInput())}getState(){return this.proxy}setFieldValue(t,e){this.proxy=mt(this.proxy,t,e)}emitInput(){this.$emit("input",h(this.proxy))}emitValidation(t,e){this.$emit("validation",{path:t,violations:e})}onStateChange(t){const e=h(t),r=this.proxy;let o=!1;this.registry.forEach(((n,i)=>{const a=g(t,i,null),s=g(r,i,null);n.proxy=a,E(a,s)||(n.$emit("input",a),mt(e,i,a),o=!0)})),this.proxy=e,o&&this.emitInput()}onFieldsErrorsChange(t){this.registry.forEach(((e,r)=>{e.setErrors(t[r]||[])}))}created(){this.$formulario.register(this.id,this),"object"==typeof this.state&&(this.proxy=h(this.state))}beforeDestroy(){this.$formulario.unregister(this.id)}runValidation(){const t=[],e={};return this.registry.forEach(((r,o)=>{t.push(r.runValidation().then((t=>{e[o]=t})))})),Promise.all(t).then((()=>e))}hasValidationErrors(){return this.runValidation().then((t=>Object.keys(t).some((e=>t[e].length>0))))}setErrors({fieldsErrors:t,formErrors:e}){this.localFieldsErrors=t||{},this.localFormErrors=e||[]}resetValidation(){this.localFieldsErrors={},this.localFormErrors=[],this.registry.forEach((t=>{t.resetValidation()}))}onSubmit(){return this.runValidation().then((t=>{Object.keys(t).some((e=>t[e].length>0))?this.$emit("error",t):this.$emit("submit",h(this.proxy))}))}};m([X("input",{default:()=>({})})],yt.prototype,"state",void 0),m([H({default:()=>(t=>{const e=(u.get(t)||0)+1;return u.set(t,e),`${t}-${e}`})("formulario-form")})],yt.prototype,"id",void 0),m([H({default:()=>({})})],yt.prototype,"fieldsErrors",void 0),m([H({default:()=>[]})],yt.prototype,"formErrors",void 0),m([q("__FormularioForm_register")],yt.prototype,"register",null),m([q("__FormularioForm_unregister")],yt.prototype,"unregister",null),m([q("__FormularioForm_getState")],yt.prototype,"getState",null),m([q("__FormularioForm_set")],yt.prototype,"setFieldValue",null),m([q("__FormularioForm_emitInput")],yt.prototype,"emitInput",null),m([q("__FormularioForm_emitValidation")],yt.prototype,"emitValidation",null),m([J("state",{deep:!0})],yt.prototype,"onStateChange",null),m([J("fieldsErrorsComputed",{deep:!0,immediate:!0})],yt.prototype,"onFieldsErrorsChange",null),yt=m([z({name:"FormularioForm"})],yt);const vt=yt;var gt=function(){var t=this,e=t.$createElement;return(t._self._c||e)("form",{on:{submit:function(e){return e.preventDefault(),t.onSubmit(e)}}},[t._t("default",null,{errors:t.formErrorsComputed})],2)};gt._withStripped=!0;const _t=st({render:gt,staticRenderFns:[]},undefined,vt,undefined,false,undefined,!1,void 0,void 0,void 0);return{Formulario:A,install(t,e){t.component("FormularioField",ct),t.component("FormularioFieldGroup",ht),t.component("FormularioForm",_t),t.component("FormularioInput",ct),t.component("FormularioGrouping",ht),t.mixin({beforeCreate(){const t=this.$options;"function"==typeof t.formulario?this.$formulario=t.formulario():t.parent&&t.parent.$formulario?this.$formulario=t.parent.$formulario:this.$formulario=new A(e)}})}}}(Vue); diff --git a/dist/formulario.umd.js b/dist/formulario.umd.js index eea3c0d..ff5a127 100644 --- a/dist/formulario.umd.js +++ b/dist/formulario.umd.js @@ -49,63 +49,222 @@ return merged; } - /** - * Converts to array. - * If given parameter is not string, object ot array, result will be an empty array. - * @param {*} item - */ - function arrayify(item) { - if (!item) { - return []; - } - if (typeof item === 'string') { - return [item]; - } - if (Array.isArray(item)) { - return item; - } - if (typeof item === 'object') { - return Object.values(item); - } - return []; - } + const registry = new Map(); + var id = (prefix) => { + const current = registry.get(prefix) || 0; + const next = current + 1; + registry.set(prefix, next); + return `${prefix}-${next}`; + }; - function isScalar(data) { - switch (typeof data) { + var TYPE; + (function (TYPE) { + TYPE["ARRAY"] = "ARRAY"; + TYPE["BIGINT"] = "BIGINT"; + TYPE["BOOLEAN"] = "BOOLEAN"; + TYPE["DATE"] = "DATE"; + TYPE["FUNCTION"] = "FUNCTION"; + TYPE["NUMBER"] = "NUMBER"; + TYPE["RECORD"] = "RECORD"; + TYPE["STRING"] = "STRING"; + TYPE["SYMBOL"] = "SYMBOL"; + TYPE["UNDEFINED"] = "UNDEFINED"; + TYPE["NULL"] = "NULL"; + })(TYPE || (TYPE = {})); + function typeOf(value) { + switch (typeof value) { + case 'bigint': + return TYPE.BIGINT; + case 'boolean': + return TYPE.BOOLEAN; + case 'function': + return TYPE.FUNCTION; + case 'number': + return TYPE.NUMBER; + case 'string': + return TYPE.STRING; case 'symbol': + return TYPE.SYMBOL; + case 'undefined': + return TYPE.UNDEFINED; + case 'object': + if (value === null) { + return TYPE.NULL; + } + if (value instanceof Date) { + return TYPE.DATE; + } + if (Array.isArray(value)) { + return TYPE.ARRAY; + } + if (value.constructor.name === 'Object') { + return TYPE.RECORD; + } + return 'InstanceOf<' + value.constructor.name + '>'; + } + throw new Error(); + } + function isRecordLike(value) { + return typeof value === 'object' && value !== null && ['Array', 'Object'].includes(value.constructor.name); + } + function isScalar(value) { + switch (typeof value) { + case 'bigint': + case 'boolean': case 'number': case 'string': - case 'boolean': + case 'symbol': case 'undefined': return true; default: - return data === null; + return value === null; } } + const cloneInstance = (original) => { + return Object.assign(Object.create(Object.getPrototypeOf(original)), original); + }; /** * A simple (somewhat non-comprehensive) clone function, valid for our use * case of needing to unbind reactive watchers. */ function clone(value) { - if (typeof value !== 'object') { + if (isScalar(value)) { return value; } - const copy = Array.isArray(value) ? [] : {}; - for (const key in value) { - if (has(value, key)) { - if (isScalar(value[key])) { - copy[key] = value[key]; - } - else if (value instanceof Date) { - copy[key] = new Date(copy[key]); - } - else { - copy[key] = clone(value[key]); - } - } + if (value instanceof Date) { + return new Date(value); } + if (!isRecordLike(value)) { + return cloneInstance(value); + } + if (Array.isArray(value)) { + return value.slice().map(clone); + } + const source = value; + return Object.keys(source).reduce((copy, key) => (Object.assign(Object.assign({}, copy), { [key]: clone(source[key]) })), {}); + } + + /*! ***************************************************************************** + Copyright (c) Microsoft Corporation. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + PERFORMANCE OF THIS SOFTWARE. + ***************************************************************************** */ + + function __rest(s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { + if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) + t[p[i]] = s[p[i]]; + } + return t; + } + + function __decorate(decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; + } + + const extractIntOrNaN = (value) => { + const numeric = parseInt(value); + return numeric.toString() === value ? numeric : NaN; + }; + const extractPath = (raw) => { + const path = []; + raw.split('.').forEach(key => { + if (/(.*)\[(\d+)]$/.test(key)) { + path.push(...key.substr(0, key.length - 1).split('[').filter(k => k.length)); + } + else { + path.push(key); + } + }); + return path; + }; + function get(state, rawOrPath, fallback = undefined) { + const path = typeof rawOrPath === 'string' ? extractPath(rawOrPath) : rawOrPath; + if (isScalar(state) || path.length === 0) { + return fallback; + } + const key = path.shift(); + const index = extractIntOrNaN(key); + if (!isNaN(index)) { + if (Array.isArray(state) && index >= 0 && index < state.length) { + return path.length === 0 ? state[index] : get(state[index], path, fallback); + } + return undefined; + } + if (has(state, key)) { + const values = state; + return path.length === 0 ? values[key] : get(values[key], path, fallback); + } + return undefined; + } + function set(state, rawOrPath, value) { + const path = typeof rawOrPath === 'string' ? extractPath(rawOrPath) : rawOrPath; + if (path.length === 0) { + return value; + } + const key = path.shift(); + const index = extractIntOrNaN(key); + if (!isRecordLike(state)) { + return set(!isNaN(index) ? [] : {}, [key, ...path], value); + } + if (!isNaN(index) && Array.isArray(state)) { + const slice = [...state]; + slice[index] = path.length === 0 ? value : set(slice[index], path, value); + return slice; + } + const slice = Object.assign({}, state); + slice[key] = path.length === 0 ? value : set(slice[key], path, value); + return slice; + } + const unsetInRecord = (record, prop) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const _a = record, _b = prop, _ = _a[_b], copy = __rest(_a, [typeof _b === "symbol" ? _b : _b + ""]); return copy; + }; + function unset(state, rawOrPath) { + if (!isRecordLike(state)) { + return state; + } + const path = typeof rawOrPath === 'string' ? extractPath(rawOrPath) : rawOrPath; + if (path.length === 0) { + return state; + } + const key = path.shift(); + const index = extractIntOrNaN(key); + if (!isNaN(index) && Array.isArray(state) && index >= 0 && index < state.length) { + const slice = [...state]; + if (path.length === 0) { + slice.splice(index, 1); + } + else { + slice[index] = unset(slice[index], path); + } + return slice; + } + if (has(state, key)) { + const slice = Object.assign({}, state); + return path.length === 0 + ? unsetInRecord(slice, key) + : Object.assign(Object.assign({}, slice), { [key]: unset(slice[key], path) }); + } + return state; } /** @@ -132,31 +291,47 @@ }, escaped)); } - function shallowEqualObjects(objA, objB) { - if (objA === objB) { - return true; - } - if (!objA || !objB) { + function datesEquals(a, b) { + return a.getTime() === b.getTime(); + } + function arraysEquals(a, b, predicate) { + if (a.length !== b.length) { return false; } - const aKeys = Object.keys(objA); - const bKeys = Object.keys(objB); - if (bKeys.length !== aKeys.length) { - return false; - } - if (objA instanceof Date && objB instanceof Date) { - return objA.getTime() === objB.getTime(); - } - if (aKeys.length === 0) { - return objA === objB; - } - for (let i = 0; i < aKeys.length; i++) { - const key = aKeys[i]; - if (objA[key] !== objB[key]) { + for (let i = 0; i < a.length; i++) { + if (!predicate(a[i], b[i])) { return false; } } return true; + } + function recordsEquals(a, b, predicate) { + if (Object.keys(a).length !== Object.keys(b).length) { + return false; + } + for (const prop in a) { + if (!has(b, prop) || !predicate(a[prop], b[prop])) { + return false; + } + } + return true; + } + function strictEquals(a, b) { + return a === b; + } + function equals(a, b, predicate) { + const typeOfA = typeOf(a); + const typeOfB = typeOf(b); + return typeOfA === typeOfB && ((typeOfA === TYPE.ARRAY && arraysEquals(a, b, predicate)) || + (typeOfA === TYPE.DATE && datesEquals(a, b)) || + (typeOfA === TYPE.RECORD && recordsEquals(a, b, predicate)) || + (typeOfA.includes('InstanceOf') && equals(Object.entries(a), Object.entries(b), predicate))); + } + function deepEquals(a, b) { + return a === b || equals(a, b, deepEquals); + } + function shallowEquals(a, b) { + return a === b || equals(a, b, strictEquals); } /** @@ -171,65 +346,6 @@ }); } - function getNested(obj, field) { - const fieldParts = field.split('.'); - let result = obj; - for (const key in fieldParts) { - const matches = fieldParts[key].match(/(.+)\[(\d+)\]$/); - if (result === undefined) { - return null; - } - if (matches) { - result = result[matches[1]]; - if (result === undefined) { - return null; - } - result = result[matches[2]]; - } - else { - result = result[fieldParts[key]]; - } - } - return result; - } - function setNested(obj, field, value) { - const fieldParts = field.split('.'); - let subProxy = obj; - for (let i = 0; i < fieldParts.length; i++) { - const fieldPart = fieldParts[i]; - const matches = fieldPart.match(/(.+)\[(\d+)\]$/); - if (subProxy === undefined) { - break; - } - if (matches) { - if (subProxy[matches[1]] === undefined) { - subProxy[matches[1]] = []; - } - subProxy = subProxy[matches[1]]; - if (i === fieldParts.length - 1) { - subProxy[matches[2]] = value; - break; - } - else { - subProxy = subProxy[matches[2]]; - } - } - else { - if (i === fieldParts.length - 1) { - subProxy[fieldPart] = value; - break; - } - else { - // eslint-disable-next-line max-depth - if (subProxy[fieldPart] === undefined) { - subProxy[fieldPart] = {}; - } - subProxy = subProxy[fieldPart]; - } - } - } - } - const rules = { /** * Rule: the value must be "yes", "on", "1", or true @@ -335,7 +451,7 @@ * Rule: Value is in an array (stack). */ in({ value }, ...stack) { - return stack.some(item => typeof item === 'object' ? shallowEqualObjects(item, value) : item === value); + return stack.some(item => shallowEquals(item, value)); }, /** * Rule: Match the value against a (stack) of patterns or strings @@ -391,7 +507,7 @@ * Rule: Value is not in stack. */ not({ value }, ...stack) { - return !stack.some(item => typeof item === 'object' ? shallowEqualObjects(item, value) : item === value); + return !stack.some(item => shallowEquals(item, value)); }, /** * Rule: checks if the value is only alpha numeric @@ -433,6 +549,9 @@ * Rule: checks if a string is a valid url */ url({ value }) { + if (!value) { + return true; + } return isUrl(value); }, /** @@ -549,6 +668,7 @@ constructor(options) { this.validationRules = {}; this.validationMessages = {}; + this.registry = new Map(); this.validationRules = rules; this.validationMessages = messages; this.extend(options || {}); @@ -562,16 +682,51 @@ this.validationMessages = merge(this.validationMessages, extendWith.validationMessages || {}); return this; } - throw new Error(`[Formulario]: Formulario.extend() should be passed an object (was ${typeof extendWith})`); + throw new Error(`[Formulario]: Formulario.extend(): should be passed an object (was ${typeof extendWith})`); + } + runValidation(id) { + if (!this.registry.has(id)) { + throw new Error(`[Formulario]: Formulario.runValidation(): no forms with id "${id}"`); + } + const form = this.registry.get(id); + return form.runValidation(); + } + resetValidation(id) { + if (!this.registry.has(id)) { + return; + } + const form = this.registry.get(id); + form.resetValidation(); + } + /** + * Used by forms instances to add themselves into a registry + * @internal + */ + register(id, form) { + if (this.registry.has(id)) { + throw new Error(`[Formulario]: Formulario.register(): id "${id}" is already in use`); + } + this.registry.set(id, form); + } + /** + * Used by forms instances to remove themselves from a registry + * @internal + */ + unregister(id) { + if (this.registry.has(id)) { + this.registry.delete(id); + } } /** * Get validation rules by merging any passed in with global rules. + * @internal */ getRules(extendWith = {}) { return merge(this.validationRules, extendWith); } /** * Get validation messages by merging any passed in with global messages. + * @internal */ getMessages(vm, extendWith) { const raw = merge(this.validationMessages || {}, extendWith); @@ -585,583 +740,6 @@ } } - /*! ***************************************************************************** - Copyright (c) Microsoft Corporation. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - PERFORMANCE OF THIS SOFTWARE. - ***************************************************************************** */ - - function __rest(s, e) { - var t = {}; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) - t[p] = s[p]; - if (s != null && typeof Object.getOwnPropertySymbols === "function") - for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { - if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) - t[p[i]] = s[p[i]]; - } - return t; - } - - function __decorate(decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; - return c > 3 && r && Object.defineProperty(target, key, r), r; - } - - /** - * Component registry with inherent depth to handle complex nesting. This is - * important for features such as grouped fields. - */ - class Registry { - /** - * Create a new registry of components. - * @param {FormularioForm} ctx The host vm context of the registry. - */ - constructor(ctx) { - this.registry = new Map(); - this.ctx = ctx; - } - /** - * Fully register a component. - * @param {string} field name of the field. - * @param {FormularioForm} component the actual component instance. - */ - add(field, component) { - if (this.registry.has(field)) { - return; - } - this.registry.set(field, component); - // @ts-ignore - const value = getNested(this.ctx.initialValues, field); - const hasModel = has(component.$options.propsData || {}, 'value'); - // @ts-ignore - if (!hasModel && this.ctx.hasInitialValue && value !== undefined) { - // In the case that the form is carrying an initial value and the - // element is not, set it directly. - // @ts-ignore - component.context.model = value; - // @ts-ignore - } - else if (hasModel && !shallowEqualObjects(component.proxy, value)) { - // In this case, the field is v-modeled or has an initial value and the - // form has no value or a different value, so use the field value - // @ts-ignore - this.ctx.setFieldValueAndEmit(field, component.proxy); - } - } - /** - * Remove an item from the registry. - */ - remove(name) { - this.registry.delete(name); - // @ts-ignore - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const _a = this.ctx.proxy, _b = name, value = _a[_b], newProxy = __rest(_a, [typeof _b === "symbol" ? _b : _b + ""]); - // @ts-ignore - this.ctx.proxy = newProxy; - } - /** - * Check if the registry has the given key. - */ - has(key) { - return this.registry.has(key); - } - /** - * Check if the registry has elements, that equals or nested given key - */ - hasNested(key) { - for (const i of this.registry.keys()) { - if (i === key || i.includes(key + '.')) { - return true; - } - } - return false; - } - /** - * Get a particular registry value. - */ - get(key) { - return this.registry.get(key); - } - /** - * Get registry value for key or nested to given key - */ - getNested(key) { - const result = new Map(); - for (const i of this.registry.keys()) { - const objectKey = key + '.'; - const arrayKey = key + '['; - if (i === key || - i.substring(0, objectKey.length) === objectKey || - i.substring(0, arrayKey.length) === arrayKey) { - result.set(i, this.registry.get(i)); - } - } - return result; - } - /** - * Map over the registry (recursively). - */ - forEach(callback) { - this.registry.forEach((component, field) => { - callback(component, field); - }); - } - /** - * Return the keys of the registry. - */ - keys() { - return Array.from(this.registry.keys()); - } - /** - * Reduce the registry. - * @param {function} callback - * @param accumulator - */ - reduce(callback, accumulator) { - this.registry.forEach((component, field) => { - accumulator = callback(accumulator, component, field); - }); - return accumulator; - } - } - - class ErrorObserverRegistry { - constructor(observers = []) { - this.observers = []; - this.observers = observers; - } - add(observer) { - if (!this.observers.some(o => o.callback === observer.callback)) { - this.observers.push(observer); - } - } - remove(handler) { - this.observers = this.observers.filter(o => o.callback !== handler); - } - filter(predicate) { - return new ErrorObserverRegistry(this.observers.filter(predicate)); - } - some(predicate) { - return this.observers.some(predicate); - } - observe(errors) { - this.observers.forEach(observer => { - if (observer.type === 'form') { - observer.callback(errors); - } - else if (observer.field && - !Array.isArray(errors)) { - if (has(errors, observer.field)) { - observer.callback(errors[observer.field]); - } - else { - observer.callback([]); - } - } - }); - } - } - - let FormularioForm = class FormularioForm extends Vue { - constructor() { - super(...arguments); - this.path = ''; - this.proxy = {}; - this.registry = new Registry(this); - this.errorObserverRegistry = new ErrorObserverRegistry(); - // Local error messages are temporal, they wiped each resetValidation call - this.localFormErrors = []; - this.localFieldErrors = {}; - } - get initialValues() { - if (this.hasModel && typeof this.formularioValue === 'object') { - // If there is a v-model on the form/group, use those values as first priority - return Object.assign({}, this.formularioValue); // @todo - use a deep clone to detach reference types - } - return {}; - } - get mergedFormErrors() { - return [...this.formErrors, ...this.localFormErrors]; - } - get mergedFieldErrors() { - return merge(this.errors || {}, this.localFieldErrors); - } - get hasModel() { - return has(this.$options.propsData || {}, 'formularioValue'); - } - get hasInitialValue() { - return this.formularioValue && typeof this.formularioValue === 'object'; - } - onFormularioValueChanged(values) { - if (this.hasModel && values && typeof values === 'object') { - this.setValues(values); - } - } - onMergedFormErrorsChanged(errors) { - this.errorObserverRegistry.filter(o => o.type === 'form').observe(errors); - } - onMergedFieldErrorsChanged(errors) { - this.errorObserverRegistry.filter(o => o.type === 'input').observe(errors); - } - created() { - this.initProxy(); - } - getFormValues() { - return this.proxy; - } - onFormSubmit() { - return this.hasValidationErrors() - .then(hasErrors => hasErrors ? undefined : clone(this.proxy)) - .then(data => { - if (typeof data !== 'undefined') { - this.$emit('submit', data); - } - else { - this.$emit('error'); - } - }); - } - onFormularioFieldValidation(payload) { - this.$emit('validation', payload); - } - addErrorObserver(observer) { - this.errorObserverRegistry.add(observer); - if (observer.type === 'form') { - observer.callback(this.mergedFormErrors); - } - else if (observer.field && has(this.mergedFieldErrors, observer.field)) { - observer.callback(this.mergedFieldErrors[observer.field]); - } - } - removeErrorObserver(observer) { - this.errorObserverRegistry.remove(observer); - } - register(field, component) { - this.registry.add(field, component); - } - deregister(field) { - this.registry.remove(field); - } - initProxy() { - if (this.hasInitialValue) { - this.proxy = this.initialValues; - } - } - setValues(values) { - const keys = Array.from(new Set([...Object.keys(values), ...Object.keys(this.proxy)])); - let proxyHasChanges = false; - keys.forEach(field => { - if (!this.registry.hasNested(field)) { - return; - } - this.registry.getNested(field).forEach((registryField, registryKey) => { - const $input = this.registry.get(registryKey); - const oldValue = getNested(this.proxy, registryKey); - const newValue = getNested(values, registryKey); - if (!shallowEqualObjects(newValue, oldValue)) { - this.setFieldValue(registryKey, newValue); - proxyHasChanges = true; - } - if (!shallowEqualObjects(newValue, $input.proxy)) { - $input.context.model = newValue; - } - }); - }); - this.initProxy(); - if (proxyHasChanges) { - this.$emit('input', Object.assign({}, this.proxy)); - } - } - setFieldValue(field, value) { - if (value === undefined) { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const _a = this.proxy, _b = field, value = _a[_b], proxy = __rest(_a, [typeof _b === "symbol" ? _b : _b + ""]); - this.proxy = proxy; - } - else { - setNested(this.proxy, field, value); - } - } - setFieldValueAndEmit(field, value) { - this.setFieldValue(field, value); - this.$emit('input', Object.assign({}, this.proxy)); - } - setErrors({ formErrors, inputErrors }) { - this.localFormErrors = formErrors || []; - this.localFieldErrors = inputErrors || {}; - } - hasValidationErrors() { - return Promise.all(this.registry.reduce((resolvers, input) => { - resolvers.push(input.runValidation() && input.hasValidationErrors()); - return resolvers; - }, [])).then(results => results.some(hasErrors => hasErrors)); - } - resetValidation() { - this.localFormErrors = []; - this.localFieldErrors = {}; - this.registry.forEach((input) => { - input.resetValidation(); - }); - } - }; - __decorate([ - vuePropertyDecorator.Model('input', { default: () => ({}) }) - ], FormularioForm.prototype, "formularioValue", void 0); - __decorate([ - vuePropertyDecorator.Prop({ default: () => ({}) }) - ], FormularioForm.prototype, "errors", void 0); - __decorate([ - vuePropertyDecorator.Prop({ default: () => ([]) }) - ], FormularioForm.prototype, "formErrors", void 0); - __decorate([ - vuePropertyDecorator.Provide() - ], FormularioForm.prototype, "path", void 0); - __decorate([ - vuePropertyDecorator.Watch('formularioValue', { deep: true }) - ], FormularioForm.prototype, "onFormularioValueChanged", null); - __decorate([ - vuePropertyDecorator.Watch('mergedFormErrors') - ], FormularioForm.prototype, "onMergedFormErrorsChanged", null); - __decorate([ - vuePropertyDecorator.Watch('mergedFieldErrors', { deep: true, immediate: true }) - ], FormularioForm.prototype, "onMergedFieldErrorsChanged", null); - __decorate([ - vuePropertyDecorator.Provide() - ], FormularioForm.prototype, "getFormValues", null); - __decorate([ - vuePropertyDecorator.Provide() - ], FormularioForm.prototype, "onFormularioFieldValidation", null); - __decorate([ - vuePropertyDecorator.Provide() - ], FormularioForm.prototype, "addErrorObserver", null); - __decorate([ - vuePropertyDecorator.Provide() - ], FormularioForm.prototype, "removeErrorObserver", null); - __decorate([ - vuePropertyDecorator.Provide('formularioRegister') - ], FormularioForm.prototype, "register", null); - __decorate([ - vuePropertyDecorator.Provide('formularioDeregister') - ], FormularioForm.prototype, "deregister", null); - __decorate([ - vuePropertyDecorator.Provide('formularioSetter') - ], FormularioForm.prototype, "setFieldValueAndEmit", null); - FormularioForm = __decorate([ - vuePropertyDecorator.Component({ name: 'FormularioForm' }) - ], FormularioForm); - var script = FormularioForm; - - function normalizeComponent(template, style, script, scopeId, isFunctionalTemplate, moduleIdentifier /* server only */, shadowMode, createInjector, createInjectorSSR, createInjectorShadow) { - if (typeof shadowMode !== 'boolean') { - createInjectorSSR = createInjector; - createInjector = shadowMode; - shadowMode = false; - } - // Vue.extend constructor export interop. - const options = typeof script === 'function' ? script.options : script; - // render functions - if (template && template.render) { - options.render = template.render; - options.staticRenderFns = template.staticRenderFns; - options._compiled = true; - // functional template - if (isFunctionalTemplate) { - options.functional = true; - } - } - // scopedId - if (scopeId) { - options._scopeId = scopeId; - } - let hook; - if (moduleIdentifier) { - // server build - hook = function (context) { - // 2.3 injection - context = - context || // cached call - (this.$vnode && this.$vnode.ssrContext) || // stateful - (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext); // functional - // 2.2 with runInNewContext: true - if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') { - context = __VUE_SSR_CONTEXT__; - } - // inject component styles - if (style) { - style.call(this, createInjectorSSR(context)); - } - // register component module identifier for async chunk inference - if (context && context._registeredComponents) { - context._registeredComponents.add(moduleIdentifier); - } - }; - // used by ssr in case component is cached and beforeCreate - // never gets called - options._ssrRegister = hook; - } - else if (style) { - hook = shadowMode - ? function (context) { - style.call(this, createInjectorShadow(context, this.$root.$options.shadowRoot)); - } - : function (context) { - style.call(this, createInjector(context)); - }; - } - if (hook) { - if (options.functional) { - // register for functional component in vue file - const originalRender = options.render; - options.render = function renderWithStyleInjection(h, context) { - hook.call(context); - return originalRender(h, context); - }; - } - else { - // inject component registration as beforeCreate hook - const existing = options.beforeCreate; - options.beforeCreate = existing ? [].concat(existing, hook) : [hook]; - } - } - return script; - } - - /* script */ - const __vue_script__ = script; - - /* template */ - var __vue_render__ = function() { - var _vm = this; - var _h = _vm.$createElement; - var _c = _vm._self._c || _h; - return _c( - "form", - { - on: { - submit: function($event) { - $event.preventDefault(); - return _vm.onFormSubmit($event) - } - } - }, - [_vm._t("default", null, { errors: _vm.mergedFormErrors })], - 2 - ) - }; - var __vue_staticRenderFns__ = []; - __vue_render__._withStripped = true; - - /* style */ - const __vue_inject_styles__ = undefined; - /* scoped */ - const __vue_scope_id__ = undefined; - /* module identifier */ - const __vue_module_identifier__ = undefined; - /* functional template */ - const __vue_is_functional_template__ = false; - /* style inject */ - - /* style inject SSR */ - - /* style inject shadow dom */ - - - - const __vue_component__ = /*#__PURE__*/normalizeComponent( - { render: __vue_render__, staticRenderFns: __vue_staticRenderFns__ }, - __vue_inject_styles__, - __vue_script__, - __vue_scope_id__, - __vue_is_functional_template__, - __vue_module_identifier__, - false, - undefined, - undefined, - undefined - ); - - let FormularioGrouping = class FormularioGrouping extends Vue { - get groupPath() { - if (this.isArrayItem) { - return `${this.path}[${this.name}]`; - } - if (this.path === '') { - return this.name; - } - return `${this.path}.${this.name}`; - } - }; - __decorate([ - vuePropertyDecorator.Inject({ default: '' }) - ], FormularioGrouping.prototype, "path", void 0); - __decorate([ - vuePropertyDecorator.Prop({ required: true }) - ], FormularioGrouping.prototype, "name", void 0); - __decorate([ - vuePropertyDecorator.Prop({ default: false }) - ], FormularioGrouping.prototype, "isArrayItem", void 0); - __decorate([ - vuePropertyDecorator.Provide('path') - ], FormularioGrouping.prototype, "groupPath", null); - FormularioGrouping = __decorate([ - vuePropertyDecorator.Component({ name: 'FormularioGrouping' }) - ], FormularioGrouping); - var script$1 = FormularioGrouping; - - /* script */ - const __vue_script__$1 = script$1; - - /* template */ - var __vue_render__$1 = function() { - var _vm = this; - var _h = _vm.$createElement; - var _c = _vm._self._c || _h; - return _c("div", [_vm._t("default")], 2) - }; - var __vue_staticRenderFns__$1 = []; - __vue_render__$1._withStripped = true; - - /* style */ - const __vue_inject_styles__$1 = undefined; - /* scoped */ - const __vue_scope_id__$1 = undefined; - /* module identifier */ - const __vue_module_identifier__$1 = undefined; - /* functional template */ - const __vue_is_functional_template__$1 = false; - /* style inject */ - - /* style inject SSR */ - - /* style inject shadow dom */ - - - - const __vue_component__$1 = /*#__PURE__*/normalizeComponent( - { render: __vue_render__$1, staticRenderFns: __vue_staticRenderFns__$1 }, - __vue_inject_styles__$1, - __vue_script__$1, - __vue_scope_id__$1, - __vue_is_functional_template__$1, - __vue_module_identifier__$1, - false, - undefined, - undefined, - undefined - ); - function createValidator(ruleFn, ruleName, ruleArgs, messageFn) { return (context) => { return Promise.resolve(ruleFn(context, ...ruleArgs)).then(valid => { @@ -1311,42 +889,35 @@ LIVE: 'live', SUBMIT: 'submit', }; - let FormularioInput = class FormularioInput extends Vue { + let FormularioField = class FormularioField extends Vue { constructor() { super(...arguments); - this.proxy = this.getInitialValue(); + this.proxy = this.hasModel ? this.value : ''; this.localErrors = []; this.violations = []; - this.validationRun = Promise.resolve(); + this.validationRun = Promise.resolve([]); } - get fullQualifiedName() { - return this.path !== '' ? `${this.path}.${this.name}` : this.name; + get fullPath() { + return this.__Formulario_path !== '' ? `${this.__Formulario_path}.${this.name}` : this.name; } - get model() { - const model = this.hasModel ? 'value' : 'proxy'; - return this.modelGetConverter(this[model]); - } - set model(value) { - value = this.modelSetConverter(value, this.proxy); - if (!shallowEqualObjects(value, this.proxy)) { - this.proxy = value; - } - this.$emit('input', value); - if (typeof this.formularioSetter === 'function') { - this.formularioSetter(this.context.name, value); - } + /** + * Determines if this formulario element is v-modeled or not. + */ + get hasModel() { + return has(this.$options.propsData || {}, 'value'); } get context() { return Object.defineProperty({ - name: this.fullQualifiedName, + name: this.fullPath, + path: this.fullPath, runValidation: this.runValidation.bind(this), violations: this.violations, errors: this.localErrors, allErrors: [...this.localErrors, ...this.violations.map(v => v.message)], }, 'model', { - get: () => this.model, + get: () => this.modelGetConverter(this.proxy), set: (value) => { - this.model = value; + this.syncProxy(this.modelSetConverter(value, this.proxy)); }, }); } @@ -1364,84 +935,67 @@ }); return messages; } - /** - * Determines if this formulario element is v-modeled or not. - */ - get hasModel() { - return has(this.$options.propsData || {}, 'value'); + onValueChange() { + this.syncProxy(this.value); } - onProxyChanged(newValue, oldValue) { - if (!this.hasModel && !shallowEqualObjects(newValue, oldValue)) { - this.context.model = newValue; - } + onProxyChange() { if (this.validationBehavior === VALIDATION_BEHAVIOR.LIVE) { this.runValidation(); } else { - this.violations = []; - } - } - onValueChanged(newValue, oldValue) { - if (this.hasModel && !shallowEqualObjects(newValue, oldValue)) { - this.context.model = newValue; + this.resetValidation(); } } + /** + * @internal + */ created() { - this.initProxy(); - if (typeof this.formularioRegister === 'function') { - this.formularioRegister(this.fullQualifiedName, this); - } - if (typeof this.addErrorObserver === 'function' && !this.errorsDisabled) { - this.addErrorObserver({ callback: this.setErrors, type: 'input', field: this.fullQualifiedName }); + if (typeof this.__FormularioForm_register === 'function') { + this.__FormularioForm_register(this.fullPath, this); } if (this.validationBehavior === VALIDATION_BEHAVIOR.LIVE) { this.runValidation(); } } - // noinspection JSUnusedGlobalSymbols + /** + * @internal + */ beforeDestroy() { - if (!this.errorsDisabled && typeof this.removeErrorObserver === 'function') { - this.removeErrorObserver(this.setErrors); - } - if (typeof this.formularioDeregister === 'function') { - this.formularioDeregister(this.fullQualifiedName); + if (typeof this.__FormularioForm_unregister === 'function') { + this.__FormularioForm_unregister(this.fullPath); } } - getInitialValue() { - return has(this.$options.propsData || {}, 'value') ? this.value : ''; - } - initProxy() { - // This should only be run immediately on created and ensures that the - // proxy and the model are both the same before any additional registration. - if (!shallowEqualObjects(this.context.model, this.proxy)) { - this.context.model = this.proxy; + syncProxy(value) { + if (!deepEquals(value, this.proxy)) { + this.proxy = value; + this.$emit('input', value); + if (typeof this.__FormularioForm_set === 'function') { + this.__FormularioForm_set(this.fullPath, value); + this.__FormularioForm_emitInput(); + } } } runValidation() { this.validationRun = this.validate().then(violations => { - const validationChanged = !shallowEqualObjects(violations, this.violations); this.violations = violations; - if (validationChanged) { - const payload = { - name: this.context.name, - violations: this.violations, - }; - this.$emit('validation', payload); - if (typeof this.onFormularioFieldValidation === 'function') { - this.onFormularioFieldValidation(payload); - } - } + this.emitValidation(this.fullPath, violations); return this.violations; }); return this.validationRun; } validate() { return validate(processConstraints(this.validation, this.$formulario.getRules(this.normalizedValidationRules), this.$formulario.getMessages(this, this.normalizedValidationMessages)), { - value: this.context.model, - name: this.context.name, - formValues: this.getFormValues(), + value: this.proxy, + name: this.fullPath, + formValues: this.__FormularioForm_getState(), }); } + emitValidation(path, violations) { + this.$emit('validation', { path, violations }); + if (typeof this.__FormularioForm_emitValidation === 'function') { + this.__FormularioForm_emitValidation(path, violations); + } + } hasValidationErrors() { return new Promise(resolve => { this.$nextTick(() => { @@ -1449,81 +1003,448 @@ }); }); } + /** + * @internal + */ setErrors(errors) { - this.localErrors = arrayify(errors); + if (!this.errorsDisabled) { + this.localErrors = errors; + } } + /** + * @internal + */ resetValidation() { this.localErrors = []; this.violations = []; } }; + __decorate([ + vuePropertyDecorator.Inject({ default: '' }) + ], FormularioField.prototype, "__Formulario_path", void 0); __decorate([ vuePropertyDecorator.Inject({ default: undefined }) - ], FormularioInput.prototype, "formularioSetter", void 0); + ], FormularioField.prototype, "__FormularioForm_set", void 0); __decorate([ vuePropertyDecorator.Inject({ default: () => () => { } }) - ], FormularioInput.prototype, "onFormularioFieldValidation", void 0); + ], FormularioField.prototype, "__FormularioForm_emitInput", void 0); + __decorate([ + vuePropertyDecorator.Inject({ default: () => () => { } }) + ], FormularioField.prototype, "__FormularioForm_emitValidation", void 0); __decorate([ vuePropertyDecorator.Inject({ default: undefined }) - ], FormularioInput.prototype, "formularioRegister", void 0); + ], FormularioField.prototype, "__FormularioForm_register", void 0); __decorate([ vuePropertyDecorator.Inject({ default: undefined }) - ], FormularioInput.prototype, "formularioDeregister", void 0); + ], FormularioField.prototype, "__FormularioForm_unregister", void 0); __decorate([ vuePropertyDecorator.Inject({ default: () => () => ({}) }) - ], FormularioInput.prototype, "getFormValues", void 0); - __decorate([ - vuePropertyDecorator.Inject({ default: undefined }) - ], FormularioInput.prototype, "addErrorObserver", void 0); - __decorate([ - vuePropertyDecorator.Inject({ default: undefined }) - ], FormularioInput.prototype, "removeErrorObserver", void 0); - __decorate([ - vuePropertyDecorator.Inject({ default: '' }) - ], FormularioInput.prototype, "path", void 0); + ], FormularioField.prototype, "__FormularioForm_getState", void 0); __decorate([ vuePropertyDecorator.Model('input', { default: '' }) - ], FormularioInput.prototype, "value", void 0); + ], FormularioField.prototype, "value", void 0); __decorate([ vuePropertyDecorator.Prop({ required: true, validator: (name) => typeof name === 'string' && name.length > 0, }) - ], FormularioInput.prototype, "name", void 0); + ], FormularioField.prototype, "name", void 0); __decorate([ vuePropertyDecorator.Prop({ default: '' }) - ], FormularioInput.prototype, "validation", void 0); + ], FormularioField.prototype, "validation", void 0); __decorate([ vuePropertyDecorator.Prop({ default: () => ({}) }) - ], FormularioInput.prototype, "validationRules", void 0); + ], FormularioField.prototype, "validationRules", void 0); __decorate([ vuePropertyDecorator.Prop({ default: () => ({}) }) - ], FormularioInput.prototype, "validationMessages", void 0); + ], FormularioField.prototype, "validationMessages", void 0); __decorate([ vuePropertyDecorator.Prop({ default: VALIDATION_BEHAVIOR.DEMAND, validator: behavior => Object.values(VALIDATION_BEHAVIOR).includes(behavior) }) - ], FormularioInput.prototype, "validationBehavior", void 0); + ], FormularioField.prototype, "validationBehavior", void 0); __decorate([ vuePropertyDecorator.Prop({ default: false }) - ], FormularioInput.prototype, "errorsDisabled", void 0); + ], FormularioField.prototype, "errorsDisabled", void 0); __decorate([ vuePropertyDecorator.Prop({ default: () => (value) => value }) - ], FormularioInput.prototype, "modelGetConverter", void 0); + ], FormularioField.prototype, "modelGetConverter", void 0); __decorate([ vuePropertyDecorator.Prop({ default: () => (value) => value }) - ], FormularioInput.prototype, "modelSetConverter", void 0); - __decorate([ - vuePropertyDecorator.Watch('proxy') - ], FormularioInput.prototype, "onProxyChanged", null); + ], FormularioField.prototype, "modelSetConverter", void 0); __decorate([ vuePropertyDecorator.Watch('value') - ], FormularioInput.prototype, "onValueChanged", null); - FormularioInput = __decorate([ - vuePropertyDecorator.Component({ name: 'FormularioInput', inheritAttrs: false }) - ], FormularioInput); - var script$2 = FormularioInput; + ], FormularioField.prototype, "onValueChange", null); + __decorate([ + vuePropertyDecorator.Watch('proxy') + ], FormularioField.prototype, "onProxyChange", null); + FormularioField = __decorate([ + vuePropertyDecorator.Component({ name: 'FormularioField', inheritAttrs: false }) + ], FormularioField); + var script = FormularioField; + + function normalizeComponent(template, style, script, scopeId, isFunctionalTemplate, moduleIdentifier /* server only */, shadowMode, createInjector, createInjectorSSR, createInjectorShadow) { + if (typeof shadowMode !== 'boolean') { + createInjectorSSR = createInjector; + createInjector = shadowMode; + shadowMode = false; + } + // Vue.extend constructor export interop. + const options = typeof script === 'function' ? script.options : script; + // render functions + if (template && template.render) { + options.render = template.render; + options.staticRenderFns = template.staticRenderFns; + options._compiled = true; + // functional template + if (isFunctionalTemplate) { + options.functional = true; + } + } + // scopedId + if (scopeId) { + options._scopeId = scopeId; + } + let hook; + if (moduleIdentifier) { + // server build + hook = function (context) { + // 2.3 injection + context = + context || // cached call + (this.$vnode && this.$vnode.ssrContext) || // stateful + (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext); // functional + // 2.2 with runInNewContext: true + if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') { + context = __VUE_SSR_CONTEXT__; + } + // inject component styles + if (style) { + style.call(this, createInjectorSSR(context)); + } + // register component module identifier for async chunk inference + if (context && context._registeredComponents) { + context._registeredComponents.add(moduleIdentifier); + } + }; + // used by ssr in case component is cached and beforeCreate + // never gets called + options._ssrRegister = hook; + } + else if (style) { + hook = shadowMode + ? function (context) { + style.call(this, createInjectorShadow(context, this.$root.$options.shadowRoot)); + } + : function (context) { + style.call(this, createInjector(context)); + }; + } + if (hook) { + if (options.functional) { + // register for functional component in vue file + const originalRender = options.render; + options.render = function renderWithStyleInjection(h, context) { + hook.call(context); + return originalRender(h, context); + }; + } + else { + // inject component registration as beforeCreate hook + const existing = options.beforeCreate; + options.beforeCreate = existing ? [].concat(existing, hook) : [hook]; + } + } + return script; + } + + /* script */ + const __vue_script__ = script; + + /* template */ + var __vue_render__ = function() { + var _vm = this; + var _h = _vm.$createElement; + var _c = _vm._self._c || _h; + return _c( + "div", + _vm._b({}, "div", _vm.$attrs, false), + [_vm._t("default", null, { context: _vm.context })], + 2 + ) + }; + var __vue_staticRenderFns__ = []; + __vue_render__._withStripped = true; + + /* style */ + const __vue_inject_styles__ = undefined; + /* scoped */ + const __vue_scope_id__ = undefined; + /* module identifier */ + const __vue_module_identifier__ = undefined; + /* functional template */ + const __vue_is_functional_template__ = false; + /* style inject */ + + /* style inject SSR */ + + /* style inject shadow dom */ + + + + const __vue_component__ = /*#__PURE__*/normalizeComponent( + { render: __vue_render__, staticRenderFns: __vue_staticRenderFns__ }, + __vue_inject_styles__, + __vue_script__, + __vue_scope_id__, + __vue_is_functional_template__, + __vue_module_identifier__, + false, + undefined, + undefined, + undefined + ); + + let FormularioFieldGroup = class FormularioFieldGroup extends Vue { + get fullPath() { + const path = `${this.name}`; + if (parseInt(path).toString() === path) { + return `${this.__Formulario_path}[${path}]`; + } + if (this.__Formulario_path === '') { + return path; + } + return `${this.__Formulario_path}.${path}`; + } + }; + __decorate([ + vuePropertyDecorator.Inject({ default: '' }) + ], FormularioFieldGroup.prototype, "__Formulario_path", void 0); + __decorate([ + vuePropertyDecorator.Prop({ required: true }) + ], FormularioFieldGroup.prototype, "name", void 0); + __decorate([ + vuePropertyDecorator.Provide('__Formulario_path') + ], FormularioFieldGroup.prototype, "fullPath", null); + FormularioFieldGroup = __decorate([ + vuePropertyDecorator.Component({ name: 'FormularioFieldGroup' }) + ], FormularioFieldGroup); + var script$1 = FormularioFieldGroup; + + /* script */ + const __vue_script__$1 = script$1; + + /* template */ + var __vue_render__$1 = function() { + var _vm = this; + var _h = _vm.$createElement; + var _c = _vm._self._c || _h; + return _c("div", [_vm._t("default")], 2) + }; + var __vue_staticRenderFns__$1 = []; + __vue_render__$1._withStripped = true; + + /* style */ + const __vue_inject_styles__$1 = undefined; + /* scoped */ + const __vue_scope_id__$1 = undefined; + /* module identifier */ + const __vue_module_identifier__$1 = undefined; + /* functional template */ + const __vue_is_functional_template__$1 = false; + /* style inject */ + + /* style inject SSR */ + + /* style inject shadow dom */ + + + + const __vue_component__$1 = /*#__PURE__*/normalizeComponent( + { render: __vue_render__$1, staticRenderFns: __vue_staticRenderFns__$1 }, + __vue_inject_styles__$1, + __vue_script__$1, + __vue_scope_id__$1, + __vue_is_functional_template__$1, + __vue_module_identifier__$1, + false, + undefined, + undefined, + undefined + ); + + const update = (state, path, value) => { + if (value === undefined) { + return unset(state, path); + } + return set(state, path, value); + }; + let FormularioForm = class FormularioForm extends Vue { + constructor() { + super(...arguments); + this.proxy = {}; + this.registry = new Map(); + // Local error messages are temporal, they wiped each resetValidation call + this.localFieldsErrors = {}; + this.localFormErrors = []; + } + get fieldsErrorsComputed() { + return merge(this.fieldsErrors || {}, this.localFieldsErrors); + } + get formErrorsComputed() { + return [...this.formErrors, ...this.localFormErrors]; + } + register(path, field) { + if (!this.registry.has(path)) { + this.registry.set(path, field); + } + const value = get(this.proxy, path); + if (!field.hasModel) { + if (value !== undefined) { + field.proxy = value; + } + else { + this.setFieldValue(path, null); + this.emitInput(); + } + } + else if (!deepEquals(field.proxy, value)) { + this.setFieldValue(path, field.proxy); + this.emitInput(); + } + if (has(this.fieldsErrorsComputed, path)) { + field.setErrors(this.fieldsErrorsComputed[path]); + } + } + unregister(path) { + if (this.registry.has(path)) { + this.registry.delete(path); + this.proxy = unset(this.proxy, path); + this.emitInput(); + } + } + getState() { + return this.proxy; + } + setFieldValue(path, value) { + this.proxy = update(this.proxy, path, value); + } + emitInput() { + this.$emit('input', clone(this.proxy)); + } + emitValidation(path, violations) { + this.$emit('validation', { path, violations }); + } + onStateChange(newState) { + const newProxy = clone(newState); + const oldProxy = this.proxy; + let proxyHasChanges = false; + this.registry.forEach((field, path) => { + const newValue = get(newState, path, null); + const oldValue = get(oldProxy, path, null); + field.proxy = newValue; + if (!deepEquals(newValue, oldValue)) { + field.$emit('input', newValue); + update(newProxy, path, newValue); + proxyHasChanges = true; + } + }); + this.proxy = newProxy; + if (proxyHasChanges) { + this.emitInput(); + } + } + onFieldsErrorsChange(fieldsErrors) { + this.registry.forEach((field, path) => { + field.setErrors(fieldsErrors[path] || []); + }); + } + created() { + this.$formulario.register(this.id, this); + if (typeof this.state === 'object') { + this.proxy = clone(this.state); + } + } + beforeDestroy() { + this.$formulario.unregister(this.id); + } + runValidation() { + const runs = []; + const violations = {}; + this.registry.forEach((field, path) => { + runs.push(field.runValidation().then(v => { violations[path] = v; })); + }); + return Promise.all(runs).then(() => violations); + } + hasValidationErrors() { + return this.runValidation().then(violations => { + return Object.keys(violations).some(path => violations[path].length > 0); + }); + } + setErrors({ fieldsErrors, formErrors }) { + this.localFieldsErrors = fieldsErrors || {}; + this.localFormErrors = formErrors || []; + } + resetValidation() { + this.localFieldsErrors = {}; + this.localFormErrors = []; + this.registry.forEach((field) => { + field.resetValidation(); + }); + } + onSubmit() { + return this.runValidation().then(violations => { + const hasErrors = Object.keys(violations).some(path => violations[path].length > 0); + if (!hasErrors) { + this.$emit('submit', clone(this.proxy)); + } + else { + this.$emit('error', violations); + } + }); + } + }; + __decorate([ + vuePropertyDecorator.Model('input', { default: () => ({}) }) + ], FormularioForm.prototype, "state", void 0); + __decorate([ + vuePropertyDecorator.Prop({ default: () => id('formulario-form') }) + ], FormularioForm.prototype, "id", void 0); + __decorate([ + vuePropertyDecorator.Prop({ default: () => ({}) }) + ], FormularioForm.prototype, "fieldsErrors", void 0); + __decorate([ + vuePropertyDecorator.Prop({ default: () => ([]) }) + ], FormularioForm.prototype, "formErrors", void 0); + __decorate([ + vuePropertyDecorator.Provide('__FormularioForm_register') + ], FormularioForm.prototype, "register", null); + __decorate([ + vuePropertyDecorator.Provide('__FormularioForm_unregister') + ], FormularioForm.prototype, "unregister", null); + __decorate([ + vuePropertyDecorator.Provide('__FormularioForm_getState') + ], FormularioForm.prototype, "getState", null); + __decorate([ + vuePropertyDecorator.Provide('__FormularioForm_set') + ], FormularioForm.prototype, "setFieldValue", null); + __decorate([ + vuePropertyDecorator.Provide('__FormularioForm_emitInput') + ], FormularioForm.prototype, "emitInput", null); + __decorate([ + vuePropertyDecorator.Provide('__FormularioForm_emitValidation') + ], FormularioForm.prototype, "emitValidation", null); + __decorate([ + vuePropertyDecorator.Watch('state', { deep: true }) + ], FormularioForm.prototype, "onStateChange", null); + __decorate([ + vuePropertyDecorator.Watch('fieldsErrorsComputed', { deep: true, immediate: true }) + ], FormularioForm.prototype, "onFieldsErrorsChange", null); + FormularioForm = __decorate([ + vuePropertyDecorator.Component({ name: 'FormularioForm' }) + ], FormularioForm); + var script$2 = FormularioForm; /* script */ const __vue_script__$2 = script$2; @@ -1534,9 +1455,16 @@ var _h = _vm.$createElement; var _c = _vm._self._c || _h; return _c( - "div", - { staticClass: "formulario-input" }, - [_vm._t("default", null, { context: _vm.context })], + "form", + { + on: { + submit: function($event) { + $event.preventDefault(); + return _vm.onSubmit($event) + } + } + }, + [_vm._t("default", null, { errors: _vm.formErrorsComputed })], 2 ) }; @@ -1573,10 +1501,15 @@ ); var index = { + Formulario, install(Vue, options) { - Vue.component('FormularioForm', __vue_component__); + Vue.component('FormularioField', __vue_component__); + Vue.component('FormularioFieldGroup', __vue_component__$1); + Vue.component('FormularioForm', __vue_component__$2); + // @deprecated Use FormularioField instead + Vue.component('FormularioInput', __vue_component__); + // @deprecated Use FormularioFieldGroup instead Vue.component('FormularioGrouping', __vue_component__$1); - Vue.component('FormularioInput', __vue_component__$2); Vue.mixin({ beforeCreate() { const o = this.$options;