12
common/resources/client/utils/dom/create-event-handler.ts
Executable file
12
common/resources/client/utils/dom/create-event-handler.ts
Executable file
@@ -0,0 +1,12 @@
|
||||
import {EventHandler, SyntheticEvent} from 'react';
|
||||
|
||||
export function createEventHandler(handler?: EventHandler<SyntheticEvent>) {
|
||||
if (!handler) return handler;
|
||||
|
||||
return (e: SyntheticEvent) => {
|
||||
// ignore events bubbling up from portals
|
||||
if (e.currentTarget.contains(e.target as HTMLElement)) {
|
||||
handler(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
35
common/resources/client/utils/dom/create-ref-loop.ts
Executable file
35
common/resources/client/utils/dom/create-ref-loop.ts
Executable file
@@ -0,0 +1,35 @@
|
||||
export function createRafLoop(callback: () => void) {
|
||||
let id: number | undefined;
|
||||
|
||||
function start() {
|
||||
// Time updates are already in progress.
|
||||
if (!isUndefined(id)) return;
|
||||
loop();
|
||||
}
|
||||
|
||||
function loop() {
|
||||
id = window.requestAnimationFrame(function rafLoop() {
|
||||
if (isUndefined(id)) return;
|
||||
callback();
|
||||
loop();
|
||||
});
|
||||
}
|
||||
|
||||
function stop() {
|
||||
if (isNumber(id)) window.cancelAnimationFrame(id);
|
||||
id = undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
start,
|
||||
stop,
|
||||
};
|
||||
}
|
||||
|
||||
function isUndefined(value: unknown): value is undefined {
|
||||
return typeof value === 'undefined';
|
||||
}
|
||||
|
||||
function isNumber(value: any): value is number {
|
||||
return typeof value === 'number' && !Number.isNaN(value);
|
||||
}
|
||||
20
common/resources/client/utils/dom/get-bounding-client-rect.ts
Executable file
20
common/resources/client/utils/dom/get-bounding-client-rect.ts
Executable file
@@ -0,0 +1,20 @@
|
||||
export interface PlainRect {
|
||||
top: number;
|
||||
right: number;
|
||||
bottom: number;
|
||||
left: number;
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
export function getBoundingClientRect(el: HTMLElement | Range) {
|
||||
const rect = el.getBoundingClientRect();
|
||||
return {
|
||||
top: rect.top,
|
||||
right: rect.right,
|
||||
bottom: rect.bottom,
|
||||
left: rect.left,
|
||||
width: rect.width,
|
||||
height: rect.height,
|
||||
};
|
||||
}
|
||||
9
common/resources/client/utils/dom/is-any-input-focused.ts
Executable file
9
common/resources/client/utils/dom/is-any-input-focused.ts
Executable file
@@ -0,0 +1,9 @@
|
||||
export function isAnyInputFocused(doc?: Document): boolean {
|
||||
if (!doc) {
|
||||
doc = document;
|
||||
}
|
||||
return doc.activeElement
|
||||
? ['INPUT', 'TEXTAREA'].includes(doc.activeElement.tagName) ||
|
||||
(doc.activeElement as HTMLElement).isContentEditable
|
||||
: false;
|
||||
}
|
||||
3
common/resources/client/utils/dom/is-ssr.ts
Executable file
3
common/resources/client/utils/dom/is-ssr.ts
Executable file
@@ -0,0 +1,3 @@
|
||||
export function isSsr() {
|
||||
return import.meta.env.SSR;
|
||||
}
|
||||
21
common/resources/client/utils/dom/observe-size.ts
Executable file
21
common/resources/client/utils/dom/observe-size.ts
Executable file
@@ -0,0 +1,21 @@
|
||||
import {RefObject} from 'react';
|
||||
|
||||
type Callback = (e: {width: number; height: number}) => void;
|
||||
|
||||
export function observeSize(
|
||||
ref: RefObject<HTMLElement>,
|
||||
callback: Callback
|
||||
): () => void {
|
||||
const observer = new ResizeObserver(entries => {
|
||||
const rect = entries[0].contentRect;
|
||||
callback({width: rect.width, height: rect.height});
|
||||
});
|
||||
if (ref.current) {
|
||||
observer.observe(ref.current);
|
||||
}
|
||||
return () => {
|
||||
if (ref.current) {
|
||||
observer.unobserve(ref.current);
|
||||
}
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user