@atlaskit/editor-plugin-code-block-advanced
Version:
CodeBlockAdvanced plugin for @atlaskit/editor-core
105 lines (101 loc) • 4.14 kB
JavaScript
import { ViewPlugin, WidgetType, Decoration as CodeMirrorDecoration } from '@codemirror/view';
import { fg } from '@atlaskit/platform-feature-flags';
class PMWidget extends WidgetType {
constructor(toDOMElement) {
super();
this.toDOMElement = toDOMElement;
}
toDOM() {
return this.toDOMElement;
}
ignoreEvent() {
return false;
}
}
// This type is not exposed publically by ProseMirror but we need it to map to CodeMirror
// See: https://github.com/ProseMirror/prosemirror-view/blob/master/src/decoration.ts
// This type is not exposed publically by ProseMirror but we need it to map to CodeMirror
// See: https://github.com/ProseMirror/prosemirror-view/blob/master/src/decoration.ts
// This type is not exposed publically by ProseMirror but we need it to map to CodeMirror
// See: https://github.com/ProseMirror/prosemirror-view/blob/master/src/decoration.ts
function isExtendedDecoration(decoration) {
return decoration.inline !== undefined && decoration.widget !== undefined && decoration.type !== undefined;
}
const getHTMLElement = (toDOM, view, getPos) => {
if (toDOM instanceof Function) {
const element = toDOM(view, getPos);
return element instanceof HTMLElement ? element : undefined;
} else if (toDOM instanceof HTMLElement) {
return toDOM;
}
};
const mapPMDecorationToCMDecoration = (decoration, view, getPos) => {
if (!isExtendedDecoration(decoration)) {
return undefined;
}
if (decoration.inline) {
const markDecoration = CodeMirrorDecoration.mark({
attributes: decoration.type.attrs
});
return markDecoration.range(decoration.from, decoration.to);
} else if (decoration.widget) {
var _decoration$type;
const toDOM = getHTMLElement(decoration === null || decoration === void 0 ? void 0 : (_decoration$type = decoration.type) === null || _decoration$type === void 0 ? void 0 : _decoration$type.toDOM, view, getPos);
if (!toDOM) {
return undefined;
}
const widgetDecoration = CodeMirrorDecoration.widget({
widget: new PMWidget(toDOM),
side: decoration.type.side
});
return widgetDecoration.range(decoration.from, decoration.to);
}
};
function isDefined(value) {
return value !== undefined;
}
export const sortDecorationsByPositionAndSide = (a, b) => a.from - b.from || a.value.startSide - b.value.startSide;
/**
* Creates CodeMirror versions of the decorations provided by ProseMirror.
*
* Inline ProseMirror decorations -> Mark CodeMirror decorations
* Widget ProseMirror decorations -> Widget CodeMirror decorations
*
* This way any decorations applied in ProseMirror land should automatically be supported
* by the CodeMirror editor
*
* @param updateDecorationsEffect Facet for the prosemirror decorations
* @returns CodeMirror extension
*/
export const prosemirrorDecorationPlugin = (updateDecorationsEffect, editorView, getPos) => ViewPlugin.fromClass(class {
constructor(view) {
this.decorations = this.updateDecorations(view);
}
updateDecorations(view) {
const {
from,
to
} = view.viewport;
const innnerDecorations = view.state.facet(updateDecorationsEffect);
const allDecorations = [];
innnerDecorations === null || innnerDecorations === void 0 ? void 0 : innnerDecorations.map(source => {
source === null || source === void 0 ? void 0 : source.forEachSet(set => {
const decorations = set.find(from, to)
// Do not render the code block line decorations
.filter(dec => dec.spec.type !== 'decorationWidgetType');
allDecorations.push(...decorations);
});
});
const cmDecorations = allDecorations.sort((a, b) => a.from < b.from ? -1 : 1).map(decoration => mapPMDecorationToCMDecoration(decoration, editorView, getPos)).filter(isDefined);
if (fg('platform_editor_fix_decoration_edge_case')) {
return CodeMirrorDecoration.set(cmDecorations.sort(sortDecorationsByPositionAndSide));
} else {
return CodeMirrorDecoration.set(cmDecorations);
}
}
update(update) {
this.decorations = this.updateDecorations(update.view);
}
}, {
decorations: v => v.decorations
});