@atlaskit/editor-plugin-block-controls
Version:
Block controls plugin for @atlaskit/editor-core
56 lines (53 loc) • 2.52 kB
JavaScript
import { Decoration, DecorationSet } from '@atlaskit/editor-prosemirror/view';
export const TYPE_SURFACE_ANCHOR_DEC = 'block-controls-surface-anchor';
export const SURFACE_ANCHOR_ATTR = 'data-block-controls-surface-anchor';
export const SURFACE_NODE_TYPE_ATTR = 'data-block-controls-surface-node-type';
export const SURFACE_ANCHOR_VARIABLE = '--block-controls-surface-anchor-name';
/**
* These node views expose the box used by the measured placement fallback rather than their
* ProseMirror node wrapper. The marker carries the name through a custom property so sparse CSS
* can name that inner box without adding a widget or changing the node view.
*/
const INNER_CONTENT_NODE_TYPES = new Set(['blockCard', 'bodiedExtension', 'embedCard', 'extension', 'mediaSingle', 'multiBodiedExtension', 'table']);
const getMarkerStyle = (nodeType, anchorName) => {
const inheritedName = `${SURFACE_ANCHOR_VARIABLE}: ${anchorName};`;
// Inner boxes get their anchor from the sparse global selector. Naming only the node wrapper
// would position media/table/extension controls against the wrapper instead of visible content.
return INNER_CONTENT_NODE_TYPES.has(nodeType) ? inheritedName : `${inheritedName} anchor-name: ${anchorName};`;
};
/**
* Builds sparse CSS anchor decorations from already-qualified cached positions. Anchor identity is
* supplied by the editor's native node-anchor provider so sparse surfaces and consumers share the
* same `data-node-anchor`.
*/
export const createSurfaceAnchorDecorations = (state, positions, resolveAnchorName, previousAnchors) => {
const anchors = new Map();
const decorations = [];
for (const position of positions) {
if (anchors.has(position)) {
continue;
}
const node = state.doc.nodeAt(position);
if (!(node !== null && node !== void 0 && node.isBlock)) {
continue;
}
const anchorName = resolveAnchorName(node, position, previousAnchors === null || previousAnchors === void 0 ? void 0 : previousAnchors.get(position));
if (!anchorName) {
continue;
}
anchors.set(position, anchorName);
decorations.push(Decoration.node(position, position + node.nodeSize, {
[SURFACE_ANCHOR_ATTR]: anchorName,
[SURFACE_NODE_TYPE_ATTR]: node.type.name,
style: getMarkerStyle(node.type.name, anchorName)
}, {
type: TYPE_SURFACE_ANCHOR_DEC,
anchorName,
nodeType: node.type.name
}));
}
return {
anchors,
decorations: DecorationSet.create(state.doc, decorations)
};
};