"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _react = _interopRequireWildcard(require("react"));
var _classnames = _interopRequireDefault(require("classnames"));
var _reactAce = _interopRequireDefault(require("react-ace"));
var _eui = require("@elastic/eui");
require("./_index.scss");
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
/*
 * 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.
 */

/**
 * Wraps Object.keys with proper typescript definition of the resulting array
 */
function keysOf(obj) {
  return Object.keys(obj);
}
const DEFAULT_MODE = 'text';
const DEFAULT_THEME = 'textmate';
function setOrRemoveAttribute(element, attributeName, value) {
  if (value === null || value === undefined) {
    element.removeAttribute(attributeName);
  } else {
    element.setAttribute(attributeName, value);
  }
}
class EuiCodeEditor extends _react.Component {
  constructor(props) {
    super(props);
    (0, _defineProperty2.default)(this, "state", {
      isHintActive: true,
      isEditing: false,
      name: (0, _eui.htmlIdGenerator)()()
    });
    (0, _defineProperty2.default)(this, "idGenerator", (0, _eui.htmlIdGenerator)());
    (0, _defineProperty2.default)(this, "aceEditor", null);
    (0, _defineProperty2.default)(this, "editorHint", null);
    (0, _defineProperty2.default)(this, "aceEditorRef", aceEditor => {
      var _this$props$onAceEdit, _this$props;
      if (aceEditor) {
        this.aceEditor = aceEditor;
        const textbox = aceEditor.editor.textInput.getElement();
        textbox.tabIndex = -1;
        textbox.addEventListener('keydown', this.onKeydownAce);
        setOrRemoveAttribute(textbox, 'aria-label', this.props['aria-label']);
        setOrRemoveAttribute(textbox, 'aria-labelledby', this.props['aria-labelledby']);
        setOrRemoveAttribute(textbox, 'aria-describedby', this.props['aria-describedby']);
      }
      (_this$props$onAceEdit = (_this$props = this.props).onAceEditorRef) === null || _this$props$onAceEdit === void 0 ? void 0 : _this$props$onAceEdit.call(_this$props, aceEditor);
    });
    (0, _defineProperty2.default)(this, "onEscToExit", () => {
      this.stopEditing();
      if (this.editorHint) {
        this.editorHint.focus();
      }
    });
    (0, _defineProperty2.default)(this, "onKeydownAce", event => {
      if (event.key === _eui.keys.ESCAPE) {
        event.preventDefault();
        event.stopPropagation();
        // Handles exiting edit mode when `isReadOnly` is set.
        // Other 'esc' cases handled by `stopEditingOnEsc` command.
        // Would run after `stopEditingOnEsc`.
        if (this.aceEditor !== null && !this.aceEditor.editor.completer && this.state.isEditing) {
          this.onEscToExit();
        }
      }
    });
    (0, _defineProperty2.default)(this, "onFocusAce", (event, editor) => {
      this.setState({
        isEditing: true
      });
      if (this.props.onFocus) {
        this.props.onFocus(event, editor);
      }
    });
    (0, _defineProperty2.default)(this, "onBlurAce", (event, editor) => {
      this.stopEditing();
      if (this.props.onBlur) {
        this.props.onBlur(event, editor);
      }
    });
    (0, _defineProperty2.default)(this, "startEditing", () => {
      this.setState({
        isHintActive: false
      });
      if (this.aceEditor !== null) {
        this.aceEditor.editor.textInput.focus();
      }
    });
  }
  stopEditing() {
    this.setState({
      isHintActive: true,
      isEditing: false
    });
  }
  isCustomMode() {
    return typeof this.props.mode === 'object';
  }
  setCustomMode() {
    if (this.aceEditor !== null) {
      this.aceEditor.editor.getSession().setMode(this.props.mode);
    }
  }
  componentDidMount() {
    if (this.isCustomMode()) {
      this.setCustomMode();
    }
    const {
      isReadOnly,
      id
    } = this.props;
    const textareaProps = {
      id,
      readOnly: isReadOnly
    };
    const el = document.getElementById(this.state.name);
    if (el) {
      const textarea = el.querySelector('textarea');
      if (textarea) keysOf(textareaProps).forEach(key => {
        if (textareaProps[key]) textarea.setAttribute(`${key}`, textareaProps[key].toString());
      });
    }
  }
  componentDidUpdate(prevProps) {
    if (this.props.mode !== prevProps.mode && this.isCustomMode()) {
      this.setCustomMode();
    }
  }
  render() {
    const {
      width,
      height,
      onBlur,
      isReadOnly,
      setOptions,
      cursorStart,
      mode = DEFAULT_MODE,
      'data-test-subj': dataTestSubj = 'codeEditorContainer',
      theme = DEFAULT_THEME,
      commands = [],
      ...rest
    } = this.props;
    const classes = (0, _classnames.default)('euiCodeEditorWrapper', {
      'euiCodeEditorWrapper-isEditing': this.state.isEditing
    });
    const promptClasses = (0, _classnames.default)('euiCodeEditorKeyboardHint', {
      'euiCodeEditorKeyboardHint-isInactive': !this.state.isHintActive
    });
    let filteredCursorStart;
    const options = {
      ...setOptions
    };
    if (isReadOnly) {
      // Put the cursor at the beginning of the editor, so that it doesn't look like
      // a prompt to begin typing.
      filteredCursorStart = -1;
      Object.assign(options, {
        readOnly: true,
        highlightActiveLine: false,
        highlightGutterLine: false
      });
    } else {
      filteredCursorStart = cursorStart;
    }
    const prompt = /*#__PURE__*/_react.default.createElement("button", {
      className: promptClasses,
      id: this.idGenerator('codeEditor'),
      ref: hint => {
        this.editorHint = hint;
      },
      onClick: this.startEditing,
      "data-test-subj": "codeEditorHint"
    }, /*#__PURE__*/_react.default.createElement("p", {
      className: "euiText"
    }, isReadOnly ? /*#__PURE__*/_react.default.createElement(_eui.EuiI18n, {
      token: "euiCodeEditor.startInteracting",
      default: "Press Enter to start interacting with the code."
    }) : /*#__PURE__*/_react.default.createElement(_eui.EuiI18n, {
      token: "euiCodeEditor.startEditing",
      default: "Press Enter to start editing."
    })), /*#__PURE__*/_react.default.createElement("p", {
      className: "euiText"
    }, isReadOnly ? /*#__PURE__*/_react.default.createElement(_eui.EuiI18n, {
      token: "euiCodeEditor.stopInteracting",
      default: "When you're done, press Escape to stop interacting with the code."
    }) : /*#__PURE__*/_react.default.createElement(_eui.EuiI18n, {
      token: "euiCodeEditor.stopEditing",
      default: "When you're done, press Escape to stop editing."
    })));
    return /*#__PURE__*/_react.default.createElement("div", {
      className: classes,
      style: {
        width,
        height
      },
      "data-test-subj": dataTestSubj
    }, prompt, /*#__PURE__*/_react.default.createElement(_reactAce.default
    // Setting a default, existing `mode` is necessary to properly initialize the editor
    // prior to dynamically setting a custom mode (https://github.com/elastic/eui/pull/2616)
    , (0, _extends2.default)({
      mode: this.isCustomMode() ? DEFAULT_MODE : mode // https://github.com/securingsincity/react-ace/pull/771
      ,
      name: this.state.name,
      theme: theme,
      ref: this.aceEditorRef,
      width: width,
      height: height,
      onFocus: this.onFocusAce,
      onBlur: this.onBlurAce,
      setOptions: options,
      editorProps: {
        $blockScrolling: Infinity
      },
      cursorStart: filteredCursorStart,
      commands: [
      // Handles exiting edit mode in all cases except `isReadOnly`
      // Runs before `onKeydownAce`.
      {
        name: 'stopEditingOnEsc',
        bindKey: {
          win: 'Esc',
          mac: 'Esc'
        },
        exec: this.onEscToExit
      }, ...commands]
    }, rest)));
  }
}

// Needed for React.lazy
// eslint-disable-next-line import/no-default-export
(0, _defineProperty2.default)(EuiCodeEditor, "defaultProps", {
  setOptions: {
    showLineNumbers: false,
    tabSize: 2
  }
});
var _default = EuiCodeEditor;
exports.default = _default;
module.exports = exports.default;