@atlaskit/editor-plugin-selection-toolbar
Version:
@atlaskit/editor-plugin-selection-toolbar for @atlaskit/editor-core
127 lines (118 loc) • 5.19 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.calculateToolbarPositionTrackHead = void 0;
/**
* These functions are currently not used. They were added to provide more control
* of the toolbar in different products, i.e confluence comments and annotations.
* Work to add the toolbar to more products has been paused at the time of writing.
*/
var getScrollParent = function getScrollParent(editorView) {
var _editorContentArea$pa;
// Find the nearest Editor
// Ignored via go/ees005
// eslint-disable-next-line @atlaskit/editor/no-as-casting
var editorContentArea = editorView.dom.closest('.ak-editor-content-area');
// Check if the Editor is a child of another, the annotation editor inside
// Confluence full-page editor for example.
// If so, we need to append the toolbar to the closest Editor
if (editorContentArea !== null && editorContentArea !== void 0 && (_editorContentArea$pa = editorContentArea.parentElement) !== null && _editorContentArea$pa !== void 0 && _editorContentArea$pa.closest('.ak-editor-content-area')) {
return {
scrollWrapper: editorContentArea,
offset: editorContentArea.offsetTop
};
}
// If the Editor is full-page there should be a parent .fabric-editor-popup-scroll-parent
var scrollParent = editorView.dom.closest('.fabric-editor-popup-scroll-parent');
// If there is a scroll parent then we can assume the Editor is full-page
if (scrollParent) {
return {
scrollWrapper: scrollParent,
offset: scrollParent.scrollTop
};
}
// If there is no scroll parent then we can assume the Editor is not full-page
if (editorContentArea && !scrollParent) {
return {
scrollWrapper: editorContentArea,
offset: editorContentArea.offsetTop
};
}
// Use the document body as a fallback
return {
scrollWrapper: document.body,
offset: 0
};
};
/*
Calculates the position of the floating toolbar relative to the selection.
This is a re-implementation which closely matches the behaviour on Confluence renderer.
The main difference is the popup is always above the selection.
Things to consider:
- stick as close to the head X release coordinates as possible
- coordinates of head X and getBoundingClientRect() are absolute in client viewport (not including scroll offsets)
- popup may appear in '.fabric-editor-popup-scroll-parent' (or body)
- we use the toolbarRect to center align toolbar
- use wrapperBounds to clamp values
- editorView.dom bounds differ to wrapperBounds, convert at the end
*/
var calculateToolbarPositionTrackHead = exports.calculateToolbarPositionTrackHead = function calculateToolbarPositionTrackHead(toolbarTitle) {
return function (editorView, nextPos) {
// Ignored via go/ees005
// eslint-disable-next-line @atlaskit/editor/no-as-casting
var toolbar = document.querySelector("div[aria-label=\"".concat(toolbarTitle, "\"]"));
if (!toolbar) {
return nextPos;
}
var _getScrollParent = getScrollParent(editorView),
scrollWrapper = _getScrollParent.scrollWrapper,
offset = _getScrollParent.offset;
var wrapperBounds = scrollWrapper.getBoundingClientRect();
var selection = window && window.getSelection();
var range = selection && !selection.isCollapsed && selection.getRangeAt(0);
if (!range) {
return nextPos;
}
var toolbarRect = toolbar.getBoundingClientRect();
var _editorView$state$sel = editorView.state.selection,
head = _editorView$state$sel.head,
anchor = _editorView$state$sel.anchor;
var topCoords = editorView.coordsAtPos(Math.min(head, anchor));
var bottomCoords = editorView.coordsAtPos(Math.max(head, anchor) - Math.min(range.endOffset, 1));
var top;
// If not the same line, display toolbar below.
if (head > anchor && topCoords.top !== bottomCoords.top) {
// We are taking the previous pos to the maxium, so avoid end of line positions
// returning the next line's rect.
top = (bottomCoords.top || 0) + toolbarRect.height / 1.15;
} else {
top = (topCoords.top || 0) - toolbarRect.height * 1.5;
}
var left = (head > anchor ? bottomCoords.right : topCoords.left) - toolbarRect.width / 2;
// Place toolbar below selection if not sufficient space above
if (top < wrapperBounds.top) {
var _getCoordsBelowSelect = getCoordsBelowSelection(bottomCoords, toolbarRect);
top = _getCoordsBelowSelect.top;
left = _getCoordsBelowSelect.left;
}
// Make sure the toolbar doesn't extend out of the Editor
if (left + toolbarRect.width > wrapperBounds.right) {
left = wrapperBounds.right - toolbarRect.width;
}
// remap positions from browser document to wrapperBounds
return {
top: top - wrapperBounds.top + offset,
left: Math.max(0, left - wrapperBounds.left)
};
};
};
/**
* Returns the coordintes at the bottom the selection.
*/
var getCoordsBelowSelection = function getCoordsBelowSelection(bottomCoords, toolbarRect) {
return {
top: (bottomCoords.top || 0) + toolbarRect.height / 1.15,
left: bottomCoords.right - toolbarRect.width / 2
};
};