mirror of
https://github.com/Redocly/redoc.git
synced 2025-12-07 18:03:52 +03:00
* Break out scrollIntoViewIfNeeded into freely usable function * Always use alternate implementation of scrollIntoViewIfNeeded Refs #1714 Refs #1742
78 lines
2.4 KiB
TypeScript
78 lines
2.4 KiB
TypeScript
export const IS_BROWSER = typeof window !== 'undefined' && 'HTMLElement' in window;
|
|
|
|
export function querySelector(selector: string): Element | null {
|
|
if (typeof document !== 'undefined') {
|
|
return document.querySelector(selector);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Drop everything inside <...> (i.e., tags/elements), and keep the text.
|
|
* Unlike browser innerText, this removes newlines; it also doesn't handle
|
|
* un-encoded `<` or `>` characters very well, so don't feed it malformed HTML
|
|
*/
|
|
export function html2Str(html: string): string {
|
|
return html
|
|
.split(/<[^>]+>/)
|
|
.map(chunk => {
|
|
return chunk.trim();
|
|
})
|
|
.filter(trimmedChunk => {
|
|
return trimmedChunk.length > 0;
|
|
})
|
|
.join(' ');
|
|
}
|
|
|
|
// Alternate scrollIntoViewIfNeeded implementation.
|
|
// Used in all cases, since it seems Chrome's implementation is buggy
|
|
// when "Experimental Web Platform Features" is enabled (at least of version 96).
|
|
// See #1714, #1742
|
|
|
|
export function scrollIntoViewIfNeeded(el: HTMLElement, centerIfNeeded = true) {
|
|
const parent = el.parentNode as HTMLElement | null;
|
|
if (!parent) {
|
|
return;
|
|
}
|
|
const parentComputedStyle = window.getComputedStyle(parent, undefined);
|
|
const parentBorderTopWidth = parseInt(
|
|
parentComputedStyle.getPropertyValue('border-top-width'),
|
|
10,
|
|
);
|
|
const parentBorderLeftWidth = parseInt(
|
|
parentComputedStyle.getPropertyValue('border-left-width'),
|
|
10,
|
|
);
|
|
const overTop = el.offsetTop - parent.offsetTop < parent.scrollTop;
|
|
const overBottom =
|
|
el.offsetTop - parent.offsetTop + el.clientHeight - parentBorderTopWidth >
|
|
parent.scrollTop + parent.clientHeight;
|
|
const overLeft = el.offsetLeft - parent.offsetLeft < parent.scrollLeft;
|
|
const overRight =
|
|
el.offsetLeft - parent.offsetLeft + el.clientWidth - parentBorderLeftWidth >
|
|
parent.scrollLeft + parent.clientWidth;
|
|
const alignWithTop = overTop && !overBottom;
|
|
|
|
if ((overTop || overBottom) && centerIfNeeded) {
|
|
parent.scrollTop =
|
|
el.offsetTop -
|
|
parent.offsetTop -
|
|
parent.clientHeight / 2 -
|
|
parentBorderTopWidth +
|
|
el.clientHeight / 2;
|
|
}
|
|
|
|
if ((overLeft || overRight) && centerIfNeeded) {
|
|
parent.scrollLeft =
|
|
el.offsetLeft -
|
|
parent.offsetLeft -
|
|
parent.clientWidth / 2 -
|
|
parentBorderLeftWidth +
|
|
el.clientWidth / 2;
|
|
}
|
|
|
|
if ((overTop || overBottom || overLeft || overRight) && !centerIfNeeded) {
|
|
el.scrollIntoView(alignWithTop);
|
|
}
|
|
}
|