import React, { useEffect, useState } from "react"; import { t } from "../../i18n"; import { ExcalidrawElement } from "../../element/types"; import { ShadeList } from "./ShadeList"; import PickerColorList from "./PickerColorList"; import { useAtom } from "jotai"; import { CustomColorList } from "./CustomColorList"; import { colorPickerKeyNavHandler } from "./keyboardNavHandlers"; import PickerHeading from "./PickerHeading"; import { ColorPickerType, activeColorPickerSectionAtom, getColorNameAndShadeFromColor, getMostUsedCustomColors, isCustomColor, } from "./colorPickerUtils"; import { ColorPaletteCustom, DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX, DEFAULT_ELEMENT_STROKE_COLOR_INDEX, } from "../../colors"; import { KEYS } from "../../keys"; import { EVENT } from "../../constants"; interface PickerProps { color: string; onChange: (color: string) => void; label: string; type: ColorPickerType; elements: readonly ExcalidrawElement[]; palette: ColorPaletteCustom; updateData: (formData?: any) => void; children?: React.ReactNode; onEyeDropperToggle: (force?: boolean) => void; onEscape: (event: React.KeyboardEvent | KeyboardEvent) => void; } export const Picker = ({ color, onChange, label, type, elements, palette, updateData, children, onEyeDropperToggle, onEscape, }: PickerProps) => { const [customColors] = React.useState(() => { if (type === "canvasBackground") { return []; } return getMostUsedCustomColors(elements, type, palette); }); const [activeColorPickerSection, setActiveColorPickerSection] = useAtom( activeColorPickerSectionAtom, ); const colorObj = getColorNameAndShadeFromColor({ color, palette, }); useEffect(() => { if (!activeColorPickerSection) { const isCustom = isCustomColor({ color, palette }); const isCustomButNotInList = isCustom && !customColors.includes(color); setActiveColorPickerSection( isCustomButNotInList ? "hex" : isCustom ? "custom" : colorObj?.shade != null ? "shades" : "baseColors", ); } }, [ activeColorPickerSection, color, palette, setActiveColorPickerSection, colorObj, customColors, ]); const [activeShade, setActiveShade] = useState( colorObj?.shade ?? (type === "elementBackground" ? DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX : DEFAULT_ELEMENT_STROKE_COLOR_INDEX), ); useEffect(() => { if (colorObj?.shade != null) { setActiveShade(colorObj.shade); } const keyup = (event: KeyboardEvent) => { if (event.key === KEYS.ALT) { onEyeDropperToggle(false); } }; document.addEventListener(EVENT.KEYUP, keyup, { capture: true }); return () => { document.removeEventListener(EVENT.KEYUP, keyup, { capture: true }); }; }, [colorObj, onEyeDropperToggle]); const pickerRef = React.useRef(null); return (
{ const handled = colorPickerKeyNavHandler({ event, activeColorPickerSection, palette, color, onChange, onEyeDropperToggle, customColors, setActiveColorPickerSection, updateData, activeShade, onEscape, }); if (handled) { event.preventDefault(); event.stopPropagation(); } }} className="color-picker-content" // to allow focusing by clicking but not by tabbing tabIndex={-1} > {!!customColors.length && (
{t("colorPicker.mostUsedCustomColors")}
)}
{t("colorPicker.colors")}
{t("colorPicker.shades")}
{children}
); };