'use strict';

var React = require('react');
var tslib_es6 = require('../tslib.es6-cjs.js');
var classnames = require('classnames');
var mergeRefs = require('../mergeRefs-cjs.js');
var reactHookForm = require('react-hook-form');
require('../Button-cjs.js');
require('@jobber/design');
var filterDataAttributes = require('../filterDataAttributes-cjs.js');
var FormField = require('../FormField-cjs.js');
require('@jobber/hooks');
require('framer-motion');
require('../Icon-cjs.js');
require('../Text-cjs.js');
require('../Typography-cjs.js');
require('../useFormFieldFocus-cjs.js');
require('../InputValidation-cjs.js');
require('../Spinner-cjs.js');
require('react-router-dom');

var styles = {"mask":"_78-Lxj78xPg-","hiddenValue":"GoiXVXaU1Qs-","emptyValue":"oOrjwubmsVA-","spinning":"T3VvmDmzs-4-"};

function useInputMask({ value = "", pattern, delimiter = "*", strict = true, onChange, }) {
    const [isMasking, setIsMasking] = React.useState(!value);
    const patternInfo = React.useMemo(() => {
        const patternChars = pattern.split("");
        const specialChars = patternChars.filter(char => char !== delimiter);
        const maxCleanChars = patternChars.filter(char => char === delimiter).length;
        return {
            patternChars,
            specialChars,
            maxCleanChars,
        };
    }, [pattern, delimiter]);
    const inputValue = React.useMemo(() => {
        return value
            .split("")
            .filter(char => !patternInfo.specialChars.includes(char))
            .join("");
    }, [value, patternInfo.specialChars]);
    const formatValue = React.useCallback((unformattedValue) => {
        const { patternChars, specialChars, maxCleanChars } = patternInfo;
        const cleanValueChars = unformattedValue
            .split("")
            .filter(char => !specialChars.includes(char) && !Number.isNaN(Number(char)));
        const isOverCharLimit = cleanValueChars.length > maxCleanChars;
        if (!strict && isOverCharLimit) {
            return cleanValueChars.join("");
        }
        else {
            const formattedValue = patternChars.reduce(getMaskedValue([...cleanValueChars], specialChars), "");
            return formattedValue;
        }
    }, [patternInfo, strict]);
    const maskedOnChange = React.useCallback((newValue, event) => {
        const formatted = formatValue(newValue);
        onChange === null || onChange === void 0 ? void 0 : onChange(formatted, event);
    }, [formatValue, onChange]);
    const formattedValue = React.useMemo(() => formatValue(value), [formatValue, value]);
    React.useEffect(() => {
        const shouldMask = strict || inputValue.length < patternInfo.maxCleanChars;
        setIsMasking(shouldMask);
    }, [inputValue, patternInfo.maxCleanChars, strict]);
    const placeholderMask = React.useMemo(() => pattern
        .replace(new RegExp(`\\${delimiter}`, "g"), "_")
        .slice(value.length), [pattern, delimiter, value]);
    return {
        formattedValue,
        placeholderMask,
        isMasking,
        maskedOnChange,
        inputValue,
    };
}
function getMaskedValue(cleanVal, specialChars) {
    return (result, nextCharacter) => {
        if (!cleanVal.length)
            return result;
        if (specialChars.includes(nextCharacter))
            return result + nextCharacter;
        const nextValue = cleanVal.shift();
        return result + (nextValue !== undefined ? nextValue : "");
    };
}

function MaskElement({ isMasking, formattedValue, placeholderMask, }) {
    if (!isMasking) {
        return null;
    }
    return (React.createElement("div", { className: styles.mask, "aria-hidden": "true" },
        React.createElement("span", { className: styles.hiddenValue }, formattedValue),
        React.createElement("span", null, placeholderMask)));
}
function InputMask({ children, delimiter = "*", pattern, strict = true, }) {
    const { value: inputValue, onChange } = children.props;
    const { placeholderMask, isMasking, formattedValue, maskedOnChange } = useInputMask({
        value: String(inputValue || ""),
        pattern,
        delimiter,
        strict,
        onChange: onChange,
    });
    const inputMask = (React.createElement(MaskElement, { isMasking: isMasking, formattedValue: formattedValue, placeholderMask: placeholderMask }));
    return React.cloneElement(children, {
        onChange: maskedOnChange,
        children: isMasking && inputMask,
    });
}

const DEFAULT_PATTERN = "(***) ***-****";

/**
 * Combines the actions on the InputPhoneNumber such as onChange, onEnter, onFocus, onBlur, and onClear to forward information to the consumers of the InputPhoneNumber.
 * Do not repeat this pattern. We are doing this as a proof of concept relating to the refactoring of Form inputs to see what can be removed.
 */
function useInputPhoneActions({ onChange, inputRef, onFocus, onBlur, onKeyDown, onEnter, onClick, onMouseDown, onMouseUp, onPointerDown, onPointerUp, }) {
    function handleClear() {
        var _a;
        onChange && onChange("");
        (_a = inputRef === null || inputRef === void 0 ? void 0 : inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
    }
    function handleChange(event) {
        const newValue = event.currentTarget.value;
        onChange === null || onChange === void 0 ? void 0 : onChange(newValue, event);
    }
    function handleFocus(event) {
        onFocus === null || onFocus === void 0 ? void 0 : onFocus(event);
    }
    function handleKeyDown(event) {
        onKeyDown === null || onKeyDown === void 0 ? void 0 : onKeyDown(event);
        if (!onEnter)
            return;
        if (event.key !== "Enter")
            return;
        if (event.shiftKey || event.ctrlKey)
            return;
        event.preventDefault();
        onEnter === null || onEnter === void 0 ? void 0 : onEnter(event);
    }
    function handleBlur(event) {
        onBlur === null || onBlur === void 0 ? void 0 : onBlur(event);
    }
    function handleClick(event) {
        onClick === null || onClick === void 0 ? void 0 : onClick(event);
    }
    function handleMouseDown(event) {
        onMouseDown === null || onMouseDown === void 0 ? void 0 : onMouseDown(event);
    }
    function handleMouseUp(event) {
        onMouseUp === null || onMouseUp === void 0 ? void 0 : onMouseUp(event);
    }
    function handlePointerDown(event) {
        onPointerDown === null || onPointerDown === void 0 ? void 0 : onPointerDown(event);
    }
    function handlePointerUp(event) {
        onPointerUp === null || onPointerUp === void 0 ? void 0 : onPointerUp(event);
    }
    return {
        handleClear,
        handleChange,
        handleFocus,
        handleBlur,
        handleKeyDown,
        handleClick,
        handleMouseDown,
        handleMouseUp,
        handlePointerDown,
        handlePointerUp,
    };
}

const InputPhoneNumberRebuilt = React.forwardRef(function InputPhoneNumberInternal(_a, ref) {
    var _b, _c, _d, _e;
    var { pattern = DEFAULT_PATTERN } = _a, props = tslib_es6.__rest(_a, ["pattern"]);
    const inputPhoneNumberRef = (_b = ref) !== null && _b !== void 0 ? _b : React.useRef(null);
    const wrapperRef = React.useRef(null);
    const generatedId = React.useId();
    const id = props.id || generatedId;
    const { name } = mergeRefs.useAtlantisFormFieldName({
        nameProp: props.name,
        id: id,
    });
    const { formattedValue, isMasking, placeholderMask, inputValue, maskedOnChange, } = useInputMask({
        value: props.value,
        pattern,
        strict: false,
        onChange: props.onChange,
    });
    const { handleChange, handleBlur, handleFocus, handleClear, handleKeyDown, handleClick, handleMouseDown, handleMouseUp, handlePointerDown, handlePointerUp, } = useInputPhoneActions({
        onChange: maskedOnChange,
        onBlur: props.onBlur,
        onFocus: props.onFocus,
        onEnter: props.onEnter,
        onKeyDown: props.onKeyDown,
        onClick: props.onClick,
        onMouseDown: props.onMouseDown,
        onMouseUp: props.onMouseUp,
        onPointerDown: props.onPointerDown,
        onPointerUp: props.onPointerUp,
        inputRef: inputPhoneNumberRef,
    });
    const descriptionIdentifier = `descriptionUUID--${id}`, descriptionVisible = props.description && !props.inline;
    const isInvalid = Boolean(props.error || props.invalid);
    const dataAttrs = filterDataAttributes.filterDataAttributes(props);
    return (React.createElement(mergeRefs.FormFieldWrapper, { disabled: props.disabled, size: props.size, inline: props.inline, wrapperRef: wrapperRef, error: (_c = props.error) !== null && _c !== void 0 ? _c : "", invalid: Boolean(props.error || props.invalid), identifier: id, descriptionIdentifier: descriptionIdentifier, description: props.description, clearable: (_d = props.clearable) !== null && _d !== void 0 ? _d : "never", onClear: handleClear, type: "tel", placeholder: props.placeholder, value: formattedValue, prefix: props.prefix, suffix: props.suffix, readonly: props.readOnly, loading: props.loading },
        React.createElement("input", Object.assign({ id: id, name: name, type: "tel", ref: inputPhoneNumberRef, className: classnames(mergeRefs.formFieldStyles.input, {
                [styles.emptyValue]: inputValue.length === 0 && pattern[0] === "(",
            }), value: formattedValue, disabled: props.disabled, readOnly: props.readOnly, autoFocus: props.autoFocus, autoComplete: props.autoComplete, inputMode: props.inputMode, tabIndex: props.tabIndex, required: props.required, role: props.role, "aria-label": props["aria-label"], "aria-describedby": descriptionVisible
                ? descriptionIdentifier
                : props["aria-describedby"], "aria-invalid": isInvalid ? true : undefined, "aria-controls": props["aria-controls"], "aria-expanded": props["aria-expanded"], "aria-activedescendant": props["aria-activedescendant"], "aria-autocomplete": props["aria-autocomplete"], "aria-required": props["aria-required"], onChange: handleChange, onBlur: handleBlur, onFocus: handleFocus, onKeyDown: handleKeyDown, onClick: handleClick, onMouseDown: handleMouseDown, onMouseUp: handleMouseUp, onPointerDown: handlePointerDown, onPointerUp: handlePointerUp }, dataAttrs)),
        React.createElement(MaskElement, { isMasking: isMasking, formattedValue: formattedValue, placeholderMask: placeholderMask }),
        React.createElement(mergeRefs.FormFieldPostFix, { variation: "spinner", visible: (_e = props.loading) !== null && _e !== void 0 ? _e : false })));
});

function InputPhoneNumber$1(_a) {
    var { required } = _a, props = tslib_es6.__rest(_a, ["required"]);
    const { placeholder, validations, pattern = DEFAULT_PATTERN } = props;
    const errorSubject = placeholder || "Phone number";
    const { getValues } = reactHookForm.useFormContext() != undefined
        ? reactHookForm.useFormContext()
        : // If there isn't a Form Context being provided, get a form for this field.
            reactHookForm.useForm({ mode: "onTouched" });
    return (React.createElement(InputMask, { pattern: pattern, strict: false },
        React.createElement(FormField.FormField, Object.assign({}, props, { type: "tel", pattern: pattern, validations: Object.assign(Object.assign({ required: {
                    value: Boolean(required),
                    message: `${errorSubject} is required`,
                } }, validations), { validate: getPhoneNumberValidation }) }))));
    function getPhoneNumberValidation(value) {
        // Get unique characters that aren't * in the pattern
        const patternNonDelimterCharacters = pattern
            .split("")
            .filter(char => char !== "*")
            .filter((char, index, arr) => arr.indexOf(char) === index);
        const specialCharacters = patternNonDelimterCharacters.join(" ");
        // Remove special characters from pattern
        const cleanValue = value.replace(new RegExp(`[${specialCharacters}]`, "g"), "");
        const cleanValueRequiredLength = (pattern.match(/\*/g) || []).length;
        if (cleanValue.length > 0 && cleanValue.length < cleanValueRequiredLength) {
            return `${errorSubject} must contain ${cleanValueRequiredLength} or more digits`;
        }
        if (typeof (validations === null || validations === void 0 ? void 0 : validations.validate) === "function") {
            return validations.validate(value, getValues);
        }
        return true;
    }
}

function isNewInputPhoneNumberProps(props) {
    return props.version === 2;
}
const InputPhoneNumber = React.forwardRef(function InputPhoneNumberShim(props, ref) {
    if (isNewInputPhoneNumberProps(props)) {
        return React.createElement(InputPhoneNumberRebuilt, Object.assign({}, props, { ref: ref }));
    }
    else {
        return React.createElement(InputPhoneNumber$1, Object.assign({}, props));
    }
});

exports.InputPhoneNumber = InputPhoneNumber;
