UNPKG

@inkline/inkline

Version:

Inkline is the Vue.js UI/UX Library built for creating your next design system

205 lines (196 loc) 5.78 kB
import { defineComponent } from 'vue'; import IButton from '@inkline/inkline/components/IButton/index.vue'; import IInput from '@inkline/inkline/components/IInput/index.vue'; import { uid } from '@inkline/inkline/helpers'; import { defaultPropValue, sizePropValidator } from '@inkline/inkline/mixins/props'; import { InputElementEvent } from '@inkline/inkline/types'; const componentName = 'INumberInput'; export default defineComponent({ name: componentName, components: { IButton }, extends: IInput, props: { /** * The color variant of the input * @type light | dark * @default light * @name color */ color: { type: String, default: defaultPropValue<string>(componentName, 'color') }, /** * Display the input as clearable * @type Boolean * @default false * @name clearable */ clearable: { type: Boolean, default: false }, /** * The disabled state of the input * @type Boolean * @default false * @name disabled */ disabled: { type: Boolean, default: false }, /** * The id of the internal input element * @type String * @default * @name id */ id: { type: String, default: '' }, /** * Used to set the field value * @type String | Number * @default * @name modelValue */ modelValue: { type: [String, Number], default: '' }, /** * The unique identifier of the input * @type String * @default uid() * @name name */ name: { type: [String, Number], default (): string { return uid('input'); } }, /** * The readonly state of the input * @type Boolean * @default false * @name readonly */ readonly: { type: Boolean, default: false }, /** * The size variant of the input * @type sm | md | lg * @default md * @name size */ size: { type: String, default: defaultPropValue<string>(componentName, 'size'), validator: sizePropValidator }, /** * The tabindex of the input * @type Number | String * @default 0 * @name tabindex */ tabindex: { type: [Number, String], default: 0 }, /** * The minimum allowed input value * @type Number * @default -Infinity * @name min */ min: { type: [Number, String], default: -Infinity }, /** * The maximum allowed input value * @type Number * @default +Infinity * @name max */ max: { type: [Number, String], default: Infinity }, /** * The precision of the input value, for floating point numbers * @type Number * @default 0 * @name precision */ precision: { type: Number, default: 0 }, /** * The increment step to increase or decrease the value by * @type Number * @default 1 * @name step */ step: { type: Number, default: 1 } }, emits: [ /** * Event emitted for setting the modelValue * @event update:modelValue */ 'update:modelValue' ], watch: { modelValue: { immediate: true, handler (value: string) { let newValue = (value || '').toString() .replace(/^[^0-9-]/, '') .replace(/^(-)[^0-9]/, '$1') .replace(new RegExp(`^(-?[0-9]+)[^0-9${this.precision > 0 ? '.' : ''}]`), '$1'); if (this.precision > 0) { newValue = newValue .replace(/^(-?[0-9]+\.)[^0-9]/, '$1') .replace(new RegExp(`^(-?[0-9]+\\.[0-9]{0,${this.precision}}).*`), '$1'); } if (parseFloat(newValue) >= parseFloat(this.max as string)) newValue = this.max.toString(); if (parseFloat(newValue) <= parseFloat(this.min as string)) newValue = this.min.toString(); (this.parent as any).onInput?.(this.name, newValue); this.$emit('update:modelValue', newValue); } } }, methods: { decrease () { this.$emit('update:modelValue', this.formatPrecision((Number(this.modelValue) - this.step).toString())); }, increase () { this.$emit('update:modelValue', this.formatPrecision((Number(this.modelValue) + this.step).toString())); }, formatPrecision (value: string) { const parts = value.split('.'); let decimals = parts[1] || ''; for (let i = decimals.length; i < this.precision; i += 1) { decimals += '0'; } return this.precision > 0 ? `${parts[0]}.${decimals}` : parts[0]; }, onBlurFormatPrecision (event: InputElementEvent) { this.$emit('update:modelValue', this.formatPrecision(Number(this.modelValue).toString())); (this.parent as any).onBlur?.(this.name, event); } } });