mirror of
https://github.com/tenrok/OverlayScrollbars.git
synced 2026-06-21 22:40:36 +03:00
finalize SizeObserver and begin TrinsicObserver
This commit is contained in:
+276
-135
@@ -31,6 +31,9 @@ const removeAttr = (elm, attrName) => {
|
|||||||
function scrollLeft(elm, value) {
|
function scrollLeft(elm, value) {
|
||||||
return getSetProp('scrollLeft', 0, elm, value);
|
return getSetProp('scrollLeft', 0, elm, value);
|
||||||
}
|
}
|
||||||
|
function scrollTop(elm, value) {
|
||||||
|
return getSetProp('scrollTop', 0, elm, value);
|
||||||
|
}
|
||||||
|
|
||||||
const rnothtmlwhite = /[^\x20\t\r\n\f]+/g;
|
const rnothtmlwhite = /[^\x20\t\r\n\f]+/g;
|
||||||
|
|
||||||
@@ -78,6 +81,13 @@ const from = (arr) => {
|
|||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
const runEach = (arr) => {
|
||||||
|
if (arr instanceof Set) {
|
||||||
|
arr.forEach((fn) => fn && fn());
|
||||||
|
} else {
|
||||||
|
each(arr, (fn) => fn && fn());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const contents = (elm) => (elm ? from(elm.childNodes) : []);
|
const contents = (elm) => (elm ? from(elm.childNodes) : []);
|
||||||
const parent = (elm) => (elm ? elm.parentElement : null);
|
const parent = (elm) => (elm ? elm.parentElement : null);
|
||||||
@@ -117,6 +127,9 @@ const before = (parentElm, preferredAnchor, insertedElms) => {
|
|||||||
const appendChildren = (node, children) => {
|
const appendChildren = (node, children) => {
|
||||||
before(node, null, children);
|
before(node, null, children);
|
||||||
};
|
};
|
||||||
|
const prependChildren = (node, children) => {
|
||||||
|
before(node, node && node.firstChild, children);
|
||||||
|
};
|
||||||
const removeElements = (nodes) => {
|
const removeElements = (nodes) => {
|
||||||
if (isArrayLike(nodes)) {
|
if (isArrayLike(nodes)) {
|
||||||
each(from(nodes), (e) => removeElements(e));
|
each(from(nodes), (e) => removeElements(e));
|
||||||
@@ -160,6 +173,60 @@ const clientSize = (elm) =>
|
|||||||
: zeroObj;
|
: zeroObj;
|
||||||
const getBoundingClientRect = (elm) => elm.getBoundingClientRect();
|
const getBoundingClientRect = (elm) => elm.getBoundingClientRect();
|
||||||
|
|
||||||
|
let passiveEventsSupport;
|
||||||
|
|
||||||
|
const supportPassiveEvents = () => {
|
||||||
|
if (passiveEventsSupport === undefined) {
|
||||||
|
passiveEventsSupport = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
window.addEventListener(
|
||||||
|
'test',
|
||||||
|
null,
|
||||||
|
Object.defineProperty({}, 'passive', {
|
||||||
|
get: function () {
|
||||||
|
passiveEventsSupport = true;
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
return passiveEventsSupport;
|
||||||
|
};
|
||||||
|
|
||||||
|
const off = (target, eventNames, listener, capture) => {
|
||||||
|
each(eventNames.split(' '), (eventName) => {
|
||||||
|
target.removeEventListener(eventName, listener, capture);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const on = (target, eventNames, listener, options) => {
|
||||||
|
const doSupportPassiveEvents = supportPassiveEvents();
|
||||||
|
const passive = (doSupportPassiveEvents && options && options._passive) || false;
|
||||||
|
const capture = (options && options._capture) || false;
|
||||||
|
const once = (options && options._once) || false;
|
||||||
|
const offListeners = [];
|
||||||
|
const nativeOptions = doSupportPassiveEvents
|
||||||
|
? {
|
||||||
|
passive,
|
||||||
|
capture,
|
||||||
|
}
|
||||||
|
: capture;
|
||||||
|
each(eventNames.split(' '), (eventName) => {
|
||||||
|
const finalListener = once
|
||||||
|
? (evt) => {
|
||||||
|
target.removeEventListener(eventName, finalListener, capture);
|
||||||
|
listener && listener(evt);
|
||||||
|
}
|
||||||
|
: listener;
|
||||||
|
offListeners.push(off.bind(null, target, eventName, finalListener, capture));
|
||||||
|
target.addEventListener(eventName, finalListener, nativeOptions);
|
||||||
|
});
|
||||||
|
return runEach.bind(0, offListeners);
|
||||||
|
};
|
||||||
|
const stopPropagation = (evt) => evt.stopPropagation();
|
||||||
|
const preventDefault = (evt) => evt.preventDefault();
|
||||||
|
|
||||||
const hasOwnProperty = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop);
|
const hasOwnProperty = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop);
|
||||||
const keys = (obj) => (obj ? Object.keys(obj) : []);
|
const keys = (obj) => (obj ? Object.keys(obj) : []);
|
||||||
|
|
||||||
@@ -228,44 +295,6 @@ const absoluteCoordinates = (elm) => {
|
|||||||
: zeroObj$1;
|
: zeroObj$1;
|
||||||
};
|
};
|
||||||
|
|
||||||
function _classPrivateFieldGet(receiver, privateMap) {
|
|
||||||
var descriptor = privateMap.get(receiver);
|
|
||||||
|
|
||||||
if (!descriptor) {
|
|
||||||
throw new TypeError('attempted to get private field on non-instance');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (descriptor.get) {
|
|
||||||
return descriptor.get.call(receiver);
|
|
||||||
}
|
|
||||||
|
|
||||||
return descriptor.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
var classPrivateFieldGet = _classPrivateFieldGet;
|
|
||||||
|
|
||||||
function _classPrivateFieldSet(receiver, privateMap, value) {
|
|
||||||
var descriptor = privateMap.get(receiver);
|
|
||||||
|
|
||||||
if (!descriptor) {
|
|
||||||
throw new TypeError('attempted to set private field on non-instance');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (descriptor.set) {
|
|
||||||
descriptor.set.call(receiver, value);
|
|
||||||
} else {
|
|
||||||
if (!descriptor.writable) {
|
|
||||||
throw new TypeError('attempted to set read only private field');
|
|
||||||
}
|
|
||||||
|
|
||||||
descriptor.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
var classPrivateFieldSet = _classPrivateFieldSet;
|
|
||||||
|
|
||||||
const firstLetterToUpper = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
const firstLetterToUpper = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
||||||
const jsPrefixes = ['WebKit', 'Moz', 'O', 'MS', 'webkit', 'moz', 'o', 'ms'];
|
const jsPrefixes = ['WebKit', 'Moz', 'O', 'MS', 'webkit', 'moz', 'o', 'ms'];
|
||||||
const jsCache = {};
|
const jsCache = {};
|
||||||
@@ -334,10 +363,11 @@ const optionsTemplateTypes = ['boolean', 'number', 'string', 'array', 'object',
|
|||||||
return result;
|
return result;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
|
let environmentInstance;
|
||||||
const { abs, round } = Math;
|
const { abs, round } = Math;
|
||||||
const envornmentElmId = 'os-envornment';
|
const environmentElmId = 'os-environment';
|
||||||
|
|
||||||
const nativeScrollbarSize = (body, measureElm) => {
|
const getNativeScrollbarSize = (body, measureElm) => {
|
||||||
appendChildren(body, measureElm);
|
appendChildren(body, measureElm);
|
||||||
const cSize = clientSize(measureElm);
|
const cSize = clientSize(measureElm);
|
||||||
const oSize = offsetSize(measureElm);
|
const oSize = offsetSize(measureElm);
|
||||||
@@ -347,7 +377,7 @@ const nativeScrollbarSize = (body, measureElm) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const nativeScrollbarStyling = (testElm) => {
|
const getNativeScrollbarStyling = (testElm) => {
|
||||||
let result = false;
|
let result = false;
|
||||||
addClass(testElm, 'os-viewport-native-scrollbars-invisible');
|
addClass(testElm, 'os-viewport-native-scrollbars-invisible');
|
||||||
|
|
||||||
@@ -359,7 +389,7 @@ const nativeScrollbarStyling = (testElm) => {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
const rtlScrollBehavior = (parentElm, childElm) => {
|
const getRtlScrollBehavior = (parentElm, childElm) => {
|
||||||
const strHidden = 'hidden';
|
const strHidden = 'hidden';
|
||||||
style(parentElm, {
|
style(parentElm, {
|
||||||
overflowX: strHidden,
|
overflowX: strHidden,
|
||||||
@@ -377,25 +407,7 @@ const rtlScrollBehavior = (parentElm, childElm) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const passiveEvents = () => {
|
const getWindowDPR = () => {
|
||||||
let supportsPassive = false;
|
|
||||||
|
|
||||||
try {
|
|
||||||
window.addEventListener(
|
|
||||||
'test',
|
|
||||||
null,
|
|
||||||
Object.defineProperty({}, 'passive', {
|
|
||||||
get: function () {
|
|
||||||
supportsPassive = true;
|
|
||||||
},
|
|
||||||
})
|
|
||||||
);
|
|
||||||
} catch (e) {}
|
|
||||||
|
|
||||||
return supportsPassive;
|
|
||||||
};
|
|
||||||
|
|
||||||
const windowDPR = () => {
|
|
||||||
const dDPI = window.screen.deviceXDPI || 0;
|
const dDPI = window.screen.deviceXDPI || 0;
|
||||||
const sDPI = window.screen.logicalXDPI || 1;
|
const sDPI = window.screen.logicalXDPI || 1;
|
||||||
return window.devicePixelRatio || dDPI / sDPI;
|
return window.devicePixelRatio || dDPI / sDPI;
|
||||||
@@ -407,96 +419,225 @@ const diffBiggerThanOne = (valOne, valTwo) => {
|
|||||||
return !(absValOne === absValTwo || absValOne + 1 === absValTwo || absValOne - 1 === absValTwo);
|
return !(absValOne === absValTwo || absValOne + 1 === absValTwo || absValOne - 1 === absValTwo);
|
||||||
};
|
};
|
||||||
|
|
||||||
var _onChangedListener = new WeakMap();
|
const createEnvironment = () => {
|
||||||
|
const { body } = document;
|
||||||
|
const envDOM = createDOM(`<div id="${environmentElmId}"><div></div></div>`);
|
||||||
|
const envElm = envDOM[0];
|
||||||
|
const envChildElm = envElm.firstChild;
|
||||||
|
const onChangedListener = new Set();
|
||||||
|
const nativeScrollBarSize = getNativeScrollbarSize(body, envElm);
|
||||||
|
const nativeScrollbarIsOverlaid = {
|
||||||
|
x: nativeScrollBarSize.x === 0,
|
||||||
|
y: nativeScrollBarSize.y === 0,
|
||||||
|
};
|
||||||
|
const env = {
|
||||||
|
_autoUpdateLoop: false,
|
||||||
|
_nativeScrollbarSize: nativeScrollBarSize,
|
||||||
|
_nativeScrollbarIsOverlaid: nativeScrollbarIsOverlaid,
|
||||||
|
_nativeScrollbarStyling: getNativeScrollbarStyling(envElm),
|
||||||
|
_rtlScrollBehavior: getRtlScrollBehavior(envElm, envChildElm),
|
||||||
|
|
||||||
class Environment {
|
_addListener(listener) {
|
||||||
constructor() {
|
onChangedListener.add(listener);
|
||||||
_onChangedListener.set(this, {
|
},
|
||||||
writable: true,
|
|
||||||
value: void 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
classPrivateFieldSet(this, _onChangedListener, new Set());
|
_removeListener(listener) {
|
||||||
|
onChangedListener.delete(listener);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
removeAttr(envElm, 'style');
|
||||||
|
removeElements(envElm);
|
||||||
|
|
||||||
const _self = this;
|
if (!nativeScrollbarIsOverlaid.x || !nativeScrollbarIsOverlaid.y) {
|
||||||
|
let size = windowSize();
|
||||||
|
let dpr = getWindowDPR();
|
||||||
|
let scrollbarSize = nativeScrollBarSize;
|
||||||
|
window.addEventListener('resize', () => {
|
||||||
|
if (onChangedListener.size) {
|
||||||
|
const sizeNew = windowSize();
|
||||||
|
const deltaSize = {
|
||||||
|
w: sizeNew.w - size.w,
|
||||||
|
h: sizeNew.h - size.h,
|
||||||
|
};
|
||||||
|
if (deltaSize.w === 0 && deltaSize.h === 0) return;
|
||||||
|
const deltaAbsSize = {
|
||||||
|
w: abs(deltaSize.w),
|
||||||
|
h: abs(deltaSize.h),
|
||||||
|
};
|
||||||
|
const deltaAbsRatio = {
|
||||||
|
w: abs(round(sizeNew.w / (size.w / 100.0))),
|
||||||
|
h: abs(round(sizeNew.h / (size.h / 100.0))),
|
||||||
|
};
|
||||||
|
const dprNew = getWindowDPR();
|
||||||
|
const deltaIsBigger = deltaAbsSize.w > 2 && deltaAbsSize.h > 2;
|
||||||
|
const difference = !diffBiggerThanOne(deltaAbsRatio.w, deltaAbsRatio.h);
|
||||||
|
const dprChanged = dprNew !== dpr && dpr > 0;
|
||||||
|
const isZoom = deltaIsBigger && difference && dprChanged;
|
||||||
|
|
||||||
const { body } = document;
|
if (isZoom) {
|
||||||
const envDOM = createDOM(`<div id="${envornmentElmId}"><div></div></div>`);
|
const newScrollbarSize = (environmentInstance._nativeScrollbarSize = getNativeScrollbarSize(body, envElm));
|
||||||
const envElm = envDOM[0];
|
removeElements(envElm);
|
||||||
const envChildElm = envElm.firstChild;
|
|
||||||
const nScrollBarSize = nativeScrollbarSize(body, envElm);
|
|
||||||
const nativeScrollbarIsOverlaid = {
|
|
||||||
x: nScrollBarSize.x === 0,
|
|
||||||
y: nScrollBarSize.y === 0,
|
|
||||||
};
|
|
||||||
_self._autoUpdateLoop = false;
|
|
||||||
_self._nativeScrollbarSize = nScrollBarSize;
|
|
||||||
_self._nativeScrollbarIsOverlaid = nativeScrollbarIsOverlaid;
|
|
||||||
_self._nativeScrollbarStyling = nativeScrollbarStyling(envElm);
|
|
||||||
_self._rtlScrollBehavior = rtlScrollBehavior(envElm, envChildElm);
|
|
||||||
_self._supportPassiveEvents = passiveEvents();
|
|
||||||
_self._supportResizeObserver = !!jsAPI('ResizeObserver');
|
|
||||||
removeAttr(envElm, 'style');
|
|
||||||
removeElements(envElm);
|
|
||||||
|
|
||||||
if (!nativeScrollbarIsOverlaid.x || !nativeScrollbarIsOverlaid.y) {
|
if (scrollbarSize.x !== newScrollbarSize.x || scrollbarSize.y !== newScrollbarSize.y) {
|
||||||
let size = windowSize();
|
runEach(onChangedListener);
|
||||||
let dpr = windowDPR();
|
|
||||||
|
|
||||||
const onChangedListener = classPrivateFieldGet(this, _onChangedListener);
|
|
||||||
|
|
||||||
window.addEventListener('resize', () => {
|
|
||||||
if (onChangedListener.size) {
|
|
||||||
const sizeNew = windowSize();
|
|
||||||
const deltaSize = {
|
|
||||||
w: sizeNew.w - size.w,
|
|
||||||
h: sizeNew.h - size.h,
|
|
||||||
};
|
|
||||||
if (deltaSize.w === 0 && deltaSize.h === 0) return;
|
|
||||||
const deltaAbsSize = {
|
|
||||||
w: abs(deltaSize.w),
|
|
||||||
h: abs(deltaSize.h),
|
|
||||||
};
|
|
||||||
const deltaAbsRatio = {
|
|
||||||
w: abs(round(sizeNew.w / (size.w / 100.0))),
|
|
||||||
h: abs(round(sizeNew.h / (size.h / 100.0))),
|
|
||||||
};
|
|
||||||
const dprNew = windowDPR();
|
|
||||||
const deltaIsBigger = deltaAbsSize.w > 2 && deltaAbsSize.h > 2;
|
|
||||||
const difference = !diffBiggerThanOne(deltaAbsRatio.w, deltaAbsRatio.h);
|
|
||||||
const dprChanged = dprNew !== dpr && dpr > 0;
|
|
||||||
const isZoom = deltaIsBigger && difference && dprChanged;
|
|
||||||
const oldScrollbarSize = _self._nativeScrollbarSize;
|
|
||||||
let newScrollbarSize;
|
|
||||||
|
|
||||||
if (isZoom) {
|
|
||||||
newScrollbarSize = _self._nativeScrollbarSize = nativeScrollbarSize(body, envElm);
|
|
||||||
removeElements(envElm);
|
|
||||||
|
|
||||||
if (oldScrollbarSize.x !== newScrollbarSize.x || oldScrollbarSize.y !== newScrollbarSize.y) {
|
|
||||||
onChangedListener.forEach((listener) => listener && listener(_self));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size = sizeNew;
|
scrollbarSize = newScrollbarSize;
|
||||||
dpr = dprNew;
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
size = sizeNew;
|
||||||
|
dpr = dprNew;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return env;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getEnvironment = () => {
|
||||||
|
if (!environmentInstance) {
|
||||||
|
environmentInstance = createEnvironment();
|
||||||
|
}
|
||||||
|
|
||||||
|
return environmentInstance;
|
||||||
|
};
|
||||||
|
|
||||||
|
const animationStartEventName = 'animationstart';
|
||||||
|
const scrollEventName = 'scroll';
|
||||||
|
const scrollAmount = 3333333;
|
||||||
|
const ResizeObserverConstructor = jsAPI('ResizeObserver');
|
||||||
|
const classNameSizeObserver = 'os-size-observer';
|
||||||
|
const classNameSizeObserverListener = `${classNameSizeObserver}-listener`;
|
||||||
|
const classNameSizeObserverListenerItem = `${classNameSizeObserverListener}-item`;
|
||||||
|
const classNameSizeObserverListenerItemFinal = `${classNameSizeObserverListenerItem}-final`;
|
||||||
|
const cAF = cancelAnimationFrame;
|
||||||
|
const rAF = requestAnimationFrame;
|
||||||
|
|
||||||
|
const getDirection = (elm) => style(elm, 'direction');
|
||||||
|
|
||||||
|
const createSizeObserver = (target, onSizeChangedCallback, direction) => {
|
||||||
|
const rtlScrollBehavior = getEnvironment()._rtlScrollBehavior;
|
||||||
|
|
||||||
|
const baseElements = createDOM(`<div class="${classNameSizeObserver}"><div class="${classNameSizeObserverListener}"></div></div>`);
|
||||||
|
const sizeObserver = baseElements[0];
|
||||||
|
const listenerElement = sizeObserver.firstChild;
|
||||||
|
|
||||||
|
const onSizeChangedCallbackProxy = (dir) => {
|
||||||
|
if (direction) {
|
||||||
|
const rtl = getDirection(sizeObserver) === 'rtl';
|
||||||
|
scrollLeft(sizeObserver, rtl ? (rtlScrollBehavior.n ? -scrollAmount : rtlScrollBehavior.i ? 0 : scrollAmount) : scrollAmount);
|
||||||
|
scrollTop(sizeObserver, scrollAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onSizeChangedCallback(dir === true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const offListeners = [];
|
||||||
|
let appearCallback = onSizeChangedCallbackProxy;
|
||||||
|
|
||||||
|
if (ResizeObserverConstructor) {
|
||||||
|
const resizeObserverInstance = new ResizeObserverConstructor(onSizeChangedCallbackProxy);
|
||||||
|
resizeObserverInstance.observe(listenerElement);
|
||||||
|
} else {
|
||||||
|
const observerElementChildren = createDOM(
|
||||||
|
`<div class="${classNameSizeObserverListenerItem}" dir="ltr"><div class="${classNameSizeObserverListenerItem}"><div class="${classNameSizeObserverListenerItemFinal}"></div></div><div class="${classNameSizeObserverListenerItem}"><div class="${classNameSizeObserverListenerItemFinal}" style="width: 200%; height: 200%"></div></div></div>`
|
||||||
|
);
|
||||||
|
appendChildren(listenerElement, observerElementChildren);
|
||||||
|
const observerElementChildrenRoot = observerElementChildren[0];
|
||||||
|
const shrinkElement = observerElementChildrenRoot.lastChild;
|
||||||
|
const expandElement = observerElementChildrenRoot.firstChild;
|
||||||
|
const expandElementChild = expandElement == null ? void 0 : expandElement.firstChild;
|
||||||
|
let cacheSize = offsetSize(listenerElement);
|
||||||
|
let currSize = cacheSize;
|
||||||
|
let isDirty = false;
|
||||||
|
let rAFId;
|
||||||
|
|
||||||
|
const reset = () => {
|
||||||
|
scrollLeft(expandElement, scrollAmount);
|
||||||
|
scrollTop(expandElement, scrollAmount);
|
||||||
|
scrollLeft(shrinkElement, scrollAmount);
|
||||||
|
scrollTop(shrinkElement, scrollAmount);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onResized = function onResized() {
|
||||||
|
rAFId = 0;
|
||||||
|
if (!isDirty) return;
|
||||||
|
cacheSize = currSize;
|
||||||
|
onSizeChangedCallbackProxy();
|
||||||
|
};
|
||||||
|
|
||||||
|
const onScroll = (scrollEvent) => {
|
||||||
|
currSize = offsetSize(listenerElement);
|
||||||
|
isDirty = !scrollEvent || currSize.w !== cacheSize.w || currSize.h !== cacheSize.h;
|
||||||
|
|
||||||
|
if (scrollEvent && isDirty && !rAFId) {
|
||||||
|
cAF(rAFId);
|
||||||
|
rAFId = rAF(onResized);
|
||||||
|
} else if (!scrollEvent) onResized();
|
||||||
|
|
||||||
|
reset();
|
||||||
|
|
||||||
|
if (scrollEvent) {
|
||||||
|
preventDefault(scrollEvent);
|
||||||
|
stopPropagation(scrollEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
offListeners.push(on(expandElement, scrollEventName, onScroll));
|
||||||
|
offListeners.push(on(shrinkElement, scrollEventName, onScroll));
|
||||||
|
style(expandElementChild, {
|
||||||
|
width: scrollAmount,
|
||||||
|
height: scrollAmount,
|
||||||
|
});
|
||||||
|
reset();
|
||||||
|
appearCallback = onScroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
addListener(listener) {
|
if (direction) {
|
||||||
classPrivateFieldGet(this, _onChangedListener).add(listener);
|
let dirCache;
|
||||||
|
offListeners.push(
|
||||||
|
on(sizeObserver, scrollEventName, (event) => {
|
||||||
|
const dir = getDirection(sizeObserver);
|
||||||
|
const changed = dir !== dirCache;
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
if (dir === 'rtl') {
|
||||||
|
style(listenerElement, {
|
||||||
|
left: 'auto',
|
||||||
|
right: 0,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
style(listenerElement, {
|
||||||
|
left: 0,
|
||||||
|
right: 'auto',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
dirCache = dir;
|
||||||
|
onSizeChangedCallbackProxy(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
preventDefault(event);
|
||||||
|
stopPropagation(event);
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
removeListener(listener) {
|
offListeners.push(on(sizeObserver, animationStartEventName, appearCallback));
|
||||||
classPrivateFieldGet(this, _onChangedListener).delete(listener);
|
prependChildren(target, sizeObserver);
|
||||||
}
|
return () => {
|
||||||
}
|
runEach(offListeners);
|
||||||
|
removeElements(sizeObserver);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
var index = () => {
|
var index = () => {
|
||||||
return [
|
return [
|
||||||
new Environment(),
|
getEnvironment(),
|
||||||
|
createSizeObserver(document.body, () => {}),
|
||||||
createDOM(
|
createDOM(
|
||||||
'\
|
'\
|
||||||
<div class="os-host">\
|
<div class="os-host">\
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+296
-143
@@ -40,6 +40,9 @@
|
|||||||
function scrollLeft(elm, value) {
|
function scrollLeft(elm, value) {
|
||||||
return getSetProp('scrollLeft', 0, elm, value);
|
return getSetProp('scrollLeft', 0, elm, value);
|
||||||
}
|
}
|
||||||
|
function scrollTop(elm, value) {
|
||||||
|
return getSetProp('scrollTop', 0, elm, value);
|
||||||
|
}
|
||||||
|
|
||||||
var rnothtmlwhite = /[^\x20\t\r\n\f]+/g;
|
var rnothtmlwhite = /[^\x20\t\r\n\f]+/g;
|
||||||
|
|
||||||
@@ -91,6 +94,17 @@
|
|||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
var runEach = function runEach(arr) {
|
||||||
|
if (arr instanceof Set) {
|
||||||
|
arr.forEach(function (fn) {
|
||||||
|
return fn && fn();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
each(arr, function (fn) {
|
||||||
|
return fn && fn();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
var contents = function contents(elm) {
|
var contents = function contents(elm) {
|
||||||
return elm ? from(elm.childNodes) : [];
|
return elm ? from(elm.childNodes) : [];
|
||||||
@@ -134,6 +148,9 @@
|
|||||||
var appendChildren = function appendChildren(node, children) {
|
var appendChildren = function appendChildren(node, children) {
|
||||||
before(node, null, children);
|
before(node, null, children);
|
||||||
};
|
};
|
||||||
|
var prependChildren = function prependChildren(node, children) {
|
||||||
|
before(node, node && node.firstChild, children);
|
||||||
|
};
|
||||||
var removeElements = function removeElements(nodes) {
|
var removeElements = function removeElements(nodes) {
|
||||||
if (isArrayLike(nodes)) {
|
if (isArrayLike(nodes)) {
|
||||||
each(from(nodes), function (e) {
|
each(from(nodes), function (e) {
|
||||||
@@ -189,6 +206,64 @@
|
|||||||
return elm.getBoundingClientRect();
|
return elm.getBoundingClientRect();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var passiveEventsSupport;
|
||||||
|
|
||||||
|
var supportPassiveEvents = function supportPassiveEvents() {
|
||||||
|
if (passiveEventsSupport === undefined) {
|
||||||
|
passiveEventsSupport = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
window.addEventListener(
|
||||||
|
'test',
|
||||||
|
null,
|
||||||
|
Object.defineProperty({}, 'passive', {
|
||||||
|
get: function get() {
|
||||||
|
passiveEventsSupport = true;
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
return passiveEventsSupport;
|
||||||
|
};
|
||||||
|
|
||||||
|
var off = function off(target, eventNames, listener, capture) {
|
||||||
|
each(eventNames.split(' '), function (eventName) {
|
||||||
|
target.removeEventListener(eventName, listener, capture);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
var on = function on(target, eventNames, listener, options) {
|
||||||
|
var doSupportPassiveEvents = supportPassiveEvents();
|
||||||
|
var passive = (doSupportPassiveEvents && options && options._passive) || false;
|
||||||
|
var capture = (options && options._capture) || false;
|
||||||
|
var once = (options && options._once) || false;
|
||||||
|
var offListeners = [];
|
||||||
|
var nativeOptions = doSupportPassiveEvents
|
||||||
|
? {
|
||||||
|
passive: passive,
|
||||||
|
capture: capture,
|
||||||
|
}
|
||||||
|
: capture;
|
||||||
|
each(eventNames.split(' '), function (eventName) {
|
||||||
|
var finalListener = once
|
||||||
|
? function (evt) {
|
||||||
|
target.removeEventListener(eventName, finalListener, capture);
|
||||||
|
listener && listener(evt);
|
||||||
|
}
|
||||||
|
: listener;
|
||||||
|
offListeners.push(off.bind(null, target, eventName, finalListener, capture));
|
||||||
|
target.addEventListener(eventName, finalListener, nativeOptions);
|
||||||
|
});
|
||||||
|
return runEach.bind(0, offListeners);
|
||||||
|
};
|
||||||
|
var stopPropagation = function stopPropagation(evt) {
|
||||||
|
return evt.stopPropagation();
|
||||||
|
};
|
||||||
|
var preventDefault = function preventDefault(evt) {
|
||||||
|
return evt.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
var hasOwnProperty = function hasOwnProperty(obj, prop) {
|
var hasOwnProperty = function hasOwnProperty(obj, prop) {
|
||||||
return Object.prototype.hasOwnProperty.call(obj, prop);
|
return Object.prototype.hasOwnProperty.call(obj, prop);
|
||||||
};
|
};
|
||||||
@@ -267,44 +342,6 @@
|
|||||||
: zeroObj$1;
|
: zeroObj$1;
|
||||||
};
|
};
|
||||||
|
|
||||||
function _classPrivateFieldGet(receiver, privateMap) {
|
|
||||||
var descriptor = privateMap.get(receiver);
|
|
||||||
|
|
||||||
if (!descriptor) {
|
|
||||||
throw new TypeError('attempted to get private field on non-instance');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (descriptor.get) {
|
|
||||||
return descriptor.get.call(receiver);
|
|
||||||
}
|
|
||||||
|
|
||||||
return descriptor.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
var classPrivateFieldGet = _classPrivateFieldGet;
|
|
||||||
|
|
||||||
function _classPrivateFieldSet(receiver, privateMap, value) {
|
|
||||||
var descriptor = privateMap.get(receiver);
|
|
||||||
|
|
||||||
if (!descriptor) {
|
|
||||||
throw new TypeError('attempted to set private field on non-instance');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (descriptor.set) {
|
|
||||||
descriptor.set.call(receiver, value);
|
|
||||||
} else {
|
|
||||||
if (!descriptor.writable) {
|
|
||||||
throw new TypeError('attempted to set read only private field');
|
|
||||||
}
|
|
||||||
|
|
||||||
descriptor.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
var classPrivateFieldSet = _classPrivateFieldSet;
|
|
||||||
|
|
||||||
var firstLetterToUpper = function firstLetterToUpper(str) {
|
var firstLetterToUpper = function firstLetterToUpper(str) {
|
||||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||||
};
|
};
|
||||||
@@ -375,11 +412,12 @@
|
|||||||
return result;
|
return result;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
|
var environmentInstance;
|
||||||
var abs = Math.abs,
|
var abs = Math.abs,
|
||||||
round = Math.round;
|
round = Math.round;
|
||||||
var envornmentElmId = 'os-envornment';
|
var environmentElmId = 'os-environment';
|
||||||
|
|
||||||
var nativeScrollbarSize = function nativeScrollbarSize(body, measureElm) {
|
var getNativeScrollbarSize = function getNativeScrollbarSize(body, measureElm) {
|
||||||
appendChildren(body, measureElm);
|
appendChildren(body, measureElm);
|
||||||
var cSize = clientSize(measureElm);
|
var cSize = clientSize(measureElm);
|
||||||
var oSize = offsetSize(measureElm);
|
var oSize = offsetSize(measureElm);
|
||||||
@@ -389,7 +427,7 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
var nativeScrollbarStyling = function nativeScrollbarStyling(testElm) {
|
var getNativeScrollbarStyling = function getNativeScrollbarStyling(testElm) {
|
||||||
var result = false;
|
var result = false;
|
||||||
addClass(testElm, 'os-viewport-native-scrollbars-invisible');
|
addClass(testElm, 'os-viewport-native-scrollbars-invisible');
|
||||||
|
|
||||||
@@ -402,7 +440,7 @@
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
var rtlScrollBehavior = function rtlScrollBehavior(parentElm, childElm) {
|
var getRtlScrollBehavior = function getRtlScrollBehavior(parentElm, childElm) {
|
||||||
var strHidden = 'hidden';
|
var strHidden = 'hidden';
|
||||||
style(parentElm, {
|
style(parentElm, {
|
||||||
overflowX: strHidden,
|
overflowX: strHidden,
|
||||||
@@ -420,25 +458,7 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
var passiveEvents = function passiveEvents() {
|
var getWindowDPR = function getWindowDPR() {
|
||||||
var supportsPassive = false;
|
|
||||||
|
|
||||||
try {
|
|
||||||
window.addEventListener(
|
|
||||||
'test',
|
|
||||||
null,
|
|
||||||
Object.defineProperty({}, 'passive', {
|
|
||||||
get: function get() {
|
|
||||||
supportsPassive = true;
|
|
||||||
},
|
|
||||||
})
|
|
||||||
);
|
|
||||||
} catch (e) {}
|
|
||||||
|
|
||||||
return supportsPassive;
|
|
||||||
};
|
|
||||||
|
|
||||||
var windowDPR = function windowDPR() {
|
|
||||||
var dDPI = window.screen.deviceXDPI || 0;
|
var dDPI = window.screen.deviceXDPI || 0;
|
||||||
var sDPI = window.screen.logicalXDPI || 1;
|
var sDPI = window.screen.logicalXDPI || 1;
|
||||||
return window.devicePixelRatio || dDPI / sDPI;
|
return window.devicePixelRatio || dDPI / sDPI;
|
||||||
@@ -450,103 +470,236 @@
|
|||||||
return !(absValOne === absValTwo || absValOne + 1 === absValTwo || absValOne - 1 === absValTwo);
|
return !(absValOne === absValTwo || absValOne + 1 === absValTwo || absValOne - 1 === absValTwo);
|
||||||
};
|
};
|
||||||
|
|
||||||
var _onChangedListener = new WeakMap();
|
var createEnvironment = function createEnvironment() {
|
||||||
|
var _document = document,
|
||||||
|
body = _document.body;
|
||||||
|
var envDOM = createDOM('<div id="' + environmentElmId + '"><div></div></div>');
|
||||||
|
var envElm = envDOM[0];
|
||||||
|
var envChildElm = envElm.firstChild;
|
||||||
|
var onChangedListener = new Set();
|
||||||
|
var nativeScrollBarSize = getNativeScrollbarSize(body, envElm);
|
||||||
|
var nativeScrollbarIsOverlaid = {
|
||||||
|
x: nativeScrollBarSize.x === 0,
|
||||||
|
y: nativeScrollBarSize.y === 0,
|
||||||
|
};
|
||||||
|
var env = {
|
||||||
|
_autoUpdateLoop: false,
|
||||||
|
_nativeScrollbarSize: nativeScrollBarSize,
|
||||||
|
_nativeScrollbarIsOverlaid: nativeScrollbarIsOverlaid,
|
||||||
|
_nativeScrollbarStyling: getNativeScrollbarStyling(envElm),
|
||||||
|
_rtlScrollBehavior: getRtlScrollBehavior(envElm, envChildElm),
|
||||||
|
_addListener: function _addListener(listener) {
|
||||||
|
onChangedListener.add(listener);
|
||||||
|
},
|
||||||
|
_removeListener: function _removeListener(listener) {
|
||||||
|
onChangedListener.delete(listener);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
removeAttr(envElm, 'style');
|
||||||
|
removeElements(envElm);
|
||||||
|
|
||||||
var Environment = /*#__PURE__*/ (function () {
|
if (!nativeScrollbarIsOverlaid.x || !nativeScrollbarIsOverlaid.y) {
|
||||||
function Environment() {
|
var size = windowSize();
|
||||||
_onChangedListener.set(this, {
|
var dpr = getWindowDPR();
|
||||||
writable: true,
|
var scrollbarSize = nativeScrollBarSize;
|
||||||
value: void 0,
|
window.addEventListener('resize', function () {
|
||||||
});
|
if (onChangedListener.size) {
|
||||||
|
var sizeNew = windowSize();
|
||||||
|
var deltaSize = {
|
||||||
|
w: sizeNew.w - size.w,
|
||||||
|
h: sizeNew.h - size.h,
|
||||||
|
};
|
||||||
|
if (deltaSize.w === 0 && deltaSize.h === 0) return;
|
||||||
|
var deltaAbsSize = {
|
||||||
|
w: abs(deltaSize.w),
|
||||||
|
h: abs(deltaSize.h),
|
||||||
|
};
|
||||||
|
var deltaAbsRatio = {
|
||||||
|
w: abs(round(sizeNew.w / (size.w / 100.0))),
|
||||||
|
h: abs(round(sizeNew.h / (size.h / 100.0))),
|
||||||
|
};
|
||||||
|
var dprNew = getWindowDPR();
|
||||||
|
var deltaIsBigger = deltaAbsSize.w > 2 && deltaAbsSize.h > 2;
|
||||||
|
var difference = !diffBiggerThanOne(deltaAbsRatio.w, deltaAbsRatio.h);
|
||||||
|
var dprChanged = dprNew !== dpr && dpr > 0;
|
||||||
|
var isZoom = deltaIsBigger && difference && dprChanged;
|
||||||
|
|
||||||
classPrivateFieldSet(this, _onChangedListener, new Set());
|
if (isZoom) {
|
||||||
|
var newScrollbarSize = (environmentInstance._nativeScrollbarSize = getNativeScrollbarSize(body, envElm));
|
||||||
|
removeElements(envElm);
|
||||||
|
|
||||||
var _self = this;
|
if (scrollbarSize.x !== newScrollbarSize.x || scrollbarSize.y !== newScrollbarSize.y) {
|
||||||
|
runEach(onChangedListener);
|
||||||
var _document = document,
|
|
||||||
body = _document.body;
|
|
||||||
var envDOM = createDOM('<div id="' + envornmentElmId + '"><div></div></div>');
|
|
||||||
var envElm = envDOM[0];
|
|
||||||
var envChildElm = envElm.firstChild;
|
|
||||||
var nScrollBarSize = nativeScrollbarSize(body, envElm);
|
|
||||||
var nativeScrollbarIsOverlaid = {
|
|
||||||
x: nScrollBarSize.x === 0,
|
|
||||||
y: nScrollBarSize.y === 0,
|
|
||||||
};
|
|
||||||
_self._autoUpdateLoop = false;
|
|
||||||
_self._nativeScrollbarSize = nScrollBarSize;
|
|
||||||
_self._nativeScrollbarIsOverlaid = nativeScrollbarIsOverlaid;
|
|
||||||
_self._nativeScrollbarStyling = nativeScrollbarStyling(envElm);
|
|
||||||
_self._rtlScrollBehavior = rtlScrollBehavior(envElm, envChildElm);
|
|
||||||
_self._supportPassiveEvents = passiveEvents();
|
|
||||||
_self._supportResizeObserver = !!jsAPI('ResizeObserver');
|
|
||||||
removeAttr(envElm, 'style');
|
|
||||||
removeElements(envElm);
|
|
||||||
|
|
||||||
if (!nativeScrollbarIsOverlaid.x || !nativeScrollbarIsOverlaid.y) {
|
|
||||||
var size = windowSize();
|
|
||||||
var dpr = windowDPR();
|
|
||||||
|
|
||||||
var onChangedListener = classPrivateFieldGet(this, _onChangedListener);
|
|
||||||
|
|
||||||
window.addEventListener('resize', function () {
|
|
||||||
if (onChangedListener.size) {
|
|
||||||
var sizeNew = windowSize();
|
|
||||||
var deltaSize = {
|
|
||||||
w: sizeNew.w - size.w,
|
|
||||||
h: sizeNew.h - size.h,
|
|
||||||
};
|
|
||||||
if (deltaSize.w === 0 && deltaSize.h === 0) return;
|
|
||||||
var deltaAbsSize = {
|
|
||||||
w: abs(deltaSize.w),
|
|
||||||
h: abs(deltaSize.h),
|
|
||||||
};
|
|
||||||
var deltaAbsRatio = {
|
|
||||||
w: abs(round(sizeNew.w / (size.w / 100.0))),
|
|
||||||
h: abs(round(sizeNew.h / (size.h / 100.0))),
|
|
||||||
};
|
|
||||||
var dprNew = windowDPR();
|
|
||||||
var deltaIsBigger = deltaAbsSize.w > 2 && deltaAbsSize.h > 2;
|
|
||||||
var difference = !diffBiggerThanOne(deltaAbsRatio.w, deltaAbsRatio.h);
|
|
||||||
var dprChanged = dprNew !== dpr && dpr > 0;
|
|
||||||
var isZoom = deltaIsBigger && difference && dprChanged;
|
|
||||||
var oldScrollbarSize = _self._nativeScrollbarSize;
|
|
||||||
var newScrollbarSize;
|
|
||||||
|
|
||||||
if (isZoom) {
|
|
||||||
newScrollbarSize = _self._nativeScrollbarSize = nativeScrollbarSize(body, envElm);
|
|
||||||
removeElements(envElm);
|
|
||||||
|
|
||||||
if (oldScrollbarSize.x !== newScrollbarSize.x || oldScrollbarSize.y !== newScrollbarSize.y) {
|
|
||||||
onChangedListener.forEach(function (listener) {
|
|
||||||
return listener && listener(_self);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size = sizeNew;
|
scrollbarSize = newScrollbarSize;
|
||||||
dpr = dprNew;
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
size = sizeNew;
|
||||||
|
dpr = dprNew;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var _proto = Environment.prototype;
|
return env;
|
||||||
|
};
|
||||||
|
|
||||||
_proto.addListener = function addListener(listener) {
|
var getEnvironment = function getEnvironment() {
|
||||||
classPrivateFieldGet(this, _onChangedListener).add(listener);
|
if (!environmentInstance) {
|
||||||
|
environmentInstance = createEnvironment();
|
||||||
|
}
|
||||||
|
|
||||||
|
return environmentInstance;
|
||||||
|
};
|
||||||
|
|
||||||
|
var animationStartEventName = 'animationstart';
|
||||||
|
var scrollEventName = 'scroll';
|
||||||
|
var scrollAmount = 3333333;
|
||||||
|
var ResizeObserverConstructor = jsAPI('ResizeObserver');
|
||||||
|
var classNameSizeObserver = 'os-size-observer';
|
||||||
|
var classNameSizeObserverListener = classNameSizeObserver + '-listener';
|
||||||
|
var classNameSizeObserverListenerItem = classNameSizeObserverListener + '-item';
|
||||||
|
var classNameSizeObserverListenerItemFinal = classNameSizeObserverListenerItem + '-final';
|
||||||
|
var cAF = cancelAnimationFrame;
|
||||||
|
var rAF = requestAnimationFrame;
|
||||||
|
|
||||||
|
var getDirection = function getDirection(elm) {
|
||||||
|
return style(elm, 'direction');
|
||||||
|
};
|
||||||
|
|
||||||
|
var createSizeObserver = function createSizeObserver(target, onSizeChangedCallback, direction) {
|
||||||
|
var rtlScrollBehavior = getEnvironment()._rtlScrollBehavior;
|
||||||
|
|
||||||
|
var baseElements = createDOM('<div class="' + classNameSizeObserver + '"><div class="' + classNameSizeObserverListener + '"></div></div>');
|
||||||
|
var sizeObserver = baseElements[0];
|
||||||
|
var listenerElement = sizeObserver.firstChild;
|
||||||
|
|
||||||
|
var onSizeChangedCallbackProxy = function onSizeChangedCallbackProxy(dir) {
|
||||||
|
if (direction) {
|
||||||
|
var rtl = getDirection(sizeObserver) === 'rtl';
|
||||||
|
scrollLeft(sizeObserver, rtl ? (rtlScrollBehavior.n ? -scrollAmount : rtlScrollBehavior.i ? 0 : scrollAmount) : scrollAmount);
|
||||||
|
scrollTop(sizeObserver, scrollAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
onSizeChangedCallback(dir === true);
|
||||||
};
|
};
|
||||||
|
|
||||||
_proto.removeListener = function removeListener(listener) {
|
var offListeners = [];
|
||||||
classPrivateFieldGet(this, _onChangedListener).delete(listener);
|
var appearCallback = onSizeChangedCallbackProxy;
|
||||||
};
|
|
||||||
|
|
||||||
return Environment;
|
if (ResizeObserverConstructor) {
|
||||||
})();
|
var resizeObserverInstance = new ResizeObserverConstructor(onSizeChangedCallbackProxy);
|
||||||
|
resizeObserverInstance.observe(listenerElement);
|
||||||
|
} else {
|
||||||
|
var observerElementChildren = createDOM(
|
||||||
|
'<div class="' +
|
||||||
|
classNameSizeObserverListenerItem +
|
||||||
|
'" dir="ltr"><div class="' +
|
||||||
|
classNameSizeObserverListenerItem +
|
||||||
|
'"><div class="' +
|
||||||
|
classNameSizeObserverListenerItemFinal +
|
||||||
|
'"></div></div><div class="' +
|
||||||
|
classNameSizeObserverListenerItem +
|
||||||
|
'"><div class="' +
|
||||||
|
classNameSizeObserverListenerItemFinal +
|
||||||
|
'" style="width: 200%; height: 200%"></div></div></div>'
|
||||||
|
);
|
||||||
|
appendChildren(listenerElement, observerElementChildren);
|
||||||
|
var observerElementChildrenRoot = observerElementChildren[0];
|
||||||
|
var shrinkElement = observerElementChildrenRoot.lastChild;
|
||||||
|
var expandElement = observerElementChildrenRoot.firstChild;
|
||||||
|
var expandElementChild = expandElement == null ? void 0 : expandElement.firstChild;
|
||||||
|
var cacheSize = offsetSize(listenerElement);
|
||||||
|
var currSize = cacheSize;
|
||||||
|
var isDirty = false;
|
||||||
|
var rAFId;
|
||||||
|
|
||||||
|
var reset = function reset() {
|
||||||
|
scrollLeft(expandElement, scrollAmount);
|
||||||
|
scrollTop(expandElement, scrollAmount);
|
||||||
|
scrollLeft(shrinkElement, scrollAmount);
|
||||||
|
scrollTop(shrinkElement, scrollAmount);
|
||||||
|
};
|
||||||
|
|
||||||
|
var onResized = function onResized() {
|
||||||
|
rAFId = 0;
|
||||||
|
if (!isDirty) return;
|
||||||
|
cacheSize = currSize;
|
||||||
|
onSizeChangedCallbackProxy();
|
||||||
|
};
|
||||||
|
|
||||||
|
var onScroll = function onScroll(scrollEvent) {
|
||||||
|
currSize = offsetSize(listenerElement);
|
||||||
|
isDirty = !scrollEvent || currSize.w !== cacheSize.w || currSize.h !== cacheSize.h;
|
||||||
|
|
||||||
|
if (scrollEvent && isDirty && !rAFId) {
|
||||||
|
cAF(rAFId);
|
||||||
|
rAFId = rAF(onResized);
|
||||||
|
} else if (!scrollEvent) onResized();
|
||||||
|
|
||||||
|
reset();
|
||||||
|
|
||||||
|
if (scrollEvent) {
|
||||||
|
preventDefault(scrollEvent);
|
||||||
|
stopPropagation(scrollEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
offListeners.push(on(expandElement, scrollEventName, onScroll));
|
||||||
|
offListeners.push(on(shrinkElement, scrollEventName, onScroll));
|
||||||
|
style(expandElementChild, {
|
||||||
|
width: scrollAmount,
|
||||||
|
height: scrollAmount,
|
||||||
|
});
|
||||||
|
reset();
|
||||||
|
appearCallback = onScroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (direction) {
|
||||||
|
var dirCache;
|
||||||
|
offListeners.push(
|
||||||
|
on(sizeObserver, scrollEventName, function (event) {
|
||||||
|
var dir = getDirection(sizeObserver);
|
||||||
|
var changed = dir !== dirCache;
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
if (dir === 'rtl') {
|
||||||
|
style(listenerElement, {
|
||||||
|
left: 'auto',
|
||||||
|
right: 0,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
style(listenerElement, {
|
||||||
|
left: 0,
|
||||||
|
right: 'auto',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
dirCache = dir;
|
||||||
|
onSizeChangedCallbackProxy(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
preventDefault(event);
|
||||||
|
stopPropagation(event);
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
offListeners.push(on(sizeObserver, animationStartEventName, appearCallback));
|
||||||
|
prependChildren(target, sizeObserver);
|
||||||
|
return function () {
|
||||||
|
runEach(offListeners);
|
||||||
|
removeElements(sizeObserver);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
var index = function () {
|
var index = function () {
|
||||||
return [
|
return [
|
||||||
new Environment(),
|
getEnvironment(),
|
||||||
|
createSizeObserver(document.body, function () {}),
|
||||||
createDOM(
|
createDOM(
|
||||||
'\
|
'\
|
||||||
<div class="os-host">\
|
<div class="os-host">\
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,5 +1,6 @@
|
|||||||
import { createDOM } from 'support/dom';
|
import { createDOM } from 'support/dom';
|
||||||
import { Environment } from 'environment';
|
import { getEnvironment } from 'environment';
|
||||||
|
import { createSizeObserver } from 'overlayscrollbars/observers/SizeObserver';
|
||||||
|
|
||||||
const abc = {
|
const abc = {
|
||||||
a: 1,
|
a: 1,
|
||||||
@@ -9,7 +10,8 @@ const abc = {
|
|||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
return [
|
return [
|
||||||
new Environment(),
|
getEnvironment(),
|
||||||
|
createSizeObserver(document.body, () => {}),
|
||||||
createDOM(
|
createDOM(
|
||||||
'\
|
'\
|
||||||
<div class="os-host">\
|
<div class="os-host">\
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import {
|
|||||||
on,
|
on,
|
||||||
preventDefault,
|
preventDefault,
|
||||||
stopPropagation,
|
stopPropagation,
|
||||||
|
addClass,
|
||||||
} from 'support';
|
} from 'support';
|
||||||
import { getEnvironment } from 'environment';
|
import { getEnvironment } from 'environment';
|
||||||
|
|
||||||
@@ -20,6 +21,7 @@ const scrollEventName = 'scroll';
|
|||||||
const scrollAmount = 3333333;
|
const scrollAmount = 3333333;
|
||||||
const ResizeObserverConstructor = jsAPI('ResizeObserver');
|
const ResizeObserverConstructor = jsAPI('ResizeObserver');
|
||||||
const classNameSizeObserver = 'os-size-observer';
|
const classNameSizeObserver = 'os-size-observer';
|
||||||
|
const classNameSizeObserverAppear = `${classNameSizeObserver}-appear`;
|
||||||
const classNameSizeObserverListener = `${classNameSizeObserver}-listener`;
|
const classNameSizeObserverListener = `${classNameSizeObserver}-listener`;
|
||||||
const classNameSizeObserverListenerItem = `${classNameSizeObserverListener}-item`;
|
const classNameSizeObserverListenerItem = `${classNameSizeObserverListener}-item`;
|
||||||
const classNameSizeObserverListenerItemFinal = `${classNameSizeObserverListenerItem}-final`;
|
const classNameSizeObserverListenerItemFinal = `${classNameSizeObserverListenerItem}-final`;
|
||||||
@@ -30,7 +32,13 @@ const getDirection = (elm: HTMLElement) => style(elm, 'direction');
|
|||||||
// TODO:
|
// TODO:
|
||||||
// 1. MAYBE add comparison function to offsetSize etc.
|
// 1. MAYBE add comparison function to offsetSize etc.
|
||||||
|
|
||||||
export const createSizeObserver = (target: HTMLElement, onSizeChangedCallback: (direction?: boolean) => any, direction?: boolean) => {
|
export type SizeObserverOptions = { _direction?: boolean; _appear?: boolean };
|
||||||
|
export const createSizeObserver = (
|
||||||
|
target: HTMLElement,
|
||||||
|
onSizeChangedCallback: (direction?: boolean) => any,
|
||||||
|
options?: SizeObserverOptions
|
||||||
|
): (() => void) => {
|
||||||
|
const { _direction: direction = false, _appear: appear = false } = options || {};
|
||||||
const rtlScrollBehavior = getEnvironment()._rtlScrollBehavior;
|
const rtlScrollBehavior = getEnvironment()._rtlScrollBehavior;
|
||||||
const baseElements = createDOM(`<div class="${classNameSizeObserver}"><div class="${classNameSizeObserverListener}"></div></div>`);
|
const baseElements = createDOM(`<div class="${classNameSizeObserver}"><div class="${classNameSizeObserverListener}"></div></div>`);
|
||||||
const sizeObserver = baseElements[0] as HTMLElement;
|
const sizeObserver = baseElements[0] as HTMLElement;
|
||||||
@@ -49,6 +57,7 @@ export const createSizeObserver = (target: HTMLElement, onSizeChangedCallback: (
|
|||||||
if (ResizeObserverConstructor) {
|
if (ResizeObserverConstructor) {
|
||||||
const resizeObserverInstance = new ResizeObserverConstructor(onSizeChangedCallbackProxy);
|
const resizeObserverInstance = new ResizeObserverConstructor(onSizeChangedCallbackProxy);
|
||||||
resizeObserverInstance.observe(listenerElement);
|
resizeObserverInstance.observe(listenerElement);
|
||||||
|
offListeners.push(() => resizeObserverInstance.disconnect());
|
||||||
} else {
|
} else {
|
||||||
const observerElementChildren = createDOM(
|
const observerElementChildren = createDOM(
|
||||||
`<div class="${classNameSizeObserverListenerItem}" dir="ltr"><div class="${classNameSizeObserverListenerItem}"><div class="${classNameSizeObserverListenerItemFinal}"></div></div><div class="${classNameSizeObserverListenerItem}"><div class="${classNameSizeObserverListenerItemFinal}" style="width: 200%; height: 200%"></div></div></div>`
|
`<div class="${classNameSizeObserverListenerItem}" dir="ltr"><div class="${classNameSizeObserverListenerItem}"><div class="${classNameSizeObserverListenerItemFinal}"></div></div><div class="${classNameSizeObserverListenerItem}"><div class="${classNameSizeObserverListenerItemFinal}" style="width: 200%; height: 200%"></div></div></div>`
|
||||||
@@ -84,7 +93,9 @@ export const createSizeObserver = (target: HTMLElement, onSizeChangedCallback: (
|
|||||||
if (scrollEvent && isDirty && !rAFId) {
|
if (scrollEvent && isDirty && !rAFId) {
|
||||||
cAF(rAFId);
|
cAF(rAFId);
|
||||||
rAFId = rAF(onResized);
|
rAFId = rAF(onResized);
|
||||||
} else if (!scrollEvent) onResized();
|
} else if (!scrollEvent) {
|
||||||
|
onResized();
|
||||||
|
}
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
if (scrollEvent) {
|
if (scrollEvent) {
|
||||||
@@ -129,7 +140,11 @@ export const createSizeObserver = (target: HTMLElement, onSizeChangedCallback: (
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
offListeners.push(on(sizeObserver, animationStartEventName, appearCallback));
|
if (appear) {
|
||||||
|
addClass(sizeObserver, classNameSizeObserverAppear);
|
||||||
|
offListeners.push(on(sizeObserver, animationStartEventName, appearCallback));
|
||||||
|
}
|
||||||
|
|
||||||
prependChildren(target, sizeObserver);
|
prependChildren(target, sizeObserver);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import { createDOM, offsetSize, jsAPI, runEach, prependChildren, removeElements } from 'support';
|
||||||
|
import { createSizeObserver } from 'overlayscrollbars/observers/SizeObserver';
|
||||||
|
|
||||||
|
const classNameTrinsicObserver = 'os-trinsic-observer';
|
||||||
|
const IntersectionObserverConstructor = jsAPI('IntersectionObserver');
|
||||||
|
|
||||||
|
export const createTrinsicObserver = (
|
||||||
|
target: HTMLElement,
|
||||||
|
onTrinsicChangedCallback: (widthIntrinsic: boolean, heightIntrinsic: boolean) => any
|
||||||
|
): (() => void) => {
|
||||||
|
const trinsicObserver = createDOM(`<div class="${classNameTrinsicObserver}"></div>`)[0] as HTMLElement;
|
||||||
|
const offListeners: (() => void)[] = [];
|
||||||
|
let heightIntrinsic = false;
|
||||||
|
|
||||||
|
if (IntersectionObserverConstructor) {
|
||||||
|
const intersectionObserverInstance: IntersectionObserver = new IntersectionObserverConstructor(
|
||||||
|
(entries: IntersectionObserverEntry[]) => {
|
||||||
|
if (entries && entries.length > 0) {
|
||||||
|
const last = entries.pop();
|
||||||
|
if (last) {
|
||||||
|
const newHeightIntrinsic = last.isIntersecting || last.intersectionRatio > 0;
|
||||||
|
|
||||||
|
if (newHeightIntrinsic !== heightIntrinsic) {
|
||||||
|
onTrinsicChangedCallback(false, newHeightIntrinsic);
|
||||||
|
heightIntrinsic = newHeightIntrinsic;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ root: target }
|
||||||
|
);
|
||||||
|
intersectionObserverInstance.observe(trinsicObserver);
|
||||||
|
offListeners.push(() => intersectionObserverInstance.disconnect());
|
||||||
|
} else {
|
||||||
|
offListeners.push(
|
||||||
|
createSizeObserver(trinsicObserver, () => {
|
||||||
|
const newSize = offsetSize(trinsicObserver);
|
||||||
|
const newHeightIntrinsic = newSize.h === 0;
|
||||||
|
if (newHeightIntrinsic !== heightIntrinsic) {
|
||||||
|
onTrinsicChangedCallback(false, newSize.h === 0);
|
||||||
|
heightIntrinsic = newHeightIntrinsic;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
prependChildren(target, trinsicObserver);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
runEach(offListeners);
|
||||||
|
removeElements(trinsicObserver);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ $scrollbar-cushion: 100px;
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
z-index: -1;
|
z-index: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.os-size-observer-appear {
|
||||||
animation-duration: 0.001s;
|
animation-duration: 0.001s;
|
||||||
animation-name: os-size-observer-appear-animation;
|
animation-name: os-size-observer-appear-animation;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
.os-trinsic-observer {
|
||||||
|
flex: none;
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: relative;
|
||||||
|
max-width: 1px;
|
||||||
|
max-height: 1px;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
border: none;
|
||||||
|
overflow: hidden;
|
||||||
|
z-index: -1;
|
||||||
|
height: 0;
|
||||||
|
top: calc(-100% + 1px);
|
||||||
|
|
||||||
|
&:not(:empty) {
|
||||||
|
height: calc(100% + 1px);
|
||||||
|
top: auto;
|
||||||
|
|
||||||
|
& > .os-size-observer {
|
||||||
|
width: 1000%;
|
||||||
|
height: 1000%;
|
||||||
|
min-height: 1px;
|
||||||
|
min-width: 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -170,7 +170,7 @@ createSizeObserver(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
true
|
{ _direction: true, _appear: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
export { start };
|
export { start };
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { XY } from 'support';
|
import { XY } from 'support';
|
||||||
declare type OnEnvironmentChanged = (env: Environment) => void;
|
export declare type OnEnvironmentChanged = (env: Environment) => void;
|
||||||
export declare class Environment {
|
export interface Environment {
|
||||||
#private;
|
|
||||||
_autoUpdateLoop: boolean;
|
_autoUpdateLoop: boolean;
|
||||||
_nativeScrollbarSize: XY;
|
_nativeScrollbarSize: XY;
|
||||||
_nativeScrollbarIsOverlaid: XY<boolean>;
|
_nativeScrollbarIsOverlaid: XY<boolean>;
|
||||||
@@ -10,10 +9,7 @@ export declare class Environment {
|
|||||||
n: boolean;
|
n: boolean;
|
||||||
i: boolean;
|
i: boolean;
|
||||||
};
|
};
|
||||||
_supportPassiveEvents: boolean;
|
_addListener(listener: OnEnvironmentChanged): void;
|
||||||
_supportResizeObserver: boolean;
|
_removeListener(listener: OnEnvironmentChanged): void;
|
||||||
constructor();
|
|
||||||
addListener(listener: OnEnvironmentChanged): void;
|
|
||||||
removeListener(listener: OnEnvironmentChanged): void;
|
|
||||||
}
|
}
|
||||||
export {};
|
export declare const getEnvironment: () => Environment;
|
||||||
|
|||||||
+1
-2
@@ -1,3 +1,2 @@
|
|||||||
import { Environment } from 'environment';
|
declare const _default: () => (import("./environment").Environment | (() => void) | readonly Node[])[];
|
||||||
declare const _default: () => (Environment | readonly Node[])[];
|
|
||||||
export default _default;
|
export default _default;
|
||||||
|
|||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
export declare const createSizeObserver: (target: HTMLElement, onSizeChangedCallback: (direction?: boolean | undefined) => any, direction?: boolean | undefined) => () => void;
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
export declare const hi: () => null;
|
||||||
-1
@@ -1 +0,0 @@
|
|||||||
export declare const createSizeObserver: (onSizeChangedCallback: () => void) => HTMLElement;
|
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
import { WH } from 'support/dom';
|
export interface WH<T = number> {
|
||||||
|
w: T;
|
||||||
|
h: T;
|
||||||
|
}
|
||||||
export declare const windowSize: () => WH;
|
export declare const windowSize: () => WH;
|
||||||
export declare const offsetSize: (elm: HTMLElement | null) => WH;
|
export declare const offsetSize: (elm: HTMLElement | null) => WH;
|
||||||
export declare const clientSize: (elm: HTMLElement | null) => WH;
|
export declare const clientSize: (elm: HTMLElement | null) => WH;
|
||||||
|
|||||||
@@ -1 +1,9 @@
|
|||||||
export declare const on: (target: EventTarget, type: string, listener: EventListenerOrEventListenerObject | null, options: AddEventListenerOptions) => void;
|
export interface OnOptions {
|
||||||
|
_capture?: boolean;
|
||||||
|
_passive?: boolean;
|
||||||
|
_once?: boolean;
|
||||||
|
}
|
||||||
|
export declare const off: (target: EventTarget, eventNames: string, listener: EventListener, capture?: boolean | undefined) => void;
|
||||||
|
export declare const on: (target: EventTarget, eventNames: string, listener: EventListener, options?: OnOptions | undefined) => (() => void);
|
||||||
|
export declare const stopPropagation: (evt: Event) => void;
|
||||||
|
export declare const preventDefault: (evt: Event) => void;
|
||||||
|
|||||||
+1
-8
@@ -2,15 +2,8 @@ export * from 'support/dom/attribute';
|
|||||||
export * from 'support/dom/class';
|
export * from 'support/dom/class';
|
||||||
export * from 'support/dom/create';
|
export * from 'support/dom/create';
|
||||||
export * from 'support/dom/dimensions';
|
export * from 'support/dom/dimensions';
|
||||||
|
export * from 'support/dom/events';
|
||||||
export * from 'support/dom/style';
|
export * from 'support/dom/style';
|
||||||
export * from 'support/dom/manipulation';
|
export * from 'support/dom/manipulation';
|
||||||
export * from 'support/dom/offset';
|
export * from 'support/dom/offset';
|
||||||
export * from 'support/dom/traversal';
|
export * from 'support/dom/traversal';
|
||||||
export interface XY<T = number> {
|
|
||||||
x: T;
|
|
||||||
y: T;
|
|
||||||
}
|
|
||||||
export interface WH<T = number> {
|
|
||||||
w: T;
|
|
||||||
h: T;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
import { XY } from 'support/dom';
|
export interface XY<T = number> {
|
||||||
|
x: T;
|
||||||
|
y: T;
|
||||||
|
}
|
||||||
export declare const absoluteCoordinates: (elm: HTMLElement | null) => XY;
|
export declare const absoluteCoordinates: (elm: HTMLElement | null) => XY;
|
||||||
export declare const offsetCoordinates: (elm: HTMLElement | null) => XY;
|
export declare const offsetCoordinates: (elm: HTMLElement | null) => XY;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { PlainObject } from 'typings';
|
import { PlainObject } from 'typings';
|
||||||
|
declare type RunEachItem = ((...args: any) => any | any[]) | null | undefined;
|
||||||
export declare function each<T>(array: Array<T> | ReadonlyArray<T>, callback: (value: T, indexOrKey: number, source: Array<T>) => boolean | void): Array<T> | ReadonlyArray<T>;
|
export declare function each<T>(array: Array<T> | ReadonlyArray<T>, callback: (value: T, indexOrKey: number, source: Array<T>) => boolean | void): Array<T> | ReadonlyArray<T>;
|
||||||
export declare function each<T>(array: Array<T> | ReadonlyArray<T> | null, callback: (value: T, indexOrKey: number, source: Array<T>) => boolean | void): Array<T> | ReadonlyArray<T> | null;
|
export declare function each<T>(array: Array<T> | ReadonlyArray<T> | null, callback: (value: T, indexOrKey: number, source: Array<T>) => boolean | void): Array<T> | ReadonlyArray<T> | null;
|
||||||
export declare function each<T>(arrayLikeObject: ArrayLike<T>, callback: (value: T, indexOrKey: number, source: ArrayLike<T>) => boolean | void): ArrayLike<T>;
|
export declare function each<T>(arrayLikeObject: ArrayLike<T>, callback: (value: T, indexOrKey: number, source: ArrayLike<T>) => boolean | void): ArrayLike<T>;
|
||||||
@@ -7,3 +8,5 @@ export declare function each(obj: PlainObject, callback: (value: any, indexOrKey
|
|||||||
export declare function each(obj: PlainObject | null, callback: (value: any, indexOrKey: string, source: PlainObject) => boolean | void): PlainObject | null;
|
export declare function each(obj: PlainObject | null, callback: (value: any, indexOrKey: string, source: PlainObject) => boolean | void): PlainObject | null;
|
||||||
export declare const indexOf: <T = any>(arr: T[], item: T, fromIndex?: number | undefined) => number;
|
export declare const indexOf: <T = any>(arr: T[], item: T, fromIndex?: number | undefined) => number;
|
||||||
export declare const from: <T = any>(arr: ArrayLike<T>) => T[];
|
export declare const from: <T = any>(arr: ArrayLike<T>) => T[];
|
||||||
|
export declare const runEach: (arr: ArrayLike<RunEachItem> | Set<RunEachItem>) => void;
|
||||||
|
export {};
|
||||||
|
|||||||
Reference in New Issue
Block a user