import { useCallback, useRef, useState } from "react"; import { useEffect } from "react"; import { HexColorInput, HexColorPicker } from "react-colorful"; import { isValidHexCode, fallBackHex } from "@components/CustomBranding"; import Swatch from "@components/Swatch"; type Handler = (event: MouseEvent | Event) => void; function useEventListener< KW extends keyof WindowEventMap, KH extends keyof HTMLElementEventMap, T extends HTMLElement | void = void >( eventName: KW | KH, handler: (event: WindowEventMap[KW] | HTMLElementEventMap[KH] | Event) => void, element?: React.RefObject ) { // Create a ref that stores handler const savedHandler = useRef(); useEffect(() => { // Define the listening target const targetElement: T | Window = element?.current || window; if (!(targetElement && targetElement.addEventListener)) { return; } // Update saved handler if necessary if (savedHandler.current !== handler) { savedHandler.current = handler; } // Create event listener that calls handler function stored in ref const eventListener: typeof handler = (event) => { // eslint-disable-next-line no-extra-boolean-cast if (!!savedHandler?.current) { savedHandler.current(event); } }; targetElement.addEventListener(eventName, eventListener); // Remove event listener on cleanup return () => { targetElement.removeEventListener(eventName, eventListener); }; }, [eventName, element, handler]); } function useOnClickOutside( ref: React.RefObject, handler: Handler, mouseEvent: "mousedown" | "mouseup" = "mousedown" ): void { useEventListener(mouseEvent, (event) => { const el = ref?.current; // Do nothing if clicking ref's element or descendent elements if (!el || el.contains(event.target as Node)) { return; } handler(event); }); } export type ColorPickerProps = { defaultValue: string; onChange: (text: string) => void; }; const ColorPicker = (props: ColorPickerProps) => { const init = !isValidHexCode(props.defaultValue) ? fallBackHex(props.defaultValue) : props.defaultValue; const [color, setColor] = useState(init); const [isOpen, toggle] = useState(false); const popover = useRef() as React.MutableRefObject; const close = useCallback(() => toggle(false), []); useOnClickOutside(popover, close); return (
toggle(!isOpen)} /> {isOpen && (
{ setColor(val); props.onChange(val); }} />
)} { setColor(val); props.onChange(val); }} type="text" />
); }; export default ColorPicker;