UNPKG

@atlaskit/editor-plugin-highlight

Version:

Highlight plugin for @atlaskit/editor-core

111 lines (107 loc) 3.85 kB
import { entireSelectionContainsMark } from '@atlaskit/editor-common/mark'; import { TextSelection } from '@atlaskit/editor-prosemirror/state'; import { CellSelection } from '@atlaskit/editor-tables/cell-selection'; /** * Value returned by `getActiveColor` when the selection spans more than one * distinct highlight (background) color. Callers can compare against this to * detect a multi-color selection. */ export const MULTIPLE_HIGHLIGHT_COLORS_SELECTED = 'multiple'; const getAllUniqueBackgroundColorMarksInRange = (from, to, tr) => { const { doc } = tr; const { backgroundColor } = doc.type.schema.marks; const colorMarks = []; const colorSet = new Set(); doc.nodesBetween(from, to, node => { if (node.isLeaf) { const mark = backgroundColor.isInSet(node.marks); if (mark && !colorSet.has(mark.attrs.color)) { colorMarks.push(mark); colorSet.add(mark.attrs.color); } } }); return colorMarks; }; const getAllUniqueBackgroundColorMarksInCellSelection = (selection, tr) => { const colorMarks = []; const colorSet = new Set(); selection.forEachCell((cell, cellPos) => { const from = cellPos; const to = cellPos + cell.nodeSize; const marks = getAllUniqueBackgroundColorMarksInRange(from, to, tr); marks.forEach(mark => { if (!colorSet.has(mark.attrs.color)) { colorMarks.push(mark); colorSet.add(mark.attrs.color); } }); }); return colorMarks; }; // For Cell Selections - find first instance of a backgroundColor mark // if all cells entirely contain this mark, set the color. // If the selection contains multiple colors, return null const getColorFromCellSelection = (selection, tr) => { const marks = getAllUniqueBackgroundColorMarksInCellSelection(selection, tr); if (marks.length > 1) { return MULTIPLE_HIGHLIGHT_COLORS_SELECTED; } const firstColorMark = marks.at(0); if (!firstColorMark) { return null; } let foundUncolouredNode = false; selection.forEachCell((cell, cellPos) => { if (foundUncolouredNode) { return; } const from = cellPos; const to = cellPos + cell.nodeSize; if (!entireSelectionContainsMark(firstColorMark, tr.doc, from, to)) { foundUncolouredNode = true; } }); return foundUncolouredNode ? null : firstColorMark.attrs.color; }; // All other selections - find the first instance of a backgroundColor mark // if selection entirely contains this mark, set the color. // If the selection contains multiple colors, return null const getColorFromRange = (from, to, tr) => { const marks = getAllUniqueBackgroundColorMarksInRange(from, to, tr); if (marks.length > 1) { return MULTIPLE_HIGHLIGHT_COLORS_SELECTED; } const firstColorMark = marks.at(0); if (firstColorMark && entireSelectionContainsMark(firstColorMark, tr.doc, from, to)) { return firstColorMark.attrs.color; } return null; }; // For Cursor selections - set color if it is found in the storedMarks or $cursor.marks const getColorFromCursor = (selection, tr) => { var _mark$attrs$color; if (!selection.$cursor) { return null; } const mark = tr.doc.type.schema.marks.backgroundColor.isInSet([...(tr.storedMarks ? tr.storedMarks : []), ...selection.$cursor.marks()]); return (_mark$attrs$color = mark === null || mark === void 0 ? void 0 : mark.attrs.color) !== null && _mark$attrs$color !== void 0 ? _mark$attrs$color : null; }; export const getActiveColor = tr => { const { selection } = tr; let color = null; if (selection instanceof CellSelection) { color = getColorFromCellSelection(selection, tr); } else if (selection instanceof TextSelection && selection.$cursor) { color = getColorFromCursor(selection, tr); } else { color = getColorFromRange(selection.from, selection.to, tr); } return color; };