es-grid-template
Version:
es-grid-template
157 lines (151 loc) • 4.82 kB
JavaScript
import { asyncScheduler, BehaviorSubject, defer, fromEvent, Subscription } from 'rxjs';
import { map, throttleTime } from 'rxjs/operators';
import * as styledComponents from 'styled-components';
/** Version of the `styled-components` library. ali-react-table supports both v3 and v5. */
export const STYLED_VERSION = styledComponents.createGlobalStyle != null ? 'v5' : 'v3';
export const STYLED_REF_PROP = STYLED_VERSION === 'v3' ? 'innerRef' : 'ref';
export const OVERSCAN_SIZE = 300;
export const AUTO_VIRTUAL_THRESHOLD = 300;
export function sum(arr) {
let result = 0;
arr.forEach(x => {
result += x;
});
return result;
}
// Use defer to avoid referencing window too early, which can cause errors in SSR
export const throttledWindowResize$ = defer(() => fromEvent(window, 'resize', {
passive: true
}).pipe(throttleTime(150, asyncScheduler, {
leading: true,
trailing: true
})));
/** Get the default scrollbar size */
function getScrollbarSizeImpl() {
const scrollDiv = document.createElement('div');
scrollDiv.style.position = 'absolute';
scrollDiv.style.width = '100px';
scrollDiv.style.height = '100px';
scrollDiv.style.overflow = 'scroll';
scrollDiv.style.top = '-9999px';
document.body.appendChild(scrollDiv);
const scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;
const scrollbarHeight = scrollDiv.offsetHeight - scrollDiv.clientHeight;
document.body.removeChild(scrollDiv);
return {
width: scrollbarWidth,
height: scrollbarHeight
};
}
let scrollBarSize$;
export function getScrollbarSize() {
if (scrollBarSize$ == null) {
scrollBarSize$ = new BehaviorSubject(getScrollbarSizeImpl());
throttledWindowResize$.pipe(map(() => getScrollbarSizeImpl())).subscribe(scrollBarSize$);
}
return scrollBarSize$.value;
}
/**
* Synchronize the `scrollLeft` value among multiple elements.
* The callback will be invoked whenever `scrollLeft` changes.
*/
export function syncScrollLeft(elements, callback) {
const bypassSet = new Set();
function publishScrollLeft(origin, scrollLeft) {
bypassSet.clear();
for (const elem of elements) {
if (elem === origin) {
continue;
}
elem.scrollLeft = scrollLeft;
bypassSet.add(elem);
}
}
const subscription = new Subscription();
for (const ele of elements) {
const listener = () => {
if (bypassSet.has(ele)) {
bypassSet.delete(ele);
return;
}
const scrollLeft = ele.scrollLeft;
publishScrollLeft(ele, scrollLeft);
callback(scrollLeft);
};
ele.addEventListener('scroll', listener, {
passive: true
});
subscription.add(() => ele.removeEventListener('scroll', listener));
}
return subscription;
}
/**
* Performs equality by iterating through keys on an object and returning false
* when any key has values which are not strictly equal between the arguments.
* Returns true when the values of all keys are strictly equal.
*/
export function shallowEqual(objA, objB) {
const hasOwnProperty = Object.prototype.hasOwnProperty;
if (Object.is(objA, objB)) {
return true;
}
if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {
return false;
}
const keysA = Object.keys(objA);
const keysB = Object.keys(objB);
if (keysA.length !== keysB.length) {
return false;
}
// Test for A's keys different from B.
for (let i = 0; i < keysA.length; i++) {
if (!hasOwnProperty.call(objB, keysA[i]) || !Object.is(objA[keysA[i]], objB[keysA[i]])) {
return false;
}
}
return true;
}
export function getParentElement(element, selector) {
function isMatched(el, str = "") {
// eslint-disable-next-line no-param-reassign
str = str.toLowerCase();
let matched = false;
const firstChar = str.split("")[0];
if (firstChar === ".") {
const selectorClass = str.split(".")[1] || "";
const elCls = el.className || "";
if (typeof elCls === "string") {
const cls = elCls.toLowerCase().split(" ");
matched = cls.indexOf(selectorClass) > -1;
}
} else if (firstChar === "#") {
const selectorID = str.split("#")[1] || "";
const elID = el.id || "";
if (typeof elID === "string") {
matched = elID.toLowerCase() === selectorID;
}
} else {
matched = el.tagName.toLowerCase() === str;
}
return matched;
}
function getParent(el, tagName) {
if (!el) {
return null;
}
if (isMatched(el, tagName)) {
// return el;
}
const p = el.parentElement || el.parentNode;
if (p) {
if (isMatched(p, tagName)) {
return p;
} else {
return getParent(p, tagName);
}
} else {
return null;
}
}
return getParent(element, selector);
}