@atlaskit/editor-common
Version:
A package that contains common classes and components for editor and renderer
72 lines (69 loc) • 2.78 kB
JavaScript
// Use this selector to set the intersection observer boundary for editor's inline node views
// If this does not exist, it will use the IntersectionObserver's default root
const INTERSECTION_OBSERVER_ROOT_SELECTOR = '[data-editor-scroll-container="true"]';
const editorObservers = new WeakMap();
const callbackMap = new WeakMap();
/**
* Creates a node visibility manager
* @param editorElement
* @returns
*/
export const nodeVisibilityManager = editorElement => {
// Warning! do not reference editorElement outside of internal functions.
// editorElement is passed to allow support for multiple editors,
const unObserveInternal = nodeElement => {
var _editorObservers$get;
(_editorObservers$get = editorObservers.get(editorElement)) === null || _editorObservers$get === void 0 ? void 0 : _editorObservers$get.unobserve(nodeElement);
callbackMap.delete(nodeElement);
};
const observe = observerConfig => {
var _editorObservers$get2;
callbackMap.set(observerConfig.element, observerConfig);
(_editorObservers$get2 = editorObservers.get(editorElement)) === null || _editorObservers$get2 === void 0 ? void 0 : _editorObservers$get2.observe(observerConfig.element);
// return clean up
return () => {
// consumer needs to unobserve on destroy if their element
// was observed but never scrolled into view
unObserveInternal(observerConfig.element);
};
};
const initialiseNodeObserver = () => {
if (editorObservers.has(editorElement)) {
return;
}
const intersectionObserverOptions = {
root: editorElement.closest(INTERSECTION_OBSERVER_ROOT_SELECTOR),
rootMargin: '0px 0px 100px 0px',
threshold: 0
};
const editorObserver = new IntersectionObserver(entries => entries.map(entry => ({
entry,
callback: callbackMap.get(entry.target)
}))
// Invoke callbacks together to group browser rendering
// Avoiding requestAnimationFrame to reduce visual flickering
.forEach(({
entry,
callback
}) => {
if (entry.isIntersecting) {
callback === null || callback === void 0 ? void 0 : callback.onFirstVisible();
if (entry.target instanceof HTMLElement) {
// immediately unobserve the element after it is visible
unObserveInternal(entry.target);
}
}
}), intersectionObserverOptions);
editorObservers.set(editorElement, editorObserver);
};
const disconnect = () => {
var _editorObservers$get3;
(_editorObservers$get3 = editorObservers.get(editorElement)) === null || _editorObservers$get3 === void 0 ? void 0 : _editorObservers$get3.disconnect();
editorObservers.delete(editorElement);
};
return {
initialiseNodeObserver,
observe,
disconnect
};
};