"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = InlineEdit;
var _react = _interopRequireWildcard(require("react"));
var _classnames = _interopRequireDefault(require("classnames"));
var _uniqueId = _interopRequireDefault(require("lodash-es/uniqueId"));
var _faPen = require("@fortawesome/free-solid-svg-icons/faPen");
var _faCircleXmark = require("@fortawesome/free-solid-svg-icons/faCircleXmark");
var _faCircleNotch = require("@fortawesome/free-solid-svg-icons/faCircleNotch");
var _fontAwesomeIcon = require("../font-awesome-icon");
var _input = require("../input");
var _textarea = require("../textarea");
var _useNonNativeButtonAttrs = require("../hooks/use-non-native-button-attrs");
var _useFocusWithin = require("../hooks/use-focus-within");
var _formField = require("../form-field");
var _types = require("./types");
var _useTranslation = require("../hooks/use-translation");
var _truncateWithTooltip = require("../truncate-with-tooltip");
var _jsxRuntime = require("react/jsx-runtime");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
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); }
const {
  H1,
  H2,
  H3,
  H4,
  H5,
  P
} = _types.INLINE_EDIT_TAGS;
const classNameToTagMap = {
  'heading-01': H1,
  'heading-02': H2,
  'heading-03': H3,
  'heading-04': H4,
  'heading-05': H5
};
const defaultTag = P;
const openState = new Map();
const isSomeOneOpen = () => {
  const values = Array.from(openState.values());
  return values.some(val => val);
};

/**
 * @midnight-gray-supported
 * @uxr-only-supported
 * @alpine-light-supported
 * */
function InlineEdit({
  onSubmit,
  placeholder,
  textTestId,
  textWrapperTestId,
  inputTestId,
  value = '',
  className,
  overrideTag,
  onChange = () => {},
  isMultiline = false,
  typoClassName = 'body',
  inputProps = {},
  textareaProps = {},
  autoFocus = false,
  rows = 3,
  readOnly = false,
  submitAriaLabel,
  cancelAriaLabel,
  onCancel,
  isLoading,
  loadingAriaLabel,
  editableTextAriaLabel
}) {
  const {
    t
  } = (0, _useTranslation.useTranslation)();
  const [touched, setTouched] = (0, _react.useState)(false);
  const [inputValue, setInputValue] = (0, _react.useState)(value);
  const [componentId] = (0, _react.useState)(() => (0, _uniqueId.default)());
  const [isEditMode, setIsEditMode] = (0, _react.useState)(false);
  const container = (0, _react.useRef)(null);
  const handleCancel = () => {
    setInputValue(value);
    setIsEditMode(false);
    onCancel?.();
  };
  const hasError = (0, _react.useMemo)(() => [inputProps?.validity?.getType?.(inputValue), inputProps?.validity?.type, textareaProps?.validity?.getType?.(inputValue), textareaProps?.validity?.type].includes(_formField.VALIDATION_RULE_TYPES.ERROR), [textareaProps?.validity, inputProps?.validity]);
  (0, _react.useEffect)(() => {
    if (hasError) {
      setIsEditMode(true);
    }
  }, [hasError]);
  const onFormSubmit = () => {
    setTouched(true);
    if (!hasError) {
      onSubmit(inputValue);
      setIsEditMode(false);
    }
  };
  (0, _react.useEffect)(() => {
    onChange(inputValue);
  }, [inputValue]);
  (0, _react.useEffect)(() => {
    openState.set(componentId, isEditMode);
  }, [isEditMode]);
  (0, _react.useEffect)(() => () => {
    openState.delete(componentId);
  }, []);
  (0, _react.useLayoutEffect)(() => {
    // If the component is mounted, autoFocus is true, and there are no other inline edits in edit mode -
    // set the open state and edit mode to true
    // previously it was set in state initialization function but since react 18 that initialization function
    // can be called twice without unmount if 2+ components rendering inline edit are wrapped in Suspense and lazy loaded
    // it results in inline edits being locked up because first id is set to true, however latest render would use different id
    // it turns out to be common react thing: https://stackoverflow.com/questions/73325723/suspense-as-a-root-element-causes-two-instances-of-component-in-production-and
    if (autoFocus && !(isSomeOneOpen() || readOnly || isLoading)) {
      openState.set(componentId, true);
      setIsEditMode(true);
    }
  }, []);
  const onTextClick = e => {
    e.preventDefault();
    if (!isSomeOneOpen() && !readOnly && !isLoading) {
      setIsEditMode(true);
    }
  };
  const buttonAttrs = (0, _useNonNativeButtonAttrs.useNonNativeButtonAttrs)({
    onClick: onTextClick,
    onKeyDown: onTextClick,
    isDisabled: readOnly
  });
  const focusWithinProps = (0, _useFocusWithin.useFocusWithin)({
    onBlur: onFormSubmit
  });
  const onFieldChange = e => {
    const {
      value: newValue
    } = e.target;
    setInputValue(newValue);
  };
  const fieldProps = {
    placeholder,
    className: 'inline-edit-input controllable-field',
    value: inputValue.trim() ? inputValue : '',
    onChange: onFieldChange,
    fieldClass: typoClassName,
    touched,
    autoFocus: true,
    fieldTestId: inputTestId,
    useFont: false,
    disableApplyButton: hasError,
    shouldDisplayControls: true,
    onSubmit: onFormSubmit,
    onCancel: handleCancel,
    rightIcon: hasError ? _faCircleXmark.faCircleXmark : null,
    iconTooltipText: isMultiline ? textareaProps.validity?.value?.toString() : inputProps.validity?.value?.toString(),
    submitAriaLabel,
    cancelAriaLabel
  };
  const onFormKeyDown = e => {
    if (e.key === 'Esc' || e.key === 'Escape') {
      e.stopPropagation();
      handleCancel();
    }
    if (isMultiline) {
      if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) {
        e.preventDefault();
        onFormSubmit();
      }
    }
  };
  (0, _react.useEffect)(() => {
    setTouched(false);
  }, [isEditMode]);
  (0, _react.useEffect)(() => {
    setInputValue(value);
  }, [value]);
  const TagName = (0, _react.useMemo)(() => overrideTag || classNameToTagMap[typoClassName] || defaultTag, [typoClassName, overrideTag]);
  return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
    ref: container,
    className: (0, _classnames.default)('inline-edit-container', className),
    children: isEditMode ?
    /*#__PURE__*/
    // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions
    (0, _jsxRuntime.jsx)("form", {
      onKeyDown: onFormKeyDown,
      onBlur: focusWithinProps.onBlur,
      onSubmit: e => {
        e.preventDefault();
        onFormSubmit();
      },
      children: isMultiline ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_textarea.TextArea, {
        ...fieldProps,
        ...textareaProps,
        validity: {
          type: textareaProps.validity?.type,
          value: hasError
        },
        rows: rows,
        autoFocus: true,
        className: (0, _classnames.default)(fieldProps.className, 'resized')
        // eslint-disable-next-line react/forbid-component-props
        ,
        style: {
          width: container?.current?.offsetWidth
        }
      }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_input.Input, {
        ...fieldProps,
        ...inputProps,
        validity: {
          type: inputProps.validity?.type,
          value: hasError
        },
        shouldDisplayControls: true,
        autoFocus: true
      })
    }) : /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
      className: (0, _classnames.default)('inline-edit-text-container', (readOnly || isLoading) && 'read-only'),
      "test-id": textWrapperTestId,
      ...buttonAttrs,
      "aria-label": editableTextAriaLabel ?? t('Click to edit text'),
      children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
        className: "inline-edit-text-wrapper",
        children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_truncateWithTooltip.TruncateWithTooltip, {
          className: (0, _classnames.default)(typoClassName, 'inline-text-wrapper', isMultiline && `multiline rows-${rows}`, !inputValue.trim() && 'empty'),
          tooltipTestId: textTestId ? `${textTestId}-tooltip` : 'inline-text-tooltip',
          children: /*#__PURE__*/(0, _jsxRuntime.jsx)(TagName, {
            "test-id": textTestId,
            children: inputValue.trim() ? inputValue : placeholder
          })
        }), isLoading && /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
          role: "status",
          "aria-label": loadingAriaLabel ?? t('Updating text'),
          "test-id": "is-loading-icon",
          className: "is-loading-icon",
          "aria-busy": true,
          children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_fontAwesomeIcon.FontAwesomeIcon, {
            icon: _faCircleNotch.faCircleNotch,
            spin: true
          })
        })]
      }), !readOnly && !isLoading && /*#__PURE__*/(0, _jsxRuntime.jsx)(_fontAwesomeIcon.FontAwesomeIcon, {
        className: "inline-edit-pencil-button",
        icon: _faPen.faPen,
        "test-id": "edit-icon"
      })]
    })
  });
}