A Photoshop-inspired, VueJS number input component in which the user can modify the value by dragging with the mouse.
A simple number input component that users can edit by dragging the label around, inspired by Photoshop UX.
Written in Typescript.
<template>
<div>
<draggable-number-input v-model="someNumber" label="My number" />
</div>
</template>
<script>
export default {
data() {
return {
someNumber: 1,
};
},
};
</script>
This will create an unstyled HTML5 <input type="number">
tied to someNumber
, the value of which the user can easily increase or decrease by dragging (respectively) up and down on the label.
The only two required properties are label
and value
(in the example case, handled through the v-model
syntactic sugar).
Property | Description | Type | Default | Options | |
---|---|---|---|---|---|
dragDirection | The axis in which the user has to drag to increase/decrease the number. | String | “Y” | “X” | “Y” | |
hideLabel | Whether or not to hide the label. | Boolean | false | true | false |
label | The label to show next to the input. It is also used to generate the name of the input and the class of the wrapper. | String | - | - | |
max | Maximum allowed value. | Number | Infinity | - | |
min | Minimum allowed value. | Number | -Infinity | - | |
step | The amount by which the value is increased on mouse movement. | Number | 1 | - | |
value | The value of the input. | Number | - | - |
The generated HTML looks like this:
<div class="vue-draggable-number-container ${generatedInputName}">
<label for="${generatedInputName}"> </label>
<input type="number" name="${generatedInputName}" />
</div>
Where ${generatedInputName}
is draggable-number-
plus the kebab-cased label.
These are useful to target the component for styling.
As mentioned, the inspiration from this component came from Adobe Photoshop’s UX. Hence, a usecase for it could be sizing inputs. We can imagine we have an element we want to resize, while keeping the aspect-ratio of the element constant.
We would have something like this:
<template>
<div id="advanced-demo">
<draggable-number-input label="Width:" @input="adjustHeight" v-model="width" drag-direction="X" />
<input v-model="aspectRatio.isLocked" @change="lockAspectRatio">
<label for="lock-aspect-ratio">
<!-- SVG Icon -->
</label>
<draggable-number-input label="Height:" @input="adjustWidth" v-model="height" drag-direction="Y" />
</div>
</template>
<script lang="ts">
export default class LockedRatioDemo extends Vue {
public width = 10;
public height = 20;
public aspectRatio = {
isLocked: true,
ratio: this.height / this.width
}
private adjustHeight(val: number) {
if(!this.aspectRatio.isLocked)
return;
this.height = Math.round(val * this.aspectRatio.ratio);
}
private adjustWidth(val: number) {
if(!this.aspectRatio.isLocked)
return;
this.width = Math.round( val * (1 / this.aspectRatio.ratio) );
}
private lockAspectRatio() {
this.aspectRatio.ratio = this.height / this.width;
}
}
</script>