ColorInput = props => {
    const {
        id,
        className,
        style,
        value,
        onChange,
        defaultColors,
        variant,
        onClick,
        label,
        labelAlignment,
        hideLabel,
        required,
        readOnly,
        disabled,
        error,
        tabIndex,
        name,
        placeholder,
        bottomHelpText,
        onFocus: focusInProps,
        onBlur: blurInProps,
        size,
        borderRadius,
    } = useReduxForm(props);
    const [isOpen, setIsOpen] = useState(false);
    const [colorValue, setColorValue] = useState(getColorValue(value));
    const [sampleColor, setSampleColor] = useState(value);
    const pickerRef = useRef();
    const containerRef = useRef();
    const triggerRef = useRef();
    const alphaInputRef = useRef();
    const inputRef = useRef();

    const inputId = useUniqueIdentifier('color-input');
    const errorMessageId = useErrorMessageId(error);
    const labelId = useLabelId(label);

    const [focusIndex, setFocusIndex] = useFocusIndex(
        containerRef,
        triggerRef,
        inputRef,
        alphaInputRef,
    );

    useOutsideClick(
        containerRef,
        () => {
            setFocusIndex(-1);
        },
        focusIndex > -1,
    );
    useOutsideClick(
        pickerRef,
        event => {
            if (
                event.target !== triggerRef.current &&
                !triggerRef.current.contains(event.target) &&
                !pickerRef.current.contains(event.target)
            ) {
                setIsOpen(false);
            }
        },
        isOpen,
    );
    useScrollingIntent({
        callback: () => setIsOpen(false),
        isListening: isOpen,
        triggerElementRef: () => triggerRef,
        threshold: 5,
    });
    useWindowResize(() => setIsOpen(false), isOpen);

    const onBlur = useCallback(() => {
        const { hex } = value;
        if (!isHexColor(hex)) setSampleColor(undefined);
        blurInProps(value);
    }, [value, blurInProps]);

    const onFocus = useCallback(() => focusInProps(value), [value, focusInProps]);

    const handleFocus = useHandleFocus({ focusIndex, onFocus, setFocusIndex, value });
    const handleBlur = useHandleBlur({ focusIndex, onBlur, value });

    const handleClick = event => {
        if (focusIndex === 1) {
            setFocusIndex(0);
        } else {
            setFocusIndex(1);
        }

        event.preventDefault();
        if (isOpen) setIsOpen(false);
        else setIsOpen(true);
        return onClick(event);
    };

    const handleChange = event => {
        const eventValue = event.target.value;
        const { alpha } = value;
        const hex = getHexString(eventValue);
        const isValid = isHexColor(hex);
        const newValue = { hex, alpha, isValid };
        if (isValid) {
            setSampleColor(newValue);
            setColorValue(getColorValue(newValue));
        }
        onChange(newValue);
    };

    const handleAlphaChange = event => {
        if (!event.target.value) {
            onChange({ ...value, alpha: null });
            return;
        }

        let alpha = Number.parseInt(event.target.value || '0', 10);
        if (alpha > 100) alpha = 100;
        else if (alpha < 0) alpha = 0;
        alpha /= 100;

        const newValue = { ...value, alpha };
        setSampleColor(newValue);
        setColorValue(getColorValue(newValue));
        if (!Number.isNaN(alpha)) onChange(newValue);
    };

    const handleColorChange = color => {
        const { hex, rgba } = color;
        const newValue = { hex, alpha: rgba[3], isValid: isHexColor(hex) };
        setColorValue(color);
        setSampleColor(newValue);
        onChange(newValue);
    };

    const isFocus = focusIndex > -1 || isOpen;
    const inputValue =
        (value && value.hex) || value.hex === '' ? value.hex.replace('#', '') : '000000';
    const alphaValue =
        (value && value.alpha) || value.alpha === 0 ? Math.round(value.alpha * 100) : '';

    return (
        <StyledContainer id={id} className={className} style={style} ref={containerRef}>
            <Label
                label={label}
                labelAlignment={labelAlignment}
                hideLabel={hideLabel}
                required={required}
                inputId={inputId}
                readOnly={readOnly}
                id={labelId}
                size={size}
            />
            <StyledInputContainer
                disabled={disabled}
                readOnly={readOnly}
                error={error}
                isFocus={isFocus}
                borderRadius={borderRadius}
                size={size}
            >
                <StyledTrigger
                    ref={triggerRef}
                    onClick={handleClick}
                    onFocus={event => handleFocus(event, 0)}
                    onBlur={handleBlur}
                    tabIndex={tabIndex}
                    disabled={disabled}
                    type="button"
                >
                    <StyledFlagContainer disabled={disabled}>
                        <ColorSample value={sampleColor} size={size} />
                        <StyledIndicator error={error} disabled={disabled} />
                    </StyledFlagContainer>
                    <AssistiveText text="pick color" />
                </StyledTrigger>
                <ColorInputContainer>
                    <StyledIconContainer>#</StyledIconContainer>
                    <StyledInput
                        id={inputId}
                        ref={inputRef}
                        name={name}
                        type="text"
                        value={inputValue}
                        placeholder={placeholder}
                        tabIndex={tabIndex}
                        onFocus={event => handleFocus(event, 2)}
                        onBlur={handleBlur}
                        onClick={onClick}
                        onChange={handleChange}
                        disabled={disabled}
                        readOnly={readOnly}
                        required={required}
                        aria-labelledby={labelId}
                        aria-describedby={errorMessageId}
                        error={error}
                        isFocus={isFocus}
                        size={size}
                    />
                </ColorInputContainer>
                <StyledAlpha disabled={disabled}>
                    <StyledAlphaInput
                        type="number"
                        min="0"
                        max="100"
                        ref={alphaInputRef}
                        onFocus={event => handleFocus(event, 3)}
                        onBlur={handleBlur}
                        onChange={handleAlphaChange}
                        value={alphaValue}
                        size={size}
                    />
                    %
                </StyledAlpha>
            </StyledInputContainer>
            <RenderIf isTrue={bottomHelpText}>
                <HelpText alignSelf="center">{bottomHelpText}</HelpText>
            </RenderIf>
            <RenderIf isTrue={error}>
                <ErrorText alignSelf="center" id={errorMessageId}>
                    {error}
                </ErrorText>
            </RenderIf>
            <InternalOverlay isVisible={isOpen} triggerElementRef={() => triggerRef}>
                <div ref={pickerRef}>
                    <StyledCard borderRadius={borderRadius}>
                        <StyledContent>
                            <ColorPicker
                                value={colorValue}
                                defaultColors={defaultColors}
                                variant={variant}
                                onChange={handleColorChange}
                            />
                        </StyledContent>
                    </StyledCard>
                </div>
            </InternalOverlay>
        </StyledContainer>
    );
}
Provides a color input with an improved color picker.
@category Form