blob: 2d0e77a21ad73e7f034b0e7c6392cd9cad182a4d (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
/** Find an element by selector. */
export const query = (selector: string, context: Document | Element = document) => {
return context.querySelector<HTMLElement>(selector);
};
/** Find a set of elements by selector. */
export const queryAll = (
selector: string,
context: Document | Element = document
): HTMLElement[] => {
return Array.from(context.querySelectorAll(selector));
};
/** Return a Promise that resolves after the next event loop. */
export const nextTick = (): Promise<void> => {
return new Promise((resolve) => {
requestAnimationFrame(() => {
requestAnimationFrame(() => {
resolve();
});
});
});
};
/** Check if an object is a Promise or a Thenable */
export function isPromise<T>(obj: unknown): obj is PromiseLike<T> {
return (
!!obj &&
(typeof obj === 'object' || typeof obj === 'function') &&
typeof (obj as Record<string, unknown>).then === 'function'
);
}
/** Call a function as a Promise. Resolves with the returned Promsise or immediately. */
// eslint-disable-next-line @typescript-eslint/ban-types, @typescript-eslint/no-explicit-any
export function runAsPromise(func: Function, args: unknown[] = []): Promise<unknown> {
return new Promise((resolve, reject) => {
const result: unknown = func(...args);
if (isPromise(result)) {
result.then(resolve, reject);
} else {
resolve(result);
}
});
}
/**
* Force a layout reflow, e.g. after adding classnames
* @see https://stackoverflow.com/a/21665117/3759615
*/
export function forceReflow(element?: HTMLElement): void {
element = element || document.body;
element?.getBoundingClientRect();
}
/**
* Read data attribute from closest element with that attribute.
*
* Returns `undefined` if no element is found or attribute is missing.
* Returns `true` if attribute is present without a value.
*/
export function getContextualAttr(
el: Element | undefined,
attr: string
): string | boolean | undefined {
const target = el?.closest(`[${attr}]`);
return target?.hasAttribute(attr) ? target?.getAttribute(attr) || true : undefined;
}
|