UNPKG

@atlaskit/editor-plugin-history

Version:

History plugin for @atlaskit/editor-core

158 lines 5.21 kB
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin'; import { pluginFactory } from '@atlaskit/editor-common/utils'; import { undo } from '@atlaskit/prosemirror-history/undo'; import { HistoryActionTypes } from './editor-actions/actions'; import reducer from './editor-actions/reducer'; import { getPmHistoryPluginState } from './editor-actions/utils'; import { historyPluginKey } from './pm-plugins/plugin-key'; const getInitialState = () => ({ canUndo: false, canRedo: false }); const { createPluginState, getPluginState } = pluginFactory(historyPluginKey, reducer); /** * Expose prosemirror-history's `undo` as an `EditorCommand`. `undo(state, dispatch)` * builds its own transaction, so capture that transaction and return it in place of the * one passed in. Nothing is re-implemented: the returned transaction is exactly what * pressing Cmd+Z would dispatch, and callers may add metadata to it before it is * dispatched by `api.core.actions.execute`. */ const undoCommand = editorViewRef => ({ tr }) => { var _editorViewRef$curren; const state = (_editorViewRef$curren = editorViewRef.current) === null || _editorViewRef$curren === void 0 ? void 0 : _editorViewRef$curren.state; // The caller's `tr` is discarded, so refuse if it already carries changes or is stale. if (!state || tr.steps.length > 0 || tr.before !== state.doc) { return null; } let undoTr = null; undo(state, built => { undoTr = built; }); return undoTr; }; const createPlugin = (dispatch, editorViewRef) => new SafePlugin({ state: createPluginState(dispatch, getInitialState), key: historyPluginKey, view: editorView => { editorViewRef.current = editorView; return { destroy: () => { if (editorViewRef.current === editorView) { editorViewRef.current = undefined; } } }; }, appendTransaction: (transactions, oldState, newState) => { if (transactions.find(tr => tr.docChanged && tr.getMeta('addToHistory') !== false || tr.getMeta('endHistorySlice'))) { const pmHistoryPluginState = getPmHistoryPluginState(newState); if (!pmHistoryPluginState) { return; } const canUndo = pmHistoryPluginState.done.eventCount > 0; const canRedo = pmHistoryPluginState.undone.eventCount > 0; const { canUndo: prevCanUndo, canRedo: prevCanRedo } = getPluginState(newState); if (canUndo !== prevCanUndo || canRedo !== prevCanRedo) { const action = { type: HistoryActionTypes.UPDATE, canUndo, canRedo }; return newState.tr.setMeta(historyPluginKey, action); } } } }); const historyPlugin = ({ api }) => { let currentId = null; const editorViewRef = { current: undefined }; return { name: 'history', pmPlugins() { return [{ name: 'history', plugin: ({ dispatch }) => createPlugin(dispatch, editorViewRef) }]; }, getSharedState: editorState => { var _getPmHistoryPluginSt, _done$eventCount, _undone$eventCount; if (!editorState) { return undefined; } const historyPluginState = historyPluginKey.getState(editorState); if (!historyPluginState) { return undefined; } const { done, undone } = (_getPmHistoryPluginSt = getPmHistoryPluginState(editorState)) !== null && _getPmHistoryPluginSt !== void 0 ? _getPmHistoryPluginSt : {}; return { canUndo: historyPluginState.canUndo, canRedo: historyPluginState.canRedo, done: { eventCount: (_done$eventCount = done === null || done === void 0 ? void 0 : done.eventCount) !== null && _done$eventCount !== void 0 ? _done$eventCount : 0 }, undone: { eventCount: (_undone$eventCount = undone === null || undone === void 0 ? void 0 : undone.eventCount) !== null && _undone$eventCount !== void 0 ? _undone$eventCount : 0 } }; }, commands: { undo: undoCommand(editorViewRef), updatePluginState: ({ tr }) => { var _api$history$sharedSt; const { done, undone } = (_api$history$sharedSt = api === null || api === void 0 ? void 0 : api.history.sharedState.currentState()) !== null && _api$history$sharedSt !== void 0 ? _api$history$sharedSt : {}; if (done === undefined || undone === undefined) { return tr; } const canUndo = done.eventCount > 0; const canRedo = undone.eventCount > 0; const action = { type: HistoryActionTypes.UPDATE, canUndo, canRedo }; return tr.setMeta(historyPluginKey, action); }, startHistorySlice: id => ({ tr }) => { if (currentId) { return null; } currentId = id; return tr.setMeta('startHistorySlice', true); }, endHistorySlice: id => ({ tr }) => { if (currentId !== id) { return null; } currentId = null; return tr.setMeta('endHistorySlice', true); } } }; }; export default historyPlugin;