@dialpad/dialtone-vue
Version:
Vue component library for Dialpad's design system Dialtone
1 lines • 19.7 kB
Source Map (JSON)
{"version":3,"file":"input.cjs","sources":["../../../components/input/input.vue"],"sourcesContent":["<template>\n <div\n ref=\"container\"\n :class=\"[rootClass, 'd-input__root', { 'd-input--hidden': hidden }]\"\n data-qa=\"dt-input\"\n >\n <label\n class=\"d-input__label\"\n :aria-details=\"$slots.description || description ? descriptionKey : undefined\"\n data-qa=\"dt-input-label-wrapper\"\n >\n <!-- @slot Slot for label, defaults to label prop -->\n <slot name=\"labelSlot\">\n <div\n v-if=\"labelVisible && label\"\n ref=\"label\"\n data-qa=\"dt-input-label\"\n :class=\"[\n 'd-input__label-text',\n 'd-label',\n labelSizeClasses[size],\n ]\"\n >\n {{ label }}\n </div>\n </slot>\n <div\n v-if=\"$slots.description || description || shouldValidateLength\"\n :id=\"descriptionKey\"\n ref=\"description\"\n :class=\"[\n 'd-input__description',\n 'd-description',\n descriptionSizeClasses[size],\n ]\"\n data-qa=\"dt-input-description\"\n >\n <div\n v-if=\"$slots.description || description\"\n >\n <!-- @slot Slot for description, defaults to description prop -->\n <slot name=\"description\">{{ description }}</slot>\n </div>\n <div\n v-if=\"shouldValidateLength\"\n data-qa=\"dt-input-length-description\"\n class=\"d-input__length-description\"\n >\n {{ validationProps.length.description }}\n </div>\n </div>\n <div\n :class=\"inputWrapperClasses()\"\n :read-only=\"disabled\"\n >\n <span\n class=\"d-input-icon d-input-icon--left\"\n data-qa=\"dt-input-left-icon-wrapper\"\n @focusout=\"onBlur\"\n >\n <!-- @slot Slot for left icon -->\n <slot\n name=\"leftIcon\"\n :icon-size=\"iconSize\"\n />\n </span>\n <textarea\n v-if=\"isTextarea\"\n ref=\"input\"\n :value=\"value\"\n :name=\"name\"\n :disabled=\"disabled\"\n :autocomplete=\"$attrs.autocomplete ?? 'off'\"\n :class=\"inputClasses()\"\n :maxlength=\"shouldLimitMaxLength ? validationProps.length.max : null\"\n :data-qa=\"$attrs['data-qa'] ?? 'dt-input-input'\"\n v-bind=\"$attrs\"\n v-on=\"inputListeners\"\n />\n <input\n v-else\n ref=\"input\"\n :value=\"value\"\n :name=\"name\"\n :type=\"type\"\n :disabled=\"disabled\"\n :autocomplete=\"$attrs.autocomplete ?? 'off'\"\n :class=\"inputClasses()\"\n :maxlength=\"shouldLimitMaxLength ? validationProps.length.max : null\"\n :data-qa=\"$attrs['data-qa'] ?? 'dt-input-input'\"\n v-bind=\"$attrs\"\n v-on=\"inputListeners\"\n >\n <span\n class=\"d-input-icon d-input-icon--right\"\n data-qa=\"dt-input-right-icon-wrapper\"\n @focusout=\"onBlur\"\n >\n <!-- @slot Slot for right icon -->\n <slot\n name=\"rightIcon\"\n :icon-size=\"iconSize\"\n :clear=\"clearInput\"\n />\n </span>\n </div>\n </label>\n <dt-validation-messages\n :validation-messages=\"validationMessages\"\n :show-messages=\"showMessages\"\n :class=\"messagesClass\"\n v-bind=\"messagesChildProps\"\n data-qa=\"dt-input-messages\"\n />\n </div>\n</template>\n\n<script>\n/* eslint-disable max-lines */\nimport { DESCRIPTION_SIZE_TYPES, VALIDATION_MESSAGE_TYPES } from '@/common/constants';\nimport {\n INPUT_TYPES,\n INPUT_SIZES,\n INPUT_SIZE_CLASSES,\n INPUT_ICON_SIZES,\n INPUT_STATE_CLASSES,\n DESCRIPTION_SIZE_CLASSES,\n LABEL_SIZE_CLASSES,\n} from './input_constants';\nimport {\n getUniqueString,\n getValidationState,\n} from '@/common/utils';\nimport { DtValidationMessages } from '@/components/validation_messages';\nimport { MessagesMixin } from '@/common/mixins/input';\n\n/**\n * An input field is an input control that allows users to enter alphanumeric information.\n * It can have a range of options and supports single line and multi-line lengths,\n * as well as varying formats, including numbers, masked passwords, etc.\n * @property {Boolean} placeholder attribute\n * @see https://dialtone.dialpad.com/components/input.html\n */\nexport default {\n name: 'DtInput',\n\n components: { DtValidationMessages },\n\n mixins: [MessagesMixin],\n\n inheritAttrs: false,\n\n props: {\n /**\n * Name property of the input element\n */\n name: {\n type: String,\n default: '',\n },\n\n /**\n * Type of the input.\n * When `textarea` a `<textarea>` element will be rendered instead of an `<input>` element.\n * @values text, password, email, number, textarea, date, time, file, tel, search\n * @default 'text'\n */\n type: {\n type: String,\n default: INPUT_TYPES.TEXT,\n validator: (t) => Object.values(INPUT_TYPES).includes(t),\n },\n\n /**\n * Value of the input\n */\n value: {\n type: [String, Number],\n default: '',\n },\n\n /**\n * Disables the input\n * @values true, false\n */\n disabled: {\n type: Boolean,\n default: false,\n },\n\n /**\n * Label for the input\n */\n label: {\n type: String,\n default: '',\n },\n\n /**\n * Determines visibility of input label.\n * @values true, false\n */\n labelVisible: {\n type: Boolean,\n default: true,\n },\n\n /**\n * Description for the input\n */\n description: {\n type: String,\n default: '',\n },\n\n /**\n * Size of the input, one of `xs`, `sm`, `md`, `lg`, `xl`\n * @values xs, sm, md, lg, xl\n */\n size: {\n type: String,\n default: 'md',\n validator: (t) => Object.values(INPUT_SIZES).includes(t),\n },\n\n /**\n * Additional class name for the input element.\n * Can accept String, Object, and Array, i.e. has the\n * same API as Vue's built-in handling of the class attribute.\n */\n inputClass: {\n type: [String, Object, Array],\n default: '',\n },\n\n /**\n * Additional class name for the input wrapper element.\n * Can accept all of String, Object, and Array, i.e. has the\n * same api as Vue's built-in handling of the class attribute.\n */\n inputWrapperClass: {\n type: [String, Object, Array],\n default: '',\n },\n\n /**\n * Additional class name for the root element.\n * Can accept all of String, Object, and Array, i.e. has the\n * same api as Vue's built-in handling of the class attribute.\n */\n rootClass: {\n type: [String, Object, Array],\n default: '',\n },\n\n /**\n * The current character length that the user has entered into the input.\n * This will only need to be used if you are using `validate.length` and\n * the string contains abnormal characters.\n * For example, an emoji could take up many characters in the input, but should only count as 1 character.\n * If no number is provided, a built-in length calculation will be used for the length validation.\n */\n currentLength: {\n type: Number,\n default: null,\n },\n\n /**\n * Whether the input will continue to display a warning validation message even if the input has lost focus.\n */\n retainWarning: {\n type: Boolean,\n default: false,\n },\n\n /**\n * Validation for the input. Supports maximum length validation with the structure:\n * `{ \"length\": {\"description\": string, \"max\": number, \"warn\": number, \"message\": string,\n * \"limitMaxLength\": boolean }}`\n */\n validate: {\n type: Object,\n default: null,\n },\n\n /**\n * hidden allows to use input without the element visually present in DOM\n */\n hidden: {\n type: Boolean,\n default: false,\n },\n },\n\n emits: [\n /**\n * Native input event\n *\n * @event input\n * @type {String}\n */\n 'input',\n\n /**\n * Native input blur event\n *\n * @event blur\n * @type {FocusEvent}\n */\n 'blur',\n\n /**\n * Input clear event\n *\n * @event clear\n */\n 'clear',\n\n /**\n * Native input focus event\n *\n * @event focus\n * @type {FocusEvent}\n */\n 'focus',\n\n /**\n * Native input focusin event\n *\n * @event focusin\n * @type {FocusEvent}\n */\n 'focusin',\n\n /**\n * Native input focusout event\n *\n * @event focusout\n * @type {FocusEvent}\n */\n 'focusout',\n\n /**\n * Length of the input when currentLength prop is not passed\n *\n * @event update:length\n * @type {Number}\n */\n 'update:length',\n\n /**\n * Result of the input validation\n *\n * @event update:invalid\n * @type {Boolean}\n */\n 'update:invalid',\n ],\n\n data () {\n return {\n isInputFocused: false,\n isInvalid: false,\n defaultLength: 0,\n };\n },\n\n computed: {\n\n isTextarea () {\n return this.type === INPUT_TYPES.TEXTAREA;\n },\n\n isDefaultSize () {\n return this.size === INPUT_SIZES.DEFAULT;\n },\n\n iconSize () {\n return INPUT_ICON_SIZES[this.size];\n },\n\n isValidSize () {\n return Object.values(INPUT_SIZES).includes(this.size);\n },\n\n isValidDescriptionSize () {\n return Object.values(DESCRIPTION_SIZE_TYPES).includes(this.size);\n },\n\n inputComponent () {\n if (this.isTextarea) {\n return 'textarea';\n }\n\n return 'input';\n },\n\n inputListeners () {\n return {\n /* TODO\n Check if any usages of this component leverage $listeners and either remove if unused or scope the removal\n and migration prior to upgrading to Vue 3.x\n */\n ...this.$listeners,\n input: event => this.$emit('input', event.target.value),\n focus: event => {\n this.isInputFocused = true;\n this.$emit('focus', event);\n },\n\n blur: event => {\n this.isInputFocused = false;\n this.onBlur(event);\n },\n };\n },\n\n descriptionKey () {\n return `input-description-${getUniqueString()}`;\n },\n\n inputState () {\n return getValidationState(this.validationMessages);\n },\n\n defaultLengthCalculation () {\n return this.calculateLength(this.value);\n },\n\n validationProps () {\n return {\n length: {\n description: this?.validate?.length?.description,\n max: this?.validate?.length?.max,\n warn: this?.validate?.length?.warn,\n message: this?.validate?.length?.message,\n limitMaxLength: this?.validate?.length?.limitMaxLength ? this.validate.length.limitMaxLength : false,\n },\n };\n },\n\n validationMessages () {\n // Add length validation message if exists\n if (this.showLengthLimitValidation) {\n return this.formattedMessages.concat([this.inputLengthErrorMessage()]);\n }\n\n return this.formattedMessages;\n },\n\n showInputState () {\n return this.showMessages && this.inputState;\n },\n\n inputLength () {\n return this.currentLength ? this.currentLength : this.defaultLengthCalculation;\n },\n\n inputLengthState () {\n if (this.inputLength < this.validationProps.length.warn) {\n return null;\n } else if (this.inputLength <= this.validationProps.length.max) {\n return this.validationProps.length.warn ? VALIDATION_MESSAGE_TYPES.WARNING : null;\n } else {\n return VALIDATION_MESSAGE_TYPES.ERROR;\n }\n },\n\n shouldValidateLength () {\n return !!(\n this.validationProps.length.description &&\n this.validationProps.length.max\n );\n },\n\n shouldLimitMaxLength () {\n return this.shouldValidateLength && this.validationProps.length.limitMaxLength;\n },\n\n showLengthLimitValidation () {\n return (\n this.shouldValidateLength &&\n this.inputLengthState !== null &&\n this.validationProps.length.message &&\n (this.retainWarning || this.isInputFocused || this.isInvalid)\n );\n },\n\n sizeModifierClass () {\n if (this.isDefaultSize || !this.isValidSize) {\n return '';\n }\n\n return INPUT_SIZE_CLASSES[this.inputComponent][this.size];\n },\n\n stateClass () {\n return [INPUT_STATE_CLASSES[this.inputState]];\n },\n },\n\n watch: {\n isInvalid (val) {\n this.$emit('update:invalid', val);\n },\n\n value: {\n immediate: true,\n handler (newValue) {\n if (this.shouldValidateLength) {\n this.validateLength(this.inputLength);\n }\n\n if (this.currentLength == null) {\n this.$emit('update:length', this.calculateLength(newValue));\n }\n },\n },\n },\n\n beforeMount () {\n this.descriptionSizeClasses = DESCRIPTION_SIZE_CLASSES;\n this.labelSizeClasses = LABEL_SIZE_CLASSES;\n },\n\n methods: {\n inputClasses () {\n return [\n 'd-input__input',\n this.inputComponent === 'input' ? 'd-input' : 'd-textarea',\n {\n [this.stateClass]: this.showInputState,\n 'd-input-icon--left': this.$slots.leftIcon,\n 'd-input-icon--right': this.$slots.rightIcon,\n },\n this.sizeModifierClass,\n this.inputClass,\n ];\n },\n\n inputWrapperClasses () {\n if (this.hidden) {\n return [];\n }\n return [\n 'd-input__wrapper',\n { [this.stateClass]: this.showInputState },\n this.inputWrapperClass,\n ];\n },\n\n calculateLength (value) {\n if (typeof value !== 'string') {\n return 0;\n }\n\n return [...value].length;\n },\n\n inputLengthErrorMessage () {\n return {\n message: this.validationProps.length.message,\n type: this.inputLengthState,\n };\n },\n\n onBlur (e) {\n // Do not emit a blur event if the target element is a child of this component\n if (!this.$refs.container?.contains(e.relatedTarget)) {\n this.$emit('blur', e);\n }\n },\n\n emitClearEvents () {\n this.$emit('input', '');\n this.$emit('clear');\n this.$emit('update:modelValue', '');\n },\n\n blur () {\n this.$refs.input.blur();\n },\n\n focus () {\n this.$refs.input.focus();\n },\n\n select () {\n this.$refs.input.select();\n },\n\n getMessageKey (type, index) {\n return `message-${type}-${index}`;\n },\n\n validateLength (length) {\n this.isInvalid = (length > this.validationProps.length.max);\n },\n\n clearInput () {\n this.$refs.input.value = '';\n this.$refs.input.focus();\n this.emitClearEvents();\n },\n },\n};\n</script>\n"],"names":["_sfc_main","DtValidationMessages","MessagesMixin","INPUT_TYPES","t","INPUT_SIZES","INPUT_ICON_SIZES","DESCRIPTION_SIZE_TYPES","event","getUniqueString","getValidationState","_b","_a","_d","_c","_f","_e","_h","_g","_j","_i","VALIDATION_MESSAGE_TYPES","INPUT_SIZE_CLASSES","INPUT_STATE_CLASSES","val","newValue","DESCRIPTION_SIZE_CLASSES","LABEL_SIZE_CLASSES","value","type","index","length"],"mappings":"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"}