FIX: HSVInput circular update dependencies

This commit is contained in:
Robert Kossessa
2024-03-13 02:23:51 +01:00
parent bf22fb41cf
commit 3204604fa3
3 changed files with 57 additions and 49 deletions

View File

@@ -188,9 +188,9 @@ import { MoreHorizontal } from 'lucide-vue-next'
import { Separator } from '@renderer/components/ui/separator'
const props = defineProps({
color: {
type: Color,
default: () => Color.rgb(255, 0, 0)
colorNumber: {
type: Number,
default: () => Color('#ff0000').rgbNumber()
},
roundedTop: {
type: Boolean,
@@ -198,15 +198,25 @@ const props = defineProps({
}
})
// TODO: Currently color updates are passed up with input events and then passed back down as props
// This is the vue way, but that also means that the color is converted into a number and then back into a color
// This causes a loss of precision and the sliders to jump around a bit when the color is updated
// It would be better to pass the color number here and convert it to a color object here as well
// Then we can use the color object to update the sliders and inputs
// And only pass the color number up when it actually changes
const emit = defineEmits(['input'])
const previousColor = ref(Color(props.colorNumber))
const color = computed({
get() {
if (previousColor.value.rgbNumber() === props.colorNumber) {
return previousColor.value
}
return Color(props.colorNumber)
},
set(newColor) {
if (newColor.rgbNumber() !== color.value.rgbNumber()) {
previousColor.value = newColor
emit('input', newColor.rgbNumber())
}
}
})
const hueSliderValue = ref(0)
const saturationSliderValue = ref(100)
const valueSliderValue = ref(50)
@@ -217,7 +227,7 @@ const hueSliderModel = computed({
},
set(hue) {
hueSliderValue.value = hue[0]
emit('input', props.color.hue(hue[0]))
color.value = color.value.hue(hue[0])
}
})
@@ -227,7 +237,7 @@ const saturationSliderModel = computed({
},
set(saturation) {
saturationSliderValue.value = saturation[0]
emit('input', props.color.saturationv(saturation[0]))
color.value = color.value.saturationv(saturation[0])
}
})
@@ -237,7 +247,7 @@ const valueSliderModel = computed({
},
set(value) {
valueSliderValue.value = value[0]
emit('input', props.color.value(value[0]))
color.value = color.value.value(value[0])
}
})
@@ -263,7 +273,7 @@ function onSubmitHexInput() {
input = '#' + input
}
if (input.match(/^#[0-9A-F]{6}$/i)) {
emit('input', Color(input))
color.value = Color(input)
} else shake()
}
@@ -274,10 +284,10 @@ function onSubmitHueInput() {
return
}
const newHue = Math.max(0, Math.min(input, 360))
if (newHue === props.color.hue()) {
if (newHue === color.value.hue()) {
updateInputs()
}
emit('input', props.color.hue(newHue))
color.value = color.value.hue(newHue)
}
function onSubmitSaturationInput() {
@@ -287,10 +297,10 @@ function onSubmitSaturationInput() {
return
}
const newSaturation = Math.max(0, Math.min(input, 100))
if (newSaturation === props.color.saturationv()) {
if (newSaturation === color.value.saturationv()) {
updateInputs()
}
emit('input', props.color.saturationv(newSaturation))
color.value = color.value.saturationv(newSaturation)
}
function onSubmitValueInput() {
@@ -300,10 +310,10 @@ function onSubmitValueInput() {
return
}
const newValue = Math.max(0, Math.min(input, 100))
if (newValue === props.color.value()) {
if (newValue === color.value.value()) {
updateInputs()
}
emit('input', props.color.value(newValue))
color.value = color.value.value(newValue)
}
function onSubmitRGBInput() {
@@ -315,27 +325,26 @@ function onSubmitRGBInput() {
return
}
const newColor = Color.rgb(r, g, b)
if (newColor.hex() === props.color.hex()) {
if (newColor.hex() === color.value.hex()) {
updateInputs()
}
emit('input', newColor)
color.value = newColor
}
function updateInputs() {
console.log('COLORRR', props.color)
hexInput.value = props.color.hex().substring(1, 7)
hueInput.value = String(parseInt(props.color.hue())).padStart(3, '0')
saturationInput.value = String(parseInt(props.color.saturationv())).padStart(3, '0')
valueInput.value = String(parseInt(props.color.value())).padStart(3, '0')
rInput.value = String(parseInt(props.color.red())).padStart(3, '0')
gInput.value = String(parseInt(props.color.green())).padStart(3, '0')
bInput.value = String(parseInt(props.color.blue())).padStart(3, '0')
hueSliderValue.value = props.color.hue()
saturationSliderValue.value = props.color.saturationv()
valueSliderValue.value = props.color.value()
hexInput.value = color.value.hex().substring(1, 7)
hueInput.value = String(parseInt(color.value.hue())).padStart(3, '0')
saturationInput.value = String(parseInt(color.value.saturationv())).padStart(3, '0')
valueInput.value = String(parseInt(color.value.value())).padStart(3, '0')
rInput.value = String(parseInt(color.value.red())).padStart(3, '0')
gInput.value = String(parseInt(color.value.green())).padStart(3, '0')
bInput.value = String(parseInt(color.value.blue())).padStart(3, '0')
hueSliderValue.value = color.value.hue()
saturationSliderValue.value = color.value.saturationv()
valueSliderValue.value = color.value.value()
}
watch(() => props.color, updateInputs)
watch(() => props.colorNumber, updateInputs)
onBeforeMount(updateInputs)
const colorFieldText = ref(null)

View File

@@ -2,7 +2,7 @@
<div
class="pt-2"
:style="{
background: `linear-gradient(180deg, ${options[currentOption].color.hex() + '11'}, ${options[currentOption].color.hex() + '30'} 25%, ${options[currentOption].color.hex() + '30'} 40%, transparent 60%`
background: `linear-gradient(180deg, ${currentColorHex + '11'}, ${currentColorHex + '30'} 25%, ${currentColorHex + '30'} 40%, transparent 60%`
}"
>
<div
@@ -28,13 +28,13 @@
:key="key"
class="h-6 flex-1"
:class="{ 'color-tab': currentOption === key }"
:style="{ background: option.color.hex() }"
:style="{ background: Color(option.colorNumber).hex() }"
@click="currentOption = key"
/>
</div>
<HSVInput
:color="options[currentOption].color"
@input="(color) => $emit('input', currentOption, color)"
:color-number="options[currentOption].colorNumber"
@input="(colorNumber) => $emit('input', currentOption, colorNumber)"
/>
</div>
</template>
@@ -47,7 +47,7 @@ defineEmits(['input'])
const currentOption = ref(null)
const currentColorHex = computed(() => props.options[currentOption.value].color.hex())
const currentColorHex = computed(() => Color(props.options[currentOption.value].colorNumber).hex())
const props = defineProps({
options: {
@@ -55,15 +55,15 @@ const props = defineProps({
default: () => ({
one: {
titleKey: 'One',
color: Color('#ff0000')
colorNumber: Color('#ff0000').rgbNumber()
},
two: {
titleKey: 'Two',
color: Color('#00ff00')
colorNumber: Color('#00ff00').rgbNumber()
},
three: {
titleKey: 'Three',
color: Color('#0000ff')
colorNumber: Color('#0000ff').rgbNumber()
}
})
}

View File

@@ -3,12 +3,12 @@
<PaletteInput
:options="keyColors"
@input="
(optionKey, color) => {
(optionKey, colorNumber) => {
keyColors = {
...keyColors,
[optionKey]: {
...keyColors[optionKey],
color
colorNumber
}
}
}
@@ -20,7 +20,6 @@
import { Palette } from 'lucide-vue-next'
import ConfigSection from '@renderer/components/common/ConfigSection.vue'
import PaletteInput from '@renderer/components/common/PaletteInput.vue'
import Color from 'color'
import { useDeviceStore } from '@renderer/deviceStore'
import { useAppStore } from '@renderer/appStore'
import { storeToRefs } from 'pinia'
@@ -35,17 +34,17 @@ const keyColors = computed({
return {
default: {
titleKey: 'default',
color: Color(keyColor.value(appStore.selectedKey, false))
colorNumber: keyColor.value(appStore.selectedKey, false)
},
pressed: {
titleKey: 'pressed',
color: Color(keyColor.value(appStore.selectedKey, true))
colorNumber: keyColor.value(appStore.selectedKey, true)
}
}
},
set(newValue) {
deviceStore.setKeyColor(appStore.selectedKey, false, Color(newValue.default.color).rgbNumber())
deviceStore.setKeyColor(appStore.selectedKey, true, Color(newValue.pressed.color).rgbNumber())
deviceStore.setKeyColor(appStore.selectedKey, false, newValue.default.colorNumber)
deviceStore.setKeyColor(appStore.selectedKey, true, newValue.pressed.colorNumber)
}
})
</script>