import { Fun, Throttler } from '@ephox/katamari'; import type { SugarElement } from '../node/SugarElement'; import * as Traverse from '../search/Traverse'; import * as Visibility from '../view/Visibility'; /* * Long term it's probably worth looking at using a single event per page the way Resize does. * This could get a bit slow with a lot of editors in a heavy page. * * It's a bit harder to manage, though, because visibility is a one-shot listener. */ const observe = (element: SugarElement, f: () => void): () => void => { const observer: MutationObserver = new window.MutationObserver(f); const unbindMutate = () => observer.disconnect(); // childList is super expensive, but required on Safari where the iframe has no width or height immediately. // If it becomes a performance issue, we can make childList === isSafari but thus far Sugar has no platform detection so that would be a sad day. observer.observe(Traverse.owner(element).dom, { attributes: true, subtree: true, childList: true, attributeFilter: [ 'style', 'class' ] }); return unbindMutate; }; const onShow = (element: SugarElement, f: () => void): () => void => { if (Visibility.isVisible(element)) { window.requestAnimationFrame(f); return Fun.noop; } else { // these events might come in thick and fast, so throttle them const throttler = Throttler.adaptable(() => { if (Visibility.isVisible(element)) { unbind(); window.requestAnimationFrame(f); } }, 100); const unbind = observe(element, throttler.throttle); return unbind; } }; export { onShow };