// Mixins import Colorable from '../colorable'; import Themeable from '../themeable'; import { inject as RegistrableInject } from '../registrable'; // Utilities import { deepEqual } from '../../util/helpers'; import { consoleError } from '../../util/console'; import mixins from '../../util/mixins'; /* @vue/component */ export default mixins(Colorable, RegistrableInject('form'), Themeable).extend({ name: 'validatable', props: { disabled: Boolean, error: Boolean, errorCount: { type: [Number, String], default: 1 }, errorMessages: { type: [String, Array], default: () => [] }, messages: { type: [String, Array], default: () => [] }, readonly: Boolean, rules: { type: Array, default: () => [] }, success: Boolean, successMessages: { type: [String, Array], default: () => [] }, validateOnBlur: Boolean, value: { required: false } }, data() { return { errorBucket: [], hasColor: false, hasFocused: false, hasInput: false, isFocused: false, isResetting: false, lazyValue: this.value, valid: false }; }, computed: { computedColor() { if (this.disabled) return undefined; if (this.color) return this.color; // It's assumed that if the input is on a // dark background, the user will want to // have a white color. If the entire app // is setup to be dark, then they will // like want to use their primary color if (this.isDark && !this.appIsDark) return 'white';else return 'primary'; }, hasError() { return this.internalErrorMessages.length > 0 || this.errorBucket.length > 0 || this.error; }, // TODO: Add logic that allows the user to enable based // upon a good validation hasSuccess() { return this.internalSuccessMessages.length > 0 || this.success; }, externalError() { return this.internalErrorMessages.length > 0 || this.error; }, hasMessages() { return this.validationTarget.length > 0; }, hasState() { if (this.disabled) return false; return this.hasSuccess || this.shouldValidate && this.hasError; }, internalErrorMessages() { return this.genInternalMessages(this.errorMessages); }, internalMessages() { return this.genInternalMessages(this.messages); }, internalSuccessMessages() { return this.genInternalMessages(this.successMessages); }, internalValue: { get() { return this.lazyValue; }, set(val) { this.lazyValue = val; this.$emit('input', val); } }, shouldValidate() { if (this.externalError) return true; if (this.isResetting) return false; return this.validateOnBlur ? this.hasFocused && !this.isFocused : this.hasInput || this.hasFocused; }, validations() { return this.validationTarget.slice(0, Number(this.errorCount)); }, validationState() { if (this.disabled) return undefined; if (this.hasError && this.shouldValidate) return 'error'; if (this.hasSuccess) return 'success'; if (this.hasColor) return this.computedColor; return undefined; }, validationTarget() { if (this.internalErrorMessages.length > 0) { return this.internalErrorMessages; } else if (this.successMessages.length > 0) { return this.internalSuccessMessages; } else if (this.messages.length > 0) { return this.internalMessages; } else if (this.shouldValidate) { return this.errorBucket; } else return []; } }, watch: { rules: { handler(newVal, oldVal) { if (deepEqual(newVal, oldVal)) return; this.validate(); }, deep: true }, internalValue() { // If it's the first time we're setting input, // mark it with hasInput this.hasInput = true; this.validateOnBlur || this.$nextTick(this.validate); }, isFocused(val) { // Should not check validation // if disabled or readonly if (!val && !this.disabled && !this.readonly) { this.hasFocused = true; this.validateOnBlur && this.validate(); } }, isResetting() { setTimeout(() => { this.hasInput = false; this.hasFocused = false; this.isResetting = false; this.validate(); }, 0); }, hasError(val) { if (this.shouldValidate) { this.$emit('update:error', val); } }, value(val) { this.lazyValue = val; } }, beforeMount() { this.validate(); }, created() { this.form && this.form.register(this); }, beforeDestroy() { this.form && this.form.unregister(this); }, methods: { genInternalMessages(messages) { if (!messages) return [];else if (Array.isArray(messages)) return messages;else return [messages]; }, /** @public */ reset() { this.isResetting = true; this.internalValue = Array.isArray(this.internalValue) ? [] : undefined; }, /** @public */ resetValidation() { this.isResetting = true; }, /** @public */ validate(force = false, value) { const errorBucket = []; value = value || this.internalValue; if (force) this.hasInput = this.hasFocused = true; for (let index = 0; index < this.rules.length; index++) { const rule = this.rules[index]; const valid = typeof rule === 'function' ? rule(value) : rule; if (typeof valid === 'string') { errorBucket.push(valid); } else if (typeof valid !== 'boolean') { consoleError(`Rules should return a string or boolean, received '${typeof valid}' instead`, this); } } this.errorBucket = errorBucket; this.valid = errorBucket.length === 0; return this.valid; } } }); //# sourceMappingURL=index.js.map