Skip to content

Commit

Permalink
fix(esl-utils): fix types and Element check for isVisible predicate…
Browse files Browse the repository at this point in the history
… (support of separate DOM realms)
  • Loading branch information
ala-n committed Aug 24, 2023
1 parent eb7ede6 commit 7c83e09
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {ExportNs} from '../../esl-utils/environment/export-ns';
import {tuple, wrap, uniq} from '../../esl-utils/misc/array';
import {unwrapParenthesis} from '../../esl-utils/misc/format';
import {findAll, findChildren, findNext, findParent, findClosest, findPrev} from '../../esl-utils/dom/traversing';
import {isElement} from '../../esl-utils/misc/object';
import {isVisible} from '../../esl-utils/dom/visible';

type ProcessorDescriptor = [string?, string?];
Expand Down Expand Up @@ -53,7 +54,7 @@ export class ESLTraversingQuery {
return wrap(list[index - 1]);
},
'::not': (list: Element[], sel?: string) => list.filter((el) => !el.matches(sel || '')),
'::visible': (list: Element[]) => list.filter((el) => (el instanceof HTMLElement) && isVisible(el)),
'::visible': (list: Element[]) => list.filter((el) => isElement(el) && isVisible(el)),
'::filter': (list: Element[], sel?: string) => list.filter((el) => el.matches(sel || ''))
};

Expand Down
18 changes: 12 additions & 6 deletions src/modules/esl-utils/dom/visible.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {isElement} from '../misc/object/types';
import {Rect} from './rect';
import {getListScrollParents} from './scroll';
import {findClosestBy, findHost} from './traversing';
Expand All @@ -12,26 +13,31 @@ export interface VisibilityOptions {
viewport?: boolean;
}

/** @returns if the exact passed Element hidden with CSS visibility */
const isHiddenPredicate = (el: Element): boolean => isElement(el) && getComputedStyle(el).visibility === 'hidden';

/** @returns if the exact passed Element is transparent (CSS opacity is 0) */
const isTransparentPredicate = (el: Element): boolean => isElement(el) && getComputedStyle(el).opacity === '0';

/**
* Checks if the specified element is visible
* @param el - element to be checked
* @param options - object of additional visibility options to include
*/
export function isVisible(el: HTMLElement, options: VisibilityOptions = {visibility: true}): boolean {
export function isVisible(el: Element, options: VisibilityOptions = {visibility: true}): boolean {
if (!el.getClientRects().length) return false;
if (options.visibility && findHost(el, (host) => getComputedStyle(host).visibility === 'hidden')) return false;
if (options.opacity &&
findClosestBy(el, (parent) => parent instanceof Element && getComputedStyle(parent).opacity === '0')) return false;
if (options.visibility && findHost(el, isHiddenPredicate)) return false;
if (options.opacity && findClosestBy(el, isTransparentPredicate)) return false;
return !(options.viewport && !isInViewport(el));
}

/**
* Checks if the specified element is inside the viewport
* @param el - element to be checked
*/
export function isInViewport(el: HTMLElement): boolean {
export function isInViewport(el: Element): boolean {
const wndIntersection = Rect.intersect(getWindowRect(), Rect.from(el.getBoundingClientRect()));
if (wndIntersection.area === 0) return false;
return !getListScrollParents(el).some((parent: HTMLElement) =>
return !getListScrollParents(el).some((parent: Element) =>
Rect.intersect(wndIntersection, Rect.from(parent.getBoundingClientRect())).area === 0);
}

0 comments on commit 7c83e09

Please sign in to comment.