123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- 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,
- getColorNameAndShadeFromHex,
- getMostUsedCustomColors,
- isCustomColor,
- } from "./colorPickerUtils";
- import {
- ColorPaletteCustom,
- DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX,
- DEFAULT_ELEMENT_STROKE_COLOR_INDEX,
- } from "../../colors";
- interface PickerProps {
- color: string | null;
- onChange: (color: string) => void;
- label: string;
- type: ColorPickerType;
- elements: readonly ExcalidrawElement[];
- palette: ColorPaletteCustom;
- updateData: (formData?: any) => void;
- children?: React.ReactNode;
- }
- export const Picker = ({
- color,
- onChange,
- label,
- type,
- elements,
- palette,
- updateData,
- children,
- }: PickerProps) => {
- const [customColors] = React.useState(() => {
- if (type === "canvasBackground") {
- return [];
- }
- return getMostUsedCustomColors(elements, type, palette);
- });
- const [activeColorPickerSection, setActiveColorPickerSection] = useAtom(
- activeColorPickerSectionAtom,
- );
- const colorObj = getColorNameAndShadeFromHex({
- hex: color || "transparent",
- 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);
- }
- }, [colorObj]);
- return (
- <div role="dialog" aria-modal="true" aria-label={t("labels.colorPicker")}>
- <div
- onKeyDown={(e) => {
- e.preventDefault();
- e.stopPropagation();
- colorPickerKeyNavHandler({
- e,
- activeColorPickerSection,
- palette,
- hex: color,
- onChange,
- customColors,
- setActiveColorPickerSection,
- updateData,
- activeShade,
- });
- }}
- className="color-picker-content"
- // to allow focusing by clicking but not by tabbing
- tabIndex={-1}
- >
- {!!customColors.length && (
- <div>
- <PickerHeading>
- {t("colorPicker.mostUsedCustomColors")}
- </PickerHeading>
- <CustomColorList
- colors={customColors}
- color={color}
- label={t("colorPicker.mostUsedCustomColors")}
- onChange={onChange}
- />
- </div>
- )}
- <div>
- <PickerHeading>{t("colorPicker.colors")}</PickerHeading>
- <PickerColorList
- color={color}
- label={label}
- palette={palette}
- onChange={onChange}
- activeShade={activeShade}
- />
- </div>
- <div>
- <PickerHeading>{t("colorPicker.shades")}</PickerHeading>
- <ShadeList hex={color} onChange={onChange} palette={palette} />
- </div>
- {children}
- </div>
- </div>
- );
- };
|