"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Field = exports.TextField = void 0;
const react_1 = __importStar(require("react"));
const css_utilities_1 = require("@shopify/css-utilities");
const Icon_1 = require("../Icon");
const VisuallyHidden_1 = require("../VisuallyHidden");
const Labelled_1 = require("../Labelled");
const Text_1 = require("../Text");
const Tooltip_1 = require("../Tooltip");
const InlineError_1 = require("../InlineError");
const BlockStack_1 = require("../BlockStack");
const Theme_1 = require("../Theme");
const typography_styles_css_1 = __importDefault(require("../../utilities/typography-styles.css"));
const strings_1 = require("../../utilities/strings");
const id_1 = require("../../utilities/id");
const errors_1 = require("../../utilities/errors");
const autocomplete_1 = require("../../utilities/autocomplete");
const TextField_css_1 = __importDefault(require("./TextField.css"));
const createId = id_1.createIdCreator('TextField');
/**
 * A text field is an input field that merchants can type into.
 */
exports.TextField = react_1.forwardRef((props, ref) => {
    const { controls: { background: controlsBackground }, textFields: { labelPosition, background: textFieldsBackground, errorIndentation, errorTypographyStyle, }, } = Theme_1.useThemeConfiguration();
    const background = textFieldsBackground || controlsBackground || 'surfaceTertiary';
    const { accessibilityDescription, error, id: explicitId, label, tooltip, value: explicitValue, } = props;
    const id = id_1.useId(explicitId, createId);
    const descriptionId = accessibilityDescription
        ? `${id}-description`
        : undefined;
    const description = descriptionId ? (<VisuallyHidden_1.VisuallyHidden>
      <Text_1.Text id={descriptionId}>{accessibilityDescription}</Text_1.Text>
    </VisuallyHidden_1.VisuallyHidden>) : null;
    const errorMarkup = error && (<span className={css_utilities_1.classNames(errorIndentation &&
        TextField_css_1.default[css_utilities_1.variationName('Error-errorIndentation', errorIndentation)], errorTypographyStyle && typography_styles_css_1.default[errorTypographyStyle])}>
      <InlineError_1.InlineError controlID={id}>{error}</InlineError_1.InlineError>
    </span>);
    const tooltipMarkup = tooltip ? (<div className={TextField_css_1.default.Tooltip}>
      <Tooltip_1.Tooltip content={tooltip.content}>
        <VisuallyHidden_1.VisuallyHidden>{tooltip.label}</VisuallyHidden_1.VisuallyHidden>
        <Icon_1.Icon source="questionFill" size="large" appearance="subdued"/>
      </Tooltip_1.Tooltip>
    </div>) : null;
    return (<BlockStack_1.BlockStack spacing="tight">
      <Labelled_1.Labelled label={label} htmlFor={id} isEmpty={strings_1.isEmptyString(explicitValue)} position={labelPosition} background={background} subdued={props.readonly}>
        <div className={TextField_css_1.default.Wrapper}>
          {description}
          <exports.Field ref={ref} {...props} id={id} ariaDescribedBy={descriptionId}/>
          {tooltipMarkup}
        </div>
      </Labelled_1.Labelled>
      {errorMarkup}
    </BlockStack_1.BlockStack>);
});
exports.Field = react_1.forwardRef(function Field({ id, min, max, step, name, label, value: explicitValue, controlledValue, type = 'text', role, required, error, tooltip, autocomplete, autofocus, multiline, disabled, readonly, ariaActiveDescendant, ariaAutocomplete, ariaControls, ariaDescribedBy, ariaExpanded, onFocus, onBlur, onChange, onInput, onKeyDown, }, ref) {
    const innerRef = react_1.useRef();
    const refsSetter = react_1.useCallback((instance) => {
        if (typeof ref === 'function') {
            ref(instance);
        }
        else if (ref) {
            ref.current = instance;
        }
        innerRef.current = instance;
    }, [ref]);
    react_1.useEffect(() => {
        var _a;
        if (autofocus) {
            (_a = innerRef.current) === null || _a === void 0 ? void 0 : _a.focus();
        }
    }, [autofocus]);
    const { controls: { background: controlsBackground }, textFields: { labelPosition = 'inside', background: textFieldsBackground, border = 'full', borderColor = 'base', focusBorder = 'full', typographyStyle: style, }, label: { typographyStyle: placeholderStyle }, } = Theme_1.useThemeConfiguration();
    const background = textFieldsBackground || controlsBackground || 'surfaceTertiary';
    const labelled = Labelled_1.useLabelled();
    const [localValue, setLocalValue] = usePartiallyControlledState(controlledValue !== null && controlledValue !== void 0 ? controlledValue : explicitValue);
    const className = css_utilities_1.classNames(TextField_css_1.default.Field, Boolean(error) && TextField_css_1.default.hasError, Boolean(tooltip) && TextField_css_1.default['Field-hasTooltip'], labelled.isFloating &&
        labelPosition !== 'outside' &&
        TextField_css_1.default['Field-isFloating'], disabled && TextField_css_1.default['Field-isDisabled'], readonly && TextField_css_1.default['Field-isReadOnly'], TextField_css_1.default[css_utilities_1.variationName('Field-background', background)], TextField_css_1.default[css_utilities_1.variationName('Field-border', border)], TextField_css_1.default[css_utilities_1.variationName('Field-borderColor', borderColor)], TextField_css_1.default[css_utilities_1.variationName('Field-focusBorder', focusBorder)], style && typography_styles_css_1.default[style], placeholderStyle &&
        typography_styles_css_1.default[css_utilities_1.variationName('placeholder', placeholderStyle)]);
    const finalDescribedBy = [ariaDescribedBy, error && errors_1.errorId(id)]
        .filter(Boolean)
        .join(' ');
    const field = react_1.default.createElement(multiline ? 'textarea' : 'input', {
        id,
        min,
        max,
        step,
        name,
        placeholder: labelled.isFloating || labelPosition === 'outside' ? undefined : label,
        className,
        required,
        type: normalizeType(multiline ? undefined : type),
        disabled,
        readOnly: readonly,
        'aria-activedescendant': ariaActiveDescendant,
        'aria-autocomplete': ariaAutocomplete,
        'aria-controls': ariaControls,
        'aria-describedby': finalDescribedBy,
        'aria-expanded': ariaExpanded,
        'aria-invalid': Boolean(error),
        'aria-required': required,
        onBlur: ({ currentTarget: { value } }) => {
            const currentValue = explicitValue !== null && explicitValue !== void 0 ? explicitValue : '';
            if (value !== currentValue)
                onChange === null || onChange === void 0 ? void 0 : onChange(value);
            onBlur === null || onBlur === void 0 ? void 0 : onBlur();
            labelled.onBlur();
        },
        onChange({ currentTarget: { value } }) {
            setLocalValue(value);
            onInput === null || onInput === void 0 ? void 0 : onInput(value);
            labelled.onChange(strings_1.isEmptyString(value));
        },
        onFocus: () => {
            onFocus === null || onFocus === void 0 ? void 0 : onFocus();
            labelled.onFocus();
        },
        onKeyDown,
        ref: refsSetter,
        role,
        value: localValue,
        autoComplete: autocomplete_1.autocompleteToHtml(autocomplete),
        autofocus,
    });
    return field;
});
function usePartiallyControlledState(value) {
    const [localValue, setLocalValue] = react_1.useState(value);
    const lastExplicitValue = react_1.useRef(value);
    let valueToReturn = localValue;
    if (lastExplicitValue.current !== value) {
        lastExplicitValue.current = value;
        setLocalValue(value);
        valueToReturn = value;
    }
    return [valueToReturn, setLocalValue];
}
// Takes the `type` we allow for a TextField props, and maps it to the
// valid type for an HTML input. Currently, the only difference is
// that we use the full word `telephone` instead of `tel`.
function normalizeType(type) {
    return type === 'telephone' ? 'tel' : type;
}
