UNPKG

@atlaskit/editor-plugin-code-block-advanced

Version:

CodeBlockAdvanced plugin for @atlaskit/editor-core

105 lines (101 loc) 4.14 kB
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 });