text: "use strict";
  
  Object.defineProperty(exports, "__esModule", {
    value: true
  });
  exports.hasEditableTarget = exports.PortableTextEditable = void 0;
  
  var _isEqual2 = _interopRequireDefault(require("lodash/isEqual"));
  
  var _slate = require("slate");
  
  var _isHotkey = _interopRequireDefault(require("is-hotkey"));
  
  var _react = _interopRequireWildcard(require("react"));
  
  var _slateReact = require("@sanity/slate-react");
  
  var _values = require("../utils/values");
  
  var _selection = require("../utils/selection");
  
  var _ranges = require("../utils/ranges");
  
  var _debug = require("../utils/debug");
  
  var _weakMaps = require("../utils/weakMaps");
  
  var _Leaf = require("./Leaf");
  
  var _Element = require("./Element");
  
  var _usePortableTextEditor = require("./hooks/usePortableTextEditor");
  
  var _usePortableTextEditorValue = require("./hooks/usePortableTextEditorValue");
  
  var _PortableTextEditor = require("./PortableTextEditor");
  
  var _plugins = require("./plugins");
  
  var _useForwardedRef = require("./hooks/useForwardedRef");
  
  var _excluded = ["hotkeys", "onBeforeInput", "onPaste", "onCopy", "renderAnnotation", "renderBlock", "renderChild", "renderDecorator", "renderPlaceholder", "selection", "scrollSelectionIntoView", "spellCheck"];
  
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(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; }
  
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  
  function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
  
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
  
  function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
  
  function _extends() { _extends = Object.assign || 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); }
  
  function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
  
  function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
  
  function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
  
  function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
  
  function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
  
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
  
  function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
  
  function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
  
  var debug = (0, _debug.debugWithName)('component:Editable'); // Weakmap for testing if we need to update the state value from a new value coming in from props
  
  var VALUE_TO_SLATE_VALUE = new WeakMap();
  var PLACEHOLDER_STYLE = {
    opacity: 0.5,
    position: 'absolute',
    userSelect: 'none'
  };
  
  var NOOP = () => {// Nope
  };
  
  var isDOMNode = value => {
    return value instanceof Node;
  };
  /**
   * Check if the target is editable and in the editor.
   */
  
  
  var hasEditableTarget = (editor, target) => {
    return isDOMNode(target) && _slateReact.ReactEditor.hasDOMNode(editor, target, {
      editable: true
    });
  };
  
  exports.hasEditableTarget = hasEditableTarget;
  var PortableTextEditable = /*#__PURE__*/(0, _react.forwardRef)(function PortableTextEditable(props, forwardedRef) {
    var hotkeys = props.hotkeys,
        onBeforeInput = props.onBeforeInput,
        onPaste = props.onPaste,
        onCopy = props.onCopy,
        renderAnnotation = props.renderAnnotation,
        renderBlock = props.renderBlock,
        renderChild = props.renderChild,
        renderDecorator = props.renderDecorator,
        renderPlaceholder = props.renderPlaceholder,
        propsSelection = props.selection,
        scrollSelectionIntoView = props.scrollSelectionIntoView,
        spellCheck = props.spellCheck,
        restProps = _objectWithoutProperties(props, _excluded);
  
    var portableTextEditor = (0, _usePortableTextEditor.usePortableTextEditor)();
    var value = (0, _usePortableTextEditorValue.usePortableTextEditorValue)();
    var ref = (0, _useForwardedRef.useForwardedRef)(forwardedRef);
    var slateEditor = portableTextEditor.slateInstance;
    var change$ = portableTextEditor.change$,
        isThrottling = portableTextEditor.isThrottling,
        keyGenerator = portableTextEditor.keyGenerator,
        portableTextFeatures = portableTextEditor.portableTextFeatures,
        readOnly = portableTextEditor.readOnly;
    var blockType = portableTextFeatures.types.block;
    var placeHolderBlock = (0, _react.useMemo)(() => ({
      _type: blockType.name,
      _key: keyGenerator(),
      style: portableTextFeatures.styles[0].value,
      markDefs: [],
      children: [{
        _type: 'span',
        _key: keyGenerator(),
        text: '',
        marks: []
      }]
    }), [blockType.name, keyGenerator, portableTextFeatures.styles]);
    var isEmpty = (0, _react.useMemo)(() => (0, _values.isEqualToEmptyEditor)(slateEditor.children, portableTextFeatures), [portableTextFeatures, slateEditor.children]);
    var initialValue = (0, _react.useMemo)(() => (0, _values.toSlateValue)(getValueOrInitialValue(value, [placeHolderBlock]), blockType.name, _weakMaps.KEY_TO_SLATE_ELEMENT.get(slateEditor)), // eslint-disable-next-line react-hooks/exhaustive-deps
    [placeHolderBlock, slateEditor, blockType.name] // Note that 'value' is deliberately left out here.
    ); // React/UI-spesific plugins
  
    var withInsertData = (0, _react.useMemo)(() => (0, _plugins.createWithInsertData)(change$, portableTextFeatures, keyGenerator), [change$, keyGenerator, portableTextFeatures]);
    var withHotKeys = (0, _react.useMemo)(() => (0, _plugins.createWithHotkeys)(portableTextFeatures, keyGenerator, portableTextEditor, hotkeys), [hotkeys, keyGenerator, portableTextEditor, portableTextFeatures]); // Create the PortableTextEditor API
  
    var withEditableAPI = (0, _react.useMemo)(() => (0, _plugins.createWithEditableAPI)(portableTextEditor, portableTextFeatures, keyGenerator), [keyGenerator, portableTextEditor, portableTextFeatures]); // Update the Slate instance's plugins which are dependent on props for Editable
  
    (0, _react.useMemo)(() => withHotKeys(withInsertData(withEditableAPI((0, _slateReact.withReact)(slateEditor)))), [slateEditor, withEditableAPI, withHotKeys, withInsertData]); // Track selection (action) state
  
    var _useState = (0, _react.useState)(false),
        _useState2 = _slicedToArray(_useState, 2),
        isSelecting = _useState2[0],
        setIsSelecting = _useState2[1];
  
    (0, _react.useEffect)(() => {
      slateEditor.isSelecting = isSelecting;
    }, [isSelecting, slateEditor]);
    (0, _react.useEffect)(() => {
      slateEditor.isThrottling = isThrottling;
    }, [isThrottling, slateEditor]);
    var renderElement = (0, _react.useCallback)(eProps => /*#__PURE__*/_react.default.createElement(_Element.Element, _extends({}, eProps, {
      portableTextFeatures: portableTextFeatures,
      readOnly: readOnly,
      renderBlock: renderBlock,
      renderChild: renderChild
    })), [portableTextFeatures, readOnly, renderBlock, renderChild]);
    var renderLeaf = (0, _react.useCallback)(lProps => {
      if (renderPlaceholder && lProps.leaf.placeholder) {
        return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("div", {
          style: PLACEHOLDER_STYLE,
          contentEditable: false
        }, renderPlaceholder()), /*#__PURE__*/_react.default.createElement(_Leaf.Leaf, _extends({}, lProps, {
          keyGenerator: keyGenerator,
          portableTextFeatures: portableTextFeatures,
          renderAnnotation: renderAnnotation,
          renderChild: renderChild,
          renderDecorator: renderDecorator,
          readOnly: readOnly
        })));
      }
  
      return /*#__PURE__*/_react.default.createElement(_Leaf.Leaf, _extends({}, lProps, {
        keyGenerator: keyGenerator,
        portableTextFeatures: portableTextFeatures,
        renderAnnotation: renderAnnotation,
        renderChild: renderChild,
        renderDecorator: renderDecorator,
        readOnly: readOnly
      }));
    }, [keyGenerator, portableTextFeatures, renderAnnotation, renderChild, renderDecorator, renderPlaceholder, readOnly]); // Restore value from props
  
    (0, _react.useEffect)(() => {
      if (isThrottling) {
        debug('Not setting value from props (throttling)');
        return;
      }
  
      if (isSelecting) {
        debug('Not setting value from props (is selecting)');
        return;
      }
  
      var fromMap = value && VALUE_TO_SLATE_VALUE.get(value);
  
      if (fromMap !== slateEditor.children) {
        var equal = true;
        var defaultValue = [placeHolderBlock];
        var slateValueFromProps = (0, _values.toSlateValue)(getValueOrInitialValue(value, defaultValue), blockType.name, _weakMaps.KEY_TO_SLATE_ELEMENT.get(slateEditor));
        var val = value || defaultValue;
        val.forEach((blk, index) => {
          if (slateEditor.isTextBlock(blk)) {
            if (!(0, _isEqual2.default)((0, _values.toSlateValue)([blk], blockType.name)[0], slateEditor.children[index])) {
              equal = false;
            }
          } else {
            var blkVal = slateEditor.children[index];
  
            if (!blkVal || blkVal && 'value' in blkVal && !(0, _isEqual2.default)(blk, _objectSpread({
              _key: blkVal._key,
              _type: blkVal._type
            }, blkVal.value))) {
              equal = false;
            }
          }
        }); // Only update the new value from props if the editor is not longer equal to the props value.
        // IME composing on Safari MacOS breaks when we replace the value like this.
        // This will help with that - at least in single user mode.
  
        debug("Setting value from props");
  
        if (equal) {
          debug("Editor value is in sync");
        } else {
          debug("Updating children");
          slateEditor.children = slateValueFromProps;
          slateEditor.onChange();
          VALUE_TO_SLATE_VALUE.set(val, slateEditor.children);
        }
  
        change$.next({
          type: 'value',
          value
        });
      }
    }, [change$, isSelecting, isThrottling, placeHolderBlock, blockType.name, slateEditor, value]); // Restore selection from props
  
    (0, _react.useEffect)(() => {
      if (propsSelection && !isThrottling && !(0, _isEqual2.default)(propsSelection, (0, _ranges.toPortableTextRange)(slateEditor, slateEditor.selection))) {
        debug("Selection from props ".concat(JSON.stringify(propsSelection)));
        var normalizedSelection = (0, _selection.normalizeSelection)(propsSelection, value);
  
        if (normalizedSelection !== null) {
          debug("Normalized selection from props ".concat(JSON.stringify(normalizedSelection)));
          var slateRange = (0, _ranges.toSlateRange)(normalizedSelection, slateEditor);
  
          if (slateRange) {
            _slate.Transforms.select(slateEditor, slateRange);
  
            slateEditor.onChange();
          }
        }
      } // eslint-disable-next-line react-hooks/exhaustive-deps
  
    }, [slateEditor, propsSelection]); // Note that 'isThrottling' and 'value' is deliberately left out here.
    // Set initial selection from props
  
    (0, _react.useEffect)(() => {
      if (propsSelection) {
        _PortableTextEditor.PortableTextEditor.select(portableTextEditor, propsSelection);
      } // eslint-disable-next-line react-hooks/exhaustive-deps
  
    }, []); // Only initial
    // Handle from props onCopy function
  
    var handleCopy = (0, _react.useCallback)(event => {
      if (onCopy) {
        var result = onCopy(event); // CopyFn may return something to avoid doing default stuff
  
        if (result !== undefined) {
          event.preventDefault();
        }
      }
    }, [onCopy]); // Handle incoming pasting events in the editor
  
    var handlePaste = (0, _react.useCallback)(event => {
      if (!slateEditor.selection) {
        return;
      }
  
      if (onPaste) {
        var resolveOnPasteResultOrError = () => {
          try {
            var _slateEditor$selectio;
  
            return onPaste({
              event,
              value: _PortableTextEditor.PortableTextEditor.getValue(portableTextEditor),
              path: ((_slateEditor$selectio = slateEditor.selection) === null || _slateEditor$selectio === void 0 ? void 0 : _slateEditor$selectio.focus.path) || [],
              portableTextFeatures,
              // New key added in v.2.23.2
              type: blockType // For legacy support
  
            });
          } catch (error) {
            return error;
          }
        }; // Resolve it as promise (can be either async promise or sync return value)
  
  
        var resolved = Promise.resolve(resolveOnPasteResultOrError());
        resolved.then(result => {
          debug('Custom paste function from client resolved', result);
          change$.next({
            type: 'loading',
            isLoading: true
          });
  
          if (!result) {
            return;
          }
  
          if (result instanceof Error) {
            throw result;
          }
  
          if (result && result.insert) {
            event.preventDefault(); // Stop the chain
  
            slateEditor.insertData(event.clipboardData);
            change$.next({
              type: 'loading',
              isLoading: false
            });
            return;
          }
  
          console.warn('Your onPaste function returned something unexpected:', result);
        }).catch(error => {
          change$.next({
            type: 'loading',
            isLoading: false
          });
          console.error(error); // eslint-disable-line no-console
  
          return error;
        });
      }
  
      event.preventDefault();
      slateEditor.insertData(event.clipboardData);
    }, [blockType, change$, onPaste, portableTextEditor, portableTextFeatures, slateEditor]);
  
    var _isSelecting = (0, _react.useRef)(false);
  
    var onSelectStart = (0, _react.useCallback)(event => {
      if (hasEditableTarget(slateEditor, event.target)) {
        debug('Start selecting');
        _isSelecting.current = true;
        setTimeout(() => setIsSelecting(true));
      }
    }, [slateEditor]);
    var onSelectEnd = (0, _react.useCallback)(() => {
      if (_isSelecting.current) {
        debug('Done selecting');
        setTimeout(() => setIsSelecting(false));
      }
    }, [_isSelecting]);
    var isSelectKeys = (0, _react.useCallback)(event => (0, _isHotkey.default)('shift+down', event) || (0, _isHotkey.default)('shift+end', event) || (0, _isHotkey.default)('shift+home', event) || (0, _isHotkey.default)('shift+left', event) || (0, _isHotkey.default)('shift+pageDown', event) || (0, _isHotkey.default)('shift+pageUp', event) || (0, _isHotkey.default)('shift+right', event) || (0, _isHotkey.default)('shift+up', event), []);
    var isSelectingWithKeys = (0, _react.useRef)(false);
    var onSelectStartWithKeys = (0, _react.useCallback)(event => {
      if (isSelectKeys(event)) {
        isSelectingWithKeys.current = true;
        onSelectStart(event);
      }
    }, [isSelectKeys, onSelectStart]);
    var onSelectEndWithKeys = (0, _react.useCallback)(event => {
      if (isSelectingWithKeys.current && event.key === 'Shift') {
        onSelectEnd();
        isSelectingWithKeys.current = false;
      }
    }, [onSelectEnd]);
    (0, _react.useEffect)(() => {
      if (ref.current && !readOnly) {
        var currentRef = ref.current;
        currentRef.addEventListener('keydown', onSelectStartWithKeys, false);
        currentRef.addEventListener('keyup', onSelectEndWithKeys, false);
        currentRef.addEventListener('mousedown', onSelectStart, false);
        window.addEventListener('mouseup', onSelectEnd, false); // Must be on window, or we might not catch it if the pointer is another place at the time.
  
        currentRef.addEventListener('dragend', onSelectEnd, false);
        return () => {
          currentRef.removeEventListener('keydown', onSelectStartWithKeys, false);
          currentRef.removeEventListener('keyup', onSelectEndWithKeys, false);
          currentRef.removeEventListener('mousedown', onSelectStart, false);
          window.removeEventListener('mouseup', onSelectEnd, false);
          currentRef.removeEventListener('dragend', onSelectEnd, false);
        };
      }
  
      return NOOP;
    }, [ref, onSelectEnd, onSelectEndWithKeys, onSelectStart, onSelectStartWithKeys, readOnly]);
    var handleOnFocus = (0, _react.useCallback)(() => {
      change$.next({
        type: 'focus'
      });
    }, [change$]);
    var handleOnBlur = (0, _react.useCallback)(() => {
      change$.next({
        type: 'blur'
      });
    }, [change$]);
    var handleOnBeforeInput = (0, _react.useCallback)(event => {
      if (onBeforeInput) {
        onBeforeInput(event);
      }
    }, [onBeforeInput]);
    var handleKeyDown = slateEditor.pteWithHotKeys;
    var scrollSelectionIntoViewToSlate = (0, _react.useMemo)(() => {
      // Use slate-react default scroll into view
      if (scrollSelectionIntoView === undefined) {
        return undefined;
      } // Disable scroll into view totally
  
  
      if (scrollSelectionIntoView === null) {
        return NOOP;
      } // Translate PortableTextEditor prop fn to Slate plugin fn
  
  
      return (editor, domRange) => {
        scrollSelectionIntoView(portableTextEditor, domRange);
      };
    }, [portableTextEditor, scrollSelectionIntoView]);
    var decorate = (0, _react.useCallback)(() => {
      if (isEmpty) {
        return [{
          anchor: {
            path: [0, 0],
            offset: 0
          },
          focus: {
            path: [0, 0],
            offset: 0
          },
          placeholder: true
        }];
      }
  
      return [];
    }, [isEmpty]); // The editor
  
    var slateEditable = (0, _react.useMemo)(() => /*#__PURE__*/_react.default.createElement(_slateReact.Slate, {
      onChange: NOOP,
      editor: slateEditor,
      value: initialValue
    }, /*#__PURE__*/_react.default.createElement(_slateReact.Editable, {
      autoFocus: false,
      className: "pt-editable",
      decorate: decorate,
      onBlur: handleOnBlur,
      onCopy: handleCopy,
      onDOMBeforeInput: handleOnBeforeInput,
      onFocus: handleOnFocus,
      onKeyDown: handleKeyDown,
      onPaste: handlePaste,
      readOnly: readOnly,
      renderElement: renderElement,
      renderLeaf: renderLeaf,
      scrollSelectionIntoView: scrollSelectionIntoViewToSlate,
      spellCheck: spellCheck
    })), [slateEditor, initialValue, decorate, handleOnBlur, handleCopy, handleOnBeforeInput, handleOnFocus, handleKeyDown, handlePaste, readOnly, renderElement, renderLeaf, scrollSelectionIntoViewToSlate, spellCheck]);
  
    if (!portableTextEditor) {
      return null;
    }
  
    return /*#__PURE__*/_react.default.createElement("div", _extends({
      ref: ref
    }, restProps), slateEditable);
  });
  exports.PortableTextEditable = PortableTextEditable;
  
  function getValueOrInitialValue(value, initialValue) {
    if (value && Array.isArray(value) && value.length > 0) {
      return value;
    }
  
    return initialValue;
  }