@atlaskit/editor-plugin-scroll-into-view
Version:
Scroll-into-view plugin for @atlaskit/editor-core
60 lines (58 loc) • 2.41 kB
JavaScript
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
import { PluginKey } from '@atlaskit/editor-prosemirror/state';
import { ReplaceStep, ReplaceAroundStep } from '@atlaskit/editor-prosemirror/transform';
import { TEXT_INPUT_RULE_TRANSACTION_KEY } from '@atlaskit/prosemirror-input-rules';
/**
* Plugin to scroll the user's selection into view whenever the user updates
* the document eg. inserting, deleting, formatting
*
* Behaviour is on by default, can be explicitly opted out of for a transaction by
* setting scrollIntoView=false meta
* We ignore collab transactions, appended transactions, transactions without steps,
* transactions with addToHistory=false meta and typeahead trigger transactions
*/
export const scrollIntoViewPluginKey = new PluginKey('scrollIntoViewPlugin');
/**
* Determines if a transaction contains changes that should trigger scrolling into view.
* This includes:
* - Specific step types (Replace, ReplaceAround)
*/
const hasRelevantChanges = tr => {
// Check if there are any steps that modified the document
if (!tr.docChanged) {
return false;
}
// Look for specific types of steps that should trigger scrolling
const hasRelevantStep = tr.steps.some(step => step instanceof ReplaceStep || step instanceof ReplaceAroundStep);
return hasRelevantStep;
};
const createPlugin = () => new SafePlugin({
key: scrollIntoViewPluginKey,
appendTransaction: (transactions, _oldState, newState) => {
if (!transactions.length) {
return;
}
const tr = transactions[0];
if ((hasRelevantChanges(tr) || tr.storedMarksSet) && !tr.scrolledIntoView && tr.getMeta('scrollIntoView') !== false &&
// ignore anything we would not want to undo
// this covers things like autofixing layouts, hovering table rows/cols
tr.getMeta('addToHistory') !== false &&
// ignore collab changes from another user
!tr.getMeta('isRemote') &&
// ignore any transaction coming from the input text rule plugin
!tr.getMeta(TEXT_INPUT_RULE_TRANSACTION_KEY) &&
// ignore appended transactions as they should be treated as side effects
tr.getMeta('appendedTransaction') === undefined) {
return newState.tr.scrollIntoView();
}
}
});
export const scrollIntoViewPlugin = () => ({
name: 'scrollIntoView',
pmPlugins() {
return [{
name: 'scrollIntoView',
plugin: () => createPlugin()
}];
}
});