function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }

/*
Copyright (c) Uber Technologies, Inc.

This source code is licensed under the MIT license found in the
LICENSE file in the root directory of this source tree.
*/
import * as React from 'react';
import TreeNode from './tree-node';
import { StyledTreeItemList } from './styled-components';
import { getPrevId, getNextId, getParentId, getFirstChildId, getEndId, getExpandableSiblings, defaultGetId, getCharMatchId } from './utils';
import { isFocusVisible } from '../utils/focusVisible';
import { getOverride, getOverrideProps } from '../helpers/overrides';
export default function TreeView(props) {
  const {
    data,
    indentGuides = false,
    onToggle,
    overrides = {},
    renderAll,
    getId = defaultGetId
  } = props;
  const {
    Root: RootOverride
  } = overrides;
  const Root = getOverride(RootOverride) || StyledTreeItemList;
  const firstId = data.length > 0 ? getId(data[0]) : 0;
  const [selectedNodeId, setSelectedNodeId] = React.useState(firstId);
  const [focusVisible, setFocusVisible] = React.useState(false);
  const [typeAheadChars, setTypeAheadChars] = React.useState('');
  const timeOutRef = React.useRef(null);
  const treeItemRefs = {};

  const focusTreeItem = id => {
    if (!id) return;
    setSelectedNodeId(id);
    const refs = treeItemRefs[id]; // @ts-expect-error

    const node = refs && refs.current;
    if (node) node.focus();
  };

  const onKeyDown = (e, node) => {
    const elementId = e.target.getAttribute('data-nodeid'); // this check prevents bubbling

    if (elementId !== getId(node) && parseInt(elementId) !== getId(node)) {
      return;
    }

    switch (e.key) {
      case 'ArrowRight':
        e.preventDefault();

        if (typeof node.isExpanded === 'boolean' && !node.isExpanded) {
          onToggle && onToggle(node);
        } else {
          focusTreeItem(getFirstChildId(data, selectedNodeId, getId));
        }

        break;

      case 'ArrowLeft':
        e.preventDefault();

        if (typeof node.isExpanded === 'boolean' && node.isExpanded) {
          onToggle && onToggle(node);
        } else {
          focusTreeItem(getParentId(data, selectedNodeId, null, getId));
        }

        break;

      case 'ArrowUp':
        e.preventDefault();
        focusTreeItem(getPrevId(data, selectedNodeId, null, getId));
        break;

      case 'ArrowDown':
        e.preventDefault();
        focusTreeItem(getNextId(data, selectedNodeId, null, getId));
        break;

      case ' ':
      case 'Enter':
        e.preventDefault();
        onToggle && onToggle(node);
        break;

      case 'Home':
        e.preventDefault();

        if (data.length) {
          focusTreeItem(getId(data[0]));
        }

        break;

      case 'End':
        e.preventDefault();
        focusTreeItem(getEndId(data, getId));
        break;

      case '*':
        e.preventDefault();
        getExpandableSiblings(data, selectedNodeId, getId).forEach(node => onToggle && onToggle(node));
        break;

      default:
        if (timeOutRef.current !== null) {
          clearTimeout(timeOutRef.current);
        }

        setTypeAheadChars(typeAheadChars + e.key);
        timeOutRef.current = setTimeout(() => {
          setTypeAheadChars('');
        }, 500);
        focusTreeItem(getCharMatchId(data, selectedNodeId, typeAheadChars + e.key, null, getId));
        break;
    }
  };

  const onFocus = event => {
    if (isFocusVisible(event)) {
      setFocusVisible(true);
    }

    if (selectedNodeId === null && data.length) {
      setSelectedNodeId(getId(data[0]));
    }
  };

  const onBlur = event => {
    if (focusVisible) {
      setFocusVisible(false);
    }
  };

  return /*#__PURE__*/React.createElement(Root, _extends({
    role: "tree"
  }, getOverrideProps(RootOverride)), data.map(node => /*#__PURE__*/React.createElement(TreeNode, {
    indentGuides: indentGuides,
    key: getId(node),
    node: node,
    getId: getId,
    onToggle: node => {
      onToggle && onToggle(node);
      focusTreeItem(getId(node));
    },
    overrides: overrides,
    renderAll: renderAll,
    selectedNodeId: selectedNodeId,
    onKeyDown: onKeyDown,
    onFocus: onFocus,
    onBlur: onBlur,
    addRef: (id, ref) => {
      treeItemRefs[id] = ref;
    },
    removeRef: id => {
      delete treeItemRefs[id];
    },
    isFocusVisible: focusVisible
  })));
}