@atlaskit/editor-common
Version:
A package that contains common classes and components for editor and renderer
103 lines (102 loc) • 3.42 kB
JavaScript
/**
* 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));
*
*/
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function isFunction(x) {
return typeof x === 'function';
}
export 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;
},
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/max-params
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);
}
};
}