@ishitatsuyuki/oruga-next
Version:
UI components for Vue.js and CSS framework agnostic
190 lines (173 loc) • 4.36 kB
text/typescript
import { defineComponent } from 'vue'
import { getOptions } from './config';
import { getValueByPath } from './helpers'
export default defineComponent({
inject: {
$field: { from: "$field", default: false }
},
emits: ['blur', 'focus'],
props: {
/**
* Makes input full width when inside a grouped or addon field
*/
expanded: Boolean,
/**
* Makes the element rounded
*/
rounded: Boolean,
/**
* Icon name to be added
*/
icon: String,
/**
* Icon pack to use
* @values mdi, fa, fas and any other custom icon pack
*/
iconPack: String,
/** Native options to use in HTML5 validation */
autocomplete: String,
/** Same as native maxlength, plus character counter */
maxlength: [Number, String],
/** Enable html 5 native validation */
useHtml5Validation: {
type: Boolean,
default: () => {
return getValueByPath(getOptions(), "useHtml5Validation", true);
},
},
/** Show status icon using field and variant prop */
statusIcon: {
type: Boolean,
default: () => {
return getValueByPath(getOptions(), "statusIcon", true);
},
},
/**
* The message which is shown when a validation error occurs
*/
validationMessage: String,
},
data() {
return {
isValid: true,
isFocused: false,
newIconPack: this.iconPack,
};
},
computed: {
parentField() {
return this.$field;
},
/**
* Get the type prop from parent if it's a Field.
*/
statusVariant() {
if (!this.parentField) return;
if (!this.parentField.newVariant) return;
if (typeof this.parentField.newVariant === "string") {
return this.parentField.newVariant;
} else {
for (const key in this.parentField.newVariant) {
if (this.parentField.newVariant[key]) {
return key;
}
}
}
},
/**
* Get the message prop from parent if it's a Field.
*/
statusMessage() {
if (!this.parentField) return;
return this.parentField.newMessage || this.parentField.hasMessageSlot;
},
/**
* Icon name based on the variant.
*/
statusVariantIcon() {
const statusVariantIcon = getValueByPath(getOptions(), "statusVariantIcon", {
'success': 'check',
'danger': 'alert-circle',
'info': 'information',
'warning': 'alert'
});
return statusVariantIcon[this.statusVariant] || ''
}
},
methods: {
/**
* Focus method that work dynamically depending on the component.
*/
focus() {
const el = this.getElement();
if (!el) return;
this.$nextTick(() => {
if (el) el.focus();
});
},
onBlur(event: Event) {
this.isFocused = false;
if (this.parentField) {
this.parentField.isFocused = false;
}
this.$emit("blur", event);
this.checkHtml5Validity();
},
onFocus(event: Event) {
this.isFocused = true;
if (this.parentField) {
this.parentField.isFocused = true;
}
this.$emit("focus", event);
},
getElement() {
let el = this.$refs[this.$elementRef];
while (el && el.$elementRef) {
el = el.$refs[el.$elementRef];
}
return el;
},
setInvalid() {
const variant = "danger";
const message = this.validationMessage || this.getElement().validationMessage;
this.setValidity(variant, message);
},
setValidity(variant, message) {
this.$nextTick(() => {
if (this.parentField) {
// Set type only if not defined
if (!this.parentField.variant) {
this.parentField.newVariant = variant;
}
// Set message only if not defined
if (!this.parentField.message) {
this.parentField.newMessage = message;
}
}
});
},
/**
* Check HTML5 validation, set isValid property.
* If validation fail, send 'danger' type,
* and error message to parent if it's a Field.
*/
checkHtml5Validity() {
if (!this.useHtml5Validation) return;
const el = this.getElement();
if (!el) return;
if (!el.checkValidity()) {
this.setInvalid();
this.isValid = false;
} else {
this.setValidity(null, null);
this.isValid = true;
}
return this.isValid;
},
syncFilled(value) {
if (this.parentField) {
this.parentField.isFilled = !!value
}
}
}
})