Skip to content

Commit

Permalink
fix(VColorPicker): support dynamic width (#16675)
Browse files Browse the repository at this point in the history
Fixes #7151
Fixes #16668
  • Loading branch information
KaelWD committed Feb 21, 2023
1 parent 6ef2482 commit 7190d27
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@

.v-color-picker-canvas
$root: &
display: flex
position: relative
overflow: hidden
contain: strict
contain: content

&__dot
position: absolute
Expand Down
38 changes: 27 additions & 11 deletions packages/vuetify/src/components/VColorPicker/VColorPickerCanvas.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// Styles
import './VColorPickerCanvas.sass'

// Composables
import { useResizeObserver } from '@/composables/resizeObserver'

// Utilities
import { clamp, convertToUnit, defineComponent, getEventCoordinates, useRender } from '@/util'
import { computed, onMounted, ref, watch } from 'vue'
Expand Down Expand Up @@ -53,6 +56,16 @@ export const VColorPickerCanvas = defineComponent({
})

const canvasRef = ref<HTMLCanvasElement | null>()
const canvasWidth = ref(parseFloat(props.width))
const canvasHeight = ref(parseFloat(props.height))
const { resizeRef } = useResizeObserver(entries => {
if (!resizeRef.value?.offsetParent) return

const { width, height } = entries[0].contentRect

canvasWidth.value = width
canvasHeight.value = height
})

function updateDotPosition (x: number, y: number, rect: DOMRect) {
const { left, top, width, height } = rect
Expand Down Expand Up @@ -107,13 +120,12 @@ export const VColorPickerCanvas = defineComponent({

if (!canvasRef.value) return

const { width, height } = canvasRef.value.getBoundingClientRect()
const { x, y } = dotPosition.value

emit('update:color', {
h: props.color?.h ?? 0,
s: clamp(x, 0, width) / width,
v: 1 - clamp(y, 0, height) / height,
s: clamp(x, 0, canvasWidth.value) / canvasWidth.value,
v: 1 - clamp(y, 0, canvasHeight.value) / canvasHeight.value,
a: props.color?.a ?? 1,
})
})
Expand All @@ -140,6 +152,13 @@ export const VColorPickerCanvas = defineComponent({
}

watch(() => props.color?.h, updateCanvas, { immediate: true })
watch(() => [canvasWidth.value, canvasHeight.value], (newVal, oldVal) => {
updateCanvas()
dotPosition.value = {
x: dotPosition.value.x * newVal[0] / oldVal[0],
y: dotPosition.value.y * newVal[1] / oldVal[1],
}
}, { flush: 'post' })

watch(() => props.color, () => {
if (isInteracting.value) {
Expand All @@ -150,28 +169,25 @@ export const VColorPickerCanvas = defineComponent({
isOutsideUpdate.value = true

dotPosition.value = props.color ? {
x: props.color.s * parseInt(props.width, 10),
y: (1 - props.color.v) * parseInt(props.height, 10),
x: props.color.s * canvasWidth.value,
y: (1 - props.color.v) * canvasHeight.value,
} : { x: 0, y: 0 }
}, { deep: true, immediate: true })

onMounted(() => updateCanvas())

useRender(() => (
<div
ref={ resizeRef }
class="v-color-picker-canvas"
style={{
width: convertToUnit(props.width),
height: convertToUnit(props.height),
}}
onClick={ handleClick }
onMousedown={ handleMouseDown }
onTouchstart={ handleMouseDown }
>
<canvas
ref={ canvasRef }
width={ props.width }
height={ props.height }
width={ canvasWidth.value }
height={ canvasHeight.value }
/>
<div
class={[
Expand Down
4 changes: 2 additions & 2 deletions packages/vuetify/src/composables/resizeObserver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ import type { DeepReadonly, Ref } from 'vue'
import { IN_BROWSER } from '@/util/globals'

interface ResizeState {
resizeRef: Ref<Element | undefined>
resizeRef: Ref<HTMLElement | undefined>
contentRect: DeepReadonly<Ref<DOMRectReadOnly | undefined>>
}

export function useResizeObserver (callback?: ResizeObserverCallback): ResizeState {
const resizeRef = ref<Element>()
const resizeRef = ref<HTMLElement>()
const contentRect = ref<DOMRectReadOnly>()

if (IN_BROWSER) {
Expand Down

0 comments on commit 7190d27

Please sign in to comment.