@atlaskit/editor-plugin-synced-block
Version:
SyncedBlock plugin for @atlaskit/editor-core
58 lines • 2.79 kB
JavaScript
import { bindAll } from 'bind-event-listener';
import { SyncBlockSharedCssClassName, SyncBlockLabelSharedCssClassName } from '@atlaskit/editor-common/styles/sync-block';
import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
const getSelectedReference = view => {
const selection = view.dom.ownerDocument.getSelection();
const anchor = selection === null || selection === void 0 ? void 0 : selection.anchorNode;
const anchorElement = anchor instanceof Element ? anchor : anchor === null || anchor === void 0 ? void 0 : anchor.parentElement;
const renderer = anchorElement === null || anchorElement === void 0 ? void 0 : anchorElement.closest(`.${SyncBlockSharedCssClassName.renderer}`);
if (!renderer || !(selection !== null && selection !== void 0 && selection.focusNode) || !renderer.contains(selection.focusNode)) {
return null;
}
const reference = renderer.closest(`.${SyncBlockSharedCssClassName.prefix}`);
return reference && view.dom.contains(reference) ? reference : null;
};
export const createReferenceSelectionView = view => {
const syncReferenceSelection = reference => {
var _doc$nodeAt;
if (!view.editable || !reference) {
return;
}
const pos = view.posAtDOM(reference, 0);
const {
doc,
schema,
selection
} = view.state;
if (((_doc$nodeAt = doc.nodeAt(pos)) === null || _doc$nodeAt === void 0 ? void 0 : _doc$nodeAt.type) !== schema.nodes.syncBlock || selection instanceof NodeSelection && selection.from === pos) {
return;
}
// The selectable renderer owns native focus, so PM's observer ignores its selection.
// Track the containing atom without focusing the editor or clearing highlighted text.
view.dispatch(view.state.tr.setSelection(NodeSelection.create(doc, pos)));
};
const unbind = bindAll(view.dom.ownerDocument, [{
type: 'selectionchange',
listener: () => syncReferenceSelection(getSelectedReference(view))
}, {
type: 'click',
listener: event => {
if (event.button !== 0 || !view.editable) {
return;
}
const target = event.target instanceof Element ? event.target : null;
const reference = target === null || target === void 0 ? void 0 : target.closest(`.${SyncBlockSharedCssClassName.prefix}`);
if (!reference || !view.dom.contains(reference)) {
return;
}
// Edge clicks never create a native selection inside the renderer.
syncReferenceSelection(reference);
if (!(target !== null && target !== void 0 && target.closest(`.${SyncBlockSharedCssClassName.renderer}`)) && !(target !== null && target !== void 0 && target.closest(`.${SyncBlockLabelSharedCssClassName.labelClassName}`))) {
view.focus();
}
}
}]);
return {
destroy: unbind
};
};