vuetify
Version:
Vue Material Component Framework
189 lines (173 loc) • 4.57 kB
text/typescript
// Styles
import './VColorPickerEdit.sass'
// Components
import VBtn from '../VBtn'
import VIcon from '../VIcon'
// Helpers
import { parseHex } from '../../util/colorUtils'
// Types
import Vue, { VNode, PropType } from 'vue'
import { VColorPickerColor, fromRGBA, fromHexa, fromHSLA } from './util'
type Input = [string, number, string]
export type Mode = {
inputs?: Input[]
from: Function
}
export const modes = {
rgba: {
inputs: [
['r', 255, 'int'],
['g', 255, 'int'],
['b', 255, 'int'],
['a', 1, 'float'],
],
from: fromRGBA,
},
hsla: {
inputs: [
['h', 360, 'int'],
['s', 1, 'float'],
['l', 1, 'float'],
['a', 1, 'float'],
],
from: fromHSLA,
},
hexa: {
from: fromHexa,
},
} as { [key: string]: Mode }
export default Vue.extend({
name: 'v-color-picker-edit',
props: {
color: Object as PropType<VColorPickerColor>,
disabled: Boolean,
hideAlpha: Boolean,
hideModeSwitch: Boolean,
mode: {
type: String,
default: 'rgba',
validator: (v: string) => Object.keys(modes).includes(v),
},
},
data () {
return {
modes,
internalMode: this.mode,
}
},
computed: {
currentMode (): Mode {
return this.modes[this.internalMode]
},
},
watch: {
mode (mode) {
this.internalMode = mode
},
},
created () {
this.internalMode = this.mode
},
methods: {
getValue (v: any, type: string) {
if (type === 'float') return Math.round(v * 100) / 100
else if (type === 'int') return Math.round(v)
else return 0
},
parseValue (v: string, type: string) {
if (type === 'float') return parseFloat(v)
else if (type === 'int') return parseInt(v, 10) || 0
else return 0
},
changeMode () {
const modes = Object.keys(this.modes)
const index = modes.indexOf(this.internalMode)
const newMode = modes[(index + 1) % modes.length]
this.internalMode = newMode
this.$emit('update:mode', newMode)
},
genInput (target: string, attrs: any, value: any, on: any): VNode {
return this.$createElement('div', {
staticClass: 'v-color-picker__input',
}, [
this.$createElement('input', {
key: target,
attrs,
domProps: {
value,
},
on,
}),
this.$createElement('span', target.toUpperCase()),
])
},
genInputs (): VNode[] | VNode {
if (this.internalMode === 'hexa') {
const hex = this.color.hexa
const value = this.hideAlpha && hex.endsWith('FF') ? hex.substr(0, 7) : hex
return this.genInput(
'hex',
{
maxlength: this.hideAlpha ? 7 : 9,
disabled: this.disabled,
},
value,
{
change: (e: Event) => {
const el = e.target as HTMLInputElement
this.$emit('update:color', this.currentMode.from(parseHex(el.value)))
},
}
)
} else {
const inputs = this.hideAlpha ? this.currentMode.inputs!.slice(0, -1) : this.currentMode.inputs!
return inputs.map(([target, max, type]) => {
const value = this.color[this.internalMode as keyof VColorPickerColor] as any
return this.genInput(
target,
{
type: 'number',
min: 0,
max,
step: type === 'float' ? '0.01' : type === 'int' ? '1' : undefined,
disabled: this.disabled,
},
this.getValue(value[target], type),
{
input: (e: Event) => {
const el = e.target as HTMLInputElement
const newVal = this.parseValue(el.value || '0', type)
this.$emit('update:color', this.currentMode.from(
Object.assign({}, value, { [target]: newVal }),
this.color.alpha
))
},
}
)
})
}
},
genSwitch (): VNode {
return this.$createElement(VBtn, {
props: {
small: true,
icon: true,
disabled: this.disabled,
},
on: {
click: this.changeMode,
},
}, [
this.$createElement(VIcon, '$unfold'),
])
},
},
render (h): VNode {
return h('div', {
staticClass: 'v-color-picker__edit',
}, [
this.genInputs(),
!this.hideModeSwitch && this.genSwitch(),
])
},
})