"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.pluginFactory = pluginFactory;
/**
 * Creates a ProseMirror plugin's state and handles UI updates.
 *
 * Here's a few things to keep in mind:
 * - plugin's state is stored as a single object
 * - `Reducer` specifies how plugin's state changes in response to commands
 * - `Command` describes only what happen, but not how state changes
 * - `mapping` could be used to map ProseMirror positions stored in plugin's state
 *
 * Example:
 *  const { createPluginState, createCommand, getPluginState } = pluginFactory(
 *    reducer,
 *    pluginKey
 *  );
 *
 *  export const createPlugin = (dispatch: Dispatch, initialState) =>
 *    new SafePlugin({
 *      state: createPluginState(dispatch, initialState),
 *      key: pluginKey
 *    });
 *
 * Example of a reducer:
 *
 *  export const reducer = (
 *    state: TablePluginState,
 *    action: TableAction,
 *  ): TablePluginState => {
 *    switch (action.type) {
 *      case 'TOGGLE_CONTEXTUAL_MENU':
 *      return {
 *        ...state,
 *        isContextualMenuOpen: !state.isContextualMenuOpen,
 *      };
 *    default:
 *      return state;
 *    }
 *  };
 *
 *
 * Example of a command:
 *
 * export const toggleContextualMenu = createCommand({
 *   type: 'TOGGLE_CONTEXTUAL_MENU',
 * }, tr => tr.setMeta('addToHistory', false));
 *
 */

function isFunction(x) {
  return typeof x === 'function';
}
function pluginFactory(pluginKey, reducer) {
  var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
  var mapping = options.mapping,
    onDocChanged = options.onDocChanged,
    onSelectionChanged = options.onSelectionChanged;
  return {
    createPluginState: function createPluginState(dispatch, initialState) {
      return {
        init: function init(_, state) {
          return isFunction(initialState) ? initialState(state) : initialState;
        },
        apply: function apply(tr, _pluginState, _oldEditorState, newEditorState) {
          var oldPluginState = mapping ? mapping(tr, _pluginState, newEditorState) : _pluginState;
          var newPluginState = oldPluginState;
          var meta = tr.getMeta(pluginKey);
          if (meta) {
            newPluginState = reducer(oldPluginState, meta);
          }
          if (onDocChanged && tr.docChanged) {
            newPluginState = onDocChanged(tr, newPluginState, newEditorState);
          } else if (onSelectionChanged && tr.selectionSet) {
            newPluginState = onSelectionChanged(tr, newPluginState, newEditorState);
          }
          if (newPluginState !== oldPluginState) {
            dispatch(pluginKey, newPluginState);
          }
          return newPluginState;
        }
      };
    },
    createCommand: function createCommand(action, transform) {
      return function (state, dispatch) {
        if (dispatch) {
          var _tr = transform ? transform(state.tr, state) : state.tr;
          var resolvedAction = isFunction(action) ? action(state) : action;
          if (_tr && resolvedAction) {
            dispatch(_tr.setMeta(pluginKey, resolvedAction));
          } else {
            return false;
          }
        }
        return true;
      };
    },
    getPluginState: function getPluginState(state) {
      return pluginKey.getState(state);
    }
  };
}