mirror of
https://github.com/tenrok/OverlayScrollbars.git
synced 2026-05-23 20:44:08 +03:00
improve code, add ignoreMutation option
This commit is contained in:
@@ -20,20 +20,23 @@ type DOMTargetObserverCallback = (targetChangedAttrs: string[], targetStyleChang
|
||||
interface DOMObserverOptionsBase {
|
||||
_attributes?: string[];
|
||||
_styleChangingAttributes?: string[];
|
||||
/**
|
||||
* A function which can ignore a changed attribute if it returns true.
|
||||
* for DOMTargetObserver this applies to the changes to the observed target
|
||||
* for DOMContentObserver this applies to changes to nested targets -> nested targets are elements which match the "_nestedTargetSelector" selector
|
||||
*/
|
||||
_ignoreTargetChange?: DOMObserverIgnoreTargetChange;
|
||||
}
|
||||
|
||||
interface DOMContentObserverOptions extends DOMObserverOptionsBase {
|
||||
_eventContentChange?: DOMObserverEventContentChange; // [selector, eventname(s) | function returning eventname(s)] -> eventnames divided by whitespaces
|
||||
_nestedTargetSelector?: string;
|
||||
_ignoreContentChange?: DOMObserverIgnoreContentChange; // function which will prevent marking certain dom changes as content change if it returns true
|
||||
_ignoreNestedTargetChange?: DOMObserverIgnoreTargetChange; // a function which will prevent marking certain attributes as changed on nested targets if it returns true
|
||||
}
|
||||
|
||||
interface DOMTargetObserverOptions extends DOMObserverOptionsBase {
|
||||
_ignoreTargetChange?: DOMObserverIgnoreTargetChange; // a function which will prevent marking certain attributes as changed if it returns true
|
||||
}
|
||||
type DOMTargetObserverOptions = DOMObserverOptionsBase;
|
||||
|
||||
type ContentChangeArrayItem = [string?, string?] | null | undefined;
|
||||
type ContentChangeArrayItem = [selector?: string, eventNames?: string] | null | undefined;
|
||||
|
||||
export type DOMObserverEventContentChange =
|
||||
| Array<ContentChangeArrayItem>
|
||||
@@ -161,7 +164,6 @@ export const createDOMObserver = <ContentObserver extends boolean>(
|
||||
_eventContentChange,
|
||||
_nestedTargetSelector,
|
||||
_ignoreTargetChange,
|
||||
_ignoreNestedTargetChange,
|
||||
_ignoreContentChange,
|
||||
} = (options as DOMContentObserverOptions & DOMTargetObserverOptions) || {};
|
||||
const [destroyEventContentChange, updateEventContentChangeElements] = createEventContentChange(
|
||||
@@ -182,8 +184,7 @@ export const createDOMObserver = <ContentObserver extends boolean>(
|
||||
const finalStyleChangingAttributes = _styleChangingAttributes || [];
|
||||
const observedAttributes = finalAttributes.concat(finalStyleChangingAttributes);
|
||||
const observerCallback = (mutations: MutationRecord[]) => {
|
||||
const ignoreTargetChange =
|
||||
(isContentObserver ? _ignoreNestedTargetChange : _ignoreTargetChange) || noop;
|
||||
const ignoreTargetChange = _ignoreTargetChange || noop;
|
||||
const ignoreContentChange = _ignoreContentChange || noop;
|
||||
const targetChangedAttrs: string[] = [];
|
||||
const totalAddedNodes: Node[] = [];
|
||||
|
||||
@@ -41,9 +41,10 @@ export type UpdatedCallback = (this: any, args?: UpdatedArgs) => void;
|
||||
export interface OSOptions {
|
||||
paddingAbsolute: boolean;
|
||||
updating: {
|
||||
elementEvents: Array<[string, string]> | null;
|
||||
elementEvents: Array<[elementSelector: string, eventNames: string]> | null;
|
||||
attributes: string[] | null;
|
||||
debounce: number | [number, number] | null;
|
||||
debounce: [timeout: number, maxWait: number] | number | null; // (if tuple: [timeout: 0, maxWait: 33], if number: [timeout: number, maxWait: false]) debounce for content Changes
|
||||
ignoreMutation: ((mutation: MutationRecord) => any) | null;
|
||||
};
|
||||
overflow: {
|
||||
x: OverflowBehavior;
|
||||
@@ -97,8 +98,9 @@ export const defaultOptions: OSOptions = {
|
||||
paddingAbsolute: false, // true || false
|
||||
updating: {
|
||||
elementEvents: [['img', 'load']], // array of tuples || null
|
||||
attributes: null,
|
||||
debounce: [0, 33], // number || number array || null
|
||||
attributes: null, // string array || null
|
||||
ignoreMutation: null, // () => any || null
|
||||
},
|
||||
overflow: {
|
||||
x: 'scroll', // visible-hidden || visible-scroll || hidden || scroll || v-h || v-s || h || s
|
||||
|
||||
@@ -62,6 +62,14 @@ export interface OverlayScrollbarsState {
|
||||
hasOverflow: XY<boolean>;
|
||||
}
|
||||
|
||||
export interface OverlayScrollbarsElements {
|
||||
target: HTMLElement;
|
||||
host: HTMLElement;
|
||||
padding: HTMLElement;
|
||||
viewport: HTMLElement;
|
||||
content: HTMLElement;
|
||||
}
|
||||
|
||||
export interface OverlayScrollbars {
|
||||
options(): OSOptions;
|
||||
options(newOptions?: PartialOptions<OSOptions>): OSOptions;
|
||||
@@ -70,6 +78,7 @@ export interface OverlayScrollbars {
|
||||
destroy(): void;
|
||||
|
||||
state(): OverlayScrollbarsState;
|
||||
elements(): OverlayScrollbarsElements;
|
||||
|
||||
on: AddOSEventListener;
|
||||
off: RemoveOSEventListener;
|
||||
@@ -177,7 +186,7 @@ export const OverlayScrollbars: OverlayScrollbarsStatic = (
|
||||
},
|
||||
on: addEvent,
|
||||
off: removeEvent,
|
||||
state: () => {
|
||||
state() {
|
||||
const { _overflowAmount, _overflowStyle, _hasOverflow, _padding, _paddingAbsolute } =
|
||||
structureState();
|
||||
return assignDeep(
|
||||
@@ -191,6 +200,19 @@ export const OverlayScrollbars: OverlayScrollbarsStatic = (
|
||||
}
|
||||
);
|
||||
},
|
||||
elements() {
|
||||
const { _target, _host, _padding, _viewport, _content } = structureState._elements;
|
||||
return assignDeep(
|
||||
{},
|
||||
{
|
||||
target: _target,
|
||||
host: _host,
|
||||
padding: _padding || _viewport,
|
||||
viewport: _viewport,
|
||||
content: _content || _viewport,
|
||||
}
|
||||
);
|
||||
},
|
||||
update(force?: boolean) {
|
||||
update({}, force);
|
||||
},
|
||||
|
||||
@@ -25,6 +25,7 @@ const optionsTemplate: OptionsTemplate<OSOptions> = {
|
||||
elementEvents: arrayNullValues, // array of tuples || null
|
||||
attributes: arrayNullValues,
|
||||
debounce: [oTypes.number, oTypes.array, oTypes.null], // number || number array || null
|
||||
ignoreMutation: [oTypes.function, oTypes.null], // function || null
|
||||
},
|
||||
overflow: {
|
||||
x: overflowAllowedValues, // visible-hidden || visible-scroll || hidden || scrol
|
||||
|
||||
@@ -3,7 +3,7 @@ import { type, isArray, isUndefined, isPlainObject, isString } from 'support/uti
|
||||
import { PlainObject, PartialOptions } from 'typings';
|
||||
|
||||
export type OptionsObjectType = Record<string, unknown>;
|
||||
export type OptionsFunctionType = (this: unknown, ...args: unknown[]) => unknown;
|
||||
export type OptionsFunctionType = (this: any, ...args: any[]) => any;
|
||||
export type OptionsTemplateType<T extends OptionsTemplateNativeTypes> = ExtractPropsKey<
|
||||
OptionsTemplateTypeMap,
|
||||
T
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import {
|
||||
diffClass,
|
||||
debounce,
|
||||
isArray,
|
||||
isNumber,
|
||||
@@ -19,14 +18,10 @@ import {
|
||||
removeClass,
|
||||
addClass,
|
||||
hasClass,
|
||||
isFunction,
|
||||
} from 'support';
|
||||
import { getEnvironment } from 'environment';
|
||||
import {
|
||||
dataAttributeHost,
|
||||
classNameViewport,
|
||||
classNameContent,
|
||||
classNameOverflowVisible,
|
||||
} from 'classnames';
|
||||
import { dataAttributeHost, classNameViewport, classNameOverflowVisible } from 'classnames';
|
||||
import { createSizeObserver, SizeObserverCallbackParams } from 'observers/sizeObserver';
|
||||
import { createTrinsicObserver } from 'observers/trinsicObserver';
|
||||
import { createDOMObserver, DOMObserver } from 'observers/domObserver';
|
||||
@@ -54,29 +49,12 @@ type ExcludeFromTuple<T extends readonly any[], E> = T extends [infer F, ...infe
|
||||
const hostSelector = `[${dataAttributeHost}]`;
|
||||
|
||||
// TODO: observer textarea attrs if textarea
|
||||
// TODO: test _ignoreContentChange & _ignoreNestedTargetChange for content dom observer
|
||||
// TODO: test _ignoreTargetChange for target dom observer
|
||||
|
||||
const viewportSelector = `.${classNameViewport}`;
|
||||
const contentSelector = `.${classNameContent}`;
|
||||
const ignorePrefix = 'os-';
|
||||
const viewportAttrsFromTarget = ['tabindex'];
|
||||
const baseStyleChangingAttrsTextarea = ['wrap', 'cols', 'rows'];
|
||||
const baseStyleChangingAttrs = ['id', 'class', 'style', 'open'];
|
||||
|
||||
const ignoreTargetChange = (
|
||||
target: Node,
|
||||
attrName: string,
|
||||
oldValue: string | null,
|
||||
newValue: string | null
|
||||
) => {
|
||||
if (attrName === 'class' && oldValue && newValue) {
|
||||
const diff = diffClass(oldValue, newValue);
|
||||
return !!diff.find((addedOrRemovedClass) => addedOrRemovedClass.indexOf(ignorePrefix) !== 0);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
export const createStructureSetupObservers = (
|
||||
structureSetupElements: StructureSetupElementsObj,
|
||||
state: SetupState<StructureSetupState>,
|
||||
@@ -198,21 +176,23 @@ export const createStructureSetupObservers = (
|
||||
const [destroyHostMutationObserver] = createDOMObserver(_host, false, onHostMutation, {
|
||||
_styleChangingAttributes: baseStyleChangingAttrs,
|
||||
_attributes: baseStyleChangingAttrs.concat(viewportAttrsFromTarget),
|
||||
_ignoreTargetChange: ignoreTargetChange,
|
||||
});
|
||||
|
||||
updateViewportAttrsFromHost();
|
||||
|
||||
return [
|
||||
(checkOption) => {
|
||||
const [ignoreMutation] = checkOption<string[] | null>('updating.ignoreMutation');
|
||||
const [attributes, attributesChanged] = checkOption<string[] | null>('updating.attributes');
|
||||
const [elementEvents, elementEventsChanged] = checkOption<Array<[string, string]> | null>(
|
||||
'updating.elementEvents'
|
||||
);
|
||||
const [attributes, attributesChanged] = checkOption<string[] | null>('updating.attributes');
|
||||
const [debounceValue, debounceChanged] = checkOption<Array<number> | number | null>(
|
||||
'updating.debounce'
|
||||
);
|
||||
const updateContentMutationObserver = elementEventsChanged || attributesChanged;
|
||||
const ignoreMutationFromOptions = (mutation: MutationRecord) =>
|
||||
isFunction(ignoreMutation) && ignoreMutation(mutation);
|
||||
|
||||
if (updateContentMutationObserver) {
|
||||
if (contentMutationObserver) {
|
||||
@@ -227,17 +207,14 @@ export const createStructureSetupObservers = (
|
||||
_styleChangingAttributes: contentMutationObserverAttr.concat(attributes || []),
|
||||
_attributes: contentMutationObserverAttr.concat(attributes || []),
|
||||
_eventContentChange: elementEvents,
|
||||
_ignoreNestedTargetChange: ignoreTargetChange,
|
||||
_nestedTargetSelector: hostSelector,
|
||||
_ignoreContentChange: (mutation, isNestedTarget) => {
|
||||
const { target, attributeName } = mutation;
|
||||
return !isNestedTarget && attributeName
|
||||
? liesBetween(
|
||||
target as Element,
|
||||
hostSelector,
|
||||
_content ? contentSelector : viewportSelector
|
||||
)
|
||||
: false;
|
||||
const ignore =
|
||||
!isNestedTarget && attributeName
|
||||
? liesBetween(target as Element, hostSelector, viewportSelector)
|
||||
: false;
|
||||
return ignore || !!ignoreMutationFromOptions(mutation);
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
+19
-25
@@ -137,12 +137,6 @@ const targetDomObserver = createDOMObserver(
|
||||
should.ok(false, 'A target dom observer must not call the _ignoreContentChange method.');
|
||||
return true;
|
||||
},
|
||||
// @ts-ignore
|
||||
_ignoreNestedTargetChange: () => {
|
||||
// if param: isContentObserver = false, this function should never be called.
|
||||
should.ok(false, 'A target dom observer must not call the _ignoreNestedTargetChange method.');
|
||||
return true;
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
@@ -182,7 +176,7 @@ const createContentDomOserver = (
|
||||
? liesBetween(target as Element, hostSelector, '.content')
|
||||
: false;
|
||||
},
|
||||
_ignoreNestedTargetChange: (_target, attrName, oldValue, newValue) => {
|
||||
_ignoreTargetChange: (_target, attrName, oldValue, newValue) => {
|
||||
if (attrName === 'class' && oldValue && newValue) {
|
||||
const diff = diffClass(oldValue, newValue);
|
||||
const ignore = diff.length === 1 && diff[0].startsWith(ignorePrefix);
|
||||
@@ -190,12 +184,6 @@ const createContentDomOserver = (
|
||||
}
|
||||
return false;
|
||||
},
|
||||
// @ts-ignore
|
||||
_ignoreTargetChange: () => {
|
||||
// if param: isContentObserver = true, this function should never be called.
|
||||
should.ok(false, 'A content dom observer must not call the _ignoreTargetChange method.');
|
||||
return true;
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
@@ -503,7 +491,8 @@ const addRemoveImgElmsFn = async (changeless = false) => {
|
||||
const addChanged = async (
|
||||
newEventContentChange: Array<[string?, string?] | null | undefined>
|
||||
) => {
|
||||
contentDomObserver._destroy();
|
||||
const [destroyA] = contentDomObserver;
|
||||
destroyA();
|
||||
contentDomObserver = createContentDomOserver(newEventContentChange);
|
||||
|
||||
const img = new Image(1, 1);
|
||||
@@ -523,7 +512,8 @@ const addRemoveImgElmsFn = async (changeless = false) => {
|
||||
compare(1);
|
||||
});
|
||||
|
||||
contentDomObserver._destroy();
|
||||
const [destroyB] = contentDomObserver;
|
||||
destroyB();
|
||||
contentDomObserver = createContentDomOserver(contentChange);
|
||||
};
|
||||
|
||||
@@ -604,7 +594,8 @@ const addRemoveTransitionElmsFn = async () => {
|
||||
});
|
||||
|
||||
await startTransition(elm, expectTransitionEndContentChange && true);
|
||||
contentDomObserver._destroy();
|
||||
const [destroy] = contentDomObserver;
|
||||
destroy();
|
||||
contentDomObserver = createContentDomOserver(contentChange);
|
||||
await startTransition(elm, expectTransitionEndContentChange && false);
|
||||
|
||||
@@ -615,7 +606,8 @@ const addRemoveTransitionElmsFn = async () => {
|
||||
|
||||
await add(false);
|
||||
|
||||
contentDomObserver._destroy();
|
||||
const [destroy] = contentDomObserver;
|
||||
destroy();
|
||||
contentDomObserver = createContentDomOserver(
|
||||
contentChange.concat([['.transition', 'transitionend']])
|
||||
);
|
||||
@@ -734,15 +726,17 @@ const start = async () => {
|
||||
|
||||
await addRemoveImgElmsFn();
|
||||
|
||||
targetDomObserver._update();
|
||||
targetDomObserver._destroy();
|
||||
targetDomObserver._destroy();
|
||||
targetDomObserver._update();
|
||||
const [destroyTarget, updateTarget] = targetDomObserver;
|
||||
updateTarget();
|
||||
destroyTarget();
|
||||
destroyTarget();
|
||||
updateTarget();
|
||||
|
||||
contentDomObserver._update();
|
||||
contentDomObserver._destroy();
|
||||
contentDomObserver._destroy();
|
||||
contentDomObserver._update();
|
||||
const [destroyContent, updateContent] = contentDomObserver;
|
||||
updateContent();
|
||||
destroyContent();
|
||||
destroyContent();
|
||||
updateContent();
|
||||
|
||||
await addRemoveImgElmsFn(true); // won't trigger changes after destroy
|
||||
|
||||
|
||||
+36
-14
@@ -5,7 +5,7 @@ import { OverlayScrollbars } from 'overlayscrollbars';
|
||||
import { resize } from '@/testing-browser/Resize';
|
||||
import { timeout } from '@/testing-browser/timeout';
|
||||
import { setTestResult, waitForOrFailTest } from '@/testing-browser/TestResult';
|
||||
import { addClass, removeAttr, style } from 'support';
|
||||
import { addClass, each, isArray, removeAttr, style } from 'support';
|
||||
|
||||
OverlayScrollbars.env().setDefaultOptions({
|
||||
nativeScrollbarsOverlaid: { initialize: true },
|
||||
@@ -28,14 +28,16 @@ const resizeBetweenB: HTMLElement | null = document.createElement('div');
|
||||
let rootUpdateCount = 0;
|
||||
let aUpdateCount = 0;
|
||||
let bUpdateCount = 0;
|
||||
OverlayScrollbars(
|
||||
targetRoot!,
|
||||
const rootInstance = OverlayScrollbars(
|
||||
{ target: targetRoot!, padding: true },
|
||||
{},
|
||||
{
|
||||
initialized() {
|
||||
addClass(targetRoot!.querySelector('.os-viewport'), 'flex');
|
||||
addClass(resizeBetweenRoot, 'resize resizeBetween');
|
||||
targetRoot!.append(resizeBetweenRoot);
|
||||
requestAnimationFrame(() => {
|
||||
addClass(rootInstance.elements().content, 'flex');
|
||||
addClass(resizeBetweenRoot, 'resize resizeBetween');
|
||||
targetRoot!.append(resizeBetweenRoot);
|
||||
});
|
||||
},
|
||||
updated() {
|
||||
rootUpdateCount++;
|
||||
@@ -47,17 +49,18 @@ OverlayScrollbars(
|
||||
},
|
||||
}
|
||||
);
|
||||
OverlayScrollbars(
|
||||
const aInstance = OverlayScrollbars(
|
||||
{ target: targetA!, content: true },
|
||||
{},
|
||||
{
|
||||
initialized() {
|
||||
addClass(targetA!.querySelector('.os-content'), 'flex');
|
||||
addClass(resizeBetweenA, 'resize resizeBetween');
|
||||
targetA!.append(resizeBetweenA);
|
||||
requestAnimationFrame(() => {
|
||||
addClass(aInstance.elements().content, 'flex');
|
||||
addClass(resizeBetweenA, 'resize resizeBetween');
|
||||
targetA!.append(resizeBetweenA);
|
||||
});
|
||||
},
|
||||
updated(args) {
|
||||
console.log(args);
|
||||
updated() {
|
||||
aUpdateCount++;
|
||||
requestAnimationFrame(() => {
|
||||
if (updatesASlot) {
|
||||
@@ -67,7 +70,7 @@ OverlayScrollbars(
|
||||
},
|
||||
}
|
||||
);
|
||||
OverlayScrollbars(
|
||||
const bInstance = OverlayScrollbars(
|
||||
targetB!,
|
||||
{},
|
||||
{
|
||||
@@ -131,7 +134,26 @@ const resizeResize = async (resizeElm: HTMLElement) => {
|
||||
removeAttr(resizeElm, 'style');
|
||||
};
|
||||
|
||||
const overwriteScrollHeight = (elm: HTMLElement | HTMLElement[]) => {
|
||||
const elements = isArray(elm) ? elm : [elm];
|
||||
|
||||
each(elements, (currElm) => {
|
||||
Object.defineProperty(currElm, 'scrollHeight', {
|
||||
configurable: true,
|
||||
get() {
|
||||
setTestResult(false);
|
||||
throw new Error('accessed scrollHeight');
|
||||
},
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const testBetweenElements = async () => {
|
||||
overwriteScrollHeight([
|
||||
rootInstance.elements().viewport,
|
||||
aInstance.elements().viewport,
|
||||
bInstance.elements().viewport,
|
||||
]);
|
||||
await waitForOrFailTest(async () => {
|
||||
await resizeBetween(resizeBetweenRoot);
|
||||
await resizeBetween(resizeBetweenA);
|
||||
@@ -150,8 +172,8 @@ const testResizeElements = async () => {
|
||||
const start = async () => {
|
||||
setTestResult(null);
|
||||
|
||||
await testBetweenElements();
|
||||
await testResizeElements();
|
||||
await testBetweenElements(); // has to be last
|
||||
|
||||
setTestResult(true);
|
||||
};
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
import './index.scss';
|
||||
import 'styles/overlayscrollbars.scss';
|
||||
import should from 'should';
|
||||
import { OverlayScrollbars } from 'overlayscrollbars';
|
||||
import { resize } from '@/testing-browser/Resize';
|
||||
import { timeout } from '@/testing-browser/timeout';
|
||||
import { setTestResult, waitForOrFailTest } from '@/testing-browser/TestResult';
|
||||
import { addClass, each, isArray, removeAttr, style } from 'support';
|
||||
|
||||
OverlayScrollbars.env().setDefaultOptions({
|
||||
nativeScrollbarsOverlaid: { initialize: true },
|
||||
});
|
||||
|
||||
const startBtn: HTMLButtonElement | null = document.querySelector('#start');
|
||||
const target: HTMLElement | null = document.querySelector('#target');
|
||||
const updatesSlot: HTMLElement | null = document.querySelector('#update');
|
||||
|
||||
let updateCount = 0;
|
||||
|
||||
const osInstance = OverlayScrollbars(
|
||||
{ target: target! },
|
||||
{
|
||||
updating: {
|
||||
ignoreMutation(mutation) {
|
||||
console.log(mutation);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
updated() {
|
||||
updateCount++;
|
||||
requestAnimationFrame(() => {
|
||||
if (updatesSlot) {
|
||||
updatesSlot.textContent = `${updateCount}`;
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const start = async () => {
|
||||
setTestResult(null);
|
||||
|
||||
setTestResult(true);
|
||||
};
|
||||
|
||||
startBtn?.addEventListener('click', start);
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<div id="controls">
|
||||
<button id="start">start</button>
|
||||
</div>
|
||||
<div id="stage">
|
||||
<div>
|
||||
<div id="target" class="container">
|
||||
<span>Hello</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: scroll;
|
||||
}
|
||||
#controls {
|
||||
flex: none;
|
||||
}
|
||||
#stage {
|
||||
flex: auto;
|
||||
position: relative;
|
||||
|
||||
& > div {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background: lightgoldenrodyellow;
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
border: 1px solid red;
|
||||
width: 60%;
|
||||
height: 60%;
|
||||
padding: 10px;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.resize {
|
||||
overflow: hidden;
|
||||
background: lime;
|
||||
border: 1px solid green;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.resizer {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.resizeBetween {
|
||||
background: tomato;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.resizeBtn {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
background: blue;
|
||||
opacity: 0.3;
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// @ts-ignore
|
||||
import { playwrightRollup, expectSuccess } from '@/playwright/rollup';
|
||||
import { test } from '@playwright/test';
|
||||
|
||||
playwrightRollup();
|
||||
|
||||
test.describe('StructureSetup.elements', () => {
|
||||
test('nesting updates', async ({ page }) => {
|
||||
await page.click('#start');
|
||||
await expectSuccess(page);
|
||||
});
|
||||
});
|
||||
+4
-6
@@ -202,7 +202,7 @@ const metricsDimensionsEqual = (a: Metrics, b: Metrics) => {
|
||||
return JSON.stringify(aDimensions) === JSON.stringify(bDimensions);
|
||||
};
|
||||
|
||||
target!.querySelector('.os-viewport')?.addEventListener('scroll', (e) => {
|
||||
osInstance.elements().viewport.addEventListener('scroll', (e) => {
|
||||
const viewport: HTMLElement | null = e.currentTarget as HTMLElement;
|
||||
comparison!.scrollLeft = viewport.scrollLeft;
|
||||
comparison!.scrollTop = viewport.scrollTop;
|
||||
@@ -265,15 +265,13 @@ const checkMetrics = async (checkComparison: CheckComparisonObj) => {
|
||||
await waitForOrFailTest(async () => {
|
||||
const comparisonMetrics = getMetrics(comparison!);
|
||||
const targetMetrics = getMetrics(target!);
|
||||
const targetViewport = target!.querySelector<HTMLElement>('.os-viewport');
|
||||
const targetPadding = target!.querySelector<HTMLElement>('.os-padding');
|
||||
const targetViewport = osInstance.elements().viewport;
|
||||
const targetPadding = osInstance.elements().padding;
|
||||
const { x: overflowOptionX, y: overflowOptionY } = osInstance.options().overflow;
|
||||
const overflowOptionXVisible = isVisibleOverflow(overflowOptionX);
|
||||
const overflowOptionYVisible = isVisibleOverflow(overflowOptionY);
|
||||
const hostOverflowStyle = style(target, 'overflow');
|
||||
const paddingOverflowStyle = targetPadding
|
||||
? style(targetPadding, 'overflow')
|
||||
: hostOverflowStyle;
|
||||
const paddingOverflowStyle = style(targetPadding, 'overflow');
|
||||
const viewportOverflowXStyle = style(targetViewport!, 'overflowX');
|
||||
const viewportOverflowYStyle = style(targetViewport!, 'overflowY');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user