"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _typeof = require("@babel/runtime/helpers/typeof");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.OPTION_CHECKED_STATES = exports.EuiListItemLayout = void 0;
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
var _react = _interopRequireWildcard(require("react"));
var _react2 = require("@emotion/react");
var _classnames = _interopRequireDefault(require("classnames"));
var _services = require("../../services");
var _list_item_layout = require("./_list_item_layout.styles");
var _tool_tip = require("../tool_tip");
var _form = require("../form");
var _icon = require("../icon");
var _button_display = require("../button/button_display/_button_display");
var _external_link_icon = require("../link/external_link_icon");
var _excluded = ["children", "element", "wrapperElement", "className", "css", "role", "prepend", "append", "extraAction", "wrapperProps", "contentProps", "prependProps", "appendProps", "textProps", "tooltipProps", "checked", "isDisabled", "hasAriaDisabled", "isFocused", "isSelected", "isSingleSelection", "selectionMode", "showIndicator", "textWrap", "external", "aria-describedby", "aria-selected", "aria-checked", "data-test-subj", "onClick"],
  _excluded2 = ["href", "target", "rel"],
  _excluded3 = ["ref"];
/*
 * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
 * or more contributor license agreements. Licensed under the Elastic License
 * 2.0 and the Server Side Public License, v 1; you may not use this file except
 * in compliance with, at your election, the Elastic License 2.0 or the Server
 * Side Public License, v 1.
 */
// @ts-ignore module doesn't export `createElement`
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
var OPTION_CHECKED_STATES = exports.OPTION_CHECKED_STATES = ['on', 'off', 'mixed', undefined];
var NATIVELY_CHECKABLE_ROLES = ['checkbox', 'menuitemcheckbox', 'radio', 'menuitemradio', 'switch'];
var ROLES_THAT_CAN_BE_MIXED = ['option', 'checkbox', 'menuitemcheckbox'];
var ROLES_THAT_CAN_USE_ARIA_CHECKED = ['option'].concat(NATIVELY_CHECKABLE_ROLES);
var ROLES_THAT_CAN_USE_ARIA_SELECTED = ['tab', 'gridcell', 'option', 'row', 'treeitem'];

// Ensure an exclusive union of either li, div, button, or anchor

/**
 * This is an EUI internal-only layout component that is used to share layout and
 * styles between selection and navigational list components.
 */
var EuiListItemLayout = exports.EuiListItemLayout = /*#__PURE__*/(0, _react.forwardRef)(function (_ref, ref) {
  var _tooltipProps$anchorP;
  var _children = _ref.children,
    _ref$element = _ref.element,
    _element = _ref$element === void 0 ? 'li' : _ref$element,
    wrapperElement = _ref.wrapperElement,
    className = _ref.className,
    css = _ref.css,
    role = _ref.role,
    _prepend = _ref.prepend,
    _append = _ref.append,
    extraAction = _ref.extraAction,
    _wrapperProps = _ref.wrapperProps,
    _contentProps = _ref.contentProps,
    _prependProps = _ref.prependProps,
    _appendProps = _ref.appendProps,
    _textProps = _ref.textProps,
    _tooltipProps = _ref.tooltipProps,
    checked = _ref.checked,
    isDisabled = _ref.isDisabled,
    _ref$hasAriaDisabled = _ref.hasAriaDisabled,
    hasAriaDisabled = _ref$hasAriaDisabled === void 0 ? false : _ref$hasAriaDisabled,
    isFocused = _ref.isFocused,
    isSelected = _ref.isSelected,
    _ref$isSingleSelectio = _ref.isSingleSelection,
    isSingleSelection = _ref$isSingleSelectio === void 0 ? true : _ref$isSingleSelectio,
    _selectionMode = _ref.selectionMode,
    _ref$showIndicator = _ref.showIndicator,
    showIndicator = _ref$showIndicator === void 0 ? true : _ref$showIndicator,
    _ref$textWrap = _ref.textWrap,
    textWrap = _ref$textWrap === void 0 ? 'truncate' : _ref$textWrap,
    external = _ref.external,
    _ariaDescribedBy = _ref['aria-describedby'],
    _ariaSelected = _ref['aria-selected'],
    _ariaChecked = _ref['aria-checked'],
    _ref$dataTestSubj = _ref['data-test-subj'],
    dataTestSubj = _ref$dataTestSubj === void 0 ? 'euiListItemLayout' : _ref$dataTestSubj,
    onClick = _ref.onClick,
    props = (0, _objectWithoutProperties2.default)(_ref, _excluded);
  var _useState = (0, _react.useState)(null),
    _useState2 = (0, _slicedToArray2.default)(_useState, 2),
    tooltipRef = _useState2[0],
    setTooltipRef = _useState2[1]; // Needs to be state and not a ref to trigger useEffect
  var _useState3 = (0, _react.useState)(_ariaDescribedBy),
    _useState4 = (0, _slicedToArray2.default)(_useState3, 2),
    ariaDescribedBy = _useState4[0],
    setAriaDescribedBy = _useState4[1];
  var _ref2 = props,
    href = _ref2.href,
    target = _ref2.target,
    rel = _ref2.rel,
    rest = (0, _objectWithoutProperties2.default)(_ref2, _excluded2);
  var component = _element === 'a' && isDisabled ? 'button' : _element;
  var isLink = component === 'a' && !isDisabled;
  var buttonIsDisabled = (0, _button_display.isButtonDisabled)({
    href: href,
    isDisabled: component === 'button' && isDisabled
  });
  var _useEuiDisabledElemen = (0, _services.useEuiDisabledElement)({
      isDisabled: buttonIsDisabled,
      hasAriaDisabled: hasAriaDisabled,
      onKeyDown: rest.onKeyDown
    }),
    disabledRef = _useEuiDisabledElemen.ref,
    disabledButtonProps = (0, _objectWithoutProperties2.default)(_useEuiDisabledElemen, _excluded3);
  var setCombinedRef = (0, _services.useCombinedRefs)((0, _react.useMemo)(function () {
    return [disabledRef, ref];
  }, [disabledRef, ref]));
  var hasToolTip = !!_tooltipProps;
  var isNonInteractiveComponent = ['li', 'div'].includes(component);
  var isInteractiveComponent = ['button', 'a'].includes(component) || ['button', 'link'].includes(role !== null && role !== void 0 ? role : '');
  var isInteractive = isInteractiveComponent || !!onClick;
  /* Multi-action: component is interactive (button/a) and has an additional action passed via `extraAction`,
  which requires to not nest interactive elements. The wrapper is the outermost styled container and owns
  hover/focus/selected styles.
  Single-action: component (li/div) is the outermost element and owns all styles. */
  var isMultiAction = extraAction != null && isInteractiveComponent;
  var WrapperElement = isMultiAction ? wrapperElement !== null && wrapperElement !== void 0 ? wrapperElement : 'li' : isInteractiveComponent ? wrapperElement : undefined;
  var hasWrapper = WrapperElement != null;

  // aria-checked is intended to be used with role="checkbox" but
  // the MDN documentation lists it as a possibility for role="option".
  // See https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-checked
  // and https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/option_role
  var ariaChecked = (0, _react.useMemo)(function () {
    if (!role) return undefined;
    if (!ROLES_THAT_CAN_USE_ARIA_CHECKED.includes(role)) return undefined;
    switch (checked) {
      case 'on':
      case 'off':
        return true;
      case 'mixed':
        if (ROLES_THAT_CAN_BE_MIXED.includes(role)) {
          return 'mixed';
        } else {
          return false;
        }
      default:
        return _ariaChecked !== null && _ariaChecked !== void 0 ? _ariaChecked : false;
    }
  }, [role, checked, _ariaChecked]);
  var defaultSelectionMode = (0, _react.useMemo)(function () {
    if (!isSingleSelection) {
      return 'checked';
    }
    if (role && NATIVELY_CHECKABLE_ROLES.includes(role)) {
      return 'checked';
    }
    return 'selected';
  }, [isSingleSelection, role]);
  var selectionMode = _selectionMode !== null && _selectionMode !== void 0 ? _selectionMode : defaultSelectionMode;
  var hasAriaChecked = (selectionMode === 'checked' ? ariaChecked : undefined) !== undefined;
  var hasAriaSelected = ROLES_THAT_CAN_USE_ARIA_SELECTED.includes(role !== null && role !== void 0 ? role : '');
  var hasCustomAriaSelected = _ariaSelected != null;

  /* Styles */

  var wrapperClasses = (0, _classnames.default)('euiListItemLayout__wrapper', _wrapperProps === null || _wrapperProps === void 0 ? void 0 : _wrapperProps.className);
  var classes = (0, _classnames.default)('euiListItemLayout', className);
  var wrapperStyles = (0, _services.useEuiMemoizedStyles)(_list_item_layout.euiListItemLayoutWrapperStyles);
  var styles = (0, _services.useEuiMemoizedStyles)(_list_item_layout.euiListItemLayoutStyles);
  var interactiveStyles = [isInteractive && styles.isInteractive, isFocused && styles.isFocused, (isSingleSelection || !showIndicator) && isSelected && styles.isSelected, (isSingleSelection || !showIndicator) && isSelected && isFocused && styles.isSelectedFocused];
  var wrapperCssStyles = [wrapperStyles.euiListItemLayout__wrapper, extraAction && wrapperStyles.hasExtraAction, !isDisabled && hasWrapper && interactiveStyles, hasWrapper && css, isDisabled && hasWrapper && styles.isDisabled];
  var cssStyles = [styles.euiListItemLayout, hasWrapper && styles.euiListItemLayout__action, !isDisabled && !hasWrapper && interactiveStyles, !hasWrapper && css, isDisabled && styles.isDisabled, hasAriaDisabled && buttonIsDisabled && hasToolTip && styles.buttonIsDisabled];

  // Manually trigger the tooltip on keyboard focus
  (0, _react.useEffect)(function () {
    if (!tooltipRef || isFocused == null || !hasAriaDisabled && isDisabled) {
      return;
    }
    if (isFocused) {
      tooltipRef.showToolTip();
    } else {
      tooltipRef.hideToolTip();
    }
  }, [isFocused, isDisabled, hasAriaDisabled, tooltipRef]);

  /* Props */

  // Manually set the `aria-describedby` id on the wrapper
  (0, _react.useEffect)(function () {
    if (tooltipRef) {
      var tooltipId = tooltipRef.id;
      setAriaDescribedBy((0, _classnames.default)(tooltipId, _ariaDescribedBy));
    }
  }, [tooltipRef, _ariaDescribedBy]);
  var contentProps = (0, _react.useMemo)(function () {
    return _objectSpread(_objectSpread({}, _contentProps), {}, {
      css: [styles.euiListItemLayout__content, _contentProps === null || _contentProps === void 0 ? void 0 : _contentProps.css],
      className: (0, _classnames.default)('euiListItemLayout__content', _contentProps === null || _contentProps === void 0 ? void 0 : _contentProps.className)
    });
  }, [_contentProps, styles]);
  var textProps = (0, _react.useMemo)(function () {
    return _objectSpread(_objectSpread({}, _textProps), {}, {
      css: [styles.euiListItemLayout__text, styles.textWrap[textWrap], _textProps === null || _textProps === void 0 ? void 0 : _textProps.css],
      className: (0, _classnames.default)('euiListItemLayout__text', _textProps === null || _textProps === void 0 ? void 0 : _textProps.className)
    });
  }, [_textProps, textWrap, styles]);

  /**
   * ARIA selection attribute appliance:
   * - multi-selection + checkable role -> `aria-checked`
   * - multi-selection + non-checkable, selectable role -> `aria-selected`
   * - multi-selection + non-checkable, non-selectable role -> `aria-current`
   * - single-selection + checkable role -> `aria-checked`
   * - single-selection + non-checkable, selectable role -> `aria-selected`
   * - single-selection + non-checkable, non-selectable role -> `aria-current`
   */

  // added to selection list items only (`component=li/div`)
  var selectionProps = isNonInteractiveComponent && !isInteractiveComponent ? {
    role: role,
    'aria-checked': hasAriaChecked ? ariaChecked : undefined,
    'aria-selected': !hasAriaChecked && hasAriaSelected ? isSelected : undefined,
    'aria-current': !hasAriaChecked && !hasAriaSelected && isSelected ? 'true' : undefined
  } : {};

  // added to navigational list items only (`component=button/a`)
  var navigationalProps = isInteractiveComponent ? {
    /* supports aria-checked as custom `role` can enable checked states */
    'aria-checked': hasAriaChecked ? ariaChecked : undefined,
    'aria-current': !hasAriaChecked && !hasCustomAriaSelected && isSelected ? 'true' : undefined,
    // indicates currently active navigation item
    /* allow manual `aria-selected` overrides; By default a list of navigational elements likely uses `aria-current` but using
    a button with appropriate `role` within a selection list could still be valid, though weird (e.g. custom EuiSuperSelect) */
    'aria-selected': !hasAriaChecked && hasCustomAriaSelected ? isSelected : undefined // indicates current selected item
  } : {};
  var linkProps = ['a'].includes(component) && !isDisabled ? {
    href: href,
    target: target,
    rel: rel
  } : {};
  var disabledProps = isDisabled ? buttonIsDisabled ? disabledButtonProps : {
    disabled: component === 'button' ? isDisabled : undefined,
    'aria-disabled': component !== 'button' ? isDisabled : undefined
  } : {};
  var wrapperProps = _objectSpread(_objectSpread({
    'data-test-subj': "".concat(dataTestSubj, "-wrapper")
  }, _wrapperProps), {}, {
    className: wrapperClasses,
    css: [wrapperCssStyles, _wrapperProps === null || _wrapperProps === void 0 ? void 0 : _wrapperProps.css]
  });
  var tooltipProps = _objectSpread(_objectSpread({}, _tooltipProps), {}, {
    anchorProps: _objectSpread(_objectSpread({}, _tooltipProps === null || _tooltipProps === void 0 ? void 0 : _tooltipProps.anchorProps), {}, {
      css: [isDisabled && styles.tooltip.isDisabled, _tooltipProps === null || _tooltipProps === void 0 || (_tooltipProps$anchorP = _tooltipProps.anchorProps) === null || _tooltipProps$anchorP === void 0 ? void 0 : _tooltipProps$anchorP.css]
    })
  });
  var hasInternalTooltip = isNonInteractiveComponent && hasToolTip;
  var elementProps = _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({
    ref: setCombinedRef,
    role: role,
    className: classes,
    css: cssStyles
  }, selectionProps), navigationalProps), linkProps), disabledProps), {}, (0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)({}, 'aria-describedby', hasInternalTooltip ? ariaDescribedBy : _ariaDescribedBy), 'data-test-subj', dataTestSubj), "onClick", onClick), rest);

  /* Render nodes */

  var indicator = (0, _react.useMemo)(function () {
    if (showIndicator) {
      if (!isSingleSelection) {
        return (0, _react2.jsx)(_form.EuiCheckboxControl, {
          className: "euiListItemLayout__checkbox",
          checked: checked === 'on',
          disabled: isDisabled,
          indeterminate: checked === 'mixed',
          excluded: checked === 'off'
        });
      }
      var _resolveIconAndColor = resolveIconAndColor(checked, isSelected, isDisabled),
        icon = _resolveIconAndColor.icon,
        color = _resolveIconAndColor.color;
      return (0, _react2.jsx)(_icon.EuiIcon, {
        css: styles.euiListItemLayout__icon,
        className: "euiListItemLayout__icon",
        color: color,
        type: icon
      });
    }
  }, [checked, isSingleSelection, showIndicator, isSelected, isDisabled, styles]);
  var prepend = (0, _react.useMemo)(function () {
    if (_prepend) {
      var prependProps = _objectSpread(_objectSpread({}, _prependProps), {}, {
        css: [styles.euiListItemLayout__prepend, _prependProps === null || _prependProps === void 0 ? void 0 : _prependProps.css],
        className: (0, _classnames.default)('euiListItemLayout__prepend', _prependProps === null || _prependProps === void 0 ? void 0 : _prependProps.className)
      });
      return (0, _react2.jsx)("span", prependProps, _prepend);
    }
  }, [_prepend, _prependProps, styles]);
  var append = (0, _react.useMemo)(function () {
    if (_append) {
      var appendProps = _objectSpread(_objectSpread({}, _appendProps), {}, {
        css: [styles.euiListItemLayout__append, _appendProps === null || _appendProps === void 0 ? void 0 : _appendProps.css],
        className: (0, _classnames.default)('euiListItemLayout__append', _appendProps === null || _appendProps === void 0 ? void 0 : _appendProps.className)
      });
      return (0, _react2.jsx)("span", appendProps, _append);
    }
  }, [_append, _appendProps, styles]);
  var innerContent = (0, _react2.jsx)("span", contentProps, indicator, prepend, (0, _react2.jsx)("span", textProps, _children, isLink && (0, _react2.jsx)(_external_link_icon.EuiExternalLinkIcon, {
    css: styles.externalIcon,
    external: external,
    target: target,
    size: "m"
  })), append, !isMultiAction && extraAction);
  /* for non interactive elements, specifically semantic li we need to
  ensure that the li is the outer element to be a valid child of a wrapping ul */
  var content = hasInternalTooltip ? (0, _react2.jsx)(_tool_tip.EuiToolTip, (0, _extends2.default)({
    ref: setTooltipRef,
    content: tooltipProps === null || tooltipProps === void 0 ? void 0 : tooltipProps.content,
    anchorClassName: "eui-fullWidth"
  }, tooltipProps), innerContent) : innerContent;

  /* Uses `createElement` to side step having to specify element types. Since this is an
  internal-only component and we're specifying separate types for each element, we can safely
  assume the right props are passed at this point.
  It uses the import from @emotion/react to ensure the `css` props works as in JSX. */
  var innerElement = (0, _react2.createElement)(component, elementProps, content);
  var element = !isNonInteractiveComponent && hasToolTip ? (0, _react2.jsx)(_tool_tip.EuiToolTip, (0, _extends2.default)({
    ref: setTooltipRef,
    content: tooltipProps === null || tooltipProps === void 0 ? void 0 : tooltipProps.content,
    anchorClassName: "eui-fullWidth"
  }, tooltipProps), innerElement) : innerElement;
  return WrapperElement ? (0, _react2.jsx)(WrapperElement, wrapperProps, element, isMultiAction && extraAction) : element;
});
EuiListItemLayout.displayName = 'EuiListItemLayout';

/* Internal helpers */

function resolveIconAndColor(checked, isSelected, isDisabled) {
  switch (checked) {
    case 'on':
      return {
        icon: 'check',
        color: isDisabled ? 'subdued' : isSelected ? 'primary' : 'text'
      };
    case 'off':
      return {
        icon: 'cross',
        color: isDisabled ? 'subdued' : isSelected ? 'primary' : 'text'
      };
    case 'mixed':
      return {
        icon: 'minus',
        color: isDisabled ? 'subdued' : isSelected ? 'primary' : 'text'
      };
    case undefined:
    default:
      return {
        icon: 'empty',
        color: isDisabled ? 'subdued' : 'text'
      };
  }
}