UNPKG

dockview

Version:

Zero dependency layout manager supporting tabs, grids and splitviews with ReactJS support

114 lines (113 loc) 3.8 kB
import { Emitter, addDisposableListener, addDisposableWindowListener, } from './events'; import { CompositeDisposable } from './lifecycle'; export function watchElementResize(element, cb) { const observer = new ResizeObserver((entires) => { const firstEntry = entires[0]; cb(firstEntry); }); observer.observe(element); return { dispose: () => { observer.unobserve(element); observer.disconnect(); }, }; } export const removeClasses = (element, ...classes) => { for (const classname of classes) { if (element.classList.contains(classname)) { element.classList.remove(classname); } } }; export const addClasses = (element, ...classes) => { for (const classname of classes) { if (!element.classList.contains(classname)) { element.classList.add(classname); } } }; export const toggleClass = (element, className, isToggled) => { const hasClass = element.classList.contains(className); if (isToggled && !hasClass) { element.classList.add(className); } if (!isToggled && hasClass) { element.classList.remove(className); } }; export function isAncestor(testChild, testAncestor) { while (testChild) { if (testChild === testAncestor) { return true; } testChild = testChild.parentNode; } return false; } export function getElementsByTagName(tag) { return Array.prototype.slice.call(document.getElementsByTagName(tag), 0); } export function trackFocus(element) { return new FocusTracker(element); } /** * Track focus on an element. Ensure tabIndex is set when an HTMLElement is not focusable by default */ class FocusTracker extends CompositeDisposable { constructor(element) { super(); this._onDidFocus = new Emitter(); this.onDidFocus = this._onDidFocus.event; this._onDidBlur = new Emitter(); this.onDidBlur = this._onDidBlur.event; let hasFocus = isAncestor(document.activeElement, element); let loosingFocus = false; const onFocus = () => { loosingFocus = false; if (!hasFocus) { hasFocus = true; this._onDidFocus.fire(); } }; const onBlur = () => { if (hasFocus) { loosingFocus = true; window.setTimeout(() => { if (loosingFocus) { loosingFocus = false; hasFocus = false; this._onDidBlur.fire(); } }, 0); } }; this._refreshStateHandler = () => { const currentNodeHasFocus = isAncestor(document.activeElement, element); if (currentNodeHasFocus !== hasFocus) { if (hasFocus) { onBlur(); } else { onFocus(); } } }; if (element instanceof HTMLElement) { this.addDisposables(addDisposableListener(element, 'focus', onFocus, true)); this.addDisposables(addDisposableListener(element, 'blur', onBlur, true)); } else { this.addDisposables(addDisposableWindowListener(element, 'focus', onFocus, true)); this.addDisposables(addDisposableWindowListener(element, 'blur', onBlur, true)); } } refreshState() { this._refreshStateHandler(); } dispose() { super.dispose(); this._onDidBlur.dispose(); this._onDidFocus.dispose(); } }