import { RGBA } from '@vev/utils'; import { isString } from 'lodash'; import React, { useEffect, useRef, useState } from 'react'; import tinycolor, { ColorFormats } from 'tinycolor2'; import { SilkeBox } from '../silke-box'; import { SilkeButton } from '../silke-button'; import { SilkeSwatches } from '../silke-color-swatches'; import { useSilkeCSSContext } from '../silke-css-number-field'; import { SilkeModal, SilkeModalActions, SilkeModalContent } from '../silke-modal'; import { TextFieldContext } from '../silke-text-field'; import { getColorVariableValue, getVariableValueV2, hsvToRgb, isColorVariable, isVariableV2, rgbToHsv, } from './color'; import styles from './color-picker.scss'; import { ColorInfo } from './silke-color-info'; import { ColorSpace } from './silke-color-space'; import { SilkeHueSlider } from './silke-hue-slider'; import { SilkeOpacitySlider } from './silke-opacity-slider'; const TRANSPARENT: ColorFormats.RGBA = { r: 0, b: 0, g: 0, a: 0 }; declare global { const EyeDropper: undefined | (new () => { open(): Promise<{ sRGBHex: string }> }); } export type SilkeColorPickerProps = { value: string; hideSwatches?: boolean; hidePalettes?: boolean; noVariables?: boolean; noTransparency?: boolean; onChange: (color: string) => void; }; export function SilkeColorPicker({ value, hidePalettes, hideSwatches, noVariables, noTransparency, onChange, }: SilkeColorPickerProps) { const dragging = useRef(false); const [eyeDropperActive, setEyeDropperActive] = useState(false); const [showEyeDropUnsupported, setShowEyeDropUnsupported] = useState(false); const { variables, variablesv2 } = useSilkeCSSContext(); const isValueVariableV2 = isVariableV2(value); const isValueVariable = isColorVariable(value) && !isValueVariableV2; const rgba = React.useMemo(() => { if (!value) { return TRANSPARENT; } if (isValueVariable) { return tinycolor(getColorVariableValue(value, variables)).toRgb(); } if (isValueVariableV2) { return tinycolor(getVariableValueV2(value, variablesv2)).toRgb(); } return tinycolor(value).toRgb(); }, [value, isValueVariable, isValueVariableV2, variables, variablesv2]); const [hue, setHue] = React.useState(0); useEffect(() => { if (!dragging.current) { setHue((cur) => { const { h } = rgbToHsv({ h: cur }, rgba); return Math.abs(Math.round(h * 100) - cur * 100) > 1.5 ? h : cur; }); } }, [rgba, setHue]); const handleChange = (v: string | RGBA) => { if (isString(v) && /\$|var/.test(v)) { if (noVariables) onChange(getColorVariableValue(v, variables)); else onChange(v); } else { const color = tinycolor(v); if ((!value || value === 'transparent') && !color.getAlpha()) color.setAlpha(1); onChange(color.getAlpha() === 1 ? color.toHexString() : color.toRgbString()); } }; const handleDrag = (isDragging: boolean) => (dragging.current = isDragging); const handleHue = (h: number) => { setHue(h); const hsv = rgbToHsv({}, rgba); hsv.h = h; handleChange(hsvToRgb(hsv)); }; return ( { if (typeof EyeDropper === 'undefined') { setShowEyeDropUnsupported(true); } else { try { setEyeDropperActive(true); const eyeDropper = new EyeDropper(); const { sRGBHex } = await eyeDropper.open(); onChange(sRGBHex); setEyeDropperActive(false); } catch { setEyeDropperActive(false); } } }} /> {!noTransparency && } {!(hidePalettes && hideSwatches) && ( )} {showEyeDropUnsupported && ( setShowEyeDropUnsupported(false)} > Eye dropper is unfurtunatley not supported in your browser.
You need chrome 95+ to use this feature
setShowEyeDropUnsupported(false)} />
)}
); }