"use client"; import { hexToHsva } from "@noya-app/noya-color"; import React, { useCallback, useState } from "react"; import useEyeDropper from "use-eye-dropper"; import { useColorPicker } from "../contexts/ColorPickerContext"; type DropperError = { message: string; canceled?: boolean; }; const isError = (err: DropperError | T): err is DropperError => !!err && err instanceof Error && !!err.message; const isNotCanceled = (err: DropperError | T): err is DropperError => isError(err) && !err.canceled; export function EyeDropper( props: React.DetailedHTMLProps< React.ButtonHTMLAttributes, HTMLButtonElement > ) { const [_hsva, onChange] = useColorPicker(); const { open } = useEyeDropper(); const [_error, setError] = useState(); // useEyeDropper will reject/cleanup the open() promise on unmount, // so setState never fires when the component is unmounted. const pickColor = useCallback(() => { // Using async/await (can be used as a promise as-well) const openPicker = async () => { try { const color = await open(); onChange(hexToHsva(color.sRGBHex)); } catch (e) { console.log(e); // Ensures component is still mounted // before calling setState if (isNotCanceled(e)) { setError(e); } } }; openPicker(); }, [open]); return ( ); }