improve code

This commit is contained in:
Rene
2022-07-27 20:56:47 +02:00
parent b3494f8f9c
commit 352501f2f1
14 changed files with 174 additions and 135 deletions
@@ -38,7 +38,7 @@ export interface SizeObserverCallbackParams {
_appear?: boolean;
}
export type DestroySizeObserver = () => void;
export type SizeObserver = [destroy: () => void, append: () => void];
const scrollAmount = 3333333;
const getElmDirectionIsRTL = (elm: HTMLElement): boolean => style(elm, 'direction') === 'rtl';
@@ -55,7 +55,7 @@ export const createSizeObserver = (
target: HTMLElement,
onSizeChangedCallback: (params: SizeObserverCallbackParams) => any,
options?: SizeObserverOptions
): DestroySizeObserver => {
): SizeObserver => {
const { _direction: observeDirectionChange = false, _appear: observeAppearChange = false } =
options || {};
const sizeObserverPlugin = getPlugins()[sizeObserverPluginName] as
@@ -147,68 +147,71 @@ export const createSizeObserver = (
: false;
let directionIsRTLCache: Cache<boolean> | undefined;
if (ResizeObserverConstructor) {
const resizeObserverInstance = new ResizeObserverConstructor(onSizeChangedCallbackProxy);
resizeObserverInstance.observe(listenerElement);
push(offListeners, () => {
resizeObserverInstance.disconnect();
});
} else if (sizeObserverPlugin) {
const [pluginAppearCallback, pluginOffListeners] = sizeObserverPlugin._(
listenerElement,
onSizeChangedCallbackProxy,
observeAppearChange
);
appearCallback = pluginAppearCallback;
push(offListeners, pluginOffListeners);
}
return [
() => {
runEachAndClear(offListeners);
removeElements(sizeObserver);
},
() => {
if (ResizeObserverConstructor) {
const resizeObserverInstance = new ResizeObserverConstructor(onSizeChangedCallbackProxy);
resizeObserverInstance.observe(listenerElement);
push(offListeners, () => {
resizeObserverInstance.disconnect();
});
} else if (sizeObserverPlugin) {
const [pluginAppearCallback, pluginOffListeners] = sizeObserverPlugin._(
listenerElement,
onSizeChangedCallbackProxy,
observeAppearChange
);
appearCallback = pluginAppearCallback;
push(offListeners, pluginOffListeners);
}
if (observeDirectionChange) {
directionIsRTLCache = createCache(
{
_initialValue: !getIsDirectionRTL(), // invert current value to trigger initial change
},
getIsDirectionRTL
);
const [updateDirectionIsRTLCache] = directionIsRTLCache;
if (observeDirectionChange) {
directionIsRTLCache = createCache(
{
_initialValue: !getIsDirectionRTL(), // invert current value to trigger initial change
},
getIsDirectionRTL
);
const [updateDirectionIsRTLCache] = directionIsRTLCache;
push(
offListeners,
on(sizeObserver, 'scroll', (event: Event) => {
const directionIsRTLCacheValues = updateDirectionIsRTLCache();
const [directionIsRTL, directionIsRTLChanged] = directionIsRTLCacheValues;
push(
offListeners,
on(sizeObserver, 'scroll', (event: Event) => {
const directionIsRTLCacheValues = updateDirectionIsRTLCache();
const [directionIsRTL, directionIsRTLChanged] = directionIsRTLCacheValues;
if (directionIsRTLChanged) {
removeClass(listenerElement, 'ltr rtl');
if (directionIsRTL) {
addClass(listenerElement, 'rtl');
} else {
addClass(listenerElement, 'ltr');
}
onSizeChangedCallbackProxy(directionIsRTLCacheValues);
}
if (directionIsRTLChanged) {
removeClass(listenerElement, 'ltr rtl');
if (directionIsRTL) {
addClass(listenerElement, 'rtl');
} else {
addClass(listenerElement, 'ltr');
}
onSizeChangedCallbackProxy(directionIsRTLCacheValues);
}
stopPropagation(event);
})
);
}
stopPropagation(event);
})
);
}
// appearCallback is always needed on scroll-observer strategy to reset it
if (appearCallback) {
addClass(sizeObserver, classNameSizeObserverAppear);
push(
offListeners,
on(sizeObserver, 'animationstart', appearCallback, {
// Fire only once for "CSS is ready" event if ResizeObserver strategy is used
_once: !!ResizeObserverConstructor,
})
);
}
// appearCallback is always needed on scroll-observer strategy to reset it
if (appearCallback) {
addClass(sizeObserver, classNameSizeObserverAppear);
push(
offListeners,
on(sizeObserver, 'animationstart', appearCallback, {
// Fire only once for "CSS is ready" event if ResizeObserver strategy is used
_once: !!ResizeObserverConstructor,
})
);
}
prependChildren(target, sizeObserver);
return () => {
runEachAndClear(offListeners);
removeElements(sizeObserver);
};
prependChildren(target, sizeObserver);
},
];
};
@@ -16,6 +16,7 @@ import { classNameTrinsicObserver } from 'classnames';
export type TrinsicObserverCallback = (heightIntrinsic: CacheValues<boolean>) => any;
export type TrinsicObserver = [
destroy: () => void,
append: () => void,
update: () => void | Parameters<TrinsicObserverCallback>
];
@@ -63,31 +64,37 @@ export const createTrinsicObserver = (
}
};
if (IntersectionObserverConstructor) {
intersectionObserverInstance = new IntersectionObserverConstructor(
(entries) => intersectionObserverCallback(entries),
{ root: target }
);
intersectionObserverInstance.observe(trinsicObserver);
push(offListeners, () => {
intersectionObserverInstance!.disconnect();
});
} else {
const onSizeChanged = () => {
const newSize = offsetSize(trinsicObserver);
triggerOnTrinsicChangedCallback(newSize);
};
push(offListeners, createSizeObserver(trinsicObserver, onSizeChanged));
onSizeChanged();
}
prependChildren(target, trinsicObserver);
return [
() => {
runEachAndClear(offListeners);
removeElements(trinsicObserver);
},
() => {
if (IntersectionObserverConstructor) {
intersectionObserverInstance = new IntersectionObserverConstructor(
(entries) => intersectionObserverCallback(entries),
{ root: target }
);
intersectionObserverInstance.observe(trinsicObserver);
push(offListeners, () => {
intersectionObserverInstance!.disconnect();
});
} else {
const onSizeChanged = () => {
const newSize = offsetSize(trinsicObserver);
triggerOnTrinsicChangedCallback(newSize);
};
const [destroySizeObserver, appendSizeObserver] = createSizeObserver(
trinsicObserver,
onSizeChanged
);
push(offListeners, destroySizeObserver);
appendSizeObserver();
onSizeChanged();
}
prependChildren(target, trinsicObserver);
},
() => {
if (intersectionObserverInstance) {
return intersectionObserverCallback(intersectionObserverInstance.takeRecords(), true);
@@ -91,7 +91,7 @@ export const sizeObserverPlugin: Plugin<SizeObserverPluginInstance> = {
height: scrollAmount,
});
reset();
rAF!(reset);
return [observeAppearChange ? onScroll.bind(0, false) : reset, offListeners];
},
@@ -1,7 +1,8 @@
import { offsetSize } from 'support';
import { getEnvironment } from 'environment';
import type { StructureSetupState } from 'setups';
const { min, max } = Math;
const { min, max, abs } = Math;
export const getScrollbarHandleLengthRatio = (
scrollbarHandle: HTMLElement,
scrollbarTrack: HTMLElement,
@@ -26,14 +27,22 @@ export const getScrollbarHandleOffsetRatio = (
scrollbarTrack: HTMLElement,
scrollOffsetElement: HTMLElement,
structureSetupState: StructureSetupState,
isRTL: boolean,
isHorizontal?: boolean
) => {
const { _rtlScrollBehavior } = getEnvironment();
const axis = isHorizontal ? 'x' : 'y';
const scrollLeftTop = isHorizontal ? 'Left' : 'Top';
const { _overflowAmount } = structureSetupState;
const scrollPosition = scrollOffsetElement[`scroll${scrollLeftTop}`] as number;
const scrollPositionMax = Math.floor(_overflowAmount[axis]);
const scrollPercent = min(1, scrollPosition / scrollPositionMax);
const scrollPosition = abs(scrollOffsetElement[`scroll${scrollLeftTop}`]);
const handleRTL = isHorizontal && isRTL;
const rtlNormalizedScrollPosition = _rtlScrollBehavior.i
? scrollPosition
: scrollPositionMax - scrollPosition;
const finalScrollPosition = handleRTL ? rtlNormalizedScrollPosition : scrollPosition;
const scrollPercent = min(1, finalScrollPosition / scrollPositionMax);
const lengthRatio = getScrollbarHandleLengthRatio(scrollbarHandle, scrollbarTrack, isHorizontal);
return (1 / lengthRatio) * (1 - lengthRatio) * scrollPercent;
};
@@ -132,12 +132,13 @@ export const createScrollbarsSetupElements = (
) => {
const translateAxis = isHorizontal ? 'X' : 'Y';
scrollbarsHandleStyle(scrollbarStructures, (structure) => {
const { _handle, _track } = structure;
const { _handle, _track, _scrollbar } = structure;
const offsetRatio = getScrollbarHandleOffsetRatio(
_handle,
_track,
_scrollOffsetElement,
structureSetupState,
style(_scrollbar, 'direction') === 'rtl',
isHorizontal
);
// eslint-disable-next-line no-self-compare
@@ -5,6 +5,7 @@ import {
preventDefault,
runEachAndClear,
stopPropagation,
style,
XY,
} from 'support';
import { classNamesScrollbarInteraction } from 'classnames';
@@ -14,6 +15,7 @@ import type {
ScrollbarsSetupElementsObj,
ScrollbarStructure,
} from 'setups/scrollbarsSetup/scrollbarsSetup.elements';
import { getEnvironment } from 'environment';
export type ScrollbarsSetupEvents = (
scrollbarStructure: ScrollbarStructure,
@@ -23,6 +25,7 @@ export type ScrollbarsSetupEvents = (
isHorizontal?: boolean
) => () => void;
const { round, abs } = Math;
const getPageOffset = (event: PointerEvent): XY<number> => ({
x: event.pageX,
y: event.pageY,
@@ -31,8 +34,8 @@ const getScale = (element: HTMLElement): XY<number> => {
const { width, height } = getBoundingClientRect(element);
const { w, h } = offsetSize(element);
return {
x: Math.round(width) / w || 1,
y: Math.round(height) / h || 1,
x: round(width) / w || 1,
y: round(height) / h || 1,
};
};
const continuePointerDown = (
@@ -65,7 +68,8 @@ const createDragScrollingEvents = (
structureSetupState: () => StructureSetupState,
isHorizontal?: boolean
) => {
const { _handle, _track } = scrollbarStructure;
const { _rtlScrollBehavior } = getEnvironment();
const { _handle, _track, _scrollbar } = scrollbarStructure;
const scrollOffsetKey = `scroll${isHorizontal ? 'Left' : 'Top'}`;
const xyKey = `${isHorizontal ? 'x' : 'y'}`;
const whKey = `${isHorizontal ? 'w' : 'h'}`;
@@ -77,9 +81,12 @@ const createDragScrollingEvents = (
const handleTrackDiff = offsetSize(_track)[whKey] - offsetSize(_handle)[whKey];
const scrollDeltaPercent = movement / handleTrackDiff;
const scrollDelta = scrollDeltaPercent * _overflowAmount[xyKey];
const isRTL = style(_scrollbar, 'direction') === 'rtl';
const negateMultiplactor =
isRTL && isHorizontal ? (_rtlScrollBehavior.n || _rtlScrollBehavior.i ? 1 : -1) : 1;
scrollOffsetElement[scrollOffsetKey] = mouseDownScroll + scrollDelta;
// if (_isRTL && isHorizontal && !_rtlScrollBehavior.i) scrollDelta *= -1;
scrollOffsetElement[scrollOffsetKey] =
abs(mouseDownScroll) + scrollDelta * negateMultiplactor;
};
return on(_handle, 'pointerdown', (pointerDownEvent: PointerEvent) => {
@@ -173,8 +173,12 @@ export const createScrollbarsSetup = (
return [
(changedOptions, force, structureUpdateHints) => {
const { _overflowEdgeChanged, _overflowAmountChanged, _overflowStyleChanged } =
structureUpdateHints;
const {
_overflowEdgeChanged,
_overflowAmountChanged,
_overflowStyleChanged,
_directionChanged,
} = structureUpdateHints;
const checkOption = createOptionCheck(options, changedOptions, force);
const currStructureSetupState = structureSetupState();
const { _overflowAmount, _overflowStyle } = currStructureSetupState;
@@ -187,7 +191,7 @@ export const createScrollbarsSetup = (
const [dragScroll, dragScrollChanged] = checkOption<boolean>('scrollbars.dragScroll');
const [clickScroll, clickScrollChanged] = checkOption<boolean>('scrollbars.clickScroll');
const updateHandle = _overflowEdgeChanged || _overflowAmountChanged;
const updateHandle = _overflowEdgeChanged || _overflowAmountChanged || _directionChanged;
const updateVisibility = _overflowStyleChanged || visibilityChanged;
const setScrollbarVisibility = (overflowStyle: OverflowStyle, isHorizontal: boolean) => {
@@ -22,6 +22,7 @@ import {
push,
scrollLeft,
scrollTop,
noop,
} from 'support';
import { getEnvironment } from 'environment';
import {
@@ -48,6 +49,7 @@ export type StructureSetupObserversUpdate = (checkOption: SetupUpdateCheckOption
export type StructureSetupObservers = [
destroy: () => void,
appendElements: () => void,
updateObservers: () => Partial<StructureSetupUpdateHints>,
updateObserversOptions: StructureSetupObserversUpdate
];
@@ -87,7 +89,7 @@ export const createStructureSetupObservers = (
_viewportHasClass,
_viewportAddRemoveClass,
} = structureSetupElements;
const { _nativeScrollbarsHiding: _nativeScrollbarStyling, _flexboxGlue } = getEnvironment();
const { _flexboxGlue } = getEnvironment();
const [updateContentSizeCache] = createCache<WH<number>>(
{
@@ -207,14 +209,14 @@ export const createStructureSetupObservers = (
return updateHints;
};
const trinsicObserver =
(_content || !_flexboxGlue) && createTrinsicObserver(_host, onTrinsicChanged);
const destroySizeObserver =
!_viewportIsTarget &&
createSizeObserver(_host, onSizeChanged, {
_appear: true,
_direction: !_nativeScrollbarStyling,
});
const [destroyTrinsicObserver, appendTrinsicObserver, updateTrinsicObserver] =
_content || !_flexboxGlue ? createTrinsicObserver(_host, onTrinsicChanged) : [noop, noop, noop];
const [destroySizeObserver, appendSizeObserver] = !_viewportIsTarget
? createSizeObserver(_host, onSizeChanged, {
_appear: true,
_direction: true,
})
: [noop, noop];
const [destroyHostMutationObserver, updateHostMutationObserver] = createDOMObserver(
_host,
false,
@@ -235,17 +237,21 @@ export const createStructureSetupObservers = (
return [
() => {
destroyTrinsicObserver();
destroySizeObserver();
contentMutationObserver && contentMutationObserver[0](); // destroy
trinsicObserver && trinsicObserver[0](); // destroy
destroySizeObserver && destroySizeObserver();
viewportIsTargetResizeObserver && viewportIsTargetResizeObserver.disconnect();
destroyHostMutationObserver();
},
() => {
appendSizeObserver();
appendTrinsicObserver();
},
() => {
const updateHints: Partial<StructureSetupUpdateHints> = {};
const hostUpdateResult = updateHostMutationObserver();
const trinsicUpdateResult = updateTrinsicObserver();
const contentUpdateResult = contentMutationObserver && contentMutationObserver[1](); // update
const trinsicUpdateResult = trinsicObserver && trinsicObserver[1](); // update
if (hostUpdateResult) {
assignDeep(
@@ -259,18 +265,6 @@ export const createStructureSetupObservers = (
)
);
}
if (contentUpdateResult) {
assignDeep(
updateHints,
onContentMutation.apply(
0,
push(contentUpdateResult, true) as [
...updateResult: typeof contentUpdateResult,
fromRecords: true
]
)
);
}
if (trinsicUpdateResult) {
assignDeep(
updateHints,
@@ -283,6 +277,18 @@ export const createStructureSetupObservers = (
)
);
}
if (contentUpdateResult) {
assignDeep(
updateHints,
onContentMutation.apply(
0,
push(contentUpdateResult, true) as [
...updateResult: typeof contentUpdateResult,
fromRecords: true
]
)
);
}
return updateHints;
},
@@ -73,7 +73,7 @@ export const createStructureSetup = (
const state = createState(initialStructureSetupUpdateState);
const [addEvent, removeEvent, triggerEvent] = createEventListenerHub<StructureSetupEventMap>();
const [getState] = state;
const [elements, appendElements, destroyElements] = createStructureSetupElements(target);
const [elements, appendStructureElements, destroyElements] = createStructureSetupElements(target);
const updateStructure = createStructureSetupUpdate(elements, state);
const triggerUpdateEvent: (...args: StructureSetupEventMap['u']) => void = (
updateHints,
@@ -86,20 +86,20 @@ export const createStructureSetup = (
triggerEvent('u', [updateHints, changedOptions, force]);
}
};
const [destroyObservers, updateObservers, updateObserversOptions] = createStructureSetupObservers(
elements,
state,
(updateHints) => {
const [destroyObservers, appendObserverElements, updateObservers, updateObserversOptions] =
createStructureSetupObservers(elements, state, (updateHints) => {
triggerUpdateEvent(updateStructure(checkOptionsFallback, updateHints), {}, false);
}
);
});
const structureSetupState = getState.bind(0) as (() => StructureSetupState) &
StructureSetupStaticState;
structureSetupState._addOnUpdatedListener = (listener) => {
addEvent('u', listener);
};
structureSetupState._appendElements = appendElements;
structureSetupState._appendElements = () => {
appendStructureElements();
appendObserverElements();
};
structureSetupState._elements = elements;
return [
@@ -18,6 +18,7 @@ body > .os-scrollbar {
}
.os-scrollbar-track {
position: relative;
direction: ltr !important;
padding: 0 !important;
border: none !important;
}
@@ -31,7 +32,7 @@ body > .os-scrollbar {
height: 100%;
}
.os-scrollbar.os-scrollbar-track-interactive .os-scrollbar-track,
.os-scrollbar.os-scrollbar-handle-interactive .os-scrollbar-handle {
.os-scrollbar.os-scrollbar-handle-interactive .os-scrollbar-handle {
pointer-events: auto;
touch-action: none;
}
@@ -61,10 +62,10 @@ body > .os-scrollbar {
}
.os-scrollbar-unusable,
.os-scrollbar-unusable * {
pointer-events: none !important;
pointer-events: none !important;
}
.os-scrollbar-unusable .os-scrollbar-handle {
opacity: 0 !important;
opacity: 0 !important;
}
.os-scrollbar.os-scrollbar-horizontal.os-scrollbar-cornerless {
left: 0;
@@ -24,7 +24,7 @@ $shrink-scale: 0.1;
z-index: -1;
contain: strict;
display: flex;
flex-direction: column;
flex-direction: row;
flex-wrap: nowrap;
padding: inherit;
border: inherit;
@@ -47,7 +47,7 @@ const startBtn: HTMLButtonElement | null = document.querySelector('#start');
const resizesSlot: HTMLButtonElement | null = document.querySelector('#resizes');
const preInitChildren = targetElm?.children.length;
const destroySizeObserver = createSizeObserver(
const [destroySizeObserver, appendSizeObserver] = createSizeObserver(
targetElm as HTMLElement,
({ _directionIsRTLCache, _sizeChanged }) => {
if (_sizeChanged) {
@@ -66,6 +66,7 @@ const destroySizeObserver = createSizeObserver(
},
{ _direction: true, _appear: true }
);
appendSizeObserver();
const selectCallback = generateClassChangeSelectCallback(targetElm as HTMLElement);
const iterate = async (select: HTMLSelectElement | null, afterEach?: () => any) => {
@@ -29,9 +29,8 @@ const startBtn: HTMLButtonElement | null = document.querySelector('#start');
const changesSlot: HTMLButtonElement | null = document.querySelector('#changes');
const preInitChildren = targetElm?.children.length;
const [destroyTrinsicObserver, updateTrinsicObserver] = createTrinsicObserver(
targetElm as HTMLElement,
(heightIntrinsicCache) => {
const [destroyTrinsicObserver, appendTrinsicObserver, updateTrinsicObserver] =
createTrinsicObserver(targetElm as HTMLElement, (heightIntrinsicCache) => {
const [currentHeightIntrinsic, currentHeightIntrinsicChanged] = heightIntrinsicCache;
if (currentHeightIntrinsicChanged) {
heightIterations += 1;
@@ -42,8 +41,8 @@ const [destroyTrinsicObserver, updateTrinsicObserver] = createTrinsicObserver(
changesSlot.textContent = heightIterations.toString();
}
});
}
);
});
appendTrinsicObserver();
const envElmSelectCallback = generateClassChangeSelectCallback(envElm as HTMLElement);
const targetElmSelectCallback = generateClassChangeSelectCallback(targetElm as HTMLElement);
+1
View File
@@ -0,0 +1 @@
export {};