feat(color-select-panel): add color-update event (#884)

* feat(color-select-panel): add color-select event

* fix(color-picker): extract functions to index.ts

* style: remove semicolon
This commit is contained in:
GaoNeng 2023-11-23 09:31:35 +08:00 committed by GitHub
parent c2277b8d5b
commit 9ea7373a0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 169 additions and 407 deletions

View File

@ -117,6 +117,15 @@ export default {
'en-US': 'When click cancel or click out-side will trigger cancel event'
},
demoId: 'event'
},
{
name: 'color-update',
type: '(color:Color) => void',
defaultValue: '',
desc:{
'zh-cn': '当颜色更新的时候会触发该事件,包括:点击预定义颜色、点击历史记录',
'en-US': 'when click predefine color or history, will trigger color-update event'
}
}
],
'slots': []

View File

@ -1,23 +0,0 @@
import type { IColorSelectPanel } from '@/types'
export const calcLeftByAlpha = (wrapper: HTMLElement, thumb: HTMLElement, alpha: number) => {
return Math.round((alpha * (wrapper.offsetWidth - thumb.offsetWidth / 2)) / 100)
}
export const updateThumb = (alpha: number, thumb: HTMLElement, wrapper: HTMLElement) => {
thumb.style.left = `${calcLeftByAlpha(wrapper, thumb, alpha)}px`
}
export const onDrag = (
event: MouseEvent,
bar: IColorSelectPanel<HTMLElement>,
thumb: IColorSelectPanel<HTMLElement>,
alpha: IColorSelectPanel<number>
) => {
const rect = bar.value.getBoundingClientRect()
const { clientX } = event
let left = clientX - rect.left
left = Math.max(thumb.value.offsetWidth / 2, left)
left = Math.min(left, rect.width - thumb.value.offsetWidth / 2)
alpha.value = Math.round(((left - thumb.value.offsetWidth / 2) / (rect.width - thumb.value.offsetWidth)) * 100)
}

View File

@ -1,58 +0,0 @@
import { IColorPickerRef as Ref } from '@/types'
import Color from '../utils/color'
import { draggable } from '../utils/use-drag'
import { onDrag, updateThumb } from '.'
export const api = ['state', 'color', 'slider', 'alphaWrapper', 'alphaThumb']
export const renderless = (props, context, { emit }) => {
const hex = props.color
const color = new Color(hex, props.alpha)
const [rr, gg, bb] = color.getRGB()
const r = context.ref(rr)
const g = context.ref(gg)
const b = context.ref(bb)
const slider: Ref<HTMLElement> = context.ref()
const alphaWrapper: Ref<HTMLElement> = context.ref()
const alphaThumb: Ref<HTMLElement> = context.ref()
const alpha = context.ref(color.get('a'))
context.watch(
() => props.color,
(hex: string) => {
color.reset(hex)
const [rr, gg, bb] = color.getRGB()
r.value = rr
g.value = gg
b.value = bb
}
)
context.watch(alpha, (newAlpha) => {
updateThumb(newAlpha, alphaThumb.value, alphaWrapper.value)
emit('alpha-update', alpha.value)
})
const background = context.computed(() => {
return `linear-gradient(to right, rgba(${r.value}, ${g.value}, ${b.value}, 0) 0%, rgba(${r.value}, ${g.value}, ${b.value}, 1) 100%)`
})
const state = context.reactive({
background,
hex
})
const api = {
state,
slider,
alphaWrapper,
alphaThumb
}
context.onMounted(() => {
updateThumb(alpha.value, alphaThumb.value, slider.value)
draggable(slider.value, {
drag(event) {
onDrag(event as MouseEvent, slider, alphaThumb, alpha)
},
start(event) {
onDrag(event as MouseEvent, slider, alphaThumb, alpha)
}
})
})
return api
}

View File

@ -1,80 +0,0 @@
import { IColorSelectPanel } from '@/types'
import type Color from '../utils/color'
export const setPosition = (el: HTMLElement, x: number, y: number) => {
el.style.top = `${y}px`
el.style.left = `${x}px`
}
export const getXBySaturation = (s: number, width: number) => (s * width) / 100
export const getYByLight = (l: number, height: number) => ((100 - l) * height) / 100
export const updatePosition = (
event: MouseEvent | TouchEvent,
rect: DOMRect,
cursor: IColorSelectPanel<HTMLElement>
) => {
let x = (event as MouseEvent).clientX - rect.left
let y = (event as MouseEvent).clientY - rect.top
x = Math.max(0, x)
x = Math.min(x, rect.width)
y = Math.max(0, y)
y = Math.min(y, rect.height)
setPosition(cursor.value, x - (1 / 2) * cursor.value.offsetWidth, y - (1 / 2) * cursor.value.offsetWidth)
return { x, y }
}
export const calcSaturation = (x: number, width: number) => x / width
export const calcBrightness = (y: number, height: number) => 100 - (y / height) * 100
export const getThumbTop = (wrapper: HTMLElement, thumb: HTMLElement, hue: number) => {
return Math.round((hue * (wrapper.offsetHeight - thumb.offsetHeight / 2)) / 360)
}
export const resetCursor = (
s: number,
v: number,
wrapper: IColorSelectPanel<HTMLElement>,
cursor: IColorSelectPanel<HTMLElement>,
thumb: IColorSelectPanel<HTMLElement>,
color: Color,
h: IColorSelectPanel<number>
) => {
const { width, height } = wrapper.value.getBoundingClientRect()
const x = getXBySaturation(s, width) - (1 / 2) * cursor.value.offsetWidth
const y = getYByLight(v, height) - (1 / 2) * cursor.value.offsetWidth
setPosition(cursor.value, x < 0 ? 0 : x, y < 0 ? 0 : y)
const thummbTop = getThumbTop(wrapper.value, thumb.value, color.get('h'))
thumb.value.style.top = `${thummbTop}px`
h.value = color.get('h')
}
export const updateCursor = (wrapper: IColorSelectPanel<HTMLElement>, cursor: IColorSelectPanel<HTMLElement>, emit) => {
return (color: Color, event: MouseEvent) => {
const rect = wrapper.value.getBoundingClientRect()
const { x, y } = updatePosition(event, rect, cursor)
color.set({
s: calcSaturation(x, rect.width) * 100,
v: calcBrightness(y, rect.height)
})
emit('sv-update', {
s: color.get('s'),
v: color.get('v')
})
}
}
export const updateThumb = (
bar: IColorSelectPanel<HTMLElement>,
thumb: IColorSelectPanel<HTMLElement>,
h: IColorSelectPanel<Number>,
emit
) => {
return (event: MouseEvent) => {
const e = event as MouseEvent
const rect = bar.value.getBoundingClientRect()
let top = e.clientY - rect.top
top = Math.min(top, rect.height - thumb.value.offsetHeight / 2)
top = Math.max(thumb.value.offsetHeight / 2, top)
thumb.value.style.top = `${top}px`
h.value = Math.round(((top - thumb.value.offsetHeight / 2) / (rect.height - thumb.value.offsetHeight)) * 360)
emit('hue-update', h.value)
}
}

View File

@ -1,55 +0,0 @@
import { IColorSelectPanel as Ref } from '@/types'
import { draggable } from '../utils/use-drag'
import Color from '../utils/color'
import { getThumbTop, resetCursor, updateThumb, updateCursor } from './index'
export const api = ['state', 'cursor', 'wrapper', 'bar', 'thumb']
export const renderless = (props, context, { emit }) => {
const cursor: Ref<HTMLElement> = context.ref()
const wrapper: Ref<HTMLElement> = context.ref()
const thumb: Ref<HTMLElement> = context.ref()
const bar: Ref<HTMLElement> = context.ref()
const color = new Color(props.color)
const h = context.ref(color.get('h'))
const background = context.computed(() => {
return `hsl(${h.value}deg, 100%, 50%)`
})
const state = context.reactive({
background
})
const api = { state, cursor, wrapper, bar, thumb }
context.watch(
() => props.color,
(newColor) => {
color.reset(newColor)
resetCursor(color.get('s'), color.get('v'), wrapper, cursor, thumb, color, h)
}
)
context.onMounted(() => {
const update = {
thumb: updateThumb(bar, thumb, h, emit),
cursor: updateCursor(wrapper, cursor, emit)
}
const thumbTop = getThumbTop(wrapper.value, thumb.value, h.value)
thumb.value.style.top = `${thumbTop}px`
resetCursor(color.get('s'), color.get('v'), wrapper, cursor, thumb, color, h)
draggable(wrapper.value, {
drag(event) {
update.cursor(color, event as MouseEvent)
},
start(event) {
update.cursor(color, event as MouseEvent)
}
})
draggable(bar.value, {
drag(event) {
update.thumb(event as MouseEvent)
},
start(event) {
update.thumb(event as MouseEvent)
}
})
})
return api
}

View File

@ -1,68 +1,61 @@
import { IColorPickerRef, IColorSelectPanelRef } from '@/types'
import { IColorPickerRef as Ref } from '@/types'
import type Color from './utils/color'
export const onConfirm = (
hex: IColorSelectPanelRef<string>,
triggerBg: IColorSelectPanelRef<string>,
res: IColorSelectPanelRef<string>,
emit,
isShow: IColorSelectPanelRef<boolean>,
prev: IColorPickerRef<string>
) => {
return (color: string) => {
prev.value = res.value;
res.value = color
hex.value = res.value
triggerBg.value = res.value
emit('confirm', res.value)
isShow.value = false
}
}
export const onCancel = (
res: IColorSelectPanelRef<string>,
triggerBg: IColorSelectPanelRef<string>,
emit,
isShow: IColorSelectPanelRef<boolean>,
hex: IColorSelectPanelRef<string>,
color: Color, prev: IColorPickerRef<string>
tmpColor: Color,
triggerBg: Ref<string>,
isShow: Ref<boolean>,
pre: Ref<string>,
emit
) => {
return () => {
if (isShow.value) {
res.value = prev.value;
hex.value = prev.value;
triggerBg.value = prev.value;
color.reset(hex.value)
emit('cancel')
}
return (color: Ref<Color>)=>{
tmpColor.reset(color.value.getHex())
triggerBg.value = pre.value
isShow.value = false
}
}
export const onColorUpdate = (color: Color, res: IColorSelectPanelRef<string>, triggerBg: IColorPickerRef<string>) => {
res.value = color.getHex()
triggerBg.value = color.getHex();
}
export const onHSVUpdate = (color: Color, res: IColorSelectPanelRef<string>, hex: IColorSelectPanelRef<string>, triggerBg: IColorSelectPanelRef<string>) => {
return {
onHueUpdate: (hue: number) => {
color.set({ h: hue })
onColorUpdate(color, res, triggerBg)
hex.value = color.getHex()
},
onSVUpdate: ({ s, v }: { s: number; v: number }) => {
color.set({ h: color.get('h'), s, v })
onColorUpdate(color, res, triggerBg)
hex.value = color.getHex();
}
emit('cancel')
}
}
export const onAlphaUpdate = (color: Color, res: IColorSelectPanelRef<string>, triggerBg: IColorSelectPanelRef<string>) => {
return {
update: (alpha: number) => {
color.set({ a: alpha })
onColorUpdate(color, res, triggerBg)
}
export const onConfirm = (
triggerBg: Ref<string>,
pre: Ref<string>,
hex: Ref<string>,
isShow: Ref<boolean>,
emit
) => {
return (color: string)=>{
pre.value = triggerBg.value
triggerBg.value = color
hex.value = color
isShow.value = false
emit('confirm', color)
}
}
export const onHueUpdate = (
tmpColor: Color,
triggerBg: Ref<string>
) => {
return (h: number) => {
triggerBg.value = tmpColor.getHex();
tmpColor.set({h})
}
}
export const onSVUpdate = (
tmpColor: Color,
triggerBg: Ref<string>
) => {
return ({s,v})=>{
triggerBg.value = tmpColor.getHex();
tmpColor.set({s,v})
}
}
export const onColorUpdate = (
triggerBg: Ref<string>
) => {
return (color: Ref<Color>) => {
triggerBg.value = color.value.getHex();
}
}

View File

@ -7,7 +7,7 @@ function hexToRgb(hex: string) {
let a = parseInt(hex.slice(7), 16) / 255
return { r, g, b, a: a * 100 }
}
const normalizeHexColor = (color: string) => {
export const normalizeHexColor = (color: string) => {
let normalizedColor: string = color.replace('#', '')
if (normalizedColor.length === 3) {
normalizedColor = normalizedColor
@ -40,6 +40,7 @@ export default class Color {
private s = 0
private v = 0
private a = 100
private preH = 0;
private enableAlpha = false
constructor(value: string, alpha = false) {
this.reset(value)
@ -61,14 +62,17 @@ export default class Color {
this.s = s
this.v = v
this.a = a
this.preH = h;
}
set({ h, s, v, a }: { h?: number; s?: number; v?: number; a?: number }) {
this.h = h ?? this.h
this.s = s ?? this.s
this.v = v ?? this.v
this.a = a ?? this.a
}
setPrevH(val: number){
this.preH = val;
}
/**
*
@ -104,7 +108,7 @@ export default class Color {
}
}
get(key: 'h' | 's' | 'v' | 'a') {
get(key: 'h' | 's' | 'v' | 'a' |'preH') {
return this[key]
}
}

View File

@ -1,43 +0,0 @@
let isDragging = false
export interface DraggableOptions {
drag?: (event: MouseEvent | TouchEvent) => void
start?: (event: MouseEvent | TouchEvent) => void
end?: (event: MouseEvent | TouchEvent) => void
}
export function draggable(element: HTMLElement, options: DraggableOptions) {
const moveFn = function (event: MouseEvent | TouchEvent) {
options.drag?.(event)
}
const upFn = function (event: MouseEvent | TouchEvent) {
document.removeEventListener('mousemove', moveFn)
document.removeEventListener('mouseup', upFn)
document.removeEventListener('touchmove', moveFn)
document.removeEventListener('touchend', upFn)
document.onselectstart = null
document.ondragstart = null
isDragging = false
options.end?.(event)
}
const downFn = function (event: MouseEvent | TouchEvent) {
if (isDragging) return
event.preventDefault()
document.onselectstart = () => false
document.ondragstart = () => false
document.addEventListener('mousemove', moveFn)
document.addEventListener('mouseup', upFn)
document.addEventListener('touchmove', moveFn)
document.addEventListener('touchend', upFn)
isDragging = true
options.start?.(event)
}
element.addEventListener('mousedown', downFn)
element.addEventListener('touchstart', downFn)
}

View File

@ -1,6 +1,6 @@
import { IColorSelectPanelRef as Ref } from '@/types'
import Color from './utils/color'
import { onConfirm, onCancel, onHSVUpdate, onAlphaUpdate } from '.'
import { onConfirm, onCancel, onHueUpdate, onSVUpdate, onColorUpdate } from './index'
export const api = [
'state',
@ -17,12 +17,11 @@ export const api = [
export const renderless = (props, context, { emit }) => {
const { modelValue, visible, predefine, size, history } = context.toRefs(props)
const pre = context.ref(modelValue.value ?? 'transparent')
const triggerBg = context.ref(pre.value ?? 'transparent')
const tmpColor = new Color(triggerBg.value ?? 'transparent')
const hex = context.ref(modelValue.value ?? 'transparent')
const res = context.ref(modelValue.value ?? 'transparent')
const prev = context.ref(modelValue.value ?? 'transparent')
const triggerBg = context.ref(modelValue.value ?? 'transparent')
const isShow = context.ref(visible?.value ?? false)
const cursor: Ref<HTMLElement> = context.ref()
const changeVisible = (state: boolean) => {
isShow.value = state
}
@ -32,46 +31,38 @@ export const renderless = (props, context, { emit }) => {
const predefineStack: Ref<string[]> = context.ref(
[...(predefine?.value ?? [])]
)
const color = new Color(hex.value, props.alpha)
const state = context.reactive({
isShow,
hex,
color,
triggerBg,
defaultValue: modelValue,
res,
stack,
predefineStack,
size: size ?? '',
stack
size: size ?? ''
})
const api = {
state,
changeVisible,
onCancel: onCancel(tmpColor, triggerBg, isShow, pre, emit),
onConfirm: onConfirm(triggerBg, pre, hex, isShow, emit),
onHueUpdate: onHueUpdate(tmpColor, triggerBg),
onSVUpdate: onSVUpdate(tmpColor, triggerBg),
onColorUpdate: onColorUpdate(triggerBg)
}
context.watch(predefine, (newPredefine: string[]) => {
predefineStack.value = [...newPredefine];
predefineStack.value = [...newPredefine]
}, { deep: true })
context.watch(history, (newHistory: string[]) => {
stack.value = [...newHistory]
}, { deep: true })
context.watch(modelValue, (newValue) => {
context.watch(modelValue, (newValue)=>{
pre.value = newValue
hex.value = newValue
res.value = newValue
triggerBg.value = newValue
prev.value = newValue;
color.reset(hex.value)
state.hex = newValue
state.triggerBg = newValue;
})
context.watch(visible, (visible) => {
context.watch(visible, (visible)=>{
isShow.value = visible
})
const { onHueUpdate, onSVUpdate } = onHSVUpdate(color, res, hex, triggerBg)
const { update } = onAlphaUpdate(color, res, triggerBg)
const api = {
state,
changeVisible,
onHueUpdate,
onSVUpdate,
onConfirm: onConfirm(hex, triggerBg, res, emit, isShow, prev),
onCancel: onCancel(res, triggerBg, emit, isShow, hex, color, prev),
onAlphaUpdate: update,
cursor
}
return api
}

View File

@ -6,8 +6,7 @@ import { onDrag, updateThumb } from '.'
export const api = ['state', 'color', 'slider', 'alphaWrapper', 'alphaThumb']
export const renderless = (props, context, { emit }) => {
const hex = props.color
const color = new Color(hex, props.alpha)
const color:Color = props.color
const [rr, gg, bb] = color.getRGB()
const r = context.ref(rr)
const g = context.ref(gg)
@ -18,14 +17,13 @@ export const renderless = (props, context, { emit }) => {
const alpha = context.ref(color.get('a'))
context.watch(
() => props.color,
(hex: string) => {
color.reset(hex)
() => {
const [rr, gg, bb] = color.getRGB()
r.value = rr
g.value = gg
b.value = bb
alpha.value = color.get('a')
}
}, {deep: true}
)
context.watch(alpha, (newAlpha) => {
updateThumb(newAlpha, alphaThumb.value, alphaWrapper.value)
@ -36,7 +34,6 @@ export const renderless = (props, context, { emit }) => {
})
const state = context.reactive({
background,
hex
})
const api = {
state,

View File

@ -56,11 +56,13 @@ export const updateCursor = (
const { x, y } = updatePosition(event, rect, cursor)
color.set({
s: calcSaturation(x, rect.width) * 100,
v: calcBrightness(y, rect.height)
v: calcBrightness(y, rect.height),
h: color.get('h')
})
emit('sv-update', {
s: color.get('s'),
v: color.get('v')
v: color.get('v'),
h: color.get('h')
})
}
}

View File

@ -1,31 +1,30 @@
import { IColorSelectPanelRef as Ref } from '@/types'
import { draggable } from '../utils/use-drag'
import Color from '../utils/color'
import { getThumbTop, resetCursor, updateThumb, updateCursor } from './index'
import Color from '../utils/color'
export const api = ['state', 'cursor', 'wrapper', 'bar', 'thumb']
export const renderless = (props, context, { emit }) => {
export const renderless = (props, context, { emit, expose }) => {
const cursor: Ref<HTMLElement> = context.ref()
const wrapper: Ref<HTMLElement> = context.ref()
const thumb: Ref<HTMLElement> = context.ref()
const bar: Ref<HTMLElement> = context.ref()
const color = new Color(props.color)
const color:Color = props.color
const h = context.ref(color.get('h'))
const background = context.computed(() => {
return `hsl(${h.value}deg, 100%, 50%)`
})
const background:string = `hsl(${h.value}deg, 100%, 50%)`
const state = context.reactive({
background
})
const api = { state, cursor, wrapper, bar, thumb }
context.watch(
() => props.color,
(newColor) => {
color.reset(newColor)
resetCursor(color.get('s'), color.get('v'), wrapper, cursor, thumb, color, h)
}
)
context.watch(()=>props, ()=>{
h.value = color.get('h')
resetCursor(color.get('s'), color.get('v'), wrapper, cursor, thumb, color, h)
}, {deep: true})
context.watch(h,(newHue: string) => {
state.background = `hsl(${newHue}deg, 100%, 50%)`
})
context.onMounted(() => {
const update = {
thumb: updateThumb(bar, thumb, h, emit),

View File

@ -1,17 +1,18 @@
import { IColorSelectPanelRef } from '@/types'
import type Color from './utils/color'
import Color from './utils/color'
export const onConfirm = (
hex: IColorSelectPanelRef<string>,
triggerBg: IColorSelectPanelRef<string>,
pre: IColorSelectPanelRef<string>,
res: IColorSelectPanelRef<string>,
emit,
stack: IColorSelectPanelRef<string[]>,
enableHistory: boolean
enableHistory: boolean,
color: IColorSelectPanelRef<Color>
) => {
return () => {
pre.value = hex.value
hex.value = res.value
triggerBg.value = res.value
if (enableHistory) {
const itemIdx = Math.max(
stack.value.indexOf(res.value),
@ -23,56 +24,61 @@ export const onConfirm = (
}
stack.value.unshift(res.value)
}
color.value.setPrevH(color.value.get('h'))
emit('confirm', res.value)
}
}
export const onCancel = (
res: IColorSelectPanelRef<string>,
triggerBg: IColorSelectPanelRef<string>,
pre: IColorSelectPanelRef<string>,
emit,
isShow: IColorSelectPanelRef<boolean>,
hex: IColorSelectPanelRef<string>,
color: Color
color: IColorSelectPanelRef<Color>
) => {
return () => {
if (isShow.value) {
res.value = triggerBg.value
hex.value = triggerBg.value
color.reset(hex.value)
emit('cancel')
res.value = pre.value
hex.value = pre.value
const tmpColor = new Color(pre.value)
color.value.set({
...tmpColor.getHSV(),
h: color.value.get('preH')
})
emit('cancel', color)
}
}
}
export const onColorUpdate = (color: Color, res: IColorSelectPanelRef<string>) => {
res.value = color.getHex()
export const onColorUpdate = (color: IColorSelectPanelRef<Color>, res: IColorSelectPanelRef<string>) => {
res.value = color.value.getHex()
}
export const onHSVUpdate = (
color: Color,
color: IColorSelectPanelRef<Color>,
res: IColorSelectPanelRef<string>,
hex: IColorSelectPanelRef<string>,
emit
) => {
return {
onHueUpdate: (hue: number) => {
color.set({ h: hue })
color.value.set({ h: hue })
onColorUpdate(color, res)
hex.value = color.getHex()
hex.value = color.value.getHex()
emit('hue-update', hue)
},
onSVUpdate: ({ s, v }: { s: number; v: number }) => {
color.set({ s, v })
hex.value = color.value.getHex()
onColorUpdate(color, res)
emit('sv-update', { s, v })
}
}
}
export const onAlphaUpdate = (color: Color, res: IColorSelectPanelRef<string>) => {
export const onAlphaUpdate = (color: IColorSelectPanelRef<Color>, res: IColorSelectPanelRef<string>) => {
return {
update: (alpha: number) => {
color.set({ a: alpha })
color.value.set({ a: alpha })
onColorUpdate(color, res)
}
}
@ -81,23 +87,33 @@ export const onAlphaUpdate = (color: Color, res: IColorSelectPanelRef<string>) =
export const handleHistoryClick = (
hex: IColorSelectPanelRef<string>,
res: IColorSelectPanelRef<string>,
color: Color
color: IColorSelectPanelRef<Color>,
emit
) => {
return (history: string) => {
hex.value = history
res.value = history
color.reset(history)
const tmpColor = new Color(history)
color.value.set({
...tmpColor.getHSV(),
})
emit('color-update', color)
}
}
export const handlePredefineClick = (
hex: IColorSelectPanelRef<string>,
res: IColorSelectPanelRef<string>,
color: Color
color: IColorSelectPanelRef<Color>,
emit
) => {
return (selectedColor: string) => {
hex.value = selectedColor
res.value = selectedColor
color.reset(selectedColor)
const tmpColor = new Color(selectedColor)
color.value.set({
...tmpColor.getHSV(),
})
emit('color-update', color)
}
}

View File

@ -40,6 +40,7 @@ export default class Color {
private s = 0
private v = 0
private a = 100
private preH = 0
private enableAlpha = false
constructor(value: string, alpha = false) {
this.reset(value)
@ -57,18 +58,21 @@ export default class Color {
this.hex = normalizeHexColor(hex)
const { r, g, b, a } = hexToRgb(this.hex)
const { h, s, v } = rgb([r, g, b, a]).hsv().object()
this.preH = h
this.h = h
this.s = s
this.v = v
this.a = a
}
set({ h, s, v, a }: { h?: number; s?: number; v?: number; a?: number }) {
this.h = h ?? this.h
this.s = s ?? this.s
this.v = v ?? this.v
this.a = a ?? this.a
}
setPrevH(val: number){
this.preH = val
}
/**
*
@ -104,7 +108,7 @@ export default class Color {
}
}
get(key: 'h' | 's' | 'v' | 'a') {
get(key: 'h' | 's' | 'v' | 'a' |'preH') {
return this[key]
}
}

View File

@ -20,6 +20,7 @@ export const renderless = (props, context, { emit }) => {
const { modelValue, visible, history, predefine } = context.toRefs(props)
const hex = context.ref(modelValue?.value ?? 'transparent')
const res = context.ref(modelValue?.value ?? 'transparent')
const pre = context.ref(res.value)
const triggerBg = context.ref(modelValue?.value ?? 'transparent')
const isShow = context.ref(visible?.value ?? false)
const cursor: Ref<HTMLElement> = context.ref()
@ -30,7 +31,7 @@ export const renderless = (props, context, { emit }) => {
const changeVisible = (state: boolean) => {
isShow.value = state
}
const color = new Color(hex.value, props.alpha)
const color:Ref<Color> = context.ref(new Color(hex.value, props.alpha))
const state = context.reactive({
isShow,
hex,
@ -57,11 +58,15 @@ export const renderless = (props, context, { emit }) => {
},
{ deep: true }
)
context.watch(state,()=>{
state.color = state.color
}, {deep: true})
context.watch(modelValue, (newValue) => {
pre.value = res.value
hex.value = newValue
res.value = newValue
triggerBg.value = newValue
color.reset(hex.value)
color.value.reset(newValue)
state.color.reset(newValue)
})
context.watch(visible, (visible) => {
isShow.value = visible
@ -73,11 +78,11 @@ export const renderless = (props, context, { emit }) => {
changeVisible,
onHueUpdate,
onSVUpdate,
onConfirm: onConfirm(hex, triggerBg, res, emit, stack, enableHistory),
onCancel: onCancel(res, triggerBg, emit, isShow, hex, color),
onConfirm: onConfirm(hex, pre, res, emit, stack, enableHistory, color),
onCancel: onCancel(res, pre, emit, isShow, hex, color),
onAlphaUpdate: update,
onHistoryClick: handleHistoryClick(hex, res, color),
onPredefineColorClick: handlePredefineClick(hex, res, color),
onHistoryClick: handleHistoryClick(hex, res, color, emit),
onPredefineColorClick: handlePredefineClick(hex, res, color, emit),
cursor
}
return api

View File

@ -21,6 +21,7 @@
@cancel="onCancel"
@hue-update="onHueUpdate"
@sv-update="onSVUpdate"
@color-update="onColorUpdate"
v-model="state.hex"
:visible="state.isShow"
:alpha="alpha"

View File

@ -25,7 +25,7 @@ export default defineComponent({
emits: ['alpha-update'],
props: {
color: {
type: String
type: Object
}
},
setup(props, context) {

View File

@ -25,7 +25,7 @@ export default defineComponent({
emits: ['hue-update', 'sv-update'],
props: {
color: {
type: String
type: Object
},
alpha: {
type: Boolean

View File

@ -1,7 +1,7 @@
<template>
<div class="tiny-color-select-panel__wrapper" @click.stop v-if="state.isShow" v-clickoutside="onCancel">
<hue-select :color="state.hex" @hue-update="onHueUpdate" @sv-update="onSVUpdate" />
<alpha-select v-if="alpha" :color="state.res" @alpha-update="onAlphaUpdate" />
<hue-select :color="state.color" @hue-update="onHueUpdate" @sv-update="onSVUpdate" />
<alpha-select v-if="alpha" :color="state.color" @alpha-update="onAlphaUpdate" />
<div class="tiny-color-select-panel__wrapper__tools">
<tiny-input v-model="state.res" />
<tiny-button-group>
@ -65,7 +65,7 @@ import Clickoutside from '@opentiny/vue-renderless/common/deps/clickoutside'
import { t } from '@opentiny/vue-locale'
export default defineComponent({
emits: ['update:modelValue', 'cancel', 'confirm', 'hue-update', 'sv-update'],
emits: ['update:modelValue', 'cancel', 'confirm', 'hue-update', 'sv-update', 'color-update'],
props: [...props, 'modelValue', 'visible', 'alpha', 'history', 'predefine'],
components: {
hueSelect: HueSelect,