@atlaskit/editor-plugin-selection-marker
Version:
Selection marker plugin for @atlaskit/editor-core.
92 lines • 3.62 kB
JavaScript
import debounce from 'lodash/debounce';
import { getBrowserInfo } from '@atlaskit/editor-common/browser';
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
import { isEmptyDocument } from '@atlaskit/editor-common/utils';
import { PluginKey } from '@atlaskit/editor-prosemirror/state';
import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
import { selectionDecoration } from '../ui/selection-decoration';
import { createWidgetDecoration } from '../ui/widget-decoration';
export const key = new PluginKey('selectionMarker');
function getDecorations(tr, type) {
const {
selection
} = tr;
switch (type) {
case 'none':
return DecorationSet.empty;
case 'highlight':
return DecorationSet.create(tr.doc, [...createWidgetDecoration(selection.$anchor, 'anchor', selection, true), ...selectionDecoration(tr.doc, selection, true), ...createWidgetDecoration(selection.$head, 'head', selection, true)]);
case 'blur':
return DecorationSet.create(tr.doc, [...createWidgetDecoration(selection.$anchor, 'anchor', selection, false), ...selectionDecoration(tr.doc, selection, false)]);
}
}
function getDecorationType(tr, shouldHideDecorations) {
if (shouldHideDecorations || isEmptyDocument(tr.doc)) {
return 'none';
}
// TODO: ED-26961 - implement "highlight" for AI features
return 'blur';
}
export const applyNextPluginState = (tr, currentState, oldEditorState) => {
var _meta$forceHide, _meta$shouldHideDecor;
const meta = tr.getMeta(key);
if (!meta && !tr.selectionSet) {
return currentState;
}
const forceHide = (_meta$forceHide = meta === null || meta === void 0 ? void 0 : meta.forceHide) !== null && _meta$forceHide !== void 0 ? _meta$forceHide : currentState.forceHide;
const shouldHideDecorations = (_meta$shouldHideDecor = meta === null || meta === void 0 ? void 0 : meta.shouldHideDecorations) !== null && _meta$shouldHideDecor !== void 0 ? _meta$shouldHideDecor : currentState.shouldHideDecorations;
const type = getDecorationType(tr, shouldHideDecorations);
let nextDecorations = currentState.decorations;
const hasSelectionChangedToRange = oldEditorState.selection.empty && !tr.selection.empty;
if (hasSelectionChangedToRange || currentState.decorationType !== type) {
nextDecorations = getDecorations(tr, type);
} else {
nextDecorations = nextDecorations.map(tr.mapping, tr.doc, {});
}
return {
decorations: nextDecorations,
shouldHideDecorations,
forceHide,
decorationType: type
};
};
const debouncedDecorations = debounce(state => {
var _key$getState;
return (_key$getState = key.getState(state)) === null || _key$getState === void 0 ? void 0 : _key$getState.decorations;
}, 25);
export const createPlugin = api => {
return new SafePlugin({
key,
state: {
init() {
return {
decorations: DecorationSet.empty,
shouldHideDecorations: true,
forceHide: false,
decorationType: 'none'
};
},
apply: applyNextPluginState
},
props: {
decorations: state => {
const browser = getBrowserInfo();
if (browser.ie) {
return debouncedDecorations(state);
} else {
var _key$getState2;
return (_key$getState2 = key.getState(state)) === null || _key$getState2 === void 0 ? void 0 : _key$getState2.decorations;
}
}
}
});
};
export function dispatchShouldHideDecorations(editorView, shouldHideDecorations) {
const {
dispatch,
state
} = editorView;
dispatch(state.tr.setMeta(key, {
shouldHideDecorations
}));
}