improve event flow

This commit is contained in:
Rene
2022-07-12 12:56:27 +02:00
parent 295f94309f
commit a4482f96d6
16 changed files with 685 additions and 633 deletions
+130 -120
View File
@@ -670,11 +670,11 @@ const createEventListenerHub = t => {
}), e); }), e);
return removeEvent.bind(0, t, e); return removeEvent.bind(0, t, e);
} }
function triggerEvent(t, ...e) { function triggerEvent(t, e) {
const o = n.get(t); const o = n.get(t);
each(from(o), (t => { each(from(o), (t => {
if (e) { if (e && !isEmptyArray(e)) {
t(e); t.apply(0, e);
} else { } else {
t(); t();
} }
@@ -1048,10 +1048,11 @@ const createStructureSetupElements = t => {
const N = f && elementIsGenerated(z); const N = f && elementIsGenerated(z);
const R = f ? L : contents([ P, E, D, z, L ].find((t => false === elementIsGenerated(t)))); const R = f ? L : contents([ P, E, D, z, L ].find((t => false === elementIsGenerated(t))));
const H = P || E; const H = P || E;
const F = addDataAttrHost(z, y ? "viewport" : "host"); const appendElements = () => {
const k = addClass(D, A); const t = addDataAttrHost(z, y ? "viewport" : "host");
const V = addClass(E, !y && $); const n = addClass(D, A);
const B = addClass(P, I); const o = addClass(E, !y && $);
const s = addClass(P, I);
if (N) { if (N) {
insertAfter(L, z); insertAfter(L, z);
push(j, (() => { push(j, (() => {
@@ -1064,7 +1065,7 @@ const createStructureSetupElements = t => {
appendChildren(D || z, !y && E); appendChildren(D || z, !y && E);
appendChildren(E, P); appendChildren(E, P);
push(j, (() => { push(j, (() => {
F(); t();
removeAttr(E, S); removeAttr(E, S);
removeAttr(E, C); removeAttr(E, C);
if (elementIsGenerated(P)) { if (elementIsGenerated(P)) {
@@ -1076,9 +1077,9 @@ const createStructureSetupElements = t => {
if (elementIsGenerated(D)) { if (elementIsGenerated(D)) {
unwrap(D); unwrap(D);
} }
k(); n();
V(); o();
B(); s();
})); }));
if (e && !y) { if (e && !y) {
push(j, removeClass.bind(0, E, T)); push(j, removeClass.bind(0, E, T));
@@ -1087,7 +1088,8 @@ const createStructureSetupElements = t => {
insertBefore(E, M); insertBefore(E, M);
push(j, removeElements.bind(0, M)); push(j, removeElements.bind(0, M));
} }
return [ x, runEach.bind(0, j) ]; };
return [ x, appendElements, runEach.bind(0, j) ];
}; };
const createTrinsicUpdate = (t, n) => { const createTrinsicUpdate = (t, n) => {
@@ -2011,29 +2013,27 @@ const ut = {
const createStructureSetup = (t, n) => { const createStructureSetup = (t, n) => {
const e = createOptionCheck(n, {}); const e = createOptionCheck(n, {});
const o = createState(ut); const o = createState(ut);
const s = new Set; const [s, c, i] = createEventListenerHub();
const [c] = o; const [r] = o;
const runOnUpdatedListeners = (t, n, e) => { const [a, l, u] = createStructureSetupElements(t);
runEach(s, [ t, n || {}, !!e ]); const f = createStructureSetupUpdate(a, o);
}; const [d, _] = createStructureSetupObservers(a, o, (t => {
const [i, r] = createStructureSetupElements(t); i("u", [ f(e, t), {}, false ]);
const a = createStructureSetupUpdate(i, o);
const [l, u] = createStructureSetupObservers(i, o, (t => {
runOnUpdatedListeners(a(e, t));
})); }));
const f = c.bind(0); const g = r.bind(0);
f.Pt = t => { g.Pt = t => {
s.add(t); s("u", t);
}; };
f.Mt = i; g.Mt = l;
g.jt = a;
return [ (t, e) => { return [ (t, e) => {
const o = createOptionCheck(n, t, e); const o = createOptionCheck(n, t, e);
l(o); d(o);
runOnUpdatedListeners(a(o, {}, e)); i("u", [ f(o, {}, e), t, !!e ]);
}, f, () => { }, g, () => {
s.clear(); c();
_();
u(); u();
r();
} ]; } ];
}; };
@@ -2044,41 +2044,44 @@ const generateScrollbarDOM = t => {
appendChildren(n, e); appendChildren(n, e);
appendChildren(e, o); appendChildren(e, o);
return { return {
jt: n, Nt: n,
Nt: e, Rt: e,
Rt: o Ht: o
}; };
}; };
const createScrollbarsSetupElements = (t, n) => { const createScrollbarsSetupElements = (t, n) => {
const {N: e} = getEnvironment(); const {N: e} = getEnvironment();
const {Ht: o} = e(); const {Ft: o} = e();
const {Y: s, B: c, U: i, tt: r} = n; const {Y: s, B: c, U: i, tt: r} = n;
const a = !r && t.scrollbarsSlot; const a = !r && t.scrollbarsSlot;
const l = dynamicInitializationElement([ s, c, i ], (() => c), o, a); const l = dynamicInitializationElement([ s, c, i ], (() => c), o, a);
const u = generateScrollbarDOM(F); const u = generateScrollbarDOM(F);
const f = generateScrollbarDOM(k); const f = generateScrollbarDOM(k);
const {jt: d} = u; const {Nt: d} = u;
const {jt: _} = f; const {Nt: _} = f;
const appendElements = () => {
appendChildren(l, d); appendChildren(l, d);
appendChildren(l, _); appendChildren(l, _);
};
return [ { return [ {
Ft: u, kt: u,
kt: f Vt: f
}, removeElements.bind(0, [ d, _ ]) ]; }, appendElements, removeElements.bind(0, [ d, _ ]) ];
}; };
const createScrollbarsSetup = (t, n, e) => { const createScrollbarsSetup = (t, n, e) => {
const o = createState({}); const o = createState({});
const [s] = o; const [s] = o;
const [c, i] = createScrollbarsSetupElements(t, e); const [c, i, r] = createScrollbarsSetupElements(t, e);
const r = s.bind(0); const a = s.bind(0);
r.Mt = c; a.jt = c;
a.Mt = i;
return [ (t, e) => { return [ (t, e) => {
const o = createOptionCheck(n, t, e); const o = createOptionCheck(n, t, e);
console.log(o); console.log(o);
}, r, () => { }, a, () => {
i(); r();
} ]; } ];
}; };
@@ -2157,34 +2160,95 @@ const removeInstance = t => {
const getInstance = t => mt.get(t); const getInstance = t => mt.get(t);
const OverlayScrollbars = (t, n, e) => { const OverlayScrollbars = (t, n, e) => {
const {H: o, I: s, j: c} = getEnvironment(); let o = false;
const i = getPlugins(); const {H: s, I: c, j: i} = getEnvironment();
const r = isHTMLElement(t) ? t : t.target; const r = getPlugins();
const a = getInstance(r); const a = isHTMLElement(t) ? t : t.target;
if (a) { const l = getInstance(a);
return a; if (l) {
return l;
} }
const l = i[bt]; const u = r[bt];
const validateOptions = t => { const validateOptions = t => {
const n = t || {}; const n = t || {};
const e = l && l.Vt; const e = u && u.Bt;
return e ? e(n, true) : n; return e ? e(n, true) : n;
}; };
const u = assignDeep({}, o(), validateOptions(n)); const f = assignDeep({}, s(), validateOptions(n));
const [f, d, _] = createEventListenerHub(e); const [d, _, g] = createEventListenerHub(e);
if (s.x && s.y && !u.nativeScrollbarsOverlaid.initialize) { const [h, p, v] = createStructureSetup(t, f);
_("initializationWithdrawn"); const [w, b, y] = createScrollbarsSetup(t, f, p.jt);
}
const [g, h, p] = createStructureSetup(t, u);
const [v, , w] = createScrollbarsSetup(t, u, h.Mt);
const update = (t, n) => { const update = (t, n) => {
g(t, n); h(t, n);
v(t, n); w(t, n);
}; };
const b = c(update.bind(0, {}, true)); const m = i(update.bind(0, {}, true));
h.Pt(((t, n, e) => { const destroy = t => {
removeInstance(a);
m();
y();
v();
o = true;
g("destroyed", [ S, !!t ]);
_();
};
const S = {
options(t) {
if (t) {
const n = getOptionsDiff(f, validateOptions(t));
if (!isEmptyObject(n)) {
assignDeep(f, n);
update(n);
}
}
return assignDeep({}, f);
},
on: d,
off: _,
state() {
const {yt: t, vt: n, St: e, A: s, ft: c} = p();
return assignDeep({}, {
overflowAmount: t,
overflowStyle: n,
hasOverflow: e,
padding: s,
paddingAbsolute: c,
destroyed: o
});
},
elements() {
const {Y: t, B: n, A: e, U: o, $: s} = p.jt;
return assignDeep({}, {
target: t,
host: n,
padding: e || o,
viewport: o,
content: s || o
});
},
update(t) {
update({}, t);
return S;
},
destroy: destroy.bind(0)
};
if (c.x && c.y && !f.nativeScrollbarsOverlaid.initialize) {
destroy(true);
return S;
}
each(keys(r), (t => {
const n = r[t];
if (isFunction(n)) {
n(OverlayScrollbars, S);
}
}));
p.Mt();
b.Mt();
addInstance(a, S);
g("initialized", [ S ]);
p.Pt(((t, n, e) => {
const {it: o, ut: s, ct: c, xt: i, Ct: r, rt: a, bt: l} = t; const {it: o, ut: s, ct: c, xt: i, Ct: r, rt: a, bt: l} = t;
_("updated", { g("updated", [ S, {
updateHints: { updateHints: {
sizeChanged: o, sizeChanged: o,
directionChanged: s, directionChanged: s,
@@ -2196,63 +2260,9 @@ const OverlayScrollbars = (t, n, e) => {
}, },
changedOptions: n, changedOptions: n,
force: e force: e
}); } ]);
})); }));
const y = { return S.update(true);
options(t) {
if (t) {
const n = getOptionsDiff(u, validateOptions(t));
if (!isEmptyObject(n)) {
assignDeep(u, n);
update(n);
}
}
return assignDeep({}, u);
},
on: f,
off: d,
state() {
const {yt: t, vt: n, St: e, A: o, ft: s} = h();
return assignDeep({}, {
overflowAmount: t,
overflowStyle: n,
hasOverflow: e,
padding: o,
paddingAbsolute: s
});
},
elements() {
const {Y: t, B: n, A: e, U: o, $: s} = h.Mt;
return assignDeep({}, {
target: t,
host: n,
padding: e || o,
viewport: o,
content: s || o
});
},
update(t) {
update({}, t);
},
destroy: () => {
removeInstance(r);
b();
d();
w();
p();
_("destroyed");
}
};
each(keys(i), (t => {
const n = i[t];
if (isFunction(n)) {
n(OverlayScrollbars, y);
}
}));
y.update(true);
addInstance(r, y);
_("initialized");
return y;
}; };
OverlayScrollbars.plugin = addPlugin; OverlayScrollbars.plugin = addPlugin;
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -31,17 +31,6 @@ import type {
EventListener as GeneralEventListener, EventListener as GeneralEventListener,
} from 'support/eventListeners'; } from 'support/eventListeners';
/*
onScrollStart : null,
onScroll : null,
onScrollStop : null,
onOverflowChanged : null,
onOverflowAmountChanged : null, // fusion with onOverflowChanged
onDirectionChanged : null, // gone
onContentSizeChanged : null, // gone
onHostSizeChanged : null, // gone
*/
export interface OverlayScrollbarsStatic { export interface OverlayScrollbarsStatic {
( (
target: InitializationTarget | InitializationTargetObject, target: InitializationTarget | InitializationTargetObject,
@@ -75,6 +64,7 @@ export interface State {
overflowAmount: XY<number>; overflowAmount: XY<number>;
overflowStyle: XY<OverflowStyle>; overflowStyle: XY<OverflowStyle>;
hasOverflow: XY<boolean>; hasOverflow: XY<boolean>;
destroyed: boolean;
} }
export interface Elements { export interface Elements {
@@ -100,10 +90,18 @@ export interface OnUpdatedEventListenerArgs {
} }
export type EventListenerMap = { export type EventListenerMap = {
initialized: []; /**
initializationWithdrawn: []; * Triggered after all elements are initialized and appended.
updated: [OnUpdatedEventListenerArgs]; */
destroyed: []; initialized: [instance: OverlayScrollbars];
/**
* Triggered after an update.
*/
updated: [instance: OverlayScrollbars, onUpdatedArgs: OnUpdatedEventListenerArgs];
/**
* Triggered after all elements, observers and events are destroyed.
*/
destroyed: [instance: OverlayScrollbars, withdrawn: boolean];
}; };
export type InitialEventListeners = GeneralInitialEventListeners<EventListenerMap>; export type InitialEventListeners = GeneralInitialEventListeners<EventListenerMap>;
@@ -117,7 +115,7 @@ export interface OverlayScrollbars {
options(): Options; options(): Options;
options(newOptions?: PartialOptions<Options>): Options; options(newOptions?: PartialOptions<Options>): Options;
update(force?: boolean): void; update(force?: boolean): OverlayScrollbars;
destroy(): void; destroy(): void;
@@ -142,6 +140,7 @@ export const OverlayScrollbars: OverlayScrollbarsStatic = (
options?, options?,
eventListeners? eventListeners?
): OverlayScrollbars => { ): OverlayScrollbars => {
let destroyed = false;
const { const {
_getDefaultOptions, _getDefaultOptions,
_nativeScrollbarIsOverlaid, _nativeScrollbarIsOverlaid,
@@ -168,59 +167,33 @@ export const OverlayScrollbars: OverlayScrollbarsStatic = (
validateOptions(options) validateOptions(options)
); );
const [addEvent, removeEvent, triggerEvent] = createEventListenerHub(eventListeners); const [addEvent, removeEvent, triggerEvent] = createEventListenerHub(eventListeners);
if (
_nativeScrollbarIsOverlaid.x &&
_nativeScrollbarIsOverlaid.y &&
!currentOptions.nativeScrollbarsOverlaid.initialize
) {
triggerEvent('initializationWithdrawn');
}
const [updateStructure, structureState, destroyStructure] = createStructureSetup( const [updateStructure, structureState, destroyStructure] = createStructureSetup(
target, target,
currentOptions currentOptions
); );
const [updateScrollbars, , destroyScrollbars] = createScrollbarsSetup( const [updateScrollbars, scrollbarsState, destroyScrollbars] = createScrollbarsSetup(
target, target,
currentOptions, currentOptions,
structureState._elements structureState._elements
); );
const update = (changedOptions: PartialOptions<Options>, force?: boolean) => { const update = (changedOptions: PartialOptions<Options>, force?: boolean) => {
updateStructure(changedOptions, force); updateStructure(changedOptions, force);
updateScrollbars(changedOptions, force); updateScrollbars(changedOptions, force);
}; };
const removeEnvListener = addEnvListener(update.bind(0, {}, true)); const removeEnvListener = addEnvListener(update.bind(0, {}, true));
const destroy = (withdrawn?: boolean) => {
removeInstance(instanceTarget);
removeEnvListener();
structureState._addOnUpdatedListener((updateHints, changedOptions, force) => { destroyScrollbars();
const { destroyStructure();
_sizeChanged,
_directionChanged,
_heightIntrinsicChanged,
_overflowAmountChanged,
_overflowStyleChanged,
_contentMutation,
_hostMutation,
} = updateHints;
triggerEvent('updated', [ destroyed = true;
{
updateHints: { // eslint-disable-next-line no-use-before-define
sizeChanged: _sizeChanged, triggerEvent('destroyed', [instance, !!withdrawn]);
directionChanged: _directionChanged, removeEvent();
heightIntrinsicChanged: _heightIntrinsicChanged, };
overflowAmountChanged: _overflowAmountChanged,
overflowStyleChanged: _overflowStyleChanged,
contentMutation: _contentMutation,
hostMutation: _hostMutation,
},
changedOptions,
force,
},
]);
});
const instance: OverlayScrollbars = { const instance: OverlayScrollbars = {
options(newOptions?: PartialOptions<Options>) { options(newOptions?: PartialOptions<Options>) {
@@ -235,7 +208,9 @@ export const OverlayScrollbars: OverlayScrollbarsStatic = (
return assignDeep({}, currentOptions); return assignDeep({}, currentOptions);
}, },
on: addEvent, on: addEvent,
off: removeEvent, off: (name, listener) => {
name && listener && removeEvent(name, listener as any);
},
state() { state() {
const { _overflowAmount, _overflowStyle, _hasOverflow, _padding, _paddingAbsolute } = const { _overflowAmount, _overflowStyle, _hasOverflow, _padding, _paddingAbsolute } =
structureState(); structureState();
@@ -247,6 +222,7 @@ export const OverlayScrollbars: OverlayScrollbarsStatic = (
hasOverflow: _hasOverflow, hasOverflow: _hasOverflow,
padding: _padding, padding: _padding,
paddingAbsolute: _paddingAbsolute, paddingAbsolute: _paddingAbsolute,
destroyed,
} }
); );
}, },
@@ -265,17 +241,9 @@ export const OverlayScrollbars: OverlayScrollbarsStatic = (
}, },
update(force?: boolean) { update(force?: boolean) {
update({}, force); update({}, force);
return instance;
}, },
destroy: () => { destroy: destroy.bind(0),
removeInstance(instanceTarget);
removeEnvListener();
removeEvent();
destroyScrollbars();
destroyStructure();
triggerEvent('destroyed');
},
}; };
each(keys(plugins), (pluginName) => { each(keys(plugins), (pluginName) => {
@@ -285,13 +253,51 @@ export const OverlayScrollbars: OverlayScrollbarsStatic = (
} }
}); });
instance.update(true); if (
_nativeScrollbarIsOverlaid.x &&
_nativeScrollbarIsOverlaid.y &&
!currentOptions.nativeScrollbarsOverlaid.initialize
) {
destroy(true);
return instance;
}
structureState._appendElements();
scrollbarsState._appendElements();
addInstance(instanceTarget, instance); addInstance(instanceTarget, instance);
triggerEvent('initialized', [instance]);
triggerEvent('initialized'); structureState._addOnUpdatedListener((updateHints, changedOptions, force) => {
const {
_sizeChanged,
_directionChanged,
_heightIntrinsicChanged,
_overflowAmountChanged,
_overflowStyleChanged,
_contentMutation,
_hostMutation,
} = updateHints;
return instance; triggerEvent('updated', [
instance,
{
updateHints: {
sizeChanged: _sizeChanged,
directionChanged: _directionChanged,
heightIntrinsicChanged: _heightIntrinsicChanged,
overflowAmountChanged: _overflowAmountChanged,
overflowStyleChanged: _overflowStyleChanged,
contentMutation: _contentMutation,
hostMutation: _hostMutation,
},
changedOptions,
force,
},
]);
});
return instance.update(true);
}; };
OverlayScrollbars.plugin = addPlugin; OverlayScrollbars.plugin = addPlugin;
@@ -1 +0,0 @@
export { optionsValidationPlugin } from 'plugins/optionsValidation/optionsValidation';
@@ -27,7 +27,11 @@ export interface ScrollbarsSetupElementsObj {
_verticalScrollbarStructure: ScrollbarStructure; _verticalScrollbarStructure: ScrollbarStructure;
} }
export type ScrollbarsSetupElements = [elements: ScrollbarsSetupElementsObj, destroy: () => void]; export type ScrollbarsSetupElements = [
elements: ScrollbarsSetupElementsObj,
appendElements: () => void,
destroy: () => void
];
const generateScrollbarDOM = (scrollbarClassName: string): ScrollbarStructure => { const generateScrollbarDOM = (scrollbarClassName: string): ScrollbarStructure => {
const scrollbar = createDiv(`${classNameScrollbar} ${scrollbarClassName}`); const scrollbar = createDiv(`${classNameScrollbar} ${scrollbarClassName}`);
@@ -68,14 +72,17 @@ export const createScrollbarsSetupElements = (
const { _scrollbar: horizontalScrollbar } = horizontalScrollbarStructure; const { _scrollbar: horizontalScrollbar } = horizontalScrollbarStructure;
const { _scrollbar: verticalScrollbar } = verticalScrollbarStructure; const { _scrollbar: verticalScrollbar } = verticalScrollbarStructure;
const appendElements = () => {
appendChildren(evaluatedScrollbarSlot, horizontalScrollbar); appendChildren(evaluatedScrollbarSlot, horizontalScrollbar);
appendChildren(evaluatedScrollbarSlot, verticalScrollbar); appendChildren(evaluatedScrollbarSlot, verticalScrollbar);
};
return [ return [
{ {
_horizontalScrollbarStructure: horizontalScrollbarStructure, _horizontalScrollbarStructure: horizontalScrollbarStructure,
_verticalScrollbarStructure: verticalScrollbarStructure, _verticalScrollbarStructure: verticalScrollbarStructure,
}, },
appendElements,
removeElements.bind(0, [horizontalScrollbar, verticalScrollbar]), removeElements.bind(0, [horizontalScrollbar, verticalScrollbar]),
]; ];
}; };
@@ -13,6 +13,7 @@ export interface ScrollbarsSetupState {}
export interface ScrollbarsSetupStaticState { export interface ScrollbarsSetupStaticState {
_elements: ScrollbarsSetupElementsObj; _elements: ScrollbarsSetupElementsObj;
_appendElements: () => void;
} }
export const createScrollbarsSetup = ( export const createScrollbarsSetup = (
@@ -23,11 +24,15 @@ export const createScrollbarsSetup = (
const state = createState({}); const state = createState({});
const [getState] = state; const [getState] = state;
const [elements, destroyElements] = createScrollbarsSetupElements(target, structureSetupElements); const [elements, appendElements, destroyElements] = createScrollbarsSetupElements(
target,
structureSetupElements
);
const scrollbarsSetupState = getState.bind(0) as (() => ScrollbarsSetupState) & const scrollbarsSetupState = getState.bind(0) as (() => ScrollbarsSetupState) &
ScrollbarsSetupStaticState; ScrollbarsSetupStaticState;
scrollbarsSetupState._elements = elements; scrollbarsSetupState._elements = elements;
scrollbarsSetupState._appendElements = appendElements;
return [ return [
(changedOptions, force?) => { (changedOptions, force?) => {
@@ -43,7 +43,11 @@ import type {
StructureStaticInitializationElement, StructureStaticInitializationElement,
} from 'setups/structureSetup/structureSetup.initialization'; } from 'setups/structureSetup/structureSetup.initialization';
export type StructureSetupElements = [targetObj: StructureSetupElementsObj, destroy: () => void]; export type StructureSetupElements = [
targetObj: StructureSetupElementsObj,
appendElements: () => void,
destroy: () => void
];
export interface StructureSetupElementsObj { export interface StructureSetupElementsObj {
_target: InitializationTargetElement; _target: InitializationTargetElement;
@@ -197,6 +201,7 @@ export const createStructureSetupElements = (
) )
); );
const contentSlot = _content || _viewport; const contentSlot = _content || _viewport;
const appendElements = () => {
const removeHostDataAttr = addDataAttrHost(_host, viewportIsTarget ? 'viewport' : 'host'); const removeHostDataAttr = addDataAttrHost(_host, viewportIsTarget ? 'viewport' : 'host');
const removePaddingClass = addClass(_padding, classNamePadding); const removePaddingClass = addClass(_padding, classNamePadding);
const removeViewportClass = addClass(_viewport, !viewportIsTarget && classNameViewport); const removeViewportClass = addClass(_viewport, !viewportIsTarget && classNameViewport);
@@ -243,6 +248,7 @@ export const createStructureSetupElements = (
insertBefore(_viewport, _viewportArrange); insertBefore(_viewport, _viewportArrange);
push(destroyFns, removeElements.bind(0, _viewportArrange)); push(destroyFns, removeElements.bind(0, _viewportArrange));
} }
};
return [evaluatedTargetObj, runEach.bind(0, destroyFns)]; return [evaluatedTargetObj, appendElements, runEach.bind(0, destroyFns)];
}; };
@@ -1,11 +1,11 @@
import { runEach } from 'support'; import { createEventListenerHub } from 'support';
import { createState, createOptionCheck } from 'setups/setups'; import { createState, createOptionCheck } from 'setups/setups';
import { createStructureSetupElements } from 'setups/structureSetup/structureSetup.elements'; import { createStructureSetupElements } from 'setups/structureSetup/structureSetup.elements';
import { createStructureSetupUpdate } from 'setups/structureSetup/structureSetup.update'; import { createStructureSetupUpdate } from 'setups/structureSetup/structureSetup.update';
import { createStructureSetupObservers } from 'setups/structureSetup/structureSetup.observers'; import { createStructureSetupObservers } from 'setups/structureSetup/structureSetup.observers';
import type { StructureSetupUpdateHints } from 'setups/structureSetup/structureSetup.update'; import type { StructureSetupUpdateHints } from 'setups/structureSetup/structureSetup.update';
import type { StructureSetupElementsObj } from 'setups/structureSetup/structureSetup.elements'; import type { StructureSetupElementsObj } from 'setups/structureSetup/structureSetup.elements';
import type { TRBL, XY } from 'support'; import type { TRBL, XY, EventListener } from 'support';
import type { Options, ReadonlyOSOptions } from 'options'; import type { Options, ReadonlyOSOptions } from 'options';
import type { Setup } from 'setups'; import type { Setup } from 'setups';
import type { InitializationTarget } from 'initialization'; import type { InitializationTarget } from 'initialization';
@@ -24,14 +24,17 @@ export interface StructureSetupState {
export interface StructureSetupStaticState { export interface StructureSetupStaticState {
_elements: StructureSetupElementsObj; _elements: StructureSetupElementsObj;
_addOnUpdatedListener: (listener: OnUpdatedListener) => void; _appendElements: () => void;
_addOnUpdatedListener: (listener: EventListener<StructureSetupEventMap, 'u'>) => void;
} }
export type OnUpdatedListener = ( type StructureSetupEventMap = {
u: [
updateHints: StructureSetupUpdateHints, updateHints: StructureSetupUpdateHints,
changedOptions: PartialOptions<Options>, changedOptions: PartialOptions<Options>,
force: boolean force: boolean
) => void; ];
};
const initialStructureSetupUpdateState: StructureSetupState = { const initialStructureSetupUpdateState: StructureSetupState = {
_padding: { _padding: {
@@ -72,42 +75,35 @@ export const createStructureSetup = (
): Setup<StructureSetupState, StructureSetupStaticState> => { ): Setup<StructureSetupState, StructureSetupStaticState> => {
const checkOptionsFallback = createOptionCheck(options, {}); const checkOptionsFallback = createOptionCheck(options, {});
const state = createState(initialStructureSetupUpdateState); const state = createState(initialStructureSetupUpdateState);
const onUpdatedListeners = new Set<OnUpdatedListener>(); const [addEvent, removeEvent, triggerEvent] = createEventListenerHub<StructureSetupEventMap>();
const [getState] = state; const [getState] = state;
const runOnUpdatedListeners = ( const [elements, appendElements, destroyElements] = createStructureSetupElements(target);
updateHints: StructureSetupUpdateHints,
changedOptions?: PartialOptions<Options>,
force?: boolean
) => {
runEach(onUpdatedListeners, [updateHints, changedOptions || {}, !!force]);
};
const [elements, destroyElements] = createStructureSetupElements(target);
const updateStructure = createStructureSetupUpdate(elements, state); const updateStructure = createStructureSetupUpdate(elements, state);
const [updateObservers, destroyObservers] = createStructureSetupObservers( const [updateObservers, destroyObservers] = createStructureSetupObservers(
elements, elements,
state, state,
(updateHints) => { (updateHints) => {
runOnUpdatedListeners(updateStructure(checkOptionsFallback, updateHints)); triggerEvent('u', [updateStructure(checkOptionsFallback, updateHints), {}, false]);
} }
); );
const structureSetupState = getState.bind(0) as (() => StructureSetupState) & const structureSetupState = getState.bind(0) as (() => StructureSetupState) &
StructureSetupStaticState; StructureSetupStaticState;
structureSetupState._addOnUpdatedListener = (listener) => { structureSetupState._addOnUpdatedListener = (listener) => {
onUpdatedListeners.add(listener); addEvent('u', listener);
}; };
structureSetupState._appendElements = appendElements;
structureSetupState._elements = elements; structureSetupState._elements = elements;
return [ return [
(changedOptions, force?) => { (changedOptions, force?) => {
const checkOption = createOptionCheck(options, changedOptions, force); const checkOption = createOptionCheck(options, changedOptions, force);
updateObservers(checkOption); updateObservers(checkOption);
runOnUpdatedListeners(updateStructure(checkOption, {}, force)); triggerEvent('u', [updateStructure(checkOption, {}, force), changedOptions, !!force]);
}, },
structureSetupState, structureSetupState,
() => { () => {
onUpdatedListeners.clear(); removeEvent();
destroyObservers(); destroyObservers();
destroyElements(); destroyElements();
}, },
@@ -115,7 +115,8 @@ const assertCorrectDOMStructure = (textarea: boolean, viewportIsTarget: boolean)
const createStructureSetupProxy = ( const createStructureSetupProxy = (
target: InitializationTarget | StructureInitialization target: InitializationTarget | StructureInitialization
): StructureSetupElementsProxy => { ): StructureSetupElementsProxy => {
const [elements, destroy] = createStructureSetupElements(target); const [elements, appendElements, destroy] = createStructureSetupElements(target);
appendElements();
return { return {
input: target, input: target,
elements, elements,
@@ -7,8 +7,11 @@ import { timeout } from '@/testing-browser/timeout';
import { setTestResult, waitForOrFailTest } from '@/testing-browser/TestResult'; import { setTestResult, waitForOrFailTest } from '@/testing-browser/TestResult';
import { addClass, each, isArray, removeAttr, style } from 'support'; import { addClass, each, isArray, removeAttr, style } from 'support';
// @ts-ignore
window.OverlayScrollbars = OverlayScrollbars;
OverlayScrollbars.env().setDefaultOptions({ OverlayScrollbars.env().setDefaultOptions({
nativeScrollbarsOverlaid: { initialize: true }, nativeScrollbarsOverlaid: { initialize: false },
}); });
const startBtn: HTMLButtonElement | null = document.querySelector('#start'); const startBtn: HTMLButtonElement | null = document.querySelector('#start');
@@ -33,6 +36,7 @@ let rootUpdateCount = 0;
let aUpdateCount = 0; let aUpdateCount = 0;
let bUpdateCount = 0; let bUpdateCount = 0;
let cUpdateCount = 0; let cUpdateCount = 0;
const rootInstance = OverlayScrollbars( const rootInstance = OverlayScrollbars(
{ target: targetRoot!, padding: true }, { target: targetRoot!, padding: true },
{}, {},
@@ -25,6 +25,13 @@ import { timeout } from '@/testing-browser/timeout';
import { Options } from 'options'; import { Options } from 'options';
import { PartialOptions } from 'typings'; import { PartialOptions } from 'typings';
// @ts-ignore
window.OverlayScrollbars = OverlayScrollbars;
OverlayScrollbars.env().setDefaultOptions({
nativeScrollbarsOverlaid: { initialize: true },
});
interface Metrics { interface Metrics {
offset: { offset: {
left: number; left: number;
@@ -122,7 +129,7 @@ const osInstance =
// @ts-ignore // @ts-ignore
(window.os = OverlayScrollbars( (window.os = OverlayScrollbars(
initObj, initObj,
{ nativeScrollbarsOverlaid: { initialize: true } }, {},
{ {
updated() { updated() {
updateCount++; updateCount++;
+28 -24
View File
@@ -12,11 +12,8 @@ interface XY<T> {
x: T; x: T;
y: T; y: T;
} }
type EventListener<EventMap extends Record<string, any>, Name extends keyof EventMap> = (...args: EventMap[Name] extends undefined ? [ type EventListener<EventMap extends Record<string, any[]>, Name extends keyof EventMap> = (...args: EventMap[Name]) => void;
] : [ type InitialEventListeners<EventMap extends Record<string, any[]>> = {
args: EventMap[Name]
]) => void;
type InitialEventListeners<EventMap extends Record<string, any>> = {
[K in keyof EventMap]?: EventListener<EventMap> | EventListener<EventMap>[]; [K in keyof EventMap]?: EventListener<EventMap> | EventListener<EventMap>[];
}; };
type OverflowBehavior = "hidden" | "scroll" | "visible" | "visible-hidden" | "visible-scroll"; type OverflowBehavior = "hidden" | "scroll" | "visible" | "visible-hidden" | "visible-scroll";
@@ -125,16 +122,6 @@ type DynamicInitializationElement<Args extends any[]> = ((...args: Args) => Dyna
type InitializtationElementStrategy<InitElm> = Exclude<InitElm, HTMLElement>; type InitializtationElementStrategy<InitElm> = Exclude<InitElm, HTMLElement>;
type GeneralInitialEventListeners = InitialEventListeners; type GeneralInitialEventListeners = InitialEventListeners;
type GeneralEventListener = EventListener; type GeneralEventListener = EventListener;
/*
onScrollStart : null,
onScroll : null,
onScrollStop : null,
onOverflowChanged : null,
onOverflowAmountChanged : null, // fusion with onOverflowChanged
onDirectionChanged : null, // gone
onContentSizeChanged : null, // gone
onHostSizeChanged : null, // gone
*/
interface OverlayScrollbarsStatic { interface OverlayScrollbarsStatic {
(target: InitializationTarget | InitializationTargetObject, options?: PartialOptions<Options>, eventListeners?: GeneralInitialEventListeners<EventListenerMap>): OverlayScrollbars; (target: InitializationTarget | InitializationTargetObject, options?: PartialOptions<Options>, eventListeners?: GeneralInitialEventListeners<EventListenerMap>): OverlayScrollbars;
plugin(osPlugin: OSPlugin | OSPlugin[]): void; plugin(osPlugin: OSPlugin | OSPlugin[]): void;
@@ -163,6 +150,7 @@ interface State {
overflowAmount: XY<number>; overflowAmount: XY<number>;
overflowStyle: XY<OverflowStyle>; overflowStyle: XY<OverflowStyle>;
hasOverflow: XY<boolean>; hasOverflow: XY<boolean>;
destroyed: boolean;
} }
interface Elements { interface Elements {
target: HTMLElement; target: HTMLElement;
@@ -184,24 +172,40 @@ interface OnUpdatedEventListenerArgs {
changedOptions: PartialOptions<Options>; changedOptions: PartialOptions<Options>;
force: boolean; force: boolean;
} }
interface EventListenerMap { type EventListenerMap = {
initialized: undefined; /**
initializationWithdrawn: undefined; * Triggered after all elements are initialized and appended.
updated: OnUpdatedEventListenerArgs; */
destroyed: undefined; initialized: [
} instance: OverlayScrollbars
];
/**
* Triggered after an update.
*/
updated: [
instance: OverlayScrollbars,
onUpdatedArgs: OnUpdatedEventListenerArgs
];
/**
* Triggered after all elements, observers and events are destroyed.
*/
destroyed: [
instance: OverlayScrollbars,
withdrawn: boolean
];
};
type EventListener$0<Name extends keyof EventListenerMap> = GeneralEventListener<EventListenerMap, Name>; type EventListener$0<Name extends keyof EventListenerMap> = GeneralEventListener<EventListenerMap, Name>;
interface OverlayScrollbars { interface OverlayScrollbars {
options(): Options; options(): Options;
options(newOptions?: PartialOptions<Options>): Options; options(newOptions?: PartialOptions<Options>): Options;
update(force?: boolean): void; update(force?: boolean): OverlayScrollbars;
destroy(): void; destroy(): void;
state(): State; state(): State;
elements(): Elements; elements(): Elements;
on<Name extends keyof EventListenerMap>(name: Name, listener: EventListener$0<Name>): () => void; on<Name extends keyof EventListenerMap>(name: Name, listener: EventListener$0<Name>): () => void;
on<Name extends keyof EventListenerMap>(name: Name, listener: EventListener$0<Name>[]): () => void; on<Name extends keyof EventListenerMap>(name: Name, listener: EventListener$0<Name>[]): () => void;
off<Name extends keyof EventListenerMap>(name: Name, listener?: EventListener$0<Name>): void; off<Name extends keyof EventListenerMap>(name: Name, listener: EventListener$0<Name>): void;
off<Name extends keyof EventListenerMap>(name: Name, listener?: EventListener$0<Name>[]): void; off<Name extends keyof EventListenerMap>(name: Name, listener: EventListener$0<Name>[]): void;
} }
/** /**
* Notes: * Notes: