"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.TextInputBase = void 0;
var _react = require("react");
var _reactNative = require("react-native");
var _reactNativeLinearGradient = _interopRequireDefault(require("react-native-linear-gradient"));
var _reactNativeReanimated = _interopRequireWildcard(require("react-native-reanimated"));
var _context = require("../../context");
var _core = require("../../core");
var _accessibility = require("../../utils/accessibility");
var _fonts = require("../../utils/fonts");
var _textInput = require("../../utils/textInput");
var _icons = require("../icons");
var _layout = require("../layout");
var _typography = require("../typography");
var _jsxRuntime = require("react/jsx-runtime");
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
/* eslint-disable functional/immutable-data */

const inputMarginTop = 16;
const inputHeight = 60;
const inputPaddingHorizontal = 12;
const inputPaddingVertical = 8;
const inputRadius = 8;
const inputTransitionDuration = 250;
const inputLabelScaleFactor = 0.75; /* 16pt becomes 12pt */
const inputLabelFontSize = 16;
const inputDisabledOpacity = 0.5;
const inputRightElementMargin = 8;
const iconSize = 24;
const iconMargin = 8;
const styles = _reactNative.StyleSheet.create({
  textInput: {
    flexDirection: "row",
    alignItems: "center",
    height: inputHeight,
    paddingVertical: inputPaddingVertical
  },
  textInputOuterBorder: {
    ..._reactNative.StyleSheet.absoluteFillObject,
    borderRadius: inputRadius,
    borderCurve: "continuous",
    borderWidth: 1
  },
  textInputInnerBorder: {
    ..._reactNative.StyleSheet.absoluteFillObject,
    borderRadius: inputRadius,
    borderCurve: "continuous",
    borderWidth: 2
  },
  textInputStyle: {
    flexGrow: 1,
    flexShrink: 1,
    /* The following `paddingVertical` property fixes a weird bug on
    Android where the text input scrolls, if the user apply some
    gestures on it with keyboard open */
    paddingVertical: 0,
    marginTop: inputMarginTop,
    height: "100%",
    /* Slightly move the input on the left on Android
       to align to the label */
    ...(_reactNative.Platform.OS === "android" && {
      marginLeft: -4
    })
  },
  textInputLabelWrapper: {
    position: "absolute",
    zIndex: 10,
    bottom: 0,
    top: 0,
    justifyContent: "center"
  }
});
const HelperRow = ({
  value,
  counterLimit,
  bottomMessage,
  bottomMessageColor,
  inputType,
  textInputProps
}) => {
  const theme = (0, _context.useIOTheme)();
  const valueCount = inputType === "default" ? value.length : value.replace(/\s/g, "").length;
  const helperAccessibilityLabel = (0, _react.useMemo)(() => {
    if (textInputProps?.keyboardType === "numeric") {
      return `${value.split("").join(" ")}, ${valueCount} / ${counterLimit}`;
    }
    return `${value}, ${valueCount}`;
  }, [value, valueCount, counterLimit, textInputProps]);
  const bottomMessageColorDefault = theme["textBody-tertiary"];
  const bottomMessageColorValue = bottomMessageColor ?? bottomMessageColorDefault;
  const helperRowStyle = (0, _react.useMemo)(() => {
    if (counterLimit && bottomMessage) {
      return {
        justifyContent: "space-between"
      };
    }
    if (counterLimit) {
      return {
        justifyContent: "flex-end"
      };
    }
    if (bottomMessage) {
      return {
        justifyContent: "flex-start"
      };
    }
    return {};
  }, [counterLimit, bottomMessage]);
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
    style: [{
      flexDirection: "row",
      alignItems: "center",
      paddingHorizontal: inputPaddingHorizontal
    }, helperRowStyle]
    // in case of error message the element should be ignored by VO or Talkback
    ,
    accessibilityElementsHidden: bottomMessageColor === "error-600",
    importantForAccessibility: bottomMessageColor === "error-600" ? "no-hide-descendants" : "auto",
    children: [bottomMessage && /*#__PURE__*/(0, _jsxRuntime.jsx)(_typography.BodySmall, {
      weight: "Regular",
      color: bottomMessageColorValue,
      children: bottomMessage
    }), counterLimit && /*#__PURE__*/(0, _jsxRuntime.jsx)(_typography.BodySmall, {
      accessibilityLiveRegion: "polite",
      weight: "Regular",
      accessibilityLabel: helperAccessibilityLabel,
      color: bottomMessageColorValue,
      children: `${valueCount} / ${counterLimit}`
    })]
  });
};
const TextInputBase = ({
  disabled = false,
  placeholder,
  value = "",
  onChangeText,
  accessibilityLabel,
  accessibilityHint,
  textInputProps,
  inputType = "default",
  status,
  icon,
  rightElement,
  counterLimit,
  accessibilityAnnounceLimitReached,
  bottomMessage,
  bottomMessageColor,
  onBlur,
  onFocus,
  isPassword,
  autoFocus,
  testID
}) => {
  const inputRef = (0, _react.useRef)(null);
  const [inputStatus, setInputStatus] = (0, _react.useState)(disabled ? "disabled" : "initial");
  const focusedState = (0, _reactNativeReanimated.useSharedValue)(0);
  const {
    newTypefaceEnabled
  } = (0, _context.useIONewTypeface)();
  const {
    dynamicFontScale,
    spacingScaleMultiplier
  } = (0, _accessibility.useIOFontDynamicScale)();
  const theme = (0, _context.useIOTheme)();
  const iconColor = theme["icon-decorative"];
  const inputLabelColor = _core.IOColors[theme["textInputLabel-default"]];
  const inputTextColor = _core.IOColors[theme["textInputValue-default"]];
  const inputDisabledTextColor = _core.IOColors[theme["textInputValue-disabled"]];

  /* Get the label width to enable the correct translation */
  const [labelWidth, setLabelWidth] = (0, _react.useState)(0);
  const getLabelWidth = ({
    nativeEvent
  }) => {
    setLabelWidth(nativeEvent.layout.width);
  };

  /* Set `inputStatus` when `status` changes
     (e.g. when it's passed as a prop) */
  (0, _react.useEffect)(() => {
    if (status) {
      setInputStatus(status);
    }
  }, [status]);

  /* Visual attributes */
  const appBackground = _core.IOColors[theme["appBackground-primary"]];
  const borderColorMap = (0, _react.useMemo)(() => ({
    initial: _core.IOColors[theme["textInputBorder-default"]],
    disabled: _core.IOColors[theme["textInputBorder-default"]],
    focused: _core.IOColors[theme["interactiveElem-default"]],
    error: _core.IOColors[theme.errorText]
  }), [theme]);
  const easingConf = {
    duration: inputTransitionDuration,
    easing: _reactNativeReanimated.Easing.inOut(_reactNativeReanimated.Easing.cubic)
  };
  const animatedLabelStyle = (0, _reactNativeReanimated.useAnimatedStyle)(() => {
    const enableTransition = focusedState.value || value.length > 0;
    return {
      transform: [{
        /* Since we can't have RN 0.73 yet, we use this calculation
        to simulate `transformOrigin: left` */
        translateX: (0, _reactNativeReanimated.withTiming)(enableTransition ? -labelWidth * (1 - inputLabelScaleFactor) / 2 : 0, easingConf)
      }, {
        translateY: (0, _reactNativeReanimated.withTiming)(enableTransition ? -12 : 0, easingConf)
      }, {
        scale: (0, _reactNativeReanimated.withTiming)(enableTransition ? inputLabelScaleFactor : 1, easingConf)
      }]
    };
  });

  /* Interpolate border color based on input status,
     but not apply the transition on `focus` state
     because it's already managed by the
     `animatedInnerBorderStyle` */
  const animatedOuterBorderStyle = (0, _reactNativeReanimated.useAnimatedStyle)(() => ({
    borderColor: inputStatus !== "focused" ? (0, _reactNativeReanimated.interpolateColor)(1, [0, 1], [borderColorMap.initial, borderColorMap[inputStatus]]) : borderColorMap.initial
  }));
  const animatedInnerBorderStyle = (0, _reactNativeReanimated.useAnimatedStyle)(() => ({
    opacity: (0, _reactNativeReanimated.withTiming)(focusedState.value ? 1 : 0, easingConf)
  }));
  const onTextInputPress = () => {
    if (disabled) {
      return;
    }
    focusedState.value = 1;
    setInputStatus("focused");
    inputRef?.current?.focus();
  };
  const onChangeTextHandler = (0, _react.useCallback)(text => {
    const actualTextLength = inputType !== "default" ? text.replace(/\s/g, "").length : text.length;

    // Notify the user when the limit is reached
    // This is only for iOS, as Android handles it via accessibilityLiveRegion
    if (counterLimit && actualTextLength >= counterLimit && accessibilityAnnounceLimitReached && _reactNative.Platform.OS === "ios") {
      _reactNative.AccessibilityInfo.announceForAccessibility(accessibilityAnnounceLimitReached);
    }
    if (counterLimit && actualTextLength > counterLimit) {
      return;
    }
    if (inputType !== "default") {
      // necessary to omit whitespaces added by the valueFormat function
      const formattedText = text.replace(/\s/g, "");
      onChangeText(formattedText);
    } else {
      onChangeText(text);
    }
  }, [counterLimit, onChangeText, inputType, accessibilityAnnounceLimitReached]);
  const onBlurHandler = (0, _react.useCallback)(() => {
    focusedState.value = 0;
    onBlur?.();
    setInputStatus("initial");
  }, [focusedState, onBlur]);
  const onFocusHandler = () => {
    focusedState.value = 1;
    onFocus?.();
    setInputStatus("focused");
  };
  const derivedInputProps = (0, _react.useMemo)(() => (0, _textInput.getInputPropsByType)(inputType), [inputType]);
  const inputValue = (0, _react.useMemo)(() => derivedInputProps && derivedInputProps.valueFormat ? derivedInputProps.valueFormat(value) : value, [value, derivedInputProps]);

  // Calculate the adjusted maxLength to account for spaces
  const adjustedMaxLength = (0, _react.useMemo)(() => {
    if (counterLimit && derivedInputProps && derivedInputProps.valueFormat) {
      const spacesCount = Math.floor(counterLimit / 4);
      return counterLimit + spacesCount;
    }
    return counterLimit;
  }, [counterLimit, derivedInputProps]);
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
    children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Pressable, {
      onPress: onTextInputPress,
      style: [inputStatus === "disabled" ? {
        opacity: inputDisabledOpacity
      } : {}, styles.textInput, {
        paddingHorizontal: inputPaddingHorizontal * dynamicFontScale * spacingScaleMultiplier
      }],
      accessible: false,
      accessibilityRole: "none",
      importantForAccessibility: "no",
      children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeReanimated.default.View, {
        style: [styles.textInputOuterBorder, animatedOuterBorderStyle]
      }), !disabled && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeReanimated.default.View, {
        style: [{
          borderColor: borderColorMap.focused
        }, styles.textInputInnerBorder, animatedInnerBorderStyle]
      }), icon && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
        children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_icons.Icon, {
          allowFontScaling: true,
          name: icon,
          color: iconColor,
          size: iconSize
        }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_layout.HSpacer, {
          allowScaleSpacing: true,
          size: iconMargin
        })]
      }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TextInput, {
        ref: inputRef,
        testID: testID,
        ...(derivedInputProps ? derivedInputProps.textInputProps : textInputProps),
        accessible: true,
        importantForAccessibility: "yes",
        accessibilityElementsHidden: false,
        editable: !disabled,
        secureTextEntry: isPassword,
        disableFullscreenUI: true,
        accessibilityState: {
          disabled
        },
        accessibilityLabel: accessibilityLabel ?? placeholder,
        accessibilityHint: accessibilityHint,
        accessibilityLiveRegion: "polite",
        selectionColor: _core.IOColors[theme["interactiveElem-default"]] // Caret on iOS
        ,
        cursorColor: _core.IOColors[theme["interactiveElem-default"]] // Caret Android
        ,
        maxLength: adjustedMaxLength,
        maxFontSizeMultiplier: _fonts.IOMaxFontSizeMultiplier,
        onBlur: onBlurHandler,
        onFocus: onFocusHandler,
        blurOnSubmit: true,
        onChangeText: onChangeTextHandler,
        style: [{
          ...(0, _fonts.makeFontStyleObject)(inputLabelFontSize, newTypefaceEnabled ? "Titillio" : "TitilliumSansPro", undefined, "Regular")
        }, styles.textInputStyle, !disabled ? {
          color: inputTextColor
        } : {
          color: inputDisabledTextColor
        }],
        autoFocus: autoFocus,
        value: inputValue
      }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeReanimated.default.View, {
        pointerEvents: "none",
        style: [styles.textInputLabelWrapper, {
          paddingHorizontal: inputPaddingHorizontal * dynamicFontScale * spacingScaleMultiplier
        }, icon ? {
          left: (iconSize + iconMargin) * dynamicFontScale * spacingScaleMultiplier
        } : {}],
        children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeReanimated.default.Text, {
          onLayout: getLabelWidth,
          numberOfLines: 1,
          accessible: false,
          maxFontSizeMultiplier: _fonts.IOMaxFontSizeMultiplier,
          style: [{
            ...(0, _fonts.makeFontStyleObject)(inputLabelFontSize, newTypefaceEnabled ? "Titillio" : "TitilliumSansPro", undefined, "Regular"),
            color: inputLabelColor
          }, animatedLabelStyle],
          children: placeholder
        })
      }), rightElement && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNativeReanimated.default.View, {
        style: {
          alignSelf: "stretch",
          overflow: "visible",
          justifyContent: "center"
        },
        children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeLinearGradient.default, {
          useAngle: true,
          angle: 90,
          style: {
            width: inputRightElementMargin * 3,
            position: "absolute",
            left: -inputRightElementMargin * 3,
            top: 0,
            bottom: 0
          },
          colors: [(0, _core.hexToRgba)(appBackground, 0), appBackground]
        }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_layout.HSpacer, {
          size: inputRightElementMargin
        }), rightElement]
      })]
    }), (bottomMessage || counterLimit) && /*#__PURE__*/(0, _jsxRuntime.jsx)(HelperRow, {
      value: inputValue,
      bottomMessage: bottomMessage,
      bottomMessageColor: bottomMessageColor,
      counterLimit: counterLimit,
      inputType: inputType,
      textInputProps: textInputProps
    })]
  });
};
exports.TextInputBase = TextInputBase;
//# sourceMappingURL=TextInputBase.js.map